ci: automate post-release development bump PRs (#4590)
## TL;DR
After a package release is published, open a PR to start the next patch
development version. This removes the manual PR creation step that
blocks ordinary PRs while `main` holds a final version. A maintainer
still approves the bump.
## Trigger and safety
The new workflow handles `release: published` and manual retries with a
`tag` input. It accepts final numeric package tags, strips an optional
`v`, and skips development, OpenCV, and docs tags. It changes only
`unstructured/__version__.py` in the generated PR, for example `0.27.35`
to `0.27.36-dev`.
It acts only when `main` still holds the released version. If `main`
already holds a development version at least as new as the target, the
run is a successful no-op; any other version fails without a change.
Before acting, it also verifies that the supplied tag identifies a
published final GitHub Release. Serialized runs and a fixed branch per
target version let retries update the same PR. The existing version
guard already covers a final version to its next-patch `-dev`; the new
decision tests run alongside that guard in CI.
## Token, approval, and recovery
PR creation and squash auto-merge use the existing `GH_CREATE_PR_TOKEN`.
PRs opened by `GITHUB_TOKEN` do not trigger the required workflows, so
it cannot be used for creation. The default token has only `contents:
read` permission. Actions follow the repository's version-tag pinning
style.
The token owner authors the bump PR. Another maintainer must approve it.
Auto-merge requests entry into the merge queue after approval and
required checks. If auto-merge is not permitted, the workflow warns and
a maintainer must enqueue it. A missing or expired token, or failed PR
creation, produces an error directing maintainers to the manual bump in
CONTRIBUTING.md.
After merge, a safe smoke test is to run `workflow_dispatch` with the
latest package tag while `main` already holds the next `-dev`: the run
should report a no-op and create no PR. This implementation PR has no
version or changelog change, and does not change publication workflows.
## Validation
### Offline version decisions and guard
Tests cover version computation, optional `v`, ignored tags, bare and
numbered development versions, and unexpected main versions. The tests
also cover the actual version-file format and release-query failure. The
existing guard tests confirm the generated bump passes `check-version`.
```bash
bash scripts/test-post-release-dev-bump.sh
# 24 checks passed
bash scripts/test-check-new-release-version.sh
# Passed 25 version guard tests.
```
### Shell checks
```bash
shellcheck scripts/check-new-release-version.sh scripts/post-release-dev-bump.sh scripts/test-post-release-dev-bump.sh
shfmt -i 2 -d scripts/check-new-release-version.sh scripts/post-release-dev-bump.sh scripts/test-post-release-dev-bump.sh
# Both passed with no output.
```
## Reviews
- Claude Opus code review: **APPROVED** after the version-file parsing
and published-release fixes.
- GPT Pro production review: **SAFE TO MERGE**, with no High/Critical
defects, from a fresh full-context review at
`b64f3236f776b56e30420ee930b637efcc787fd5`. The completed browser
verdict was recovered after a capture timeout.
- Opus 4.6 reviewed this description; valid wording suggestions were
applied.
At that head, `check-version`, ShellCheck, shfmt, lint, CodeQL, and the
completed test jobs passed. No failures were reported; unit, PDF/image
dependency, and Docker jobs were still running at handoff. Long jobs
were not awaited. Actionlint was not installed, and installation failed
on a TLS timeout. No live release or workflow dispatch was run.
authored by codex
## Repair result (2026-10-26)
Both P2 findings are fixed in
`057d6d6d5bce493a7b5f6a5490ff8e7a2e63659b`. All tag aliases now share
one queue with `queue: max`, and each run checks out and plans against
current `main` after waiting. Accepted pending work survives ignored
tags, case variants, and stale retries. GitHub keeps up to 100 pending
runs and cancels later arrivals at capacity; maintainers can retry after
the queue drains. Completed-bump retries use the shared version parser
and accept supported dotted development versions.
The queue and dotted-development regression tests fail before the fixes
and pass afterward. The queue tests model GitHub's documented scheduling
contract; no live release workflow was invoked.
### Focused validation
```bash
bash scripts/test-post-release-dev-bump.sh
# Passed, including queue/alias and dotted-development regressions.
bash scripts/test-check-new-release-version.sh
# Passed 25 version guard tests.
```
ShellCheck, shfmt, Bash syntax, and YAML parsing passed. Actionlint
1.7.12 does not recognize the documented `queue` property and reports
the existing custom runner labels and the PR action's legacy runtime
declaration; these diagnostics were assessed in the full review.
A fresh full-context GPT Pro review at this head against main
`7bda7d82887a78bde8c19caf6574514d62a82574` is technically clean, with
both P2 findings resolved and no further code changes requested.
Exact-head required checks passed; CI, CodeQL, Security, and Partition
Benchmark succeeded. The review excludes `uv.lock` and `CHANGELOG.md`;
neither is changed by this PR.
**Human release-policy review remains required.** Maintainers must
decide the token's automatic version-PR and auto-merge role, confirm
independent approval and merge rules for that identity, and accept the
GitHub Release trigger and next-patch development convention. The
technical result does not accept those decisions. No merge, auto-merge
activation, release, or secret change was performed.
(authored by codex)
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>