From 17d6b0e554ed17e18ce3181aed906ea07e14b7f3 Mon Sep 17 00:00:00 2001 From: Nick Holden Date: Fri, 27 Mar 2026 14:41:24 -0700 Subject: [PATCH 1/2] Add --delete-descendants flag to branch delete command Allows users to delete a branch and all of its descendant branches in a single operation. Works for both MySQL and PostgreSQL databases. Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/cmd/branch/delete.go | 16 ++-- internal/cmd/branch/delete_test.go | 114 +++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 6 deletions(-) diff --git a/internal/cmd/branch/delete.go b/internal/cmd/branch/delete.go index 4822f967..60e938a5 100644 --- a/internal/cmd/branch/delete.go +++ b/internal/cmd/branch/delete.go @@ -16,6 +16,7 @@ import ( func DeleteCmd(ch *cmdutil.Helper) *cobra.Command { var force bool + var deleteDescendants bool cmd := &cobra.Command{ Use: "delete ", @@ -122,15 +123,17 @@ func DeleteCmd(ch *cmdutil.Helper) *cobra.Command { if db.Kind == "mysql" { err = client.DatabaseBranches.Delete(ctx, &planetscale.DeleteDatabaseBranchRequest{ - Organization: ch.Config.Organization, - Database: source, - Branch: branch, + Organization: ch.Config.Organization, + Database: source, + Branch: branch, + DeleteDescendants: deleteDescendants, }) } else { err = client.PostgresBranches.Delete(ctx, &planetscale.DeletePostgresBranchRequest{ - Organization: ch.Config.Organization, - Database: source, - Branch: branch, + Organization: ch.Config.Organization, + Database: source, + Branch: branch, + DeleteDescendants: deleteDescendants, }) } @@ -158,5 +161,6 @@ func DeleteCmd(ch *cmdutil.Helper) *cobra.Command { } cmd.Flags().BoolVar(&force, "force", false, "Delete a branch without confirmation") + cmd.Flags().BoolVar(&deleteDescendants, "delete-descendants", false, "Delete the branch and all of its descendant branches") return cmd } diff --git a/internal/cmd/branch/delete_test.go b/internal/cmd/branch/delete_test.go index c9d6a99d..2b4c7f29 100644 --- a/internal/cmd/branch/delete_test.go +++ b/internal/cmd/branch/delete_test.go @@ -131,6 +131,63 @@ func TestBranch_DeleteCmd_ServiceTokenPermissionError(t *testing.T) { c.Assert(orgSvc.ListFnInvoked, qt.IsTrue) } +func TestBranch_DeleteCmd_WithDeleteDescendants(t *testing.T) { + c := qt.New(t) + + var buf bytes.Buffer + format := printer.JSON + p := printer.NewPrinter(&format) + p.SetResourceOutput(&buf) + + org := "planetscale" + db := "planetscale" + branch := "development" + + svc := &mock.DatabaseBranchesService{ + DeleteFn: func(ctx context.Context, req *ps.DeleteDatabaseBranchRequest) error { + c.Assert(req.Branch, qt.Equals, branch) + c.Assert(req.Database, qt.Equals, db) + c.Assert(req.Organization, qt.Equals, org) + c.Assert(req.DeleteDescendants, qt.IsTrue) + return nil + }, + } + + dbSvc := &mock.DatabaseService{ + GetFn: func(ctx context.Context, req *ps.GetDatabaseRequest) (*ps.Database, error) { + c.Assert(req.Database, qt.Equals, db) + c.Assert(req.Organization, qt.Equals, org) + return &ps.Database{Kind: "mysql"}, nil + }, + } + + ch := &cmdutil.Helper{ + Printer: p, + Config: &config.Config{ + Organization: org, + }, + Client: func() (*ps.Client, error) { + return &ps.Client{ + DatabaseBranches: svc, + Databases: dbSvc, + }, nil + }, + } + + cmd := DeleteCmd(ch) + cmd.SetArgs([]string{db, branch, "--force", "--delete-descendants"}) + err := cmd.Execute() + + res := map[string]string{ + "result": "branch deleted", + "branch": branch, + } + + c.Assert(err, qt.IsNil) + c.Assert(svc.DeleteFnInvoked, qt.IsTrue) + c.Assert(buf.String(), qt.JSONEquals, res) +} + func TestBranch_DeleteCmd_PostgreSQL(t *testing.T) { c := qt.New(t) @@ -186,3 +243,60 @@ func TestBranch_DeleteCmd_PostgreSQL(t *testing.T) { c.Assert(svc.DeleteFnInvoked, qt.IsTrue) c.Assert(buf.String(), qt.JSONEquals, res) } + +func TestBranch_DeleteCmd_PostgreSQL_WithDeleteDescendants(t *testing.T) { + c := qt.New(t) + + var buf bytes.Buffer + format := printer.JSON + p := printer.NewPrinter(&format) + p.SetResourceOutput(&buf) + + org := "planetscale" + db := "planetscale" + branch := "development" + + svc := &mock.PostgresBranchesService{ + DeleteFn: func(ctx context.Context, req *ps.DeletePostgresBranchRequest) error { + c.Assert(req.Branch, qt.Equals, branch) + c.Assert(req.Database, qt.Equals, db) + c.Assert(req.Organization, qt.Equals, org) + c.Assert(req.DeleteDescendants, qt.IsTrue) + return nil + }, + } + + dbSvc := &mock.DatabaseService{ + GetFn: func(ctx context.Context, req *ps.GetDatabaseRequest) (*ps.Database, error) { + c.Assert(req.Database, qt.Equals, db) + c.Assert(req.Organization, qt.Equals, org) + return &ps.Database{Kind: "postgresql"}, nil + }, + } + + ch := &cmdutil.Helper{ + Printer: p, + Config: &config.Config{ + Organization: org, + }, + Client: func() (*ps.Client, error) { + return &ps.Client{ + PostgresBranches: svc, + Databases: dbSvc, + }, nil + }, + } + + cmd := DeleteCmd(ch) + cmd.SetArgs([]string{db, branch, "--force", "--delete-descendants"}) + err := cmd.Execute() + + res := map[string]string{ + "result": "branch deleted", + "branch": branch, + } + + c.Assert(err, qt.IsNil) + c.Assert(svc.DeleteFnInvoked, qt.IsTrue) + c.Assert(buf.String(), qt.JSONEquals, res) +} From 8f20f0ae372a04b52cffdff998e6186f6582b112 Mon Sep 17 00:00:00 2001 From: Nick Holden Date: Fri, 27 Mar 2026 15:00:09 -0700 Subject: [PATCH 2/2] Update planetscale-go to v0.157.0 Pulls in the DeleteDescendants field on branch delete request structs. Co-Authored-By: Claude Opus 4.6 (1M context) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d33c8ed8..0c27106c 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/mattn/go-shellwords v1.0.12 github.com/mitchellh/go-homedir v1.1.0 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c - github.com/planetscale/planetscale-go v0.156.0 + github.com/planetscale/planetscale-go v0.157.0 github.com/planetscale/psdb v0.0.0-20250717190954-65c6661ab6e4 github.com/planetscale/psdbproxy v0.0.0-20250728082226-3f4ea3a74ec7 github.com/spf13/cobra v1.10.2 diff --git a/go.sum b/go.sum index 4e670d63..4cc9b45d 100644 --- a/go.sum +++ b/go.sum @@ -176,8 +176,8 @@ github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjL github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/planetscale/noglog v0.2.1-0.20210421230640-bea75fcd2e8e h1:MZ8D+Z3m2vvqGZLvoQfpaGg/j1fNDr4j03s3PRz4rVY= github.com/planetscale/noglog v0.2.1-0.20210421230640-bea75fcd2e8e/go.mod h1:hwAsSPQdvPa3WcfKfzTXxtEq/HlqwLjQasfO6QbGo4Q= -github.com/planetscale/planetscale-go v0.156.0 h1:VThRagwFmthnPZ/A0W8N+bHHQ8+PdqdcLBHunr7p/jY= -github.com/planetscale/planetscale-go v0.156.0/go.mod h1:paQCI5SgquuoewvMQM7R+r1XJO868bdP6/ihGidYRM0= +github.com/planetscale/planetscale-go v0.157.0 h1:b0kWxC39F4/FQw2/Y+5/H4tRWUAzvl2ZukimrsTYP7M= +github.com/planetscale/planetscale-go v0.157.0/go.mod h1:paQCI5SgquuoewvMQM7R+r1XJO868bdP6/ihGidYRM0= github.com/planetscale/psdb v0.0.0-20250717190954-65c6661ab6e4 h1:Xv5pj20Rhfty1Tv0OVcidg4ez4PvGrpKvb6rvUwQgDs= github.com/planetscale/psdb v0.0.0-20250717190954-65c6661ab6e4/go.mod h1:M52h5IWxAcbdQ1hSZrLAGQC4ZXslxEsK/Wh9nu3wdWs= github.com/planetscale/psdbproxy v0.0.0-20250728082226-3f4ea3a74ec7 h1:aRd6vdE1fyuSI4RVj7oCr8lFmgqXvpnPUmN85VbZCp8=