Skip to content

Allow gh api --paginate --slurp to be used with --jq #10459

@0xdevalias

Description

@0xdevalias

Describe the feature or problem you’d like to solve

Currently, when trying to use gh api with --paginate --slurp alongside --jq I get the following error:

the --slurp option is not supported with --jq or --template

I would have expected to be able to use these together, most likely getting a top-level array of all of the responses, that I could then process however I like with --jq syntax.

For example, using only --paginate but not --slurp:

⇒ gh api notifications --method GET -F participating=false -F all=true -F page=1 -F per_page=50 --paginate --jq 'length'

50
50
50
50
50
50
50
50
50
50
50
50
50
50
50
50
50
50
50
50
50
50
50
14

Using --paginate --slurp with --jq:

⇒ gh api notifications --method GET -F participating=false -F all=true -F page=1 -F per_page=50 --paginate --slurp --jq 'length' | subl

the `--slurp` option is not supported with `--jq` or `--template`

Using --paginate --slurp and then needing to call out to external jq for further processing:

⇒ gh api notifications --method GET -F participating=false -F all=true -F page=1 -F per_page=50 --paginate --slurp | jq 'length'
24

⇒ gh api notifications --method GET -F participating=false -F all=true -F page=1 -F per_page=50 --paginate --slurp | jq 'map(length)'
[
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  50,
  14
]

For a more real-world example of what I was trying to achieve with --paginate and --jq; that I was then expecting --slurp would help me with (note that I am starting from page 20 here to reduce the length of the output for demonstration purposes):

⇒ gh api notifications --method GET -F participating=false -F all=true -F page=20 -F per_page=50 --paginate --jq '
  # Filter for notifications whose subject type is 'Release',
  # group them by repository, and output repo name and count sorted descending.
  [ .[] | select(.subject.type == "Release") ]
  | group_by(.repository.full_name)
  | map({ repo: .[0].repository.full_name, count: length })
  | sort_by(.count) | reverse
  #| map("\(.repo)  \(.count)")
  # | .[]
'

[{"count":3,"repo":"invoke-ai/InvokeAI"},{"count":2,"repo":"refined-github/refined-github"},{"count":2,"repo":"reduxjs/redux-toolkit"},{"count":2,"repo":"ollama/ollama"},{"count":2,"repo":"aws/aws-cdk"},{"count":1,"repo":"supabase/supabase"},{"count":1,"repo":"remix-run/react-router"},{"count":1,"repo":"obsidianmd/obsidian-releases"},{"count":1,"repo":"langflow-ai/langflow"},{"count":1,"repo":"facebook/react"},{"count":1,"repo":"OpenInterpreter/open-interpreter"}]
[{"count":6,"repo":"invoke-ai/InvokeAI"},{"count":3,"repo":"holochain/holochain"},{"count":2,"repo":"stripe/stripe-js"},{"count":2,"repo":"aws/aws-cdk"},{"count":1,"repo":"reduxjs/redux-toolkit"},{"count":1,"repo":"jehna/humanify"},{"count":1,"repo":"firebase/firebase-js-sdk"},{"count":1,"repo":"actions/checkout"},{"count":1,"repo":"Aider-AI/aider"}]
[{"count":4,"repo":"invoke-ai/InvokeAI"},{"count":3,"repo":"holochain/holochain"},{"count":1,"repo":"stripe/stripe-js"},{"count":1,"repo":"refined-github/refined-github"},{"count":1,"repo":"microsoft/autogen"},{"count":1,"repo":"firebase/firebase-js-sdk"},{"count":1,"repo":"aws/aws-cdk"},{"count":1,"repo":"actions/checkout"},{"count":1,"repo":"Readarr/Readarr"},{"count":1,"repo":"ProxymanApp/Proxyman"},{"count":1,"repo":"Aider-AI/aider"}]
[{"count":3,"repo":"invoke-ai/InvokeAI"},{"count":2,"repo":"ollama/ollama"},{"count":2,"repo":"aws/aws-cdk"},{"count":1,"repo":"refined-github/refined-github"},{"count":1,"repo":"holochain/holochain"},{"count":1,"repo":"firebase/firebase-js-sdk"},{"count":1,"repo":"Whisky-App/Whisky"},{"count":1,"repo":"JedWatson/react-select"},{"count":1,"repo":"Heroic-Games-Launcher/HeroicGamesLauncher"},{"count":1,"repo":"Aider-AI/aider"}]
[{"count":1,"repo":"supabase/supabase"},{"count":1,"repo":"stripe/stripe-js"},{"count":1,"repo":"holochain/holochain"}]

Essentially, the --paginate data seems to be processed individually by --jq; so the output is sort of reminiscent of JSON Lines:

Because each page of the --paginate'd data is treated separately by --jq, when I try and aggregate/count, it doesn't really work, as in this case I get ~24 pages of counts by repo, rather than 1 full count by repo.

By my reading of the vast history of related issues/PR's (linked below), I believe this was kept as there was a desire to not introduce potentially breaking changes before v3 (even if the likelihood of this having any real world user impact was probably low, but somewhat unquantifiable). I believe this was the reason that --slurp was introduced, as a potentially temporary addon so that --paginate's old functionality remained, but we could opt in to a single JSON return value by using --slurp.

Proposed solution

When I was first reading through #8620 (after eventually getting to it through all the past related context linked below), I was expecting that the whole point of that PR was so I could use --paginate --slurp with --jq to avoid needing to rely on an external program (eg. jq); as otherwise, I believe we could have just always relied on an external jq --slurp with the old --paginate implementation.

I would really love to be able to use --paginate, and then process that with --jq; and have it all treated as a 'single pass', rather than the JSON Lines style processing we currently get. My understanding of --slurp is that that would be ideal for this; but we can't use that with --jq currently.

Additional context

I spent a bunch of time reading through the long history of related issues.. (with a LOT of effort put in by @heaths, along with a bunch of others along the way) and while I'm not necessarily deeply wiser about the full spectrum of implementation choices explored and iterated through; here is my attempted shortlist of related issues/PR's in hopefully roughly relevant historical order:

Tangentially related, but probably not relevant (including because it recently touched a similar area, so not sure if there was a regression, but based on above context, I think probably isn't relevant):

Similarly, I'm not sure if this is only tangentially related or not.. but it feels in a similar space of things, so linking in case the additional context is helpful:

Tangentially Related

There have been a number of other json/jq Quality of Life issues I've opened recently; and some awesome PRs associated with some of them, made by @heaths . I'm not sure of the deeper specifics as to whether any of them would crossover with this at an implementation level; but from a user perspective, it's kind of weird/confusing feeling when different CLI commands seem to handle json/jq differently.

Originally posted by @0xdevalias in #10385

Metadata

Metadata

Assignees

Labels

enhancementa request to improve CLIgh-apirelating to the gh api commandneeds-triageneeds to be reviewed

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions