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

supabase / cli / 5072142569

24 May 2023 06:27PM UTC coverage: 62.969% (+0.01%) from 62.956%
5072142569

Pull #1145

github

Qiao Han
chore: do not map remote db password
Pull Request #1145: fix: use db password everywhere

30 of 30 new or added lines in 8 files covered. (100.0%)

4513 of 7167 relevant lines covered (62.97%)

1006.67 hits per line

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

90.3
/internal/db/diff/migra.go
1
package diff
2

3
import (
4
        "bytes"
5
        "context"
6
        _ "embed"
7
        "errors"
8
        "fmt"
9
        "io"
10
        "os"
11
        "strconv"
12
        "strings"
13
        "time"
14

15
        "github.com/docker/docker/api/types/container"
16
        "github.com/docker/go-connections/nat"
17
        "github.com/jackc/pgconn"
18
        "github.com/jackc/pgx/v4"
19
        "github.com/spf13/afero"
20
        "github.com/supabase/cli/internal/db/reset"
21
        "github.com/supabase/cli/internal/db/start"
22
        "github.com/supabase/cli/internal/gen/keys"
23
        "github.com/supabase/cli/internal/migration/apply"
24
        "github.com/supabase/cli/internal/utils"
25
)
26

27
var (
28
        //go:embed templates/migra.sh
29
        diffSchemaScript string
30
)
31

32
func RunMigra(ctx context.Context, schema []string, file string, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) (err error) {
5✔
33
        // Sanity checks.
5✔
34
        if err := utils.LoadConfigFS(fsys); err != nil {
6✔
35
                return err
1✔
36
        }
1✔
37
        if len(config.Password) > 0 {
7✔
38
                fmt.Fprintln(os.Stderr, "Connecting to remote database...")
3✔
39
        } else {
4✔
40
                fmt.Fprintln(os.Stderr, "Connecting to local database...")
1✔
41
                if err := utils.AssertSupabaseDbIsRunning(); err != nil {
2✔
42
                        return err
1✔
43
                }
1✔
44
                config.Host = "localhost"
×
45
                config.Port = uint16(utils.Config.Db.Port)
×
46
                config.User = "postgres"
×
47
                config.Password = "postgres"
×
48
                config.Database = "postgres"
×
49
        }
50
        // 1. Load all user defined schemas
51
        if len(schema) == 0 {
4✔
52
                schema, err = loadSchema(ctx, config, options...)
1✔
53
                if err != nil {
2✔
54
                        return err
1✔
55
                }
1✔
56
        }
57
        // 3. Run migra to diff schema
58
        out, err := DiffDatabase(ctx, schema, config, os.Stderr, fsys, options...)
2✔
59
        if err != nil {
3✔
60
                return err
1✔
61
        }
1✔
62
        branch := keys.GetGitBranch(fsys)
1✔
63
        fmt.Fprintln(os.Stderr, "Finished "+utils.Aqua("supabase db diff")+" on branch "+utils.Aqua(branch)+".\n")
1✔
64
        return SaveDiff(out, file, fsys)
1✔
65
}
66

67
func loadSchema(ctx context.Context, config pgconn.Config, options ...func(*pgx.ConnConfig)) (schema []string, err error) {
1✔
68
        var conn *pgx.Conn
1✔
69
        if config.Host == "localhost" && config.Port == uint16(utils.Config.Db.Port) {
1✔
70
                conn, err = utils.ConnectLocalPostgres(ctx, config, options...)
×
71
        } else {
1✔
72
                conn, err = utils.ConnectRemotePostgres(ctx, config, options...)
1✔
73
        }
1✔
74
        if err != nil {
1✔
75
                return schema, err
×
76
        }
×
77
        defer conn.Close(context.Background())
1✔
78
        return LoadUserSchemas(ctx, conn)
1✔
79
}
80

81
func LoadUserSchemas(ctx context.Context, conn *pgx.Conn, exclude ...string) ([]string, error) {
2✔
82
        // Include auth,storage,extensions by default for RLS policies
2✔
83
        if len(exclude) == 0 {
3✔
84
                exclude = append([]string{
1✔
85
                        "_analytics",
1✔
86
                        "pgbouncer",
1✔
87
                        "realtime",
1✔
88
                        "_realtime",
1✔
89
                        // Exclude functions because Webhooks support is early alpha
1✔
90
                        "supabase_functions",
1✔
91
                        "supabase_migrations",
1✔
92
                }, utils.SystemSchemas...)
1✔
93
        }
1✔
94
        return reset.ListSchemas(ctx, conn, exclude...)
2✔
95
}
96

97
func CreateShadowDatabase(ctx context.Context) (string, error) {
5✔
98
        config := start.NewContainerConfig()
5✔
99
        config.Entrypoint = nil
5✔
100
        hostPort := strconv.FormatUint(uint64(utils.Config.Db.ShadowPort), 10)
5✔
101
        hostConfig := container.HostConfig{
5✔
102
                PortBindings: nat.PortMap{"5432/tcp": []nat.PortBinding{{HostPort: hostPort}}},
5✔
103
                Tmpfs:        map[string]string{"/docker-entrypoint-initdb.d": ""},
5✔
104
                AutoRemove:   true,
5✔
105
        }
5✔
106
        return utils.DockerStart(ctx, config, hostConfig, "")
5✔
107
}
5✔
108

109
func connectShadowDatabase(ctx context.Context, timeout time.Duration, options ...func(*pgx.ConnConfig)) (conn *pgx.Conn, err error) {
6✔
110
        now := time.Now()
6✔
111
        expiry := now.Add(timeout)
6✔
112
        ticker := time.NewTicker(time.Second)
6✔
113
        defer ticker.Stop()
6✔
114
        // Retry until connected, cancelled, or timeout
6✔
115
        for t := now; t.Before(expiry); t = <-ticker.C {
12✔
116
                conn, err = utils.ConnectLocalPostgres(ctx, pgconn.Config{Port: uint16(utils.Config.Db.ShadowPort)}, options...)
6✔
117
                if err == nil || errors.Is(ctx.Err(), context.Canceled) {
12✔
118
                        break
6✔
119
                }
120
        }
121
        return conn, err
6✔
122
}
123

124
func MigrateShadowDatabase(ctx context.Context, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
6✔
125
        conn, err := connectShadowDatabase(ctx, 10*time.Second, options...)
6✔
126
        if err != nil {
7✔
127
                return err
1✔
128
        }
1✔
129
        defer conn.Close(context.Background())
5✔
130
        if err := apply.BatchExecDDL(ctx, conn, strings.NewReader(utils.GlobalsSql)); err != nil {
7✔
131
                return err
2✔
132
        }
2✔
133
        if roles, err := fsys.Open(utils.CustomRolesPath); err == nil {
3✔
134
                if err := apply.BatchExecDDL(ctx, conn, roles); err != nil {
×
135
                        return err
×
136
                }
×
137
        } else if !errors.Is(err, os.ErrNotExist) {
3✔
138
                return err
×
139
        }
×
140
        if err := apply.BatchExecDDL(ctx, conn, strings.NewReader(utils.InitialSchemaSql)); err != nil {
4✔
141
                return err
1✔
142
        }
1✔
143
        return apply.MigrateDatabase(ctx, conn, fsys)
2✔
144
}
145

146
// Diffs local database schema against shadow, dumps output to stdout.
147
func DiffSchemaMigra(ctx context.Context, source, target string, schema []string) (string, error) {
2✔
148
        env := []string{"SOURCE=" + source, "TARGET=" + target}
2✔
149
        // Passing in script string means command line args must be set manually, ie. "$@"
2✔
150
        args := "set -- " + strings.Join(schema, " ") + ";"
2✔
151
        cmd := []string{"/bin/sh", "-c", args + diffSchemaScript}
2✔
152
        var out, stderr bytes.Buffer
2✔
153
        if err := utils.DockerRunOnceWithConfig(
2✔
154
                ctx,
2✔
155
                container.Config{
2✔
156
                        Image: utils.MigraImage,
2✔
157
                        Env:   env,
2✔
158
                        Cmd:   cmd,
2✔
159
                },
2✔
160
                container.HostConfig{
2✔
161
                        NetworkMode: container.NetworkMode("host"),
2✔
162
                },
2✔
163
                "",
2✔
164
                &out,
2✔
165
                &stderr,
2✔
166
        ); err != nil {
3✔
167
                return "", fmt.Errorf("error diffing schema: %w:\n%s", err, stderr.String())
1✔
168
        }
1✔
169
        return out.String(), nil
1✔
170
}
171

172
func DiffDatabase(ctx context.Context, schema []string, config pgconn.Config, w io.Writer, fsys afero.Fs, options ...func(*pgx.ConnConfig)) (string, error) {
5✔
173
        fmt.Fprintln(w, "Creating shadow database...")
5✔
174
        shadow, err := CreateShadowDatabase(ctx)
5✔
175
        if err != nil {
7✔
176
                return "", err
2✔
177
        }
2✔
178
        defer utils.DockerRemove(shadow)
3✔
179
        if err := MigrateShadowDatabase(ctx, fsys, options...); err != nil {
4✔
180
                return "", err
1✔
181
        }
1✔
182
        fmt.Fprintln(w, "Diffing schemas:", strings.Join(schema, ","))
2✔
183
        source := fmt.Sprintf("postgresql://postgres:postgres@localhost:%d/postgres", utils.Config.Db.ShadowPort)
2✔
184
        target := utils.ToPostgresURL(config)
2✔
185
        return DiffSchemaMigra(ctx, source, target, schema)
2✔
186
}
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