Now that GitHub released v1.0 of the gh
cli tool, and this
is all over HN, it might make sense to write a note about my clumsy
aliases and shell functions I cobbled together in the past
month. Background story is that my dayjob moved to GitHub
coming from Bitbucket. From my point of view the WebUI for
Bitbucket is mediocre, but the one at GitHub is just awful
and painful to use, especially for PR processing. So I longed
for the terminal and ended up with
gh
and
wtfutil
as a dashboard.
The setup we have is painful on its own, with several orgs and repos which are more like monorepos covering several corners of infrastructure, and some which are very focused on a single component. All workflows are anti GitHub workflows, so you must have permission on the repo, create a branch in that repo as a feature branch, and open a PR for the merge back into master.
gh functions and aliases
# setup a token with perms to everything, dealing with SAML is a PITA
export GITHUB_TOKEN="c0ffee4711"
# I use a light theme on my terminal, so adjust the gh theme
export GLAMOUR_STYLE="light"
#simple aliases to poke at a PR
alias gha="gh pr review --approve"
alias ghv="gh pr view"
alias ghd="gh pr diff"
### github support functions, most invoked with a PR ID as $1
#primary function to review PRs
function ghs {
gh pr view ${1}
gh pr checks ${1}
gh pr diff ${1}
}
# very custom PR create function relying on ORG and TEAM settings hard coded
# main idea is to create the PR with my team directly assigned as reviewer
function ghc {
if git status | grep -q 'Untracked'; then
echo "ERROR: untracked files in branch"
git status
return 1
fi
git push --set-upstream origin HEAD
gh pr create -f -r "$(git remote -v | grep push | grep -oE 'myorg-[a-z]+')/myteam"
}
# merge a PR and update master if we're not in a different branch
function ghm {
gh pr merge -d -r ${1}
if [[ "$(git rev-parse --abbrev-ref HEAD)" =~ (master|main) ]]; then
git pull
fi
}
# get an overview over the files changed in a PR
function ghf {
gh pr diff ${1} | diffstat -l
}
# generate a link to a commit in the WebUI to pass on to someone else
# input is a git commit hash
function ghlink {
local repo="$(git remote -v | grep -E "github.+push" | cut -d':' -f 2 | cut -d'.' -f 1)"
echo "https://github.com/${repo}/commit/${1}"
}
Update 2020-10-14: create pr from a branch with multiple commits
Bitbucket had a nice PR creation functionality by default: If you created
a PR from a branch with multiple commits, it derived the titel from the
branch name and create a PR discribtion based on all commit messages. I
replicated this behaviour, and open the description text in an editor (via $EDITOR
)
for you to edit. Feels more native, like a git commit
, now. In the honor of
Bitbucket it currently derives the PR title from the branch name, though I'm
wondering if that should be changed to something more helpful. Lacking ideas at
the moment.
function ghbbc {
if git status | grep -q 'Untracked'; then
echo "ERROR: untracked files in branch"
git status
return 1
fi
local commitmsg="$(mktemp ${XDG_RUNTIME_DIR}/ghbbc_commit.XXXXXXX)"
git log --pretty=format:"%B" origin.. > ${commitmsg}
eval "${EDITOR} ${commitmsg}"
git push --set-upstream origin HEAD
gh pr create \
-r "$(git remote -v | grep push | grep -oE 'myorg-[a-z]+')/myteam" \
-b "$(cat ${commitmsg})" \
-t "$(git rev-parse --abbrev-ref HEAD)"
rm ${commitmsg}
wtfutil
I have a terminal covering half my screensize with small dashboards listing PRs for the repos I care about. For other repos I reverted back to mail notifications which get sorted and processed from time to time. A sample dashboard config looks like this:
github_admin:
apiKey: "c0ffee4711"
baseURL: ""
customQueries:
othersPRs:
title: "Pull Requests"
filter: "is:open is:pr -author:hoexter -label:dependencies"
enabled: true
enableStatus: true
showOpenReviewRequests: false
showStats: false
position:
top: 0
left: 0
height: 3
width: 1
refreshInterval: 30
repositories:
- "myorg/admin"
uploadURL: ""
username: "hoexter"
type: github
The -label:dependencies
is used here to filter out dependabot PRs in the
dashboard.
Workflow
Look at a PR with ghv $ID
, if it's ok ACK it with gha $ID
.
Create a PR from a feature branch with ghc
and later on merge it with ghm $ID
.
The $ID
is retrieved from looking at my wtfutil based dashboard.
Security Considerations
The world is full of bad jokes. For the WebUI access I've the full array of pain with SAML auth, which expires too often, and 2nd factor verification for my account backed by a Yubikey. But to work with the CLI you basically need an API token with full access, everything else drives you insane. So I gave in and generated exactly that. End result is that I now have an API token - which is basically a password - which has full power, and is stored in config files and environment variables. So the security features created around the login are all void now. Was that the aim of it after all?