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

supabase / cli / 4061558793

01 Feb 2023 06:23AM UTC coverage: 61.977% (-0.03%) from 62.009%
4061558793

Pull #832

github

Lakshan Perera
fix: set container name when calling DockerRunOnceWithStream
Pull Request #832: fix: set container name when calling DockerRunOnceWithStream

6 of 6 new or added lines in 3 files covered. (100.0%)

3617 of 5836 relevant lines covered (61.98%)

1260.31 hits per line

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

30.58
/internal/functions/serve/serve.go
1
package serve
2

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

12
        "github.com/docker/docker/api/types"
13
        "github.com/docker/docker/api/types/container"
14
        "github.com/docker/docker/pkg/stdcopy"
15
        "github.com/joho/godotenv"
16
        "github.com/spf13/afero"
17
        "github.com/supabase/cli/internal/utils"
18
)
19

20
const (
21
        relayFuncDir              = "/home/deno/functions"
22
        customDockerImportMapPath = "/home/deno/import_map.json"
23
)
24

25
func ParseEnvFile(envFilePath string) ([]string, error) {
1✔
26
        env := []string{}
1✔
27
        if len(envFilePath) == 0 {
2✔
28
                return env, nil
1✔
29
        }
1✔
30
        envMap, err := godotenv.Read(envFilePath)
×
31
        if err != nil {
×
32
                return env, err
×
33
        }
×
34
        for name, value := range envMap {
×
35
                if strings.HasPrefix(name, "SUPABASE_") {
×
36
                        return env, errors.New("Invalid env name: " + name + ". Env names cannot start with SUPABASE_.")
×
37
                }
×
38
                env = append(env, name+"="+value)
×
39
        }
40
        return env, nil
×
41
}
42

43
func Run(ctx context.Context, slug string, envFilePath string, noVerifyJWT *bool, importMapPath string, serveAll bool, fsys afero.Fs) error {
1✔
44
        if serveAll {
1✔
45
                return runServeAll(ctx, envFilePath, noVerifyJWT, importMapPath, fsys)
×
46
        }
×
47

48
        // 1. Sanity checks.
49
        {
1✔
50
                if err := utils.LoadConfigFS(fsys); err != nil {
1✔
51
                        return err
×
52
                }
×
53
                if err := utils.AssertSupabaseDbIsRunning(); err != nil {
1✔
54
                        return err
×
55
                }
×
56
                if err := utils.ValidateFunctionSlug(slug); err != nil {
1✔
57
                        return err
×
58
                }
×
59
                if envFilePath != "" {
1✔
60
                        if _, err := fsys.Stat(envFilePath); err != nil {
×
61
                                return fmt.Errorf("Failed to read env file: %w", err)
×
62
                        }
×
63
                }
64
                if importMapPath != "" {
1✔
65
                        // skip
×
66
                } else if functionConfig, ok := utils.Config.Functions[slug]; ok && functionConfig.ImportMap != "" {
1✔
67
                        if filepath.IsAbs(functionConfig.ImportMap) {
×
68
                                importMapPath = functionConfig.ImportMap
×
69
                        } else {
×
70
                                importMapPath = filepath.Join(utils.SupabaseDirPath, functionConfig.ImportMap)
×
71
                        }
×
72
                } else if f, err := fsys.Stat(utils.FallbackImportMapPath); err == nil && !f.IsDir() {
1✔
73
                        importMapPath = utils.FallbackImportMapPath
×
74
                }
×
75
                if importMapPath != "" {
1✔
76
                        if _, err := fsys.Stat(importMapPath); err != nil {
×
77
                                return fmt.Errorf("Failed to read import map: %w", err)
×
78
                        }
×
79
                }
80
        }
81

82
        // 2. Parse user defined env
83
        userEnv, err := ParseEnvFile(envFilePath)
1✔
84
        if err != nil {
1✔
85
                return err
×
86
        }
×
87

88
        // 3. Start relay.
89
        {
1✔
90
                _ = utils.Docker.ContainerRemove(ctx, utils.DenoRelayId, types.ContainerRemoveOptions{
1✔
91
                        RemoveVolumes: true,
1✔
92
                        Force:         true,
1✔
93
                })
1✔
94

1✔
95
                env := []string{
1✔
96
                        "JWT_SECRET=" + utils.JWTSecret,
1✔
97
                        "DENO_ORIGIN=http://localhost:8000",
1✔
98
                }
1✔
99
                verifyJWTEnv := "VERIFY_JWT=true"
1✔
100
                if noVerifyJWT == nil {
2✔
101
                        if functionConfig, ok := utils.Config.Functions[slug]; ok && !*functionConfig.VerifyJWT {
1✔
102
                                verifyJWTEnv = "VERIFY_JWT=false"
×
103
                        }
×
104
                } else if *noVerifyJWT {
×
105
                        verifyJWTEnv = "VERIFY_JWT=false"
×
106
                }
×
107
                env = append(env, verifyJWTEnv)
1✔
108

1✔
109
                cwd, err := os.Getwd()
1✔
110
                if err != nil {
1✔
111
                        return err
×
112
                }
×
113

114
                binds := []string{filepath.Join(cwd, utils.FunctionsDir) + ":" + relayFuncDir + ":ro,z"}
1✔
115
                // If a import map path is explcitly provided, mount it as a separate file
1✔
116
                if importMapPath != "" {
1✔
117
                        binds = append(binds, filepath.Join(cwd, importMapPath)+":"+customDockerImportMapPath+":ro,z")
×
118
                }
×
119
                if _, err := utils.DockerStart(
1✔
120
                        ctx,
1✔
121
                        container.Config{
1✔
122
                                Image: utils.DenoRelayImage,
1✔
123
                                Env:   append(env, userEnv...),
1✔
124
                        },
1✔
125
                        container.HostConfig{
1✔
126
                                Binds: binds,
1✔
127
                                // Allows containerized functions on Linux to reach host OS
1✔
128
                                ExtraHosts: []string{"host.docker.internal:host-gateway"},
1✔
129
                        },
1✔
130
                        utils.DenoRelayId,
1✔
131
                ); err != nil {
1✔
132
                        return err
×
133
                }
×
134

135
                go func() {
2✔
136
                        <-ctx.Done()
1✔
137
                        if ctx.Err() != nil {
1✔
138
                                utils.DockerRemove(utils.DenoRelayId)
×
139
                        }
×
140
                }()
141
        }
142

143
        // 4. Start Function.
144
        localFuncDir := filepath.Join(utils.FunctionsDir, slug)
1✔
145
        localImportMapPath := filepath.Join(localFuncDir, "import_map.json")
1✔
146

1✔
147
        // We assume the image is always Linux, so path separator must always be `/`.
1✔
148
        // We can't use filepath.Join because it uses the path separator for the host system, which is `\` for Windows.
1✔
149
        dockerFuncPath := relayFuncDir + "/" + slug + "/index.ts"
1✔
150
        dockerImportMapPath := relayFuncDir + "/" + slug + "/import_map.json"
1✔
151

1✔
152
        if importMapPath != "" {
1✔
153
                localImportMapPath = importMapPath
×
154
                dockerImportMapPath = customDockerImportMapPath
×
155
        }
×
156

157
        denoCacheCmd := []string{"deno", "cache"}
1✔
158
        {
2✔
159
                if _, err := fsys.Stat(localImportMapPath); err == nil {
1✔
160
                        denoCacheCmd = append(denoCacheCmd, "--import-map="+dockerImportMapPath)
×
161
                } else if errors.Is(err, os.ErrNotExist) {
2✔
162
                        // skip
1✔
163
                } else {
1✔
164
                        return fmt.Errorf("failed to check import_map.json for function %s: %w", slug, err)
×
165
                }
×
166
                denoCacheCmd = append(denoCacheCmd, dockerFuncPath)
1✔
167
        }
168

169
        fmt.Println("Starting " + utils.Bold(localFuncDir))
1✔
170
        if _, err := utils.DockerExecOnce(ctx, utils.DenoRelayId, userEnv, denoCacheCmd); err != nil {
2✔
171
                return err
1✔
172
        }
1✔
173

174
        {
×
175
                fmt.Println("Serving " + utils.Bold(localFuncDir))
×
176

×
177
                env := []string{
×
178
                        "SUPABASE_URL=http://" + utils.KongId + ":8000",
×
179
                        "SUPABASE_ANON_KEY=" + utils.AnonKey,
×
180
                        "SUPABASE_SERVICE_ROLE_KEY=" + utils.ServiceRoleKey,
×
181
                        "SUPABASE_DB_URL=postgresql://postgres:postgres@localhost:" + strconv.FormatUint(uint64(utils.Config.Db.Port), 10) + "/postgres",
×
182
                }
×
183

×
184
                denoRunCmd := []string{"deno", "run", "--no-check=remote", "--allow-all", "--watch", "--no-clear-screen", "--no-npm"}
×
185
                {
×
186
                        if _, err := fsys.Stat(localImportMapPath); err == nil {
×
187
                                denoRunCmd = append(denoRunCmd, "--import-map="+dockerImportMapPath)
×
188
                        } else if errors.Is(err, os.ErrNotExist) {
×
189
                                // skip
×
190
                        } else {
×
191
                                return fmt.Errorf("failed to check index.ts for function %s: %w", slug, err)
×
192
                        }
×
193
                        denoRunCmd = append(denoRunCmd, dockerFuncPath)
×
194
                }
195

196
                exec, err := utils.Docker.ContainerExecCreate(
×
197
                        ctx,
×
198
                        utils.DenoRelayId,
×
199
                        types.ExecConfig{
×
200
                                Env:          append(env, userEnv...),
×
201
                                Cmd:          denoRunCmd,
×
202
                                AttachStderr: true,
×
203
                                AttachStdout: true,
×
204
                        },
×
205
                )
×
206
                if err != nil {
×
207
                        return err
×
208
                }
×
209

210
                resp, err := utils.Docker.ContainerExecAttach(ctx, exec.ID, types.ExecStartCheck{})
×
211
                if err != nil {
×
212
                        return err
×
213
                }
×
214

215
                if _, err := stdcopy.StdCopy(os.Stdout, os.Stderr, resp.Reader); err != nil {
×
216
                        return err
×
217
                }
×
218
        }
219

220
        fmt.Println("Stopped serving " + utils.Bold(localFuncDir))
×
221
        return nil
×
222
}
223

224
func runServeAll(ctx context.Context, envFilePath string, noVerifyJWT *bool, importMapPath string, fsys afero.Fs) error {
×
225
        // 1. Sanity checks.
×
226
        {
×
227
                if err := utils.LoadConfigFS(fsys); err != nil {
×
228
                        return err
×
229
                }
×
230
                if err := utils.AssertSupabaseDbIsRunning(); err != nil {
×
231
                        return err
×
232
                }
×
233
                if envFilePath != "" {
×
234
                        if _, err := fsys.Stat(envFilePath); err != nil {
×
235
                                return fmt.Errorf("Failed to read env file: %w", err)
×
236
                        }
×
237
                }
238
                if importMapPath != "" {
×
239
                        // skip
×
240
                } else if f, err := fsys.Stat(utils.FallbackImportMapPath); err == nil && !f.IsDir() {
×
241
                        importMapPath = utils.FallbackImportMapPath
×
242
                }
×
243
                if importMapPath != "" {
×
244
                        if _, err := fsys.Stat(importMapPath); err != nil {
×
245
                                return fmt.Errorf("Failed to read import map: %w", err)
×
246
                        }
×
247
                }
248
        }
249

250
        // 2. Parse user defined env
251
        userEnv, err := ParseEnvFile(envFilePath)
×
252
        if err != nil {
×
253
                return err
×
254
        }
×
255

256
        // 3. Start container
257
        {
×
258
                _ = utils.Docker.ContainerRemove(ctx, utils.DenoRelayId, types.ContainerRemoveOptions{
×
259
                        RemoveVolumes: true,
×
260
                        Force:         true,
×
261
                })
×
262

×
263
                env := []string{
×
264
                        "JWT_SECRET=" + utils.JWTSecret,
×
265
                        "SUPABASE_URL=http://" + utils.KongId + ":8000",
×
266
                        "SUPABASE_ANON_KEY=" + utils.AnonKey,
×
267
                        "SUPABASE_SERVICE_ROLE_KEY=" + utils.ServiceRoleKey,
×
268
                        "SUPABASE_DB_URL=postgresql://postgres:postgres@localhost:" + strconv.FormatUint(uint64(utils.Config.Db.Port), 10) + "/postgres",
×
269
                }
×
270
                verifyJWTEnv := "VERIFY_JWT=true"
×
271
                if noVerifyJWT != nil {
×
272
                        verifyJWTEnv = "VERIFY_JWT=false"
×
273
                }
×
274
                env = append(env, verifyJWTEnv)
×
275

×
276
                cwd, err := os.Getwd()
×
277
                if err != nil {
×
278
                        return err
×
279
                }
×
280

281
                binds := []string{
×
282
                        filepath.Join(cwd, utils.FunctionsDir) + ":" + relayFuncDir + ":ro,z",
×
283
                        utils.DenoRelayId + ":/root/.cache/deno:rw,z",
×
284
                }
×
285
                // If a import map path is explcitly provided, mount it as a separate file
×
286
                if importMapPath != "" {
×
287
                        binds = append(binds, filepath.Join(cwd, importMapPath)+":"+customDockerImportMapPath+":ro,z")
×
288
                }
×
289

290
                fmt.Println("Serving " + utils.Bold(utils.FunctionsDir))
×
291

×
292
                if err := utils.DockerRunOnceWithStream(
×
293
                        ctx,
×
294
                        utils.EdgeRuntimeImage,
×
295
                        append(env, userEnv...),
×
296
                        []string{"start", "--dir", relayFuncDir, "-p", "8081"},
×
297
                        binds,
×
298
                        utils.DenoRelayId,
×
299
                        os.Stdout,
×
300
                        os.Stderr,
×
301
                ); err != nil {
×
302
                        return err
×
303
                }
×
304
        }
305

306
        fmt.Println("Stopped serving " + utils.Bold(utils.FunctionsDir))
×
307
        return nil
×
308

309
}
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