Skip to content
Open
Show file tree
Hide file tree
Changes from all 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