-
Notifications
You must be signed in to change notification settings - Fork 511
feat(cli): add schema-first schema and migrations commands #6274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: avallete/main-db-baseline-restore
Are you sure you want to change the base?
Changes from all commits
77aa3fc
2866313
836b871
fb07560
a51494f
c732def
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import { Command } from "effect/unstable/cli"; | ||
| import { withJsonErrorHandling } from "../../../../shared/output/json-error-handling.ts"; | ||
| import { withLegacyCommandInstrumentation } from "../../../telemetry/legacy-command-instrumentation.ts"; | ||
| import { legacySchemaRuntimeLayer } from "../../../schema/legacy-schema-runtime.layer.ts"; | ||
| import { legacyMigrationsApply } from "./apply.handler.ts"; | ||
|
|
||
| export const legacyMigrationsApplyCommand = Command.make("apply").pipe( | ||
| Command.withDescription("Apply exact pending migration files to the local database."), | ||
| Command.withShortDescription("Apply pending migrations locally"), | ||
| Command.withHandler(() => | ||
| legacyMigrationsApply().pipe(withLegacyCommandInstrumentation(), withJsonErrorHandling), | ||
| ), | ||
| Command.provide(legacySchemaRuntimeLayer(["migrations", "apply"])), | ||
| ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import { Effect } from "effect"; | ||
| import { applyMigrations } from "../../../../shared/migrations/apply-migrations.ts"; | ||
| import { renderSchemaResult } from "../../../../shared/schema/schema-render.ts"; | ||
|
|
||
| export const legacyMigrationsApply = Effect.fn("legacy.migrations.apply")(function* () { | ||
| const result = yield* applyMigrations(); | ||
| yield* renderSchemaResult("Apply migrations", result); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import { Command, Flag } from "effect/unstable/cli"; | ||
| import type * as CliCommand from "effect/unstable/cli/Command"; | ||
| import { withJsonErrorHandling } from "../../../../shared/output/json-error-handling.ts"; | ||
| import { withLegacyCommandInstrumentation } from "../../../telemetry/legacy-command-instrumentation.ts"; | ||
| import { legacySchemaRuntimeLayer } from "../../../schema/legacy-schema-runtime.layer.ts"; | ||
| import { legacyMigrationsDiff } from "./diff.handler.ts"; | ||
|
|
||
| const config = { | ||
| against: Flag.string("against").pipe( | ||
| Flag.withDescription("Live database to compare: local, linked, or a connection string."), | ||
| Flag.optional, | ||
| ), | ||
| file: Flag.string("file").pipe( | ||
| Flag.withDescription("Write preview SQL to a file without applying it."), | ||
| Flag.withAlias("f"), | ||
| Flag.optional, | ||
| ), | ||
| } as const; | ||
|
|
||
| export type LegacyMigrationsDiffFlags = CliCommand.Command.Config.Infer<typeof config>; | ||
|
|
||
| export const legacyMigrationsDiffCommand = Command.make("diff", config).pipe( | ||
| Command.withDescription( | ||
| "Preview the SQL required to move from migration replay to a live database.\n\n" + | ||
| "This is the successor to db diff. It never mutates the database.", | ||
| ), | ||
| Command.withShortDescription("Diff migration replay against a live database"), | ||
| Command.withExamples([ | ||
| { command: "supabase migrations diff --against local", description: "Preview local drift" }, | ||
| { command: "supabase migrations diff --against linked", description: "Preview remote drift" }, | ||
| ]), | ||
| Command.withHandler((flags) => | ||
| legacyMigrationsDiff(flags).pipe( | ||
| withLegacyCommandInstrumentation({ flags, config, aliases: { f: "file" } }), | ||
| withJsonErrorHandling, | ||
| ), | ||
| ), | ||
| Command.provide(legacySchemaRuntimeLayer(["migrations", "diff"])), | ||
| ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import { Effect, Option } from "effect"; | ||
| import { diffMigrations } from "../../../../shared/migrations/diff-migrations.ts"; | ||
| import { renderSchemaResult } from "../../../../shared/schema/schema-render.ts"; | ||
| import type { LegacyMigrationsDiffFlags } from "./diff.command.ts"; | ||
|
|
||
| export const legacyMigrationsDiff = Effect.fn("legacy.migrations.diff")(function* ( | ||
| flags: LegacyMigrationsDiffFlags, | ||
| ) { | ||
| const result = yield* diffMigrations({ | ||
| against: Option.getOrUndefined(flags.against), | ||
| file: Option.getOrUndefined(flags.file), | ||
| }); | ||
| yield* renderSchemaResult("Diff migrations", result); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import { Command, Flag } from "effect/unstable/cli"; | ||
| import type * as CliCommand from "effect/unstable/cli/Command"; | ||
| import { withJsonErrorHandling } from "../../../../shared/output/json-error-handling.ts"; | ||
| import { withLegacyCommandInstrumentation } from "../../../telemetry/legacy-command-instrumentation.ts"; | ||
| import { legacySchemaRuntimeLayer } from "../../../schema/legacy-schema-runtime.layer.ts"; | ||
| import { legacyMigrationsList } from "./list.handler.ts"; | ||
|
|
||
| const config = { | ||
| against: Flag.string("against").pipe( | ||
| Flag.withDescription("Target to compare: local, linked, or a connection string."), | ||
| Flag.optional, | ||
| ), | ||
| } as const; | ||
|
|
||
| export type LegacyMigrationsListFlags = CliCommand.Command.Config.Infer<typeof config>; | ||
|
|
||
| export const legacyMigrationsListCommand = Command.make("list", config).pipe( | ||
| Command.withDescription("Compare local migration files with target migration history."), | ||
| Command.withShortDescription("List local and remote migrations"), | ||
| Command.withHandler((flags) => | ||
| legacyMigrationsList(flags).pipe( | ||
| withLegacyCommandInstrumentation({ flags, config }), | ||
| withJsonErrorHandling, | ||
| ), | ||
| ), | ||
| Command.provide(legacySchemaRuntimeLayer(["migrations", "list"])), | ||
| ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import { Effect, Option } from "effect"; | ||
| import { listMigrations } from "../../../../shared/migrations/list-migrations.ts"; | ||
| import { renderSchemaResult } from "../../../../shared/schema/schema-render.ts"; | ||
| import type { LegacyMigrationsListFlags } from "./list.command.ts"; | ||
|
|
||
| export const legacyMigrationsList = Effect.fn("legacy.migrations.list")(function* ( | ||
| flags: LegacyMigrationsListFlags, | ||
| ) { | ||
| const result = yield* listMigrations({ against: Option.getOrUndefined(flags.against) }); | ||
| yield* renderSchemaResult("List migrations", result); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import { Command } from "effect/unstable/cli"; | ||
| import { SCHEMA_ECOSYSTEM_MAPPING_HELP } from "../../../shared/schema/schema-ecosystem.ts"; | ||
| import { legacyMigrationsApplyCommand } from "./apply/apply.command.ts"; | ||
| import { legacyMigrationsDiffCommand } from "./diff/diff.command.ts"; | ||
| import { legacyMigrationsListCommand } from "./list/list.command.ts"; | ||
| import { legacyMigrationsNewCommand } from "./new/new.command.ts"; | ||
| import { legacyMigrationsPullCommand } from "./pull/pull.command.ts"; | ||
| import { legacyMigrationsPushCommand } from "./push/push.command.ts"; | ||
|
|
||
| export const legacyMigrationsCommand = Command.make("migrations").pipe( | ||
| Command.withDescription( | ||
| "Advanced file-and-history database workflow.\n\n" + | ||
| "These commands operate on supabase/migrations and do not load declarative SQL. " + | ||
| "migrations push is the only path that mutates a durable remote schema.\n\n" + | ||
| SCHEMA_ECOSYSTEM_MAPPING_HELP, | ||
| ), | ||
| Command.withShortDescription("Manage migration files and history"), | ||
| Command.withSubcommands([ | ||
| legacyMigrationsNewCommand, | ||
| legacyMigrationsListCommand, | ||
| legacyMigrationsDiffCommand, | ||
| legacyMigrationsApplyCommand, | ||
| legacyMigrationsPushCommand, | ||
| legacyMigrationsPullCommand, | ||
| ]), | ||
| ); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| import { Argument, Command } from "effect/unstable/cli"; | ||
| import type * as CliCommand from "effect/unstable/cli/Command"; | ||
| import { withJsonErrorHandling } from "../../../../shared/output/json-error-handling.ts"; | ||
| import { withLegacyCommandInstrumentation } from "../../../telemetry/legacy-command-instrumentation.ts"; | ||
| import { legacySchemaRuntimeLayer } from "../../../schema/legacy-schema-runtime.layer.ts"; | ||
| import { legacyMigrationsNew } from "./new.handler.ts"; | ||
|
|
||
| const config = { | ||
| name: Argument.string("name").pipe( | ||
| Argument.withDescription("Migration name."), | ||
| Argument.optional, | ||
| ), | ||
| } as const; | ||
|
|
||
| export type LegacyMigrationsNewFlags = CliCommand.Command.Config.Infer<typeof config>; | ||
|
|
||
| export const legacyMigrationsNewCommand = Command.make("new", config).pipe( | ||
| Command.withDescription("Create an empty migration file for manual authoring."), | ||
| Command.withShortDescription("Create an empty migration"), | ||
| Command.withExamples([ | ||
| { | ||
| command: "supabase migrations new add_custom_data", | ||
| description: "Create supabase/migrations/<timestamp>_add_custom_data.sql", | ||
| }, | ||
| ]), | ||
| Command.withHandler((flags) => | ||
| legacyMigrationsNew(flags).pipe(withLegacyCommandInstrumentation(), withJsonErrorHandling), | ||
| ), | ||
| Command.provide(legacySchemaRuntimeLayer(["migrations", "new"])), | ||
| ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import { Effect, Option } from "effect"; | ||
| import { newMigration } from "../../../../shared/migrations/new-migration.ts"; | ||
| import { renderSchemaResult } from "../../../../shared/schema/schema-render.ts"; | ||
| import type { LegacyMigrationsNewFlags } from "./new.command.ts"; | ||
|
|
||
| export const legacyMigrationsNew = Effect.fn("legacy.migrations.new")(function* ( | ||
| flags: LegacyMigrationsNewFlags, | ||
| ) { | ||
| const result = yield* newMigration(Option.getOrUndefined(flags.name)); | ||
| yield* renderSchemaResult("Create migration", result); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import { Command, Flag } from "effect/unstable/cli"; | ||
| import type * as CliCommand from "effect/unstable/cli/Command"; | ||
| import { withJsonErrorHandling } from "../../../../shared/output/json-error-handling.ts"; | ||
| import { withLegacyCommandInstrumentation } from "../../../telemetry/legacy-command-instrumentation.ts"; | ||
| import { legacySchemaRuntimeLayer } from "../../../schema/legacy-schema-runtime.layer.ts"; | ||
| import { legacyMigrationsPull } from "./pull.handler.ts"; | ||
|
|
||
| const config = { | ||
| from: Flag.string("from").pipe( | ||
| Flag.withDescription("Remote database: linked or a connection string."), | ||
| Flag.optional, | ||
| ), | ||
| name: Flag.string("name").pipe( | ||
| Flag.withDescription("Name for the pulled migration file."), | ||
| Flag.optional, | ||
| ), | ||
| } as const; | ||
|
|
||
| export type LegacyMigrationsPullFlags = CliCommand.Command.Config.Infer<typeof config>; | ||
|
|
||
| export const legacyMigrationsPullCommand = Command.make("pull", config).pipe( | ||
| Command.withDescription( | ||
| "Record remote-only database state as local migration files.\n\n" + | ||
| "Does not interpret declarative SQL.", | ||
| ), | ||
| Command.withShortDescription("Pull remote schema drift into migrations"), | ||
| Command.withHandler((flags) => | ||
| legacyMigrationsPull(flags).pipe( | ||
| withLegacyCommandInstrumentation({ flags, config }), | ||
| withJsonErrorHandling, | ||
| ), | ||
| ), | ||
| Command.provide(legacySchemaRuntimeLayer(["migrations", "pull"])), | ||
| ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import { Effect, Option } from "effect"; | ||
| import { pullMigrations } from "../../../../shared/migrations/pull-migrations.ts"; | ||
| import { renderSchemaResult } from "../../../../shared/schema/schema-render.ts"; | ||
| import type { LegacyMigrationsPullFlags } from "./pull.command.ts"; | ||
|
|
||
| export const legacyMigrationsPull = Effect.fn("legacy.migrations.pull")(function* ( | ||
| flags: LegacyMigrationsPullFlags, | ||
| ) { | ||
| const result = yield* pullMigrations({ | ||
| from: Option.getOrUndefined(flags.from), | ||
| name: Option.getOrUndefined(flags.name), | ||
| }); | ||
| yield* renderSchemaResult("Pull remote migrations", result); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| import { Command, Flag } from "effect/unstable/cli"; | ||
| import type * as CliCommand from "effect/unstable/cli/Command"; | ||
| import { withJsonErrorHandling } from "../../../../shared/output/json-error-handling.ts"; | ||
| import { withLegacyCommandInstrumentation } from "../../../telemetry/legacy-command-instrumentation.ts"; | ||
| import { legacySchemaRuntimeLayer } from "../../../schema/legacy-schema-runtime.layer.ts"; | ||
| import { legacyMigrationsPush } from "./push.handler.ts"; | ||
|
|
||
| const config = { | ||
| yes: Flag.boolean("yes").pipe( | ||
| Flag.withDescription("Answer ordinary prompts. Does not skip target identity or live verify."), | ||
| Flag.withAlias("y"), | ||
| ), | ||
|
Comment on lines
+9
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For the supported persistent-flag form AGENTS.md reference: apps/cli/AGENTS.md:L340-L344 Useful? React with 👍 / 👎. |
||
| projectRef: Flag.string("project-ref").pipe( | ||
| Flag.withDescription("Must match the resolved linked project."), | ||
| Flag.optional, | ||
| ), | ||
| allowRemote: Flag.boolean("allow-remote").pipe( | ||
| Flag.withDescription("Acknowledge an unverifiable --db-url target."), | ||
| ), | ||
| dbUrl: Flag.string("db-url").pipe( | ||
| Flag.withDescription("Raw connection string. Requires --allow-remote."), | ||
| Flag.optional, | ||
| ), | ||
| skipVerify: Flag.boolean("skip-verify").pipe( | ||
| Flag.withDescription("Skip isolated-shadow declarations-ahead and remote-drift checks."), | ||
| ), | ||
| } as const; | ||
|
|
||
| export type LegacyMigrationsPushFlags = CliCommand.Command.Config.Infer<typeof config>; | ||
|
|
||
| export const legacyMigrationsPushCommand = Command.make("push", config).pipe( | ||
| Command.withDescription( | ||
| "Apply exact pending migration files to the linked platform database.\n\n" + | ||
| "This is the only CLI path that mutates durable remote schema. " + | ||
| "It fails closed when declarations are ahead of the migration head or remote drift is detected.", | ||
| ), | ||
| Command.withShortDescription("Push pending migrations to the platform"), | ||
| Command.withHandler((flags) => | ||
| legacyMigrationsPush(flags).pipe( | ||
| withLegacyCommandInstrumentation({ flags, config, aliases: { y: "yes" } }), | ||
| withJsonErrorHandling, | ||
| ), | ||
| ), | ||
| Command.provide(legacySchemaRuntimeLayer(["migrations", "push"])), | ||
| ); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neither new stable-shell command group includes a
SIDE_EFFECTS.md, so the database writes, filesystem changes, environment inputs, and failure exits introduced by these commands have no compatibility checklist. Add the required manifest for bothschemaandmigrationsrather than shipping undocumented legacy command surfaces.AGENTS.md reference: apps/cli/AGENTS.md:L185-L189
Useful? React with 👍 / 👎.