Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

github-review-poller

Get a Slack DM when a GitHub pull request is waiting on your review.

A self-contained alternative for when the official GitHub Slack app isn't set up on a repository you review for. It runs entirely from your own account — a GitHub token and a Slack delivery target — so it needs no configuration on the repository side.

Runs on macOS, Linux, and Windows. Python 3.8+, standard library only: no pip, no venv, no dependencies.

How it works

Every couple of minutes it asks GitHub which open PRs are waiting on you:

is:open is:pr archived:false review-requested:@me
is:open is:pr archived:false team-review-requested:<org>/<team>   (per team)

New results get a Slack message. Results that disappear (you reviewed it, or the request was withdrawn) are forgotten, so a later re-request notifies again.

Both queries matter. review-requested:@me does not match PRs where a team you belong to was asked to review. If you only ran the first query you'd have a tool that looks like it works while silently missing a whole class of request. Put your teams in config.json.

Setup

git clone <this repo>
cd github-review-poller
python3 install.py          # Windows: py install.py

The installer walks through the three things it needs. Details below if you'd rather do it by hand or something goes wrong.

1. GitHub token

A classic PAT with the repo scope, from https://github.com/settings/tokens. Add read:org if you want the installer to list your teams for you.

The most common failure: if the repo is in an org that enforces SSO, the token must be SSO-authorized for that org — on the token's settings page, Configure SSO. Without it, private repos return zero results with no error, so the poller looks like it's working and finds nothing. Run python3 poller.py --check, which tests for this explicitly.

2. Slack delivery

Three modes. workflow_webhook is the default because it's built entirely from native Slack steps, so there's no app to install.

workflow_webhook — Workflow Builder DMs you (recommended)

In Slack: Automations → Workflows → New Workflow

  1. Trigger: From a webhook
  2. Add a variable named exactly text, type Text
  3. Add step: Send a message to a person → choose yourself → insert the {text} variable as the message body
  4. Publish, then copy the webhook URL

Requires a paid Slack plan (Workflow Builder isn't on Free). Webhook workflows are available to members by default, though a workspace can turn that off — if "From a webhook" isn't among the triggers, that setting is why.

Slack limits these webhooks to 1 request/second and rejects nested JSON. Both are handled: sends are paced, and the payload is flat.

Want richer messages? Declare variables named repo, number, title, url, author, age, draft on the trigger and set "include_fields": true in config.json. Every declared variable must exist or Slack rejects the request.

bot_token — your own Slack app

Create an app with the chat:write bot scope, install it, and supply the bot token plus your own member ID (Profile → ⋯ → Copy member ID, looks like U01ABCDEF). Best formatting (Block Kit), at the cost of having an app to set up.

incoming_webhook — private channel fallback

An incoming webhook is bound to the channel chosen at install time and cannot DM you — that's a Slack limitation, not an oversight here. Create a private channel, point a webhook at it, and set the channel to All messages so it still pings you.

3. Scheduling

install.py sets this up for you, per platform:

OS Mechanism Inspect it with
macOS launchd agent, StartInterval launchctl print gui/$(id -u)/com.github-review-poller
Linux systemd user timer systemctl --user list-timers github-review-poller.timer
Linux (no systemd) crontab entry crontab -l
Windows Task Scheduler, run via pythonw.exe so no console window flashes schtasks /query /tn GitHubReviewPoller

On Linux, run loginctl enable-linger $USER if you want it to keep polling while you're logged out.

None of these fire while the machine is asleep; each runs shortly after wake.

Usage

python3 poller.py --check              # diagnose everything, notify nothing
python3 poller.py --check --post-test  # ...and send one real test message
python3 poller.py --dry-run            # print what would be sent; writes nothing
python3 poller.py --seed               # adopt the current backlog silently
python3 poller.py --seed --announce    # ...but post one summary of it first
python3 poller.py                      # one poll (what the scheduler runs)
python3 poller.py --watch              # poll forever, in the foreground
python3 poller.py -v                   # include debug lines

The first run seeds silently — it adopts everything already outstanding without notifying, so setting this up doesn't dump your whole backlog into Slack. Only requests that arrive afterwards ping you.

Configuration

config.json in the config directory (see --check for the exact path). It holds no secrets.

Key Default Meaning
teams [] "org/team" slugs to watch. Omitted teams are never noticed.
ignore_drafts false Skip draft PRs
interval_seconds 120 Poll interval (floor: 30)
slack.mode workflow_webhook workflow_webhook, bot_token, or incoming_webhook
slack.include_fields false Send all flat variables, not just text
slack.user_id "" Your U… ID; required for bot_token only

Secrets

Resolved environment variable first, then file:

  1. GRP_GITHUB_TOKEN / GRP_SLACK_TARGET
  2. secrets.json in the config directory, written 0600

On Windows permissions follow NTFS ACLs, so secrets.json is not chmod-protected — treat it as readable by your Windows account.

If you prefer env vars, set them before running install.py: the values are baked into the scheduled job, because schedulers otherwise run with a nearly empty environment and the job would silently find no credentials.

Where files live

macOS Linux Windows
config ~/Library/Application Support/… $XDG_CONFIG_HOME or ~/.config/… %APPDATA%\…
state …/state $XDG_STATE_HOME or ~/.local/state/… %LOCALAPPDATA%\…\state
logs ~/Library/Logs/… …/state/logs %LOCALAPPDATA%\…\logs

Override with GRP_CONFIG_DIR, GRP_STATE_DIR, GRP_LOG_DIR.

Troubleshooting

Start with python3 poller.py --check. Then the log file (path is in --check).

No notifications at all, and --check shows 0 results for the direct query. Almost always the SSO authorization above. Confirm by opening the same search on github.com — if the website shows PRs the token doesn't, it's SSO or a missing repo scope.

Nothing since I scheduled it, but manual runs work. The scheduled job runs with a different environment. If your secrets come from env vars, re-run install.py with them set so they're written into the job definition.

--check says a query "filter ignored". A team-review-requested slug that GitHub can't resolve doesn't return zero — it silently drops the qualifier and matches every open PR on GitHub (verified: ~85,000,000 results). The poller refuses any query returning more than 200 results rather than sending you hundreds of messages. Fix or remove that team in config.json. Direct-request results are unaffected; the bad team is skipped and logged.

Team reviews aren't showing up. Check teams in config.json and that each slug is org/team exactly as it appears in the team URL.

Duplicate messages. Expected if two machines poll at the same time — state is per-machine by design. Run it on one machine, or accept the duplicates.

A message failed to send. That PR is deliberately not recorded, so the next run retries it rather than dropping it silently.

Tests

python3 -m unittest discover -s tests -v

45 tests, no network access, no credentials, nothing touched outside a temp directory. Worth running on each OS you install on — it covers the paths, atomic state writes, and flood guard that differ across platforms.

Uninstall

python3 install.py --uninstall     # removes the scheduled job

Then delete the config and state directories (--check lists them) to remove the token and webhook URL.

About

Get a Slack DM when a GitHub pull request is waiting on your review. Cross-platform, stdlib-only Python.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages