@@ -43,6 +43,7 @@ type ApiOptions struct {
4343 Silent bool
4444 Template string
4545 CacheTTL time.Duration
46+ FilterOutput string
4647
4748 HttpClient func () (* http.Client , error )
4849 BaseRepo func () (ghrepo.Interface , error )
@@ -97,6 +98,11 @@ func NewCmdApi(f *cmdutil.Factory, runF func(*ApiOptions) error) *cobra.Command
9798 original query accepts an %[1]s$endCursor: String%[1]s variable and that it fetches the
9899 %[1]spageInfo{ hasNextPage, endCursor }%[1]s set of fields from a collection.
99100
101+ The %[1]s--jq%[1]s option accepts a query in jq syntax and will print only the resulting
102+ values that match the query. This is equivalent to piping the output to %[1]sjq -r%[1]s,
103+ but does not require the jq utility to be installed on the system. To learn more
104+ about the query syntax, see: https://stedolan.github.io/jq/manual/v1.6/
105+
100106 With %[1]s--template%[1]s, the provided Go template is rendered using the JSON data as input.
101107 For the syntax of Go templates, see: https://golang.org/pkg/text/template/
102108
@@ -124,6 +130,9 @@ func NewCmdApi(f *cmdutil.Factory, runF func(*ApiOptions) error) *cobra.Command
124130 # opt into GitHub API previews
125131 $ gh api --preview baptiste,nebula ...
126132
133+ # print only specific fields from the response
134+ $ gh api repos/:owner/:repo/issues --filter '.[].title'
135+
127136 # use a template for the output
128137 $ gh api repos/:owner/:repo/issues --template \
129138 '{{range .}}{{.title}} ({{.labels | pluck "name" | join ", " | color "yellow"}}){{"\n"}}{{end}}'
@@ -172,15 +181,29 @@ func NewCmdApi(f *cmdutil.Factory, runF func(*ApiOptions) error) *cobra.Command
172181
173182 if c .Flags ().Changed ("hostname" ) {
174183 if err := ghinstance .HostnameValidator (opts .Hostname ); err != nil {
175- return & cmdutil.FlagError {Err : fmt .Errorf ("error parsing --hostname: %w" , err )}
184+ return & cmdutil.FlagError {Err : fmt .Errorf ("error parsing ` --hostname` : %w" , err )}
176185 }
177186 }
178187
179188 if opts .Paginate && ! strings .EqualFold (opts .RequestMethod , "GET" ) && opts .RequestPath != "graphql" {
180- return & cmdutil.FlagError {Err : errors .New (`the '--paginate' option is not supported for non-GET requests` )}
189+ return & cmdutil.FlagError {Err : errors .New ("the `--paginate` option is not supported for non-GET requests" )}
190+ }
191+
192+ if err := cmdutil .MutuallyExclusive (
193+ "the `--paginate` option is not supported with `--input`" ,
194+ opts .Paginate ,
195+ opts .RequestInputFile != "" ,
196+ ); err != nil {
197+ return err
181198 }
182- if opts .Paginate && opts .RequestInputFile != "" {
183- return & cmdutil.FlagError {Err : errors .New (`the '--paginate' option is not supported with '--input'` )}
199+
200+ if err := cmdutil .MutuallyExclusive (
201+ "only one of `--template`, `--jq`, or `--silent` may be used" ,
202+ opts .Silent ,
203+ opts .FilterOutput != "" ,
204+ opts .Template != "" ,
205+ ); err != nil {
206+ return err
184207 }
185208
186209 if runF != nil {
@@ -201,6 +224,7 @@ func NewCmdApi(f *cmdutil.Factory, runF func(*ApiOptions) error) *cobra.Command
201224 cmd .Flags ().StringVar (& opts .RequestInputFile , "input" , "" , "The `file` to use as body for the HTTP request" )
202225 cmd .Flags ().BoolVar (& opts .Silent , "silent" , false , "Do not print the response body" )
203226 cmd .Flags ().StringVarP (& opts .Template , "template" , "t" , "" , "Format the response using a Go template" )
227+ cmd .Flags ().StringVarP (& opts .FilterOutput , "jq" , "q" , "" , "Query to select values from the response using jq syntax" )
204228 cmd .Flags ().DurationVar (& opts .CacheTTL , "cache" , 0 , "Cache the response, e.g. \" 3600s\" , \" 60m\" , \" 1h\" " )
205229 return cmd
206230}
@@ -332,7 +356,13 @@ func processResponse(resp *http.Response, opts *ApiOptions, headersOutputStream
332356 responseBody = io .TeeReader (responseBody , bodyCopy )
333357 }
334358
335- if opts .Template != "" {
359+ if opts .FilterOutput != "" {
360+ // TODO: reuse parsed query across pagination invocations
361+ err = filterJSON (opts .IO .Out , responseBody , opts .FilterOutput )
362+ if err != nil {
363+ return
364+ }
365+ } else if opts .Template != "" {
336366 // TODO: reuse parsed template across pagination invocations
337367 err = executeTemplate (opts .IO .Out , responseBody , opts .Template , opts .IO .ColorEnabled ())
338368 if err != nil {
0 commit comments