Skip to content

Release 0.3.0 + tag-triggered PyPI publish via Trusted Publishing - #94

Merged
mspinola merged 2 commits into
mainfrom
ci/release-workflow
Aug 2, 2026
Merged

mspinola merged 2 commits into
mainfrom
ci/release-workflow

Conversation

@mspinola

@mspinola mspinola commented Aug 2, 2026

Copy link
Copy Markdown
Owner

cotdata had no release workflow, so publishing meant a manual twine upload with a stored API token from somebody's laptop. crucible already solved this the other way — OIDC Trusted Publishing, no stored credentials — and one publish mechanism across the fleet is one thing to get right and one thing to audit. This is that workflow, adapted.

Two guards rather than crucible's one, because cotdata carries its version in two places: pyproject.toml and src/cotdata/__init__.py. A release that bumps one and forgets the other installs fine and then lies about itself at runtime, which is exactly the kind of thing nobody checks by hand twice.

Publishes nothing on its own. It needs a one-time GitHub publisher configured on PyPI (owner mspinola, repo cotdata, workflow release.yml, environment pypi), which can only be done from the project owner's PyPI account, and it fires on a tag push whose version matches pyproject. workflow_dispatch builds and twine checks without publishing, which is the only dry run available since there is no TestPyPI path.

🤖 Generated with Claude Code

mspinola and others added 2 commits August 2, 2026 17:05
cotdata had no release workflow, so publishing meant a manual twine upload with a
stored API token from somebody's laptop. crucible already solved this the other way,
with OIDC Trusted Publishing and no stored credentials, and one publish mechanism
across the fleet is one thing to get right and one thing to audit. This is that
workflow, adapted.

Two guards rather than crucible's one, because cotdata carries its version in two
places: pyproject.toml and src/cotdata/__init__.py. A release that bumps one and
forgets the other installs fine and then lies about itself at runtime, which is
exactly the kind of thing nobody checks by hand twice.

Does not publish anything on its own. It needs a one-time GitHub publisher on PyPI
(owner mspinola, repo cotdata, workflow release.yml, environment pypi) which can
only be configured from the project owner's PyPI account, and it fires on a tag push
whose version matches pyproject.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
0.2.0 was tagged earlier today and never uploaded, because this repo had no release
workflow at the time and the alternative was a hand-rolled twine upload with a stored
token. That tag stands as a git tag and nothing more. Main has since moved past it
(#93 removed the flow decomposition), so publishing the tagged tree would ship
something that was never main's head, and re-pointing the tag would change what
0.2.0 means after the fact.

0.3.0 is what main actually is. Minor rather than patch because a public CLI
subcommand is gone, and everything from 0.2.0 rides along, so a consumer stepping up
from PyPI's 0.1.0 gets the whole vintage subsystem in one move.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@mspinola mspinola changed the title ci: tag-triggered PyPI publish via Trusted Publishing Release 0.3.0 + tag-triggered PyPI publish via Trusted Publishing Aug 2, 2026
@mspinola
mspinola merged commit 452e6c9 into main Aug 2, 2026
5 checks passed
@mspinola
mspinola deleted the ci/release-workflow branch August 2, 2026 21:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant