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

supabase / cli / 12941917448

24 Jan 2025 02:14AM UTC coverage: 58.238% (-0.05%) from 58.292%
12941917448

Pull #3046

github

web-flow
Merge 322044b46 into 337aacd0d
Pull Request #3046: feat(cli): add repeatable migrations

25 of 48 new or added lines in 4 files covered. (52.08%)

6 existing lines in 2 files now uncovered.

7617 of 13079 relevant lines covered (58.24%)

202.0 hits per line

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

71.88
/internal/migration/list/list.go
1
package list
2

3
import (
4
        "context"
5
        "fmt"
6
        "math"
7
        "strconv"
8
        "strings"
9

10
        "github.com/charmbracelet/glamour"
11
        "github.com/go-errors/errors"
12
        "github.com/jackc/pgconn"
13
        "github.com/jackc/pgx/v4"
14
        "github.com/spf13/afero"
15
        "github.com/supabase/cli/internal/utils"
16
        "github.com/supabase/cli/pkg/migration"
17
)
18

19
func Run(ctx context.Context, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
3✔
20
        remoteVersions, err := loadRemoteVersions(ctx, config, options...)
3✔
21
        if err != nil {
4✔
22
                return err
1✔
23
        }
1✔
24
        localVersions, err := LoadLocalVersions(fsys)
2✔
25
        if err != nil {
3✔
26
                return err
1✔
27
        }
1✔
28
        table := makeTable(remoteVersions, localVersions)
1✔
29
        return RenderTable(table)
1✔
30
}
31

32
func loadRemoteVersions(ctx context.Context, config pgconn.Config, options ...func(*pgx.ConnConfig)) ([]string, error) {
7✔
33
        conn, err := utils.ConnectByConfig(ctx, config, options...)
7✔
34
        if err != nil {
9✔
35
                return nil, err
2✔
36
        }
2✔
37
        defer conn.Close(context.Background())
5✔
38
        return migration.ListRemoteMigrations(ctx, conn)
5✔
39
}
40

41
func makeTable(remoteMigrations, localMigrations []string) string {
4✔
42
        var err error
4✔
43
        table := "|Local|Remote|Time (UTC)|\n|-|-|-|\n"
4✔
44
        for i, j := 0, 0; i < len(remoteMigrations) || j < len(localMigrations); {
14✔
45
                remoteTimestamp := math.MaxInt
10✔
46
                if i < len(remoteMigrations) {
18✔
47
                        if remoteTimestamp, err = strconv.Atoi(remoteMigrations[i]); err != nil {
10✔
48
                                i++
2✔
49
                                continue
2✔
50
                        }
51
                }
52
                localTimestamp := math.MaxInt
8✔
53
                if j < len(localMigrations) {
14✔
54
                        if localTimestamp, err = strconv.Atoi(localMigrations[j]); err != nil {
8✔
55
                                j++
2✔
56
                                continue
2✔
57
                        }
58
                }
59
                // Top to bottom chronological order
60
                if localTimestamp < remoteTimestamp {
8✔
61
                        table += fmt.Sprintf("|`%s`|` `|`%s`|\n", localMigrations[j], utils.FormatTimestampVersion(localMigrations[j]))
2✔
62
                        j++
2✔
63
                } else if remoteTimestamp < localTimestamp {
8✔
64
                        table += fmt.Sprintf("|` `|`%s`|`%s`|\n", remoteMigrations[i], utils.FormatTimestampVersion(remoteMigrations[i]))
2✔
65
                        i++
2✔
66
                } else {
4✔
67
                        table += fmt.Sprintf("|`%s`|`%s`|`%s`|\n", localMigrations[j], remoteMigrations[i], utils.FormatTimestampVersion(remoteMigrations[i]))
2✔
68
                        i++
2✔
69
                        j++
2✔
70
                }
2✔
71
        }
72

73
        for i, j := 0, 0; i < len(remoteMigrations) || j < len(localMigrations); {
16✔
74
                if i < len(remoteMigrations) && !strings.HasPrefix(remoteMigrations[i], "r_") {
18✔
75
                        i++
6✔
76
                        continue
6✔
77
                }
78

79
                if j < len(localMigrations) && !strings.HasPrefix(localMigrations[j], "r_") {
12✔
80
                        j++
6✔
81
                        continue
6✔
82
                }
83

84
                // Append repeatable migrations to table
NEW
85
                if i >= len(remoteMigrations) {
×
NEW
86
                        table += fmt.Sprintf("|`%s`|` `|` `|\n", localMigrations[j])
×
NEW
87
                        j++
×
NEW
88
                } else if j >= len(localMigrations) {
×
NEW
89
                        table += fmt.Sprintf("|` `|`%s`|` `|\n", remoteMigrations[i])
×
NEW
90
                        i++
×
NEW
91
                } else {
×
NEW
92
                        if localMigrations[j] < remoteMigrations[i] {
×
NEW
93
                                table += fmt.Sprintf("|`%s`|` `|` `|\n", localMigrations[j])
×
NEW
94
                                j++
×
NEW
95
                        } else if remoteMigrations[i] < localMigrations[j] {
×
NEW
96
                                table += fmt.Sprintf("|` `|`%s`|` `|\n", remoteMigrations[i])
×
NEW
97
                                i++
×
NEW
98
                        } else {
×
NEW
99
                                table += fmt.Sprintf("|`%s`|`%s`|` `|\n", localMigrations[j], remoteMigrations[i])
×
NEW
100
                                i++
×
NEW
101
                                j++
×
NEW
102
                        }
×
103
                }
104
        }
105

106
        return table
4✔
107
}
108

109
func RenderTable(markdown string) error {
1✔
110
        r, err := glamour.NewTermRenderer(
1✔
111
                glamour.WithAutoStyle(),
1✔
112
                glamour.WithWordWrap(-1),
1✔
113
        )
1✔
114
        if err != nil {
1✔
115
                return errors.Errorf("failed to initialise terminal renderer: %w", err)
×
116
        }
×
117
        out, err := r.Render(markdown)
1✔
118
        if err != nil {
1✔
119
                return errors.Errorf("failed to render markdown: %w", err)
×
120
        }
×
121
        fmt.Print(out)
1✔
122
        return nil
1✔
123
}
124

125
func LoadLocalVersions(fsys afero.Fs) ([]string, error) {
5✔
126
        var versions []string
5✔
127
        filter := func(v string) bool {
7✔
128
                versions = append(versions, v)
2✔
129
                return true
2✔
130
        }
2✔
131
        _, err := migration.ListLocalMigrations(utils.MigrationsDir, afero.NewIOFS(fsys), filter)
5✔
132
        return versions, err
5✔
133
}
134

135
func LoadPartialMigrations(version string, fsys afero.Fs) ([]string, error) {
×
136
        filter := func(v string) bool {
×
NEW
137
                return version == "" || strings.HasPrefix(version, "r_") || v <= version
×
138
        }
×
139
        return migration.ListLocalMigrations(utils.MigrationsDir, afero.NewIOFS(fsys), filter)
×
140
}
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