yq deal with list items that can be values or objects

38 Views Asked by At

I'm trying to do some pipeline work that injects certain values in a yaml document (an mkdocs config) if they are not currently present. But the problem is that the current values can be either items in a list or objects in a list:

This is valid:

plugins:
  - search

but also this is valid:

plugins:
  - search:
      lang: en
      foo: bar

What I want to do is simply take a config, see if it already has a search plugin section or not, and if it doesn't append the config part in the 2nd one. But just checking if search is present is not possible with one function, so I'm looking for ideas how to be able to handle this properly:

$ yq 'contains({"plugins": ["search"]})' test.yaml
true
$ yq 'contains({"plugins": ["search"]})' test2.yaml
false

On a different note: I also tried creating a template.yaml, where yq would merge the template.yaml on top of the current yaml config, so values in the template would always be present, but that proved to be an even bigger challenge than this one.

1

There are 1 best solutions below

1
pmf On

You didn't specify which of the two implementations of yq you are using (see the Tag Info to ).

With kislyuk/yq, you could use any to test for both cases: any item either itself being the search term, or having a field with the search term as its name using has (bind the term to a variable (or pass it as external argument using --arg) if you want to have it in one place only):

$ yq '.plugins | any(. == "search", has("search")?)' test.yaml test2.yaml
true
true

With mikefarah/yq, to provide a condition, you would use any_c instead (passing in external values would be done via environment variables):

$ yq '.plugins | any_c(. == "search" or has("search"))' test.yaml test2.yaml 
true
---
true

As for your "different note", you'd need to be more specific by including some samples, etc., and ideally in a separate question. But my initial guess is that you want something along the lines of .plugins |= (select(any(…) | not) += ["search"]) with kislyuk/yq, and equivalently .plugins |= (select(any_c(…) | not) += "search") with mikefarah/yq.