Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cmd/stackpack.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ func StackPackCommand(cli *di.Deps) *cobra.Command {
cmd.AddCommand(stackpack.StackpackUpgradeCommand(cli))
cmd.AddCommand(stackpack.StackpackConfirmManualStepsCommand(cli))
cmd.AddCommand(stackpack.StackpackDescribeCommand(cli))
cmd.AddCommand(stackpack.StackpackListVersionsCommand(cli))
cmd.AddCommand(stackpack.StackpackDeleteVersionCommand(cli))
cmd.AddCommand(stackpack.StackpackDeleteVersionsCommand(cli))

// The not-production-ready commands
if os.Getenv(experimentalStackpackEnvVar) != "" {
Expand Down
3 changes: 3 additions & 0 deletions cmd/stackpack/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ const (
IdFlag = "id"
NameFlag = "name"
UnlockedStrategyFlag = "unlocked-strategy"
VersionFlag = "version"
AllFlag = "all"
DevOnlyFlag = "dev-only"
)
55 changes: 55 additions & 0 deletions cmd/stackpack/stackpack_delete_version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package stackpack

import (
"fmt"

"github.com/spf13/cobra"
"github.com/stackvista/stackstate-cli/generated/stackstate_api"
"github.com/stackvista/stackstate-cli/internal/common"
"github.com/stackvista/stackstate-cli/internal/di"
)

type DeleteVersionArgs struct {
Name string
Version string
}

func StackpackDeleteVersionCommand(cli *di.Deps) *cobra.Command {
args := &DeleteVersionArgs{}
cmd := &cobra.Command{
Use: "delete-version",
Short: "Delete a specific version of a StackPack",
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.",
Example: `# delete version 1.0.0 of the kubernetes StackPack
sts stackpack delete-version --name kubernetes --version 1.0.0`,
RunE: cli.CmdRunEWithApi(RunStackpackDeleteVersionCommand(args)),
}
common.AddRequiredNameFlagVar(cmd, &args.Name, "Name of the StackPack")
cmd.Flags().StringVar(&args.Version, VersionFlag, "", "Version to delete")
cmd.MarkFlagRequired(VersionFlag) //nolint:errcheck
return cmd
}

func RunStackpackDeleteVersionCommand(args *DeleteVersionArgs) di.CmdWithApiFn {
return func(
cmd *cobra.Command,
cli *di.Deps,
api *stackstate_api.APIClient,
serverInfo *stackstate_api.ServerInfo,
) common.CLIError {
resp, err := api.StackpackApi.StackPackDeleteVersion(cli.Context, args.Name, args.Version).Execute()
if err != nil {
return common.NewResponseError(err, resp)
}

if cli.IsJson() {
cli.Printer.PrintJson(map[string]interface{}{
"deleted": args.Version,
})
} else {
cli.Printer.Success(fmt.Sprintf("Successfully deleted version %s of StackPack %s", args.Version, args.Name))
}

return nil
}
}
40 changes: 40 additions & 0 deletions cmd/stackpack/stackpack_delete_version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package stackpack

import (
"testing"

"github.com/spf13/cobra"
"github.com/stackvista/stackstate-cli/internal/di"
"github.com/stretchr/testify/assert"
)

func setupStackPackDeleteVersionCmd(t *testing.T) (*di.MockDeps, *cobra.Command) {
cli := di.NewMockDeps(t)
cmd := StackpackDeleteVersionCommand(&cli.Deps)
return &cli, cmd
}

func TestStackpackDeleteVersionPrintToConsole(t *testing.T) {
cli, cmd := setupStackPackDeleteVersionCmd(t)
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "delete-version", "--name", "kubernetes", "--version", "1.0.0")

expectedSuccessMessage := []string{"Successfully deleted version 1.0.0 of StackPack kubernetes"}
assert.True(t, cli.MockPrinter.HasNonJsonCalls)
assert.Equal(t, expectedSuccessMessage, *cli.MockPrinter.SuccessCalls)

assert.Equal(t, 1, len(*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionCalls))
call := (*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionCalls)[0]
assert.Equal(t, "kubernetes", call.PstackPackName)
assert.Equal(t, "1.0.0", call.Pversion)
}

func TestStackpackDeleteVersionPrintToJson(t *testing.T) {
cli, cmd := setupStackPackDeleteVersionCmd(t)
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "delete-version", "--name", "kubernetes", "--version", "1.0.0", "-o", "json")

expectedJsonCalls := []map[string]interface{}{{
"deleted": "1.0.0",
}}
assert.False(t, cli.MockPrinter.HasNonJsonCalls)
assert.Equal(t, expectedJsonCalls, *cli.MockPrinter.PrintJsonCalls)
}
112 changes: 112 additions & 0 deletions cmd/stackpack/stackpack_delete_versions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package stackpack

import (
"fmt"
"strings"

"github.com/spf13/cobra"
"github.com/stackvista/stackstate-cli/generated/stackstate_api"
"github.com/stackvista/stackstate-cli/internal/common"
"github.com/stackvista/stackstate-cli/internal/di"
"github.com/stackvista/stackstate-cli/internal/printer"
)

const (
FromFlag = "from"
ToFlag = "to"
)

type DeleteVersionsArgs struct {
Name string
From string
To string
All bool
DevOnly bool
}

func StackpackDeleteVersionsCommand(cli *di.Deps) *cobra.Command {
args := &DeleteVersionsArgs{}
cmd := &cobra.Command{
Use: "delete-versions",
Short: "Delete multiple versions of a StackPack",
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.",
Example: `# delete all versions up to and including 1.5.0
sts stackpack delete-versions --name kubernetes --to 1.5.0

# delete versions in a specific range
sts stackpack delete-versions --name kubernetes --from 1.0.0 --to 1.5.0

# delete all development (SNAPSHOT) versions only
sts stackpack delete-versions --name kubernetes --all --dev-only`,
RunE: cli.CmdRunEWithApi(RunStackpackDeleteVersionsCommand(args)),
}
common.AddRequiredNameFlagVar(cmd, &args.Name, "Name of the StackPack")
cmd.Flags().StringVar(&args.From, FromFlag, "", "Inclusive lower bound: delete versions >= this version")
cmd.Flags().StringVar(&args.To, ToFlag, "", "Inclusive upper bound: delete versions <= this version")
cmd.Flags().BoolVar(&args.All, AllFlag, false, "Delete all versions (cannot be combined with --from or --to)")
cmd.Flags().BoolVar(&args.DevOnly, DevOnlyFlag, false, "Restrict to development versions only (e.g. SNAPSHOT)")
return cmd
}

func RunStackpackDeleteVersionsCommand(args *DeleteVersionsArgs) di.CmdWithApiFn {
return func(
cmd *cobra.Command,
cli *di.Deps,
api *stackstate_api.APIClient,
serverInfo *stackstate_api.ServerInfo,
) common.CLIError {
if !args.All && args.From == "" && args.To == "" {
return common.NewCLIArgParseError(fmt.Errorf("at least one of --all, --from, or --to must be specified"))
}
if args.All && (args.From != "" || args.To != "") {
return common.NewCLIArgParseError(fmt.Errorf("--all cannot be combined with --from or --to"))
}

req := api.StackpackApi.StackPackDeleteVersions(cli.Context, args.Name)
if args.From != "" {
req = req.From(args.From)
}
if args.To != "" {
req = req.To(args.To)
}
if args.All {
req = req.All(true)
}
if args.DevOnly {
req = req.Dev(true)
}

result, resp, err := req.Execute()
if err != nil {
return common.NewResponseError(err, resp)
}

if cli.IsJson() {
cli.Printer.PrintJson(map[string]interface{}{
"deleted": result.Deleted,
"skippedInUse": result.SkippedInUse,
})
} else {
if len(result.Deleted) > 0 {
cli.Printer.Success(fmt.Sprintf("Deleted versions: %s", strings.Join(result.Deleted, ", ")))
}
if len(result.SkippedInUse) > 0 {
cli.Printer.Table(printer.TableData{
Header: []string{"skipped (in use)"},
Data: func() [][]interface{} {
rows := make([][]interface{}, 0, len(result.SkippedInUse))
for _, v := range result.SkippedInUse {
rows = append(rows, []interface{}{v})
}
return rows
}(),
})
}
if len(result.Deleted) == 0 && len(result.SkippedInUse) == 0 {
cli.Printer.Success("No versions matched the specified criteria")
}
}

return nil
}
}
108 changes: 108 additions & 0 deletions cmd/stackpack/stackpack_delete_versions_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package stackpack

import (
"testing"

"github.com/spf13/cobra"
"github.com/stackvista/stackstate-cli/generated/stackstate_api"
"github.com/stackvista/stackstate-cli/internal/di"
"github.com/stretchr/testify/assert"
)

func setupStackPackDeleteVersionsCmd(t *testing.T) (*di.MockDeps, *cobra.Command) {
cli := di.NewMockDeps(t)
cmd := StackpackDeleteVersionsCommand(&cli.Deps)
cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsResponse.Result = stackstate_api.DeleteVersionsResult{
Deleted: []string{"1.0.0", "1.1.0"},
SkippedInUse: []string{"1.2.0"},
}
return &cli, cmd
}

func TestStackpackDeleteVersionsWithTo(t *testing.T) {
cli, cmd := setupStackPackDeleteVersionsCmd(t)
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "delete-versions", "--name", "kubernetes", "--to", "1.5.0")

assert.True(t, cli.MockPrinter.HasNonJsonCalls)
assert.Equal(t, []string{"Deleted versions: 1.0.0, 1.1.0"}, *cli.MockPrinter.SuccessCalls)

assert.Equal(t, 1, len(*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsCalls))
call := (*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsCalls)[0]
assert.Equal(t, "kubernetes", call.PstackPackName)
assert.Nil(t, call.Pfrom)
assert.Equal(t, "1.5.0", *call.Pto)
assert.Nil(t, call.Pall)
assert.Nil(t, call.Pdev)
}

func TestStackpackDeleteVersionsWithRange(t *testing.T) {
cli, cmd := setupStackPackDeleteVersionsCmd(t)
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "delete-versions", "--name", "kubernetes", "--from", "1.0.0", "--to", "1.5.0")

assert.Equal(t, 1, len(*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsCalls))
call := (*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsCalls)[0]
assert.Equal(t, "kubernetes", call.PstackPackName)
assert.Equal(t, "1.0.0", *call.Pfrom)
assert.Equal(t, "1.5.0", *call.Pto)
assert.Nil(t, call.Pall)
assert.Nil(t, call.Pdev)
}

func TestStackpackDeleteVersionsWithAll(t *testing.T) {
cli, cmd := setupStackPackDeleteVersionsCmd(t)
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "delete-versions", "--name", "kubernetes", "--all")

assert.Equal(t, 1, len(*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsCalls))
call := (*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsCalls)[0]
assert.Equal(t, "kubernetes", call.PstackPackName)
assert.Nil(t, call.Pfrom)
assert.Nil(t, call.Pto)
assert.Equal(t, true, *call.Pall)
assert.Nil(t, call.Pdev)
}

func TestStackpackDeleteVersionsWithAllAndDevOnly(t *testing.T) {
cli, cmd := setupStackPackDeleteVersionsCmd(t)
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "delete-versions", "--name", "kubernetes", "--all", "--dev-only")

assert.Equal(t, 1, len(*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsCalls))
call := (*cli.MockClient.ApiMocks.StackpackApi.StackPackDeleteVersionsCalls)[0]
assert.Equal(t, "kubernetes", call.PstackPackName)
assert.Nil(t, call.Pfrom)
assert.Nil(t, call.Pto)
assert.Equal(t, true, *call.Pall)
assert.Equal(t, true, *call.Pdev)
}

func TestStackpackDeleteVersionsPrintToJson(t *testing.T) {
cli, cmd := setupStackPackDeleteVersionsCmd(t)
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "delete-versions", "--name", "kubernetes", "--to", "2.0.0", "-o", "json")

expectedJsonCalls := []map[string]interface{}{{
"deleted": []string{"1.0.0", "1.1.0"},
"skippedInUse": []string{"1.2.0"},
}}
assert.False(t, cli.MockPrinter.HasNonJsonCalls)
assert.Equal(t, expectedJsonCalls, *cli.MockPrinter.PrintJsonCalls)
}

func TestStackpackDeleteVersionsNoFlags(t *testing.T) {
cli := di.NewMockDeps(t)
cmd := StackpackDeleteVersionsCommand(&cli.Deps)
_, err := di.ExecuteCommandWithContext(&cli.Deps, cmd, "delete-versions", "--name", "kubernetes")
assert.Error(t, err)
}

func TestStackpackDeleteVersionsAllWithFrom(t *testing.T) {
cli := di.NewMockDeps(t)
cmd := StackpackDeleteVersionsCommand(&cli.Deps)
_, err := di.ExecuteCommandWithContext(&cli.Deps, cmd, "delete-versions", "--name", "kubernetes", "--all", "--from", "1.0.0")
assert.Error(t, err)
}

func TestStackpackDeleteVersionsAllWithTo(t *testing.T) {
cli := di.NewMockDeps(t)
cmd := StackpackDeleteVersionsCommand(&cli.Deps)
_, err := di.ExecuteCommandWithContext(&cli.Deps, cmd, "delete-versions", "--name", "kubernetes", "--all", "--to", "1.5.0")
assert.Error(t, err)
}
Loading
Loading