A Go CLI tool that monitors open pull requests on GitHub and sends reminder messages to a Slack channel, helping teams keep on top of PRs waiting for review.
The tool runs a step-by-step pipeline and logs every action to the terminal:
1. Fetch all open pull requests from the configured repository.
2. Filter PRs through three sequential gates, logging each excluded PR with its reason:
- Draft — draft PRs are always excluded.
- Labels — if
PR_LABELSis configured, only PRs carrying at least one of those labels pass through. - Approvals — if
PR_MINIMUM_APPROVALSis configured, PRs that already have enough valid approvals are excluded. An approval counts only if the reviewer's last state-changing review isAPPROVEDand they don't have a pending re-review request.
3. Calculate how long each remaining PR has been waiting for review (based on the most recent matching labeled event, falling back to the PR creation date), and check its combined CI/CD status.
4. Send a Slack message with two sections:
- PRs waiting for review — PRs that passed all filters.
- PRs with failing CI — subset of the above whose combined check status is
failureorerror.
📋 Fetching open pull requests...
✅ Found 9 open PR(s)
🔍 Filtering PRs...
✗ #1687 [Branch Integração] PauseAds (draft)
Removed 1 draft PR(s) → 8 remaining
✗ #1703 [DPEE-149] Habilitar menu de idiomas no ao vivo (no required label)
Removed 1 PR(s) without required label(s) [ReadyForReview] → 7 remaining
✗ #1719 [DMD-207] Atualização do IMA SDK tvOS (2/2 approvals)
✗ #1707 [DPEPT-61] Migração para a v7 do youbora (2/2 approvals)
Removed 2 PR(s) with ≥2 approval(s) → 5 remaining
⏱ Calculating wait times and checking CI status...
#1700 My PR title — waiting 5 days ci: ✅
#1701 Another PR — waiting 1 day ci: ❌
📣 Slack message:
*🔎 PRs aguardando revisão:*
<https://github.com/org/repo/pull/1700|#1700 My PR title> — @alice — aguardando há 5 dias 🚨
<https://github.com/org/repo/pull/1701|#1701 Another PR> — @bob — aguardando há 1 dia
*🔴 PRs com checks falhando:*
<https://github.com/org/repo/pull/1701|#1701 Another PR> — @bob
🚀 Sending Slack message...
✅ Message sent!| Variable | Required | Description |
|---|---|---|
GITHUB_TOKEN |
✅ | GitHub personal access token used to call the GitHub API. |
GITHUB_REPOSITORY |
✅ | Repository to monitor in owner/repo format (e.g. my-org/my-repo). |
PR_REMINDER_SLACK_WEBHOOK_URL |
✅ | Slack incoming webhook URL where reminders are posted. |
PR_LABELS |
☑️ | Comma-separated list of labels that mark a PR as waiting for review (e.g. ReadyForReview,needs-review). When empty, no label filtering is applied. |
PR_MINIMUM_APPROVALS |
☑️ | Minimum number of valid approvals for a PR to be excluded from the reminder. Defaults to 0 (no threshold). |
git clone https://github.com/agripinogabriel/pull-request-reminder.git
cd pull-request-reminderThe following properties must be defined on the running machine as enviroment vars:
GITHUB_TOKEN=ghp_yourtoken
GITHUB_REPOSITORY=my-org/my-repo
PR_REMINDER_SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxx/yyy/zzz
PR_LABELS=ReadyForReview,needs-review
PR_MINIMUM_APPROVALS=2make runOr directly with Go:
go run main.gogo test ./....
├── main.go # Entry point — filtering pipeline and Slack dispatch
└── internal/
├── env/ # Environment variable loading
├── github/ # GitHub API client (PRs, events, reviews, commit status)
├── reviewwait/ # Determines which PRs are waiting for review and for how long
├── approval/ # Counts valid approvals per PR
├── cistatus/ # Evaluates combined CI/CD check status
├── slack/ # Sends messages via Slack incoming webhook
└── slackformat/ # Formats PR statuses into Slack messagesThe message is split into two sections (each omitted when empty):
PRs waiting for review — the PR number and title form a clickable link; author and wait time are shown outside the link:
*🔎 PRs aguardando revisão:*
<https://github.com/…|#1700 My PR title> — @alice — aguardando há 5 dias 🚨The 🚨 emoji is added when a PR has been waiting for more than 3 days.
PRs with failing CI checks:
*🔴 PRs com checks falhando:*
<https://github.com/…|#1701 Broken build PR> — @bob