diff --git a/cmd/config.go b/cmd/config.go new file mode 100644 index 000000000..d73daa546 --- /dev/null +++ b/cmd/config.go @@ -0,0 +1,38 @@ +package cmd + +import ( + "os" + "os/signal" + + "github.com/spf13/afero" + "github.com/spf13/cobra" + "github.com/supabase/cli/internal/config/push" + "github.com/supabase/cli/internal/utils/flags" +) + +var ( + configCmd = &cobra.Command{ + GroupID: groupManagementAPI, + Use: "config", + Short: "Manage Supabase project configurations", + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + ctx, _ := signal.NotifyContext(cmd.Context(), os.Interrupt) + cmd.SetContext(ctx) + return cmd.Root().PersistentPreRunE(cmd, args) + }, + } + + configPushCmd = &cobra.Command{ + Use: "push", + Short: "Pushes local config.toml to the linked project", + RunE: func(cmd *cobra.Command, args []string) error { + return push.Run(cmd.Context(), flags.ProjectRef, afero.NewOsFs()) + }, + } +) + +func init() { + configCmd.PersistentFlags().StringVar(&flags.ProjectRef, "project-ref", "", "Project ref of the Supabase project.") + configCmd.AddCommand(configPushCmd) + rootCmd.AddCommand(configCmd) +} diff --git a/internal/config/push/push.go b/internal/config/push/push.go new file mode 100644 index 000000000..0a8c88c4e --- /dev/null +++ b/internal/config/push/push.go @@ -0,0 +1,30 @@ +package push + +import ( + "context" + "fmt" + "os" + + "github.com/spf13/afero" + "github.com/supabase/cli/internal/utils" + "github.com/supabase/cli/pkg/config" +) + +func Run(ctx context.Context, ref string, fsys afero.Fs) error { + if err := utils.LoadConfigFS(fsys); err != nil { + return err + } + client := config.NewConfigUpdater(*utils.GetSupabase()) + fmt.Fprintln(os.Stderr, "Pushing config to project:", ref) + remote, _ := utils.Config.GetRemoteByProjectRef(ref) + console := utils.NewConsole() + keep := func(name string) bool { + title := fmt.Sprintf("Do you want to push %s config to remote?", name) + shouldPush, err := console.PromptYesNo(ctx, title, true) + if err != nil { + fmt.Fprintln(os.Stderr, err) + } + return shouldPush + } + return client.UpdateRemoteConfig(ctx, remote, keep) +} diff --git a/pkg/config/updater.go b/pkg/config/updater.go index 832eb639b..445000d0b 100644 --- a/pkg/config/updater.go +++ b/pkg/config/updater.go @@ -17,26 +17,26 @@ 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 { +func (u *ConfigUpdater) UpdateRemoteConfig(ctx context.Context, remote baseConfig, filter ...func(string) bool) error { + if err := u.UpdateApiConfig(ctx, remote.ProjectId, remote.Api, filter...); err != nil { return err } - if err := u.UpdateDbConfig(ctx, remote.ProjectId, remote.Db); err != nil { + if err := u.UpdateDbConfig(ctx, remote.ProjectId, remote.Db, filter...); err != nil { return err } - if err := u.UpdateAuthConfig(ctx, remote.ProjectId, remote.Auth); err != nil { + if err := u.UpdateAuthConfig(ctx, remote.ProjectId, remote.Auth, filter...); err != nil { return err } - if err := u.UpdateStorageConfig(ctx, remote.ProjectId, remote.Storage); err != nil { + if err := u.UpdateStorageConfig(ctx, remote.ProjectId, remote.Storage, filter...); err != nil { return err } - if err := u.UpdateExperimentalConfig(ctx, remote.ProjectId, remote.Experimental); err != nil { + if err := u.UpdateExperimentalConfig(ctx, remote.ProjectId, remote.Experimental, filter...); err != nil { return err } return nil } -func (u *ConfigUpdater) UpdateApiConfig(ctx context.Context, projectRef string, c api) error { +func (u *ConfigUpdater) UpdateApiConfig(ctx context.Context, projectRef string, c api, filter ...func(string) bool) error { apiConfig, err := u.client.V1GetPostgrestServiceConfigWithResponse(ctx, projectRef) if err != nil { return errors.Errorf("failed to read API config: %w", err) @@ -51,7 +51,11 @@ func (u *ConfigUpdater) UpdateApiConfig(ctx context.Context, projectRef string, return nil } fmt.Fprintln(os.Stderr, "Updating API service with config:", string(apiDiff)) - + for _, keep := range filter { + if !keep("api") { + return nil + } + } 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 { @@ -60,7 +64,7 @@ func (u *ConfigUpdater) UpdateApiConfig(ctx context.Context, projectRef string, return nil } -func (u *ConfigUpdater) UpdateDbSettingsConfig(ctx context.Context, projectRef string, s settings) error { +func (u *ConfigUpdater) UpdateDbSettingsConfig(ctx context.Context, projectRef string, s settings, filter ...func(string) bool) error { dbConfig, err := u.client.V1GetPostgresConfigWithResponse(ctx, projectRef) if err != nil { return errors.Errorf("failed to read DB config: %w", err) @@ -75,6 +79,11 @@ func (u *ConfigUpdater) UpdateDbSettingsConfig(ctx context.Context, projectRef s return nil } fmt.Fprintln(os.Stderr, "Updating DB service with config:", string(dbDiff)) + for _, keep := range filter { + if !keep("db") { + return nil + } + } updateBody := s.ToUpdatePostgresConfigBody() if resp, err := u.client.V1UpdatePostgresConfigWithResponse(ctx, projectRef, updateBody); err != nil { return errors.Errorf("failed to update DB config: %w", err) @@ -84,14 +93,14 @@ func (u *ConfigUpdater) UpdateDbSettingsConfig(ctx context.Context, projectRef s return nil } -func (u *ConfigUpdater) UpdateDbConfig(ctx context.Context, projectRef string, c db) error { - if err := u.UpdateDbSettingsConfig(ctx, projectRef, c.Settings); err != nil { +func (u *ConfigUpdater) UpdateDbConfig(ctx context.Context, projectRef string, c db, filter ...func(string) bool) error { + if err := u.UpdateDbSettingsConfig(ctx, projectRef, c.Settings, filter...); err != nil { return err } return nil } -func (u *ConfigUpdater) UpdateAuthConfig(ctx context.Context, projectRef string, c auth) error { +func (u *ConfigUpdater) UpdateAuthConfig(ctx context.Context, projectRef string, c auth, filter ...func(string) bool) error { if !c.Enabled { return nil } @@ -109,7 +118,11 @@ func (u *ConfigUpdater) UpdateAuthConfig(ctx context.Context, projectRef string, return nil } fmt.Fprintln(os.Stderr, "Updating Auth service with config:", string(authDiff)) - + for _, keep := range filter { + if !keep("auth") { + return nil + } + } if resp, err := u.client.V1UpdateAuthServiceConfigWithResponse(ctx, projectRef, c.ToUpdateAuthConfigBody()); err != nil { return errors.Errorf("failed to update Auth config: %w", err) } else if status := resp.StatusCode(); status < 200 || status >= 300 { @@ -118,7 +131,7 @@ func (u *ConfigUpdater) UpdateAuthConfig(ctx context.Context, projectRef string, return nil } -func (u *ConfigUpdater) UpdateStorageConfig(ctx context.Context, projectRef string, c storage) error { +func (u *ConfigUpdater) UpdateStorageConfig(ctx context.Context, projectRef string, c storage, filter ...func(string) bool) error { if !c.Enabled { return nil } @@ -136,7 +149,11 @@ func (u *ConfigUpdater) UpdateStorageConfig(ctx context.Context, projectRef stri return nil } fmt.Fprintln(os.Stderr, "Updating Storage service with config:", string(storageDiff)) - + for _, keep := range filter { + if !keep("storage") { + return nil + } + } if resp, err := u.client.V1UpdateStorageConfigWithResponse(ctx, projectRef, c.ToUpdateStorageConfigBody()); err != nil { return errors.Errorf("failed to update Storage config: %w", err) } else if status := resp.StatusCode(); status < 200 || status >= 300 { @@ -145,10 +162,14 @@ func (u *ConfigUpdater) UpdateStorageConfig(ctx context.Context, projectRef stri return nil } -func (u *ConfigUpdater) UpdateExperimentalConfig(ctx context.Context, projectRef string, exp experimental) error { +func (u *ConfigUpdater) UpdateExperimentalConfig(ctx context.Context, projectRef string, exp experimental, filter ...func(string) bool) error { if exp.Webhooks != nil && exp.Webhooks.Enabled { fmt.Fprintln(os.Stderr, "Enabling webhooks for project:", projectRef) - + for _, keep := range filter { + if !keep("webhooks") { + return nil + } + } if resp, err := u.client.V1EnableDatabaseWebhookWithResponse(ctx, projectRef); err != nil { return errors.Errorf("failed to enable webhooks: %w", err) } else if status := resp.StatusCode(); status < 200 || status >= 300 {