Repository: fluxcd/flux2

Issue:
Add `--show-history` to `flux debug` commands
To improve the debugging experience, we should add a flag for listing the rollout history of Flux HelmReleases and Kustomizations (depends on https://github.com/fluxcd/kustomize-controller/pull/1502).

Tasks:
- [x] Implement `flux debug helmrelease --show-history`
- [x] Implement `flux debug kustomization --show-history`



Hints from issue comments:
@hawkaii: Can I work on this?@stefanprodan: Sure @hawkaii you can start with `flux debug helmrelease --show-history` the history type is already in the HR v2 so no controller release is needed.

Solution patch:
diff --git a/cmd/flux/debug_helmrelease.go b/cmd/flux/debug_helmrelease.go
index 0fcdfcab..040cae8f 100644
--- a/cmd/flux/debug_helmrelease.go
+++ b/cmd/flux/debug_helmrelease.go
@@ -40,15 +40,19 @@ WARNING: This command will print sensitive information if Kubernetes Secrets are
   flux debug hr podinfo --show-status
 
   # Export the final values of a Helm release composed from referred ConfigMaps and Secrets
-  flux debug hr podinfo --show-values > values.yaml`,
+  flux debug hr podinfo --show-values > values.yaml
+
+  # Print the reconciliation history of a Helm release  
+  flux debug hr podinfo --show-history`,
 	RunE:              debugHelmReleaseCmdRun,
 	Args:              cobra.ExactArgs(1),
 	ValidArgsFunction: resourceNamesCompletionFunc(helmv2.GroupVersion.WithKind(helmv2.HelmReleaseKind)),
 }
 
 type debugHelmReleaseFlags struct {
-	showStatus bool
-	showValues bool
+	showStatus  bool
+	showValues  bool
+	showHistory bool
 }
 
 var debugHelmReleaseArgs debugHelmReleaseFlags
@@ -56,15 +60,26 @@ var debugHelmReleaseArgs debugHelmReleaseFlags
 func init() {
 	debugHelmReleaseCmd.Flags().BoolVar(&debugHelmReleaseArgs.showStatus, "show-status", false, "print the status of the Helm release")
 	debugHelmReleaseCmd.Flags().BoolVar(&debugHelmReleaseArgs.showValues, "show-values", false, "print the final values of the Helm release")
+	debugHelmReleaseCmd.Flags().BoolVar(&debugHelmReleaseArgs.showHistory, "show-history", false, "print the reconciliation history of the Helm release")
 	debugCmd.AddCommand(debugHelmReleaseCmd)
 }
 
 func debugHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
 	name := args[0]
 
-	if (!debugHelmReleaseArgs.showStatus && !debugHelmReleaseArgs.showValues) ||
-		(debugHelmReleaseArgs.showStatus && debugHelmReleaseArgs.showValues) {
-		return fmt.Errorf("either --show-status or --show-values must be set")
+	flagsSet := 0
+	if debugHelmReleaseArgs.showStatus {
+		flagsSet++
+	}
+	if debugHelmReleaseArgs.showValues {
+		flagsSet++
+	}
+	if debugHelmReleaseArgs.showHistory {
+		flagsSet++
+	}
+
+	if flagsSet != 1 {
+		return fmt.Errorf("exactly one of --show-status, --show-values, or --show-history must be set")
 	}
 
 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
@@ -109,5 +124,19 @@ func debugHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
 		rootCmd.Print(string(values))
 	}
 
+	if debugHelmReleaseArgs.showHistory {
+		if len(hr.Status.History) == 0 {
+			hr.Status.History = helmv2.Snapshots{}
+		}
+
+		history, err := yaml.Marshal(hr.Status.History)
+		if err != nil {
+			return err
+		}
+
+		rootCmd.Println("# History documentation: https://fluxcd.io/flux/components/helm/helmreleases/#helmrelease-status")
+		rootCmd.Print(string(history))
+		return nil
+	}
 	return nil
 }



Test patch:
diff --git a/cmd/flux/debug_helmrelease_test.go b/cmd/flux/debug_helmrelease_test.go
index a9de9344..12f60017 100644
--- a/cmd/flux/debug_helmrelease_test.go
+++ b/cmd/flux/debug_helmrelease_test.go
@@ -56,6 +56,18 @@ func TestDebugHelmRelease(t *testing.T) {
 			"testdata/debug_helmrelease/values-from.golden.yaml",
 			tmpl,
 		},
+		{
+			"debug history",
+			"debug helmrelease test-with-history --show-history --show-status=false",
+			"testdata/debug_helmrelease/history.golden.yaml",
+			tmpl,
+		},
+		{
+			"debug history empty",
+			"debug helmrelease test-values-inline --show-history --show-status=false",
+			"testdata/debug_helmrelease/history-empty.golden.yaml",
+			tmpl,
+		},
 	}
 
 	for _, tt := range cases {
diff --git a/cmd/flux/testdata/debug_helmrelease/history-empty.golden.yaml b/cmd/flux/testdata/debug_helmrelease/history-empty.golden.yaml
new file mode 100644
index 00000000..c6ee02fa
--- /dev/null
+++ b/cmd/flux/testdata/debug_helmrelease/history-empty.golden.yaml
@@ -0,0 +1,2 @@
+# History documentation: https://fluxcd.io/flux/components/helm/helmreleases/#helmrelease-status
+[]
diff --git a/cmd/flux/testdata/debug_helmrelease/history.golden.yaml b/cmd/flux/testdata/debug_helmrelease/history.golden.yaml
new file mode 100644
index 00000000..5215ed77
--- /dev/null
+++ b/cmd/flux/testdata/debug_helmrelease/history.golden.yaml
@@ -0,0 +1,25 @@
+# History documentation: https://fluxcd.io/flux/components/helm/helmreleases/#helmrelease-status
+- appVersion: 6.0.0
+  chartName: podinfo
+  chartVersion: 6.0.0
+  configDigest: sha256:abc123
+  deleted: "2024-01-01T10:00:00Z"
+  digest: sha256:def456
+  firstDeployed: "2024-01-01T09:00:00Z"
+  lastDeployed: "2024-01-01T10:00:00Z"
+  name: test-with-history
+  namespace: {{ .fluxns }}
+  status: superseded
+  version: 1
+- appVersion: 6.1.0
+  chartName: podinfo
+  chartVersion: 6.1.0
+  configDigest: sha256:xyz789
+  deleted: null
+  digest: sha256:ghi012
+  firstDeployed: "2024-01-01T11:00:00Z"
+  lastDeployed: "2024-01-01T11:00:00Z"
+  name: test-with-history
+  namespace: {{ .fluxns }}
+  status: deployed
+  version: 2
diff --git a/cmd/flux/testdata/debug_helmrelease/objects.yaml b/cmd/flux/testdata/debug_helmrelease/objects.yaml
index 060aa71c..7083b1ef 100644
--- a/cmd/flux/testdata/debug_helmrelease/objects.yaml
+++ b/cmd/flux/testdata/debug_helmrelease/objects.yaml
@@ -46,6 +46,47 @@ spec:
       name: none
       optional: true
 ---
+apiVersion: helm.toolkit.fluxcd.io/v2
+kind: HelmRelease
+metadata:
+  name: test-with-history
+  namespace: {{ .fluxns }}
+spec:
+  chartRef:
+    kind: OCIRepository
+    name: podinfo
+  interval: 5m0s
+  values:
+    image:
+      repository: stefanprodan/podinfo
+      tag: 5.0.0
+status:
+  observedGeneration: 1
+  history:
+    - name: test-with-history
+      namespace: {{ .fluxns }}
+      version: 1
+      configDigest: sha256:abc123
+      chartName: podinfo
+      chartVersion: 6.0.0
+      appVersion: 6.0.0
+      deleted: "2024-01-01T10:00:00Z"
+      digest: sha256:def456
+      firstDeployed: "2024-01-01T09:00:00Z"
+      lastDeployed: "2024-01-01T10:00:00Z"
+      status: superseded
+    - name: test-with-history
+      namespace: {{ .fluxns }}
+      version: 2
+      configDigest: sha256:xyz789
+      chartName: podinfo
+      chartVersion: 6.1.0
+      appVersion: 6.1.0
+      digest: sha256:ghi012
+      firstDeployed: "2024-01-01T11:00:00Z"
+      lastDeployed: "2024-01-01T11:00:00Z"
+      status: deployed
+---
 apiVersion: v1
 kind: ConfigMap
 metadata: