Repository: helm/helm (go)

Issue:
helm uninstall with --keep-history then upgrade --install results in UPGRADE FAILED "chartname" has no deployed releases
Output of `helm version`:
```
Version:"v3.10.2"
GitCommit:"50f003e5ee8704ec937a756c646870227d7c8b58"
GitTreeState:"clean"
GoVersion:"go1.19.3"
```

Output of `kubectl version`:

```
Client Version: version.Info{Major:"1", Minor:"25", GitVersion:"v1.25.4", GitCommit:"872a965c6c6526caa949f0c6ac028ef7aff3fb78", GitTreeState:"clean", BuildDate:"2022-11-09T13:28:30Z", GoVersion:"go1.19.3", Compiler:"gc", Platform:"darwin/arm64"}
Kustomize Version: v4.5.7
Server Version: version.Info{Major:"1", Minor:"22+", GitVersion:"v1.22.15-eks-fb459a0", GitCommit:"be82fa628e60d024275efaa239bfe53a9119c2d9", GitTreeState:"clean", BuildDate:"2022-10-24T20:33:23Z", GoVersion:"go1.16.15", Compiler:"gc", Platform:"linux/amd64"}
```

Cloud Provider/Platform (AKS, GKE, Minikube etc.): EKS

Context:

I'm creating a dashboard where I want to preserve history for a helm chart.

This would allow me to know when a chart was first installed (after potential uninstalls) using the helm history command.


Reproduce Steps:

```
# initial install
helm -n xyz upgrade --install devactions devactions
# uninstall
helm -n xyz uninstall devactions --keep-history
# install again
helm -n xyz upgrade --install devactions devactions
```

> Error: UPGRADE FAILED: "devactions" has no deployed releases


I can only reinstall if I drop the instance without `--keep-history`.






Pull request:
fix: reinstall previously uninstalled chart with --keep-history

<!--  Thanks for sending a pull request!  Here are some tips for you:
1. Make sure to read the Contributing Guide before submitting your PR: https://github.com/helm/helm/blob/main/CONTRIBUTING.md
2. If this PR closes another issue, add 'closes #<issue number>' somewhere in the PR summary. GitHub will automatically close that issue when this PR gets merged. Alternatively, adding 'refs #<issue number>' will not close the issue, but help provide the reviewer more context.-->

**What this PR does / why we need it**:

Before, if a chart was uninstalled using the `--keep-history` flag, the next
attempt to upgrade/install the chart would result in an error.

This PR fixes that by correctly checking if the last release of the chart
stored in history has been uninstalled and running the install with the
`--replace` flag if that's the case.


Closes #11553 

**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


Patch:
diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go
index 3302da12c..f2873ff4d 100644
--- a/cmd/helm/upgrade.go
+++ b/cmd/helm/upgrade.go
@@ -36,6 +36,7 @@ import (
 	"helm.sh/helm/v3/pkg/cli/values"
 	"helm.sh/helm/v3/pkg/downloader"
 	"helm.sh/helm/v3/pkg/getter"
+	"helm.sh/helm/v3/pkg/release"
 	"helm.sh/helm/v3/pkg/storage/driver"
 )
 
@@ -96,7 +97,8 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 				// If a release does not exist, install it.
 				histClient := action.NewHistory(cfg)
 				histClient.Max = 1
-				if _, err := histClient.Run(args[0]); err == driver.ErrReleaseNotFound {
+				versions, err := histClient.Run(args[0])
+				if err == driver.ErrReleaseNotFound || isReleaseUninstalled(versions) {
 					// Only print this to stdout for table output
 					if outfmt == output.Table {
 						fmt.Fprintf(out, "Release %q does not exist. Installing it now.\n", args[0])
@@ -121,6 +123,10 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 					instClient.DependencyUpdate = client.DependencyUpdate
 					instClient.EnableDNS = client.EnableDNS
 
+					if isReleaseUninstalled(versions) {
+						instClient.Replace = true
+					}
+
 					rel, err := runInstall(args, instClient, valueOpts, out)
 					if err != nil {
 						return err
@@ -252,3 +258,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 
 	return cmd
 }
+
+func isReleaseUninstalled(versions []*release.Release) bool {
+	return len(versions) > 0 && versions[len(versions)-1].Info.Status == release.StatusUninstalled
+}


Test patch:
diff --git a/cmd/helm/testdata/output/upgrade-uninstalled-with-keep-history.txt b/cmd/helm/testdata/output/upgrade-uninstalled-with-keep-history.txt
new file mode 100644
index 000000000..f53b8715a
--- /dev/null
+++ b/cmd/helm/testdata/output/upgrade-uninstalled-with-keep-history.txt
@@ -0,0 +1,7 @@
+Release "funny-bunny" does not exist. Installing it now.
+NAME: funny-bunny
+LAST DEPLOYED: Fri Sep  2 22:04:05 1977
+NAMESPACE: default
+STATUS: deployed
+REVISION: 3
+TEST SUITE: None
diff --git a/cmd/helm/upgrade_test.go b/cmd/helm/upgrade_test.go
index 8afcb139b..e687a5425 100644
--- a/cmd/helm/upgrade_test.go
+++ b/cmd/helm/upgrade_test.go
@@ -176,6 +176,12 @@ func TestUpgradeCmd(t *testing.T) {
 			wantError: true,
 			rels:      []*release.Release{relWithStatusMock("funny-bunny", 2, ch, release.StatusPendingInstall)},
 		},
+		{
+			name:   "install a previously uninstalled release with '--keep-history' using 'upgrade --install'",
+			cmd:    fmt.Sprintf("upgrade funny-bunny -i '%s'", chartPath),
+			golden: "output/upgrade-uninstalled-with-keep-history.txt",
+			rels:   []*release.Release{relWithStatusMock("funny-bunny", 2, ch, release.StatusUninstalled)},
+		},
 	}
 	runTestCmd(t, tests)
 }