Auto-publish .dev releases on every push to main#1472
Conversation
Adds .github/workflows/devx_tag.yml, modeled on prime-rl's devx_tag.yaml. On every push to main (and on workflow_dispatch), it: - enumerates v* tags to compute the next dev tag (vX.Y.(Z+1).dev1 from a stable parent, vX.Y.Z.dev(N+1) from a dev parent), - builds a synthetic commit on top of the current main HEAD that bumps verifiers/__init__.py to the new version and writes a stub release notes file at assets/release/RELEASE_<tag>.md (auto-generated from the git log since the previous tag), - annotates and pushes the tag without touching the main branch, - dispatches tag-and-release.yml for that tag so the existing build + PyPI publish + GitHub Release pipeline runs unchanged. When a push already modifies verifiers/__init__.py the workflow skips, deferring to tag-and-release.yml's auto-tag-on-main job (so manual stable releases or legacy release-prep PRs never produce two tags for the same SHA). Documents the new flow in assets/release/release_workflow.md and lists the workflow in .github/workflows/README.md. Co-authored-by: Cursor <cursoragent@cursor.com>
ApprovabilityVerdict: Needs human review Unable to check for correctness in 713fa05. This PR adds automatic PyPI publishing on every push to main, which is a significant production deployment infrastructure change. Additionally, there's an unresolved medium-severity comment about a potential race condition in the skip logic that could cause duplicate tag creation. You can customize Macroscope's approvability policy. Learn more. |
Dev releases (devx_tag.yml) are now self-contained: compute next dev tag, build a synthetic commit that bumps verifiers/__init__.py, push the tag, then build and publish to PyPI via Trusted Publisher (pypi-prod environment, OIDC). No release-notes file, no GitHub Release — dev releases are just "tag + push to PyPI". Stable releases (tag-and-release.yml) keep the existing assets/release/RELEASE_<tag>.md + GitHub Release flow, and explicitly reject .dev tags so the split is enforced end-to-end: - push tag trigger excludes v*.dev* - auto-tag-on-main skips with an explanatory message if __init__.py is bumped to a .dev value (since dev versions are owned by devx_tag.yml) - workflow_dispatch / pushed-tag flow errors on .dev tags Docs in assets/release/release_workflow.md and .github/workflows/README.md are reworked to describe the two independent flows. Co-authored-by: Cursor <cursoragent@cursor.com>
verifiers/__init__.py's __version__ is now treated as the latest stable release version. devx_tag.yml never touches it. The dev flow collapses to prime-rl's exact pattern: create a lightweight tag at main HEAD, then override __init__.py in the workflow checkout only (uncommitted) before building so the wheel carries the dev version. Source installs from main therefore always report the latest stable version. The dev version only exists on the published wheel — there is no drift to chase between main's __version__ and PyPI. Updated docs in assets/release/release_workflow.md and the workflows README to describe the invariant. Co-authored-by: Cursor <cursoragent@cursor.com>
| if [ -z "$BEFORE_SHA" ] || [ "$BEFORE_SHA" = "0000000000000000000000000000000000000000" ]; then | ||
| echo "skip=false" >> "$GITHUB_OUTPUT" | ||
| exit 0 | ||
| fi |
There was a problem hiding this comment.
Invalid before skips init guard
Medium Severity
When github.event.before is empty or the all-zero SHA, the skip step sets skip=false and exits before checking whether verifiers/__init__.py changed. A force-push or first push to main that lands stable release prep can still get a .dev tag and PyPI publish while auto-tag-on-main skips tagging for the same reason.
Reviewed by Cursor Bugbot for commit 18ff1cd. Configure here.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 51406cb. Configure here.
verifiers/__init__.py's __version__ is the single source of truth for the latest *stable* release. The legacy manual flow had been updating it to dev values (most recently 0.1.15.dev11); under the new split release pipeline only stable releases bump this file, so reset it to the actual latest stable on PyPI. tag-and-release.yml's auto-tag-on-main will see this as a downgrade, try to create v0.1.14, find it already exists, and no-op. devx_tag.yml sees __init__.py modified in this push and defers. Co-authored-by: Cursor <cursoragent@cursor.com>
51406cb to
713fa05
Compare


Summary
Split the release pipeline into two independent flows so dev and stable releases never share infrastructure:
.github/workflows/devx_tag.yml) — self-contained. On every push tomain, the workflow enumeratesv*tags to pick the nextvX.Y.(Z+1).dev1(from a stable parent) orvX.Y.Z.dev(N+1)(from a dev parent), creates a lightweight tag atmainHEAD via the git-refs API, checks out the tag, overridesverifiers/__init__.py's__version__to the dev value in the workflow checkout only (uncommitted), runsuv build, and publishes to PyPI via Trusted Publisher (pypi-prodenvironment, OIDC). No release-notes file, no GitHub Release — dev releases are just "tag + build + push to PyPI". Modeled on prime-rl'sdevx_tag.yaml..github/workflows/tag-and-release.yml) — unchanged in shape, but reserved for non-dev tags only. Push trigger excludesv*.dev*,auto-tag-on-mainskips with an explanatory message whenverifiers/__init__.pyis bumped to a.devvalue, and the dispatched / pushed-tag flow errors on.devtags. Still requiresassets/release/RELEASE_<tag>.mdand still creates a GitHub Release.verifiers/__init__.py's__version__is treated as the latest stable release version and is only ever modified by a stable release-prep PR.devx_tag.ymlnever touches it. As part of this PR__version__is reset from the legacy0.1.15.dev11to0.1.14(the actual latest stable on PyPI) so the invariant holds from day one.devx_tag.ymldefers to the stable flow when a push already modifiesverifiers/__init__.py, so a stable release-prep PR never produces two tags for the same SHA. After a stable cut, the next push tomainautomatically produces the first.dev1of the next patch cycle without touchingmain.Docs in
assets/release/release_workflow.mdand.github/workflows/README.mdare rewritten around the two flows and the new__init__.py = latest stableinvariant.Breaking
tag-and-release.ymlno longer accepts.devtags via push trigger orworkflow_dispatch. Usedevx_tag.ymlinstead (runs automatically on every push tomain; can also be dispatched manually).verifiers/__init__.pyto avX.Y.Z.devNvalue is no longer how dev releases ship.auto-tag-on-mainnow skips that case with an explanatory log line so it does not race withdevx_tag.yml. The convention going forward is:__version__only ever changes when shipping a stable release.pip install verifiers==X.Y.Z.devNorpip install verifiers --pre).git checkout vX.Y.Z.devNwill show__version__equal to the latest stable, not the dev value, because the dev override is never committed. The wheel installed from PyPI still reports the dev version correctly.verifiers/__init__.pyis reset from0.1.15.dev11to0.1.14. Source installs (e.g.pip install -e .from amainclone) will now report0.1.14instead of0.1.15.dev11. Wheels installed from PyPI continue to report their own dev/stable version.Setup required
Before merging, add a PyPI Trusted Publisher entry for the new workflow:
verifiersPrimeIntellect-aiverifiersdevx_tag.ymlpypi-prod(The existing entry for
tag-and-release.ymlstays in place for stable releases.)Test plan
devx_tag.yml+pypi-prodbefore merging.mainproduces avX.Y.Z.devNtag (lightweight, pointing atmainHEAD) and that theDevX Tagworkflow publishes the wheel to PyPI labeled with that version.verifiers/__init__.pyto a non-dev version is handled only bytag-and-release.yml'sauto-tag-on-mainand thatdevx_tag.ymlskips it.workflow_dispatchontag-and-release.ymlwith a.devNtag errors with "Dev tags are not accepted by this workflow".Note
High Risk
Changes production PyPI publishing and tagging on every merge to main; misconfiguration or tag logic bugs could publish wrong versions or collide with stable releases.
Overview
Splits dev and stable publishing into separate GitHub Actions flows and documents the maintainer workflow end-to-end.
A new
devx_tag.ymlruns on every push tomain(and manual dispatch): it skips whenverifiers/__init__.pychanged (stable prep), computes the nextvX.Y.Z.devNtag from existingv*tags, creates a lightweight tag at HEAD, patches__version__only in the CI checkout foruv build, and publishes to PyPI via OIDC—no GitHub Release orRELEASE_*.md.tag-and-release.ymlis narrowed to stable releases: tag pushes ignorev*.dev*,auto-tag-on-mainrefuses a dev__version__bump, and manual/tag resolution errors on dev tags.assets/release/release_workflow.mdand.github/workflows/README.mddescribe the two pipelines and PyPI Trusted Publisher setup for both workflows.verifiers/__init__.pyis reset to0.1.14as the on-mainstable version string (replacing0.1.15.dev11), matching the model where dev numbers live on tags/wheels, not onmain.Reviewed by Cursor Bugbot for commit 713fa05. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Auto-publish
.devreleases to PyPI on every push to mainvX.Y.Z.devNtag, creates it at the push SHA, builds a wheel and sdist, and publishes them to PyPI via OIDC Trusted Publisher.v*.dev*tags and exit early if__version__is set to a dev value, so only stablevX.Y.Ztags go through the stable release path.__version__to0.1.14(from0.1.15.dev11) to reflect the latest stable release in the repo.Macroscope summarized 713fa05.