From 06b5d480d15f944f97ea4ed48b1aca374a5ed6fc Mon Sep 17 00:00:00 2001 From: Mike Deeks Date: Thu, 22 Jan 2026 16:43:29 -0800 Subject: [PATCH 1/2] Fix merge order. Global has least priority. --- braintrust/templates/api-configmap.yaml | 2 +- braintrust/templates/api-deployment.yaml | 4 ++-- braintrust/templates/api-service.yaml | 2 +- braintrust/templates/api-serviceaccount.yaml | 2 +- braintrust/templates/brainstore-reader-configmap.yaml | 2 +- braintrust/templates/brainstore-reader-deployment.yaml | 4 ++-- braintrust/templates/brainstore-reader-service.yaml | 2 +- braintrust/templates/brainstore-serviceaccount.yaml | 2 +- braintrust/templates/brainstore-writer-configmap.yaml | 2 +- braintrust/templates/brainstore-writer-deployment.yaml | 4 ++-- braintrust/templates/brainstore-writer-service.yaml | 2 +- 11 files changed, 14 insertions(+), 14 deletions(-) diff --git a/braintrust/templates/api-configmap.yaml b/braintrust/templates/api-configmap.yaml index 0482bfa..8c40187 100644 --- a/braintrust/templates/api-configmap.yaml +++ b/braintrust/templates/api-configmap.yaml @@ -4,7 +4,7 @@ kind: ConfigMap metadata: name: {{ .Values.api.name }} namespace: {{ include "braintrust.namespace" . }} - {{- with (merge (deepCopy .Values.global.labels) .Values.api.labels) }} + {{- with (merge (deepCopy .Values.api.labels) .Values.global.labels) }} labels: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/braintrust/templates/api-deployment.yaml b/braintrust/templates/api-deployment.yaml index ae1fc2c..7a440fc 100644 --- a/braintrust/templates/api-deployment.yaml +++ b/braintrust/templates/api-deployment.yaml @@ -3,7 +3,7 @@ kind: Deployment metadata: name: {{ .Values.api.name }} namespace: {{ include "braintrust.namespace" . }} - {{- with (merge (deepCopy .Values.global.labels) .Values.api.labels) }} + {{- with (merge (deepCopy .Values.api.labels) .Values.global.labels) }} labels: {{- toYaml . | nindent 4 }} {{- end }} @@ -31,7 +31,7 @@ spec: {{- if and (eq .Values.cloud "google") .Values.api.enableGcsAuth }} gke-workload-identity/use: "true" {{- end }} - {{- with (merge (deepCopy .Values.global.labels) .Values.api.labels .Values.api.podLabels) }} + {{- with (merge (deepCopy .Values.api.podLabels) .Values.api.labels .Values.global.labels) }} {{- toYaml . | nindent 8 }} {{- end }} annotations: diff --git a/braintrust/templates/api-service.yaml b/braintrust/templates/api-service.yaml index 5d4b437..0ff776c 100644 --- a/braintrust/templates/api-service.yaml +++ b/braintrust/templates/api-service.yaml @@ -3,7 +3,7 @@ kind: Service metadata: name: {{ .Values.api.service.name | default .Values.api.name }} namespace: {{ include "braintrust.namespace" . }} - {{- with (merge (deepCopy .Values.global.labels) .Values.api.labels) }} + {{- with (merge (deepCopy .Values.api.labels) .Values.global.labels) }} labels: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/braintrust/templates/api-serviceaccount.yaml b/braintrust/templates/api-serviceaccount.yaml index 01127a6..ec38d03 100644 --- a/braintrust/templates/api-serviceaccount.yaml +++ b/braintrust/templates/api-serviceaccount.yaml @@ -3,7 +3,7 @@ kind: ServiceAccount metadata: name: {{ .Values.api.serviceAccount.name }} namespace: {{ include "braintrust.namespace" . }} - {{- with (merge (deepCopy .Values.global.labels) .Values.api.labels) }} + {{- with (merge (deepCopy .Values.api.labels) .Values.global.labels) }} labels: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/braintrust/templates/brainstore-reader-configmap.yaml b/braintrust/templates/brainstore-reader-configmap.yaml index d6f3d08..049cc36 100644 --- a/braintrust/templates/brainstore-reader-configmap.yaml +++ b/braintrust/templates/brainstore-reader-configmap.yaml @@ -4,7 +4,7 @@ kind: ConfigMap metadata: name: {{ .Values.brainstore.reader.name }} namespace: {{ include "braintrust.namespace" . }} - {{- with (merge (deepCopy .Values.global.labels) .Values.brainstore.reader.labels) }} + {{- with (merge (deepCopy .Values.brainstore.reader.labels) .Values.global.labels) }} labels: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/braintrust/templates/brainstore-reader-deployment.yaml b/braintrust/templates/brainstore-reader-deployment.yaml index 17bb2bf..65b2a9c 100644 --- a/braintrust/templates/brainstore-reader-deployment.yaml +++ b/braintrust/templates/brainstore-reader-deployment.yaml @@ -3,7 +3,7 @@ kind: Deployment metadata: name: {{ .Values.brainstore.reader.name }} namespace: {{ include "braintrust.namespace" . }} - {{- with (merge (deepCopy .Values.global.labels) .Values.brainstore.reader.labels) }} + {{- with (merge (deepCopy .Values.brainstore.reader.labels) .Values.global.labels) }} labels: {{- toYaml . | nindent 4 }} {{- end }} @@ -31,7 +31,7 @@ spec: {{- if eq .Values.cloud "google" }} gke-workload-identity/use: "true" {{- end }} - {{- with (merge (deepCopy .Values.global.labels) .Values.brainstore.reader.labels .Values.brainstore.reader.podLabels) }} + {{- with (merge (deepCopy .Values.brainstore.reader.podLabels) .Values.brainstore.reader.labels .Values.global.labels) }} {{- toYaml . | nindent 8 }} {{- end }} annotations: diff --git a/braintrust/templates/brainstore-reader-service.yaml b/braintrust/templates/brainstore-reader-service.yaml index 2bb5451..e968425 100644 --- a/braintrust/templates/brainstore-reader-service.yaml +++ b/braintrust/templates/brainstore-reader-service.yaml @@ -3,7 +3,7 @@ kind: Service metadata: name: {{ .Values.brainstore.reader.service.name | default .Values.brainstore.reader.name }} namespace: {{ include "braintrust.namespace" . }} - {{- with (merge (deepCopy .Values.global.labels) .Values.brainstore.reader.labels) }} + {{- with (merge (deepCopy .Values.brainstore.reader.labels) .Values.global.labels) }} labels: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/braintrust/templates/brainstore-serviceaccount.yaml b/braintrust/templates/brainstore-serviceaccount.yaml index b8ad15a..3b55c62 100644 --- a/braintrust/templates/brainstore-serviceaccount.yaml +++ b/braintrust/templates/brainstore-serviceaccount.yaml @@ -3,7 +3,7 @@ kind: ServiceAccount metadata: name: {{ .Values.brainstore.serviceAccount.name }} namespace: {{ include "braintrust.namespace" . }} - {{- with (merge (deepCopy .Values.global.labels) .Values.brainstore.labels) }} + {{- with (merge (deepCopy .Values.brainstore.labels) .Values.global.labels) }} labels: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/braintrust/templates/brainstore-writer-configmap.yaml b/braintrust/templates/brainstore-writer-configmap.yaml index d934491..890d95c 100644 --- a/braintrust/templates/brainstore-writer-configmap.yaml +++ b/braintrust/templates/brainstore-writer-configmap.yaml @@ -4,7 +4,7 @@ kind: ConfigMap metadata: name: {{ .Values.brainstore.writer.name }} namespace: {{ include "braintrust.namespace" . }} - {{- with (merge (deepCopy .Values.global.labels) .Values.brainstore.writer.labels) }} + {{- with (merge (deepCopy .Values.brainstore.writer.labels) .Values.global.labels) }} labels: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/braintrust/templates/brainstore-writer-deployment.yaml b/braintrust/templates/brainstore-writer-deployment.yaml index 2a24a0c..aadf86b 100644 --- a/braintrust/templates/brainstore-writer-deployment.yaml +++ b/braintrust/templates/brainstore-writer-deployment.yaml @@ -3,7 +3,7 @@ kind: Deployment metadata: name: {{ .Values.brainstore.writer.name }} namespace: {{ include "braintrust.namespace" . }} - {{- with (merge (deepCopy .Values.global.labels) .Values.brainstore.writer.labels) }} + {{- with (merge (deepCopy .Values.brainstore.writer.labels) .Values.global.labels) }} labels: {{- toYaml . | nindent 4 }} {{- end }} @@ -31,7 +31,7 @@ spec: {{- if eq .Values.cloud "google" }} gke-workload-identity/use: "true" {{- end }} - {{- with (merge (deepCopy .Values.global.labels) .Values.brainstore.writer.labels .Values.brainstore.writer.podLabels) }} + {{- with (merge (deepCopy .Values.brainstore.writer.podLabels) .Values.brainstore.writer.labels .Values.global.labels) }} {{- toYaml . | nindent 8 }} {{- end }} annotations: diff --git a/braintrust/templates/brainstore-writer-service.yaml b/braintrust/templates/brainstore-writer-service.yaml index e109f14..9b7496a 100644 --- a/braintrust/templates/brainstore-writer-service.yaml +++ b/braintrust/templates/brainstore-writer-service.yaml @@ -3,7 +3,7 @@ kind: Service metadata: name: {{ .Values.brainstore.writer.service.name | default .Values.brainstore.writer.name }} namespace: {{ include "braintrust.namespace" . }} - {{- with (merge (deepCopy .Values.global.labels) .Values.brainstore.writer.labels) }} + {{- with (merge (deepCopy .Values.brainstore.writer.labels) .Values.global.labels) }} labels: {{- toYaml . | nindent 4 }} {{- end }} From 4615a094871440ea73fd9f4995aa24e927d41aa6 Mon Sep 17 00:00:00 2001 From: Mike Deeks Date: Thu, 22 Jan 2026 16:43:37 -0800 Subject: [PATCH 2/2] Tests for merge order --- .../tests/labels-merge-isolation_test.yaml | 24 +- braintrust/tests/pod-labels_test.yaml | 272 ++++++++++++++++++ 2 files changed, 284 insertions(+), 12 deletions(-) create mode 100644 braintrust/tests/pod-labels_test.yaml diff --git a/braintrust/tests/labels-merge-isolation_test.yaml b/braintrust/tests/labels-merge-isolation_test.yaml index d37dce4..1b5f965 100644 --- a/braintrust/tests/labels-merge-isolation_test.yaml +++ b/braintrust/tests/labels-merge-isolation_test.yaml @@ -206,11 +206,11 @@ tests: value: platform # Note: Helm's merge function gives precedence to the destination (first argument). - # With `merge (deepCopy .Values.global.labels) .Values.component.labels`, - # global labels take precedence over component labels when keys conflict. - # Component labels are only added if the key doesn't exist in global labels. + # With `merge (deepCopy .Values.component.labels) .Values.global.labels`, + # component labels take precedence over global labels when keys conflict. + # Global labels are only added if the key doesn't exist in component labels. - - it: should give global labels precedence over API labels when keys conflict + - it: should give component labels precedence over global labels when keys conflict (API) values: - __fixtures__/base-values.yaml set: @@ -221,16 +221,16 @@ tests: namespace: "braintrust" template: api-deployment.yaml asserts: - # Global label takes precedence for conflicting key + # Component label takes precedence for conflicting key - equal: path: metadata.labels.tier - value: global-tier + value: api-tier # Non-conflicting component label is still added - equal: path: metadata.labels["api-only"] value: api-value - - it: should give global labels precedence over Reader labels when keys conflict + - it: should give component labels precedence over global labels when keys conflict (Reader) values: - __fixtures__/base-values.yaml set: @@ -241,16 +241,16 @@ tests: namespace: "braintrust" template: brainstore-reader-deployment.yaml asserts: - # Global label takes precedence for conflicting key + # Component label takes precedence for conflicting key - equal: path: metadata.labels.tier - value: global-tier + value: reader-tier # Non-conflicting component label is still added - equal: path: metadata.labels["reader-only"] value: reader-value - - it: should give global labels precedence over Writer labels when keys conflict + - it: should give component labels precedence over global labels when keys conflict (Writer) values: - __fixtures__/base-values.yaml set: @@ -261,10 +261,10 @@ tests: namespace: "braintrust" template: brainstore-writer-deployment.yaml asserts: - # Global label takes precedence for conflicting key + # Component label takes precedence for conflicting key - equal: path: metadata.labels.tier - value: global-tier + value: writer-tier # Non-conflicting component label is still added - equal: path: metadata.labels["writer-only"] diff --git a/braintrust/tests/pod-labels_test.yaml b/braintrust/tests/pod-labels_test.yaml new file mode 100644 index 0000000..18dce1c --- /dev/null +++ b/braintrust/tests/pod-labels_test.yaml @@ -0,0 +1,272 @@ +suite: test podLabels feature +templates: + - api-deployment.yaml + - brainstore-reader-deployment.yaml + - brainstore-writer-deployment.yaml +tests: + # Test that podLabels are applied only to pod template labels, not deployment metadata labels + - it: should apply api.podLabels only to pod template labels, not deployment metadata + values: + - __fixtures__/base-values.yaml + set: + api.podLabels.pod-only-label: "pod-value" + api.labels.component: "api" + release: + namespace: "braintrust" + template: api-deployment.yaml + asserts: + # podLabels should appear in pod template metadata + - equal: + path: spec.template.metadata.labels["pod-only-label"] + value: pod-value + # podLabels should NOT appear in deployment metadata + - isNull: + path: metadata.labels["pod-only-label"] + # Regular labels should appear in both + - equal: + path: metadata.labels.component + value: api + - equal: + path: spec.template.metadata.labels.component + value: api + + - it: should apply brainstore.reader.podLabels only to pod template labels, not deployment metadata + values: + - __fixtures__/base-values.yaml + set: + brainstore.reader.podLabels.pod-only-label: "reader-pod-value" + brainstore.reader.labels.component: "reader" + release: + namespace: "braintrust" + template: brainstore-reader-deployment.yaml + asserts: + # podLabels should appear in pod template metadata + - equal: + path: spec.template.metadata.labels["pod-only-label"] + value: reader-pod-value + # podLabels should NOT appear in deployment metadata + - isNull: + path: metadata.labels["pod-only-label"] + # Regular labels should appear in both + - equal: + path: metadata.labels.component + value: reader + - equal: + path: spec.template.metadata.labels.component + value: reader + + - it: should apply brainstore.writer.podLabels only to pod template labels, not deployment metadata + values: + - __fixtures__/base-values.yaml + set: + brainstore.writer.podLabels.pod-only-label: "writer-pod-value" + brainstore.writer.labels.component: "writer" + release: + namespace: "braintrust" + template: brainstore-writer-deployment.yaml + asserts: + # podLabels should appear in pod template metadata + - equal: + path: spec.template.metadata.labels["pod-only-label"] + value: writer-pod-value + # podLabels should NOT appear in deployment metadata + - isNull: + path: metadata.labels["pod-only-label"] + # Regular labels should appear in both + - equal: + path: metadata.labels.component + value: writer + - equal: + path: spec.template.metadata.labels.component + value: writer + + # Test that podLabels are isolated between components + - it: should isolate podLabels between api, reader, and writer deployments + values: + - __fixtures__/base-values.yaml + set: + api.podLabels.api-pod-specific: "api-pod" + brainstore.reader.podLabels.reader-pod-specific: "reader-pod" + brainstore.writer.podLabels.writer-pod-specific: "writer-pod" + release: + namespace: "braintrust" + template: api-deployment.yaml + asserts: + # API should have its own podLabel + - equal: + path: spec.template.metadata.labels["api-pod-specific"] + value: api-pod + # API should NOT have reader or writer podLabels + - isNull: + path: spec.template.metadata.labels["reader-pod-specific"] + - isNull: + path: spec.template.metadata.labels["writer-pod-specific"] + + - it: should isolate reader podLabels from api and writer + values: + - __fixtures__/base-values.yaml + set: + api.podLabels.api-pod-specific: "api-pod" + brainstore.reader.podLabels.reader-pod-specific: "reader-pod" + brainstore.writer.podLabels.writer-pod-specific: "writer-pod" + release: + namespace: "braintrust" + template: brainstore-reader-deployment.yaml + asserts: + # Reader should have its own podLabel + - equal: + path: spec.template.metadata.labels["reader-pod-specific"] + value: reader-pod + # Reader should NOT have api or writer podLabels + - isNull: + path: spec.template.metadata.labels["api-pod-specific"] + - isNull: + path: spec.template.metadata.labels["writer-pod-specific"] + + - it: should isolate writer podLabels from api and reader + values: + - __fixtures__/base-values.yaml + set: + api.podLabels.api-pod-specific: "api-pod" + brainstore.reader.podLabels.reader-pod-specific: "reader-pod" + brainstore.writer.podLabels.writer-pod-specific: "writer-pod" + release: + namespace: "braintrust" + template: brainstore-writer-deployment.yaml + asserts: + # Writer should have its own podLabel + - equal: + path: spec.template.metadata.labels["writer-pod-specific"] + value: writer-pod + # Writer should NOT have api or reader podLabels + - isNull: + path: spec.template.metadata.labels["api-pod-specific"] + - isNull: + path: spec.template.metadata.labels["reader-pod-specific"] + + # Test merge behavior: global labels, component labels, and podLabels all combined + - it: should merge global labels, api labels, and api podLabels in pod template + values: + - __fixtures__/base-values.yaml + set: + global.labels.environment: "production" + api.labels.component: "api" + api.podLabels.pod-role: "server" + release: + namespace: "braintrust" + template: api-deployment.yaml + asserts: + # All three should be present in pod template labels + - equal: + path: spec.template.metadata.labels.environment + value: production + - equal: + path: spec.template.metadata.labels.component + value: api + - equal: + path: spec.template.metadata.labels["pod-role"] + value: server + # Only global and component labels in deployment metadata + - equal: + path: metadata.labels.environment + value: production + - equal: + path: metadata.labels.component + value: api + - isNull: + path: metadata.labels["pod-role"] + + - it: should merge global labels, reader labels, and reader podLabels in pod template + values: + - __fixtures__/base-values.yaml + set: + global.labels.environment: "staging" + brainstore.reader.labels.component: "reader" + brainstore.reader.podLabels.pod-role: "cache" + release: + namespace: "braintrust" + template: brainstore-reader-deployment.yaml + asserts: + # All three should be present in pod template labels + - equal: + path: spec.template.metadata.labels.environment + value: staging + - equal: + path: spec.template.metadata.labels.component + value: reader + - equal: + path: spec.template.metadata.labels["pod-role"] + value: cache + # Only global and component labels in deployment metadata + - equal: + path: metadata.labels.environment + value: staging + - equal: + path: metadata.labels.component + value: reader + - isNull: + path: metadata.labels["pod-role"] + + - it: should merge global labels, writer labels, and writer podLabels in pod template + values: + - __fixtures__/base-values.yaml + set: + global.labels.environment: "development" + brainstore.writer.labels.component: "writer" + brainstore.writer.podLabels.pod-role: "persistence" + release: + namespace: "braintrust" + template: brainstore-writer-deployment.yaml + asserts: + # All three should be present in pod template labels + - equal: + path: spec.template.metadata.labels.environment + value: development + - equal: + path: spec.template.metadata.labels.component + value: writer + - equal: + path: spec.template.metadata.labels["pod-role"] + value: persistence + # Only global and component labels in deployment metadata + - equal: + path: metadata.labels.environment + value: development + - equal: + path: metadata.labels.component + value: writer + - isNull: + path: metadata.labels["pod-role"] + + # Note: Helm's merge function gives precedence to the destination (first argument). + # With `merge (deepCopy .Values.api.podLabels) .Values.api.labels .Values.global.labels`, + # podLabels take precedence, then component labels, then global labels (last has lowest priority). + - it: should give podLabels precedence over global labels when keys conflict + values: + - __fixtures__/base-values.yaml + set: + global.labels.tier: "global-tier" + api.podLabels.tier: "pod-tier" + release: + namespace: "braintrust" + template: api-deployment.yaml + asserts: + # Pod label takes precedence in pod template + - equal: + path: spec.template.metadata.labels.tier + value: pod-tier + + - it: should give podLabels precedence over component labels when keys conflict + values: + - __fixtures__/base-values.yaml + set: + api.labels.tier: "component-tier" + api.podLabels.tier: "pod-tier" + release: + namespace: "braintrust" + template: api-deployment.yaml + asserts: + # Pod label takes precedence in pod template + - equal: + path: spec.template.metadata.labels.tier + value: pod-tier