Releasing¶
One-time setup: let GitHub publish for you (already done)¶
PyPI can be told to trust one workflow in one repository, so releases go out with no API token anywhere. Nothing to store, nothing to leak, nothing to rotate, and nobody can publish from their laptop by accident.
socialchimp is on PyPI now, and this was done once, before the 0.1.0
upload: the pending publisher below was added, and PyPI promoted it to a
regular one itself the moment that first upload succeeded. Nothing here
needs doing again unless the project or the repository is ever recreated -
kept below for that day, and for anyone setting up the same thing for a
package of their own.
Before a project's first upload, go to https://pypi.org/manage/account/publishing/, and under Add a new pending publisher choose GitHub and fill in exactly:
| Field | Value |
|---|---|
| PyPI project name | socialchimp |
| Owner | raghulj |
| Repository name | socialchimp |
| Workflow name | publish.yml |
| Environment name | pypi |
Two things people get wrong here:
- Workflow name is the file name,
publish.yml— notPublish, which is the name inside the file. - Environment name must match the
environment: name: pypiin.github/workflows/publish.yml. If you leave it blank on PyPI, it must be blank in the workflow too, or the upload is refused.
Optionally, on GitHub under Settings → Environments → pypi, add yourself as a required reviewer. Then every publish waits for you to press a button, which is a cheap way to make an accidental release impossible. (This project has: every release since 0.1.0 has paused for that approval.)
Where work happens¶
dev is the default branch and where everything lands. main is what has
been released.
main is protected: no force pushes, no deletions, CI has to pass on all
four Python versions, and changes arrive by pull request. So a release is a
pull request from dev to main, and the tag goes on main.
Publishing has a second gate on top of that: the pypi environment needs
raghulj to approve it, so nothing reaches PyPI without somebody pressing a
button, even if a bad commit gets onto main.
Cutting a release¶
-
Update the version in
src/socialchimp/__init__.py. That is the only place it lives; the package metadata reads it from there. -
Write the changelog entry in
CHANGELOG.md. Say what will surprise somebody, not just what changed. Anything that alters behaviour people already rely on goes near the top, in plain words. -
Run the whole gate, and do not skip it because CI is green — CI ran on the last commit, not on what is in front of you:
- Check the built package, not just the source. A wheel can be wrong in ways the test suite cannot see:
rm -rf dist && uv build
uv venv /tmp/check && VIRTUAL_ENV=/tmp/check uv pip install dist/*.whl
VIRTUAL_ENV=/tmp/check uv run python -c "
import socialchimp as sc
print(sc.__version__, sc.available_platforms())
"
Every network should be listed. If one is missing, its entry point is not
in pyproject.toml, and nobody would be able to load it by name.
- Open a pull request from
devtomainand merge it once CI is green, then tag the merge commit:
gh pr create --base main --head dev --title "Release 0.4.0"
# once it is merged:
git checkout main && git pull
git tag -a v0.4.0 -m "socialchimp 0.4.0"
git push origin v0.4.0
git checkout dev
This is a merge commit, not a squash - git log on main should show
one merge per release, each tagged, as it has for 0.1.0 through 0.4.0.
- Publish the GitHub release. That is what starts the upload:
The workflow runs the whole gate again on four Python versions, builds, checks the files are uploadable, and only then publishes. Publishing cannot be undone — PyPI never allows a version number to be reused, even after deleting it — so it is worth the few minutes.
Numbering¶
While the first number is 0, treat the middle one as the breaking one: a
0.3.1 on top of 0.3.0 is safe, a 0.4.0 may not be. Both 0.2.0 and 0.3.0
did break something - 0.2.0 changed the shape of Update.raw for Facebook,
Instagram and Threads, and 0.3.0 changed how Dispatcher.deliver behaves and
removed post_to_many entirely - and each said so at the top of its
CHANGELOG.md section. What a version bump means for people writing their
own networks specifically (a narrower promise than "nothing breaks") is in
adding a platform.
Trying it without the real thing¶
To see the rendered project page before it is permanent, publish to TestPyPI first. Add a second pending publisher at https://test.pypi.org/manage/account/publishing/ with the same values, then: