From c2ca428a8ed7d63c46af9de742d4fcc28efee45f Mon Sep 17 00:00:00 2001 From: Lakshya Singh Panwar Date: Mon, 22 Dec 2025 02:07:59 +0000 Subject: [PATCH 1/3] feat(db): display project name and ID when pushing migrations --- cmd/db.go | 2 +- internal/bootstrap/bootstrap.go | 2 +- internal/db/push/push.go | 19 ++++++++++++++++++- internal/db/push/push_test.go | 18 +++++++++--------- 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/cmd/db.go b/cmd/db.go index 5367436df..6f9c8719a 100644 --- a/cmd/db.go +++ b/cmd/db.go @@ -149,7 +149,7 @@ var ( Use: "push", Short: "Push new migrations to the remote database", RunE: func(cmd *cobra.Command, args []string) error { - return push.Run(cmd.Context(), dryRun, includeAll, includeRoles, includeSeed, flags.DbConfig, afero.NewOsFs()) + return push.Run(cmd.Context(), dryRun, includeAll, includeRoles, includeSeed, flags.ProjectRef, flags.DbConfig, afero.NewOsFs()) }, } diff --git a/internal/bootstrap/bootstrap.go b/internal/bootstrap/bootstrap.go index d8279d135..d75ce2cb2 100644 --- a/internal/bootstrap/bootstrap.go +++ b/internal/bootstrap/bootstrap.go @@ -121,7 +121,7 @@ func Run(ctx context.Context, starter StarterTemplate, fsys afero.Fs, options .. } policy.Reset() if err := backoff.RetryNotify(func() error { - return push.Run(ctx, false, false, true, true, config, fsys) + return push.Run(ctx, false, false, true, true, "", config, fsys) }, policy, utils.NewErrorCallback()); err != nil { return err } diff --git a/internal/db/push/push.go b/internal/db/push/push.go index 6960702d1..b970d0d09 100644 --- a/internal/db/push/push.go +++ b/internal/db/push/push.go @@ -17,10 +17,15 @@ import ( "github.com/supabase/cli/pkg/vault" ) -func Run(ctx context.Context, dryRun, ignoreVersionMismatch bool, includeRoles, includeSeed bool, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error { +func Run(ctx context.Context, dryRun, ignoreVersionMismatch bool, includeRoles, includeSeed bool, projectRef string, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error { if dryRun { fmt.Fprintln(os.Stderr, "DRY RUN: migrations will *not* be pushed to the database.") } + if len(projectRef) > 0 { + if err := printProjectInfo(ctx, projectRef); err != nil { + return err + } + } conn, err := utils.ConnectByConfig(ctx, config, options...) if err != nil { return err @@ -130,3 +135,15 @@ func confirmSeedAll(pending []migration.SeedFile) (msg string) { } return msg } + +func printProjectInfo(ctx context.Context, projectRef string) error { + resp, err := utils.GetSupabase().V1GetProjectWithResponse(ctx, projectRef) + if err != nil { + return errors.Errorf("failed to retrieve project: %w", err) + } + if resp.JSON200 == nil { + return errors.Errorf("unexpected retrieve project status %d: %s", resp.StatusCode(), string(resp.Body)) + } + fmt.Fprintln(os.Stderr, "Pushing to project", utils.Bold(resp.JSON200.Name), "("+resp.JSON200.Ref+")") + return nil +} diff --git a/internal/db/push/push_test.go b/internal/db/push/push_test.go index b5d0d2c7f..b5da97686 100644 --- a/internal/db/push/push_test.go +++ b/internal/db/push/push_test.go @@ -40,7 +40,7 @@ func TestMigrationPush(t *testing.T) { conn.Query(migration.LIST_MIGRATION_VERSION). Reply("SELECT 0") // Run test - err := Run(context.Background(), true, false, true, true, dbConfig, fsys, conn.Intercept) + err := Run(context.Background(), true, false, true, true, "", dbConfig, fsys, conn.Intercept) // Check error assert.NoError(t, err) }) @@ -54,7 +54,7 @@ func TestMigrationPush(t *testing.T) { conn.Query(migration.LIST_MIGRATION_VERSION). Reply("SELECT 0") // Run test - err := Run(context.Background(), false, false, false, false, dbConfig, fsys, conn.Intercept) + err := Run(context.Background(), false, false, false, false, "", dbConfig, fsys, conn.Intercept) // Check error assert.NoError(t, err) }) @@ -63,7 +63,7 @@ func TestMigrationPush(t *testing.T) { // Setup in-memory fs fsys := afero.NewMemMapFs() // Run test - err := Run(context.Background(), false, false, false, false, pgconn.Config{}, fsys) + err := Run(context.Background(), false, false, false, false, "", pgconn.Config{}, fsys) // Check error assert.ErrorContains(t, err, "invalid port (outside range)") }) @@ -77,7 +77,7 @@ func TestMigrationPush(t *testing.T) { conn.Query(migration.LIST_MIGRATION_VERSION). ReplyError(pgerrcode.InvalidCatalogName, `database "target" does not exist`) // Run test - err := Run(context.Background(), false, false, false, false, pgconn.Config{ + err := Run(context.Background(), false, false, false, false, "", pgconn.Config{ Host: "db.supabase.co", Port: 5432, User: "admin", @@ -104,7 +104,7 @@ func TestMigrationPush(t *testing.T) { Query(migration.INSERT_MIGRATION_VERSION, "0", "test", nil). ReplyError(pgerrcode.NotNullViolation, `null value in column "version" of relation "schema_migrations"`) // Run test - err := Run(context.Background(), false, false, false, false, dbConfig, fsys, conn.Intercept) + err := Run(context.Background(), false, false, false, false, "", dbConfig, fsys, conn.Intercept) // Check error assert.ErrorContains(t, err, `ERROR: null value in column "version" of relation "schema_migrations" (SQLSTATE 23502)`) assert.ErrorContains(t, err, "At statement: 0\n"+migration.INSERT_MIGRATION_VERSION) @@ -128,7 +128,7 @@ func TestPushAll(t *testing.T) { Query(migration.INSERT_MIGRATION_VERSION, "0", "test", nil). Reply("INSERT 0 1") // Run test - err := Run(context.Background(), false, false, true, true, dbConfig, fsys, conn.Intercept) + err := Run(context.Background(), false, false, true, true, "", dbConfig, fsys, conn.Intercept) // Check error assert.NoError(t, err) }) @@ -145,7 +145,7 @@ func TestPushAll(t *testing.T) { conn.Query(migration.LIST_MIGRATION_VERSION). Reply("SELECT 0") // Run test - err := Run(context.Background(), false, false, true, true, dbConfig, fsys, conn.Intercept) + err := Run(context.Background(), false, false, true, true, "", dbConfig, fsys, conn.Intercept) // Check error assert.ErrorIs(t, err, context.Canceled) }) @@ -161,7 +161,7 @@ func TestPushAll(t *testing.T) { conn.Query(migration.LIST_MIGRATION_VERSION). Reply("SELECT 0") // Run test - err := Run(context.Background(), false, false, true, false, dbConfig, fsys, conn.Intercept) + err := Run(context.Background(), false, false, true, false, "", dbConfig, fsys, conn.Intercept) // Check error assert.ErrorIs(t, err, os.ErrPermission) }) @@ -191,7 +191,7 @@ func TestPushAll(t *testing.T) { Query(migration.UPSERT_SEED_FILE, seedPath, digest). ReplyError(pgerrcode.NotNullViolation, `null value in column "hash" of relation "seed_files"`) // Run test - err := Run(context.Background(), false, false, false, true, dbConfig, fsys, conn.Intercept) + err := Run(context.Background(), false, false, false, true, "", dbConfig, fsys, conn.Intercept) // Check error assert.ErrorContains(t, err, `ERROR: null value in column "hash" of relation "seed_files" (SQLSTATE 23502)`) }) From b451da843933647a1b9f5fa12ffa021e9fabe65f Mon Sep 17 00:00:00 2001 From: Lakshya Singh Panwar Date: Mon, 22 Dec 2025 02:30:38 +0000 Subject: [PATCH 2/3] fix(db): use consistent message format for project info display --- internal/db/push/push.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/db/push/push.go b/internal/db/push/push.go index b970d0d09..0eccb8fdc 100644 --- a/internal/db/push/push.go +++ b/internal/db/push/push.go @@ -144,6 +144,6 @@ func printProjectInfo(ctx context.Context, projectRef string) error { if resp.JSON200 == nil { return errors.Errorf("unexpected retrieve project status %d: %s", resp.StatusCode(), string(resp.Body)) } - fmt.Fprintln(os.Stderr, "Pushing to project", utils.Bold(resp.JSON200.Name), "("+resp.JSON200.Ref+")") + fmt.Fprintf(os.Stderr, "Pushing to linked project: %s (%s)\n", utils.Aqua(resp.JSON200.Name), resp.JSON200.Ref) return nil } From d4134e3651516f796d3f2876c9fb7125267d028b Mon Sep 17 00:00:00 2001 From: Lakshya Singh Panwar Date: Tue, 23 Dec 2025 11:06:23 +0000 Subject: [PATCH 3/3] fix(db): simplify project info display by printing in flag parser --- cmd/db.go | 2 +- internal/bootstrap/bootstrap.go | 2 +- internal/db/push/push.go | 19 +------------------ internal/db/push/push_test.go | 18 +++++++++--------- internal/utils/flags/db_url.go | 1 + 5 files changed, 13 insertions(+), 29 deletions(-) diff --git a/cmd/db.go b/cmd/db.go index 6f9c8719a..5367436df 100644 --- a/cmd/db.go +++ b/cmd/db.go @@ -149,7 +149,7 @@ var ( Use: "push", Short: "Push new migrations to the remote database", RunE: func(cmd *cobra.Command, args []string) error { - return push.Run(cmd.Context(), dryRun, includeAll, includeRoles, includeSeed, flags.ProjectRef, flags.DbConfig, afero.NewOsFs()) + return push.Run(cmd.Context(), dryRun, includeAll, includeRoles, includeSeed, flags.DbConfig, afero.NewOsFs()) }, } diff --git a/internal/bootstrap/bootstrap.go b/internal/bootstrap/bootstrap.go index d75ce2cb2..d8279d135 100644 --- a/internal/bootstrap/bootstrap.go +++ b/internal/bootstrap/bootstrap.go @@ -121,7 +121,7 @@ func Run(ctx context.Context, starter StarterTemplate, fsys afero.Fs, options .. } policy.Reset() if err := backoff.RetryNotify(func() error { - return push.Run(ctx, false, false, true, true, "", config, fsys) + return push.Run(ctx, false, false, true, true, config, fsys) }, policy, utils.NewErrorCallback()); err != nil { return err } diff --git a/internal/db/push/push.go b/internal/db/push/push.go index 0eccb8fdc..6960702d1 100644 --- a/internal/db/push/push.go +++ b/internal/db/push/push.go @@ -17,15 +17,10 @@ import ( "github.com/supabase/cli/pkg/vault" ) -func Run(ctx context.Context, dryRun, ignoreVersionMismatch bool, includeRoles, includeSeed bool, projectRef string, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error { +func Run(ctx context.Context, dryRun, ignoreVersionMismatch bool, includeRoles, includeSeed bool, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error { if dryRun { fmt.Fprintln(os.Stderr, "DRY RUN: migrations will *not* be pushed to the database.") } - if len(projectRef) > 0 { - if err := printProjectInfo(ctx, projectRef); err != nil { - return err - } - } conn, err := utils.ConnectByConfig(ctx, config, options...) if err != nil { return err @@ -135,15 +130,3 @@ func confirmSeedAll(pending []migration.SeedFile) (msg string) { } return msg } - -func printProjectInfo(ctx context.Context, projectRef string) error { - resp, err := utils.GetSupabase().V1GetProjectWithResponse(ctx, projectRef) - if err != nil { - return errors.Errorf("failed to retrieve project: %w", err) - } - if resp.JSON200 == nil { - return errors.Errorf("unexpected retrieve project status %d: %s", resp.StatusCode(), string(resp.Body)) - } - fmt.Fprintf(os.Stderr, "Pushing to linked project: %s (%s)\n", utils.Aqua(resp.JSON200.Name), resp.JSON200.Ref) - return nil -} diff --git a/internal/db/push/push_test.go b/internal/db/push/push_test.go index b5da97686..b5d0d2c7f 100644 --- a/internal/db/push/push_test.go +++ b/internal/db/push/push_test.go @@ -40,7 +40,7 @@ func TestMigrationPush(t *testing.T) { conn.Query(migration.LIST_MIGRATION_VERSION). Reply("SELECT 0") // Run test - err := Run(context.Background(), true, false, true, true, "", dbConfig, fsys, conn.Intercept) + err := Run(context.Background(), true, false, true, true, dbConfig, fsys, conn.Intercept) // Check error assert.NoError(t, err) }) @@ -54,7 +54,7 @@ func TestMigrationPush(t *testing.T) { conn.Query(migration.LIST_MIGRATION_VERSION). Reply("SELECT 0") // Run test - err := Run(context.Background(), false, false, false, false, "", dbConfig, fsys, conn.Intercept) + err := Run(context.Background(), false, false, false, false, dbConfig, fsys, conn.Intercept) // Check error assert.NoError(t, err) }) @@ -63,7 +63,7 @@ func TestMigrationPush(t *testing.T) { // Setup in-memory fs fsys := afero.NewMemMapFs() // Run test - err := Run(context.Background(), false, false, false, false, "", pgconn.Config{}, fsys) + err := Run(context.Background(), false, false, false, false, pgconn.Config{}, fsys) // Check error assert.ErrorContains(t, err, "invalid port (outside range)") }) @@ -77,7 +77,7 @@ func TestMigrationPush(t *testing.T) { conn.Query(migration.LIST_MIGRATION_VERSION). ReplyError(pgerrcode.InvalidCatalogName, `database "target" does not exist`) // Run test - err := Run(context.Background(), false, false, false, false, "", pgconn.Config{ + err := Run(context.Background(), false, false, false, false, pgconn.Config{ Host: "db.supabase.co", Port: 5432, User: "admin", @@ -104,7 +104,7 @@ func TestMigrationPush(t *testing.T) { Query(migration.INSERT_MIGRATION_VERSION, "0", "test", nil). ReplyError(pgerrcode.NotNullViolation, `null value in column "version" of relation "schema_migrations"`) // Run test - err := Run(context.Background(), false, false, false, false, "", dbConfig, fsys, conn.Intercept) + err := Run(context.Background(), false, false, false, false, dbConfig, fsys, conn.Intercept) // Check error assert.ErrorContains(t, err, `ERROR: null value in column "version" of relation "schema_migrations" (SQLSTATE 23502)`) assert.ErrorContains(t, err, "At statement: 0\n"+migration.INSERT_MIGRATION_VERSION) @@ -128,7 +128,7 @@ func TestPushAll(t *testing.T) { Query(migration.INSERT_MIGRATION_VERSION, "0", "test", nil). Reply("INSERT 0 1") // Run test - err := Run(context.Background(), false, false, true, true, "", dbConfig, fsys, conn.Intercept) + err := Run(context.Background(), false, false, true, true, dbConfig, fsys, conn.Intercept) // Check error assert.NoError(t, err) }) @@ -145,7 +145,7 @@ func TestPushAll(t *testing.T) { conn.Query(migration.LIST_MIGRATION_VERSION). Reply("SELECT 0") // Run test - err := Run(context.Background(), false, false, true, true, "", dbConfig, fsys, conn.Intercept) + err := Run(context.Background(), false, false, true, true, dbConfig, fsys, conn.Intercept) // Check error assert.ErrorIs(t, err, context.Canceled) }) @@ -161,7 +161,7 @@ func TestPushAll(t *testing.T) { conn.Query(migration.LIST_MIGRATION_VERSION). Reply("SELECT 0") // Run test - err := Run(context.Background(), false, false, true, false, "", dbConfig, fsys, conn.Intercept) + err := Run(context.Background(), false, false, true, false, dbConfig, fsys, conn.Intercept) // Check error assert.ErrorIs(t, err, os.ErrPermission) }) @@ -191,7 +191,7 @@ func TestPushAll(t *testing.T) { Query(migration.UPSERT_SEED_FILE, seedPath, digest). ReplyError(pgerrcode.NotNullViolation, `null value in column "hash" of relation "seed_files"`) // Run test - err := Run(context.Background(), false, false, false, true, "", dbConfig, fsys, conn.Intercept) + err := Run(context.Background(), false, false, false, true, dbConfig, fsys, conn.Intercept) // Check error assert.ErrorContains(t, err, `ERROR: null value in column "hash" of relation "seed_files" (SQLSTATE 23502)`) }) diff --git a/internal/utils/flags/db_url.go b/internal/utils/flags/db_url.go index 3ec94073b..458f24acc 100644 --- a/internal/utils/flags/db_url.go +++ b/internal/utils/flags/db_url.go @@ -81,6 +81,7 @@ func ParseDatabaseConfig(ctx context.Context, flagSet *pflag.FlagSet, fsys afero if err := LoadProjectRef(fsys); err != nil { return err } + fmt.Fprintln(os.Stderr, "Linked project:", ProjectRef) if err := LoadConfig(fsys); err != nil { return err }