diff --git a/cli/cmd/release_create.go b/cli/cmd/release_create.go index 789ab683..9c8eb297 100644 --- a/cli/cmd/release_create.go +++ b/cli/cmd/release_create.go @@ -51,7 +51,10 @@ func (r *runners) InitReleaseCreate(parent *cobra.Command) error { - ./manifests/*.yaml With this config, simply run: - replicated release create --version 1.0.0 --promote Unstable`, + replicated release create --version 1.0.0 --promote Unstable + + To mark a release as required during upgrades: + replicated release create --version 1.0.0 --promote Unstable --required`, SilenceUsage: false, SilenceErrors: true, // this command uses custom error printing } @@ -78,7 +81,6 @@ func (r *runners) InitReleaseCreate(parent *cobra.Command) error { cmd.Flags().StringVarP(&r.outputFormat, "output", "o", "table", "The output format to use. One of: json|table") // not supported for KOTS - cmd.Flags().MarkHidden("required") cmd.Flags().MarkHidden("yaml-file") cmd.Flags().MarkHidden("yaml") cmd.Flags().MarkHidden("chart") @@ -468,6 +470,11 @@ func (r *runners) validateReleaseCreateParams() error { } } + // can't mark a release as required if you didn't pass a promote channel + if r.args.createReleasePromoteRequired && r.args.createReleasePromote == "" { + return errors.New("--required can only be used with --promote ") + } + // If no sources specified, config-based flow will be used (validated elsewhere) if numSources == 0 { return nil diff --git a/cli/cmd/release_create_test.go b/cli/cmd/release_create_test.go index 2986cfb4..05ed05ca 100644 --- a/cli/cmd/release_create_test.go +++ b/cli/cmd/release_create_test.go @@ -220,3 +220,64 @@ func TestSetKOTSDefaultReleaseParams_SetsEnsureChannelAndLint(t *testing.T) { assert.True(t, args.createReleasePromoteEnsureChannel, "ensure-channel should be set to true") assert.True(t, args.createReleaseLint, "lint should be set to true") } + +// TestRequiredFlagRequiresPromote tests that --required fails without --promote +func TestRequiredFlagRequiresPromote(t *testing.T) { + r := &runners{ + args: runnerArgs{ + createReleasePromoteRequired: true, + createReleasePromote: "", // No promote channel + createReleaseYamlDir: "./manifests", + }, + appType: "kots", + } + + err := r.validateReleaseCreateParams() + assert.Error(t, err) + assert.Contains(t, err.Error(), "--required can only be used with --promote") +} + +// TestRequiredFlagWithPromote tests that --required works with --promote +func TestRequiredFlagWithPromote(t *testing.T) { + r := &runners{ + args: runnerArgs{ + createReleasePromoteRequired: true, + createReleasePromote: "Unstable", + createReleaseYamlDir: "./manifests", + }, + appType: "kots", + } + + err := r.validateReleaseCreateParams() + assert.NoError(t, err) +} + +// TestRequiredFlagDefaultsFalse tests that --required defaults to false +func TestRequiredFlagDefaultsFalse(t *testing.T) { + r := &runners{ + args: runnerArgs{ + createReleasePromote: "Unstable", + createReleaseYamlDir: "./manifests", + }, + } + + assert.False(t, r.args.createReleasePromoteRequired, + "--required should default to false") +} + +// TestRequiredFlagRequiresPromoteInConfigBasedFlow tests that --required fails +// without --promote even in config-based flow (no explicit yaml sources) +func TestRequiredFlagRequiresPromoteInConfigBasedFlow(t *testing.T) { + r := &runners{ + args: runnerArgs{ + createReleasePromoteRequired: true, + createReleasePromote: "", // No promote channel + // No yaml sources specified - simulates config-based flow + }, + appType: "kots", + } + + err := r.validateReleaseCreateParams() + assert.Error(t, err) + assert.Contains(t, err.Error(), "--required can only be used with --promote") +}