alex/pr-tracker

★ 4Forks 0SwiftGitHub ↗Compare

README

PR Tracker

A small native macOS app for tracking your own open pull requests (GitHub) and changes (Gerrit), built per the design spec in "PR Tracker - Design Spec" (Grouped Inbox direction). Three operations: add a PR/CL by pasting its URL, see everything grouped by what it's waiting on, and mark one change as depending on another.

Built with SwiftUI via Swift Package Manager — no Xcode project required.

Requirements

  • macOS 14+
  • Swift toolchain (Command Line Tools are enough)
  • gh CLI, authenticated (gh auth login) — the app uses gh auth token for GitHub API access
  • For Gerrit, nothing extra on public hosts. Private hosts (or private changes) are read with the credentials in ~/.gitcookies, the same file git-codereview and git cl use (Gerrit → Settings → HTTP Credentials).

Build & run

./build.sh
open "build/PR Tracker.app"

(swift run also works for quick iteration, without the app bundle niceties.)

Usage

  • Add a PR — copy a PR link on GitHub (github.com/owner/repo/pull/123) or a change link on any Gerrit host (host/c/project/+/123, a trailing patchset number is fine), then press ⌘V anywhere in the app (or click the paste field). A popover previews the fetched change; one click adds it to the right group.
  • Groups — every PR lands in exactly one derived state: Waiting on you (changes requested, unresolved comments, failing checks, or draft), Waiting on review, Waiting on CI, Blocked (user-set dependency), or Merged. The sidebar filters by group or by repository. For Gerrit changes the attention set decides "Waiting on you" vs "Waiting on review"; CI comes from the host's verification label (Verified, LUCI-TryBot-Result, Presubmit-*-Verified), with Commit-Queue +1 shown as running.
  • Dependencies — right-click a PR → "Blocked by" → pick another tracked PR. The blocked PR nests under its blocker with a connector; when the blocker merges it returns to its derived state automatically. Cycles are disabled at pick time. Gerrit stacks are linked automatically: each change nests under the change it's rebased on whenever that one is tracked too (re-derived on every refresh, so rebases follow), and the add popover offers to add the whole stack at once. Setting or clearing "Blocked by" by hand on a Gerrit change turns the automatic link off for that change.
  • Other row actions — double-click (or right-click) to open in the browser, Copy URL, Mark as Merged, Remove from Tracker.
  • Refresh — every tracked PR is re-fetched every 5 minutes, on app activation, via the toolbar refresh button, or with ⌘R. States are always derived, never hand-set (except dependency, mark-as-merged, and remove).
  • Merged/closed PRs are kept for reference for 3 days, then pruned.

App icon

Resources/AppIcon.icns is generated on first build by Tools/make-icon.swift (headless AppKit drawing + iconutil). Delete the .icns and rebuild to regenerate it.

Data

Tracked PRs persist to ~/Library/Application Support/PRTracker/prs.json.

Debug

PRTRACKER_SNAPSHOT=/tmp/shot.png writes a PNG of the app's windows a few seconds after launch (no screen-recording permission needed); PRTRACKER_LIGHT=1 forces light appearance; PRTRACKER_PASTE=<url>[,<url>…] simulates the paste-to-add flow for each URL, and PRTRACKER_AUTOADD=1 confirms each preview; PRTRACKER_DATA_DIR=<dir> redirects the data file. Useful for headless UI verification.

Contributors

alex

Issues