nuhkoca
nuhkoca

Reputation: 1943

How to pass an array to jq to filter results

I am fetching list of PR approvals from Github API using curl and jq to put a label in each PR if conditions are met. I have a few conditions for that namely;

In fact, everything is working well but I wanted to beautify my code for example passing the list as an argument rather than having it hardcoded in code. I tried below but it is not working due to:

jq: error (at :1): Cannot iterate over string ("joedoe,")

response=$(curl \
  -H "Accept: application/vnd.github.v3+json" \
  --request GET \
  --url https://api.github.com/repos/my-organization/my-repo/pulls/my-pr-number/reviews \
  --header "Authorization: token ***" \
  --header "Content-Type: application/json")

requiredViewers=("joedoe", "johnsmith", "johnstiles")

echo $response | jq --arg items $requiredViewers '( map( select( .state=="APPROVED" ) ) | 
                                                    map( { user: .user.login, state: .state, submitted_at: .submitted_at } ) | 
                                                    unique_by( .user ) | 
                                                    sort_by( .submitted_at ) | 
                                                    reverse ) | 
                                                    any( .[].user; . | 
                                                    IN ( $items[] --> this is not working ) ) and 
                                                    length>=2'

I had a look at similar posts on SO but couldn't get it to working unfortunately. My question is that how can I pass a list as an argument and make it working as like hardcoding them?

Upvotes: 1

Views: 2853

Answers (1)

peak
peak

Reputation: 116650

The simplest way to achieve your goal would be to define requiredViewers as a JSON array, and to pass it in using --argjson instead of --arg (assuming your version of jq supports --argjson):

requiredViewers='["joedoe", "johnsmith", "johnstiles"]'

echo "$response" |
  jq --argjson items "$requiredViewers" '
    ( map( select( .state=="APPROVED" ) ) 
      | map( { user: .user.login, state, submitted_at } )
      | unique_by( .user ) 
      | sort_by( .submitted_at )
      | reverse )
    | any( .[].user; 
           IN ( $items[] ) ) and length>=2
'

If your jq does not support --argjson

If you cannot upgrade your jq, then one possibility would be to pass the JSON array in as a string using --arg, and to use fromjson to convert it to a JSON array.

Notes

  1. The leading '. |' in constructs such as '. | IN(...)' should be omitted.
  2. Don't forget to quote your shell variables.
  3. The jq expression {foo: .foo} can be abbreviated to {foo}
  4. There are some aspects of your jq program that do not seem to make much sense but in the absence of both explicit requirements and sample JSON, I've focused on the main question.
  5. I'd suggest adopting a style that does not require so much right-indentation; the "pipes-on-the-left" style works for me :-)

Upvotes: 7

Related Questions