Repository navigation
Publishing on every merged PR is hard to control #95
Description
Publishing on every merged PR is hard to control
publish.yaml currently triggers on a merged pull request:
on:
pull_request:
types: [closed]
branches: [main]
jobs:
publish:
if: github.event.pull_request.merged == trueand then bumps the patch version, commits it to main, tags, builds and publishes
to PyPI. So every merge is a release. I ran into several consequences of that
while working on #91/#92/#93, so collecting them here.
Consequences
- There is no such thing as an unreleased merge. A docs typo, a CI tweak, a
comment change or an internal refactor all ship a new version to PyPI. Two PRs
merged back to back are two releases; changes cannot be batched into one. - The version number carries no information. The bump is always
patch, so a
new feature or a breaking change cannot be released as minor or major without
intervening by hand.0.4.6means "six merges", not anything semantic. - Publishing is not gated on tests. The
publishjob has noneeds:and does
not runpytest.test.yamlruns on the pull request, but nothing re-checks the
merge result, and nothing stops a publish when the suite is red — which it
currently is onmain(see Drop tensorflow_probability so scenvi imports on current jax #93). - It cannot work for pull requests from forks. Fork-triggered
pull_request
workflows get no secrets and a read-onlyGITHUB_TOKEN, so both
secrets.PYPI_TOKENandgit push origin HEAD:mainshould fail. Import ENVI lazily so a broken jax stack cannot take COVET down #91 and COVET: make preprocessing explicit and batch_size numerically inert #92 are
the first fork PRs on this repo — every previously merged PR came from a
dpeerlab:branch — so this has not been exercised yet. Worth confirming before
merging them. - CI pushes directly to
main. The version bump is committed and pushed with
contents: write, which bypasses any branch protection you might otherwise want. - Concurrent merges race. Two PRs merged close together both read
poetry version -sfrom the same starting point and bump to the same number; the
second push or publish then fails. - A long-lived API token.
PYPI_TOKENis a stored credential with upload
rights, rather than PyPI's OIDC trusted publishing.
Suggestion
Trigger on a published GitHub release instead:
on:
release:
types: [published]and publish with pypa/gh-action-pypi-publish
under permissions: {id-token: write}, using PyPI trusted publishing — no stored
token. Take the version from the tag rather than committing a bump, which also
removes the CI push to main entirely.
This is what scverse's
cookiecutter template does, and
adopting its conventions here (hatchling, PEP 621 metadata, release-triggered
trusted publishing) would be a reasonable base more broadly — it would also make
the two-package version story in #94 considerably easier.
Cutting a release then becomes: merge what you want, when you want; press
"Draft a new release" when the set of changes is worth publishing; write release
notes; done.
Happy to open a PR for this if you'd like — it is a small change, but it is your
release process, so I did not want to send one unasked.
Activity
Marius1311 commentedon Aug 5, 2026
Opened #96 with a fix. It needs one setup step on the PyPI side before merging — a trusted publisher registered for
scenvi(ownerdpeerlab, repoENVI, workflowpublish.yaml, environmentpypi) — since nobody outside the project owners can configure that. Details in the PR.