Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions internal/db/push/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ func Run(ctx context.Context, dryRun bool, config pgconn.Config, fsys afero.Fs,
return nil
}
// Push pending migrations
if !dryRun {
if err := repair.CreateMigrationTable(ctx, conn); err != nil {
return err
}
}
for _, filename := range pending {
if dryRun {
fmt.Fprintln(os.Stderr, "Would push migration "+utils.Bold(filename)+"...")
Expand Down
28 changes: 26 additions & 2 deletions internal/db/push/push_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,31 @@ func TestMigrationPush(t *testing.T) {
conn := pgtest.NewConn()
defer conn.Close(t)
conn.Query(list.LIST_MIGRATION_VERSION).
ReplyError(pgerrcode.UndefinedTable, `relation "supabase_migrations.schema_migrations" does not exist`)
ReplyError(pgerrcode.InvalidCatalogName, `database "target" does not exist`)
// Run test
err := Run(context.Background(), false, dbConfig, fsys, conn.Intercept)
// Check error
assert.ErrorContains(t, err, `ERROR: relation "supabase_migrations.schema_migrations" does not exist (SQLSTATE 42P01)`)
assert.ErrorContains(t, err, `ERROR: database "target" does not exist (SQLSTATE 3D000)`)
})

t.Run("throws error on schema create failure", func(t *testing.T) {
// Setup in-memory fs
fsys := afero.NewMemMapFs()
path := filepath.Join(utils.MigrationsDir, "0_test.sql")
require.NoError(t, afero.WriteFile(fsys, path, []byte(""), 0644))
// Setup mock postgres
conn := pgtest.NewConn()
defer conn.Close(t)
conn.Query(list.LIST_MIGRATION_VERSION).
Reply("SELECT 0").
Query(repair.CREATE_VERSION_SCHEMA).
Reply("CREATE SCHEMA").
Query(repair.CREATE_VERSION_TABLE).
ReplyError(pgerrcode.InsufficientPrivilege, "permission denied for relation supabase_migrations")
// Run test
err := Run(context.Background(), false, dbConfig, fsys, conn.Intercept)
// Check error
assert.ErrorContains(t, err, `ERROR: permission denied for relation supabase_migrations (SQLSTATE 42501)`)
})

t.Run("throws error on push failure", func(t *testing.T) {
Expand All @@ -90,6 +110,10 @@ func TestMigrationPush(t *testing.T) {
defer conn.Close(t)
conn.Query(list.LIST_MIGRATION_VERSION).
Reply("SELECT 0").
Query(repair.CREATE_VERSION_SCHEMA).
Reply("CREATE SCHEMA").
Query(repair.CREATE_VERSION_TABLE).
Reply("CREATE TABLE").
Query(repair.INSERT_MIGRATION_VERSION, "0").
ReplyError(pgerrcode.NotNullViolation, `null value in column "version" of relation "schema_migrations"`)
// Run test
Expand Down
7 changes: 7 additions & 0 deletions internal/migration/list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package list

import (
"context"
"errors"
"fmt"
"math"
"os"
Expand All @@ -11,6 +12,7 @@ import (

"github.com/charmbracelet/glamour"
"github.com/jackc/pgconn"
"github.com/jackc/pgerrcode"
"github.com/jackc/pgx/v4"
"github.com/spf13/afero"
"github.com/supabase/cli/internal/utils"
Expand Down Expand Up @@ -44,6 +46,11 @@ func loadRemoteVersions(ctx context.Context, config pgconn.Config, options ...fu
func LoadRemoteMigrations(ctx context.Context, conn *pgx.Conn) ([]string, error) {
rows, err := conn.Query(ctx, LIST_MIGRATION_VERSION)
if err != nil {
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) && pgErr.Code == pgerrcode.UndefinedTable {
// If migration history table is undefined, the remote project has no migrations
return nil, nil
}
return nil, err
}
versions := []string{}
Expand Down
7 changes: 4 additions & 3 deletions internal/migration/list/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,17 @@ func TestRemoteMigrations(t *testing.T) {
assert.ErrorContains(t, err, "invalid port (outside range)")
})

t.Run("throws error on missing schema", func(t *testing.T) {
t.Run("loads empty migrations on missing table", func(t *testing.T) {
// Setup mock postgres
conn := pgtest.NewConn()
defer conn.Close(t)
conn.Query(LIST_MIGRATION_VERSION).
ReplyError(pgerrcode.UndefinedTable, "relation \"supabase_migrations.schema_migrations\" does not exist")
// Run test
_, err := loadRemoteVersions(context.Background(), dbConfig, conn.Intercept)
versions, err := loadRemoteVersions(context.Background(), dbConfig, conn.Intercept)
// Check error
assert.ErrorContains(t, err, `ERROR: relation "supabase_migrations.schema_migrations" does not exist (SQLSTATE 42P01)`)
assert.NoError(t, err)
assert.Empty(t, versions)
})

t.Run("throws error on invalid row", func(t *testing.T) {
Expand Down