Repository: helm/helm
Pull request #10564 (2022-01-17 02:55:59)

Closes #3352, add support for --ignore-not-found just like kubectl delete
**What this PR does / why we need it**:
Closes #3352, add the option `--ignore-not-found` for `helm uninstall`.
`kubectl delete` has a similar option, which is very handy when deleting a lot of resources because we don't have to make sure they exist beforehand.

**Special notes for your reviewer**:

**If applicable**:
- [ ] this PR contains documentation
- [x] this PR contains unit tests
- [x] this PR has been tested for backwards compatibility


suzaku: Maybe we should just fork it instead of contributing PRs.
scottrigby: I like this proposal. There is a PR review meetup in Brooklyn tomorrow, this could be a good one for new reviewers
suzaku: Hi @scottrigby , any news from the PR review meetup?
scottrigby: Hi @suzaku , not yet - I am on vacation until Aug 30, and will check in with PR reviewers then. There were several new reviewers from that meetup, and one person has been given allocated time from their company to help 🙂

In the meantime Phillip Stehle has given a summary of this weeks Helm pull request review session that was planned during the last Helm dev meeting. See this slack thread:

https://kubernetes.slack.com/archives/C51E88VDG/p1660833138133719?thread_ts=1660317807.065359&channel=C51E88VDG&message_ts=1660833138.133719
suzaku: @sudermanjr Any news for this PR?
stevo-f3: Can this please be merged?
suzaku: @sudermanjr @mircozanchi Hello, if there's nothing terribly risky about merging this approved PR can we just merge it?
joejulian: This looks good. Any chance you can fix the merge conflict?

Patch:
diff --git a/cmd/helm/uninstall.go b/cmd/helm/uninstall.go
index 1a47e972c..9ced8fef0 100644
--- a/cmd/helm/uninstall.go
+++ b/cmd/helm/uninstall.go
@@ -74,6 +74,7 @@ func newUninstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 	f := cmd.Flags()
 	f.BoolVar(&client.DryRun, "dry-run", false, "simulate a uninstall")
 	f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during uninstallation")
+	f.BoolVar(&client.IgnoreNotFound, "ignore-not-found", false, `Treat "release not found" as a successful uninstall`)
 	f.BoolVar(&client.KeepHistory, "keep-history", false, "remove all associated resources and mark the release as deleted, but retain the release history")
 	f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all the resources are deleted before returning. It will wait for as long as --timeout")
 	f.StringVar(&client.DeletionPropagation, "cascade", "background", "Must be \"background\", \"orphan\", or \"foreground\". Selects the deletion cascading strategy for the dependents. Defaults to background.")
diff --git a/pkg/action/uninstall.go b/pkg/action/uninstall.go
index 801498544..40d82243e 100644
--- a/pkg/action/uninstall.go
+++ b/pkg/action/uninstall.go
@@ -21,6 +21,7 @@ import (
 	"time"
 
 	"github.com/pkg/errors"
+
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"helm.sh/helm/v3/pkg/chartutil"
@@ -38,6 +39,7 @@ type Uninstall struct {
 
 	DisableHooks        bool
 	DryRun              bool
+	IgnoreNotFound      bool
 	KeepHistory         bool
 	Wait                bool
 	DeletionPropagation string
@@ -73,6 +75,9 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error)
 
 	rels, err := u.cfg.Releases.History(name)
 	if err != nil {
+		if u.IgnoreNotFound {
+			return nil, nil
+		}
 		return nil, errors.Wrapf(err, "uninstall: Release not loaded: %s", name)
 	}
 	if len(rels) < 1 {


Test patch:
diff --git a/pkg/action/uninstall_test.go b/pkg/action/uninstall_test.go
index 311a34923..869ffb8c7 100644
--- a/pkg/action/uninstall_test.go
+++ b/pkg/action/uninstall_test.go
@@ -32,6 +32,17 @@ func uninstallAction(t *testing.T) *Uninstall {
 	return unAction
 }
 
+func TestUninstallRelease_ignoreNotFound(t *testing.T) {
+	unAction := uninstallAction(t)
+	unAction.DryRun = false
+	unAction.IgnoreNotFound = true
+
+	is := assert.New(t)
+	res, err := unAction.Run("release-non-exist")
+	is.Nil(res)
+	is.NoError(err)
+}
+
 func TestUninstallRelease_deleteRelease(t *testing.T) {
 	is := assert.New(t)