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

supabase / cli / 13259407934

11 Feb 2025 09:11AM UTC coverage: 57.895%. First build
13259407934

Pull #3123

github

web-flow
Merge 6aa46221b into f3486d9be
Pull Request #3123: feat: support deploying functions without docker

51 of 182 new or added lines in 3 files covered. (28.02%)

7722 of 13338 relevant lines covered (57.89%)

201.94 hits per line

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

77.78
/internal/functions/deploy/deploy.go
1
package deploy
2

3
import (
4
        "context"
5
        "fmt"
6
        "os"
7
        "path/filepath"
8
        "strings"
9

10
        "github.com/go-errors/errors"
11
        "github.com/spf13/afero"
12
        "github.com/supabase/cli/internal/utils"
13
        "github.com/supabase/cli/internal/utils/flags"
14
        "github.com/supabase/cli/pkg/cast"
15
        "github.com/supabase/cli/pkg/config"
16
        "github.com/supabase/cli/pkg/function"
17
)
18

19
func Run(ctx context.Context, slugs []string, useDocker bool, noVerifyJWT *bool, importMapPath string, fsys afero.Fs) error {
7✔
20
        // Load function config and project id
7✔
21
        if err := flags.LoadConfig(fsys); err != nil {
7✔
22
                return err
×
23
        } else if len(slugs) > 0 {
11✔
24
                for _, s := range slugs {
9✔
25
                        if err := utils.ValidateFunctionSlug(s); err != nil {
6✔
26
                                return err
1✔
27
                        }
1✔
28
                }
29
        } else if slugs, err = GetFunctionSlugs(fsys); err != nil {
3✔
30
                return err
×
31
        }
×
32
        // TODO: require all functions to be deployed from config for v2
33
        if len(slugs) == 0 {
7✔
34
                return errors.Errorf("No Functions specified or found in %s", utils.Bold(utils.FunctionsDir))
1✔
35
        }
1✔
36
        functionConfig, err := GetFunctionConfig(slugs, importMapPath, noVerifyJWT, fsys)
5✔
37
        if err != nil {
5✔
38
                return err
×
39
        }
×
40
        if useDocker {
10✔
41
                api := function.NewEdgeRuntimeAPI(flags.ProjectRef, *utils.GetSupabase(), NewDockerBundler(fsys))
5✔
42
                if err := api.UpsertFunctions(ctx, functionConfig); err != nil {
5✔
NEW
43
                        return err
×
NEW
44
                }
×
NEW
45
        } else if err := deploy(ctx, functionConfig, fsys); err != nil {
×
46
                return err
×
47
        }
×
48
        fmt.Printf("Deployed Functions on project %s: %s\n", utils.Aqua(flags.ProjectRef), strings.Join(slugs, ", "))
5✔
49
        url := fmt.Sprintf("%s/project/%v/functions", utils.GetSupabaseDashboardURL(), flags.ProjectRef)
5✔
50
        fmt.Println("You can inspect your deployment in the Dashboard: " + url)
5✔
51
        return nil
5✔
52
}
53

54
func GetFunctionSlugs(fsys afero.Fs) (slugs []string, err error) {
3✔
55
        pattern := filepath.Join(utils.FunctionsDir, "*", "index.ts")
3✔
56
        paths, err := afero.Glob(fsys, pattern)
3✔
57
        if err != nil {
3✔
58
                return nil, errors.Errorf("failed to glob function slugs: %w", err)
×
59
        }
×
60
        for _, path := range paths {
7✔
61
                slug := filepath.Base(filepath.Dir(path))
4✔
62
                if utils.FuncSlugPattern.MatchString(slug) {
7✔
63
                        slugs = append(slugs, slug)
3✔
64
                }
3✔
65
        }
66
        // Add all function slugs declared in config file
67
        for slug := range utils.Config.Functions {
5✔
68
                slugs = append(slugs, slug)
2✔
69
        }
2✔
70
        return slugs, nil
3✔
71
}
72

73
func GetFunctionConfig(slugs []string, importMapPath string, noVerifyJWT *bool, fsys afero.Fs) (config.FunctionConfig, error) {
10✔
74
        // Although some functions do not require import map, it's more convenient to setup
10✔
75
        // vscode deno extension with a single import map for all functions.
10✔
76
        fallbackExists := true
10✔
77
        functionsUsingDeprecatedGlobalFallback := []string{}
10✔
78
        functionsUsingDeprecatedImportMap := []string{}
10✔
79
        if _, err := fsys.Stat(utils.FallbackImportMapPath); errors.Is(err, os.ErrNotExist) {
16✔
80
                fallbackExists = false
6✔
81
        } else if err != nil {
10✔
82
                return nil, errors.Errorf("failed to fallback import map: %w", err)
×
83
        }
×
84
        // Flag import map is specified relative to current directory instead of workdir
85
        if len(importMapPath) > 0 && !filepath.IsAbs(importMapPath) {
11✔
86
                importMapPath = filepath.Join(utils.CurrentDirAbs, importMapPath)
1✔
87
        }
1✔
88
        functionConfig := make(config.FunctionConfig, len(slugs))
10✔
89
        for _, name := range slugs {
24✔
90
                function := utils.Config.Functions[name]
14✔
91
                // Precedence order: flag > config > fallback
14✔
92
                functionDir := filepath.Join(utils.FunctionsDir, name)
14✔
93
                if len(function.Entrypoint) == 0 {
22✔
94
                        function.Entrypoint = filepath.Join(functionDir, "index.ts")
8✔
95
                }
8✔
96
                if len(importMapPath) > 0 {
16✔
97
                        function.ImportMap = importMapPath
2✔
98
                } else if len(function.ImportMap) == 0 {
21✔
99
                        denoJsonPath := filepath.Join(functionDir, "deno.json")
7✔
100
                        denoJsoncPath := filepath.Join(functionDir, "deno.jsonc")
7✔
101
                        importMapPath := filepath.Join(functionDir, "import_map.json")
7✔
102
                        if _, err := fsys.Stat(denoJsonPath); err == nil {
7✔
103
                                function.ImportMap = denoJsonPath
×
104
                        } else if _, err := fsys.Stat(denoJsoncPath); err == nil {
7✔
105
                                function.ImportMap = denoJsoncPath
×
106
                        } else if _, err := fsys.Stat(importMapPath); err == nil {
7✔
107
                                function.ImportMap = importMapPath
×
108
                                functionsUsingDeprecatedImportMap = append(functionsUsingDeprecatedImportMap, name)
×
109
                        } else if fallbackExists {
8✔
110
                                function.ImportMap = utils.FallbackImportMapPath
1✔
111
                                functionsUsingDeprecatedGlobalFallback = append(functionsUsingDeprecatedGlobalFallback, name)
1✔
112
                        }
1✔
113
                }
114
                if noVerifyJWT != nil {
18✔
115
                        function.VerifyJWT = cast.Ptr(!*noVerifyJWT)
4✔
116
                }
4✔
117
                functionConfig[name] = function
14✔
118
        }
119
        if len(functionsUsingDeprecatedImportMap) > 0 {
10✔
120
                fmt.Fprintln(os.Stderr,
×
121
                        utils.Yellow("WARNING:"),
×
122
                        "Functions using deprecated import_map.json (please migrate to deno.json):",
×
123
                        utils.Aqua(strings.Join(functionsUsingDeprecatedImportMap, ", ")),
×
124
                )
×
125
        }
×
126
        if len(functionsUsingDeprecatedGlobalFallback) > 0 {
11✔
127
                fmt.Fprintln(os.Stderr,
1✔
128
                        utils.Yellow("WARNING:"),
1✔
129
                        "Functions using fallback import map:",
1✔
130
                        utils.Aqua(strings.Join(functionsUsingDeprecatedGlobalFallback, ", ")),
1✔
131
                )
1✔
132
                fmt.Fprintln(os.Stderr,
1✔
133
                        "Please use recommended per function dependency declaration ",
1✔
134
                        utils.Aqua("https://supabase.com/docs/guides/functions/import-maps"),
1✔
135
                )
1✔
136
        }
1✔
137
        return functionConfig, nil
10✔
138
}
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

© 2026 Coveralls, Inc