From 0a8f8c14af59e101edb6f6eac107bef88a4cc982 Mon Sep 17 00:00:00 2001 From: StellaOps Bot Date: Sat, 6 Dec 2025 16:32:07 +0000 Subject: [PATCH] cli: scaffold migration runner adapter and category parsing --- .../Commands/SystemCommandBuilder.cs | 34 ++++++++++++++++--- .../Services/MigrationRunnerAdapter.cs | 21 ++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 src/Cli/StellaOps.Cli/Services/MigrationRunnerAdapter.cs diff --git a/src/Cli/StellaOps.Cli/Commands/SystemCommandBuilder.cs b/src/Cli/StellaOps.Cli/Commands/SystemCommandBuilder.cs index 92d446b57..3654cd727 100644 --- a/src/Cli/StellaOps.Cli/Commands/SystemCommandBuilder.cs +++ b/src/Cli/StellaOps.Cli/Commands/SystemCommandBuilder.cs @@ -6,6 +6,23 @@ namespace StellaOps.Cli.Commands; internal static class SystemCommandBuilder { + private static MigrationCategory? ParseCategory(string? value) + { + if (string.IsNullOrWhiteSpace(value)) + { + return null; + } + + return value.ToLowerInvariant() switch + { + "startup" => MigrationCategory.Startup, + "release" => MigrationCategory.Release, + "seed" => MigrationCategory.Seed, + "data" => MigrationCategory.Data, + _ => throw new CommandLineException("Unknown category. Expected: startup|release|seed|data") + }; + } + internal static Command BuildSystemCommand() { var moduleOption = new Option("--module", description: "Module name (Authority, Scheduler, Concelier, Policy, Notify, Excititor, all)"); @@ -18,12 +35,17 @@ internal static class SystemCommandBuilder run.AddOption(dryRunOption); run.SetAction(async parseResult => { - // Placeholder implementation; real execution is handled by migration host/CLI services. - var modules = MigrationModuleRegistry.GetModules(parseResult.GetValue(moduleOption)); + var modules = MigrationModuleRegistry.GetModules(parseResult.GetValue(moduleOption)).ToList(); if (!modules.Any()) { throw new CommandLineException("No modules matched the filter; available: " + string.Join(", ", MigrationModuleRegistry.ModuleNames)); } + var category = ParseCategory(parseResult.GetValue(categoryOption)); + if (category == MigrationCategory.Release && parseResult.GetValue(dryRunOption) == false) + { + throw new CommandLineException("Release migrations require explicit approval; use --dry-run to preview or run approved release migrations manually."); + } + // TODO: wire MigrationRunnerAdapter to execute migrations per module/category. await Task.CompletedTask; }); @@ -32,11 +54,13 @@ internal static class SystemCommandBuilder status.AddOption(categoryOption); status.SetAction(async parseResult => { - var modules = MigrationModuleRegistry.GetModules(parseResult.GetValue(moduleOption)); + var modules = MigrationModuleRegistry.GetModules(parseResult.GetValue(moduleOption)).ToList(); if (!modules.Any()) { throw new CommandLineException("No modules matched the filter; available: " + string.Join(", ", MigrationModuleRegistry.ModuleNames)); } + ParseCategory(parseResult.GetValue(categoryOption)); + // TODO: wire MigrationRunnerAdapter to fetch status. await Task.CompletedTask; }); @@ -45,11 +69,13 @@ internal static class SystemCommandBuilder verify.AddOption(categoryOption); verify.SetAction(async parseResult => { - var modules = MigrationModuleRegistry.GetModules(parseResult.GetValue(moduleOption)); + var modules = MigrationModuleRegistry.GetModules(parseResult.GetValue(moduleOption)).ToList(); if (!modules.Any()) { throw new CommandLineException("No modules matched the filter; available: " + string.Join(", ", MigrationModuleRegistry.ModuleNames)); } + ParseCategory(parseResult.GetValue(categoryOption)); + // TODO: wire MigrationRunnerAdapter to verify checksums. await Task.CompletedTask; }); diff --git a/src/Cli/StellaOps.Cli/Services/MigrationRunnerAdapter.cs b/src/Cli/StellaOps.Cli/Services/MigrationRunnerAdapter.cs new file mode 100644 index 000000000..450f3ee2f --- /dev/null +++ b/src/Cli/StellaOps.Cli/Services/MigrationRunnerAdapter.cs @@ -0,0 +1,21 @@ +using System.Threading; +using System.Threading.Tasks; +using StellaOps.Infrastructure.Postgres.Migrations; + +namespace StellaOps.Cli.Services; + +internal sealed class MigrationRunnerAdapter +{ + private readonly IMigrationRunner _runner; + + public MigrationRunnerAdapter(IMigrationRunner runner) + { + _runner = runner; + } + + public Task RunAsync(string migrationsPath, MigrationCategory? category, CancellationToken cancellationToken) => + _runner.RunAsync(migrationsPath, category, cancellationToken); + + public Task VerifyAsync(string migrationsPath, MigrationCategory? category, CancellationToken cancellationToken) => + _runner.VerifyAsync(migrationsPath, category, cancellationToken); +}