feat(supabase): Supabase first-class support#156
Merged
jasdeepkhalsa merged 4 commits intomasterfrom Mar 26, 2026
Merged
Conversation
…and local stack diff
Phase 1 — Supabase-native migration format
- Add MigrationFile::scaffoldSupabase() for plain {version}_{desc}.sql files (no DOWN)
- Add --format=native|supabase option to migration:new with auto-detection fallback
- Add MigrationHistory::getSupabaseAppliedVersions() querying supabase_migrations.schema_migrations
- Add MigrationRunner::getSupabaseAppliedVersions() delegator
- Add 'Supa?' column to migration:status output when inside a Supabase project
Phase 4 — Zero-config Supabase project detection
- Add SupabaseProjectDetector: walks up dirs for supabase/config.toml,
resolves migrations dir, and reads local DB URL via `supabase status --output json`
- MigrationConfig auto-sets migrationsDir and migrationFormat='supabase' on detection;
explicit CLI flags and YAML overrides always take precedence
- DiffCommand auto-fills --server1-url from local Supabase stack when no connection given
- Support migrations.format key in dbdiff.yml / dbdiff.yml.example
Docs + tests
- Update README with migration file formats table, auto-detection section,
and Supabase diff examples
- Update dbdiff.yml.example with migrations.format key
- Add SupabaseProjectDetectorTest (filesystem mocks, no DB)
- Extend MigrationFileTest with scaffoldSupabase() coverage
- Extend MigrationConfigTest with Supabase auto-detection and override tests
- Extend MigrationHistoryTest with getSupabaseAppliedVersions() safety tests
- Extend test-supabase CI job with getSupabaseAppliedVersions() integration step
and unit test run step
1. Dual-write: migration:up/down now syncs to supabase_migrations.schema_migrations 2. Env var fallback: SUPABASE_DB_URL → DATABASE_URL → DIRECT_URL auto-detected 3. config.toml parsing: local DB credentials extracted from supabase/config.toml 4. Drift detection: migration:status shows divergence between DBDiff and Supabase history 5. Supabase-aware down: clear error message for UP-only supabase-format migrations 6. Transaction lint: warns when BEGIN/COMMIT found in supabase migrations (auto-wrapped) 7. Remote DSN from supabase link: reads .supabase/temp/project-ref to build remote URL Tests: 409 passing (708 assertions), 27 new test methods across 4 test files
MigrationStatusCommand (complexity 22 → ~6): - Extract formatState(), buildTable(), renderDriftWarnings() helpers - execute() now delegates to focused single-purpose methods SupabaseProjectDetector: - Extract public extractTomlSection() — reusable TOML section parser - Extract public parseTomlDbSection() — reusable [db] key-value parser - configTomlDbUrl() reduced from 4 returns/complexity-17 to 2 returns/~4 - Remove unused $sectionEnd variable - Rename $password → $dbPass (eliminates hardcoded-credential false positive) - resolveDbUrl() reduced from 4 returns to 1 via null-coalescing chain Tests: 417 passing (720 assertions), 8 new tests for extracted helpers
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Supabase first-class support
Adds zero-config Supabase project detection and a native Supabase migration
file format, so DBDiff works seamlessly inside any Supabase project without
any manual configuration.
This PR closes all remaining gaps in DBDiff's Supabase integration.
What's changed
1. Dual-write to
supabase_migrations.schema_migrationsmigration:upandmigration:downnow keep Supabase's own history table in sync. When running against a PostgreSQL target identified as a Supabase project, every applied migration is also written intosupabase_migrations.schema_migrations(withON CONFLICT DO NOTHING), and rolled-back migrations are pruned from it. This meanssupabase db pulland other Supabase CLI commands will see the same history as DBDiff.2. Environment variable fallback for DSN resolution
When no explicit
source/targetDSN is provided, DBDiff checksSUPABASE_DB_URL→DATABASE_URL→DIRECT_URLin order. This covers CI environments (GitHub Actions, Vercel, Netlify, Railway, Fly.io) where the DSN is injected as an env var with no config change required.3.
supabase/config.tomlparsingIf no DSN is found via env vars or
supabase status, DBDiff parses the[db]section ofsupabase/config.tomlto extractport(default54322) andpassword(defaultpostgres) and constructspostgresql://postgres:{password}@127.0.0.1:{port}/postgres. Supports quoted and unquoted values.4. Drift detection in
migration:statusmigration:statusnow compares DBDiff's_dbdiff_migrationstable against Supabase'ssupabase_migrations.schema_migrationsand reports divergence:5. Supabase-aware rollback error
migration:downnow gives a clear, actionable error forsupabase-format migrations rather than silently failing:6. Transaction lint for Supabase migrations
Before applying each
supabase-format migration, DBDiff lints the SQL forBEGIN/COMMIT/ROLLBACK/START TRANSACTION/SET TRANSACTION. Supabase wraps every migration in a transaction automatically, so manual transaction statements cause errors. Warnings are surfaced in the migration result and displayed to the user, with SQL comments stripped before analysis to avoid false positives.7. Remote DSN auto-detection from
supabase linkAfter running
supabase link, the linked project ref is recorded in.supabase/temp/project-ref. DBDiff reads this and constructs the remote DSN automatically:postgresql://postgres.{ref}:{password}@aws-0-{region}.pooler.supabase.com:6543/postgrespostgresql://postgres:{password}@db.{ref}.supabase.co:5432/postgresPassword is resolved from the
SUPABASE_DB_PASSWORDenv var or falls back to a[YOUR-PASSWORD]placeholder. The full resolution chain (resolveDbUrl) is: env vars →supabase status→config.toml.SonarQube compliance
All new code passes SonarQube analysis:
MigrationStatusCommand::execute— cognitive complexity reduced from 22 → ~6 by extractingformatState(),buildTable(), andrenderDriftWarnings()helpersSupabaseProjectDetector::configTomlDbUrl— complexity reduced from 17 → ~4, returns from 4 → 2, unused variable removed, credential false-positive eliminated by extractingextractTomlSection()andparseTomlDbSection()as reusable public helpersSupabaseProjectDetector::resolveDbUrl— returns reduced from 4 → 1 via null-coalescing chainFiles changed
src/Migration/Config/SupabaseProjectDetector.phpenvDbUrl(),extractTomlSection(),parseTomlDbSection(),configTomlDbUrl(),linkedProjectRef(),remoteDbUrl(),resolveDbUrl()src/Migration/Runner/MigrationHistory.php$supabaseSyncflag,syncToSupabase(),unsyncFromSupabase()src/Migration/Runner/MigrationRunner.phpsrc/Migration/Runner/MigrationFile.phplintSupabaseTransaction()src/Migration/Command/MigrationStatusCommand.phpformatState(),buildTable(),renderDriftWarnings(), simplifiedexecute()src/Migration/Command/DiffCommand.phpresolveDbUrl()chaintests/Migration/Config/SupabaseProjectDetectorTest.phptests/Migration/Runner/MigrationFileTest.phptests/Migration/Runner/MigrationHistoryTest.phptests/Migration/Runner/MigrationRunnerTest.phpTesting
All new functionality is covered by 35 new test methods. Tests run via PHP 8.3 on SQLite (unit) and are CI-compatible.
Usage examples