diff --git a/cmd/otelcomponentmapping/otelcomponentmapping_delete.go b/cmd/otelcomponentmapping/otelcomponentmapping_delete.go index 006b8805..45d988af 100644 --- a/cmd/otelcomponentmapping/otelcomponentmapping_delete.go +++ b/cmd/otelcomponentmapping/otelcomponentmapping_delete.go @@ -18,7 +18,7 @@ func OtelComponentMappingDeleteCommand(deps *di.Deps) *cobra.Command { cmd := &cobra.Command{ Use: "delete", Short: "Delete an OTel Component Mapping by identifier (URN)", - Long: "Delete an OTel Component Mapping by identifier (URN)", + Long: "Delete an OTel Component Mapping by identifier (URN).", Example: `# delete a component mapping by identifier sts otel-component-mapping delete --identifier urn:stackpack:stackpack-name:shared:otel-component-mapping:service`, RunE: deps.CmdRunEWithApi(RunDeleteComponentMappingCommand(args)), diff --git a/cmd/stackpack.go b/cmd/stackpack.go index a3db63cd..9201317f 100644 --- a/cmd/stackpack.go +++ b/cmd/stackpack.go @@ -1,17 +1,11 @@ package cmd import ( - "os" - "github.com/spf13/cobra" "github.com/stackvista/stackstate-cli/cmd/stackpack" "github.com/stackvista/stackstate-cli/internal/di" ) -const ( - experimentalStackpackEnvVar = "STS_EXPERIMENTAL_STACKPACKS" -) - func StackPackCommand(cli *di.Deps) *cobra.Command { cmd := &cobra.Command{ Use: "stackpack", @@ -31,14 +25,10 @@ func StackPackCommand(cli *di.Deps) *cobra.Command { cmd.AddCommand(stackpack.StackpackListVersionsCommand(cli)) cmd.AddCommand(stackpack.StackpackDeleteVersionCommand(cli)) cmd.AddCommand(stackpack.StackpackDeleteVersionsCommand(cli)) - - // The not-production-ready commands - if os.Getenv(experimentalStackpackEnvVar) != "" { - cmd.AddCommand(stackpack.StackpackScaffoldCommand(cli)) - cmd.AddCommand(stackpack.StackpackPackageCommand(cli)) - cmd.AddCommand(stackpack.StackpackTestDeployCommand(cli)) - cmd.AddCommand(stackpack.StackpackValidateCommand(cli)) - } + cmd.AddCommand(stackpack.StackpackScaffoldCommand(cli)) + cmd.AddCommand(stackpack.StackpackPackageCommand(cli)) + cmd.AddCommand(stackpack.StackpackTestDeployCommand(cli)) + cmd.AddCommand(stackpack.StackpackValidateCommand(cli)) return cmd } diff --git a/cmd/stackpack/stackpack_package.go b/cmd/stackpack/stackpack_package.go index c1861fd6..85d69ec7 100644 --- a/cmd/stackpack/stackpack_package.go +++ b/cmd/stackpack/stackpack_package.go @@ -109,8 +109,8 @@ sts stackpack package --force`, RunE: cli.CmdRunE(RunStackpackPackageCommand(args)), } - cmd.Flags().StringVarP(&args.StackpackDir, "stackpack-directory", "d", "", "Path to stackpack directory (defaults to current directory)") - cmd.Flags().StringVarP(&args.ArchiveFile, "archive-file", "f", "", "Path to the .sts file to create (defaults to -.sts in current directory)") + cmd.Flags().StringVarP(&args.StackpackDir, "directory", "d", "", "Path to stackpack directory (defaults to current directory)") + cmd.Flags().StringVarP(&args.ArchiveFile, "file", "f", "", "Path to the .sts file to create (defaults to -.sts in current directory)") cmd.Flags().BoolVar(&args.Force, "force", false, "Overwrite existing .sts file without prompting") return cmd diff --git a/cmd/stackpack/stackpack_test_deploy_cmd.go b/cmd/stackpack/stackpack_test_deploy.go similarity index 80% rename from cmd/stackpack/stackpack_test_deploy_cmd.go rename to cmd/stackpack/stackpack_test_deploy.go index 3f19243f..dd9ba478 100644 --- a/cmd/stackpack/stackpack_test_deploy_cmd.go +++ b/cmd/stackpack/stackpack_test_deploy.go @@ -15,6 +15,7 @@ import ( "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 ( @@ -59,7 +60,7 @@ sts stackpack test-deploy -d ./my-stackpack --yes`, RunE: cli.CmdRunEWithApi(RunStackpackTestDeployCommand(args)), } - cmd.Flags().StringVarP(&args.StackpackDir, "stackpack-directory", "d", "", "Path to stackpack directory (defaults to current directory)") + cmd.Flags().StringVarP(&args.StackpackDir, "directory", "d", "", "Path to stackpack directory (defaults to current directory)") cmd.Flags().StringToStringVarP(&args.Params, ParameterFlag, "p", args.Params, "List of parameters of the form \"key=value\"") cmd.Flags().BoolVarP(&args.Yes, "yes", "y", false, "Skip confirmation prompt before upload") @@ -76,11 +77,6 @@ func RunStackpackTestDeployCommand(args *TestDeployArgs) di.CmdWithApiFn { api *stackstate_api.APIClient, serverInfo *stackstate_api.ServerInfo, ) common.CLIError { - // Warn if JSON output is requested - not meaningful for test-deploy command - if cli.IsJson() { - cli.Printer.PrintLn("Warning: JSON output format is not meaningful for the test-deploy command, proceeding with text output") - } - // Set default stackpack directory if args.StackpackDir == "" { currentDir, err := os.Getwd() @@ -98,12 +94,12 @@ func RunStackpackTestDeployCommand(args *TestDeployArgs) di.CmdWithApiFn { return common.NewRuntimeError(fmt.Errorf("failed to parse %s: %w", stackpackConfigFile, err)) } - cli.Printer.Success("Starting stackpack test-deploy sequence...") - cli.Printer.PrintLn(fmt.Sprintf(" Stackpack: %s (current version: %s)", originalInfo.Name, originalInfo.Version)) - cli.Printer.PrintLn("") + printSuccess(cli, "Starting stackpack test-deploy sequence...") + printMsg(cli, fmt.Sprintf(" Stackpack: %s (current version: %s)", originalInfo.Name, originalInfo.Version)) + printMsg(cli, "") // Step 1: Check installed version and determine base version for snapshot - cli.Printer.PrintLn("Step 1/5: Checking installed version...") + printMsg(cli, "Step 1/5: Checking installed version...") installedVersion, err := getInstalledStackpackVersion(cli, api, originalInfo.Name) if err != nil { return common.NewRuntimeError(fmt.Errorf("failed to check installed stackpack version: %w", err)) @@ -111,7 +107,7 @@ func RunStackpackTestDeployCommand(args *TestDeployArgs) di.CmdWithApiFn { baseVersionForSnapshot := originalInfo.Version if installedVersion != "" { - cli.Printer.PrintLn(fmt.Sprintf(" Found installed version: %s", installedVersion)) + printMsg(cli, fmt.Sprintf(" Found installed version: %s", installedVersion)) // Compare base versions (strip cli-test suffix from installed version for comparison) installedBaseVersion := installedVersion @@ -129,15 +125,15 @@ func RunStackpackTestDeployCommand(args *TestDeployArgs) di.CmdWithApiFn { baseComparison := compareVersions(installedBaseVersion, originalInfo.Version) if baseComparison > 0 || (baseComparison == 0 && strings.Contains(installedVersion, "-cli-test.")) { baseVersionForSnapshot = installedVersion - cli.Printer.PrintLn(fmt.Sprintf(" Using installed version as base: %s", baseVersionForSnapshot)) + printMsg(cli, fmt.Sprintf(" Using installed version as base: %s", baseVersionForSnapshot)) } else if baseComparison < 0 { - cli.Printer.PrintLn(fmt.Sprintf(" Using local version as base (higher than installed): %s", baseVersionForSnapshot)) + printMsg(cli, fmt.Sprintf(" Using local version as base (higher than installed): %s", baseVersionForSnapshot)) } } // Step 2: Create temporary directory and copy stackpack - cli.Printer.PrintLn("") - cli.Printer.PrintLn("Step 2/5: Creating temporary copy for testing...") + printMsg(cli, "") + printMsg(cli, "Step 2/5: Creating temporary copy for testing...") tempDir, err := os.MkdirTemp("", "stackpack-test-*") if err != nil { @@ -147,7 +143,7 @@ func RunStackpackTestDeployCommand(args *TestDeployArgs) di.CmdWithApiFn { // Ensure cleanup of temporary directory defer func() { if removeErr := os.RemoveAll(tempDir); removeErr != nil { - cli.Printer.PrintLn(fmt.Sprintf("Warning: Failed to cleanup temporary directory: %v", removeErr)) + printMsg(cli, fmt.Sprintf("Warning: Failed to cleanup temporary directory: %v", removeErr)) } }() @@ -155,22 +151,22 @@ func RunStackpackTestDeployCommand(args *TestDeployArgs) di.CmdWithApiFn { if err := copyDirectory(args.StackpackDir, tempStackpackDir); err != nil { return common.NewRuntimeError(fmt.Errorf("failed to copy stackpack to temporary directory: %w", err)) } - cli.Printer.Success("Temporary copy created") + printSuccess(cli, "Temporary copy created") // Step 3: Update version in temporary copy - cli.Printer.PrintLn("") - cli.Printer.PrintLn("Step 3/5: Bumping version for testing...") + printMsg(cli, "") + printMsg(cli, "Step 3/5: Bumping version for testing...") tempConfigPath := filepath.Join(tempStackpackDir, stackpackConfigFile) newVersion, err := bumpSnapshotVersionWithBase(tempConfigPath, baseVersionForSnapshot) if err != nil { return common.NewRuntimeError(fmt.Errorf("failed to bump version: %w", err)) } - cli.Printer.Success(fmt.Sprintf("Version bumped to: %s", newVersion)) + printSuccess(cli, fmt.Sprintf("Version bumped to: %s", newVersion)) // Step 4: Package stackpack from temporary directory - cli.Printer.PrintLn("") - cli.Printer.PrintLn("Step 4/5: Packaging stackpack...") + printMsg(cli, "") + printMsg(cli, "Step 4/5: Packaging stackpack...") packageArgs := &PackageArgs{ StackpackDir: tempStackpackDir, // Use temporary directory Force: true, // Always overwrite for testing @@ -183,19 +179,19 @@ func RunStackpackTestDeployCommand(args *TestDeployArgs) di.CmdWithApiFn { if err := runPackageStep(cli, packageArgs); err != nil { return err } - cli.Printer.Success("Stackpack packaged successfully") + printSuccess(cli, "Stackpack packaged successfully") // Step 5: Confirm upload (if needed) and execute upload/install workflow - if !args.Yes { - cli.Printer.PrintLn("") + if !args.Yes && !cli.IsJson() { + printMsg(cli, "") if !confirmUpload(cli, packageArgs.ArchiveFile) { return common.NewRuntimeError(fmt.Errorf("upload cancelled by user")) } } // Upload stackpack - cli.Printer.PrintLn("") - cli.Printer.PrintLn("Step 5/5: Uploading and installing/upgrading stackpack...") + printMsg(cli, "") + printMsg(cli, "Step 5/5: Uploading and installing/upgrading stackpack...") uploadArgs := &UploadArgs{ FilePath: packageArgs.ArchiveFile, } @@ -203,7 +199,7 @@ func RunStackpackTestDeployCommand(args *TestDeployArgs) di.CmdWithApiFn { if err := runUploadStep(cli, api, serverInfo, uploadArgs); err != nil { return err } - cli.Printer.Success("Stackpack uploaded successfully") + printSuccess(cli, "Stackpack uploaded successfully") // Install or upgrade stackpack based on installation status if installedVersion != "" { @@ -217,7 +213,7 @@ func RunStackpackTestDeployCommand(args *TestDeployArgs) di.CmdWithApiFn { if err := runUpgradeStep(cli, api, serverInfo, upgradeArgs); err != nil { return err } - cli.Printer.Success("Stackpack upgraded successfully") + printSuccess(cli, "Stackpack upgraded successfully") } else { installArgs := &InstallArgs{ Name: originalInfo.Name, @@ -230,15 +226,20 @@ func RunStackpackTestDeployCommand(args *TestDeployArgs) di.CmdWithApiFn { if err := runInstallStep(cli, api, serverInfo, installArgs); err != nil { return err } - cli.Printer.Success("Stackpack installed successfully") + printSuccess(cli, "Stackpack installed successfully") } - cli.Printer.PrintLn("") - cli.Printer.Success("🎉 Test-deploy sequence completed successfully!") + printMsg(cli, "") + printSuccess(cli, "🎉 Test-deploy sequence completed successfully!") // Clean up .sts file if err := os.Remove(packageArgs.ArchiveFile); err != nil { - cli.Printer.PrintLn(fmt.Sprintf("Note: Could not clean up .sts file %s: %v", packageArgs.ArchiveFile, err)) + printMsg(cli, fmt.Sprintf("Note: Could not clean up .sts file %s: %v", packageArgs.ArchiveFile, err)) + } else if cli.IsJson() { + cli.Printer.PrintJson(map[string]interface{}{ + "stackpack": originalInfo.Name, + "version": newVersion, + }) } return nil @@ -315,8 +316,8 @@ func confirmUpload(cli *di.Deps, zipFile string) bool { serverURL = cli.CurrentContext.URL } - cli.Printer.PrintLn(fmt.Sprintf("⚠️ This will upload '%s' to SUSE Observability server:", filepath.Base(zipFile))) - cli.Printer.PrintLn(fmt.Sprintf(" Server: %s", serverURL)) + printMsg(cli, fmt.Sprintf("⚠️ This will upload '%s' to SUSE Observability server:", filepath.Base(zipFile))) + printMsg(cli, fmt.Sprintf(" Server: %s", serverURL)) fmt.Print(" Continue? (y/N): ") reader := bufio.NewReader(os.Stdin) @@ -332,33 +333,50 @@ func confirmUpload(cli *di.Deps, zipFile string) bool { // runPackageStep executes the package command logic func runPackageStep(cli *di.Deps, args *PackageArgs) common.CLIError { // Reuse the existing package command logic - packageCmd := &cobra.Command{} - packageFn := RunStackpackPackageCommand(args) - return packageFn(cli, packageCmd) + return runCmd(cli, func(ctx *di.Deps) common.CLIError { + packageCmd := &cobra.Command{} + packageFn := RunStackpackPackageCommand(args) + return packageFn(ctx, packageCmd) + }) } // runUploadStep executes the upload command logic func runUploadStep(cli *di.Deps, api *stackstate_api.APIClient, serverInfo *stackstate_api.ServerInfo, args *UploadArgs) common.CLIError { - // Reuse the existing upload command logic - uploadCmd := &cobra.Command{} - uploadFn := RunStackpackUploadCommand(args) - return uploadFn(uploadCmd, cli, api, serverInfo) + return runCmd(cli, func(ctx *di.Deps) common.CLIError { + // Reuse the existing upload command logic + uploadCmd := &cobra.Command{} + uploadFn := RunStackpackUploadCommand(args) + return uploadFn(uploadCmd, ctx, api, serverInfo) + }) } // runInstallStep executes the install command logic func runInstallStep(cli *di.Deps, api *stackstate_api.APIClient, serverInfo *stackstate_api.ServerInfo, args *InstallArgs) common.CLIError { - // Reuse the existing install command logic - installCmd := &cobra.Command{} - installFn := RunStackpackInstallCommand(args) - return installFn(installCmd, cli, api, serverInfo) + return runCmd(cli, func(ctx *di.Deps) common.CLIError { + // Reuse the existing install command logic + installCmd := &cobra.Command{} + installFn := RunStackpackInstallCommand(args) + return installFn(installCmd, ctx, api, serverInfo) + }) } // runUpgradeStep executes the upgrade command logic func runUpgradeStep(cli *di.Deps, api *stackstate_api.APIClient, serverInfo *stackstate_api.ServerInfo, args *UpgradeArgs) common.CLIError { - // Reuse the existing upgrade command logic - upgradeCmd := &cobra.Command{} - upgradeFn := RunStackpackUpgradeCommand(args) - return upgradeFn(upgradeCmd, cli, api, serverInfo) + return runCmd(cli, func(ctx *di.Deps) common.CLIError { + // Reuse the existing upgrade command logic + upgradeCmd := &cobra.Command{} + upgradeFn := RunStackpackUpgradeCommand(args) + return upgradeFn(upgradeCmd, ctx, api, serverInfo) + }) +} + +func runCmd(cli *di.Deps, f func(ctx *di.Deps) common.CLIError) common.CLIError { + oldPr := cli.Printer + pr := printer.NewMockPrinter(nil) + cli.Printer = &pr + err := f(cli) + cli.Printer = oldPr + return err } // getInstalledStackpackVersion checks if a stackpack is installed and returns its version @@ -489,3 +507,15 @@ func updateVersionInYaml(configPath, newVersion string) error { return nil } + +func printMsg(cli *di.Deps, msg string) { + if !cli.IsJson() { + cli.Printer.PrintLn(msg) + } +} + +func printSuccess(cli *di.Deps, msg string) { + if !cli.IsJson() { + cli.Printer.Success(msg) + } +} diff --git a/cmd/stackpack/stackpack_test_deploy_cmd_test.go b/cmd/stackpack/stackpack_test_deploy_test.go similarity index 99% rename from cmd/stackpack/stackpack_test_deploy_cmd_test.go rename to cmd/stackpack/stackpack_test_deploy_test.go index 16e42269..b832c7b5 100644 --- a/cmd/stackpack/stackpack_test_deploy_cmd_test.go +++ b/cmd/stackpack/stackpack_test_deploy_test.go @@ -33,7 +33,7 @@ func TestStackpackTestDeployCommand_FlagsAndStructure(t *testing.T) { // Test flags exist flags := cmd.Flags() - stackpackDirFlag := flags.Lookup("stackpack-directory") + stackpackDirFlag := flags.Lookup("directory") require.NotNil(t, stackpackDirFlag) assert.Equal(t, "d", stackpackDirFlag.Shorthand) diff --git a/cmd/stackpack/stackpack_validate.go b/cmd/stackpack/stackpack_validate.go index 7eef1b5c..5924c398 100644 --- a/cmd/stackpack/stackpack_validate.go +++ b/cmd/stackpack/stackpack_validate.go @@ -33,19 +33,17 @@ This command validates a stackpack by uploading it to the server. - If a directory is provided, it is automatically packaged into a .sts file before uploading - If a .sts file is provided, it is uploaded directly -Exactly one of --stackpack-directory or --stackpack-file must be specified. - -This command is experimental and requires STS_EXPERIMENTAL_STACKPACKS environment variable to be set.`, +Exactly one of --directory or --file must be specified.`, Example: `# Validate a stackpack directory (automatically packaged) -sts stackpack validate --stackpack-directory ./my-stackpack +sts stackpack validate --directory ./my-stackpack # Validate a pre-packaged .sts file -sts stackpack validate --stackpack-file ./my-stackpack.sts`, +sts stackpack validate --file ./my-stackpack.sts`, RunE: cli.CmdRunEWithApi(RunStackpackValidateCommand(args)), } - cmd.Flags().StringVarP(&args.StackpackDir, "stackpack-directory", "d", "", "Path to stackpack directory") - cmd.Flags().StringVarP(&args.StackpackFile, "stackpack-file", "f", "", "Path to .sts file") + cmd.Flags().StringVarP(&args.StackpackDir, "directory", "d", "", "Path to stackpack directory") + cmd.Flags().StringVarP(&args.StackpackFile, "file", "f", "", "Path to .sts file") return cmd } @@ -61,7 +59,7 @@ func RunStackpackValidateCommand(args *ValidateArgs) di.CmdWithApiFn { // Validate exactly one of directory or file is set if (args.StackpackDir == "" && args.StackpackFile == "") || (args.StackpackDir != "" && args.StackpackFile != "") { - return common.NewCLIArgParseError(fmt.Errorf("exactly one of --stackpack-directory or --stackpack-file must be specified")) + return common.NewCLIArgParseError(fmt.Errorf("exactly one of --directory or --file must be specified")) } // Prepare file to validate - if directory is provided, package it first diff --git a/cmd/stackpack/stackpack_validate_test.go b/cmd/stackpack/stackpack_validate_test.go index 0ff0a068..f65bdbd0 100644 --- a/cmd/stackpack/stackpack_validate_test.go +++ b/cmd/stackpack/stackpack_validate_test.go @@ -61,7 +61,7 @@ func TestValidate_WithDirectory_AutoPackages(t *testing.T) { require.NoError(t, os.MkdirAll(stackpackDir, 0755)) createTestStackpackDir(t, stackpackDir, "test-stackpack", "1.0.0") - _, err = di.ExecuteCommandWithContext(&cli.Deps, cmd, "--stackpack-directory", stackpackDir) + _, err = di.ExecuteCommandWithContext(&cli.Deps, cmd, "--directory", stackpackDir) require.NoError(t, err) // Verify success message @@ -81,7 +81,7 @@ func TestValidate_WithDirectory_InvalidStackpack(t *testing.T) { stackpackDir := filepath.Join(tempDir, "invalid-stackpack") require.NoError(t, os.MkdirAll(stackpackDir, 0755)) - _, err = di.ExecuteCommandWithContext(&cli.Deps, cmd, "--stackpack-directory", stackpackDir) + _, err = di.ExecuteCommandWithContext(&cli.Deps, cmd, "--directory", stackpackDir) require.Error(t, err) assert.Contains(t, err.Error(), "required stackpack item not found") } @@ -98,7 +98,7 @@ func TestValidate_WithDirectory_MissingStackpackYaml(t *testing.T) { require.NoError(t, os.MkdirAll(filepath.Join(stackpackDir, "resources"), 0755)) require.NoError(t, os.WriteFile(filepath.Join(stackpackDir, "README.md"), []byte("test"), 0644)) - _, err = di.ExecuteCommandWithContext(&cli.Deps, cmd, "--stackpack-directory", stackpackDir) + _, err = di.ExecuteCommandWithContext(&cli.Deps, cmd, "--directory", stackpackDir) require.Error(t, err) assert.Contains(t, err.Error(), "required stackpack item not found") } @@ -114,7 +114,7 @@ func TestValidate_WithPrePackagedFile(t *testing.T) { stackpackFile := filepath.Join(tempDir, "test.sts") require.NoError(t, os.WriteFile(stackpackFile, []byte("test stackpack content"), 0644)) - _, err = di.ExecuteCommandWithContext(&cli.Deps, cmd, "--stackpack-file", stackpackFile) + _, err = di.ExecuteCommandWithContext(&cli.Deps, cmd, "--file", stackpackFile) require.NoError(t, err) // Verify success message @@ -133,7 +133,7 @@ func TestValidate_JSONOutput(t *testing.T) { stackpackFile := filepath.Join(tempDir, "test.sts") require.NoError(t, os.WriteFile(stackpackFile, []byte("test content"), 0644)) - _, err = di.ExecuteCommandWithContext(&cli.Deps, cmd, "--stackpack-file", stackpackFile, "-o", "json") + _, err = di.ExecuteCommandWithContext(&cli.Deps, cmd, "--file", stackpackFile, "-o", "json") require.NoError(t, err) // Verify JSON was called @@ -174,7 +174,7 @@ func TestValidate_MutuallyExclusive(t *testing.T) { func TestValidate_NonexistentFile(t *testing.T) { cli, cmd := setupValidateCmd(t) - _, err := di.ExecuteCommandWithContext(&cli.Deps, cmd, "--stackpack-file", "/nonexistent/path/file.sts") + _, err := di.ExecuteCommandWithContext(&cli.Deps, cmd, "--file", "/nonexistent/path/file.sts") require.Error(t, err) assert.Contains(t, err.Error(), "failed to access stackpack file") } @@ -196,7 +196,7 @@ func TestValidate_WithDirectory_IncludingOptionalItems(t *testing.T) { require.NoError(t, os.MkdirAll(filepath.Join(stackpackDir, "includes"), 0755)) require.NoError(t, os.WriteFile(filepath.Join(stackpackDir, "includes", "include.txt"), []byte("include data"), 0644)) - _, err = di.ExecuteCommandWithContext(&cli.Deps, cmd, "--stackpack-directory", stackpackDir) + _, err = di.ExecuteCommandWithContext(&cli.Deps, cmd, "--directory", stackpackDir) require.NoError(t, err) // Verify success message @@ -208,7 +208,7 @@ func TestValidate_WithDirectory_IncludingOptionalItems(t *testing.T) { func TestValidate_NonexistentDirectory(t *testing.T) { cli, cmd := setupValidateCmd(t) - _, err := di.ExecuteCommandWithContext(&cli.Deps, cmd, "--stackpack-directory", "/nonexistent/stackpack/dir") + _, err := di.ExecuteCommandWithContext(&cli.Deps, cmd, "--directory", "/nonexistent/stackpack/dir") require.Error(t, err) assert.Contains(t, err.Error(), "required stackpack item not found") } diff --git a/cmd/stackpack_test.go b/cmd/stackpack_test.go index 3a3e7daa..c092872c 100644 --- a/cmd/stackpack_test.go +++ b/cmd/stackpack_test.go @@ -1,91 +1,13 @@ package cmd import ( - "os" "testing" "github.com/stackvista/stackstate-cli/internal/di" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) -func TestStackPackCommand_FeatureGating(t *testing.T) { - tests := []struct { - name string - envVarValue string - expectExperimentalCommands bool - description string - }{ - { - name: "experimental commands hidden by default", - envVarValue: "", - expectExperimentalCommands: false, - description: "When environment variable is not set, experimental commands should be hidden", - }, - { - name: "experimental commands visible when env var is set to 1", - envVarValue: "1", - expectExperimentalCommands: true, - description: "When environment variable is set to '1', experimental commands should be visible", - }, - { - name: "experimental commands visible when env var is set to any value", - envVarValue: "true", - expectExperimentalCommands: true, - description: "When environment variable is set to any non-empty value, experimental commands should be visible", - }, - { - name: "experimental commands visible when env var is set to enabled", - envVarValue: "enabled", - expectExperimentalCommands: true, - description: "When environment variable is set to 'enabled', experimental commands should be visible", - }, - } - - experimentalCommands := []string{"scaffold", "package", "test-deploy"} - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Store original environment value to restore later - originalValue := os.Getenv(experimentalStackpackEnvVar) - defer func() { - if originalValue == "" { - os.Unsetenv(experimentalStackpackEnvVar) - } else { - os.Setenv(experimentalStackpackEnvVar, originalValue) - } - }() - - // Set the environment variable for this test - if tt.envVarValue == "" { - os.Unsetenv(experimentalStackpackEnvVar) - } else { - err := os.Setenv(experimentalStackpackEnvVar, tt.envVarValue) - require.NoError(t, err) - } - - // Create the command - cli := di.NewMockDeps(t) - cmd := StackPackCommand(&cli.Deps) - - // Check each experimental command - for _, cmdName := range experimentalCommands { - foundCmd, _, err := cmd.Find([]string{cmdName}) - - if tt.expectExperimentalCommands { - assert.NoError(t, err, tt.description+" (command: %s)", cmdName) - assert.NotNil(t, foundCmd, tt.description+" (command: %s)", cmdName) - assert.Equal(t, cmdName, foundCmd.Use, tt.description+" (command: %s)", cmdName) - } else { - assert.Error(t, err, tt.description+" (command: %s)", cmdName) - assert.Contains(t, err.Error(), "unknown command", tt.description+" (command: %s)", cmdName) - } - } - }) - } -} - -func TestStackPackCommand_AlwaysPresentCommands(t *testing.T) { +func TestStackPackCommand_EnabledCommands(t *testing.T) { // Ensure that other commands are always present regardless of environment variable cli := di.NewMockDeps(t) cmd := StackPackCommand(&cli.Deps) @@ -100,10 +22,13 @@ func TestStackPackCommand_AlwaysPresentCommands(t *testing.T) { "upgrade", "confirm-manual-steps", "describe", + "scaffold", + "package", + "test-deploy", } for _, cmdName := range expectedCommands { - t.Run("command_"+cmdName+"_always_present", func(t *testing.T) { + t.Run("command_"+cmdName+"_enabled", func(t *testing.T) { foundCmd, _, err := cmd.Find([]string{cmdName}) assert.NoError(t, err, "Command %s should always be present", cmdName) assert.NotNil(t, foundCmd, "Command %s should always be present", cmdName) diff --git a/cmd/sts.go b/cmd/sts.go index e5788fdf..ab107f1c 100644 --- a/cmd/sts.go +++ b/cmd/sts.go @@ -1,8 +1,6 @@ package cmd import ( - "os" - "github.com/spf13/cobra" "github.com/stackvista/stackstate-cli/internal/di" ) @@ -34,12 +32,8 @@ func STSCommand(cli *di.Deps) *cobra.Command { cmd.AddCommand(UserSessionCommand(cli)) cmd.AddCommand(DashboardCommand(cli)) cmd.AddCommand(TopologyCommand(cli)) - - // Experimental commands for otel mapping - if os.Getenv("STS_EXPERIMENTAL_STACKPACKS") != "" { - cmd.AddCommand(OtelComponentMappingCommand(cli)) - cmd.AddCommand(OtelRelationMappingCommand(cli)) - } + cmd.AddCommand(OtelComponentMappingCommand(cli)) + cmd.AddCommand(OtelRelationMappingCommand(cli)) return cmd } diff --git a/cmd/sts_test.go b/cmd/sts_test.go index 699880cb..5ca7963f 100644 --- a/cmd/sts_test.go +++ b/cmd/sts_test.go @@ -39,6 +39,8 @@ func TestSTSCommandContainsExpectedSubcommands(t *testing.T) { "user-session", "dashboard", "topology", + "otel-component-mapping", + "otel-relation-mapping", } // Verify expected commands are present @@ -58,7 +60,7 @@ func TestSTSCommandStructure(t *testing.T) { cli := di.NewMockDeps(t) cmd := STSCommand(&cli.Deps) - assert.Len(t, cmd.Commands(), 17, "Expected 17 subcommands") + assert.Len(t, cmd.Commands(), 19, "Expected 19 subcommands") } func TestSTSCommandUsageTemplate(t *testing.T) {