Skip to content

feat(cli): port db push, db reset, and db start to native TypeScript#5715

Draft
avallete wants to merge 21 commits into
developfrom
avallete/exciting-noyce-078f0e
Draft

feat(cli): port db push, db reset, and db start to native TypeScript#5715
avallete wants to merge 21 commits into
developfrom
avallete/exciting-noyce-078f0e

Conversation

@avallete

Copy link
Copy Markdown
Member

Ports the db push, db reset, and db start commands of the legacy CLI shell from Go-binary proxies to native TypeScript (CLI-1325), and introduces a hidden Go seam for the container-bootstrap primitives that aren't ported.

What changed

db push — fully native: pending-migration reconciliation, seed-file ops with seed_files hash tracking, [db.vault] upsert, --include-roles/--include-seed/--dry-run, against local / linked / --db-url.

db reset — native on both legs:

  • Remote (--linked / remote --db-url): drop user schemas → vault upsert → migrate + seed, --version/--last, and the Go-parity --sql-paths seed override (merged from develop, mutually exclusive with --no-seed).
  • Local (--local / local --db-url): running check, Resetting local database…, container recreate + migrate + seed via the seam, storage-gated bucket seeding (reuses the ported seed buckets core), and the Finished … on branch <branch>. line.
  • Only the niche --experimental remote schema-files path still delegates to the Go binary.

db start — native: config validation, the AssertSupabaseDbIsRunning check (prints Go's "already running" line), else container bootstrap via the seam. No status table and no cli_stack_started — those belong to the top-level supabase start, not db start.

Hidden Go seam (db __db-bootstrap) — mirrors the existing db __shadow seam. Exposes the un-ported container primitives (StartDatabase + DockerRemoveAll cleanup, the PG14/PG15 reset recreate, the storage health gate) behind --mode {start|recreate|await-storage}. The TS side orchestrates everything else (messages, version resolution, bucket seeding, the git-branch line, telemetry, --output-format shaping); the seam runs with telemetry disabled and stderr inherited, like __shadow.

Why

db start / db reset --local need container lifecycle (create/recreate, image pull, health checks, init schema, service restarts) that is impractical to reimplement in TS. The seam keeps that lifecycle in Go while moving orchestration, output parity, telemetry, and --output-format handling to native TS — matching the approach already used for db diff / db pull.

Reviewer notes

  • The seam is the only db reset/db start boundary the in-process integration suites mock; it's covered end-to-end by the cli-e2e live suite (db-reset-start.live.e2e.test.ts, run via pnpm --filter @supabase/cli-e2e test:e2e:live), which exercises the local leg against a real Docker socket and the remote db reset leg against the staging session pooler. Both describes skip the ts-next target (the next shell has no db group).
  • db reset --local recreate forwards --no-seed / --sql-paths to the seam, which applies them via the same applyDbResetSeedFlags helper db reset uses, so seed handling stays identical across local and remote.
  • The bundled supabase-go binary must be rebuilt (pnpm build:go-sidecar copies it into dist/) since the seam adds the db __db-bootstrap command.
  • docs/go-cli-porting-status.md flips db push / db reset / db start to ported; each command's SIDE_EFFECTS.md documents the files, subprocesses, DB mutations, env vars, and exit codes.

🤖 Generated with Claude Code

claude and others added 18 commits June 24, 2026 19:10
Pure 1:1 port of Go's FindPendingMigrations + GetPendingMigrations
suggestion strings (internal/migration/up, pkg/migration/apply), the
foundation for the native legacy `db push` handler.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nv8pAJ695qfNs5Btbv5v7h
Port Go's GetPendingSeeds/SeedData with a faithful fs.Glob/path.Match
matcher, sha256 dirty detection against supabase_migrations.seed_files,
and transactional seed application (pkg/migration/seed.go, file.go).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nv8pAJ695qfNs5Btbv5v7h
Port vault.UpsertVaultSecrets (literal/env-skip parity) and the
ApplyMigrations / SeedGlobals stderr-emitting loops, extracting a shared
transactional batch core from legacyApplyMigrationFile.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nv8pAJ695qfNs5Btbv5v7h
Replace the Go-proxy shim with a native Effect handler porting
internal/db/push/push.go: target mutex, config-driven skip messages,
pending-migration/seed/roles collection, dry-run, confirm prompts,
vault upsert + migration/seed/globals apply, and three output modes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nv8pAJ695qfNs5Btbv5v7h
Cover up-to-date, apply+confirm, decline/cancel, dry-run, missing-local
and missing-remote classification, --include-all, config-disabled skips,
seed apply/up-to-date/disabled, and custom roles.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nv8pAJ695qfNs5Btbv5v7h
Add vault upsert (update+create), seed dirty/no-table/glob-warning,
linked-path, no-target-flag default, apply-error, parse-error, and
remotes-override cases. Relocate vault document parsing into the vault
module with unit coverage. The lone uncovered branch is Go's unreachable
afero.Exists error wrap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nv8pAJ695qfNs5Btbv5v7h
Rewrite push/SIDE_EFFECTS.md for the native implementation and flip
db push to `ported` in go-cli-porting-status.md. De-export internal-only
helpers flagged by knip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nv8pAJ695qfNs5Btbv5v7h
Port internal/db/reset/reset.go's remote path: --version/--last
validation, drop user schemas (embedded drop.sql), vault upsert, and
MigrateAndSeed (partial migrations + seed). The local and --experimental
paths delegate to the Go binary (telemetry-disabled) as the documented
interim until the container-bootstrap seam lands. 19 integration tests,
handler at 98.7% branch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nv8pAJ695qfNs5Btbv5v7h
Rewrite reset/SIDE_EFFECTS.md for the native remote path and the
local/experimental Go delegation; mark db reset `partial` in
go-cli-porting-status.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nv8pAJ695qfNs5Btbv5v7h
Self-contained handoff covering the container-bootstrap work remaining
(hidden __db-bootstrap Go seam + native orchestration), exact Go behavior
to match, reusable helpers, build/test commands, and parity gotchas.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nv8pAJ695qfNs5Btbv5v7h
Port `supabase db start` to a native TypeScript handler. The handler validates
config, runs Go's `AssertSupabaseDbIsRunning` check (printing the "already
running" line), and otherwise delegates the container bootstrap to a new hidden
Go `db __db-bootstrap` seam that mirrors `db __shadow`: it exposes the
un-ported container primitives (StartDatabase + DockerRemoveAll cleanup, the
PG14/PG15 reset recreate, and the storage health gate) behind `--mode`.

No status table and no `cli_stack_started` event — those belong to the
top-level `supabase start`, not `db start`. `--output-format json` emits a
structured `{ status }` result; progress stays on stderr.

The TS seam service/layer (`legacy-db-bootstrap.seam.*`) shells out to the
bundled binary with telemetry disabled and stderr inherited. The recreate /
await-storage modes are landed here for the upcoming native db reset --local.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the Go delegation for local `db reset` with a native handler: assert
the db container is running, print "Resetting local database…", recreate the
container + migrate + seed via the hidden Go `db __db-bootstrap --mode recreate`
seam (forwarding `--version`/`--no-seed`), seed buckets through the storage
health gate, and print "Finished supabase db reset on branch <branch>.".

Extract the seed-buckets local path into `legacySeedBucketsRun` so reset reuses
the exact bucket-seed logic Go invokes via `buckets.Run(ctx, "", false, fsys)`,
with its machine-summary suppressed for the reset caller. Add a `--no-seed` flag
to the recreate seam mode so it disables MigrateAndSeed's seed like `db reset`.

Only the niche `--experimental` remote schema-files path still delegates to the
Go binary. Reset handler integration coverage is 98.7% branch (one unreachable
defensive guard, matching the push/reset precedent).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Real-subprocess golden-path e2e for the native db start / db reset commands,
matching the Docker-free convention of the sibling legacy e2e tests (db diff,
seed buckets): db reset's pre-split flag validations (mutually-exclusive targets,
invalid --version, --version+--last), and db start's config-parse failure that
aborts before the running check. Full container behavior is covered by the
integration suites with the bootstrap seam mocked.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Stage 3 work (native db start, native db reset --local, the hidden Go
db __db-bootstrap seam) is implemented, tested, and documented in the command
SIDE_EFFECTS.md files and go-cli-porting-status.md. The handoff note described
this as remaining/unvalidated work and is now obsolete.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ocal

Covers the one boundary the integration suites mock — the db __db-bootstrap Go
seam driving real Docker. Boots an actual local Postgres container and exercises
db start (fresh), db start (already-running, exit 0), and db reset --local
(recreate + branch line), tearing the stack down in afterAll.

Gated behind SUPABASE_E2E_DOCKER=1 (skipped by default) so it never runs in the
normal feedback loop / default e2e suite. Validated locally against Docker
29.4.0 (3/3 pass, ~60s with images cached).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…noyce-078f0e

# Conflicts:
#	apps/cli-go/cmd/db.go
#	apps/cli/docs/go-cli-porting-status.md
#	apps/cli/src/legacy/commands/db/reset/SIDE_EFFECTS.md
#	apps/cli/src/legacy/commands/db/reset/reset.handler.ts
#	apps/cli/src/legacy/commands/db/reset/reset.integration.test.ts
Adds a live-suite test in apps/cli-e2e that boots a real local Postgres
container via the compiled CLI and drives db start (fresh), db start
(already-running, idempotent), and db reset --local (recreate + branch line),
stopping the stack in finally. Runs through the cli-e2e harness against the
real Docker socket the live setup wires up, exercising the hidden
db __db-bootstrap Go seam end-to-end across the go + ts-legacy targets
(skipped for ts-next, which has no db group).

Inert on replay/PR runs (testLive skips unless CLI_E2E_MODE=live); runs under
pnpm --filter @supabase/cli-e2e test:e2e:live.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the remote (`--db-url` over the staging session pooler) leg of `db reset` to
the live suite: drop user schemas → re-apply a local migration → seed against a
real Postgres, verified via `migration list`. `db start` has no remote leg.

Fold the local-leg coverage (db start / db reset --local, real Docker seam) and
the new remote leg into one `db-reset-start.live.e2e.test.ts`, both gated to
skip the `ts-next` target (no `db` group there).

Remove the `SUPABASE_E2E_DOCKER`-gated apps/cli live test: `*.live` tests belong
in the cli-e2e live suite, which already runs only in Docker-available
environments (gated by `CLI_E2E_MODE=live`); a separate env flag was the wrong
pattern and duplicated this coverage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@avallete

Copy link
Copy Markdown
Member Author

@codex review

`go generate` (oapi-codegen against the live Management API spec) adds the new
`storage.purge_cache` entitlement and the `Features.PurgeCache` field on the
storage config request/response. Regenerate `pkg/api/types.gen.go` and add the
matching `PurgeCache` field to the hand-built `UpdateStorageConfigBody.Features`
literal in `pkg/config/storage.go` so the package still compiles.

Fixes the Codegen CI check (`go generate` left the committed `pkg` dirty). Pure
spec sync — `PurgeCache` is nil + omitempty, so serialized request bodies are
unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 73252bd3a5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/cli/src/legacy/commands/db/shared/legacy-db-bootstrap.seam.layer.ts Outdated
Comment thread apps/cli/src/legacy/commands/db/shared/legacy-seed-ops.ts Outdated
Comment thread apps/cli/src/legacy/commands/db/reset/reset.handler.ts
Comment thread apps/cli/src/legacy/commands/db/shared/legacy-seed-ops.ts
Comment thread apps/cli/src/legacy/commands/db/reset/reset.handler.ts
Comment thread apps/cli/src/legacy/commands/db/reset/reset.command.ts
Comment thread apps/cli/src/legacy/commands/db/reset/reset.handler.ts Outdated
Comment thread apps/cli/src/legacy/commands/db/reset/reset.handler.ts
Comment thread apps/cli/src/legacy/commands/db/reset/reset.handler.ts Outdated
avallete and others added 2 commits June 26, 2026 18:28
- Honor SUPABASE_EXPERIMENTAL (not just --experimental) on db reset via
  legacyResolveExperimental, and forward --experimental into the db __db-bootstrap
  seam so the local recreate's MigrateAndSeed takes Go's experimental schema-file
  path on a versionless reset/start.
- Preserve absolute seed paths in legacyGetPendingSeeds/globOne/legacySeedData
  (Go only prefixes relative patterns with the supabase dir).
- Reject a negative --last (Go declares it UintVar; cobra rejects at parse).
- Create the supabase_migrations schema before seed_files, matching Go's
  CreateSeedTable, so seed-only runs don't fail on a missing schema.
- Keep bucket seeding non-interactive during db reset (Go's
  buckets.Run(ctx, "", false, fsys)) via a new interactive flag threaded through
  legacySeedBucketsRun and legacyPromptYesNo.
- Cache the linked project before the delegated --experimental reset (Go's
  PersistentPostRun runs even though the delegated child has telemetry disabled).
- Record --sql-paths in reset telemetry (flags map + value-consuming set).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@avallete

Copy link
Copy Markdown
Member Author

@codex review again

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants