Skip to content

Commit b968963

Browse files
committed
Merge branch 'stevenwdv-merge-anchor-fix'
2 parents 4019d42 + 92309b1 commit b968963

11 files changed

+994
-239
lines changed

pkg/yqlib/candidate_node.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,18 @@ func (n *CandidateNode) getParsedKey() interface{} {
169169

170170
}
171171

172+
func (n *CandidateNode) FilterMapContentByKey(keyPredicate func(*CandidateNode) bool) []*CandidateNode {
173+
var result []*CandidateNode
174+
for index := 0; index < len(n.Content); index = index + 2 {
175+
keyNode := n.Content[index]
176+
valueNode := n.Content[index+1]
177+
if keyPredicate(keyNode) {
178+
result = append(result, keyNode, valueNode)
179+
}
180+
}
181+
return result
182+
}
183+
172184
func (n *CandidateNode) GetPath() []interface{} {
173185
key := n.getParsedKey()
174186
if n.Parent != nil && key != nil {

pkg/yqlib/doc/operators/anchor-and-alias-operators.md

Lines changed: 232 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -5,66 +5,19 @@ Use the `alias` and `anchor` operators to read and write yaml aliases and anchor
55
`yq` supports merge aliases (like `<<: *blah`) however this is no longer in the standard yaml spec (1.2) and so `yq` will automatically add the `!!merge` tag to these nodes as it is effectively a custom tag.
66

77

8-
## Merge one map
9-
see https://yaml.org/type/merge.html
8+
## NOTE --yaml-fix-merge-anchor-to-spec flag
9+
`yq` doesn't merge anchors `<<:` to spec, in some circumstances it incorrectly overrides existing keys when the spec documents not to do that.
1010

11-
Given a sample.yml file of:
12-
```yaml
13-
- &CENTER
14-
x: 1
15-
y: 2
16-
- &LEFT
17-
x: 0
18-
y: 2
19-
- &BIG
20-
r: 10
21-
- &SMALL
22-
r: 1
23-
- !!merge <<: *CENTER
24-
r: 10
25-
```
26-
then
27-
```bash
28-
yq '.[4] | explode(.)' sample.yml
29-
```
30-
will output
31-
```yaml
32-
x: 1
33-
y: 2
34-
r: 10
35-
```
11+
To minimise disruption while still fixing the issue, a flag has been added to toggle this behaviour. This will first default to false; and log warnings to users. Then it will default to true (and still allow users to specify false if needed).
3612

37-
## Merge multiple maps
38-
see https://yaml.org/type/merge.html
13+
This flag also enables advanced merging, like inline maps, as well as fixes to ensure when exploding a particular path, neighbours are not affect ed.
14+
15+
Long story short, you should be setting this flag to true.
16+
17+
See examples of the flag differences below, where LEGACY is with the flag off; and FIXED is with the flag on.
3918

40-
Given a sample.yml file of:
41-
```yaml
42-
- &CENTER
43-
x: 1
44-
y: 2
45-
- &LEFT
46-
x: 0
47-
y: 2
48-
- &BIG
49-
r: 10
50-
- &SMALL
51-
r: 1
52-
- !!merge <<:
53-
- *CENTER
54-
- *BIG
55-
```
56-
then
57-
```bash
58-
yq '.[4] | explode(.)' sample.yml
59-
```
60-
will output
61-
```yaml
62-
r: 10
63-
x: 1
64-
y: 2
65-
```
6619

67-
## Override
20+
## Merge one map
6821
see https://yaml.org/type/merge.html
6922

7023
Given a sample.yml file of:
@@ -79,21 +32,18 @@ Given a sample.yml file of:
7932
r: 10
8033
- &SMALL
8134
r: 1
82-
- !!merge <<:
83-
- *BIG
84-
- *LEFT
85-
- *SMALL
86-
x: 1
35+
- !!merge <<: *CENTER
36+
r: 10
8737
```
8838
then
8939
```bash
9040
yq '.[4] | explode(.)' sample.yml
9141
```
9242
will output
9343
```yaml
94-
r: 10
9544
x: 1
9645
y: 2
46+
r: 10
9747
```
9848
9949
## Get anchor
@@ -254,7 +204,39 @@ f:
254204
cat: b
255205
```
256206
257-
## Explode with merge anchors
207+
## Dereference and update a field
208+
Use explode with multiply to dereference an object
209+
210+
Given a sample.yml file of:
211+
```yaml
212+
item_value: &item_value
213+
value: true
214+
thingOne:
215+
name: item_1
216+
!!merge <<: *item_value
217+
thingTwo:
218+
name: item_2
219+
!!merge <<: *item_value
220+
```
221+
then
222+
```bash
223+
yq '.thingOne |= (explode(.) | sort_keys(.)) * {"value": false}' sample.yml
224+
```
225+
will output
226+
```yaml
227+
item_value: &item_value
228+
value: true
229+
thingOne:
230+
name: item_1
231+
value: false
232+
thingTwo:
233+
name: item_2
234+
!!merge <<: *item_value
235+
```
236+
237+
## LEGACY: Explode with merge anchors
238+
Caution: this is for when --yaml-fix-merge-anchor-to-spec=false; it's not to YAML spec because the merge anchors incorrectly override the object values (foobarList.b is set to bar_b when it should still be foobarList_b). Flag will default to true in late 2025
239+
258240
Given a sample.yml file of:
259241
```yaml
260242
foo: &foo
@@ -301,33 +283,201 @@ foobar:
301283
thing: foobar_thing
302284
```
303285
304-
## Dereference and update a field
305-
Use explode with multiply to dereference an object
286+
## LEGACY: Merge multiple maps
287+
see https://yaml.org/type/merge.html. This has the correct data, but the wrong key order; set --yaml-fix-merge-anchor-to-spec=true to fix the key order.
306288
307289
Given a sample.yml file of:
308290
```yaml
309-
item_value: &item_value
310-
value: true
311-
thingOne:
312-
name: item_1
313-
!!merge <<: *item_value
314-
thingTwo:
315-
name: item_2
316-
!!merge <<: *item_value
291+
- &CENTER
292+
x: 1
293+
y: 2
294+
- &LEFT
295+
x: 0
296+
y: 2
297+
- &BIG
298+
r: 10
299+
- &SMALL
300+
r: 1
301+
- !!merge <<:
302+
- *CENTER
303+
- *BIG
317304
```
318305
then
319306
```bash
320-
yq '.thingOne |= explode(.) * {"value": false}' sample.yml
307+
yq '.[4] | explode(.)' sample.yml
321308
```
322309
will output
323310
```yaml
324-
item_value: &item_value
325-
value: true
326-
thingOne:
327-
name: item_1
328-
value: false
329-
thingTwo:
330-
name: item_2
331-
!!merge <<: *item_value
311+
r: 10
312+
x: 1
313+
y: 2
314+
```
315+
316+
## LEGACY: Override
317+
see https://yaml.org/type/merge.html. This has the correct data, but the wrong key order; set --yaml-fix-merge-anchor-to-spec=true to fix the key order.
318+
319+
Given a sample.yml file of:
320+
```yaml
321+
- &CENTER
322+
x: 1
323+
y: 2
324+
- &LEFT
325+
x: 0
326+
y: 2
327+
- &BIG
328+
r: 10
329+
- &SMALL
330+
r: 1
331+
- !!merge <<:
332+
- *BIG
333+
- *LEFT
334+
- *SMALL
335+
x: 1
336+
```
337+
then
338+
```bash
339+
yq '.[4] | explode(.)' sample.yml
340+
```
341+
will output
342+
```yaml
343+
r: 10
344+
x: 1
345+
y: 2
346+
```
347+
348+
## FIXED: Explode with merge anchors
349+
Set `--yaml-fix-merge-anchor-to-spec=true` to get this correct merge behaviour (flag will default to true in late 2025).
350+
Observe that foobarList.b property is still foobarList_b.
351+
352+
Given a sample.yml file of:
353+
```yaml
354+
foo: &foo
355+
a: foo_a
356+
thing: foo_thing
357+
c: foo_c
358+
bar: &bar
359+
b: bar_b
360+
thing: bar_thing
361+
c: bar_c
362+
foobarList:
363+
b: foobarList_b
364+
!!merge <<:
365+
- *foo
366+
- *bar
367+
c: foobarList_c
368+
foobar:
369+
c: foobar_c
370+
!!merge <<: *foo
371+
thing: foobar_thing
372+
```
373+
then
374+
```bash
375+
yq 'explode(.)' sample.yml
376+
```
377+
will output
378+
```yaml
379+
foo:
380+
a: foo_a
381+
thing: foo_thing
382+
c: foo_c
383+
bar:
384+
b: bar_b
385+
thing: bar_thing
386+
c: bar_c
387+
foobarList:
388+
b: foobarList_b
389+
a: foo_a
390+
thing: foo_thing
391+
c: foobarList_c
392+
foobar:
393+
c: foobar_c
394+
a: foo_a
395+
thing: foobar_thing
396+
```
397+
398+
## FIXED: Merge multiple maps
399+
Set `--yaml-fix-merge-anchor-to-spec=true` to get this correct merge behaviour (flag will default to true in late 2025).
400+
Taken from https://yaml.org/type/merge.html. Same values as legacy, but with the correct key order.
401+
402+
Given a sample.yml file of:
403+
```yaml
404+
- &CENTER
405+
x: 1
406+
y: 2
407+
- &LEFT
408+
x: 0
409+
y: 2
410+
- &BIG
411+
r: 10
412+
- &SMALL
413+
r: 1
414+
- !!merge <<:
415+
- *CENTER
416+
- *BIG
417+
```
418+
then
419+
```bash
420+
yq '.[4] | explode(.)' sample.yml
421+
```
422+
will output
423+
```yaml
424+
x: 1
425+
y: 2
426+
r: 10
427+
```
428+
429+
## FIXED: Override
430+
Set `--yaml-fix-merge-anchor-to-spec=true` to get this correct merge behaviour (flag will default to true in late 2025).
431+
Taken from https://yaml.org/type/merge.html. Same values as legacy, but with the correct key order.
432+
433+
Given a sample.yml file of:
434+
```yaml
435+
- &CENTER
436+
x: 1
437+
y: 2
438+
- &LEFT
439+
x: 0
440+
y: 2
441+
- &BIG
442+
r: 10
443+
- &SMALL
444+
r: 1
445+
- !!merge <<:
446+
- *BIG
447+
- *LEFT
448+
- *SMALL
449+
x: 1
450+
```
451+
then
452+
```bash
453+
yq '.[4] | explode(.)' sample.yml
454+
```
455+
will output
456+
```yaml
457+
r: 10
458+
y: 2
459+
x: 1
460+
```
461+
462+
## Exploding inline merge anchor
463+
Set `--yaml-fix-merge-anchor-to-spec=true` to get this correct merge behaviour (flag will default to true in late 2025).
464+
465+
466+
Given a sample.yml file of:
467+
```yaml
468+
a:
469+
b: &b 42
470+
!!merge <<:
471+
c: *b
472+
```
473+
then
474+
```bash
475+
yq 'explode(.) | sort_keys(.)' sample.yml
476+
```
477+
will output
478+
```yaml
479+
a:
480+
b: 42
481+
c: 42
332482
```
333483

pkg/yqlib/doc/operators/headers/anchor-and-alias-operators.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,15 @@ Use the `alias` and `anchor` operators to read and write yaml aliases and anchor
44

55
`yq` supports merge aliases (like `<<: *blah`) however this is no longer in the standard yaml spec (1.2) and so `yq` will automatically add the `!!merge` tag to these nodes as it is effectively a custom tag.
66

7+
8+
## NOTE --yaml-fix-merge-anchor-to-spec flag
9+
`yq` doesn't merge anchors `<<:` to spec, in some circumstances it incorrectly overrides existing keys when the spec documents not to do that.
10+
11+
To minimise disruption while still fixing the issue, a flag has been added to toggle this behaviour. This will first default to false; and log warnings to users. Then it will default to true (and still allow users to specify false if needed).
12+
13+
This flag also enables advanced merging, like inline maps, as well as fixes to ensure when exploding a particular path, neighbours are not affect ed.
14+
15+
Long story short, you should be setting this flag to true.
16+
17+
See examples of the flag differences below, where LEGACY is with the flag off; and FIXED is with the flag on.
18+

0 commit comments

Comments
 (0)