Unbeknownst to me, yq possesses the ability to merge whole yaml files on top of one another in order. I had been working around this ignorance using scriptlets that would set values as they were discovered while trapsing a file, so I usually avoided doing it altogether. Many of you know I am NOT a fan of complex scripting.
But after doodling around a bit with yq, I found the reduce/ireduce commands and was able to condense down the ordered/layered merging of N yaml files using a very simple yq one liner.
This was on yq version 4.44.3, so the command may differ on older versions as I think the ireduce command is more recent.
Consider my files below where defaults.yaml defines a baseline configuration I want to use in a kubernetes command (or similar) and the overrides.yaml file is a bespoke alteration to that configuration that I want to use for a specific use case without modifying the defaults file and having to make a whole new copy of it.
defaults.yaml:
a: 1
b:
x: 10overrides.yaml:
b:
x: 99
c: 3Using yq I can merge these files into an output with a one line command:
yq ea '. as $item ireduce ({}; . * $item )' defaults.yaml override.yamlThe above command uses ea as short-hand for eval-all, and then loops over all input files (defaults.yaml and override.yaml) and applies the command to them. The command is ireduce which takes an empty config {} and merges * with each item in the loop $item.
The result:
❯ yq ea '. as $item ireduce ({}; . * $item )' defaults.yaml override.yaml
a: 1
b:
x: 99
c: 3Cool eh?
** WARNING **
Be aware that this merge will NOT do a deep merge correctly. Even when using the *d token in the ireduce function, if you have an array of differing values, the last version of that array will clobber the value entirely. I spent hours trying to work around this but it seems to be a bug in ireduce currently.
So if I take the above command but want to add a generic list of files that fit a pattern, I can use an inline bash statement to generate the list for me!
yq ea '. as $item ireduce ({}; . * $item )' defaults.yaml $(ls -v overrides_*.yaml)This looks for any value matching overrides_*.yaml and add them to the argument list in order. So overrides_1.yaml and overrides_2.yaml would be applied in order. This also will do alphabetical too since its just strings.
Which YQ?
https://github.com/mikefarah/yq or https://github.com/kislyuk/yq ? (I'm guessing the former, based on version number)