Files
helm/pkg/cmd/rollback.go
MrJack f8180e6de4 feat(rollback): add --description flag to provide rollback reason
Add a new --description flag to the helm rollback command that allows
users to specify a custom description explaining why the rollback was
performed. This description is stored in the release metadata.

Changes:
- Add Description field to the Rollback action struct
- Add --description flag to the rollback CLI command
- Add 512 character limit validation for the description
- Default to 'Rollback to <version>' when no description is provided

The description flag is optional and follows the same pattern used by
the install and upgrade commands.

Closes #XXXX

Signed-off-by: MrJack <36191829+biagiopietro@users.noreply.github.com>
2026-07-27 09:01:31 +02:00

112 lines
4.2 KiB
Go

/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
import (
"fmt"
"io"
"strconv"
"time"
"github.com/spf13/cobra"
"helm.sh/helm/v4/pkg/action"
"helm.sh/helm/v4/pkg/cmd/require"
)
const rollbackDesc = `
This command rolls back a release to a previous revision.
The first argument of the rollback command is the name of a release, and the
second is a revision (version) number. If this argument is omitted or set to
0, it will roll back to the previous release.
To see revision numbers, run 'helm history RELEASE'.
`
// maxDescriptionLength is the maximum length allowed for a rollback description
const maxDescriptionLength = 512
func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
client := action.NewRollback(cfg)
client.WaitOptions = append(client.WaitOptions, defaultCLIWaitOptions()...)
cmd := &cobra.Command{
Use: "rollback <RELEASE> [REVISION]",
Short: "roll back a release to a previous revision",
Long: rollbackDesc,
Args: require.MinimumNArgs(1),
ValidArgsFunction: func(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) == 0 {
return compListReleases(toComplete, args, cfg)
}
if len(args) == 1 {
return compListRevisions(toComplete, cfg, args[0])
}
return noMoreArgsComp()
},
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 1 {
ver, err := strconv.Atoi(args[1])
if err != nil {
return fmt.Errorf("could not convert revision to a number: %w", err)
}
client.Version = ver
}
// Validate description length
if len(client.Description) > maxDescriptionLength {
return fmt.Errorf("description must be %d characters or less, got %d", maxDescriptionLength, len(client.Description))
}
dryRunStrategy, err := cmdGetDryRunFlagStrategy(cmd, false)
if err != nil {
return err
}
client.DryRunStrategy = dryRunStrategy
if err := client.Run(args[0]); err != nil {
return err
}
fmt.Fprint(out, "Rollback was a success! Happy Helming!\n")
return nil
},
}
f := cmd.Flags()
f.StringVar(&client.Description, "description", "", fmt.Sprintf("add a custom description for the rollback (max %d characters)", maxDescriptionLength))
f.BoolVar(&client.ForceReplace, "force-replace", false, "force resource updates by replacement")
f.BoolVar(&client.ForceReplace, "force", false, "deprecated")
f.MarkDeprecated("force", "use --force-replace instead")
f.BoolVar(&client.ForceConflicts, "force-conflicts", false, "if set server-side apply will force changes against conflicts")
f.StringVar(&client.ServerSideApply, "server-side", "auto", "must be \"true\", \"false\" or \"auto\". Object updates run in the server instead of the client (\"auto\" defaults the value from the previous chart release's method)")
f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during rollback")
f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)")
f.BoolVar(&client.WaitForJobs, "wait-for-jobs", false, "if set and --wait enabled, will wait until all Jobs have been completed before marking the release as successful. It will wait for as long as --timeout")
f.BoolVar(&client.CleanupOnFail, "cleanup-on-fail", false, "allow deletion of new resources created in this rollback when rollback fails")
f.IntVar(&client.MaxHistory, "history-max", settings.MaxHistory, "limit the maximum number of revisions saved per release. Use 0 for no limit")
addDryRunFlag(cmd)
AddWaitFlag(cmd, &client.WaitStrategy)
cmd.MarkFlagsMutuallyExclusive("force-replace", "force-conflicts")
cmd.MarkFlagsMutuallyExclusive("force", "force-conflicts")
return cmd
}