diff --git a/pkg/config/updater.go b/pkg/config/updater.go new file mode 100644 index 000000000..467b7bb63 --- /dev/null +++ b/pkg/config/updater.go @@ -0,0 +1,49 @@ +package config + +import ( + "context" + "fmt" + "os" + + "github.com/go-errors/errors" + v1API "github.com/supabase/cli/pkg/api" +) + +type ConfigUpdater struct { + client v1API.ClientWithResponses +} + +func NewConfigUpdater(client v1API.ClientWithResponses) ConfigUpdater { + return ConfigUpdater{client: client} +} + +func (u *ConfigUpdater) UpdateRemoteConfig(ctx context.Context, remote baseConfig) error { + if err := u.UpdateApiConfig(ctx, remote.ProjectId, remote.Api); err != nil { + return err + } + // TODO: implement other service configs, ie. auth + return nil +} + +func (u *ConfigUpdater) UpdateApiConfig(ctx context.Context, projectRef string, c api) error { + apiConfig, err := u.client.V1GetPostgrestServiceConfigWithResponse(ctx, projectRef) + if err != nil { + return errors.Errorf("failed to read API config: %w", err) + } else if apiConfig.JSON200 == nil { + return errors.Errorf("unexpected status %d: %s", apiConfig.StatusCode(), string(apiConfig.Body)) + } + apiDiff, err := c.DiffWithRemote(*apiConfig.JSON200) + if err != nil { + return err + } else if len(apiDiff) == 0 { + fmt.Fprintln(os.Stderr, "Remote API config is up to date.") + return nil + } + fmt.Fprintln(os.Stderr, "Updating API service with config:", string(apiDiff)) + if resp, err := u.client.V1UpdatePostgrestServiceConfigWithResponse(ctx, projectRef, c.ToUpdatePostgrestConfigBody()); err != nil { + return errors.Errorf("failed to update API config: %w", err) + } else if resp.JSON200 == nil { + return errors.Errorf("unexpected status %d: %s", resp.StatusCode(), string(resp.Body)) + } + return nil +} diff --git a/pkg/config/updater_test.go b/pkg/config/updater_test.go new file mode 100644 index 000000000..241d612e9 --- /dev/null +++ b/pkg/config/updater_test.go @@ -0,0 +1,65 @@ +package config + +import ( + "context" + "net/http" + "testing" + + "github.com/h2non/gock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + v1API "github.com/supabase/cli/pkg/api" +) + +func TestUpdateApi(t *testing.T) { + server := "http://localhost" + client, err := v1API.NewClientWithResponses(server) + require.NoError(t, err) + + t.Run("updates remote config", func(t *testing.T) { + updater := NewConfigUpdater(*client) + // Setup mock server + defer gock.Off() + gock.New(server). + Get("/v1/projects/test-project/postgrest"). + Reply(http.StatusOK). + JSON(v1API.PostgrestConfigWithJWTSecretResponse{}) + gock.New(server). + Patch("/v1/projects/test-project/postgrest"). + Reply(http.StatusOK). + JSON(v1API.PostgrestConfigWithJWTSecretResponse{ + DbSchema: "public,graphql_public", + DbExtraSearchPath: "public,extensions", + MaxRows: 1000, + }) + // Run test + err := updater.UpdateApiConfig(context.Background(), "test-project", api{ + Enabled: true, + Schemas: []string{"public", "graphql_public"}, + ExtraSearchPath: []string{"public", "extensions"}, + MaxRows: 1000, + }) + // Check result + assert.NoError(t, err) + assert.True(t, gock.IsDone()) + }) + + t.Run("skips update if no diff", func(t *testing.T) { + updater := NewConfigUpdater(*client) + // Setup mock server + defer gock.Off() + gock.New(server). + Get("/v1/projects/test-project/postgrest"). + Reply(http.StatusOK). + JSON(v1API.PostgrestConfigWithJWTSecretResponse{ + DbSchema: "", + DbExtraSearchPath: "public,extensions", + MaxRows: 1000, + }) + // Run test + err := updater.UpdateApiConfig(context.Background(), "test-project", api{}) + // Check result + assert.NoError(t, err) + assert.True(t, gock.IsDone()) + }) +}