Skip to content

feat: add a version-pr-reaper reusable - #69

Open
seabbs-bot wants to merge 1 commit into
mainfrom
feat/version-pr-reaper-reusable
Open

feat: add a version-pr-reaper reusable#69
seabbs-bot wants to merge 1 commit into
mainfrom
feat/version-pr-reaper-reusable

Conversation

@seabbs-bot

Copy link
Copy Markdown
Collaborator

Upstream half of EpiAware/EpiAwarePackageTools.jl#476, which @seabbs asked to be delivered as a managed action rather than copied into every package.

Why here

An auto-increment PR goes stale when a release lands by another route, or when a later bump overtakes a pending one. Nothing closed those, so PRs and their branches accumulated — six stale branches in the kit alone at the time of writing.

The kit's PR originally added ~248 lines of inline bash to the package and to its template, so every adopting package would carry a private copy of the selection logic and a fix would mean re-syncing ten repos. The logic is identical everywhere: the same semver comparison, the same Project.toml-only safety check, the same merge-base orphan sweep. It belongs in one place.

Once this lands, the kit side reduces to a thin uses: caller plus scaffold wiring, which is also where EpiAware/EpiAwarePackageTools.jl#467 is taking the caller pins.

What it does

Two passes, both guarded:

  1. Open auto-increment PRs. Closes and deletes the branch when the proposed version is at or below the version on main, and only when the diff touches Project.toml alone — so a PR someone has built on is never discarded.
  2. Orphaned branches with no open PR (closed by hand, or never created). A branch already merged into main is safe outright. Otherwise safety is judged from the branch's merge-base with main, not main's current tip: main moves on and touches files the branch never did, so diffing against the tip makes an old, harmless branch look bigger over time.

Two deliberate changes from the kit's version

dry_run is a plain input, not second-guessed. The kit's copy computed it as github.event_name == 'workflow_dispatch' && inputs.dry_run || 'false'. In a reusable that is a trap: a caller passing dry_run: true from any other trigger would have it silently ignored and reap for real. The caller decides; this workflow honours what it is given.

Permissions are declared on the job (contents: write, pull-requests: write) rather than inherited from a top-level block, matching how the other reusables here scope them.

Both gh pr close and git push --delete absorb their own failures, so one PR that a human already closed cannot abandon the rest of the run under set -euo pipefail.

yaml.safe_load parses it, and every other workflow in the repo still parses.

This was opened by a bot. Please ping @seabbs for any questions.

An auto-increment PR goes stale when a release lands by another route, or
when a later bump overtakes a pending one. Nothing closed those, so they
accumulated along with their branches.

The selection logic belongs here rather than in each package: it is the
same semver comparison, Project.toml-only check and merge-base orphan
sweep everywhere, and a copy per package means a fix has to be re-synced
across the org.

The caller supplies the triggers and passes `dry_run` through. The
reusable does not second-guess the caller's event: a caller that wants a
preview from any trigger gets one.

Co-authored-by: Sam Abbott <contact@samabbott.co.uk>

@seabbs-review-bot seabbs-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adds a reusable workflow that closes stale auto-increment version PRs and sweeps orphaned auto-increment branches once main's version catches up. The merge-base/ancestor logic and squash-merge caveat are handled correctly, but the PR-listing step can silently under-scan on a repo with many open PRs, which then lets the orphan sweep delete a branch still backing an open PR.

Automated first pass by seabbs-review-bot (Claude sonnet), triggered by: first pass. Not a human review. Comment @seabbs-review-bot to ask for another pass: @seabbs any time, the author's agent once it has pushed changes. Add the no-review label to opt this PR out. Ping @seabbs with any questions.

: > handled_branches.txt

# Only the exact prefix the increment-version action writes.
PRS=$(gh pr list --state open --json number,headRefName \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue gh pr list defaults to --limit 30 for the whole open-PR list before the jq filter for the auto/version-increment- prefix runs. On a repo with more than 30 open PRs (plausible on a first run, since accumulated stale auto-increment PRs are exactly what this workflow exists to clear), older matching PRs beyond page 1 are silently skipped. Such a PR is then absent from handled_branches.txt, so the orphan-branch step below has no way to know it isn't orphaned and can delete its branch while the PR is still open. Add --limit 200 (or paginate) to the gh pr list call.


# A single sortable integer so 0.10.0 compares above 0.9.0,
# which plain string or float comparison gets wrong.
semver_key() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion semver_key and CURRENT_KEY=$(semver_key "$CURRENT_VERSION") are duplicated verbatim in the orphan-branch step at lines 153-160. Both steps already read CURRENT_VERSION from steps.current, so compute CURRENT_KEY once in the "Read current version" step and expose it as an extra output for both later steps to consume, instead of re-deriving it twice.

@seabbs-review-bot seabbs-review-bot Bot added the llm-reviewed Reviewed by seabbs-review-bot label Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

llm-reviewed Reviewed by seabbs-review-bot

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant