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

supabase / cli / 19627513060

24 Nov 2025 08:11AM UTC coverage: 55.395% (+0.3%) from 55.094%
19627513060

Pull #4394

github

web-flow
Merge 000136c5e into 6d9e31644
Pull Request #4394: feat(cli): add concurrent images pulling

115 of 145 new or added lines in 2 files covered. (79.31%)

7 existing lines in 2 files now uncovered.

6659 of 12021 relevant lines covered (55.39%)

6.26 hits per line

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

95.56
/internal/utils/config.go
1
package utils
2

3
import (
4
        _ "embed"
5
        "io/fs"
6
        "net"
7
        "net/url"
8
        "os"
9
        "strconv"
10

11
        "github.com/compose-spec/compose-go/v2/types"
12
        "github.com/go-errors/errors"
13
        "github.com/spf13/afero"
14
        "github.com/spf13/viper"
15
        "github.com/supabase/cli/pkg/config"
16
)
17

18
var (
19
        NetId         string
20
        DbId          string
21
        ConfigId      string
22
        KongId        string
23
        GotrueId      string
24
        InbucketId    string
25
        RealtimeId    string
26
        RestId        string
27
        StorageId     string
28
        ImgProxyId    string
29
        DifferId      string
30
        PgmetaId      string
31
        StudioId      string
32
        EdgeRuntimeId string
33
        LogflareId    string
34
        VectorId      string
35
        PoolerId      string
36

37
        DbAliases          = []string{"db", "db.supabase.internal"}
38
        KongAliases        = []string{"kong", "api.supabase.internal"}
39
        GotrueAliases      = []string{"auth"}
40
        InbucketAliases    = []string{"inbucket"}
41
        RealtimeAliases    = []string{"realtime", Config.Realtime.TenantId}
42
        RestAliases        = []string{"rest"}
43
        StorageAliases     = []string{"storage"}
44
        ImgProxyAliases    = []string{"imgproxy"}
45
        PgmetaAliases      = []string{"pg_meta"}
46
        StudioAliases      = []string{"studio"}
47
        EdgeRuntimeAliases = []string{"edge_runtime"}
48
        LogflareAliases    = []string{"analytics"}
49
        VectorAliases      = []string{"vector"}
50
        PoolerAliases      = []string{"pooler"}
51

52
        //go:embed templates/initial_schemas/13.sql
53
        InitialSchemaPg13Sql string
54
        //go:embed templates/initial_schemas/14.sql
55
        InitialSchemaPg14Sql string
56
)
57

58
func GetId(name string) string {
1,156✔
59
        return "supabase_" + name + "_" + Config.ProjectId
1,156✔
60
}
1,156✔
61

62
func UpdateDockerIds() {
68✔
63
        if NetId = viper.GetString("network-id"); len(NetId) == 0 {
135✔
64
                NetId = GetId("network")
67✔
65
        }
67✔
66
        DbId = GetId(DbAliases[0])
68✔
67
        ConfigId = GetId("config")
68✔
68
        KongId = GetId(KongAliases[0])
68✔
69
        GotrueId = GetId(GotrueAliases[0])
68✔
70
        InbucketId = GetId(InbucketAliases[0])
68✔
71
        RealtimeId = GetId(RealtimeAliases[0])
68✔
72
        RestId = GetId(RestAliases[0])
68✔
73
        StorageId = GetId(StorageAliases[0])
68✔
74
        ImgProxyId = GetId(ImgProxyAliases[0])
68✔
75
        DifferId = GetId("differ")
68✔
76
        PgmetaId = GetId(PgmetaAliases[0])
68✔
77
        StudioId = GetId(StudioAliases[0])
68✔
78
        EdgeRuntimeId = GetId(EdgeRuntimeAliases[0])
68✔
79
        LogflareId = GetId(LogflareAliases[0])
68✔
80
        VectorId = GetId(VectorAliases[0])
68✔
81
        PoolerId = GetId(PoolerAliases[0])
68✔
82
}
83

84
func GetDockerIds() []string {
8✔
85
        return []string{
8✔
86
                KongId,
8✔
87
                GotrueId,
8✔
88
                InbucketId,
8✔
89
                RealtimeId,
8✔
90
                RestId,
8✔
91
                StorageId,
8✔
92
                ImgProxyId,
8✔
93
                PgmetaId,
8✔
94
                StudioId,
8✔
95
                EdgeRuntimeId,
8✔
96
                LogflareId,
8✔
97
                VectorId,
8✔
98
                PoolerId,
8✔
99
        }
8✔
100
}
8✔
101

102
var Config = config.NewConfig(config.WithHostname(GetHostname()))
103

104
func GetServices() types.Services {
2✔
105
        services := types.Services{
2✔
106
                "db": {
2✔
107
                        Name:       ShortContainerImageName(Config.Db.Image),
2✔
108
                        Image:      GetRegistryImageUrl(Config.Db.Image),
2✔
109
                        PullPolicy: types.PullPolicyMissing,
2✔
110
                },
2✔
111
        }
2✔
112
        if Config.Api.Enabled {
4✔
113
                services["gateway"] = types.ServiceConfig{
2✔
114
                        Name:       ShortContainerImageName(Config.Api.KongImage),
2✔
115
                        Image:      GetRegistryImageUrl(Config.Api.KongImage),
2✔
116
                        PullPolicy: types.PullPolicyMissing,
2✔
117
                }
2✔
118
                services["api"] = types.ServiceConfig{
2✔
119
                        Name:       ShortContainerImageName(Config.Api.Image),
2✔
120
                        Image:      GetRegistryImageUrl(Config.Api.Image),
2✔
121
                        PullPolicy: types.PullPolicyMissing,
2✔
122
                }
2✔
123
        }
2✔
124
        if Config.Auth.Enabled {
4✔
125
                services["auth"] = types.ServiceConfig{
2✔
126
                        Name:       ShortContainerImageName(Config.Auth.Image),
2✔
127
                        Image:      GetRegistryImageUrl(Config.Auth.Image),
2✔
128
                        PullPolicy: types.PullPolicyMissing,
2✔
129
                }
2✔
130
        }
2✔
131
        if Config.Inbucket.Enabled {
4✔
132
                services["mailpit"] = types.ServiceConfig{
2✔
133
                        Name:       ShortContainerImageName(Config.Inbucket.Image),
2✔
134
                        Image:      GetRegistryImageUrl(Config.Inbucket.Image),
2✔
135
                        PullPolicy: types.PullPolicyMissing,
2✔
136
                }
2✔
137
        }
2✔
138
        if Config.Realtime.Enabled {
4✔
139
                services["realtime"] = types.ServiceConfig{
2✔
140
                        Name:       ShortContainerImageName(Config.Realtime.Image),
2✔
141
                        Image:      GetRegistryImageUrl(Config.Realtime.Image),
2✔
142
                        PullPolicy: types.PullPolicyMissing,
2✔
143
                }
2✔
144
        }
2✔
145
        if Config.Storage.Enabled {
4✔
146
                services["storage"] = types.ServiceConfig{
2✔
147
                        Name:       ShortContainerImageName(Config.Storage.Image),
2✔
148
                        Image:      GetRegistryImageUrl(Config.Storage.Image),
2✔
149
                        PullPolicy: types.PullPolicyMissing,
2✔
150
                }
2✔
151
                services["imgProxy"] = types.ServiceConfig{
2✔
152
                        Name:       ShortContainerImageName(Config.Storage.ImgProxyImage),
2✔
153
                        Image:      GetRegistryImageUrl(Config.Storage.ImgProxyImage),
2✔
154
                        PullPolicy: types.PullPolicyMissing,
2✔
155
                }
2✔
156
        }
2✔
157
        if Config.EdgeRuntime.Enabled {
4✔
158
                services["edgeRuntime"] = types.ServiceConfig{
2✔
159
                        Name:       ShortContainerImageName(Config.EdgeRuntime.Image),
2✔
160
                        Image:      GetRegistryImageUrl(Config.EdgeRuntime.Image),
2✔
161
                        PullPolicy: types.PullPolicyMissing,
2✔
162
                }
2✔
163
        }
2✔
164
        if Config.Studio.Enabled {
4✔
165
                services["studio"] = types.ServiceConfig{
2✔
166
                        Name:       ShortContainerImageName(Config.Studio.Image),
2✔
167
                        Image:      GetRegistryImageUrl(Config.Studio.Image),
2✔
168
                        PullPolicy: types.PullPolicyMissing,
2✔
169
                }
2✔
170
                services["pgmeta"] = types.ServiceConfig{
2✔
171
                        Name:       ShortContainerImageName(Config.Studio.PgmetaImage),
2✔
172
                        Image:      GetRegistryImageUrl(Config.Studio.PgmetaImage),
2✔
173
                        PullPolicy: types.PullPolicyMissing,
2✔
174
                }
2✔
175
        }
2✔
176
        if Config.Analytics.Enabled {
4✔
177
                services["analytics"] = types.ServiceConfig{
2✔
178
                        Name:       ShortContainerImageName(Config.Analytics.Image),
2✔
179
                        Image:      GetRegistryImageUrl(Config.Analytics.Image),
2✔
180
                        PullPolicy: types.PullPolicyMissing,
2✔
181
                }
2✔
182
                services["vector"] = types.ServiceConfig{
2✔
183
                        Name:       ShortContainerImageName(Config.Analytics.VectorImage),
2✔
184
                        Image:      GetRegistryImageUrl(Config.Analytics.VectorImage),
2✔
185
                        PullPolicy: types.PullPolicyMissing,
2✔
186
                }
2✔
187
        }
2✔
188
        if Config.Db.Pooler.Enabled {
2✔
NEW
189
                services["pooler"] = types.ServiceConfig{
×
NEW
190
                        Name:       ShortContainerImageName(Config.Db.Pooler.Image),
×
NEW
191
                        Image:      GetRegistryImageUrl(Config.Db.Pooler.Image),
×
NEW
192
                        PullPolicy: types.PullPolicyMissing,
×
NEW
193
                }
×
NEW
194
        }
×
195
        return services
2✔
196
}
197

198
// Adapts fs.FS to support absolute paths
199
type rootFS struct {
200
        fsys afero.Fs
201
}
202

203
func (f *rootFS) Open(name string) (fs.File, error) {
886✔
204
        return f.fsys.Open(name)
886✔
205
}
886✔
206

207
func NewRootFS(fsys afero.Fs) fs.FS {
86✔
208
        return &rootFS{fsys: fsys}
86✔
209
}
86✔
210

211
func ToRealtimeEnv(addr config.AddressFamily) string {
9✔
212
        if addr == config.AddressIPv6 {
9✔
213
                return "-proto_dist inet6_tcp"
×
214
        }
×
215
        return "-proto_dist inet_tcp"
9✔
216
}
217

218
type InitParams struct {
219
        ProjectId   string
220
        UseOrioleDB bool
221
        Overwrite   bool
222
}
223

224
func InitConfig(params InitParams, fsys afero.Fs) error {
51✔
225
        c := config.NewConfig()
51✔
226
        c.ProjectId = params.ProjectId
51✔
227
        if params.UseOrioleDB {
52✔
228
                c.Experimental.OrioleDBVersion = "15.1.0.150"
1✔
229
        }
1✔
230
        // Create config file
231
        if err := MkdirIfNotExistFS(fsys, SupabaseDirPath); err != nil {
52✔
232
                return err
1✔
233
        }
1✔
234
        flag := os.O_WRONLY | os.O_CREATE
50✔
235
        if params.Overwrite {
51✔
236
                flag |= os.O_TRUNC
1✔
237
        } else {
50✔
238
                flag |= os.O_EXCL
49✔
239
        }
49✔
240
        f, err := fsys.OpenFile(ConfigPath, flag, 0644)
50✔
241
        if err != nil {
53✔
242
                return errors.Errorf("failed to create config file: %w", err)
3✔
243
        }
3✔
244
        defer f.Close()
47✔
245
        return c.Eject(f)
47✔
246
}
247

248
func WriteConfig(fsys afero.Fs, _test bool) error {
35✔
249
        return InitConfig(InitParams{}, fsys)
35✔
250
}
35✔
251

252
func GetApiUrl(path string) string {
3✔
253
        if len(Config.Api.ExternalUrl) > 0 {
5✔
254
                return Config.Api.ExternalUrl + path
2✔
255
        }
2✔
256
        hostPort := net.JoinHostPort(Config.Hostname,
1✔
257
                strconv.FormatUint(uint64(Config.Api.Port), 10),
1✔
258
        )
1✔
259
        apiUrl := url.URL{
1✔
260
                Scheme: "http",
1✔
261
                Host:   hostPort,
1✔
262
                Path:   path,
1✔
263
        }
1✔
264
        return apiUrl.String()
1✔
265
}
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