Re-arm Dependabot PRs that GitHub silently disarmed - #18
Conversation
Auto-merge is armed on PR open, then GitHub disables it when a PR-triggered workflow completes with a skipped job. Nothing re-arms it and every run still reports success, so green PRs accumulate. Measured on appeler/pranaam, where nine had. Adds a scheduled sweep that re-arms or lands stranded PRs and logs a line for each one. Eligibility is still decided once, by fetch-metadata in the pull_request context, and recorded as a label the sweep reads back. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e162f461d8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| - name: Record the verdict on the PR | ||
| if: steps.gate.outputs.eligible == 'true' | ||
| env: | ||
| PR_URL: ${{ github.event.pull_request.html_url }} |
There was a problem hiding this comment.
Grant issues permission before managing repository labels
On every eligible PR, this command attempts to create or update a repository label, but the workflow's explicit permissions block omits issues: write; unspecified permissions are set to none. GitHub's Create a label endpoint requires Issues write permission, and gh label create --help confirms that --force updates an existing label too, so this fails even after the label exists. Because the shell exits on that failure, neither the label nor auto-merge is applied, and the sweep subsequently treats the PR as ineligible.
Useful? React with 👍 / 👎.
| acted=$((acted + 1)) ;; | ||
| merge) | ||
| echo "merging #$n" | ||
| gh pr merge "$n" --squash --delete-branch || echo "::warning::could not merge #$n" |
There was a problem hiding this comment.
Preserve push workflows when directly merging PRs
When the sweep sees terminal-green checks, this immediately merges using the repository GITHUB_TOKEN. GitHub does not create new workflow runs for events caused by GITHUB_TOKEN, so the resulting push to main will not start the push-only deployment path in .github/workflows/docs.yml (its deploy job is skipped for PR events). Consequently, dependencies or Actions affecting documentation can land without rebuilding/deploying the site; use a token whose events trigger workflows or explicitly dispatch the required post-merge workflows.
Useful? React with 👍 / 👎.
zizmor's excessive-permissions audit rejects a workflow-level write grant once there is more than one job: it applies to every job whether or not that job needs it. Both jobs here do need both scopes, but they now say so themselves. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Nine green Dependabot PRs had accumulated on
appeler/pranaamwhile every auto-merge run reported success. The cause, from run 30836798988 (PR #29):Auto-merge was armed. GitHub disarmed it once a PR-triggered workflow finished with a skipped job, and
on: pull_requestnever fires again — so nothing re-arms, ever. calibre and the others have not hit this only because they happen to have no skipped job in a PR-triggered workflow. The automation is green throughout.What changed
A
schedule:trigger (every 3h) that re-arms stranded PRs. It converges regardless of why GitHub disarmed, which aworkflow_runtrigger racing the disarm event would not.Eligibility is still decided exactly once, by
dependabot/fetch-metadatain thepull_requestcontext where it is reliable — the verdict is recorded as anautomerge-eligiblelabel and read back by the sweep. Deriving it a second time from a branch name would not recover major-versus-minor, and two copies of the rule would drift.The sweep reads
statusCheckRollup, notmergeStateStatusalone:CLEANis GitHub's opinion about mergeability, and this job needs the stronger fact that every check is terminal and none failed before it merges anything directly.It logs a line per PR — armed / merged / ineligible / checks-failing / already-armed — and warns when an eligible PR it cannot act on has been open past
STALE_AFTER_HOURS. A sweep that quietly does nothing would reproduce the bug it fixes.Verified
Decision logic run against the five real open pranaam PRs and six fixtures:
The five real ones are Python-ecosystem majors and the sweep refuses all of them, which is the negative check.
🤖 Generated with Claude Code