DEV Community

Marc Dougherty
Marc Dougherty

Posted on • Updated on

Using the Github cli with Multiple Repos

I have been using the Github CLI for a while now, and
I've found it to be really great when working in the context of a single
repository. But what happens when you're responsible for work in dozens of
repos? Keeping tabs on many repos can be done, thanks to the gh api
subcommand, and aliases!

gh api allows you to call any github api endpoint, and for my particular
needs, the search/issues endpoint is the most useful, as it searches both
issues and PRs.

There are two different ways to format responses, either with the --jq flag,
which uses jq syntax or --template
which uses Go's text/template syntax. I
found prototyping with the jq syntax to be nice, but the color and formatting
choices in the --template flag won me over.

Note that the --template args in the below examples are all the same, and they
produce output like this (but with some tasteful terminal colors, which do not
appear in markdown):

[  98] chore(deps): update dependency maven to v3.6 (15 days ago)
Enter fullscreen mode Exit fullscreen mode

More information about formatting output can be found in the gh formatting

My issues/PRs that need followup

In my job, my team is responsible for the care and feeding of many different
public github repositories, which requires a lot of issue triage, and pr
followups. Switching to each of these contexts to run gh issues and
gh status is pretty tiresome, so I made a command that uses gh api to search
for open issues and PRs in any repo that are assigned to me:

gh api -XGET search/issues -f q='assignee:@me is:open  ' \
  --template '{{range .items -}}[{{.number | printf "%5.f" |autocolor "blue" }}] {{.title}} ({{ timeago .updated_at | autocolor "yellow+d" }}) {{printf "\n  " }}{{.html_url}} {{print "\n" -}}{{end}}'
Enter fullscreen mode Exit fullscreen mode

This command is not much fun to type, so I've created an alias within the gh tool (not to be confused with shell aliases). However, using the gh alias set command would require escaping the quotation marks, I chose to edit the config file directly - it lives at ~/.config/gh/config.yaml on my linux machine. Adding the following block to the aliases list will create the alias:

    mine: |
        api -XGET search/issues -f q="assignee:@me is:open"
        --template '{{range .items -}}
        [{{.number | printf "%4.f" |autocolor "blue" }}] {{.title}} ({{timeago .updated_at | autocolor "yellow+d" }})
        {{print "\n  " }}{{.html_url}} {{print "\n" -}}
Enter fullscreen mode Exit fullscreen mode

(Note that the yaml heredoc syntax (|) is used to allow a multi-line string.
Ensure the indentation is the same for all lines, or there may be problems
parsing your config!)

Now I can see all my assigned issues and PRs by running gh mine!

Unclaimed team reviews

Tracking issues and PRs that are waiting on the team's review (that nobody has
claimed yet) can be done with a similar approach. Note that you'll need to update
the search query to use your own Github Organization and Team in the query below.

gh api -XGET search/issues -f q='team-review-requested:yourorg/yourteam is:open -review:approved no:assignee' \
--template '{{range .items -}}[{{.number | printf "%4.f" |autocolor "blue" }}] {{.title}} ({{timeago .updated_at | autocolor "yellow+d" }}) {{printf "\n  " }}{{.html_url}} {{print "\n" -}}{{end}}'
Enter fullscreen mode Exit fullscreen mode

or ready for your config.yml:

    teamreviews: |
        api -XGET search/issues -f q="team-review-requested:yourorg/yourteam is:open -review:approved no:assignee"
        --template '{{range .items -}}
        [{{.number | printf "%4.f" |autocolor "blue" }}] {{.title}} ({{timeago .updated_at | autocolor "yellow+d" }})
        {{printf "\n  " }}{{.html_url}} {{print "\n" -}}
Enter fullscreen mode Exit fullscreen mode

Other useful searches

By replacing the search query (the q parameter) with another github search
, you can use this method to display other handy results.

  • Reviews I approved, but are not merged: reviewed-by:@me review:approved is:open
  • Incomplete reviews I am assigned to directly: user-review-requested:@me -review:approved (note the - prefix, which will match un-approved PRs)

I found myself using the same display with different search queries, so I ended
up making an alias for doing arbitrary searches:

    # global search, given a *quoted* github search string.
    gsearch: |
        api -XGET search/issues -f q="$1"
        --template '{{range .items -}}
        [{{.number | printf "%4.f" |autocolor "green" }}] {{.title}} ({{timeago .updated_at | autocolor "yellow+d" }})
        {{- printf "\n  " }}{{.html_url}} {{println -}}
Enter fullscreen mode Exit fullscreen mode

Future directions

I would like to have a bit of extra information about these PRs, like whether or
not their required checks are passing, all in the same output. To achieve this,
I'd probably have to write a
To avoid replicating existing gh functionality, there's a go-gh

Do you use other github searches or gh tricks to keep tabs on your work? Tell
me about it in the comments!

Top comments (0)