< Summary - ZhEaIsNsAaBn.Libraries coverage (affected: 23 packages)

Information
Class: ZhEaIsNsAaBn.DbSeeder.Design.DbSeederCli
Assembly: ZhEaIsNsAaBn.DbSeeder.Design
File(s): /home/runner/work/ZhEaIsNsAaBn.Libraries.V1/ZhEaIsNsAaBn.Libraries.V1/src/DataBasePackages/ZhEaIsNsAaBn.DbSeeder.Design/DbSeederCli.cs
Line coverage
97%
Covered lines: 34
Uncovered lines: 1
Coverable lines: 35
Total lines: 97
Line coverage: 97.1%
Branch coverage
50%
Covered branches: 3
Total branches: 6
Branch coverage: 50%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
RunAsync(...)100%210%
RunAsync(...)100%11100%
RunWithContextAsync()50%66100%

File(s)

/home/runner/work/ZhEaIsNsAaBn.Libraries.V1/ZhEaIsNsAaBn.Libraries.V1/src/DataBasePackages/ZhEaIsNsAaBn.DbSeeder.Design/DbSeederCli.cs

#LineLine coverage
 1#region Usings
 2using ZhEaIsNsAaBn.DbSeeder.Registrations;
 3#endregion
 4
 5namespace ZhEaIsNsAaBn.DbSeeder.Design;
 6
 7/// <summary>
 8/// The DbSeeder design-time commands, hosted by your own console project (e.g. a migrations CLI). Development only: the
 9/// database and write files under the project folder.
 10/// <list type="bullet">
 11/// <item><c>profile list | add &lt;name&gt; -t &lt;table&gt;… [-o folder] | edit &lt;name&gt; | remove &lt;name&gt;</c>
 12/// <item><c>baseline [-p profile] [-n name]</c> — the first migration of an existing database</item>
 13/// <item><c>add &lt;name&gt; [-p profile]</c> — a migration from the changes since <c>.snapshot/</c></item>
 14/// <item><c>snapshot rebuild [-p profile]</c> — regenerate <c>.snapshot/</c> from the database</item>
 15/// <item><c>validate [-f folder]</c> — every data file against the model; exit code 1 on errors (for CI)</item>
 16/// <item><c>list</c>, <c>update [--to id]</c> — status and apply, from the migrations folder on disk</item>
 17/// <item><c>down [--steps n | --to id] [--soft | --hard] [-y]</c> — plan, confirm, roll back; <c>--force</c> = dry run 
 18/// tree; <c>--force --execute</c> = delete it (never in Production or a protected database; the database name must be t
 19/// <item><c>script [--from id] [--to id] [-o file]</c> — idempotent SQL for a DBA</item>
 20/// </list>
 21/// Every command takes <c>-d|--dir</c> (project folder; default the current directory).
 22/// </summary>
 23public static class DbSeederCli
 24{
 25    /// <summary>Runs one command on <typeparamref name="TDbContext"/>.</summary>
 26    /// <typeparam name="TDbContext">The context; it needs an <c>AddDbSeeder&lt;TDbContext&gt;()…Build()</c> registratio
 27    /// <param name="args">The command line, e.g. <c>[ "add", "AddWallet" ]</c>.</param>
 28    /// <param name="services">The app's services (the context and its seed registration).</param>
 29    /// <param name="cancellationToken">Token to cancel the command.</param>
 30    /// <returns>The exit code: 0 on success, 1 on errors (Spectre's own code for a bad command line).</returns>
 31    /// <remarks>Prompts only when the console's profile is interactive (<c>Profile.Capabilities.Interactive</c>). Spect
 32    /// makes a redirected input or a CI server non-interactive: there <c>down</c> needs <c>--yes</c> and <c>--force --e
 33    /// <exception cref="ArgumentNullException"><paramref name="args"/> or <paramref name="services"/> is <see langword=
 34    /// <exception cref="InvalidOperationException">The context or its seed registration isn't registered.</exception>
 35    /// <example><code>return await DbSeederCli.RunAsync&lt;AppDbContext&gt;( args, host.Services );</code></example>
 36    public static Task<int> RunAsync< TDbContext >( string[] args, IServiceProvider services, CancellationToken cancella
 37        where TDbContext : DbContext
 038        => RunAsync<TDbContext>( args, services, AnsiConsole.Console, cancellationToken );
 39
 40
 41    internal static Task<int> RunAsync< TDbContext >( string[] args, IServiceProvider services, IAnsiConsole console, Ca
 42        where TDbContext : DbContext
 41143        => RunWithContextAsync<TDbContext>( args, services, console, null, cancellationToken );
 44
 45    /// The same, on <paramref name="factoryContext"/> when given (from an <c>IDesignTimeDbContextFactory</c>; disposed 
 46    /// services' context. Called by <see cref="DbSeederDesignTime"/> through reflection (the context type is only known
 47    internal static async Task<int> RunWithContextAsync< TDbContext >( string[] args, IServiceProvider services, IAnsiCo
 48                                                                         CancellationToken cancellationToken )
 49        where TDbContext : DbContext
 50    {
 41151        ArgumentNullException.ThrowIfNull( args );
 41152        ArgumentNullException.ThrowIfNull( services );
 53
 41154        var scope = services.CreateAsyncScope();
 55
 41156        await using var scopeDisposal = scope.ConfigureAwait( false );
 57
 41158        var registration = scope.ServiceProvider.GetServices<SeedContextRegistration>().FirstOrDefault( r => r.ContextTy
 41159                        ?? throw new InvalidOperationException( $"{typeof( TDbContext ).Name} has no AddDbSeeder<{typeof
 60
 41161        var (context, owned) = factoryContext is TDbContext created ? ( created, true ) : SeedContextResolver.Resolve<TD
 62
 63        try
 64        {
 41165            var app = new CommandApp( new DesignTypeRegistrar( new DesignSession( context, registration.Configuration, s
 66
 41167            app.Configure( config =>
 41168            {
 41169                config.SetApplicationName( "dbseeder" );
 41170                config.ConfigureConsole( console );
 41171
 41172                config.AddBranch( "profile", profile =>
 41173                {
 41174                    profile.SetDescription( "Capture profiles (.dbseeder/profiles.json)" );
 41175                    profile.AddCommand<ProfileListCommand>( "list" ).WithDescription( "List the profiles" );
 41176                    profile.AddCommand<ProfileAddCommand>( "add" ).WithDescription( "Add a profile" );
 41177                    profile.AddCommand<ProfileEditCommand>( "edit" ).WithDescription( "Change a profile's tables or fold
 41178                    profile.AddCommand<ProfileRemoveCommand>( "remove" ).WithDescription( "Remove a profile" );
 41179                } );
 41180                config.AddCommand<BaselineCommand>( "baseline" ).WithDescription( "First migration for an existing datab
 41181                config.AddCommand<AddCommand>( "add" ).WithDescription( "Migration from the changes since the snapshot" 
 41182                config.AddBranch( "snapshot", snapshot => snapshot.AddCommand<SnapshotRebuildCommand>( "rebuild" ).WithD
 41183                config.AddCommand<ValidateCommand>( "validate" ).WithDescription( "Check every data file against the mod
 41184                config.AddCommand<ListCommand>( "list" ).WithDescription( "Applied / pending seed migrations, checksums,
 41185                config.AddCommand<UpdateCommand>( "update" ).WithDescription( "Apply the pending seed migrations (--to <
 41186                config.AddCommand<DownCommand>( "down" ).WithDescription( "Roll back (--steps n | --to <id>) [--soft | -
 41187                config.AddCommand<ScriptCommand>( "script" ).WithDescription( "Idempotent SQL script for a DBA (--from, 
 41188            } );
 89
 41190            return await app.RunAsync( args, cancellationToken ).ConfigureAwait( false );
 91        }
 92        finally
 93        {
 41194            if ( owned ) { await context.DisposeAsync().ConfigureAwait( false ); }
 95        }
 41196    }
 97}