Open GitHub repository using dmenu
One thing I do many times every day is navigating to GitHub repositories I’m part of. I put together a shell script that uses dmenu to speed up the process:
The script uses GitHub’s REST API to get a list of repositories that the authenticated user has permission to access. Querying GitHub via the REST API is not instantaneous. Moreover, responses are returned in units of “pages” with max of 100 results per page. If user has more repositories the script has to make multiple queries to retrieve each page. To deal with this, the script caches the list of repositories and regenerates it in the background if the cache is too old:
#!/bin/bash
# Expects to find GutHub authentication in ~/.netrc
github_api_accept_header="Accept: application/vnd.github.v3+json"
rest_request=https://api.github.com/user/repos?per_page=100\&affiliation=owner,collaborator,organization_member\&sort=push
cache_file="$HOME/.cache/github_repos_dmenu"
function get_repos_one_page {
curl -s --netrc "${rest_request}&page=$1" -H "${github_api_accept_header}" | jq ".[] | {name: .full_name, url: .html_url}"
}
function get_repos_all_pages {
# Use pagination if necessary
last_page=`curl -s -I --netrc ${rest_request} -H "${github_api_accept_header}" | grep -oP '(?<=page=)(\d+)(?=>; rel="last")'`
if [ -z "$last_page" ]; then
get_repos_one_page 1
else
source `which env_parallel.bash`
seq $last_page | env_parallel -k get_repos_one_page {}
fi
}
function generate_cache {
cache=$(get_repos_all_pages)
echo $cache > $cache_file
}
function maybe_regenerate_cache {
if test `find $cache_file -mmin +2`
then
generate_cache
fi
}
[ ! -e $cache_file ] && generate_cache
selected=$(cat $cache_file | jq .name | tr -d \" | dmenu)
if [ -n "$selected" ]; then
cat $cache_file | jq ". | select(.name | contains(\"$selected\")) | .url" | tr -d \" | xargs xdg-open 2>/dev/null
i3-msg --quiet [urgent=latest] focus 2>/dev/null
fi
maybe_regenerate_cache &
How to use
Make sure your ~/.netrc
includes your GitHub username/token:
machine api.github.com
login GITHUB_USERNAME
password GITHUB_PERSONAL_TOKEN
You might also want to look at the available parameters in GitHub’s API and change REST_REQUEST
variable for more granular filtering of what repositories are listed.
You would probably want to set up a keybinding to invoke the script, but that bit depends on your environment.
Dependencies: The main dependencies are curl
for making REST requests, and jq
for parsing the JSON responses. In the script, I also make use of GNU parallel
when pagination is required. There is also an i3-specific command to bring the browser into focus after selecting a repo. These bits are not essential and can be removed if necessary.