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

supabase / cli / 14408499083

11 Apr 2025 05:15PM UTC coverage: 50.957%. First build
14408499083

Pull #3417

github

web-flow
Merge 758530526 into 96a407fc8
Pull Request #3417: fix: outside import with relative module graph

42 of 64 new or added lines in 5 files covered. (65.63%)

6974 of 13686 relevant lines covered (50.96%)

184.5 hits per line

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

86.92
/internal/functions/deploy/bundle.go
1
package deploy
2

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

11
        "github.com/docker/docker/api/types/container"
12
        "github.com/docker/docker/api/types/network"
13
        "github.com/go-errors/errors"
14
        "github.com/spf13/afero"
15
        "github.com/spf13/viper"
16
        "github.com/supabase/cli/internal/utils"
17
        "github.com/supabase/cli/pkg/api"
18
        "github.com/supabase/cli/pkg/function"
19
)
20

21
type dockerBundler struct {
22
        fsys afero.Fs
23
}
24

25
func NewDockerBundler(fsys afero.Fs) function.EszipBundler {
7✔
26
        return &dockerBundler{fsys: fsys}
7✔
27
}
7✔
28

29
func (b *dockerBundler) Bundle(ctx context.Context, slug, entrypoint, importMap string, staticFiles []string, output io.Writer) (api.FunctionDeployMetadata, error) {
8✔
30
        meta := function.NewMetadata(slug, entrypoint, importMap, staticFiles)
8✔
31
        fmt.Fprintln(os.Stderr, "Bundling Function:", utils.Bold(slug))
8✔
32
        cwd, err := os.Getwd()
8✔
33
        if err != nil {
8✔
34
                return meta, errors.Errorf("failed to get working directory: %w", err)
×
35
        }
×
36
        // BitBucket pipelines require docker bind mounts to be world writable
37
        hostOutputDir := filepath.Join(utils.TempDir, fmt.Sprintf(".output_%s", slug))
8✔
38
        if err := b.fsys.MkdirAll(hostOutputDir, 0777); err != nil {
9✔
39
                return meta, errors.Errorf("failed to mkdir: %w", err)
1✔
40
        }
1✔
41
        defer func() {
14✔
42
                if err := b.fsys.RemoveAll(hostOutputDir); err != nil {
7✔
43
                        fmt.Fprintln(os.Stderr, err)
×
44
                }
×
45
        }()
46
        // Create bind mounts
47
        binds, err := GetBindMounts(cwd, utils.FunctionsDir, hostOutputDir, entrypoint, importMap, b.fsys)
7✔
48
        if err != nil {
7✔
49
                return meta, err
×
50
        }
×
51
        hostOutputPath := filepath.Join(hostOutputDir, "output.eszip")
7✔
52
        // Create exec command
7✔
53
        cmd := []string{"bundle", "--entrypoint", utils.ToDockerPath(entrypoint), "--output", utils.ToDockerPath(hostOutputPath)}
7✔
54
        if len(importMap) > 0 {
9✔
55
                cmd = append(cmd, "--import-map", utils.ToDockerPath(importMap))
2✔
56
        }
2✔
57
        for _, sf := range staticFiles {
8✔
58
                cmd = append(cmd, "--static", utils.ToDockerPath(sf))
1✔
59
        }
1✔
60
        if viper.GetBool("DEBUG") {
7✔
61
                cmd = append(cmd, "--verbose")
×
62
        }
×
63

64
        env := []string{}
7✔
65
        if custom_registry := os.Getenv("NPM_CONFIG_REGISTRY"); custom_registry != "" {
7✔
66
                env = append(env, "NPM_CONFIG_REGISTRY="+custom_registry)
×
67
        }
×
68
        // Run bundle
69
        if err := utils.DockerRunOnceWithConfig(
7✔
70
                ctx,
7✔
71
                container.Config{
7✔
72
                        Image:      utils.Config.EdgeRuntime.Image,
7✔
73
                        Env:        env,
7✔
74
                        Cmd:        cmd,
7✔
75
                        WorkingDir: utils.ToDockerPath(cwd),
7✔
76
                },
7✔
77
                container.HostConfig{
7✔
78
                        Binds: binds,
7✔
79
                },
7✔
80
                network.NetworkingConfig{},
7✔
81
                "",
7✔
82
                os.Stdout,
7✔
83
                os.Stderr,
7✔
84
        ); err != nil {
8✔
85
                return meta, err
1✔
86
        }
1✔
87
        // Read and compress
88
        eszipBytes, err := b.fsys.Open(hostOutputPath)
6✔
89
        if err != nil {
6✔
90
                return meta, errors.Errorf("failed to open eszip: %w", err)
×
91
        }
×
92
        defer eszipBytes.Close()
6✔
93
        return meta, function.Compress(eszipBytes, output)
6✔
94
}
95

96
func GetBindMounts(cwd, hostFuncDir, hostOutputDir, hostEntrypointPath, hostImportMapPath string, fsys afero.Fs) ([]string, error) {
7✔
97
        sep := string(filepath.Separator)
7✔
98
        // Docker requires all host paths to be absolute
7✔
99
        if !filepath.IsAbs(hostFuncDir) {
14✔
100
                hostFuncDir = filepath.Join(cwd, hostFuncDir)
7✔
101
        }
7✔
102
        if !strings.HasSuffix(hostFuncDir, sep) {
14✔
103
                hostFuncDir += sep
7✔
104
        }
7✔
105
        dockerFuncDir := utils.ToDockerPath(hostFuncDir)
7✔
106
        // TODO: bind ./supabase/functions:/home/deno/functions to hide PII?
7✔
107
        binds := []string{
7✔
108
                // Reuse deno cache directory, ie. DENO_DIR, between container restarts
7✔
109
                // https://denolib.gitbook.io/guide/advanced/deno_dir-code-fetch-and-cache
7✔
110
                utils.EdgeRuntimeId + ":/root/.cache/deno:rw",
7✔
111
                hostFuncDir + ":" + dockerFuncDir + ":ro",
7✔
112
        }
7✔
113
        if len(hostOutputDir) > 0 {
14✔
114
                if !filepath.IsAbs(hostOutputDir) {
14✔
115
                        hostOutputDir = filepath.Join(cwd, hostOutputDir)
7✔
116
                }
7✔
117
                if !strings.HasSuffix(hostOutputDir, sep) {
14✔
118
                        hostOutputDir += sep
7✔
119
                }
7✔
120
                if !strings.HasPrefix(hostOutputDir, hostFuncDir) {
14✔
121
                        dockerOutputDir := utils.ToDockerPath(hostOutputDir)
7✔
122
                        binds = append(binds, hostOutputDir+":"+dockerOutputDir+":rw")
7✔
123
                }
7✔
124
        }
125
        // Imports outside of ./supabase/functions will be bound by walking the entrypoint
126
        modules, err := utils.BindHostModules(cwd, hostEntrypointPath, hostImportMapPath, fsys)
7✔
127
        if err != nil {
7✔
NEW
128
                return nil, err
×
129
        }
×
130
        if len(hostImportMapPath) > 0 {
9✔
131
                if !filepath.IsAbs(hostImportMapPath) {
4✔
132
                        hostImportMapPath = filepath.Join(cwd, hostImportMapPath)
2✔
133
                }
2✔
134
                dockerImportMapPath := utils.ToDockerPath(hostImportMapPath)
2✔
135
                modules = append(modules, hostImportMapPath+":"+dockerImportMapPath+":ro")
2✔
136
        }
137
        // Remove any duplicate mount points
138
        for _, mod := range modules {
9✔
139
                hostPath := strings.Split(mod, ":")[0]
2✔
140
                if !strings.HasPrefix(hostPath, hostFuncDir) &&
2✔
141
                        (len(hostOutputDir) == 0 || !strings.HasPrefix(hostPath, hostOutputDir)) {
4✔
142
                        binds = append(binds, mod)
2✔
143
                }
2✔
144
        }
145
        return binds, nil
7✔
146
}
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