-
Notifications
You must be signed in to change notification settings - Fork 2.7k
/
migrate_status.go
137 lines (126 loc) · 4.01 KB
/
migrate_status.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package commands
import (
"bytes"
"fmt"
"text/tabwriter"
"github.com/hasura/graphql-engine/cli/v2/internal/errors"
"github.com/hasura/graphql-engine/cli/v2/internal/hasura"
"github.com/hasura/graphql-engine/cli/v2/internal/metadatautil"
"github.com/hasura/graphql-engine/cli/v2/util"
"github.com/hasura/graphql-engine/cli/v2"
"github.com/hasura/graphql-engine/cli/v2/migrate"
"github.com/spf13/cobra"
)
func newMigrateStatusCmd(ec *cli.ExecutionContext) *cobra.Command {
opts := &MigrateStatusOptions{
EC: ec,
StatusOpts: make(StatusOptions),
}
migrateStatusCmd := &cobra.Command{
Use: "status",
Short: "Display current status of migrations on a database",
Long: "When running this command, the CLI will allow you to select which database - or all - to run the status command on. The CLI will return the current status of migrations on the selected database(s), including the version, name, source, database, and status.",
Example: ` # Use with admin secret:
hasura migrate status --admin-secret "<your-admin-secret>"
# Check status on a different server:
hasura migrate status --endpoint "<endpoint>"`,
SilenceUsage: true,
PreRunE: func(cmd *cobra.Command, args []string) error {
var op = genOpName(cmd, "PreRunE")
if err := validateConfigV3FlagsWithAll(cmd, ec); err != nil {
return errors.E(op, err)
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
var op = genOpName(cmd, "RunE")
if err := opts.Run(); err != nil {
return errors.E(op, err)
}
buf := printStatus(opts.StatusOpts)
fmt.Fprintf(ec.Stdout, "%s", buf)
return nil
},
}
return migrateStatusCmd
}
func (o *MigrateStatusOptions) Run() error {
var op errors.Op = "commands.MigrateStatusOptions.Run"
o.EC.Spin("Fetching migration status...")
defer o.EC.Spinner.Stop()
if ec.AllDatabases {
sourcesAndKind, err := metadatautil.GetSourcesAndKind(o.EC.APIClient.V1Metadata.ExportMetadata)
if err != nil {
return errors.E(op, fmt.Errorf("got error while getting the sources list : %v", err))
}
for _, source := range sourcesAndKind {
o.Source = cli.Source(source)
status, err := o.RunOnSource()
if err != nil {
return errors.E(op, fmt.Errorf("error getting status for database '%s': %v", o.Source.Name, err))
}
o.StatusOpts[o.Source] = status
}
return nil
}
o.Source = ec.Source
status, err := o.RunOnSource()
if err != nil {
return errors.E(op, fmt.Errorf("error getting status for database '%s': %v", o.Source.Name, err))
}
o.StatusOpts[o.Source] = status
return nil
}
type StatusOptions map[cli.Source]*migrate.Status
type MigrateStatusOptions struct {
EC *cli.ExecutionContext
Source cli.Source
StatusOpts StatusOptions
}
func (o *MigrateStatusOptions) RunOnSource() (*migrate.Status, error) {
var op errors.Op = "commands.MigrateStatusOptions.RunOnSource"
if o.EC.Config.Version <= cli.V2 {
o.Source.Name = ""
o.Source.Kind = hasura.SourceKindPG
}
migrateDrv, err := migrate.NewMigrate(o.EC, true, o.Source.Name, o.Source.Kind)
if err != nil {
return nil, errors.E(op, err)
}
status, err := executeStatus(migrateDrv)
if err != nil {
return nil, errors.E(op, fmt.Errorf("cannot fetch migrate status: %w", err))
}
return status, nil
}
func printStatus(statusOpts StatusOptions) *bytes.Buffer {
out := new(tabwriter.Writer)
buf := &bytes.Buffer{}
out.Init(buf, 0, 8, 2, ' ', 0)
w := util.NewPrefixWriter(out)
for source, status := range statusOpts {
if source.Name != "" {
w.Write(util.LEVEL_0, fmt.Sprintf("\nDatabase: %s\n", source.Name))
}
w.Write(util.LEVEL_0, "VERSION\tNAME\tSOURCE STATUS\tDATABASE STATUS\n")
for _, version := range status.Index {
w.Write(util.LEVEL_0, "%d\t%s\t%s\t%s\n",
version,
status.Migrations[version].Name,
convertBool(status.Migrations[version].IsPresent),
convertBool(status.Migrations[version].IsApplied),
)
}
}
out.Flush()
return buf
}
func convertBool(ok bool) string {
switch ok {
case true:
return "Present"
case false:
return "Not Present"
}
return ""
}