• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / cli / 18473583231

13 Oct 2025 05:27PM UTC coverage: 54.624% (-0.06%) from 54.687%
18473583231

Pull #4303

github

web-flow
Merge ea13baf26 into 068afe697
Pull Request #4303: feat: allow customising notify url for branches

0 of 8 new or added lines in 1 file covered. (0.0%)

6 existing lines in 2 files now uncovered.

6409 of 11733 relevant lines covered (54.62%)

6.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/cmd/branches.go
1
package cmd
2

3
import (
4
        "context"
5
        "fmt"
6
        "os"
7

8
        "github.com/go-errors/errors"
9
        "github.com/spf13/afero"
10
        "github.com/spf13/cobra"
11
        "github.com/supabase/cli/internal/branches/create"
12
        "github.com/supabase/cli/internal/branches/delete"
13
        "github.com/supabase/cli/internal/branches/disable"
14
        "github.com/supabase/cli/internal/branches/get"
15
        "github.com/supabase/cli/internal/branches/list"
16
        "github.com/supabase/cli/internal/branches/pause"
17
        "github.com/supabase/cli/internal/branches/unpause"
18
        "github.com/supabase/cli/internal/branches/update"
19
        "github.com/supabase/cli/internal/gen/keys"
20
        "github.com/supabase/cli/internal/utils"
21
        "github.com/supabase/cli/internal/utils/flags"
22
        "github.com/supabase/cli/pkg/api"
23
        "github.com/supabase/cli/pkg/cast"
24
)
25

26
var (
27
        branchesCmd = &cobra.Command{
28
                GroupID: groupManagementAPI,
29
                Use:     "branches",
30
                Short:   "Manage Supabase preview branches",
31
        }
32

33
        branchRegion = utils.EnumFlag{
34
                Allowed: awsRegions(),
35
        }
36
        persistent bool
37
        withData   bool
38
        notifyURL  string
39

40
        branchCreateCmd = &cobra.Command{
41
                Use:   "create [name]",
42
                Short: "Create a preview branch",
43
                Long:  "Create a preview branch for the linked project.",
44
                Args:  cobra.MaximumNArgs(1),
45
                RunE: func(cmd *cobra.Command, args []string) error {
×
46
                        body := api.CreateBranchBody{IsDefault: cast.Ptr(false)}
×
47
                        if len(args) > 0 {
×
48
                                body.BranchName = args[0]
×
49
                        }
×
50
                        cmdFlags := cmd.Flags()
×
51
                        if cmdFlags.Changed("region") {
×
52
                                body.Region = &branchRegion.Value
×
53
                        }
×
54
                        if cmdFlags.Changed("size") {
×
55
                                body.DesiredInstanceSize = (*api.CreateBranchBodyDesiredInstanceSize)(&size.Value)
×
56
                        }
×
57
                        if cmdFlags.Changed("persistent") {
×
58
                                body.Persistent = &persistent
×
59
                        }
×
60
                        if cmdFlags.Changed("with-data") {
×
61
                                body.WithData = &withData
×
62
                        }
×
NEW
63
                        if cmdFlags.Changed("notify-url") {
×
NEW
64
                                body.NotifyUrl = &notifyURL
×
NEW
65
                        }
×
UNCOV
66
                        return create.Run(cmd.Context(), body, afero.NewOsFs())
×
67
                },
68
        }
69

70
        branchListCmd = &cobra.Command{
71
                Use:   "list",
72
                Short: "List all preview branches",
73
                Long:  "List all preview branches of the linked project.",
74
                Args:  cobra.NoArgs,
75
                RunE: func(cmd *cobra.Command, args []string) error {
×
76
                        return list.Run(cmd.Context(), afero.NewOsFs())
×
77
                },
×
78
        }
79

80
        branchId string
81

82
        branchGetCmd = &cobra.Command{
83
                Use:   "get [name]",
84
                Short: "Retrieve details of a preview branch",
85
                Long:  "Retrieve details of the specified preview branch.",
86
                Args:  cobra.MaximumNArgs(1),
87
                RunE: func(cmd *cobra.Command, args []string) error {
×
88
                        ctx := cmd.Context()
×
89
                        fsys := afero.NewOsFs()
×
90
                        if len(args) > 0 {
×
91
                                branchId = args[0]
×
92
                        } else if err := promptBranchId(ctx, fsys); err != nil {
×
93
                                return err
×
94
                        }
×
95
                        return get.Run(ctx, branchId, fsys)
×
96
                },
97
        }
98

99
        branchStatus = utils.EnumFlag{
100
                Allowed: []string{
101
                        string(api.BranchResponseStatusRUNNINGMIGRATIONS),
102
                        string(api.BranchResponseStatusMIGRATIONSPASSED),
103
                        string(api.BranchResponseStatusMIGRATIONSFAILED),
104
                        string(api.BranchResponseStatusFUNCTIONSDEPLOYED),
105
                        string(api.BranchResponseStatusFUNCTIONSFAILED),
106
                },
107
        }
108
        branchName string
109
        gitBranch  string
110

111
        branchUpdateCmd = &cobra.Command{
112
                Use:   "update [name]",
113
                Short: "Update a preview branch",
114
                Long:  "Update a preview branch by its name or ID.",
115
                Args:  cobra.MaximumNArgs(1),
116
                RunE: func(cmd *cobra.Command, args []string) error {
×
117
                        cmdFlags := cmd.Flags()
×
118
                        var body api.UpdateBranchBody
×
119
                        if cmdFlags.Changed("name") {
×
120
                                body.BranchName = &branchName
×
121
                        }
×
122
                        if cmdFlags.Changed("git-branch") {
×
123
                                body.GitBranch = &gitBranch
×
124
                        }
×
125
                        if cmdFlags.Changed("persistent") {
×
126
                                body.Persistent = &persistent
×
127
                        }
×
128
                        if cmdFlags.Changed("status") {
×
129
                                body.Status = (*api.UpdateBranchBodyStatus)(&branchStatus.Value)
×
130
                        }
×
NEW
131
                        if cmdFlags.Changed("notify-url") {
×
NEW
132
                                body.NotifyUrl = &notifyURL
×
NEW
133
                        }
×
134
                        ctx := cmd.Context()
×
135
                        fsys := afero.NewOsFs()
×
136
                        if len(args) > 0 {
×
137
                                branchId = args[0]
×
138
                        } else if err := promptBranchId(ctx, fsys); err != nil {
×
139
                                return err
×
140
                        }
×
141
                        return update.Run(cmd.Context(), branchId, body, fsys)
×
142
                },
143
        }
144

145
        branchPauseCmd = &cobra.Command{
146
                Use:   "pause [name]",
147
                Short: "Pause a preview branch",
148
                Args:  cobra.MaximumNArgs(1),
149
                RunE: func(cmd *cobra.Command, args []string) error {
×
150
                        ctx := cmd.Context()
×
151
                        fsys := afero.NewOsFs()
×
152
                        if len(args) > 0 {
×
153
                                branchId = args[0]
×
154
                        } else if err := promptBranchId(ctx, fsys); err != nil {
×
155
                                return err
×
156
                        }
×
157
                        return pause.Run(ctx, branchId)
×
158
                },
159
        }
160

161
        branchUnpauseCmd = &cobra.Command{
162
                Use:   "unpause [name]",
163
                Short: "Unpause a preview branch",
164
                Args:  cobra.MaximumNArgs(1),
165
                RunE: func(cmd *cobra.Command, args []string) error {
×
166
                        ctx := cmd.Context()
×
167
                        fsys := afero.NewOsFs()
×
168
                        if len(args) > 0 {
×
169
                                branchId = args[0]
×
170
                        } else if err := promptBranchId(ctx, fsys); err != nil {
×
171
                                return err
×
172
                        }
×
173
                        return unpause.Run(ctx, branchId)
×
174
                },
175
        }
176

177
        branchDeleteCmd = &cobra.Command{
178
                Use:   "delete [name]",
179
                Short: "Delete a preview branch",
180
                Long:  "Delete a preview branch by its name or ID.",
181
                Args:  cobra.MaximumNArgs(1),
182
                RunE: func(cmd *cobra.Command, args []string) error {
×
183
                        ctx := cmd.Context()
×
184
                        fsys := afero.NewOsFs()
×
185
                        if len(args) > 0 {
×
186
                                branchId = args[0]
×
187
                        } else if err := promptBranchId(ctx, fsys); err != nil {
×
188
                                return err
×
189
                        }
×
190
                        return delete.Run(ctx, branchId)
×
191
                },
192
        }
193

194
        branchDisableCmd = &cobra.Command{
195
                Hidden: true,
196
                Use:    "disable",
197
                Short:  "Disable preview branching",
198
                Long:   "Disable preview branching for the linked project.",
199
                RunE: func(cmd *cobra.Command, args []string) error {
×
200
                        return disable.Run(cmd.Context(), afero.NewOsFs())
×
201
                },
×
202
        }
203
)
204

205
func init() {
×
206
        branchFlags := branchesCmd.PersistentFlags()
×
207
        branchFlags.StringVar(&flags.ProjectRef, "project-ref", "", "Project ref of the Supabase project.")
×
208
        createFlags := branchCreateCmd.Flags()
×
209
        createFlags.Var(&branchRegion, "region", "Select a region to deploy the branch database.")
×
210
        createFlags.Var(&size, "size", "Select a desired instance size for the branch database.")
×
211
        createFlags.BoolVar(&persistent, "persistent", false, "Whether to create a persistent branch.")
×
212
        createFlags.BoolVar(&withData, "with-data", false, "Whether to clone production data to the branch database.")
×
NEW
213
        createFlags.StringVar(&notifyURL, "notify-url", "", "URL to notify when branch is active healthy.")
×
214
        branchesCmd.AddCommand(branchCreateCmd)
×
215
        branchesCmd.AddCommand(branchListCmd)
×
216
        branchesCmd.AddCommand(branchGetCmd)
×
217
        updateFlags := branchUpdateCmd.Flags()
×
218
        updateFlags.StringVar(&branchName, "name", "", "Rename the preview branch.")
×
219
        updateFlags.StringVar(&gitBranch, "git-branch", "", "Change the associated git branch.")
×
220
        updateFlags.BoolVar(&persistent, "persistent", false, "Switch between ephemeral and persistent branch.")
×
221
        updateFlags.Var(&branchStatus, "status", "Override the current branch status.")
×
NEW
222
        updateFlags.StringVar(&notifyURL, "notify-url", "", "URL to notify when branch is active healthy.")
×
223
        branchesCmd.AddCommand(branchUpdateCmd)
×
224
        branchesCmd.AddCommand(branchDeleteCmd)
×
225
        branchesCmd.AddCommand(branchDisableCmd)
×
226
        branchesCmd.AddCommand(branchPauseCmd)
×
227
        branchesCmd.AddCommand(branchUnpauseCmd)
×
228
        rootCmd.AddCommand(branchesCmd)
×
229
}
×
230

231
func promptBranchId(ctx context.Context, fsys afero.Fs) error {
×
232
        if console := utils.NewConsole(); !console.IsTTY {
×
233
                // Only read from stdin if the terminal is non-interactive
×
234
                title := "Enter the name of your branch"
×
235
                if branchId = keys.GetGitBranch(fsys); len(branchId) > 0 {
×
236
                        title += fmt.Sprintf(" (or leave blank to use %s)", utils.Aqua(branchId))
×
237
                }
×
238
                title += ": "
×
239
                if name, err := console.PromptText(ctx, title); err != nil {
×
240
                        return err
×
241
                } else if len(name) > 0 {
×
242
                        branchId = name
×
243
                }
×
244
                if len(branchId) == 0 {
×
245
                        return errors.New("branch name cannot be empty")
×
246
                }
×
247
                return nil
×
248
        }
249
        branches, err := list.ListBranch(ctx, flags.ProjectRef)
×
250
        if err != nil {
×
251
                return err
×
252
        } else if len(branches) == 0 {
×
253
                utils.CmdSuggestion = fmt.Sprintf("Create your first branch with: %s", utils.Aqua("supabase branches create"))
×
254
                return errors.Errorf("branching is disabled")
×
255
        }
×
256
        // Let user choose from a list of branches
257
        items := make([]utils.PromptItem, len(branches))
×
258
        for i, branch := range branches {
×
259
                items[i] = utils.PromptItem{
×
260
                        Summary: branch.Name,
×
261
                        Details: branch.ProjectRef,
×
262
                }
×
263
        }
×
264
        title := "Select a branch:"
×
265
        choice, err := utils.PromptChoice(ctx, title, items)
×
266
        if err == nil {
×
267
                branchId = choice.Details
×
268
                fmt.Fprintln(os.Stderr, "Selected branch ID:", branchId)
×
269
        }
×
270
        return err
×
271
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc