diff --git a/diff/diff_test.go b/diff/diff_test.go index b3965e80..24d5422c 100644 --- a/diff/diff_test.go +++ b/diff/diff_test.go @@ -602,6 +602,15 @@ spec: containers: - name: app image: demo:v1 + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node-type + operator: In + values: + - standard ` newManifest := ` apiVersion: apps/v1 @@ -616,6 +625,15 @@ spec: containers: - name: app image: demo:v2 + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node-type + operator: In + values: + - dedicated ` oldIndex := manifest.Parse([]byte(oldManifest), "prod", true) newIndex := manifest.Parse([]byte(newManifest), "prod", true) @@ -633,7 +651,7 @@ spec: require.Equal(t, "Deployment", entry.Kind) require.Equal(t, "prod", entry.Namespace) require.Equal(t, "web", entry.Name) - require.Len(t, entry.Changes, 2) + require.Len(t, entry.Changes, 3) replicasChange, ok := findChange(entry.Changes, "spec", "replicas") require.True(t, ok) require.InDelta(t, float64(2), replicasChange.OldValue, 0.001) @@ -643,6 +661,11 @@ spec: require.True(t, ok) require.Equal(t, "demo:v1", imageChange.OldValue) require.Equal(t, "demo:v2", imageChange.NewValue) + + affinityChange, ok := findChange(entry.Changes, "spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].values", "0") + require.True(t, ok) + require.Equal(t, "standard", affinityChange.OldValue) + require.Equal(t, "dedicated", affinityChange.NewValue) } func TestStructuredOutputAddAndRemove(t *testing.T) { diff --git a/diff/structured.go b/diff/structured.go index 6b0f1238..6d893269 100644 --- a/diff/structured.go +++ b/diff/structured.go @@ -271,6 +271,20 @@ func diffArrayNodes(changes *[]FieldChange, tokens []string, oldNode, newNode in if reflect.DeepEqual(oldVal, newVal) { continue } + // If both oldVal and newVal are strings, we can directly record the change without further recursion. + if oldStr, ok := oldVal.(string); ok { + if newStr, ok := newVal.(string); ok { + path, field := splitTokens(next) + *changes = append(*changes, FieldChange{ + Path: path, + Field: field, + Change: "replace", + OldValue: oldStr, + NewValue: newStr, + }) + continue + } + } subPatch, err := createNodePatch(oldVal, newVal) if err != nil { return err