From f19a33819262145867993569e28995d041e87429 Mon Sep 17 00:00:00 2001 From: Qiao Han Date: Tue, 4 Feb 2025 15:44:35 +0800 Subject: [PATCH 1/2] feat: make config file optional --- internal/utils/flags/config_path.go | 7 ------- internal/utils/misc.go | 10 ---------- pkg/config/config.go | 8 +++++--- pkg/config/config_test.go | 8 ++++++++ 4 files changed, 13 insertions(+), 20 deletions(-) diff --git a/internal/utils/flags/config_path.go b/internal/utils/flags/config_path.go index d0ed105c71..bec77a4324 100644 --- a/internal/utils/flags/config_path.go +++ b/internal/utils/flags/config_path.go @@ -1,10 +1,6 @@ package flags import ( - "fmt" - "os" - - "github.com/go-errors/errors" "github.com/spf13/afero" "github.com/supabase/cli/internal/utils" ) @@ -12,9 +8,6 @@ import ( func LoadConfig(fsys afero.Fs) error { utils.Config.ProjectId = ProjectRef if err := utils.Config.Load("", utils.NewRootFS(fsys)); err != nil { - if errors.Is(err, os.ErrNotExist) { - utils.CmdSuggestion = fmt.Sprintf("Have you set up the project with %s?", utils.Aqua("supabase init")) - } return err } utils.UpdateDockerIds() diff --git a/internal/utils/misc.go b/internal/utils/misc.go index 32a2fdf157..d7d9fd33c4 100644 --- a/internal/utils/misc.go +++ b/internal/utils/misc.go @@ -261,16 +261,6 @@ func WriteFile(path string, contents []byte, fsys afero.Fs) error { return nil } -func AssertSupabaseCliIsSetUpFS(fsys afero.Fs) error { - if _, err := fsys.Stat(ConfigPath); errors.Is(err, os.ErrNotExist) { - return errors.Errorf("Cannot find %s in the current directory. Have you set up the project with %s?", Bold(ConfigPath), Aqua("supabase init")) - } else if err != nil { - return errors.Errorf("failed to read config file: %w", err) - } - - return nil -} - func AssertProjectRefIsValid(projectRef string) error { if !ProjectRefPattern.MatchString(projectRef) { return errors.New(ErrInvalidRef) diff --git a/pkg/config/config.go b/pkg/config/config.go index 5d7616575f..2bb199c01f 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -379,8 +379,8 @@ func (c *config) loadFromFile(filename string, fsys fs.FS) error { v.SetConfigType("toml") // Load default values var buf bytes.Buffer - if err := initConfigTemplate.Option("missingkey=zero").Execute(&buf, c); err != nil { - return errors.Errorf("failed to initialise template config: %w", err) + if err := c.Eject(&buf); err != nil { + return err } else if err := c.loadFromReader(v, &buf); err != nil { return err } @@ -389,7 +389,9 @@ func (c *config) loadFromFile(filename string, fsys fs.FS) error { v.SetConfigType(ext[1:]) } f, err := fsys.Open(filename) - if err != nil { + if errors.Is(err, os.ErrNotExist) { + return nil + } else if err != nil { return errors.Errorf("failed to read file config: %w", err) } defer f.Close() diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index e13e67e59a..ce1fcfa6ae 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -28,6 +28,14 @@ func TestConfigParsing(t *testing.T) { assert.NoError(t, config.Load("config.toml", fsys)) }) + t.Run("optional config file", func(t *testing.T) { + config := NewConfig() + // Run test + err := config.Load("", fs.MapFS{}) + // Check error + assert.NoError(t, err) + }) + t.Run("config file with environment variables", func(t *testing.T) { config := NewConfig() // Setup in-memory fs From a7a246a9269bfe4ae5e33c6c430fd52422d669c6 Mon Sep 17 00:00:00 2001 From: Qiao Han Date: Tue, 4 Feb 2025 17:05:45 +0800 Subject: [PATCH 2/2] chore: update unit tests --- internal/db/branch/switch_/switch__test.go | 10 ---------- internal/db/diff/diff_test.go | 23 ++++++++++++++++++++-- internal/db/pull/pull_test.go | 6 +++--- internal/db/start/start_test.go | 5 +++-- internal/functions/serve/serve_test.go | 5 +++-- internal/start/start_test.go | 8 +------- internal/status/status_test.go | 8 +------- internal/stop/stop_test.go | 6 +++--- 8 files changed, 35 insertions(+), 36 deletions(-) diff --git a/internal/db/branch/switch_/switch__test.go b/internal/db/branch/switch_/switch__test.go index 722229b79d..4e2e1055b2 100644 --- a/internal/db/branch/switch_/switch__test.go +++ b/internal/db/branch/switch_/switch__test.go @@ -3,7 +3,6 @@ package switch_ import ( "context" "net/http" - "os" "path/filepath" "testing" @@ -63,15 +62,6 @@ func TestSwitchCommand(t *testing.T) { assert.Equal(t, []byte(branch), contents) }) - t.Run("throws error on missing config", func(t *testing.T) { - // Setup in-memory fs - fsys := afero.NewMemMapFs() - // Run test - err := Run(context.Background(), "target", fsys) - // Check error - assert.ErrorIs(t, err, os.ErrNotExist) - }) - t.Run("throws error on malformed config", func(t *testing.T) { // Setup in-memory fs fsys := afero.NewMemMapFs() diff --git a/internal/db/diff/diff_test.go b/internal/db/diff/diff_test.go index 370f1be493..d8a596c217 100644 --- a/internal/db/diff/diff_test.go +++ b/internal/db/diff/diff_test.go @@ -85,13 +85,14 @@ func TestRun(t *testing.T) { assert.Equal(t, []byte(diff), contents) }) - t.Run("throws error on missing config", func(t *testing.T) { + t.Run("throws error on malformed config", func(t *testing.T) { // Setup in-memory fs fsys := afero.NewMemMapFs() + require.NoError(t, afero.WriteFile(fsys, utils.ConfigPath, []byte("malformed"), 0644)) // Run test err := Run(context.Background(), []string{"public"}, "", pgconn.Config{}, DiffSchemaMigra, fsys) // Check error - assert.ErrorIs(t, err, os.ErrNotExist) + assert.ErrorContains(t, err, "toml: expected = after a key, but the document ends there") }) t.Run("throws error on failure to load user schemas", func(t *testing.T) { @@ -342,3 +343,21 @@ func TestDropStatements(t *testing.T) { drops := findDropStatements("create table t(); drop table t; alter table t drop column c") assert.Equal(t, []string{"drop table t", "alter table t drop column c"}, drops) } + +func TestLoadSchemas(t *testing.T) { + expected := []string{ + filepath.Join(utils.SchemasDir, "comment", "model.sql"), + filepath.Join(utils.SchemasDir, "model.sql"), + filepath.Join(utils.SchemasDir, "reaction", "dislike", "model.sql"), + filepath.Join(utils.SchemasDir, "reaction", "like", "model.sql"), + } + fsys := afero.NewMemMapFs() + for _, fp := range expected { + require.NoError(t, afero.WriteFile(fsys, fp, nil, 0644)) + } + // Run test + schemas, err := loadDeclaredSchemas(fsys) + // Check error + assert.NoError(t, err) + assert.ElementsMatch(t, expected, schemas) +} diff --git a/internal/db/pull/pull_test.go b/internal/db/pull/pull_test.go index 2e55fcfed8..1c275df406 100644 --- a/internal/db/pull/pull_test.go +++ b/internal/db/pull/pull_test.go @@ -29,14 +29,14 @@ var dbConfig = pgconn.Config{ } func TestPullCommand(t *testing.T) { - t.Run("throws error on missing config", func(t *testing.T) { + t.Run("throws error on malformed config", func(t *testing.T) { // Setup in-memory fs fsys := afero.NewMemMapFs() + require.NoError(t, afero.WriteFile(fsys, utils.ConfigPath, []byte("malformed"), 0644)) // Run test err := Run(context.Background(), nil, pgconn.Config{}, "", fsys) // Check error - assert.ErrorIs(t, err, os.ErrNotExist) - assert.Empty(t, apitest.ListUnmatchedRequests()) + assert.ErrorContains(t, err, "toml: expected = after a key, but the document ends there") }) t.Run("throws error on connect failure", func(t *testing.T) { diff --git a/internal/db/start/start_test.go b/internal/db/start/start_test.go index afdb8e28b2..fdc76c6ec2 100644 --- a/internal/db/start/start_test.go +++ b/internal/db/start/start_test.go @@ -157,13 +157,14 @@ func TestStartDatabase(t *testing.T) { } func TestStartCommand(t *testing.T) { - t.Run("throws error on missing config", func(t *testing.T) { + t.Run("throws error on malformed config", func(t *testing.T) { // Setup in-memory fs fsys := afero.NewMemMapFs() + require.NoError(t, afero.WriteFile(fsys, utils.ConfigPath, []byte("malformed"), 0644)) // Run test err := Run(context.Background(), "", fsys) // Check error - assert.ErrorIs(t, err, os.ErrNotExist) + assert.ErrorContains(t, err, "toml: expected = after a key, but the document ends there") }) t.Run("throws error on missing docker", func(t *testing.T) { diff --git a/internal/functions/serve/serve_test.go b/internal/functions/serve/serve_test.go index 570c4b927d..81c385bde1 100644 --- a/internal/functions/serve/serve_test.go +++ b/internal/functions/serve/serve_test.go @@ -44,13 +44,14 @@ func TestServeCommand(t *testing.T) { assert.Empty(t, apitest.ListUnmatchedRequests()) }) - t.Run("throws error on missing config", func(t *testing.T) { + t.Run("throws error on malformed config", func(t *testing.T) { // Setup in-memory fs fsys := afero.NewMemMapFs() + require.NoError(t, afero.WriteFile(fsys, utils.ConfigPath, []byte("malformed"), 0644)) // Run test err := Run(context.Background(), "", nil, "", RuntimeOption{}, fsys) // Check error - assert.ErrorContains(t, err, "open supabase/config.toml: file does not exist") + assert.ErrorContains(t, err, "toml: expected = after a key, but the document ends there") }) t.Run("throws error on missing db", func(t *testing.T) { diff --git a/internal/start/start_test.go b/internal/start/start_test.go index bbd73ab937..bcc5be02f3 100644 --- a/internal/start/start_test.go +++ b/internal/start/start_test.go @@ -5,7 +5,6 @@ import ( "context" "errors" "net/http" - "os" "regexp" "testing" @@ -25,12 +24,7 @@ import ( ) func TestStartCommand(t *testing.T) { - t.Run("throws error on missing config", func(t *testing.T) { - err := Run(context.Background(), afero.NewMemMapFs(), []string{}, false) - assert.ErrorIs(t, err, os.ErrNotExist) - }) - - t.Run("throws error on invalid config", func(t *testing.T) { + t.Run("throws error on malformed config", func(t *testing.T) { // Setup in-memory fs fsys := afero.NewMemMapFs() require.NoError(t, afero.WriteFile(fsys, utils.ConfigPath, []byte("malformed"), 0644)) diff --git a/internal/status/status_test.go b/internal/status/status_test.go index 175d28ca0e..01dd1e73b2 100644 --- a/internal/status/status_test.go +++ b/internal/status/status_test.go @@ -5,7 +5,6 @@ import ( "context" "errors" "net/http" - "os" "testing" "github.com/docker/docker/api/types" @@ -47,12 +46,7 @@ func TestStatusCommand(t *testing.T) { assert.Empty(t, apitest.ListUnmatchedRequests()) }) - t.Run("throws error on missing config", func(t *testing.T) { - err := Run(context.Background(), CustomName{}, utils.OutputPretty, afero.NewMemMapFs()) - assert.ErrorIs(t, err, os.ErrNotExist) - }) - - t.Run("throws error on invalid config", func(t *testing.T) { + t.Run("throws error on malformed config", func(t *testing.T) { // Setup in-memory fs fsys := afero.NewMemMapFs() require.NoError(t, afero.WriteFile(fsys, utils.ConfigPath, []byte("malformed"), 0644)) diff --git a/internal/stop/stop_test.go b/internal/stop/stop_test.go index b607d87d76..81fad5deea 100644 --- a/internal/stop/stop_test.go +++ b/internal/stop/stop_test.go @@ -6,7 +6,6 @@ import ( "fmt" "io" "net/http" - "os" "testing" "github.com/docker/docker/api/types" @@ -135,13 +134,14 @@ func TestStopCommand(t *testing.T) { assert.Empty(t, apitest.ListUnmatchedRequests()) }) - t.Run("throws error on invalid config", func(t *testing.T) { + t.Run("throws error on malformed config", func(t *testing.T) { // Setup in-memory fs fsys := afero.NewMemMapFs() + require.NoError(t, afero.WriteFile(fsys, utils.ConfigPath, []byte("malformed"), 0644)) // Run test err := Run(context.Background(), false, "", false, fsys) // Check error - assert.ErrorIs(t, err, os.ErrNotExist) + assert.ErrorContains(t, err, "toml: expected = after a key, but the document ends there") }) t.Run("throws error on stop failure", func(t *testing.T) {