Pull Request Re-Review Gap Ledger
Pricing
from $10.00 / 1,000 run starteds
Pull Request Re-Review Gap Ledger
Finds each open GitHub pull request where a reviewer already reviewed, the author then pushed new commits, and nobody requested a new review. One dataset record for each pull request and reviewer pair, plus one summary for each reviewer. HTTP only, no bro
Pricing
from $10.00 / 1,000 run starteds
Rating
0.0
(0)
Developer
kingii98
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
Find each open GitHub pull request where a reviewer already reviewed, the author then pushed new commits, and nobody requested a new review.
GitHub removes a reviewer from the review request list when the reviewer submits a review. When the author then pushes a fix and does not request a new review, the pull request is in no "review requested" view, but the reviewer must still act. This Actor finds these pull requests and tells you how long each one waits.
How it works
- The Actor reads the open pull requests of each repository, the most recently updated first.
- It skips each pull request with no activity for more than
staleDaysdays. - For each other pull request, it reads the reviews, the commits and the open review requests.
- For each reviewer, it takes the last submitted review. It then compares that time with the commits that came after it.
- It writes one record for each pull request and reviewer pair, one summary for each reviewer, and one run summary.
The Actor keeps no state. Each run reads the full history again and computes each verdict again.
Verdicts
| Verdict | Meaning |
|---|---|
awaiting-re-review | The author pushed commits after the last review of the reviewer, and nobody requested a new review. This is the gap. |
requested | The reviewer is on the review request list again. The pull request shows in the normal "review requested" view. |
up-to-date | No commit came after the last review of the reviewer. |
stale-skipped | The pull request had no activity for more than staleDays days. The Actor did not read its reviews. |
Rules:
- A pending (draft) review does not count. A review that the author of the pull request wrote does not count.
- A commit by the reviewer does not need a re-review, so the Actor ignores it.
- An approval followed by new commits is
awaiting-re-review, because the approval is for old code. - A review request to a team does not name a user. It does not set
reReviewRequested. - Bot reviews are ignored unless
includeBotsis true.
Input
| Field | Default | Description |
|---|---|---|
repositories | ["pallets/click"] | 1 to 20 repositories as owner/name. |
githubToken | none | A fine-grained token that you own, with read access to pull requests and metadata only. Secret. |
reviewers | [] | Optional GitHub logins. An empty list reports all reviewers. |
staleDays | 90 | Skip a pull request with no activity for more days than this value. |
maxPullRequestsPerRepository | 200 | Read at most this number of open pull requests from each repository (1 to 200). |
includeBots | false | Also report reviews that bot accounts wrote. |
timeoutSeconds | 20 | Timeout for one GitHub API call. |
maxResponseBytes | 4000000 | Hard cap on the bytes of one GitHub API answer. |
With a token and without a token
- With
githubToken: the Actor uses the GitHub GraphQL API. One call reads 10 pull requests with their last 100 reviews, their last 100 commits and their review requests. One call costs about 1 point of the hourly budget of 5,000 points. The Actor stops while 100 points are still free and reports a partial result. The Actor can read private repositories that the token can read. - Without
githubToken: GraphQL is not available, so the Actor uses the anonymous REST API on public repositories only. It sends one call for each page of 100 pull requests, then two calls (reviews and commits) for each pull request that is not stale. The anonymous limit is 60 calls for each hour, and on the Apify platform other users can share it. The Actor stops before it spends that budget and reports a partial result.
The Actor sends the token only to api.github.com, in the Authorization header. It never writes the token to the log or to the dataset. It never changes anything on GitHub.
Output
The dataset holds three types of record. Use recordType to select them.
pull-request-reviewer (one for each pull request and reviewer pair)
| Field | Description |
|---|---|
repository | owner/name. |
number | Pull request number. |
title | Pull request title. |
url | Link to the pull request. |
author | Login of the pull request author. |
isDraft | True for a draft pull request. |
reviewer | Login of the reviewer. It is null on a stale-skipped record. |
lastReviewState | State of the last review of the reviewer: APPROVED, CHANGES_REQUESTED, COMMENTED or DISMISSED. |
lastReviewAt | Time of that review. |
lastCommitAfterReviewAt | Time of the last commit after that review. |
commitsAfterReview | Number of commits after that review. |
reReviewRequested | True when the reviewer is on the review request list now. |
hoursWaiting | Hours since the first commit after the last review. |
verdict | awaiting-re-review, requested, up-to-date or stale-skipped. |
prUpdatedAt | Last activity on the pull request. |
note | The reason for a stale-skipped verdict. |
checkedAt | Time of the run. |
reviewer-summary (one for each reviewer)
reviewer, awaitingReReview (count of awaiting-re-review pull requests), requested, upToDate, longestWaitHours, awaitingPullRequests (for example acme/web#12, the longest wait first) and checkedAt. The reviewers with the most gaps come first. Send this record to a chat channel with an Apify integration.
run-summary (one for each run)
runStatus (complete or partial), stopReason (charge-limit, rate-budget, token-rejected or null), mode (graphql or rest-anonymous), the counts pullRequestsListed, pullRequestsEvaluated, staleSkipped, pairs, awaitingReReview, reviewersWithGaps, longestWaitHours, apiRequestsSent, one status record for each repository, a note and checkedAt.
A repository that cannot be read (for example 404) gets a status in the run summary, and the other repositories continue. A gap, an unreadable repository, a refused token and a spent rate budget are results. They never make the run fail.
Pricing (pay per event)
| Event | Price | When the Actor charges it |
|---|---|---|
run-started | USD 0.01 | Once for each run, after the input is valid. |
pull-request-evaluated | USD 0.002 | Once for each open pull request that the Actor read and evaluated for all its reviewers. |
- The Actor charges for each pull request, not for each reviewer pair. A large review team does not pay more for one pull request.
- A
stale-skippedpull request and a pull request that could not be read are not charged. - Before it reads the repositories, the Actor calculates how many pull requests your maximum total charge allows. At that number it stops and reports a partial result with
stopReasoncharge-limit. The default cap of USD 2 covers about 995 pull requests. - GitHub API calls use your own token and cost you nothing inside its hourly budget.
Schedule
Run the Actor on a weekday morning schedule, for example at 08:00 in the time zone of your team. Send the reviewer summaries to a chat channel with an Apify integration. Open pull requests change each day, so the list is new each morning.
Limits
- 20 repositories and 200 open pull requests for each repository in one run.
- The Actor reads the last 100 reviews and the last 100 commits of each pull request (GraphQL), or the first and the last page of 100 (REST). A reviewer whose last review is older than that is not seen.
- A commit time is the committer date. A rebase changes that date, so a rebased pull request shows as new commits.
- The Actor does not follow redirects. A renamed repository gives an error. Use the new name.
Local development
uv syncuv run pytestuv run ruff check .