diff --git a/manifest/util.go b/manifest/util.go index 88b818af..96a1368a 100644 --- a/manifest/util.go +++ b/manifest/util.go @@ -25,16 +25,30 @@ func deleteStatusAndTidyMetadata(obj []byte) (map[string]interface{}, error) { // See the below for the goal of this metadata tidy logic. // https://github.com/databus23/helm-diff/issues/326#issuecomment-1008253274 - if a := metadata["annotations"]; a != nil { - annotations := a.(map[string]interface{}) - delete(annotations, "meta.helm.sh/release-name") - delete(annotations, "meta.helm.sh/release-namespace") - delete(annotations, "deployment.kubernetes.io/revision") - - if len(annotations) == 0 { - delete(metadata, "annotations") - } - } + pruneNestedMap(metadata, "annotations", + "meta.helm.sh/release-name", + "meta.helm.sh/release-namespace", + "deployment.kubernetes.io/revision", + ) + pruneNestedMap(metadata, "labels", "app.kubernetes.io/managed-by") return objectMap, nil } + +// pruneNestedMap removes the given fields from the nested map found at key in +// target. If the nested map ends up empty afterwards, key itself is removed +// from target. +func pruneNestedMap(target map[string]interface{}, key string, fields ...string) { + sub, ok := target[key].(map[string]interface{}) + if !ok { + return + } + + for _, field := range fields { + delete(sub, field) + } + + if len(sub) == 0 { + delete(target, key) + } +} diff --git a/manifest/util_test.go b/manifest/util_test.go index 0f86223a..6e344366 100644 --- a/manifest/util_test.go +++ b/manifest/util_test.go @@ -28,12 +28,16 @@ func Test_deleteStatusAndTidyMetadata(t *testing.T) { "metadata": { "annotations": { "deployment.kubernetes.io/revision": "1", - "meta.helm.sh/release-name": "test-release", - "meta.helm.sh/release-namespace": "test-ns", - "other-annot": "value" + "meta.helm.sh/release-name": "test-release", + "meta.helm.sh/release-namespace": "test-ns", + "other-annot": "value" }, "creationTimestamp": "2025-03-03T10:07:50Z", "generation": 1, + "labels": { + "app": "nginx", + "app.kubernetes.io/managed-by": "Helm" + }, "name": "nginx-deployment", "namespace": "test-ns", "resourceVersion": "33648", @@ -64,6 +68,9 @@ func Test_deleteStatusAndTidyMetadata(t *testing.T) { "annotations": map[string]interface{}{ "other-annot": "value", }, + "labels": map[string]interface{}{ + "app": "nginx", + }, "name": "nginx-deployment", "namespace": "test-ns", }, @@ -83,6 +90,27 @@ func Test_deleteStatusAndTidyMetadata(t *testing.T) { }, wantErr: false, }, + { + name: "empty labels are removed", + obj: []byte(` +{ + "kind": "ConfigMap", + "metadata": { + "labels": { + "app.kubernetes.io/managed-by": "Helm" + }, + "name": "example" + } +} +`), + want: map[string]interface{}{ + "kind": "ConfigMap", + "metadata": map[string]interface{}{ + "name": "example", + }, + }, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {