runMigrationRegistryEntrypoint function

Future<void> runMigrationRegistryEntrypoint({
  1. required List<String> args,
  2. required List<MigrationDescriptor> buildMigrations(),
  3. required Future<SchemaPlan> buildPlan({
    1. required MigrationDirection direction,
    2. required MigrationId id,
    3. required SchemaSnapshot snapshot,
    }),
})

Run migration registry as an Artisan command-line tool.

Provides info and run commands for listing and executing migrations. This is the entrypoint function called from generated migration registry files.

Implementation

Future<void> runMigrationRegistryEntrypoint({
  required List<String> args,
  required List<MigrationDescriptor> Function() buildMigrations,
  required Future<SchemaPlan> Function({
    required MigrationId id,
    required MigrationDirection direction,
    required SchemaSnapshot snapshot,
  })
  buildPlan,
}) async {
  final migrations = buildMigrations();

  if (migrations.isEmpty) {
    stdout.writeln(jsonEncode(const []));
    return;
  }

  final runner =
      CommandRunner<void>(
          'migrations',
          'Migration registry entrypoint',
          ansi: stdout.supportsAnsiEscapes,
        )
        ..addCommand(_MigrationRegistryInfoCommand(migrations: migrations))
        ..addCommand(
          _MigrationRegistryRunCommand(
            migrations: migrations,
            buildPlan: buildPlan,
          ),
        );

  // For compatibility with existing entrypoints:
  // - If --help is passed alone, show top-level help.
  // - If args start with --dump-json or --plan-json (legacy), route to appropriate handler.
  // - If args are empty or start with other flags, default to `info`.
  // - Otherwise, treat first arg as the subcommand.

  if (args.contains('--dump-json')) {
    // Legacy: output JSON directly
    final payload = migrations.map((m) => m.toJson()).toList();
    stdout.writeln(jsonEncode(payload));
    return;
  }

  if (args.contains('--plan-json')) {
    // Legacy: build and output a specific migration plan
    final planIndex = args.indexOf('--plan-json');
    final id = MigrationId.parse(args[planIndex + 1]);
    final directionName = args[args.indexOf('--direction') + 1];
    final direction = MigrationDirection.values.byName(directionName);
    final snapshotIndex = args.indexOf('--schema-snapshot');
    SchemaSnapshot? snapshot;
    if (snapshotIndex != -1) {
      final decoded = utf8.decode(base64.decode(args[snapshotIndex + 1]));
      final payload = jsonDecode(decoded) as Map<String, Object?>;
      snapshot = SchemaSnapshot.fromJson(payload);
    }
    final plan = await buildPlan(
      id: id,
      direction: direction,
      snapshot: snapshot ?? _emptySnapshot(),
    );
    stdout.writeln(jsonEncode(plan.toJson()));
    return;
  }

  final forwarded =
      (args.isEmpty ||
          (args.first.startsWith('-') &&
              args.first != '--help' &&
              args.first != '-h'))
      ? ['info', ...args]
      : args;

  await runner.run(forwarded);
}