Skip to content

Instantly share code, notes, and snippets.

@peterhellberg
Last active September 8, 2026 09:54
Show Gist options
  • Select an option

  • Save peterhellberg/d8af898904cdc57e83f221a27dfbe07d to your computer and use it in GitHub Desktop.

Select an option

Save peterhellberg/d8af898904cdc57e83f221a27dfbe07d to your computer and use it in GitHub Desktop.
A gh prs alias
#!/usr/bin/env bash
# gh prs — list open PRs with their review status, which github.com/<owner>/<repo>/pulls
# no longer shows (the "Approved" checkmark was removed from the list view in late 2025).
#
# Status is derived from the review lists, not reviewDecision: GitHub leaves reviewDecision
# null in repos whose branch has no rule requiring an approval, even when approvals exist.
#
# "changes" and "commented" come from latestReviews, but "approved" comes from the full
# reviews history: latestReviews holds only the single most recent review per author, so a
# review comment left after an approval hides that approval. A later COMMENTED review does
# not retract an approval — only CHANGES_REQUESTED or a dismissal does, and an approval is
# therefore ignored when that author's latestReviews state is CHANGES_REQUESTED or DISMISSED.
#
# Status column: approved (green) / changes (red) / required (yellow) / pending (yellow,
# reviewer requested, nothing submitted) / commented (cyan) / draft (dim) / — (dim, nothing pending).
# The PR number is an OSC 8 hyperlink, but only when stdout is a terminal, so `gh prs | grep` stays clean.
# Run this script once to install the alias; then: gh prs [--repo owner/name] [any other gh pr list flags]
set -euo pipefail
gh alias set --clobber --shell prs - <<'EOF'
if [ -t 1 ]; then
NUM='printf "\033]8;;%s\033\\#%v\033]8;;\033\\" .url .number'
else
NUM='printf "#%v" .number'
fi
gh pr list --json number,reviewDecision,title,reviewRequests,latestReviews,reviews,isDraft,url --template "{{range .}}{{\$approved := false}}{{\$changes := false}}{{\$commented := false}}{{\$latest := .latestReviews}}{{range \$latest}}{{if eq .state \"CHANGES_REQUESTED\"}}{{\$changes = true}}{{else if eq .state \"COMMENTED\"}}{{\$commented = true}}{{end}}{{end}}{{range \$r := .reviews}}{{if eq \$r.state \"APPROVED\"}}{{\$stale := false}}{{range \$l := \$latest}}{{if and (eq \$l.author.login \$r.author.login) (or (eq \$l.state \"CHANGES_REQUESTED\") (eq \$l.state \"DISMISSED\"))}}{{\$stale = true}}{{end}}{{end}}{{if not \$stale}}{{\$approved = true}}{{end}}{{end}}{{end}}{{if .isDraft}}{{tablerow (autocolor \"black+h\" ($NUM)) (autocolor \"black+h\" \"draft\") (autocolor \"black+h\" .title)}}{{else if \$changes}}{{tablerow ($NUM) (autocolor \"red\" \"changes\") .title}}{{else if \$approved}}{{tablerow ($NUM) (autocolor \"green\" \"approved\") .title}}{{else if eq .reviewDecision \"REVIEW_REQUIRED\"}}{{tablerow ($NUM) (autocolor \"yellow\" \"required\") .title}}{{else if .reviewRequests}}{{tablerow ($NUM) (autocolor \"yellow\" \"pending\") .title}}{{else if \$commented}}{{tablerow ($NUM) (autocolor \"cyan\" \"commented\") .title}}{{else}}{{tablerow ($NUM) (autocolor \"black+h\" \"—\") .title}}{{end}}{{end}}" "$@"
EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment