Search code examples
yamlyq

yq - Run several filters in the row


I've a YAML file representing the releases of a project:

releases:
  - name: v0.1.0
    changes:
      added:
        - Second feature (#4)
      fixed:
        - Second fix (#5)
  - name: v0.0.1
    changes:
      fixed:
        - First fix (#3)
      security:
  - name: v0.0.1
    changes:
      added:
        - Bootstrap the project (#1)
        - First feature (#2)

I'm searching the correct recipe to get the following result:

v0.1.0
Second feature (#4)
Second fix (#5)
v0.0.1
First fix (#3)
v0.0.1
Bootstrap the project (#1)
First feature (#2)

For now, the closest I've gotten is:

v0.1.0
v0.0.1
v0.0.1
Second feature (#4)
Bootstrap the project (#1)
First feature (#2)
Second fix (#5)
First fix (#3)

With the following recipe:

.releases[] | (
  .name,
  .changes.added[],
  .changes.fixed[]
)

From what I understand, with my current recipe, all the items in releases will be provided to the filter .name, then all the items in releases will be provided to .changes.added[], etc.

Is there a way to provide one item to the three filters, then another one, etc.?

Thanks in advance!

Edit (October 1st, 2023): I'm using mikefarah flavor of yq.


Solution

  • Your expected result is the default behavior with jq, and thus also with kislyuk/yq. With mikefarah/yq, however, it's different, but you can induce this behavior by storing the iteration value in a variable:

    .releases[] as $r | (
      $r.name,
      $r.changes.added[],
      $r.changes.fixed[]
    )
    
    v0.1.0
    Second feature (#4)
    Second fix (#5)
    v0.0.1
    First fix (#3)
    v0.0.1
    Bootstrap the project (#1)
    First feature (#2)
    

    Note: Depending on your actual use-case (especially wrt "interfering" values), you also might want to consider employing a recursive descent .., which traverses the tree in document order. Reduce this stream by using a reasonable discriminator, e.g. for this sample, it suffices filtering for strings to get your desired output:

    .releases | .. | select(tag == "!!str")