Skip to content

Commit 3d81c20

Browse files
authored
Merge pull request #1195 from planetscale/nick/vtctld-cli-base
vtctld: add base CLI commands
2 parents b35ff33 + 5aca10a commit 3d81c20

13 files changed

Lines changed: 518 additions & 5 deletions

go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ require (
1010
github.com/benbjohnson/clock v1.3.5
1111
github.com/briandowns/spinner v1.23.2
1212
github.com/charmbracelet/huh v0.8.0
13+
github.com/dustin/go-humanize v1.0.1
1314
github.com/fatih/color v1.18.0
1415
github.com/frankban/quicktest v1.14.6
1516
github.com/go-sql-driver/mysql v1.9.3
1617
github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1
1718
github.com/google/go-cmp v0.7.0
1819
github.com/hashicorp/go-cleanhttp v0.5.2
1920
github.com/hashicorp/go-version v1.8.0
21+
github.com/kataras/tablewriter v0.0.0-20180708051242-e063d29b7c23
2022
github.com/lensesio/tableprinter v0.0.0-20201125135848-89e81fc956e7
2123
github.com/lib/pq v1.11.2
2224
github.com/mark3labs/mcp-go v0.44.0
@@ -25,7 +27,7 @@ require (
2527
github.com/mattn/go-shellwords v1.0.12
2628
github.com/mitchellh/go-homedir v1.1.0
2729
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
28-
github.com/planetscale/planetscale-go v0.148.0
30+
github.com/planetscale/planetscale-go v0.151.0
2931
github.com/planetscale/psdb v0.0.0-20250717190954-65c6661ab6e4
3032
github.com/planetscale/psdbproxy v0.0.0-20250728082226-3f4ea3a74ec7
3133
github.com/spf13/cobra v1.10.2
@@ -68,7 +70,6 @@ require (
6870
github.com/clipperhouse/uax29/v2 v2.3.0 // indirect
6971
github.com/danieljoos/wincred v1.2.3 // indirect
7072
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
71-
github.com/dustin/go-humanize v1.0.1 // indirect
7273
github.com/dvsekhvalnov/jose2go v1.8.0 // indirect
7374
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
7475
github.com/fsnotify/fsnotify v1.9.0 // indirect
@@ -79,7 +80,6 @@ require (
7980
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
8081
github.com/inconshreveable/mousetrap v1.1.0 // indirect
8182
github.com/invopop/jsonschema v0.13.0 // indirect
82-
github.com/kataras/tablewriter v0.0.0-20180708051242-e063d29b7c23 // indirect
8383
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
8484
github.com/klauspost/compress v1.18.2 // indirect
8585
github.com/klauspost/connect-compress/v2 v2.1.0 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,8 @@ github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjL
182182
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
183183
github.com/planetscale/noglog v0.2.1-0.20210421230640-bea75fcd2e8e h1:MZ8D+Z3m2vvqGZLvoQfpaGg/j1fNDr4j03s3PRz4rVY=
184184
github.com/planetscale/noglog v0.2.1-0.20210421230640-bea75fcd2e8e/go.mod h1:hwAsSPQdvPa3WcfKfzTXxtEq/HlqwLjQasfO6QbGo4Q=
185-
github.com/planetscale/planetscale-go v0.148.0 h1:9tMRq4btsuOe5s/QCx6DNKDwKnGVEZYu++RX0rOaC6g=
186-
github.com/planetscale/planetscale-go v0.148.0/go.mod h1:PheYDHAwF14wfCBak1M0J64AdPW8NUeyvgPgWqe7zpI=
185+
github.com/planetscale/planetscale-go v0.151.0 h1:Vx1khlA76AnioSZzoY6gbJvXfMOKVWjjf4980bYgAA8=
186+
github.com/planetscale/planetscale-go v0.151.0/go.mod h1:mnADwPuBOmZaRCBbCzQna8N69vhlpEDCWGMF501qnEA=
187187
github.com/planetscale/psdb v0.0.0-20250717190954-65c6661ab6e4 h1:Xv5pj20Rhfty1Tv0OVcidg4ez4PvGrpKvb6rvUwQgDs=
188188
github.com/planetscale/psdb v0.0.0-20250717190954-65c6661ab6e4/go.mod h1:M52h5IWxAcbdQ1hSZrLAGQC4ZXslxEsK/Wh9nu3wdWs=
189189
github.com/planetscale/psdbproxy v0.0.0-20250728082226-3f4ea3a74ec7 h1:aRd6vdE1fyuSI4RVj7oCr8lFmgqXvpnPUmN85VbZCp8=

internal/cmd/branch/branch.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"time"
66

7+
"github.com/planetscale/cli/internal/cmd/branch/vtctld"
78
"github.com/planetscale/cli/internal/cmdutil"
89
ps "github.com/planetscale/planetscale-go/planetscale"
910
"github.com/spf13/cobra"
@@ -34,6 +35,7 @@ func BranchCmd(ch *cmdutil.Helper) *cobra.Command {
3435
cmd.AddCommand(RoutingRulesCmd(ch))
3536
cmd.AddCommand(SafeMigrationsCmd(ch))
3637
cmd.AddCommand(LintCmd(ch))
38+
cmd.AddCommand(vtctld.VtctldCmd(ch))
3739

3840
return cmd
3941
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package vtctld
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/planetscale/cli/internal/cmdutil"
7+
"github.com/planetscale/cli/internal/printer"
8+
ps "github.com/planetscale/planetscale-go/planetscale"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
func ListKeyspacesCmd(ch *cmdutil.Helper) *cobra.Command {
13+
var flags struct {
14+
name string
15+
}
16+
17+
cmd := &cobra.Command{
18+
Use: "list-keyspaces <database> <branch>",
19+
Short: "List vtctld keyspaces for a branch",
20+
Args: cmdutil.RequiredArgs("database", "branch"),
21+
RunE: func(cmd *cobra.Command, args []string) error {
22+
ctx := cmd.Context()
23+
database, branch := args[0], args[1]
24+
25+
client, err := ch.Client()
26+
if err != nil {
27+
return err
28+
}
29+
30+
end := ch.Printer.PrintProgress(
31+
fmt.Sprintf("Fetching keyspaces for %s/%s\u2026",
32+
printer.BoldBlue(database), printer.BoldBlue(branch)))
33+
defer end()
34+
35+
data, err := client.Vtctld.ListKeyspaces(ctx, &ps.VtctldListKeyspacesRequest{
36+
Organization: ch.Config.Organization,
37+
Database: database,
38+
Branch: branch,
39+
Name: flags.name,
40+
})
41+
if err != nil {
42+
return cmdutil.HandleError(err)
43+
}
44+
45+
end()
46+
return ch.Printer.PrettyPrintJSON(data)
47+
},
48+
}
49+
50+
cmd.Flags().StringVar(&flags.name, "name", "", "Filter by keyspace name")
51+
52+
return cmd
53+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package vtctld
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"testing"
8+
9+
qt "github.com/frankban/quicktest"
10+
11+
"github.com/planetscale/cli/internal/cmdutil"
12+
"github.com/planetscale/cli/internal/config"
13+
"github.com/planetscale/cli/internal/mock"
14+
"github.com/planetscale/cli/internal/printer"
15+
ps "github.com/planetscale/planetscale-go/planetscale"
16+
)
17+
18+
func TestListKeyspaces(t *testing.T) {
19+
c := qt.New(t)
20+
21+
org := "my-org"
22+
db := "my-db"
23+
branch := "my-branch"
24+
25+
svc := &mock.VtctldService{
26+
ListKeyspacesFn: func(ctx context.Context, req *ps.VtctldListKeyspacesRequest) (json.RawMessage, error) {
27+
c.Assert(req.Organization, qt.Equals, org)
28+
c.Assert(req.Database, qt.Equals, db)
29+
c.Assert(req.Branch, qt.Equals, branch)
30+
return json.RawMessage(`{"keyspaces":[]}`), nil
31+
},
32+
}
33+
34+
var buf bytes.Buffer
35+
format := printer.JSON
36+
p := printer.NewPrinter(&format)
37+
p.SetResourceOutput(&buf)
38+
39+
ch := &cmdutil.Helper{
40+
Printer: p,
41+
Config: &config.Config{Organization: org},
42+
Client: func() (*ps.Client, error) {
43+
return &ps.Client{
44+
Vtctld: svc,
45+
}, nil
46+
},
47+
}
48+
49+
cmd := ListKeyspacesCmd(ch)
50+
cmd.SetArgs([]string{db, branch})
51+
err := cmd.Execute()
52+
c.Assert(err, qt.IsNil)
53+
c.Assert(svc.ListKeyspacesFnInvoked, qt.IsTrue)
54+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package vtctld
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/planetscale/cli/internal/cmdutil"
7+
"github.com/planetscale/cli/internal/printer"
8+
ps "github.com/planetscale/planetscale-go/planetscale"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
func StartWorkflowCmd(ch *cmdutil.Helper) *cobra.Command {
13+
var flags struct {
14+
keyspace string
15+
}
16+
17+
cmd := &cobra.Command{
18+
Use: "start-workflow <database> <branch> <workflow>",
19+
Short: "Start a workflow on a branch",
20+
Args: cmdutil.RequiredArgs("database", "branch", "workflow"),
21+
RunE: func(cmd *cobra.Command, args []string) error {
22+
ctx := cmd.Context()
23+
database, branch, workflow := args[0], args[1], args[2]
24+
25+
client, err := ch.Client()
26+
if err != nil {
27+
return err
28+
}
29+
30+
end := ch.Printer.PrintProgress(
31+
fmt.Sprintf("Starting workflow %s on %s/%s\u2026",
32+
printer.BoldBlue(workflow), printer.BoldBlue(database), printer.BoldBlue(branch)))
33+
defer end()
34+
35+
data, err := client.Vtctld.StartWorkflow(ctx, &ps.VtctldStartWorkflowRequest{
36+
Organization: ch.Config.Organization,
37+
Database: database,
38+
Branch: branch,
39+
Workflow: workflow,
40+
Keyspace: flags.keyspace,
41+
})
42+
if err != nil {
43+
return cmdutil.HandleError(err)
44+
}
45+
46+
end()
47+
return ch.Printer.PrettyPrintJSON(data)
48+
},
49+
}
50+
51+
cmd.Flags().StringVar(&flags.keyspace, "keyspace", "", "Keyspace the workflow belongs to")
52+
cmd.MarkFlagRequired("keyspace") // nolint:errcheck
53+
54+
return cmd
55+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package vtctld
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"testing"
8+
9+
qt "github.com/frankban/quicktest"
10+
11+
"github.com/planetscale/cli/internal/cmdutil"
12+
"github.com/planetscale/cli/internal/config"
13+
"github.com/planetscale/cli/internal/mock"
14+
"github.com/planetscale/cli/internal/printer"
15+
ps "github.com/planetscale/planetscale-go/planetscale"
16+
)
17+
18+
func TestStartWorkflow(t *testing.T) {
19+
c := qt.New(t)
20+
21+
org := "my-org"
22+
db := "my-db"
23+
branch := "my-branch"
24+
25+
svc := &mock.VtctldService{
26+
StartWorkflowFn: func(ctx context.Context, req *ps.VtctldStartWorkflowRequest) (json.RawMessage, error) {
27+
c.Assert(req.Organization, qt.Equals, org)
28+
c.Assert(req.Database, qt.Equals, db)
29+
c.Assert(req.Branch, qt.Equals, branch)
30+
c.Assert(req.Workflow, qt.Equals, "my-workflow")
31+
c.Assert(req.Keyspace, qt.Equals, "my-keyspace")
32+
return json.RawMessage(`{"summary":"started"}`), nil
33+
},
34+
}
35+
36+
var buf bytes.Buffer
37+
format := printer.JSON
38+
p := printer.NewPrinter(&format)
39+
p.SetResourceOutput(&buf)
40+
41+
ch := &cmdutil.Helper{
42+
Printer: p,
43+
Config: &config.Config{Organization: org},
44+
Client: func() (*ps.Client, error) {
45+
return &ps.Client{
46+
Vtctld: svc,
47+
}, nil
48+
},
49+
}
50+
51+
cmd := StartWorkflowCmd(ch)
52+
cmd.SetArgs([]string{db, branch, "my-workflow",
53+
"--keyspace", "my-keyspace",
54+
})
55+
err := cmd.Execute()
56+
c.Assert(err, qt.IsNil)
57+
c.Assert(svc.StartWorkflowFnInvoked, qt.IsTrue)
58+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package vtctld
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/planetscale/cli/internal/cmdutil"
7+
"github.com/planetscale/cli/internal/printer"
8+
ps "github.com/planetscale/planetscale-go/planetscale"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
func StopWorkflowCmd(ch *cmdutil.Helper) *cobra.Command {
13+
var flags struct {
14+
keyspace string
15+
}
16+
17+
cmd := &cobra.Command{
18+
Use: "stop-workflow <database> <branch> <workflow>",
19+
Short: "Stop a workflow on a branch",
20+
Args: cmdutil.RequiredArgs("database", "branch", "workflow"),
21+
RunE: func(cmd *cobra.Command, args []string) error {
22+
ctx := cmd.Context()
23+
database, branch, workflow := args[0], args[1], args[2]
24+
25+
client, err := ch.Client()
26+
if err != nil {
27+
return err
28+
}
29+
30+
end := ch.Printer.PrintProgress(
31+
fmt.Sprintf("Stopping workflow %s on %s/%s\u2026",
32+
printer.BoldBlue(workflow), printer.BoldBlue(database), printer.BoldBlue(branch)))
33+
defer end()
34+
35+
data, err := client.Vtctld.StopWorkflow(ctx, &ps.VtctldStopWorkflowRequest{
36+
Organization: ch.Config.Organization,
37+
Database: database,
38+
Branch: branch,
39+
Workflow: workflow,
40+
Keyspace: flags.keyspace,
41+
})
42+
if err != nil {
43+
return cmdutil.HandleError(err)
44+
}
45+
46+
end()
47+
return ch.Printer.PrettyPrintJSON(data)
48+
},
49+
}
50+
51+
cmd.Flags().StringVar(&flags.keyspace, "keyspace", "", "Keyspace the workflow belongs to")
52+
cmd.MarkFlagRequired("keyspace") // nolint:errcheck
53+
54+
return cmd
55+
}

0 commit comments

Comments
 (0)