Skip to content

Commit 3a7e63e

Browse files
committed
Support deletion of stackpack versions
1 parent dc69036 commit 3a7e63e

57 files changed

Lines changed: 4836 additions & 1699 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cmd/stackpack.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ func StackPackCommand(cli *di.Deps) *cobra.Command {
2727
cmd.AddCommand(stackpack.StackpackUpgradeCommand(cli))
2828
cmd.AddCommand(stackpack.StackpackConfirmManualStepsCommand(cli))
2929
cmd.AddCommand(stackpack.StackpackDescribeCommand(cli))
30+
cmd.AddCommand(stackpack.StackpackListVersionsCommand(cli))
31+
cmd.AddCommand(stackpack.StackpackDeleteVersionCommand(cli))
32+
cmd.AddCommand(stackpack.StackpackDeleteVersionsCommand(cli))
3033

3134
// The not-production-ready commands
3235
if os.Getenv(experimentalStackpackEnvVar) != "" {

cmd/stackpack/flags.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@ const (
66
IdFlag = "id"
77
NameFlag = "name"
88
UnlockedStrategyFlag = "unlocked-strategy"
9+
VersionFlag = "version"
10+
AllFlag = "all"
11+
DevFlag = "dev"
912
)
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package stackpack
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/spf13/cobra"
7+
"github.com/stackvista/stackstate-cli/generated/stackstate_api"
8+
"github.com/stackvista/stackstate-cli/internal/common"
9+
"github.com/stackvista/stackstate-cli/internal/di"
10+
)
11+
12+
type DeleteVersionArgs struct {
13+
Name string
14+
Version string
15+
}
16+
17+
func StackpackDeleteVersionCommand(cli *di.Deps) *cobra.Command {
18+
args := &DeleteVersionArgs{}
19+
cmd := &cobra.Command{
20+
Use: "delete-version",
21+
Short: "Delete a specific version of a StackPack",
22+
Long: "Delete a specific version of a StackPack from the server. The version cannot be deleted if it is currently in use by an installed instance.",
23+
Example: `# delete version 1.0.0 of the kubernetes StackPack
24+
sts stackpack delete-version --name kubernetes --version 1.0.0`,
25+
RunE: cli.CmdRunEWithApi(RunStackpackDeleteVersionCommand(args)),
26+
}
27+
common.AddRequiredNameFlagVar(cmd, &args.Name, "Name of the StackPack")
28+
cmd.Flags().StringVar(&args.Version, VersionFlag, "", "Version to delete")
29+
cmd.MarkFlagRequired(VersionFlag) //nolint:errcheck
30+
return cmd
31+
}
32+
33+
func RunStackpackDeleteVersionCommand(args *DeleteVersionArgs) di.CmdWithApiFn {
34+
return func(
35+
cmd *cobra.Command,
36+
cli *di.Deps,
37+
api *stackstate_api.APIClient,
38+
serverInfo *stackstate_api.ServerInfo,
39+
) common.CLIError {
40+
resp, err := api.StackpackApi.StackPackDeleteVersion(cli.Context, args.Name, args.Version).Execute()
41+
if err != nil {
42+
return common.NewResponseError(err, resp)
43+
}
44+
45+
if cli.IsJson() {
46+
cli.Printer.PrintJson(map[string]interface{}{
47+
"deleted": args.Version,
48+
})
49+
} else {
50+
cli.Printer.Success(fmt.Sprintf("Successfully deleted version %s of StackPack %s", args.Version, args.Name))
51+
}
52+
53+
return nil
54+
}
55+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package stackpack
2+
3+
import (
4+
"testing"
5+
6+
"github.com/spf13/cobra"
7+
"github.com/stackvista/stackstate-cli/internal/di"
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func setupStackPackDeleteVersionCmd(t *testing.T) (*di.MockDeps, *cobra.Command) {
12+
cli := di.NewMockDeps(t)
13+
cmd := StackpackDeleteVersionCommand(&cli.Deps)
14+
return &cli, cmd
15+
}
16+
17+
func TestStackpackDeleteVersionPrintToConsole(t *testing.T) {
18+
cli, cmd := setupStackPackDeleteVersionCmd(t)
19+
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "delete-version", "--name", "kubernetes", "--version", "1.0.0")
20+
21+
expectedSuccessMessage := []string{"Successfully deleted version 1.0.0 of StackPack kubernetes"}
22+
assert.True(t, cli.MockPrinter.HasNonJsonCalls)
23+
assert.Equal(t, expectedSuccessMessage, *cli.MockPrinter.SuccessCalls)
24+
25+
assert.Equal(t, 1, len(*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionCalls))
26+
call := (*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionCalls)[0]
27+
assert.Equal(t, "kubernetes", call.PstackPackName)
28+
assert.Equal(t, "1.0.0", call.Pversion)
29+
}
30+
31+
func TestStackpackDeleteVersionPrintToJson(t *testing.T) {
32+
cli, cmd := setupStackPackDeleteVersionCmd(t)
33+
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "delete-version", "--name", "kubernetes", "--version", "1.0.0", "-o", "json")
34+
35+
expectedJsonCalls := []map[string]interface{}{{
36+
"deleted": "1.0.0",
37+
}}
38+
assert.False(t, cli.MockPrinter.HasNonJsonCalls)
39+
assert.Equal(t, expectedJsonCalls, *cli.MockPrinter.PrintJsonCalls)
40+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package stackpack
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/spf13/cobra"
8+
"github.com/stackvista/stackstate-cli/generated/stackstate_api"
9+
"github.com/stackvista/stackstate-cli/internal/common"
10+
"github.com/stackvista/stackstate-cli/internal/di"
11+
"github.com/stackvista/stackstate-cli/internal/printer"
12+
)
13+
14+
const (
15+
FromFlag = "from"
16+
ToFlag = "to"
17+
)
18+
19+
type DeleteVersionsArgs struct {
20+
Name string
21+
From string
22+
To string
23+
All bool
24+
Dev bool
25+
}
26+
27+
func StackpackDeleteVersionsCommand(cli *di.Deps) *cobra.Command {
28+
args := &DeleteVersionsArgs{}
29+
cmd := &cobra.Command{
30+
Use: "delete-versions",
31+
Short: "Delete multiple versions of a StackPack",
32+
Long: "Delete multiple versions of a StackPack by specifying a version range or by deleting all versions. Versions currently in use by installed instances are skipped automatically.",
33+
Example: `# delete all versions up to and including 1.5.0
34+
sts stackpack delete-versions --name kubernetes --to 1.5.0
35+
36+
# delete versions in a specific range
37+
sts stackpack delete-versions --name kubernetes --from 1.0.0 --to 1.5.0
38+
39+
# delete all development (SNAPSHOT) versions
40+
sts stackpack delete-versions --name kubernetes --all --dev`,
41+
RunE: cli.CmdRunEWithApi(RunStackpackDeleteVersionsCommand(args)),
42+
}
43+
common.AddRequiredNameFlagVar(cmd, &args.Name, "Name of the StackPack")
44+
cmd.Flags().StringVar(&args.From, FromFlag, "", "Inclusive lower bound: delete versions >= this version")
45+
cmd.Flags().StringVar(&args.To, ToFlag, "", "Inclusive upper bound: delete versions <= this version")
46+
cmd.Flags().BoolVar(&args.All, AllFlag, false, "Delete all versions (cannot be combined with --from or --to)")
47+
cmd.Flags().BoolVar(&args.Dev, DevFlag, false, "Restrict to development versions only (e.g. SNAPSHOT)")
48+
return cmd
49+
}
50+
51+
func RunStackpackDeleteVersionsCommand(args *DeleteVersionsArgs) di.CmdWithApiFn {
52+
return func(
53+
cmd *cobra.Command,
54+
cli *di.Deps,
55+
api *stackstate_api.APIClient,
56+
serverInfo *stackstate_api.ServerInfo,
57+
) common.CLIError {
58+
if !args.All && args.From == "" && args.To == "" {
59+
return common.NewCLIArgParseError(fmt.Errorf("at least one of --all, --from, or --to must be specified"))
60+
}
61+
if args.All && (args.From != "" || args.To != "") {
62+
return common.NewCLIArgParseError(fmt.Errorf("--all cannot be combined with --from or --to"))
63+
}
64+
65+
req := api.StackpackApi.StackPackDeleteVersions(cli.Context, args.Name)
66+
if args.From != "" {
67+
req = req.From(args.From)
68+
}
69+
if args.To != "" {
70+
req = req.To(args.To)
71+
}
72+
if args.All {
73+
req = req.All(true)
74+
}
75+
if args.Dev {
76+
req = req.Dev(true)
77+
}
78+
79+
result, resp, err := req.Execute()
80+
if err != nil {
81+
return common.NewResponseError(err, resp)
82+
}
83+
84+
if cli.IsJson() {
85+
cli.Printer.PrintJson(map[string]interface{}{
86+
"deleted": result.Deleted,
87+
"skippedInUse": result.SkippedInUse,
88+
})
89+
} else {
90+
if len(result.Deleted) > 0 {
91+
cli.Printer.Success(fmt.Sprintf("Deleted versions: %s", strings.Join(result.Deleted, ", ")))
92+
}
93+
if len(result.SkippedInUse) > 0 {
94+
cli.Printer.Table(printer.TableData{
95+
Header: []string{"skipped (in use)"},
96+
Data: func() [][]interface{} {
97+
rows := make([][]interface{}, 0, len(result.SkippedInUse))
98+
for _, v := range result.SkippedInUse {
99+
rows = append(rows, []interface{}{v})
100+
}
101+
return rows
102+
}(),
103+
})
104+
}
105+
if len(result.Deleted) == 0 && len(result.SkippedInUse) == 0 {
106+
cli.Printer.Success("No versions matched the specified criteria")
107+
}
108+
}
109+
110+
return nil
111+
}
112+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package stackpack
2+
3+
import (
4+
"testing"
5+
6+
"github.com/spf13/cobra"
7+
"github.com/stackvista/stackstate-cli/generated/stackstate_api"
8+
"github.com/stackvista/stackstate-cli/internal/di"
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func setupStackPackDeleteVersionsCmd(t *testing.T) (*di.MockDeps, *cobra.Command) {
13+
cli := di.NewMockDeps(t)
14+
cmd := StackpackDeleteVersionsCommand(&cli.Deps)
15+
cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsResponse.Result = stackstate_api.DeleteVersionsResult{
16+
Deleted: []string{"1.0.0", "1.1.0"},
17+
SkippedInUse: []string{"1.2.0"},
18+
}
19+
return &cli, cmd
20+
}
21+
22+
func TestStackpackDeleteVersionsWithTo(t *testing.T) {
23+
cli, cmd := setupStackPackDeleteVersionsCmd(t)
24+
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "delete-versions", "--name", "kubernetes", "--to", "1.5.0")
25+
26+
assert.True(t, cli.MockPrinter.HasNonJsonCalls)
27+
assert.Equal(t, []string{"Deleted versions: 1.0.0, 1.1.0"}, *cli.MockPrinter.SuccessCalls)
28+
29+
assert.Equal(t, 1, len(*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsCalls))
30+
call := (*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsCalls)[0]
31+
assert.Equal(t, "kubernetes", call.PstackPackName)
32+
assert.Nil(t, call.Pfrom)
33+
assert.Equal(t, "1.5.0", *call.Pto)
34+
assert.Nil(t, call.Pall)
35+
assert.Nil(t, call.Pdev)
36+
}
37+
38+
func TestStackpackDeleteVersionsWithRange(t *testing.T) {
39+
cli, cmd := setupStackPackDeleteVersionsCmd(t)
40+
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "delete-versions", "--name", "kubernetes", "--from", "1.0.0", "--to", "1.5.0")
41+
42+
assert.Equal(t, 1, len(*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsCalls))
43+
call := (*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsCalls)[0]
44+
assert.Equal(t, "kubernetes", call.PstackPackName)
45+
assert.Equal(t, "1.0.0", *call.Pfrom)
46+
assert.Equal(t, "1.5.0", *call.Pto)
47+
assert.Nil(t, call.Pall)
48+
assert.Nil(t, call.Pdev)
49+
}
50+
51+
func TestStackpackDeleteVersionsWithAll(t *testing.T) {
52+
cli, cmd := setupStackPackDeleteVersionsCmd(t)
53+
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "delete-versions", "--name", "kubernetes", "--all")
54+
55+
assert.Equal(t, 1, len(*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsCalls))
56+
call := (*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsCalls)[0]
57+
assert.Equal(t, "kubernetes", call.PstackPackName)
58+
assert.Nil(t, call.Pfrom)
59+
assert.Nil(t, call.Pto)
60+
assert.Equal(t, true, *call.Pall)
61+
assert.Nil(t, call.Pdev)
62+
}
63+
64+
func TestStackpackDeleteVersionsWithAllAndDev(t *testing.T) {
65+
cli, cmd := setupStackPackDeleteVersionsCmd(t)
66+
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "delete-versions", "--name", "kubernetes", "--all", "--dev")
67+
68+
assert.Equal(t, 1, len(*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsCalls))
69+
call := (*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsCalls)[0]
70+
assert.Equal(t, "kubernetes", call.PstackPackName)
71+
assert.Nil(t, call.Pfrom)
72+
assert.Nil(t, call.Pto)
73+
assert.Equal(t, true, *call.Pall)
74+
assert.Equal(t, true, *call.Pdev)
75+
}
76+
77+
func TestStackpackDeleteVersionsPrintToJson(t *testing.T) {
78+
cli, cmd := setupStackPackDeleteVersionsCmd(t)
79+
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "delete-versions", "--name", "kubernetes", "--to", "2.0.0", "-o", "json")
80+
81+
expectedJsonCalls := []map[string]interface{}{{
82+
"deleted": []string{"1.0.0", "1.1.0"},
83+
"skippedInUse": []string{"1.2.0"},
84+
}}
85+
assert.False(t, cli.MockPrinter.HasNonJsonCalls)
86+
assert.Equal(t, expectedJsonCalls, *cli.MockPrinter.PrintJsonCalls)
87+
}
88+
89+
func TestStackpackDeleteVersionsNoFlags(t *testing.T) {
90+
cli := di.NewMockDeps(t)
91+
cmd := StackpackDeleteVersionsCommand(&cli.Deps)
92+
_, err := di.ExecuteCommandWithContext(&cli.Deps, cmd, "delete-versions", "--name", "kubernetes")
93+
assert.Error(t, err)
94+
}
95+
96+
func TestStackpackDeleteVersionsAllWithFrom(t *testing.T) {
97+
cli := di.NewMockDeps(t)
98+
cmd := StackpackDeleteVersionsCommand(&cli.Deps)
99+
_, err := di.ExecuteCommandWithContext(&cli.Deps, cmd, "delete-versions", "--name", "kubernetes", "--all", "--from", "1.0.0")
100+
assert.Error(t, err)
101+
}
102+
103+
func TestStackpackDeleteVersionsAllWithTo(t *testing.T) {
104+
cli := di.NewMockDeps(t)
105+
cmd := StackpackDeleteVersionsCommand(&cli.Deps)
106+
_, err := di.ExecuteCommandWithContext(&cli.Deps, cmd, "delete-versions", "--name", "kubernetes", "--all", "--to", "1.5.0")
107+
assert.Error(t, err)
108+
}

0 commit comments

Comments
 (0)