From 79b74c03983f2da28fc5d5577b2ef7f7ea1eeacf Mon Sep 17 00:00:00 2001 From: Qiao Han Date: Sun, 17 Dec 2023 15:42:38 +0800 Subject: [PATCH] chore: add stacktrace to internal errors --- internal/bans/get/get.go | 6 +- internal/bans/update/update.go | 4 +- internal/branches/create/create.go | 4 +- internal/branches/create/create_test.go | 80 +++++++++++++++++++ internal/branches/delete/delete.go | 4 +- internal/branches/disable/disable.go | 4 +- internal/branches/get/get.go | 4 +- internal/branches/list/list.go | 4 +- internal/branches/update/update.go | 4 +- internal/db/branch/create/create.go | 2 +- internal/db/branch/list/list.go | 2 +- internal/db/branch/switch_/switch_.go | 2 +- internal/db/diff/diff.go | 5 +- internal/db/diff/migra.go | 2 +- internal/db/dump/dump.go | 3 +- internal/db/lint/lint.go | 18 +++-- internal/db/pull/pull.go | 30 ++++--- internal/db/push/push.go | 4 +- internal/db/reset/reset.go | 36 ++++----- internal/db/start/start.go | 17 ++-- internal/db/test/test.go | 5 +- internal/encryption/get/get.go | 4 +- internal/encryption/update/update.go | 4 +- internal/functions/delete/delete.go | 4 +- internal/functions/deploy/deploy.go | 23 +++--- internal/functions/download/download.go | 16 ++-- internal/functions/list/list.go | 4 +- internal/functions/new/new.go | 11 +-- internal/functions/new/new_test.go | 4 +- internal/functions/serve/serve.go | 12 +-- internal/gen/keys/keys.go | 11 ++- internal/gen/types/typescript/typescript.go | 6 +- internal/hostnames/activate/activate.go | 4 +- internal/hostnames/common.go | 4 +- internal/hostnames/create/create.go | 4 +- internal/hostnames/delete/delete.go | 4 +- internal/hostnames/reverify/reverify.go | 4 +- internal/init/init.go | 26 +++--- internal/inspect/bloat/bloat.go | 3 +- internal/inspect/blocking/blocking.go | 3 +- internal/inspect/cache/cache.go | 3 +- internal/inspect/calls/calls.go | 3 +- internal/inspect/index_sizes/index_sizes.go | 3 +- internal/inspect/index_usage/index_usage.go | 3 +- internal/inspect/locks/locks.go | 3 +- .../long_running_queries.go | 3 +- internal/inspect/outliers/outliers.go | 3 +- .../replication_slots/replication_slots.go | 3 +- .../role_connections/role_connections.go | 7 +- internal/inspect/seq_scans/seq_scans.go | 3 +- .../table_index_sizes/table_index_sizes.go | 3 +- .../table_record_counts.go | 3 +- internal/inspect/table_sizes/table_sizes.go | 3 +- .../total_index_size/total_index_size.go | 3 +- .../total_table_sizes/total_table_sizes.go | 3 +- .../inspect/unused_indexes/unused_indexes.go | 3 +- internal/inspect/vacuum_stats/vacuum_stats.go | 3 +- internal/link/link.go | 34 +++----- internal/migration/list/list.go | 21 ++--- internal/migration/list/list_test.go | 2 +- internal/migration/new/new.go | 7 +- internal/migration/repair/repair.go | 21 +++-- internal/migration/squash/squash.go | 7 +- internal/orgs/create/create.go | 4 +- internal/orgs/list/list.go | 4 +- internal/postgresConfig/get/get.go | 15 +--- internal/postgresConfig/update/update.go | 2 +- internal/projects/apiKeys/api_keys.go | 4 +- internal/projects/create/create.go | 4 +- internal/projects/delete/delete.go | 6 +- internal/projects/list/list.go | 4 +- internal/restrictions/get/get.go | 3 - internal/restrictions/update/update.go | 2 +- internal/secrets/list/list.go | 4 +- internal/secrets/set/set.go | 6 +- internal/secrets/unset/unset.go | 4 +- internal/services/services.go | 6 +- internal/snippets/download/download.go | 4 +- internal/snippets/list/list.go | 4 +- internal/ssl_enforcement/get/get.go | 3 - internal/ssl_enforcement/update/update.go | 4 +- internal/sso/create/create.go | 2 +- internal/sso/internal/render/render.go | 53 ++---------- internal/sso/internal/saml/files.go | 31 +++---- internal/sso/list/list.go | 4 +- internal/sso/remove/remove.go | 2 +- internal/sso/update/update.go | 4 +- internal/start/start.go | 10 +-- internal/stop/stop.go | 15 ++-- internal/storage/client/objects.go | 26 +++--- internal/storage/cp/cp.go | 12 +-- internal/storage/mv/mv.go | 6 +- internal/storage/scheme.go | 7 +- internal/test/new/new.go | 11 +-- internal/utils/pgxv5/rows.go | 15 ++++ .../vanity_subdomains/activate/activate.go | 4 +- internal/vanity_subdomains/check/check.go | 4 +- internal/vanity_subdomains/delete/delete.go | 4 +- internal/vanity_subdomains/get/get.go | 2 +- 99 files changed, 441 insertions(+), 392 deletions(-) create mode 100644 internal/branches/create/create_test.go diff --git a/internal/bans/get/get.go b/internal/bans/get/get.go index f40a900d4..81744b786 100644 --- a/internal/bans/get/get.go +++ b/internal/bans/get/get.go @@ -18,11 +18,7 @@ func Run(ctx context.Context, projectRef string, fsys afero.Fs) error { return errors.Errorf("failed to retrieve network bans: %w", err) } if resp.JSON201 == nil { - return errors.New("failed to retrieve network bans; received: " + string(resp.Body)) - } - - if err != nil { - return err + return errors.New("Unexpected error retrieving network bans: " + string(resp.Body)) } fmt.Printf("DB banned IPs: %+v\n", resp.JSON201.BannedIpv4Addresses) return nil diff --git a/internal/bans/update/update.go b/internal/bans/update/update.go index 66868f9b0..46e3cbcac 100644 --- a/internal/bans/update/update.go +++ b/internal/bans/update/update.go @@ -36,10 +36,10 @@ func Run(ctx context.Context, projectRef string, dbIpsToUnban []string, fsys afe Ipv4Addresses: dbIpsToUnban, }) if err != nil { - return err + return errors.Errorf("failed to remove network bans: %w", err) } if resp.StatusCode() != 200 { - return errors.New("failed to remove network bans: " + string(resp.Body)) + return errors.New("Unexpected error removing network bans: " + string(resp.Body)) } fmt.Printf("Successfully removed bans for %+v.\n", dbIpsToUnban) return nil diff --git a/internal/branches/create/create.go b/internal/branches/create/create.go index 403e74d92..6ffba6773 100644 --- a/internal/branches/create/create.go +++ b/internal/branches/create/create.go @@ -2,9 +2,9 @@ package create import ( "context" - "errors" "fmt" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/gen/keys" "github.com/supabase/cli/internal/utils" @@ -27,7 +27,7 @@ func Run(ctx context.Context, name, region string, fsys afero.Fs) error { Region: ®ion, }) if err != nil { - return err + return errors.Errorf("failed to create preview branch: %w", err) } if resp.JSON201 == nil { diff --git a/internal/branches/create/create_test.go b/internal/branches/create/create_test.go new file mode 100644 index 000000000..49b21a8c8 --- /dev/null +++ b/internal/branches/create/create_test.go @@ -0,0 +1,80 @@ +package create + +import ( + "context" + "net" + "net/http" + "os" + "testing" + + "github.com/spf13/afero" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/supabase/cli/internal/testing/apitest" + "github.com/supabase/cli/internal/testing/fstest" + "github.com/supabase/cli/internal/utils" + "github.com/supabase/cli/pkg/api" + "gopkg.in/h2non/gock.v1" +) + +func TestCreateCommand(t *testing.T) { + t.Run("creates preview branch", func(t *testing.T) { + ref := apitest.RandomProjectRef() + // Setup in-memory fs + fsys := afero.NewMemMapFs() + require.NoError(t, afero.WriteFile(fsys, utils.ProjectRefPath, []byte(ref), 0644)) + // Setup mock api + defer gock.OffAll() + gock.New(utils.DefaultApiHost). + Post("/v1/projects/" + ref + "/branches"). + Reply(http.StatusCreated). + JSON(api.BranchResponse{ + Id: "test-uuid", + }) + // Run test + err := Run(context.Background(), "", "sin", fsys) + // Check error + assert.NoError(t, err) + }) + + t.Run("throws error on permission denied", func(t *testing.T) { + // Setup in-memory fs + fsys := &fstest.OpenErrorFs{DenyPath: utils.ProjectRefPath} + // Run test + err := Run(context.Background(), "branch", "region", fsys) + // Check error + assert.ErrorIs(t, err, os.ErrPermission) + }) + + t.Run("throws error on network disconnected", func(t *testing.T) { + ref := apitest.RandomProjectRef() + // Setup in-memory fs + fsys := afero.NewMemMapFs() + require.NoError(t, afero.WriteFile(fsys, utils.ProjectRefPath, []byte(ref), 0644)) + // Setup mock api + defer gock.OffAll() + gock.New(utils.DefaultApiHost). + Post("/v1/projects/" + ref + "/branches"). + ReplyError(net.ErrClosed) + // Run test + err := Run(context.Background(), "", "sin", fsys) + // Check error + assert.ErrorIs(t, err, net.ErrClosed) + }) + + t.Run("throws error on service unavailable", func(t *testing.T) { + ref := apitest.RandomProjectRef() + // Setup in-memory fs + fsys := afero.NewMemMapFs() + require.NoError(t, afero.WriteFile(fsys, utils.ProjectRefPath, []byte(ref), 0644)) + // Setup mock api + defer gock.OffAll() + gock.New(utils.DefaultApiHost). + Post("/v1/projects/" + ref + "/branches"). + Reply(http.StatusServiceUnavailable) + // Run test + err := Run(context.Background(), "", "sin", fsys) + // Check error + assert.ErrorContains(t, err, "Unexpected error creating preview branch:") + }) +} diff --git a/internal/branches/delete/delete.go b/internal/branches/delete/delete.go index b552af8ae..28c457cb4 100644 --- a/internal/branches/delete/delete.go +++ b/internal/branches/delete/delete.go @@ -2,17 +2,17 @@ package delete import ( "context" - "errors" "fmt" "net/http" + "github.com/go-errors/errors" "github.com/supabase/cli/internal/utils" ) func Run(ctx context.Context, branchId string) error { resp, err := utils.GetSupabase().DeleteBranchWithResponse(ctx, branchId) if err != nil { - return err + return errors.Errorf("failed to delete preview branch: %w", err) } if resp.StatusCode() != http.StatusOK { return errors.New("Unexpected error deleting preview branch: " + string(resp.Body)) diff --git a/internal/branches/disable/disable.go b/internal/branches/disable/disable.go index ce84f6cc2..917585584 100644 --- a/internal/branches/disable/disable.go +++ b/internal/branches/disable/disable.go @@ -2,10 +2,10 @@ package disable import ( "context" - "errors" "fmt" "net/http" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" ) @@ -17,7 +17,7 @@ func Run(ctx context.Context, fsys afero.Fs) error { } resp, err := utils.GetSupabase().DisableBranchWithResponse(ctx, ref) if err != nil { - return err + return errors.Errorf("failed to disable preview branching: %w", err) } if resp.StatusCode() != http.StatusOK { return errors.New("Unexpected error disabling preview branching: " + string(resp.Body)) diff --git a/internal/branches/get/get.go b/internal/branches/get/get.go index ecfbf5be2..5c2453104 100644 --- a/internal/branches/get/get.go +++ b/internal/branches/get/get.go @@ -2,9 +2,9 @@ package get import ( "context" - "errors" "fmt" + "github.com/go-errors/errors" "github.com/supabase/cli/internal/migration/list" "github.com/supabase/cli/internal/utils" ) @@ -12,7 +12,7 @@ import ( func Run(ctx context.Context, branchId string) error { resp, err := utils.GetSupabase().GetBranchDetailsWithResponse(ctx, branchId) if err != nil { - return err + return errors.Errorf("failed to retrieve preview branch: %w", err) } if resp.JSON200 == nil { return errors.New("Unexpected error retrieving preview branch: " + string(resp.Body)) diff --git a/internal/branches/list/list.go b/internal/branches/list/list.go index 17451e545..3d188e9e7 100644 --- a/internal/branches/list/list.go +++ b/internal/branches/list/list.go @@ -2,10 +2,10 @@ package list import ( "context" - "errors" "fmt" "strings" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/migration/list" "github.com/supabase/cli/internal/utils" @@ -18,7 +18,7 @@ func Run(ctx context.Context, fsys afero.Fs) error { } resp, err := utils.GetSupabase().GetBranchesWithResponse(ctx, ref) if err != nil { - return err + return errors.Errorf("failed to list preview branches: %w", err) } if resp.JSON200 == nil { diff --git a/internal/branches/update/update.go b/internal/branches/update/update.go index 63e0861a1..e661c48ff 100644 --- a/internal/branches/update/update.go +++ b/internal/branches/update/update.go @@ -2,9 +2,9 @@ package update import ( "context" - "errors" "fmt" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" "github.com/supabase/cli/pkg/api" @@ -13,7 +13,7 @@ import ( func Run(ctx context.Context, branchId string, body api.UpdateBranchBody, fsys afero.Fs) error { resp, err := utils.GetSupabase().UpdateBranchWithResponse(ctx, branchId, body) if err != nil { - return err + return errors.Errorf("failed to update preview branch: %w", err) } if resp.JSON200 == nil { return errors.New("Unexpected error updating preview branch: " + string(resp.Body)) diff --git a/internal/db/branch/create/create.go b/internal/db/branch/create/create.go index fafbf1a9b..98996e8c9 100644 --- a/internal/db/branch/create/create.go +++ b/internal/db/branch/create/create.go @@ -4,7 +4,6 @@ import ( "bytes" "context" _ "embed" - "errors" "fmt" "io" "os" @@ -12,6 +11,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/stdcopy" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" ) diff --git a/internal/db/branch/list/list.go b/internal/db/branch/list/list.go index 72a8e50b5..b1037ac1b 100644 --- a/internal/db/branch/list/list.go +++ b/internal/db/branch/list/list.go @@ -1,12 +1,12 @@ package list import ( - "errors" "fmt" "io" "os" "path/filepath" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" ) diff --git a/internal/db/branch/switch_/switch_.go b/internal/db/branch/switch_/switch_.go index 111cf394f..462b26c69 100644 --- a/internal/db/branch/switch_/switch_.go +++ b/internal/db/branch/switch_/switch_.go @@ -2,11 +2,11 @@ package switch_ import ( "context" - "errors" "fmt" "os" "path/filepath" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" diff --git a/internal/db/diff/diff.go b/internal/db/diff/diff.go index 31b2f5207..281501837 100644 --- a/internal/db/diff/diff.go +++ b/internal/db/diff/diff.go @@ -6,6 +6,7 @@ import ( "fmt" "os" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/spf13/afero" "github.com/supabase/cli/internal/db/start" @@ -22,7 +23,7 @@ func SaveDiff(out, file string, fsys afero.Fs) error { } else if len(file) > 0 { path := new.GetMigrationPath(utils.GetCurrentTimestamp(), file) if err := afero.WriteFile(fsys, path, []byte(out), 0644); err != nil { - return err + return errors.Errorf("failed to save diff: %w", err) } fmt.Fprintln(os.Stderr, warnDiff) } else { @@ -63,7 +64,7 @@ func run(p utils.Program, ctx context.Context, schema []string, config pgconn.Co } defer utils.DockerRemove(shadow) if !start.WaitForHealthyService(ctx, shadow, start.HealthTimeout) { - return start.ErrDatabase + return errors.New(start.ErrDatabase) } if err := MigrateShadowDatabase(ctx, shadow, fsys); err != nil { return err diff --git a/internal/db/diff/migra.go b/internal/db/diff/migra.go index d6b954187..f429f6313 100644 --- a/internal/db/diff/migra.go +++ b/internal/db/diff/migra.go @@ -164,7 +164,7 @@ func DiffDatabase(ctx context.Context, schema []string, config pgconn.Config, w } defer utils.DockerRemove(shadow) if !start.WaitForHealthyService(ctx, shadow, start.HealthTimeout) { - return "", start.ErrDatabase + return "", errors.New(start.ErrDatabase) } if err := MigrateShadowDatabase(ctx, shadow, fsys, options...); err != nil { return "", err diff --git a/internal/db/dump/dump.go b/internal/db/dump/dump.go index 62234ffe5..c365edca6 100644 --- a/internal/db/dump/dump.go +++ b/internal/db/dump/dump.go @@ -10,6 +10,7 @@ import ( "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/network" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" @@ -30,7 +31,7 @@ func Run(ctx context.Context, path string, config pgconn.Config, schema []string if len(path) > 0 { f, err := fsys.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { - return err + return errors.Errorf("failed to open dump file: %w", err) } defer f.Close() outStream = f diff --git a/internal/db/lint/lint.go b/internal/db/lint/lint.go index 8f169570e..22519ae5c 100644 --- a/internal/db/lint/lint.go +++ b/internal/db/lint/lint.go @@ -9,6 +9,7 @@ import ( "os" "strings" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -80,13 +81,16 @@ func printResultJSON(result []Result, minLevel LintLevel, stdout io.Writer) erro // Pretty print output enc := json.NewEncoder(stdout) enc.SetIndent("", " ") - return enc.Encode(filtered) + if err := enc.Encode(filtered); err != nil { + return errors.Errorf("failed to print result json: %w", err) + } + return nil } func LintDatabase(ctx context.Context, conn *pgx.Conn, schema []string) ([]Result, error) { tx, err := conn.Begin(ctx) if err != nil { - return nil, err + return nil, errors.Errorf("failed to begin transaction: %w", err) } if len(schema) == 0 { schema, err = diff.LoadUserSchemas(ctx, conn, utils.InternalSchemas...) @@ -101,7 +105,7 @@ func LintDatabase(ctx context.Context, conn *pgx.Conn, schema []string) ([]Resul } }() if _, err := conn.Exec(ctx, ENABLE_PGSQL_CHECK); err != nil { - return nil, err + return nil, errors.Errorf("failed to enable pgsql_check: %w", err) } // Batch prepares statements batch := pgx.Batch{} @@ -115,18 +119,18 @@ func LintDatabase(ctx context.Context, conn *pgx.Conn, schema []string) ([]Resul fmt.Fprintln(os.Stderr, "Linting schema:", s) rows, err := br.Query() if err != nil { - return nil, err + return nil, errors.Errorf("failed to query rows: %w", err) } // Parse result row for rows.Next() { var name string var data []byte if err := rows.Scan(&name, &data); err != nil { - return nil, err + return nil, errors.Errorf("failed to scan rows: %w", err) } var r Result if err := json.Unmarshal(data, &r); err != nil { - return nil, err + return nil, errors.Errorf("failed to marshal json: %w", err) } // Update function name r.Function = s + "." + name @@ -134,7 +138,7 @@ func LintDatabase(ctx context.Context, conn *pgx.Conn, schema []string) ([]Resul } err = rows.Err() if err != nil { - return nil, err + return nil, errors.Errorf("failed to parse rows: %w", err) } } return result, nil diff --git a/internal/db/pull/pull.go b/internal/db/pull/pull.go index 9285c5a2c..cebf1c0bc 100644 --- a/internal/db/pull/pull.go +++ b/internal/db/pull/pull.go @@ -3,10 +3,10 @@ package pull import ( "context" _ "embed" - "errors" "fmt" "os" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgerrcode" "github.com/jackc/pgx/v4" @@ -20,10 +20,15 @@ import ( ) var ( - errConflict = errors.New("The remote database's migration history is not in sync with the contents of " + utils.Bold(utils.MigrationsDir) + `. Resolve this by: -- Updating the project from version control to get the latest ` + utils.Bold(utils.MigrationsDir) + `, -- Pushing unapplied migrations with ` + utils.Aqua("supabase db push") + `, -- Or failing that, manually editing supabase_migrations.schema_migrations table with ` + utils.Aqua("supabase migration repair") + ".") + errConflict = errors.Errorf(`The remote database's migration history is not in sync with the contents of %s. Resolve this by: +- Updating the project from version control to get the latest %s, +- Pushing unapplied migrations with %s, +- Or failing that, manually editing supabase_migrations.schema_migrations table with %s.`, + utils.Bold(utils.MigrationsDir), + utils.Bold(utils.MigrationsDir), + utils.Aqua("supabase db push"), + utils.Aqua("supabase migration repair"), + ) errMissing = errors.New("no migrations found") errInSync = errors.New("no schema changes found") ) @@ -82,7 +87,7 @@ func dumpRemoteSchema(p utils.Program, ctx context.Context, path string, config p.Send(utils.StatusMsg("Dumping schema from remote database...")) f, err := fsys.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { - return err + return errors.Errorf("failed to open dump file: %w", err) } defer f.Close() return dump.DumpSchema(ctx, config, nil, false, false, f) @@ -96,9 +101,12 @@ func diffRemoteSchema(p utils.Program, ctx context.Context, schema []string, pat return err } if len(output) == 0 { - return errInSync + return errors.New(errInSync) + } + if err := afero.WriteFile(fsys, path, []byte(output), 0644); err != nil { + return errors.Errorf("failed to write dump file: %w", err) } - return afero.WriteFile(fsys, path, []byte(output), 0644) + return nil } func assertRemoteInSync(ctx context.Context, conn *pgx.Conn, fsys afero.Fs) error { @@ -115,18 +123,18 @@ func assertRemoteInSync(ctx context.Context, conn *pgx.Conn, fsys afero.Fs) erro } if len(remoteMigrations) != len(localMigrations) { - return errConflict + return errors.New(errConflict) } for i, remoteTimestamp := range remoteMigrations { // LoadLocalMigrations guarantees we always have a match localTimestamp := utils.MigrateFilePattern.FindStringSubmatch(localMigrations[i])[1] if localTimestamp != remoteTimestamp { - return errConflict + return errors.New(errConflict) } } if len(localMigrations) == 0 { - return errMissing + return errors.New(errMissing) } return nil } diff --git a/internal/db/push/push.go b/internal/db/push/push.go index 4bd2ef141..a640e907d 100644 --- a/internal/db/push/push.go +++ b/internal/db/push/push.go @@ -2,11 +2,11 @@ package push import ( "context" - "errors" "fmt" "io" "os" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -63,7 +63,7 @@ func CreateCustomRoles(ctx context.Context, conn *pgx.Conn, w io.Writer, fsys af if errors.Is(err, os.ErrNotExist) { return nil } else if err != nil { - return err + return errors.Errorf("failed to load custom roles: %w", err) } fmt.Fprintln(w, "Creating custom roles "+utils.Bold(utils.CustomRolesPath)+"...") return apply.BatchExecDDL(ctx, conn, roles) diff --git a/internal/db/reset/reset.go b/internal/db/reset/reset.go index 6736d6a80..d772abf13 100644 --- a/internal/db/reset/reset.go +++ b/internal/db/reset/reset.go @@ -26,6 +26,7 @@ import ( "github.com/supabase/cli/internal/migration/repair" "github.com/supabase/cli/internal/status" "github.com/supabase/cli/internal/utils" + "github.com/supabase/cli/internal/utils/pgxv5" ) const ( @@ -51,7 +52,7 @@ func Run(ctx context.Context, version string, config pgconn.Config, fsys afero.F } if !utils.IsLoopback(config.Host) { if shouldReset := utils.PromptYesNo("Confirm resetting the remote database?", true, os.Stdin); !shouldReset { - return context.Canceled + return errors.New(context.Canceled) } return resetRemote(ctx, version, config, fsys, options...) } @@ -116,10 +117,10 @@ func resetDatabase14(ctx context.Context, version string, fsys afero.Fs, options func resetDatabase15(ctx context.Context, version string, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error { if err := utils.Docker.ContainerRemove(ctx, utils.DbId, types.ContainerRemoveOptions{Force: true}); err != nil { - return err + return errors.Errorf("failed to remove container: %w", err) } if err := utils.Docker.VolumeRemove(ctx, utils.DbId, true); err != nil { - return err + return errors.Errorf("failed to remove volume: %w", err) } // Skip syslog if vector container is not started if _, err := utils.Docker.ContainerInspect(ctx, utils.VectorId); err != nil { @@ -139,7 +140,7 @@ func resetDatabase15(ctx context.Context, version string, fsys afero.Fs, options return err } if !start.WaitForHealthyService(ctx, utils.DbId, start.HealthTimeout) { - return start.ErrDatabase + return errors.New(start.ErrDatabase) } conn, err := utils.ConnectLocalPostgres(ctx, pgconn.Config{}, options...) if err != nil { @@ -191,12 +192,14 @@ func DisconnectClients(ctx context.Context, conn *pgx.Conn) error { if _, err := conn.Exec(ctx, disconn); err != nil { var pgErr *pgconn.PgError if errors.As(err, &pgErr) && pgErr.Code != pgerrcode.InvalidCatalogName { - return err + return errors.Errorf("failed to disconnect clients: %w", err) } } term := fmt.Sprintf(utils.TerminateDbSqlFmt, "postgres") - _, err := conn.Exec(ctx, term) - return err + if _, err := conn.Exec(ctx, term); err != nil { + return errors.Errorf("failed to terminate backend: %w", err) + } + return nil } func RestartDatabase(ctx context.Context, w io.Writer) error { @@ -204,10 +207,10 @@ func RestartDatabase(ctx context.Context, w io.Writer) error { // Some extensions must be manually restarted after pg_terminate_backend // Ref: https://github.com/citusdata/pg_cron/issues/99 if err := utils.Docker.ContainerRestart(ctx, utils.DbId, container.StopOptions{}); err != nil { - return err + return errors.Errorf("failed to restart container: %w", err) } if !start.WaitForHealthyService(ctx, utils.DbId, start.HealthTimeout) { - return start.ErrDatabase + return errors.New(start.ErrDatabase) } return restartServices(ctx) } @@ -287,19 +290,14 @@ func resetRemote(ctx context.Context, version string, config pgconn.Config, fsys func ListSchemas(ctx context.Context, conn *pgx.Conn, exclude ...string) ([]string, error) { exclude = likeEscapeSchema(exclude) + if len(exclude) == 0 { + exclude = append(exclude, "") + } rows, err := conn.Query(ctx, LIST_SCHEMAS, exclude) if err != nil { - return nil, err - } - schemas := []string{} - for rows.Next() { - var name string - if err := rows.Scan(&name); err != nil { - return nil, err - } - schemas = append(schemas, name) + return nil, errors.Errorf("failed to list schemas: %w", err) } - return schemas, rows.Err() + return pgxv5.CollectStrings(rows) } func likeEscapeSchema(schemas []string) (result []string) { diff --git a/internal/db/start/start.go b/internal/db/start/start.go index 3a09ba89d..95cfa85ec 100644 --- a/internal/db/start/start.go +++ b/internal/db/start/start.go @@ -3,11 +3,9 @@ package start import ( "context" _ "embed" - "errors" "fmt" "io" "os" - "path/filepath" "strconv" "strings" "time" @@ -16,6 +14,7 @@ import ( "github.com/docker/docker/api/types/network" "github.com/docker/docker/client" "github.com/docker/go-connections/nat" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -137,7 +136,7 @@ func StartDatabase(ctx context.Context, fsys afero.Fs, w io.Writer, options ...f return err } if !WaitForHealthyService(ctx, utils.DbId, HealthTimeout) { - return ErrDatabase + return errors.New(ErrDatabase) } // Initialize if we are on PG14 and there's no existing db volume if noBackupVolume { @@ -181,14 +180,12 @@ func WithSyslogConfig(hostConfig container.HostConfig) container.HostConfig { func initCurrentBranch(fsys afero.Fs) error { // Create _current_branch file to avoid breaking db branch commands - if _, err := fsys.Stat(utils.CurrBranchPath); err == nil || !errors.Is(err, os.ErrNotExist) { - return err - } - branchDir := filepath.Dir(utils.CurrBranchPath) - if err := utils.MkdirIfNotExistFS(fsys, branchDir); err != nil { - return err + if _, err := fsys.Stat(utils.CurrBranchPath); err == nil { + return nil + } else if !errors.Is(err, os.ErrNotExist) { + return errors.Errorf("failed init current branch: %w", err) } - return afero.WriteFile(fsys, utils.CurrBranchPath, []byte("main"), 0644) + return utils.WriteFile(utils.CurrBranchPath, []byte("main"), fsys) } func initSchema(ctx context.Context, conn *pgx.Conn, host string, w io.Writer) error { diff --git a/internal/db/test/test.go b/internal/db/test/test.go index a1e083f6e..8afd1aee6 100644 --- a/internal/db/test/test.go +++ b/internal/db/test/test.go @@ -10,6 +10,7 @@ import ( "path/filepath" "github.com/docker/docker/api/types" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" ) @@ -38,10 +39,10 @@ func pgProve(ctx context.Context, dstPath string, fsys afero.Fs) error { // Copy tests into database container var buf bytes.Buffer if err := compress(utils.DbTestsDir, &buf, fsys); err != nil { - return err + return errors.Errorf("failed to compress directory: %w", err) } if err := utils.Docker.CopyToContainer(ctx, utils.DbId, dstPath, &buf, types.CopyToContainerOptions{}); err != nil { - return err + return errors.Errorf("failed to copy into container: %w", err) } // Passing in script string means command line args must be set manually, ie. "$@" args := "set -- " + filepath.ToSlash(utils.DbTestsDir) + ";" diff --git a/internal/encryption/get/get.go b/internal/encryption/get/get.go index 5525d93a3..6aa1f059c 100644 --- a/internal/encryption/get/get.go +++ b/internal/encryption/get/get.go @@ -2,16 +2,16 @@ package get import ( "context" - "errors" "fmt" + "github.com/go-errors/errors" "github.com/supabase/cli/internal/utils" ) func Run(ctx context.Context, projectRef string) error { resp, err := utils.GetSupabase().GetPgsodiumConfigWithResponse(ctx, projectRef) if err != nil { - return err + return errors.Errorf("failed to retrieve pgsodium config: %w", err) } if resp.JSON200 == nil { diff --git a/internal/encryption/update/update.go b/internal/encryption/update/update.go index 2ee99fc68..b86efde97 100644 --- a/internal/encryption/update/update.go +++ b/internal/encryption/update/update.go @@ -2,11 +2,11 @@ package update import ( "context" - "errors" "fmt" "os" "strings" + "github.com/go-errors/errors" "github.com/supabase/cli/internal/utils" "github.com/supabase/cli/internal/utils/credentials" "github.com/supabase/cli/pkg/api" @@ -19,7 +19,7 @@ func Run(ctx context.Context, projectRef string, stdin *os.File) error { RootKey: strings.TrimSpace(input), }) if err != nil { - return err + return errors.Errorf("failed to update pgsodium config: %w", err) } if resp.JSON200 == nil { diff --git a/internal/functions/delete/delete.go b/internal/functions/delete/delete.go index bd9c782a6..63b710590 100644 --- a/internal/functions/delete/delete.go +++ b/internal/functions/delete/delete.go @@ -2,10 +2,10 @@ package delete import ( "context" - "errors" "fmt" "net/http" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" ) @@ -21,7 +21,7 @@ func Run(ctx context.Context, slug string, projectRef string, fsys afero.Fs) err // 2. Delete Function. resp, err := utils.GetSupabase().DeleteFunctionWithResponse(ctx, projectRef, slug) if err != nil { - return err + return errors.Errorf("failed to delete function: %w", err) } switch resp.StatusCode() { case http.StatusNotFound: diff --git a/internal/functions/deploy/deploy.go b/internal/functions/deploy/deploy.go index e92b86721..8b638660f 100644 --- a/internal/functions/deploy/deploy.go +++ b/internal/functions/deploy/deploy.go @@ -3,7 +3,6 @@ package deploy import ( "bytes" "context" - "errors" "fmt" "io" "net/http" @@ -15,6 +14,7 @@ import ( "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/network" "github.com/docker/go-units" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/spf13/viper" "github.com/supabase/cli/internal/db/start" @@ -59,7 +59,7 @@ func getFunctionSlugs(fsys afero.Fs) ([]string, error) { pattern := filepath.Join(utils.FunctionsDir, "*", "index.ts") paths, err := afero.Glob(fsys, pattern) if err != nil { - return nil, err + return nil, errors.Errorf("failed to glob function slugs: %w", err) } var slugs []string for _, path := range paths { @@ -74,14 +74,13 @@ func getFunctionSlugs(fsys afero.Fs) ([]string, error) { func bundleFunction(ctx context.Context, slug, dockerEntrypointPath, importMapPath string, fsys afero.Fs) (*bytes.Buffer, error) { cwd, err := os.Getwd() if err != nil { - return nil, err + return nil, errors.Errorf("failed to get working directory: %w", err) } // create temp directory to store generated eszip hostOutputDir := filepath.Join(utils.TempDir, fmt.Sprintf(".output_%s", slug)) - err = fsys.MkdirAll(hostOutputDir, 0755) - if err != nil { - return nil, err + if err := fsys.MkdirAll(hostOutputDir, 0755); err != nil { + return nil, errors.Errorf("failed to mkdir: %w", err) } defer func() { if err := fsys.RemoveAll(hostOutputDir); err != nil { @@ -134,7 +133,7 @@ func bundleFunction(ctx context.Context, slug, dockerEntrypointPath, importMapPa eszipBytes, err := fsys.Open(filepath.Join(hostOutputDir, "output.eszip")) if err != nil { - return nil, err + return nil, errors.Errorf("failed to open eszip: %w", err) } defer eszipBytes.Close() @@ -144,7 +143,7 @@ func bundleFunction(ctx context.Context, slug, dockerEntrypointPath, importMapPa _, err = io.Copy(brw, eszipBytes) if err != nil { - return nil, err + return nil, errors.Errorf("failed to compress brotli: %w", err) } return compressedBuf, nil @@ -153,7 +152,7 @@ func bundleFunction(ctx context.Context, slug, dockerEntrypointPath, importMapPa func deployFunction(ctx context.Context, projectRef, slug, entrypointUrl, importMapUrl string, verifyJWT bool, functionBody io.Reader) error { resp, err := utils.GetSupabase().GetFunctionWithResponse(ctx, projectRef, slug) if err != nil { - return err + return errors.Errorf("failed to retrieve function: %w", err) } switch resp.StatusCode() { @@ -166,7 +165,7 @@ func deployFunction(ctx context.Context, projectRef, slug, entrypointUrl, import EntrypointPath: &entrypointUrl, }, eszipContentType, functionBody) if err != nil { - return err + return errors.Errorf("failed to create function: %w", err) } if resp.JSON201 == nil { return errors.New("Failed to create a new Function on the Supabase project: " + string(resp.Body)) @@ -178,7 +177,7 @@ func deployFunction(ctx context.Context, projectRef, slug, entrypointUrl, import EntrypointPath: &entrypointUrl, }, eszipContentType, functionBody) if err != nil { - return err + return errors.Errorf("failed to update function: %w", err) } if resp.JSON200 == nil { return errors.New("Failed to update an existing Function's body on the Supabase project: " + string(resp.Body)) @@ -210,7 +209,7 @@ func deployOne(ctx context.Context, slug, projectRef, importMapPath string, noVe if importMapPath == "" { resolved, err = filepath.Abs(utils.FallbackImportMapPath) if err != nil { - return err + return errors.Errorf("failed to resolve absolute path: %w", err) } } exists, _ := afero.Exists(fsys, resolved) diff --git a/internal/functions/download/download.go b/internal/functions/download/download.go index 1b0283a01..4d6be9fd0 100644 --- a/internal/functions/download/download.go +++ b/internal/functions/download/download.go @@ -53,7 +53,7 @@ func RunLegacy(ctx context.Context, slug string, projectRef string, fsys afero.F func getFunctionMetadata(ctx context.Context, projectRef, slug string) (*api.FunctionSlugResponse, error) { resp, err := utils.GetSupabase().GetFunctionWithResponse(ctx, projectRef, slug) if err != nil { - return nil, err + return nil, errors.Errorf("failed to get function metadata: %w", err) } switch resp.StatusCode() { @@ -88,7 +88,7 @@ func downloadFunction(ctx context.Context, projectRef, slug, extractScriptPath s resp, err := utils.GetSupabase().GetFunctionBodyWithResponse(ctx, projectRef, slug) if err != nil { - return err + return errors.Errorf("failed to get function body: %w", err) } if resp.StatusCode() != http.StatusOK { return errors.New("Unexpected error downloading Function: " + string(resp.Body)) @@ -140,7 +140,7 @@ func downloadOne(ctx context.Context, slug string, projectRef string, fsys afero fmt.Println("Downloading " + utils.Bold(slug)) resp, err := utils.GetSupabase().GetFunctionBodyWithResponse(ctx, projectRef, slug) if err != nil { - return "", err + return "", errors.Errorf("failed to get function body: %w", err) } if resp.StatusCode() != http.StatusOK { return "", errors.New("Unexpected error downloading Function: " + string(resp.Body)) @@ -149,19 +149,21 @@ func downloadOne(ctx context.Context, slug string, projectRef string, fsys afero // Create temp file to store downloaded eszip eszipFile, err := afero.TempFile(fsys, "", slug) if err != nil { - return "", err + return "", errors.Errorf("failed to create temporary file: %w", err) } defer eszipFile.Close() body := bytes.NewReader(resp.Body) - _, err = io.Copy(eszipFile, body) - return eszipFile.Name(), err + if _, err = io.Copy(eszipFile, body); err != nil { + return "", errors.Errorf("failed to download file: %w", err) + } + return eszipFile.Name(), nil } func extractOne(ctx context.Context, hostEszipPath string) error { hostFuncDirPath, err := filepath.Abs(utils.FunctionsDir) if err != nil { - return err + return errors.Errorf("failed to resolve absolute path: %w", err) } dockerEszipPath := path.Join(dockerEszipDir, filepath.Base(hostEszipPath)) diff --git a/internal/functions/list/list.go b/internal/functions/list/list.go index 6bd388f11..32b16b6dd 100644 --- a/internal/functions/list/list.go +++ b/internal/functions/list/list.go @@ -2,10 +2,10 @@ package list import ( "context" - "errors" "fmt" "time" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/migration/list" "github.com/supabase/cli/internal/utils" @@ -14,7 +14,7 @@ import ( func Run(ctx context.Context, projectRef string, fsys afero.Fs) error { resp, err := utils.GetSupabase().GetFunctionsWithResponse(ctx, projectRef) if err != nil { - return err + return errors.Errorf("failed to list functions: %w", err) } if resp.JSON200 == nil { diff --git a/internal/functions/new/new.go b/internal/functions/new/new.go index eb36f3416..f9447cf91 100644 --- a/internal/functions/new/new.go +++ b/internal/functions/new/new.go @@ -3,12 +3,12 @@ package new import ( "context" _ "embed" - "errors" "fmt" "html/template" "os" "path/filepath" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" ) @@ -32,9 +32,6 @@ func Run(ctx context.Context, slug string, fsys afero.Fs) error { if err := utils.ValidateFunctionSlug(slug); err != nil { return err } - if _, err := fsys.Stat(funcDir); !errors.Is(err, os.ErrNotExist) { - return errors.New("Function " + utils.Aqua(slug) + " already exists locally.") - } } // 2. Create new function. @@ -43,9 +40,9 @@ func Run(ctx context.Context, slug string, fsys afero.Fs) error { return err } path := filepath.Join(funcDir, "index.ts") - f, err := fsys.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + f, err := fsys.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644) if err != nil { - return err + return errors.Errorf("failed to create function entrypoint: %w", err) } defer f.Close() // Templatize index.ts by config.toml if available @@ -59,7 +56,7 @@ func Run(ctx context.Context, slug string, fsys afero.Fs) error { Token: utils.Config.Auth.AnonKey, } if err := indexTemplate.Execute(f, config); err != nil { - return err + return errors.Errorf("failed to initialise function entrypoint: %w", err) } } diff --git a/internal/functions/new/new_test.go b/internal/functions/new/new_test.go index 69b303b47..956a1fa32 100644 --- a/internal/functions/new/new_test.go +++ b/internal/functions/new/new_test.go @@ -33,8 +33,8 @@ func TestNewCommand(t *testing.T) { t.Run("throws error on duplicate slug", func(t *testing.T) { // Setup in-memory fs fsys := afero.NewMemMapFs() - funcDir := filepath.Join(utils.FunctionsDir, "test-func") - require.NoError(t, fsys.Mkdir(funcDir, 0755)) + funcPath := filepath.Join(utils.FunctionsDir, "test-func", "index.ts") + require.NoError(t, afero.WriteFile(fsys, funcPath, []byte{}, 0644)) // Run test assert.Error(t, Run(context.Background(), "test-func", fsys)) }) diff --git a/internal/functions/serve/serve.go b/internal/functions/serve/serve.go index 14504dd74..dc30ed76d 100644 --- a/internal/functions/serve/serve.go +++ b/internal/functions/serve/serve.go @@ -70,7 +70,7 @@ func ServeFunctions(ctx context.Context, envFilePath string, noVerifyJWT *bool, } cwd, err := os.Getwd() if err != nil { - return err + return errors.Errorf("failed to get working directory: %w", err) } if importMapPath != "" { if !filepath.IsAbs(importMapPath) { @@ -184,12 +184,12 @@ func parseEnvFile(envFilePath string, fsys afero.Fs) ([]string, error) { } f, err := fsys.Open(envFilePath) if err != nil { - return env, err + return env, errors.Errorf("failed to open env file: %w", err) } defer f.Close() envMap, err := godotenv.Parse(f) if err != nil { - return env, err + return env, errors.Errorf("failed to parse env file: %w", err) } for name, value := range envMap { if strings.HasPrefix(name, "SUPABASE_") { @@ -210,12 +210,12 @@ func populatePerFunctionConfigs(binds []string, importMapPath string, noVerifyJW cwd, err := os.Getwd() if err != nil { - return nil, "", err + return nil, "", errors.Errorf("failed to get working directory: %w", err) } functions, err := afero.ReadDir(fsys, utils.FunctionsDir) if err != nil { - return nil, "", err + return nil, "", errors.Errorf("failed to read directory: %w", err) } for _, function := range functions { if !function.IsDir() { @@ -257,7 +257,7 @@ func populatePerFunctionConfigs(binds []string, importMapPath string, noVerifyJW functionsConfigBytes, err := json.Marshal(functionsConfig) if err != nil { - return nil, "", err + return nil, "", errors.Errorf("failed to marshal config json: %w", err) } return binds, string(functionsConfigBytes), nil diff --git a/internal/gen/keys/keys.go b/internal/gen/keys/keys.go index 79f33c1ec..af230c210 100644 --- a/internal/gen/keys/keys.go +++ b/internal/gen/keys/keys.go @@ -4,12 +4,12 @@ import ( "context" "crypto/sha256" "encoding/hex" - "errors" "fmt" "os" "strings" "time" + "github.com/go-errors/errors" "github.com/go-git/go-git/v5" "github.com/golang-jwt/jwt/v5" "github.com/spf13/afero" @@ -60,7 +60,7 @@ func GenerateSecrets(ctx context.Context, projectRef, branch string, fsys afero. // Load JWT secret from api resp, err := utils.GetSupabase().GetPostgRESTConfigWithResponse(ctx, projectRef) if err != nil { - return err + return errors.Errorf("failed to get postgrest config: %w", err) } if resp.JSON200 == nil { return errors.New("Unexpected error retrieving JWT secret: " + string(resp.Body)) @@ -79,11 +79,14 @@ func GenerateSecrets(ctx context.Context, projectRef, branch string, fsys afero. anonToken := NewJWTToken(projectRef, "anon", expiry) utils.Config.Auth.AnonKey, err = anonToken.SignedString([]byte(utils.Config.Auth.JwtSecret)) if err != nil { - return err + return errors.Errorf("failed to sign anon key: %w", err) } serviceToken := NewJWTToken(projectRef, "service_role", expiry) utils.Config.Auth.ServiceRoleKey, err = serviceToken.SignedString([]byte(utils.Config.Auth.JwtSecret)) - return err + if err != nil { + return errors.Errorf("failed to sign service_role key: %w", err) + } + return nil } func GetGitBranch(fsys afero.Fs) string { diff --git a/internal/gen/types/typescript/typescript.go b/internal/gen/types/typescript/typescript.go index 9eb1b55e9..ce16c5b2b 100644 --- a/internal/gen/types/typescript/typescript.go +++ b/internal/gen/types/typescript/typescript.go @@ -2,7 +2,6 @@ package typescript import ( "context" - "errors" "fmt" "net/url" "os" @@ -10,6 +9,7 @@ import ( "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/network" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" @@ -35,7 +35,7 @@ func Run(ctx context.Context, useLocal bool, useLinked bool, projectId string, d IncludedSchemas: &included, }) if err != nil { - return err + return errors.Errorf("failed to get typescript types: %w", err) } if resp.JSON200 == nil { @@ -124,7 +124,7 @@ func Run(ctx context.Context, useLocal bool, useLinked bool, projectId string, d IncludedSchemas: &included, }) if err != nil { - return err + return errors.Errorf("failed to get typescript types: %w", err) } if resp.JSON200 == nil { diff --git a/internal/hostnames/activate/activate.go b/internal/hostnames/activate/activate.go index 40d4acc70..308142476 100644 --- a/internal/hostnames/activate/activate.go +++ b/internal/hostnames/activate/activate.go @@ -2,9 +2,9 @@ package activate import ( "context" - "errors" "fmt" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/hostnames" "github.com/supabase/cli/internal/utils" @@ -27,7 +27,7 @@ func Run(ctx context.Context, projectRef string, includeRawOutput bool, fsys afe { resp, err := utils.GetSupabase().ActivateWithResponse(ctx, projectRef) if err != nil { - return err + return errors.Errorf("failed to active custom hostname: %w", err) } if resp.JSON201 == nil { return errors.New("failed to activate custom hostname config: " + string(resp.Body)) diff --git a/internal/hostnames/common.go b/internal/hostnames/common.go index 0e2981f68..6756bc792 100644 --- a/internal/hostnames/common.go +++ b/internal/hostnames/common.go @@ -14,7 +14,7 @@ import ( func GetCustomHostnameConfig(ctx context.Context, projectRef string) (*api.GetCustomHostnameConfigResponse, error) { resp, err := utils.GetSupabase().GetCustomHostnameConfigWithResponse(ctx, projectRef) if err != nil { - return nil, err + return nil, errors.Errorf("failed to get custom hostname: %w", err) } if resp.JSON200 == nil { return nil, errors.New("failed to get custom hostname config; received: " + string(resp.Body)) @@ -59,7 +59,7 @@ type RawResponse struct { func serializeRawOutput(response *api.UpdateCustomHostnameResponse) (string, error) { output, err := json.MarshalIndent(response, "", " ") if err != nil { - return "", err + return "", errors.Errorf("failed to serialize json: %w", err) } return string(output), nil } diff --git a/internal/hostnames/create/create.go b/internal/hostnames/create/create.go index 08a4b1e51..0bdc77a9b 100644 --- a/internal/hostnames/create/create.go +++ b/internal/hostnames/create/create.go @@ -2,10 +2,10 @@ package create import ( "context" - "errors" "fmt" "strings" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/hostnames" "github.com/supabase/cli/internal/utils" @@ -32,7 +32,7 @@ func Run(ctx context.Context, projectRef string, customHostname string, includeR CustomHostname: hostname, }) if err != nil { - return err + return errors.Errorf("failed to create custom hostname: %w", err) } if resp.JSON201 == nil { return errors.New("failed to create custom hostname config: " + string(resp.Body)) diff --git a/internal/hostnames/delete/delete.go b/internal/hostnames/delete/delete.go index bf2dd7c08..ad7b3de27 100644 --- a/internal/hostnames/delete/delete.go +++ b/internal/hostnames/delete/delete.go @@ -2,9 +2,9 @@ package delete import ( "context" - "errors" "fmt" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" ) @@ -15,7 +15,7 @@ func Run(ctx context.Context, projectRef string, fsys afero.Fs) error { { resp, err := utils.GetSupabase().RemoveCustomHostnameConfigWithResponse(ctx, projectRef) if err != nil { - return err + return errors.Errorf("failed to delete custom hostname: %w", err) } if resp.StatusCode() != 200 { return errors.New("failed to delete custom hostname config; received: " + resp.Status()) diff --git a/internal/hostnames/reverify/reverify.go b/internal/hostnames/reverify/reverify.go index 63e96e28a..05720bc9d 100644 --- a/internal/hostnames/reverify/reverify.go +++ b/internal/hostnames/reverify/reverify.go @@ -2,9 +2,9 @@ package reverify import ( "context" - "errors" "fmt" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/hostnames" "github.com/supabase/cli/internal/utils" @@ -16,7 +16,7 @@ func Run(ctx context.Context, projectRef string, includeRawOutput bool, fsys afe { resp, err := utils.GetSupabase().ReverifyWithResponse(ctx, projectRef) if err != nil { - return err + return errors.Errorf("failed to re-verify custom hostname: %w", err) } if resp.JSON201 == nil { return errors.New("failed to re-verify custom hostname config: " + string(resp.Body)) diff --git a/internal/init/init.go b/internal/init/init.go index 41b1143b8..f2b2e0a54 100644 --- a/internal/init/init.go +++ b/internal/init/init.go @@ -3,12 +3,12 @@ package init import ( _ "embed" "encoding/json" - "errors" "fmt" "io" "os" "path/filepath" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" ) @@ -25,16 +25,16 @@ var ( //go:embed templates/.vscode/settings.json vscodeSettings string - errAlreadyInitialized = errors.New("Project already initialized. Remove " + utils.Bold(utils.ConfigPath) + " to reinitialize.") + errAlreadyInitialized = errors.Errorf("Project already initialized. Remove %s to reinitialize.", utils.Bold(utils.ConfigPath)) ) func Run(fsys afero.Fs, createVscodeSettings *bool, useOrioleDB bool) error { // Sanity checks. { if _, err := fsys.Stat(utils.ConfigPath); err == nil { - return errAlreadyInitialized + return errors.New(errAlreadyInitialized) } else if !errors.Is(err, os.ErrNotExist) { - return err + return errors.Errorf("failed to read config file: %w", err) } } @@ -45,7 +45,7 @@ func Run(fsys afero.Fs, createVscodeSettings *bool, useOrioleDB bool) error { // 2. Create `seed.sql`. if _, err := fsys.Create(utils.SeedDataPath); err != nil { - return err + return errors.Errorf("failed to create seed file: %w", err) } // 3. Append to `.gitignore`. @@ -78,17 +78,17 @@ func updateGitIgnore(ignorePath string, fsys afero.Fs) error { // Add a line break when appending contents = append(contents, '\n') } else if !errors.Is(err, os.ErrNotExist) { - return err + return errors.Errorf("failed to read git ignore file: %w", err) } f, err := fsys.OpenFile(ignorePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { - return err + return errors.Errorf("failed to create git ignore file: %w", err) } defer f.Close() if _, err := f.Write(append(contents, initGitignore...)); err != nil { - return err + return errors.Errorf("failed to write git ignore file: %w", err) } return nil @@ -100,14 +100,14 @@ func loadUserSettings(path string, fsys afero.Fs) (VSCodeSettings, error) { // Open our jsonFile jsonFile, err := fsys.Open(path) if err != nil { - return nil, fmt.Errorf("failed to load %s: %w", utils.Bold(path), err) + return nil, errors.Errorf("failed to load settings file: %w", err) } defer jsonFile.Close() // Parse and unmarshal JSON file. var userSettings VSCodeSettings dec := json.NewDecoder(jsonFile) if err := dec.Decode(&userSettings); err != nil { - return nil, fmt.Errorf("failed to parse %s: %w", utils.Bold(path), err) + return nil, errors.Errorf("failed to parse settings: %w", err) } return userSettings, nil } @@ -116,14 +116,14 @@ func saveUserSettings(path string, settings VSCodeSettings, fsys afero.Fs) error // Open our jsonFile jsonFile, err := fsys.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { - return fmt.Errorf("failed to open %s: %w", utils.Bold(path), err) + return errors.Errorf("failed to create settings file: %w", err) } defer jsonFile.Close() // Marshal JSON to file. enc := json.NewEncoder(jsonFile) enc.SetIndent("", " ") if err := enc.Encode(settings); err != nil { - return fmt.Errorf("failed to save %s: %w", utils.Bold(path), err) + return errors.Errorf("failed to save settings: %w", err) } return nil } @@ -137,7 +137,7 @@ func updateJsonFile(path string, template string, fsys afero.Fs) error { } // Merge template into user settings. if err := json.Unmarshal([]byte(template), &userSettings); err != nil { - return fmt.Errorf("failed to copy template: %w", err) + return errors.Errorf("failed to copy template: %w", err) } return saveUserSettings(path, userSettings, fsys) } diff --git a/internal/inspect/bloat/bloat.go b/internal/inspect/bloat/bloat.go index 3310e70ad..d80408630 100644 --- a/internal/inspect/bloat/bloat.go +++ b/internal/inspect/bloat/bloat.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -89,7 +90,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/blocking/blocking.go b/internal/inspect/blocking/blocking.go index 817e97b7f..3d418bf68 100644 --- a/internal/inspect/blocking/blocking.go +++ b/internal/inspect/blocking/blocking.go @@ -5,6 +5,7 @@ import ( "fmt" "regexp" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -48,7 +49,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/cache/cache.go b/internal/inspect/cache/cache.go index 0674bfab1..88f3c65aa 100644 --- a/internal/inspect/cache/cache.go +++ b/internal/inspect/cache/cache.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -37,7 +38,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/calls/calls.go b/internal/inspect/calls/calls.go index 8d79555d1..faf289ee3 100644 --- a/internal/inspect/calls/calls.go +++ b/internal/inspect/calls/calls.go @@ -5,6 +5,7 @@ import ( "fmt" "regexp" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -40,7 +41,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/index_sizes/index_sizes.go b/internal/inspect/index_sizes/index_sizes.go index b916ff689..2d5848bc0 100644 --- a/internal/inspect/index_sizes/index_sizes.go +++ b/internal/inspect/index_sizes/index_sizes.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -35,7 +36,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/index_usage/index_usage.go b/internal/inspect/index_usage/index_usage.go index 6060a6542..cd304609a 100644 --- a/internal/inspect/index_usage/index_usage.go +++ b/internal/inspect/index_usage/index_usage.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -44,7 +45,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/locks/locks.go b/internal/inspect/locks/locks.go index ef8cafb2a..0d3eb5cdb 100644 --- a/internal/inspect/locks/locks.go +++ b/internal/inspect/locks/locks.go @@ -5,6 +5,7 @@ import ( "fmt" "regexp" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -44,7 +45,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/long_running_queries/long_running_queries.go b/internal/inspect/long_running_queries/long_running_queries.go index 72272fcbb..9b18f527a 100644 --- a/internal/inspect/long_running_queries/long_running_queries.go +++ b/internal/inspect/long_running_queries/long_running_queries.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -39,7 +40,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/outliers/outliers.go b/internal/inspect/outliers/outliers.go index f5421e28a..33307045f 100644 --- a/internal/inspect/outliers/outliers.go +++ b/internal/inspect/outliers/outliers.go @@ -5,6 +5,7 @@ import ( "fmt" "regexp" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -40,7 +41,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/replication_slots/replication_slots.go b/internal/inspect/replication_slots/replication_slots.go index d5d5a3da0..97408d6c7 100644 --- a/internal/inspect/replication_slots/replication_slots.go +++ b/internal/inspect/replication_slots/replication_slots.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -41,7 +42,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/role_connections/role_connections.go b/internal/inspect/role_connections/role_connections.go index 290b9f24c..1d4c2badf 100644 --- a/internal/inspect/role_connections/role_connections.go +++ b/internal/inspect/role_connections/role_connections.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -43,7 +44,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { @@ -57,9 +58,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu sum += r.Active_connections } - err = list.RenderTable(table) - if err != nil { - fmt.Println(err) + if err := list.RenderTable(table); err != nil { return err } diff --git a/internal/inspect/seq_scans/seq_scans.go b/internal/inspect/seq_scans/seq_scans.go index 6e361a837..e02351187 100644 --- a/internal/inspect/seq_scans/seq_scans.go +++ b/internal/inspect/seq_scans/seq_scans.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -31,7 +32,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/table_index_sizes/table_index_sizes.go b/internal/inspect/table_index_sizes/table_index_sizes.go index c22cb1179..629058333 100644 --- a/internal/inspect/table_index_sizes/table_index_sizes.go +++ b/internal/inspect/table_index_sizes/table_index_sizes.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -34,7 +35,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/table_record_counts/table_record_counts.go b/internal/inspect/table_record_counts/table_record_counts.go index 116a52346..ba204c84c 100644 --- a/internal/inspect/table_record_counts/table_record_counts.go +++ b/internal/inspect/table_record_counts/table_record_counts.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -33,7 +34,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/table_sizes/table_sizes.go b/internal/inspect/table_sizes/table_sizes.go index a15f34644..579ba1721 100644 --- a/internal/inspect/table_sizes/table_sizes.go +++ b/internal/inspect/table_sizes/table_sizes.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -34,7 +35,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/total_index_size/total_index_size.go b/internal/inspect/total_index_size/total_index_size.go index 8e6bf65e2..389001778 100644 --- a/internal/inspect/total_index_size/total_index_size.go +++ b/internal/inspect/total_index_size/total_index_size.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -32,7 +33,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/total_table_sizes/total_table_sizes.go b/internal/inspect/total_table_sizes/total_table_sizes.go index e87092fbb..e47f90b6f 100644 --- a/internal/inspect/total_table_sizes/total_table_sizes.go +++ b/internal/inspect/total_table_sizes/total_table_sizes.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -35,7 +36,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/unused_indexes/unused_indexes.go b/internal/inspect/unused_indexes/unused_indexes.go index f6c77ef93..18fc06dc0 100644 --- a/internal/inspect/unused_indexes/unused_indexes.go +++ b/internal/inspect/unused_indexes/unused_indexes.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -38,7 +39,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/inspect/vacuum_stats/vacuum_stats.go b/internal/inspect/vacuum_stats/vacuum_stats.go index db6606036..220990ed4 100644 --- a/internal/inspect/vacuum_stats/vacuum_stats.go +++ b/internal/inspect/vacuum_stats/vacuum_stats.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -77,7 +78,7 @@ func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...fu } rows, err := conn.Query(ctx, QUERY) if err != nil { - return err + return errors.Errorf("failed to query rows: %w", err) } result, err := pgxv5.CollectRows[Result](rows) if err != nil { diff --git a/internal/link/link.go b/internal/link/link.go index 96c781a85..4acb88e60 100644 --- a/internal/link/link.go +++ b/internal/link/link.go @@ -69,10 +69,7 @@ func Run(ctx context.Context, projectRef, password string, fsys afero.Fs, option } // 3. Save project ref - if err := utils.MkdirIfNotExistFS(fsys, filepath.Dir(utils.ProjectRefPath)); err != nil { - return err - } - return afero.WriteFile(fsys, utils.ProjectRefPath, []byte(projectRef), 0644) + return utils.WriteFile(filepath.Dir(utils.ProjectRefPath), []byte(projectRef), fsys) } func PostRun(projectRef string, stdout io.Writer, fsys afero.Fs) error { @@ -83,7 +80,10 @@ func PostRun(projectRef string, stdout io.Writer, fsys afero.Fs) error { fmt.Fprintln(os.Stderr, "Local config differs from linked project. Try updating", utils.Bold(utils.ConfigPath)) enc := toml.NewEncoder(stdout) enc.Indent = "" - return enc.Encode(updatedConfig) + if err := enc.Encode(updatedConfig); err != nil { + return errors.Errorf("failed to marshal toml config: %w", err) + } + return nil } func linkServices(ctx context.Context, projectRef string, fsys afero.Fs) { @@ -132,7 +132,7 @@ func linkServices(ctx context.Context, projectRef string, fsys afero.Fs) { func linkPostgrest(ctx context.Context, projectRef string) error { resp, err := utils.GetSupabase().GetPostgRESTConfigWithResponse(ctx, projectRef) if err != nil { - return err + return errors.Errorf("failed to get postgrest config: %w", err) } if resp.JSON200 == nil { return errors.Errorf("%w: %s", tenant.ErrAuthToken, string(resp.Body)) @@ -146,10 +146,7 @@ func linkPostgrestVersion(ctx context.Context, projectRef string, fsys afero.Fs) if err != nil { return err } - if err := utils.MkdirIfNotExistFS(fsys, filepath.Dir(utils.RestVersionPath)); err != nil { - return err - } - return afero.WriteFile(fsys, utils.RestVersionPath, []byte(version), 0644) + return utils.WriteFile(filepath.Dir(utils.RestVersionPath), []byte(version), fsys) } func updateApiConfig(config api.PostgrestConfigWithJWTSecretResponse) { @@ -182,10 +179,7 @@ func linkGotrueVersion(ctx context.Context, projectRef string, fsys afero.Fs) er if err != nil { return err } - if err := utils.MkdirIfNotExistFS(fsys, filepath.Dir(utils.GotrueVersionPath)); err != nil { - return err - } - return afero.WriteFile(fsys, utils.GotrueVersionPath, []byte(version), 0644) + return utils.WriteFile(filepath.Dir(utils.GotrueVersionPath), []byte(version), fsys) } func linkStorageVersion(ctx context.Context, projectRef string, fsys afero.Fs) error { @@ -193,10 +187,7 @@ func linkStorageVersion(ctx context.Context, projectRef string, fsys afero.Fs) e if err != nil { return err } - if err := utils.MkdirIfNotExistFS(fsys, filepath.Dir(utils.StorageVersionPath)); err != nil { - return err - } - return afero.WriteFile(fsys, utils.StorageVersionPath, []byte(version), 0644) + return utils.WriteFile(filepath.Dir(utils.StorageVersionPath), []byte(version), fsys) } func linkDatabase(ctx context.Context, config pgconn.Config, options ...func(*pgx.ConnConfig)) error { @@ -215,10 +206,7 @@ func linkDatabaseVersion(ctx context.Context, projectRef string, fsys afero.Fs) if err != nil { return err } - if err := utils.MkdirIfNotExistFS(fsys, filepath.Dir(utils.PostgresVersionPath)); err != nil { - return err - } - return afero.WriteFile(fsys, utils.PostgresVersionPath, []byte(version), 0644) + return utils.WriteFile(filepath.Dir(utils.PostgresVersionPath), []byte(version), fsys) } func updatePostgresConfig(conn *pgx.Conn) { @@ -240,7 +228,7 @@ func updatePostgresConfig(conn *pgx.Conn) { func linkPooler(ctx context.Context, projectRef string) error { resp, err := utils.GetSupabase().V1GetPgbouncerConfigWithResponse(ctx, projectRef) if err != nil { - return err + return errors.Errorf("failed to get pooler config: %w", err) } if resp.JSON200 == nil { return errors.Errorf("%w: %s", tenant.ErrAuthToken, string(resp.Body)) diff --git a/internal/migration/list/list.go b/internal/migration/list/list.go index 0db6ffb4f..bbd283ae2 100644 --- a/internal/migration/list/list.go +++ b/internal/migration/list/list.go @@ -2,7 +2,6 @@ package list import ( "context" - "errors" "fmt" "math" "os" @@ -11,11 +10,13 @@ import ( "time" "github.com/charmbracelet/glamour" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgerrcode" "github.com/jackc/pgx/v4" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" + "github.com/supabase/cli/internal/utils/pgxv5" ) const LIST_MIGRATION_VERSION = "SELECT version FROM supabase_migrations.schema_migrations ORDER BY version" @@ -52,17 +53,9 @@ func LoadRemoteMigrations(ctx context.Context, conn *pgx.Conn) ([]string, error) // If migration history table is undefined, the remote project has no migrations return nil, nil } - return nil, err - } - versions := []string{} - for rows.Next() { - var version string - if err := rows.Scan(&version); err != nil { - return nil, err - } - versions = append(versions, version) + return nil, errors.Errorf("failed to query rows: %w", err) } - return versions, nil + return pgxv5.CollectStrings(rows) } const ( @@ -118,11 +111,11 @@ func RenderTable(markdown string) error { glamour.WithWordWrap(-1), ) if err != nil { - return err + return errors.Errorf("failed to initialise terminal renderer: %w", err) } out, err := r.Render(markdown) if err != nil { - return err + return errors.Errorf("failed to render markdown: %w", err) } fmt.Print(out) return nil @@ -152,7 +145,7 @@ func LoadPartialMigrations(version string, fsys afero.Fs) ([]string, error) { } localMigrations, err := afero.ReadDir(fsys, utils.MigrationsDir) if err != nil { - return nil, err + return nil, errors.Errorf("failed to read directory: %w", err) } var names []string for i, migration := range localMigrations { diff --git a/internal/migration/list/list_test.go b/internal/migration/list/list_test.go index 4eccb7805..c8f0cfc9d 100644 --- a/internal/migration/list/list_test.go +++ b/internal/migration/list/list_test.go @@ -93,7 +93,7 @@ func TestRemoteMigrations(t *testing.T) { // Run test versions, err := loadRemoteVersions(context.Background(), dbConfig, conn.Intercept) // Check error - assert.NoError(t, err) + assert.ErrorContains(t, err, "failed to parse rows") assert.Empty(t, versions) }) diff --git a/internal/migration/new/new.go b/internal/migration/new/new.go index 9c93cfe82..b9437cd55 100644 --- a/internal/migration/new/new.go +++ b/internal/migration/new/new.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" ) @@ -17,16 +18,16 @@ func Run(migrationName string, stdin afero.File, fsys afero.Fs) error { } f, err := fsys.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { - return err + return errors.Errorf("failed to open migration file: %w", err) } defer f.Close() if fi, err := stdin.Stat(); err != nil { - return err + return errors.Errorf("failed to initialise stdin: %w", err) } else if (fi.Mode() & os.ModeCharDevice) == 0 { // Ref: https://stackoverflow.com/a/26567513 if _, err := io.Copy(f, stdin); err != nil { - return err + return errors.Errorf("failed to copy from stdin: %w", err) } } diff --git a/internal/migration/repair/repair.go b/internal/migration/repair/repair.go index 78df2f880..e57e4da4d 100644 --- a/internal/migration/repair/repair.go +++ b/internal/migration/repair/repair.go @@ -63,8 +63,10 @@ func UpdateMigrationTable(ctx context.Context, conn *pgx.Conn, version, status s case Reverted: DeleteVersionSQL(&batch, version) } - _, err := conn.PgConn().ExecBatch(ctx, &batch).ReadAll() - return err + if _, err := conn.PgConn().ExecBatch(ctx, &batch).ReadAll(); err != nil { + return errors.Errorf("failed to update migration table: %w", err) + } + return nil } func batchCreateTable() pgconn.Batch { @@ -79,8 +81,10 @@ func batchCreateTable() pgconn.Batch { func CreateMigrationTable(ctx context.Context, conn *pgx.Conn) error { batch := batchCreateTable() - _, err := conn.PgConn().ExecBatch(ctx, &batch).ReadAll() - return err + if _, err := conn.PgConn().ExecBatch(ctx, &batch).ReadAll(); err != nil { + return errors.Errorf("failed to create migration table: %w", err) + } + return nil } func InsertVersionSQL(batch *pgconn.Batch, version, name string, stats []string) { @@ -115,7 +119,7 @@ func GetMigrationFile(version string, fsys afero.Fs) (string, error) { path := filepath.Join(utils.MigrationsDir, version+"_*.sql") matches, err := afero.Glob(fsys, path) if err != nil { - return "", err + return "", errors.Errorf("failed to glob migration files: %w", err) } if len(matches) == 0 { return "", errors.Errorf("glob %s: %w", path, os.ErrNotExist) @@ -140,7 +144,7 @@ func NewMigrationFromVersion(version string, fsys afero.Fs) (*MigrationFile, err func NewMigrationFromFile(path string, fsys afero.Fs) (*MigrationFile, error) { sql, err := fsys.Open(path) if err != nil { - return nil, err + return nil, errors.Errorf("failed to open migration file: %w", err) } defer sql.Close() // Unless explicitly specified, Use file length as max buffer size @@ -202,5 +206,8 @@ func (m *MigrationFile) ExecBatchWithCache(ctx context.Context, conn *pgx.Conn) batch.Queue(line) } // No need to track version here because there are no schema changes - return conn.SendBatch(ctx, &batch).Close() + if err := conn.SendBatch(ctx, &batch).Close(); err != nil { + return errors.Errorf("failed to send batch: %w", err) + } + return nil } diff --git a/internal/migration/squash/squash.go b/internal/migration/squash/squash.go index 0c4f9ab42..dd342268d 100644 --- a/internal/migration/squash/squash.go +++ b/internal/migration/squash/squash.go @@ -86,7 +86,7 @@ func squashMigrations(ctx context.Context, migrations []string, fsys afero.Fs, o path := filepath.Join(utils.MigrationsDir, migrations[len(migrations)-1]) f, err := fsys.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { - return err + return errors.Errorf("failed to open migration file: %w", err) } defer f.Close() config := pgconn.Config{ @@ -126,5 +126,8 @@ func baselineMigrations(ctx context.Context, config pgconn.Config, version strin batch := pgx.Batch{} batch.Queue(DELETE_MIGRATION_BEFORE, m.Version) batch.Queue(repair.INSERT_MIGRATION_VERSION, m.Version, m.Name, m.Lines) - return conn.SendBatch(ctx, &batch).Close() + if err := conn.SendBatch(ctx, &batch).Close(); err != nil { + return errors.Errorf("failed to update migration history: %w", err) + } + return nil } diff --git a/internal/orgs/create/create.go b/internal/orgs/create/create.go index 7cddbc4e1..a455e925e 100644 --- a/internal/orgs/create/create.go +++ b/internal/orgs/create/create.go @@ -2,9 +2,9 @@ package create import ( "context" - "errors" "fmt" + "github.com/go-errors/errors" "github.com/supabase/cli/internal/utils" "github.com/supabase/cli/pkg/api" ) @@ -12,7 +12,7 @@ import ( func Run(ctx context.Context, name string) error { resp, err := utils.GetSupabase().CreateOrganizationWithResponse(ctx, api.CreateOrganizationJSONRequestBody{Name: name}) if err != nil { - return err + return errors.Errorf("failed to create organization: %w", err) } if resp.JSON201 == nil { diff --git a/internal/orgs/list/list.go b/internal/orgs/list/list.go index a1d308bc6..d7216a24c 100644 --- a/internal/orgs/list/list.go +++ b/internal/orgs/list/list.go @@ -2,10 +2,10 @@ package list import ( "context" - "errors" "fmt" "strings" + "github.com/go-errors/errors" "github.com/supabase/cli/internal/migration/list" "github.com/supabase/cli/internal/utils" ) @@ -13,7 +13,7 @@ import ( func Run(ctx context.Context) error { resp, err := utils.GetSupabase().GetOrganizationsWithResponse(ctx) if err != nil { - return err + return errors.Errorf("failed to list organizations: %w", err) } if resp.JSON200 == nil { diff --git a/internal/postgresConfig/get/get.go b/internal/postgresConfig/get/get.go index fe616cac6..1a6db2210 100644 --- a/internal/postgresConfig/get/get.go +++ b/internal/postgresConfig/get/get.go @@ -7,9 +7,9 @@ import ( "io" "strings" - "github.com/charmbracelet/glamour" "github.com/go-errors/errors" "github.com/spf13/afero" + "github.com/supabase/cli/internal/migration/list" "github.com/supabase/cli/internal/utils" ) @@ -41,20 +41,9 @@ func PrintOutPostgresConfigOverrides(config map[string]interface{}) error { )) } - r, err := glamour.NewTermRenderer( - glamour.WithAutoStyle(), - glamour.WithWordWrap(-1), - ) - if err != nil { - return err - } - - out, err := r.Render(strings.Join(markdownTable, "")) - if err != nil { + if err := list.RenderTable(strings.Join(markdownTable, "")); err != nil { return err } - - fmt.Print(out) fmt.Println("- End of Custom Postgres Config -") return nil } diff --git a/internal/postgresConfig/update/update.go b/internal/postgresConfig/update/update.go index 9d7dfc6ee..8b27cb69e 100644 --- a/internal/postgresConfig/update/update.go +++ b/internal/postgresConfig/update/update.go @@ -55,7 +55,7 @@ func Run(ctx context.Context, projectRef string, values []string, replaceOverrid } resp, err := utils.GetSupabase().UpdateConfigWithBodyWithResponse(ctx, projectRef, "application/json", bytes.NewReader(bts)) if err != nil { - return err + return errors.Errorf("failed to update config overrides: %w", err) } if resp.JSON200 == nil { if resp.StatusCode() == 400 { diff --git a/internal/projects/apiKeys/api_keys.go b/internal/projects/apiKeys/api_keys.go index be3a1fc65..3862cb41f 100644 --- a/internal/projects/apiKeys/api_keys.go +++ b/internal/projects/apiKeys/api_keys.go @@ -2,10 +2,10 @@ package apiKeys import ( "context" - "errors" "fmt" "strings" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/migration/list" "github.com/supabase/cli/internal/utils" @@ -14,7 +14,7 @@ import ( func Run(ctx context.Context, projectRef string, fsys afero.Fs) error { resp, err := utils.GetSupabase().GetProjectApiKeysWithResponse(ctx, projectRef) if err != nil { - return err + return errors.Errorf("failed to get api keys: %w", err) } if resp.JSON200 == nil { diff --git a/internal/projects/create/create.go b/internal/projects/create/create.go index 9e1f0c0bc..ad9aa38e1 100644 --- a/internal/projects/create/create.go +++ b/internal/projects/create/create.go @@ -2,9 +2,9 @@ package create import ( "context" - "errors" "fmt" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" "github.com/supabase/cli/pkg/api" @@ -17,7 +17,7 @@ func Run(ctx context.Context, params api.CreateProjectBody, fsys afero.Fs) error resp, err := utils.GetSupabase().CreateProjectWithResponse(ctx, params) if err != nil { - return err + return errors.Errorf("failed to create project: %w", err) } if resp.JSON201 == nil { diff --git a/internal/projects/delete/delete.go b/internal/projects/delete/delete.go index 2a771b066..5ed36a3ed 100644 --- a/internal/projects/delete/delete.go +++ b/internal/projects/delete/delete.go @@ -2,11 +2,11 @@ package delete import ( "context" - "errors" "fmt" "net/http" "os" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" "github.com/supabase/cli/internal/utils/credentials" @@ -26,7 +26,7 @@ func PreRun(ref string) error { func Run(ctx context.Context, ref string, fsys afero.Fs) error { resp, err := utils.GetSupabase().DeleteProjectWithResponse(ctx, ref) if err != nil { - return err + return errors.Errorf("failed to delete project: %w", err) } switch resp.StatusCode() { @@ -35,7 +35,7 @@ func Run(ctx context.Context, ref string, fsys afero.Fs) error { case http.StatusOK: break default: - return errors.New("Failed to delete project " + utils.Aqua(ref) + ": " + string(resp.Body)) + return errors.Errorf("Failed to delete project %s: %s", utils.Aqua(ref), string(resp.Body)) } // Unlink project diff --git a/internal/projects/list/list.go b/internal/projects/list/list.go index 5e07c393d..4f6584c73 100644 --- a/internal/projects/list/list.go +++ b/internal/projects/list/list.go @@ -2,12 +2,12 @@ package list import ( "context" - "errors" "fmt" "os" "strings" "time" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/migration/list" "github.com/supabase/cli/internal/utils" @@ -16,7 +16,7 @@ import ( func Run(ctx context.Context, fsys afero.Fs) error { resp, err := utils.GetSupabase().GetProjectsWithResponse(ctx) if err != nil { - return err + return errors.Errorf("failed to list projects: %w", err) } if resp.JSON200 == nil { diff --git a/internal/restrictions/get/get.go b/internal/restrictions/get/get.go index 9d62766d8..d7b99afd7 100644 --- a/internal/restrictions/get/get.go +++ b/internal/restrictions/get/get.go @@ -21,9 +21,6 @@ func Run(ctx context.Context, projectRef string, fsys afero.Fs) error { return errors.New("failed to retrieve network restrictions; received: " + string(resp.Body)) } - if err != nil { - return err - } fmt.Printf("DB Allowed CIDRs: %+v\n", resp.JSON200.Config.DbAllowedCidrs) fmt.Printf("Restrictions applied successfully: %+v\n", resp.JSON200.Status == "applied") return nil diff --git a/internal/restrictions/update/update.go b/internal/restrictions/update/update.go index 7f254a0d2..aa97f7c42 100644 --- a/internal/restrictions/update/update.go +++ b/internal/restrictions/update/update.go @@ -42,7 +42,7 @@ func Run(ctx context.Context, projectRef string, dbCidrsToAllow []string, bypass DbAllowedCidrs: dbCidrsToAllow, }) if err != nil { - return err + return errors.Errorf("failed to apply network restrictions: %w", err) } if resp.JSON201 == nil { return errors.New("failed to update network restrictions: " + string(resp.Body)) diff --git a/internal/secrets/list/list.go b/internal/secrets/list/list.go index ef00023e3..ecb94f073 100644 --- a/internal/secrets/list/list.go +++ b/internal/secrets/list/list.go @@ -2,10 +2,10 @@ package list import ( "context" - "errors" "fmt" "strings" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/migration/list" "github.com/supabase/cli/internal/utils" @@ -14,7 +14,7 @@ import ( func Run(ctx context.Context, projectRef string, fsys afero.Fs) error { resp, err := utils.GetSupabase().GetSecretsWithResponse(ctx, projectRef) if err != nil { - return err + return errors.Errorf("failed to list secrets: %w", err) } if resp.JSON200 == nil { diff --git a/internal/secrets/set/set.go b/internal/secrets/set/set.go index d3d066f1f..517de12d5 100644 --- a/internal/secrets/set/set.go +++ b/internal/secrets/set/set.go @@ -2,11 +2,11 @@ package set import ( "context" - "errors" "fmt" "net/http" "strings" + "github.com/go-errors/errors" "github.com/joho/godotenv" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" @@ -21,7 +21,7 @@ func Run(ctx context.Context, projectRef, envFilePath string, args []string, fsy if envFilePath != "" { envMap, err := godotenv.Read(envFilePath) if err != nil { - return err + return errors.Errorf("failed to read env file: %w", err) } for name, value := range envMap { secret := api.CreateSecretBody{ @@ -49,7 +49,7 @@ func Run(ctx context.Context, projectRef, envFilePath string, args []string, fsy resp, err := utils.GetSupabase().CreateSecretsWithResponse(ctx, projectRef, secrets) if err != nil { - return err + return errors.Errorf("failed to set secrets: %w", err) } // TODO: remove the StatusOK case after 2022-08-20 diff --git a/internal/secrets/unset/unset.go b/internal/secrets/unset/unset.go index 60ea7bc95..7be11587b 100644 --- a/internal/secrets/unset/unset.go +++ b/internal/secrets/unset/unset.go @@ -2,10 +2,10 @@ package unset import ( "context" - "errors" "fmt" "net/http" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" ) @@ -16,7 +16,7 @@ func Run(ctx context.Context, projectRef string, args []string, fsys afero.Fs) e { resp, err := utils.GetSupabase().DeleteSecretsWithResponse(ctx, projectRef, args) if err != nil { - return err + return errors.Errorf("failed to delete secrets: %w", err) } if resp.StatusCode() != http.StatusOK { diff --git a/internal/services/services.go b/internal/services/services.go index 12b792a11..02baf5afc 100644 --- a/internal/services/services.go +++ b/internal/services/services.go @@ -2,11 +2,11 @@ package services import ( "context" - "errors" "fmt" "strings" "sync" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/migration/list" "github.com/supabase/cli/internal/utils" @@ -85,7 +85,7 @@ func Run(ctx context.Context, fsys afero.Fs) error { func GetDatabaseVersion(ctx context.Context, projectRef string) (string, error) { resp, err := utils.GetSupabase().GetProjectsWithResponse(ctx) if err != nil { - return "", err + return "", errors.Errorf("failed to retrieve projects: %w", err) } if resp.JSON200 == nil { return "", errors.New("Unexpected error retrieving projects: " + string(resp.Body)) @@ -95,5 +95,5 @@ func GetDatabaseVersion(ctx context.Context, projectRef string) (string, error) return project.Database.Version, nil } } - return "", errDatabaseVersion + return "", errors.New(errDatabaseVersion) } diff --git a/internal/snippets/download/download.go b/internal/snippets/download/download.go index 170ab76dd..605115d62 100644 --- a/internal/snippets/download/download.go +++ b/internal/snippets/download/download.go @@ -2,9 +2,9 @@ package download import ( "context" - "errors" "fmt" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" ) @@ -12,7 +12,7 @@ import ( func Run(ctx context.Context, snippetId string, fsys afero.Fs) error { resp, err := utils.GetSupabase().GetSnippetWithResponse(ctx, snippetId) if err != nil { - return err + return errors.Errorf("failed to download snippet: %w", err) } if resp.JSON200 == nil { diff --git a/internal/snippets/list/list.go b/internal/snippets/list/list.go index df679d1e4..0744a8421 100644 --- a/internal/snippets/list/list.go +++ b/internal/snippets/list/list.go @@ -2,10 +2,10 @@ package list import ( "context" - "errors" "fmt" "strings" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/migration/list" "github.com/supabase/cli/internal/utils" @@ -19,7 +19,7 @@ func Run(ctx context.Context, fsys afero.Fs) error { } resp, err := utils.GetSupabase().ListSnippetsWithResponse(ctx, &api.ListSnippetsParams{ProjectRef: &ref}) if err != nil { - return err + return errors.Errorf("failed to list snippets: %w", err) } if resp.JSON200 == nil { diff --git a/internal/ssl_enforcement/get/get.go b/internal/ssl_enforcement/get/get.go index 3b7273d07..8a71c6c7b 100644 --- a/internal/ssl_enforcement/get/get.go +++ b/internal/ssl_enforcement/get/get.go @@ -21,9 +21,6 @@ func Run(ctx context.Context, projectRef string, fsys afero.Fs) error { return errors.New("failed to retrieve SSL enforcement config; received: " + string(resp.Body)) } - if err != nil { - return err - } if resp.JSON200.CurrentConfig.Database && resp.JSON200.AppliedSuccessfully { fmt.Println("SSL is being enforced.") } else { diff --git a/internal/ssl_enforcement/update/update.go b/internal/ssl_enforcement/update/update.go index 36511175d..4ad7e1d09 100644 --- a/internal/ssl_enforcement/update/update.go +++ b/internal/ssl_enforcement/update/update.go @@ -2,9 +2,9 @@ package update import ( "context" - "errors" "fmt" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" "github.com/supabase/cli/pkg/api" @@ -20,7 +20,7 @@ func Run(ctx context.Context, projectRef string, enforceDbSsl bool, fsys afero.F }, }) if err != nil { - return err + return errors.Errorf("failed to update ssl enforcement: %w", err) } if resp.JSON200 == nil { return errors.New("failed to update SSL enforcement confnig: " + string(resp.Body)) diff --git a/internal/sso/create/create.go b/internal/sso/create/create.go index ef349bc93..cfaeedf14 100644 --- a/internal/sso/create/create.go +++ b/internal/sso/create/create.go @@ -63,7 +63,7 @@ func Run(ctx context.Context, params RunParams) error { resp, err := utils.GetSupabase().CreateProviderForProjectWithResponse(ctx, params.ProjectRef, body) if err != nil { - return err + return errors.Errorf("failed to create sso provider: %w", err) } if resp.JSON201 == nil { diff --git a/internal/sso/internal/render/render.go b/internal/sso/internal/render/render.go index 98cecc6a7..3f3a03db1 100644 --- a/internal/sso/internal/render/render.go +++ b/internal/sso/internal/render/render.go @@ -5,8 +5,9 @@ import ( "fmt" "strings" - "github.com/charmbracelet/glamour" + "github.com/go-errors/errors" "github.com/go-xmlfmt/xmlfmt" + "github.com/supabase/cli/internal/migration/list" "github.com/supabase/cli/internal/utils" "github.com/supabase/cli/pkg/api" ) @@ -32,7 +33,7 @@ func formatMetadataSource(provider api.Provider) string { func formatAttributeMapping(attributeMapping *api.AttributeMapping) (string, error) { data, err := json.MarshalIndent(attributeMapping, "", " ") if err != nil { - return "", err + return "", errors.Errorf("failed to marshal attribute mapping: %w", err) } return string(data), nil @@ -91,21 +92,7 @@ func ListMarkdown(providers []api.Provider) error { )) } - r, err := glamour.NewTermRenderer( - glamour.WithAutoStyle(), - glamour.WithWordWrap(-1), - ) - if err != nil { - return err - } - - out, err := r.Render(strings.Join(markdownTable, "")) - if err != nil { - return err - } - - fmt.Print(out) - return nil + return list.RenderTable(strings.Join(markdownTable, "")) } func SingleMarkdown(provider api.Provider) error { @@ -165,21 +152,7 @@ func SingleMarkdown(provider api.Provider) error { markdownTable = append(markdownTable, "", "## SAML 2.0 Metadata XML", "```xml", prettyXML, "```") } - r, err := glamour.NewTermRenderer( - glamour.WithAutoStyle(), - glamour.WithWordWrap(-1), - ) - if err != nil { - return err - } - - out, err := r.Render(strings.Join(markdownTable, "\n")) - if err != nil { - return err - } - - fmt.Print(out) - return nil + return list.RenderTable(strings.Join(markdownTable, "\n")) } func InfoMarkdown(ref string) error { @@ -203,19 +176,5 @@ func InfoMarkdown(ref string) error { fmt.Sprintf("https://%s.supabase.co", ref), )) - r, err := glamour.NewTermRenderer( - glamour.WithAutoStyle(), - glamour.WithWordWrap(-1), - ) - if err != nil { - return err - } - - out, err := r.Render(strings.Join(markdownTable, "\n")) - if err != nil { - return err - } - - fmt.Print(out) - return nil + return list.RenderTable(strings.Join(markdownTable, "\n")) } diff --git a/internal/sso/internal/saml/files.go b/internal/sso/internal/saml/files.go index 754037b39..0fe3648d8 100644 --- a/internal/sso/internal/saml/files.go +++ b/internal/sso/internal/saml/files.go @@ -19,12 +19,12 @@ var DefaultClient = http.DefaultClient func ReadMetadataFile(fsys afero.Fs, path string) (string, error) { file, err := fsys.Open(path) if err != nil { - return "", err + return "", errors.Errorf("failed to open metadata file: %w", err) } data, err := io.ReadAll(file) if err != nil { - return "", err + return "", errors.Errorf("failed to read metadata file: %w", err) } if err := ValidateMetadata(data, path); err != nil { @@ -37,18 +37,13 @@ func ReadMetadataFile(fsys afero.Fs, path string) (string, error) { func ReadAttributeMappingFile(fsys afero.Fs, path string) (*api.AttributeMapping, error) { file, err := fsys.Open(path) if err != nil { - return nil, err - } - - data, err := io.ReadAll(file) - if err != nil { - return nil, err + return nil, errors.Errorf("failed to open attribute mapping: %w", err) } var mapping api.AttributeMapping - - if err := json.Unmarshal(data, &mapping); err != nil { - return nil, err + dec := json.NewDecoder(file) + if err := dec.Decode(&mapping); err != nil { + return nil, errors.Errorf("failed to parse attribute mapping: %w", err) } return &mapping, nil @@ -65,7 +60,7 @@ func ValidateMetadata(data []byte, source string) error { func ValidateMetadataURL(ctx context.Context, metadataURL string) error { parsed, err := url.ParseRequestURI(metadataURL) if err != nil { - return err + return errors.Errorf("failed to parse metadata uri: %w", err) } if strings.ToLower(parsed.Scheme) != "https" { @@ -74,14 +69,14 @@ func ValidateMetadataURL(ctx context.Context, metadataURL string) error { req, err := http.NewRequestWithContext(ctx, http.MethodGet, metadataURL, nil) if err != nil { - return err + return errors.Errorf("failed to initialise http request: %w", err) } req.Header.Add("Accept", "application/xml") resp, err := DefaultClient.Do(req) if err != nil { - return err + return errors.Errorf("failed to send http request: %w", err) } defer resp.Body.Close() @@ -91,12 +86,8 @@ func ValidateMetadataURL(ctx context.Context, metadataURL string) error { data, err := io.ReadAll(resp.Body) if err != nil { - return err + return errors.Errorf("failed to read http response: %w", err) } - if err := ValidateMetadata(data, metadataURL); err != nil { - return err - } - - return nil + return ValidateMetadata(data, metadataURL) } diff --git a/internal/sso/list/list.go b/internal/sso/list/list.go index 02ad3fb85..82dcd42fb 100644 --- a/internal/sso/list/list.go +++ b/internal/sso/list/list.go @@ -2,10 +2,10 @@ package list import ( "context" - "errors" "net/http" "os" + "github.com/go-errors/errors" "github.com/supabase/cli/internal/sso/internal/render" "github.com/supabase/cli/internal/utils" ) @@ -13,7 +13,7 @@ import ( func Run(ctx context.Context, ref, format string) error { resp, err := utils.GetSupabase().ListAllProvidersWithResponse(ctx, ref) if err != nil { - return err + return errors.Errorf("failed to list sso providers: %w", err) } if resp.JSON200 == nil { diff --git a/internal/sso/remove/remove.go b/internal/sso/remove/remove.go index ddae950b1..29518c59a 100644 --- a/internal/sso/remove/remove.go +++ b/internal/sso/remove/remove.go @@ -14,7 +14,7 @@ import ( func Run(ctx context.Context, ref, providerId, format string) error { resp, err := utils.GetSupabase().RemoveProviderByIdWithResponse(ctx, ref, providerId) if err != nil { - return err + return errors.Errorf("failed to remove sso provider: %w", err) } if resp.JSON200 == nil { diff --git a/internal/sso/update/update.go b/internal/sso/update/update.go index 078a38d88..0f75e85e4 100644 --- a/internal/sso/update/update.go +++ b/internal/sso/update/update.go @@ -33,7 +33,7 @@ type RunParams struct { func Run(ctx context.Context, params RunParams) error { getResp, err := utils.GetSupabase().GetProviderByIdWithResponse(ctx, params.ProjectRef, params.ProviderID) if err != nil { - return err + return errors.Errorf("failed to get sso provider: %w", err) } if getResp.JSON200 == nil { @@ -103,7 +103,7 @@ func Run(ctx context.Context, params RunParams) error { putResp, err := utils.GetSupabase().UpdateProviderByIdWithResponse(ctx, params.ProjectRef, params.ProviderID, body) if err != nil { - return err + return errors.Errorf("failed to update sso provider: %w", err) } if putResp.JSON200 == nil { diff --git a/internal/start/start.go b/internal/start/start.go index 380a4bed7..91bda92da 100644 --- a/internal/start/start.go +++ b/internal/start/start.go @@ -4,7 +4,6 @@ import ( "bytes" "context" _ "embed" - "errors" "fmt" "os" "path" @@ -17,6 +16,7 @@ import ( "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/network" "github.com/docker/go-connections/nat" + "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" @@ -142,7 +142,7 @@ func run(p utils.Program, ctx context.Context, fsys afero.Fs, excludedContainers EdgeRuntimeId: utils.EdgeRuntimeId, DbId: utils.DbId, }); err != nil { - return err + return errors.Errorf("failed to exec template: %w", err) } p.Send(utils.StatusMsg("Starting syslog driver...")) if _, err := utils.DockerStart( @@ -222,7 +222,7 @@ EOF case utils.LogflareBigQuery: workdir, err := os.Getwd() if err != nil { - return err + return errors.Errorf("failed to get working directory: %w", err) } hostJwtPath := filepath.Join(workdir, utils.Config.Analytics.GcpJwtPath) bind = append(bind, hostJwtPath+":/opt/app/rel/logflare/bin/gcloud.json") @@ -296,7 +296,7 @@ EOF LogflareId: utils.LogflareId, ApiPort: utils.Config.Api.Port, }); err != nil { - return err + return errors.Errorf("failed to exec template: %w", err) } binds := []string{} @@ -309,7 +309,7 @@ EOF var err error hostPath, err = filepath.Abs(hostPath) if err != nil { - return err + return errors.Errorf("failed to resolve absolute path: %w", err) } } dockerPath := path.Join(nginxEmailTemplateDir, id+filepath.Ext(hostPath)) diff --git a/internal/stop/stop.go b/internal/stop/stop.go index 78fa010a7..1bd6974c9 100644 --- a/internal/stop/stop.go +++ b/internal/stop/stop.go @@ -43,7 +43,7 @@ func stop(ctx context.Context, backup bool, w io.Writer) error { Filters: args, }) if err != nil { - return err + return errors.Errorf("failed to list containers: %w", err) } // Gracefully shutdown containers var ids []string @@ -54,13 +54,16 @@ func stop(ctx context.Context, backup bool, w io.Writer) error { } fmt.Fprintln(w, "Stopping containers...") result := utils.WaitAll(ids, func(id string) error { - return utils.Docker.ContainerStop(ctx, id, container.StopOptions{}) + if err := utils.Docker.ContainerStop(ctx, id, container.StopOptions{}); err != nil { + return errors.Errorf("failed to stop container: %w", err) + } + return nil }) if err := errors.Join(result...); err != nil { return err } if _, err := utils.Docker.ContainersPrune(ctx, args); err != nil { - return err + return errors.Errorf("failed to prune containers: %w", err) } // Remove named volumes if backup { @@ -89,6 +92,8 @@ func stop(ctx context.Context, backup bool, w io.Writer) error { } } // Remove networks. - _, err = utils.Docker.NetworksPrune(ctx, args) - return err + if _, err = utils.Docker.NetworksPrune(ctx, args); err != nil { + return errors.Errorf("failed to prune networks: %w", err) + } + return nil } diff --git a/internal/storage/client/objects.go b/internal/storage/client/objects.go index 4bb16f2c7..67f688c69 100644 --- a/internal/storage/client/objects.go +++ b/internal/storage/client/objects.go @@ -66,19 +66,19 @@ func ListStorageObjects(ctx context.Context, projectRef, bucket, prefix string, func UploadStorageObject(ctx context.Context, projectRef, remotePath, localPath string, fsys afero.Fs) error { f, err := fsys.Open(localPath) if err != nil { - return err + return errors.Errorf("failed to open file: %w", err) } defer f.Close() // Decode mimetype header := io.LimitReader(f, 512) buf, err := io.ReadAll(header) if err != nil { - return err + return errors.Errorf("failed to read file: %w", err) } mimetype := http.DetectContentType(buf) _, err = f.Seek(0, io.SeekStart) if err != nil { - return err + return errors.Errorf("failed to seek file: %w", err) } // Prepare request apiKey, err := tenant.GetApiKeys(ctx, projectRef) @@ -89,7 +89,7 @@ func UploadStorageObject(ctx context.Context, projectRef, remotePath, localPath url := fmt.Sprintf("https://%s/storage/v1/object/%s", utils.GetSupabaseHost(projectRef), remotePath) req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, f) if err != nil { - return err + return errors.Errorf("failed to initialise http request: %w", err) } req.Header.Add("Authorization", "Bearer "+apiKey.ServiceRole) req.Header.Add("Content-Type", mimetype) @@ -98,13 +98,13 @@ func UploadStorageObject(ctx context.Context, projectRef, remotePath, localPath // Sends request resp, err := http.DefaultClient.Do(req) if err != nil { - return err + return errors.Errorf("failed to send http request: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, err := io.ReadAll(resp.Body) if err != nil { - return err + return errors.Errorf("failed to read http response: %w", err) } return errors.Errorf("Error status %d: %s", resp.StatusCode, body) } @@ -120,30 +120,32 @@ func DownloadStorageObject(ctx context.Context, projectRef, remotePath, localPat url := fmt.Sprintf("https://%s/storage/v1/object/%s", utils.GetSupabaseHost(projectRef), remotePath) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { - return err + return errors.Errorf("failed to initialise http request: %w", err) } req.Header.Add("Authorization", "Bearer "+apiKey.ServiceRole) // Sends request resp, err := http.DefaultClient.Do(req) if err != nil { - return err + return errors.Errorf("failed to send http request: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, err := io.ReadAll(resp.Body) if err != nil { - return err + return errors.Errorf("failed to read http response: %w", err) } return errors.Errorf("Error status %d: %s", resp.StatusCode, body) } // Streams to file f, err := fsys.OpenFile(localPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { - return err + return errors.Errorf("failed to open file: %w", err) } defer f.Close() - _, err = io.Copy(f, resp.Body) - return err + if _, err = io.Copy(f, resp.Body); err != nil { + return errors.Errorf("failed to write file: %w", err) + } + return nil } type MoveObjectRequest struct { diff --git a/internal/storage/cp/cp.go b/internal/storage/cp/cp.go index eaf972e9c..4af9c0f15 100644 --- a/internal/storage/cp/cp.go +++ b/internal/storage/cp/cp.go @@ -2,7 +2,6 @@ package cp import ( "context" - "errors" "fmt" "io/fs" "net/url" @@ -11,6 +10,7 @@ import ( "path/filepath" "strings" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/storage" "github.com/supabase/cli/internal/storage/client" @@ -23,11 +23,11 @@ var errUnsupportedOperation = errors.New("Unsupported operation") func Run(ctx context.Context, src, dst string, recursive bool, fsys afero.Fs) error { srcParsed, err := url.Parse(src) if err != nil { - return err + return errors.Errorf("failed to parse src url: %w", err) } dstParsed, err := url.Parse(dst) if err != nil { - return err + return errors.Errorf("failed to parse dst url: %w", err) } projectRef, err := utils.LoadProjectRef(fsys) if err != nil { @@ -47,7 +47,7 @@ func Run(ctx context.Context, src, dst string, recursive bool, fsys afero.Fs) er return errors.New("Copying between buckets is not supported") } utils.CmdSuggestion = fmt.Sprintf("Run %s to copy between local directories.", utils.Aqua("cp -r ")) - return errUnsupportedOperation + return errors.New(errUnsupportedOperation) } func DownloadStorageObjectAll(ctx context.Context, projectRef, remotePath, localPath string, fsys afero.Fs) error { @@ -96,14 +96,14 @@ func UploadStorageObjectAll(ctx context.Context, projectRef, remotePath, localPa baseName := filepath.Base(localPath) return afero.Walk(fsys, localPath, func(filePath string, info fs.FileInfo, err error) error { if err != nil { - return err + return errors.New(err) } if !info.Mode().IsRegular() { return nil } relPath, err := filepath.Rel(localPath, filePath) if err != nil { - return err + return errors.Errorf("failed to resolve relative path: %w", err) } dstPath := remotePath // Copying single file diff --git a/internal/storage/mv/mv.go b/internal/storage/mv/mv.go index 1fe1b440f..2ae30b192 100644 --- a/internal/storage/mv/mv.go +++ b/internal/storage/mv/mv.go @@ -2,12 +2,12 @@ package mv import ( "context" - "errors" "fmt" "os" "path" "strings" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/storage" "github.com/supabase/cli/internal/storage/client" @@ -36,10 +36,10 @@ func Run(ctx context.Context, src, dst string, recursive bool, fsys afero.Fs) er srcBucket, srcPrefix := storage.SplitBucketPrefix(srcParsed) dstBucket, dstPrefix := storage.SplitBucketPrefix(dstParsed) if len(srcPrefix) == 0 && len(dstPrefix) == 0 { - return errMissingPath + return errors.New(errMissingPath) } if srcBucket != dstBucket { - return errUnsupportedMove + return errors.New(errUnsupportedMove) } fmt.Fprintln(os.Stderr, "Moving object:", srcParsed, "=>", dstParsed) data, err := client.MoveStorageObject(ctx, projectRef, srcBucket, srcPrefix, dstPrefix) diff --git a/internal/storage/scheme.go b/internal/storage/scheme.go index aabf23017..96f4e6cd7 100644 --- a/internal/storage/scheme.go +++ b/internal/storage/scheme.go @@ -1,9 +1,10 @@ package storage import ( - "errors" "net/url" "strings" + + "github.com/go-errors/errors" ) const STORAGE_SCHEME = "ss" @@ -13,10 +14,10 @@ var ErrInvalidURL = errors.New("URL must match pattern ss:///bucket/[prefix]") func ParseStorageURL(objectURL string) (string, error) { parsed, err := url.Parse(objectURL) if err != nil { - return "", err + return "", errors.Errorf("failed to parse storage url: %w", err) } if strings.ToLower(parsed.Scheme) != STORAGE_SCHEME || len(parsed.Path) == 0 || len(parsed.Host) > 0 { - return "", ErrInvalidURL + return "", errors.New(ErrInvalidURL) } return parsed.Path, nil } diff --git a/internal/test/new/new.go b/internal/test/new/new.go index 3fb61345d..a8bf177f2 100644 --- a/internal/test/new/new.go +++ b/internal/test/new/new.go @@ -22,17 +22,14 @@ var ( func Run(ctx context.Context, name, template string, fsys afero.Fs) error { path := filepath.Join(utils.DbTestsDir, fmt.Sprintf("%s_test.sql", name)) - if err := utils.MkdirIfNotExistFS(fsys, filepath.Dir(path)); err != nil { - return err - } if _, err := fsys.Stat(path); err == nil { return errors.New(path + " already exists.") } - err := afero.WriteFile(fsys, path, getTemplate(template), 0644) - if err == nil { - fmt.Printf("Created new %s test at %s.\n", template, utils.Bold(path)) + if err := utils.WriteFile(path, getTemplate(template), fsys); err != nil { + return err } - return err + fmt.Printf("Created new %s test at %s.\n", template, utils.Bold(path)) + return nil } func getTemplate(name string) []byte { diff --git a/internal/utils/pgxv5/rows.go b/internal/utils/pgxv5/rows.go index 827735a6d..25021376a 100644 --- a/internal/utils/pgxv5/rows.go +++ b/internal/utils/pgxv5/rows.go @@ -10,6 +10,21 @@ import ( "github.com/jackc/pgx/v4" ) +func CollectStrings(rows pgx.Rows) ([]string, error) { + result := []string{} + for rows.Next() { + var version string + if err := rows.Scan(&version); err != nil { + return nil, errors.Errorf("failed to scan rows: %w", err) + } + result = append(result, version) + } + if err := rows.Err(); err != nil { + return nil, errors.Errorf("failed to parse rows: %w", err) + } + return result, nil +} + // CollectRows iterates through rows, calling fn for each row, and collecting the results into a slice of T. func CollectRows[T any](rows pgx.Rows) ([]T, error) { defer rows.Close() diff --git a/internal/vanity_subdomains/activate/activate.go b/internal/vanity_subdomains/activate/activate.go index f814fba27..4c954f6e2 100644 --- a/internal/vanity_subdomains/activate/activate.go +++ b/internal/vanity_subdomains/activate/activate.go @@ -2,10 +2,10 @@ package activate import ( "context" - "errors" "fmt" "strings" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" "github.com/supabase/cli/pkg/api" @@ -26,7 +26,7 @@ func Run(ctx context.Context, projectRef string, desiredSubdomain string, fsys a VanitySubdomain: subdomain, }) if err != nil { - return err + return errors.Errorf("failed activate vanity subdomain: %w", err) } if resp.JSON201 == nil { return errors.New("failed to create vanity subdomain config: " + string(resp.Body)) diff --git a/internal/vanity_subdomains/check/check.go b/internal/vanity_subdomains/check/check.go index a58a8f704..26da5bfef 100644 --- a/internal/vanity_subdomains/check/check.go +++ b/internal/vanity_subdomains/check/check.go @@ -2,10 +2,10 @@ package check import ( "context" - "errors" "fmt" "strings" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" "github.com/supabase/cli/pkg/api" @@ -26,7 +26,7 @@ func Run(ctx context.Context, projectRef string, desiredSubdomain string, fsys a VanitySubdomain: subdomain, }) if err != nil { - return err + return errors.Errorf("failed to check vanity subdomain: %w", err) } if resp.JSON201 == nil { return errors.New("failed to check subdomain availability: " + string(resp.Body)) diff --git a/internal/vanity_subdomains/delete/delete.go b/internal/vanity_subdomains/delete/delete.go index 6c4da5b07..2b45f8c9d 100644 --- a/internal/vanity_subdomains/delete/delete.go +++ b/internal/vanity_subdomains/delete/delete.go @@ -2,9 +2,9 @@ package delete import ( "context" - "errors" "fmt" + "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" ) @@ -15,7 +15,7 @@ func Run(ctx context.Context, projectRef string, fsys afero.Fs) error { { resp, err := utils.GetSupabase().RemoveVanitySubdomainConfigWithResponse(ctx, projectRef) if err != nil { - return err + return errors.Errorf("failed to delete vanity subdomain: %w", err) } if resp.StatusCode() != 200 { return errors.New("failed to delete vanity subdomain config; received: " + string(resp.Body)) diff --git a/internal/vanity_subdomains/get/get.go b/internal/vanity_subdomains/get/get.go index b7d686d84..27ac0ef35 100644 --- a/internal/vanity_subdomains/get/get.go +++ b/internal/vanity_subdomains/get/get.go @@ -15,7 +15,7 @@ func Run(ctx context.Context, projectRef string, fsys afero.Fs) error { { response, err := utils.GetSupabase().GetVanitySubdomainConfigWithResponse(ctx, projectRef) if err != nil { - return err + return errors.Errorf("failed to get vanity subdomain: %w", err) } if response.JSON200 == nil { return errors.Errorf("failed to obtain vanity subdomain config: %+v", string(response.Body))