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:

github dmenu demo

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.