Skip to content

Commit e07c7ea

Browse files
authored
feat: download all functions if no name is provided (#4789)
2 parents 9c3d835 + 04c8e03 commit e07c7ea

File tree

2 files changed

+48
-16
lines changed

2 files changed

+48
-16
lines changed

cmd/functions.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,19 @@ var (
4444
}
4545

4646
functionsDownloadCmd = &cobra.Command{
47-
Use: "download <Function name>",
47+
Use: "download [Function name]",
4848
Short: "Download a Function from Supabase",
49-
Long: "Download the source code for a Function from the linked Supabase project.",
50-
Args: cobra.ExactArgs(1),
49+
Long: "Download the source code for a Function from the linked Supabase project. If no function name is provided, downloads all functions.",
50+
Args: cobra.MaximumNArgs(1),
5151
RunE: func(cmd *cobra.Command, args []string) error {
5252
if useApi {
5353
useDocker = false
5454
}
55-
return download.Run(cmd.Context(), args[0], flags.ProjectRef, useLegacyBundle, useDocker, afero.NewOsFs())
55+
slug := ""
56+
if len(args) > 0 {
57+
slug = args[0]
58+
}
59+
return download.Run(cmd.Context(), slug, flags.ProjectRef, useLegacyBundle, useDocker, afero.NewOsFs())
5660
},
5761
}
5862

internal/functions/download/download.go

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func RunLegacy(ctx context.Context, slug string, projectRef string, fsys afero.F
5656
return err
5757
}
5858

59-
fmt.Println("Downloaded Function " + utils.Aqua(slug) + " from project " + utils.Aqua(projectRef) + ".")
59+
fmt.Fprintf(os.Stderr, "Downloaded Function %s from project %s.\n", utils.Aqua(slug), utils.Aqua(projectRef))
6060
return nil
6161
}
6262

@@ -85,7 +85,7 @@ func getFunctionMetadata(ctx context.Context, projectRef, slug string) (*api.Fun
8585
}
8686

8787
func downloadFunction(ctx context.Context, projectRef, slug, extractScriptPath string) error {
88-
fmt.Println("Downloading " + utils.Bold(slug))
88+
fmt.Fprintln(os.Stderr, "Downloading function:", utils.Bold(slug))
8989
denoPath, err := utils.GetDenoPath()
9090
if err != nil {
9191
return err
@@ -124,21 +124,49 @@ func Run(ctx context.Context, slug, projectRef string, useLegacyBundle, useDocke
124124
return err
125125
}
126126

127+
// Defaults to server-side unbundling with multipart/form-data
128+
downloader := downloadWithServerSideUnbundle
127129
if useLegacyBundle {
128-
return RunLegacy(ctx, slug, projectRef, fsys)
129-
}
130-
131-
if useDocker {
130+
downloader = RunLegacy
131+
} else if useDocker {
132132
if utils.IsDockerRunning(ctx) {
133-
// download eszip file for client-side unbundling with edge-runtime
134-
return downloadWithDockerUnbundle(ctx, slug, projectRef, fsys)
133+
// Download eszip file for client-side unbundling with edge-runtime
134+
downloader = downloadWithDockerUnbundle
135135
} else {
136136
fmt.Fprintln(os.Stderr, utils.Yellow("WARNING:"), "Docker is not running")
137137
}
138138
}
139139

140-
// Use server-side unbundling with multipart/form-data
141-
return downloadWithServerSideUnbundle(ctx, slug, projectRef, fsys)
140+
if len(slug) > 0 {
141+
return downloader(ctx, slug, projectRef, fsys)
142+
}
143+
return downloadAll(ctx, projectRef, fsys, downloader)
144+
}
145+
146+
func downloadAll(ctx context.Context, projectRef string, fsys afero.Fs, downloader func(context.Context, string, string, afero.Fs) error) error {
147+
resp, err := utils.GetSupabase().V1ListAllFunctionsWithResponse(ctx, projectRef)
148+
if err != nil {
149+
return errors.Errorf("failed to list functions: %w", err)
150+
}
151+
if resp.JSON200 == nil {
152+
return errors.Errorf("unexpected list functions status %d: %s", resp.StatusCode(), string(resp.Body))
153+
}
154+
155+
functions := *resp.JSON200
156+
if len(functions) == 0 {
157+
fmt.Fprintln(os.Stderr, "No functions found in project ", utils.Aqua(projectRef))
158+
return nil
159+
}
160+
161+
fmt.Fprintf(os.Stderr, "Found %d function(s) to download\n", len(functions))
162+
for _, f := range functions {
163+
if err := downloader(ctx, f.Slug, projectRef, fsys); err != nil {
164+
return err
165+
}
166+
}
167+
168+
fmt.Fprintln(os.Stderr, "Successfully downloaded all functions from project", utils.Aqua(projectRef))
169+
return nil
142170
}
143171

144172
func downloadWithDockerUnbundle(ctx context.Context, slug string, projectRef string, fsys afero.Fs) error {
@@ -162,7 +190,7 @@ func downloadWithDockerUnbundle(ctx context.Context, slug string, projectRef str
162190
}
163191

164192
func downloadOne(ctx context.Context, slug, projectRef string, fsys afero.Fs) (string, error) {
165-
fmt.Println("Downloading " + utils.Bold(slug))
193+
fmt.Fprintln(os.Stderr, "Downloading function:", utils.Bold(slug))
166194
resp, err := utils.GetSupabase().V1GetAFunctionBody(ctx, projectRef, slug)
167195
if err != nil {
168196
return "", errors.Errorf("failed to get function body: %w", err)
@@ -313,7 +341,7 @@ func downloadWithServerSideUnbundle(ctx context.Context, slug, projectRef string
313341
}
314342
}
315343

316-
fmt.Println("Downloaded Function " + utils.Aqua(slug) + " from project " + utils.Aqua(projectRef) + ".")
344+
fmt.Fprintf(os.Stderr, "Downloaded Function %s from project %s.\n", utils.Aqua(slug), utils.Aqua(projectRef))
317345
return nil
318346
}
319347

0 commit comments

Comments
 (0)