Releasing#
A release publishes one source distribution and one wheel of optmat to PyPI, archives
the version on Zenodo and updates the manual. The version comes from the v* git tag.
Release notes between releases#
Pull requests add independent Markdown fragments under changelog.d/, named
<short-slug>.<category>.md
(format), instead of
editing CHANGELOG.md. After each push to main, the workflow
.github/workflows/release-notes.yml creates or refreshes one draft pull request,
Prepare the next release notes, on chore/release-after-<last-version>. The latest
released version comes from CITATION.cff. The draft groups every pending fragment under
Unreleased in CHANGELOG.md and removes the collected fragments on its branch. Released
sections are copied unchanged.
Edit pending fragments in ordinary pull requests, not in the generated draft. A manual refresh is available with:
gh workflow run release-notes.yml --ref main
The updater checks that its branch is exactly what it generated before writing another commit, so manual edits stop it without being overwritten; a closed draft, or one marked ready, pauses it. It never force-pushes, approves, merges, tags or publishes.
Its pushes come from the workflow’s own token, which starts no other workflow, so CI runs on the draft only once someone pushes a commit to it: the release commit below.
Making a release#
Mark the rolling pull request ready, before editing it, which freezes the automatic refreshes. If more changes reach
mainafterwards, mergemaininto the release branch and runuv run poe changelog-collect, which appends only the fragments still present. With no fragments pending there is no rolling pull request: make a release branch frommaininstead.Make the release commit on that branch:
rename
UnreleasedinCHANGELOG.mdto## X.Y.Z (YYYY-MM-DD), above an empty## Unreleased, and give it a short summary of the release, saying whether any recommended value or model changed;if the curated records changed, state their counts there, with the sentence that
tests/test_counts.pykeeps current inREADME.md;give
CITATION.cffthe sameversionanddate-released(tests/test_release_metadata.pychecks that they agree).
A minor version may break the public surface; every break is listed under Changed (breaking).
Run
uv run poe test-release, which builds and installs the distributions offline. CI runs on the commit.Merge it once CI passes.
Tag the merge on
mainand push the tag on its own:git tag -a vX.Y.Z COMMIT -m "optmat X.Y.Z" git push origin vX.Y.Z
The repository’s rules let only administrators create a
v*tag.Publish a GitHub release from the tag, with the version’s changelog section as its notes:
gh release create vX.Y.Z --verify-tag --title "optmat X.Y.Z" --notes-file NOTES.md
The release starts
.github/workflows/release.yml, which builds the distributions, checks that the built version matches the tag and that the wheel installs and imports, and publishes to PyPI through trusted publishing. Zenodo archives the release with the metadata of.zenodo.json. The concept DOI inCITATION.cffand the README names every version, so it does not change.Tell solprop if it is waiting on the release: comment on the issue or SEP that asked for the change.
One-time setup#
These are done, and recorded here for a rebuild of the repository’s settings:
On PyPI, a trusted publisher for
LupoLab/optmat, the workflowrelease.ymland the environmentpypi, and a GitHub environment namedpypi.On Zenodo, the repository switched on under GitHub.
Under GitHub’s Settings → Actions → General → Workflow permissions, Allow GitHub Actions to create and approve pull requests enabled, with the default token permissions read-only. Only the release-notes job asks for
contents: writeandpull-requests: write. The workflow runs only frommain.