Skip to content

ci: publish to PyPI on release and add manual Prepare Release workflow - #46

Merged
gormaniac merged 4 commits into
mainfrom
claude/focused-turing-69rfl2
Nov 1, 2026
Merged

gormaniac merged 4 commits into
mainfrom
claude/focused-turing-69rfl2

Conversation

@gormaniac

@gormaniac gormaniac commented Nov 1, 2026 •

Copy link
Copy Markdown
Owner

Summary

Releases now publish to PyPI, and a whole release can be cut from the GitHub UI.

New: Prepare Release workflow (.github/workflows/prepare-release.yml)

You start it by hand (Actions → Prepare Release → Run workflow). It only runs on the default branch.

  • Inputs: a patch / minor / major bump, or an exact version, plus an optional require_changelog check.
  • Fails right away if the RELEASE_TOKEN secret isn't set.
  • Runs the tests, works out the new version, and stops if the tag already exists.
  • Runs make change-version.
  • Updates CHANGELOG.md: renames ## Unreleased to ## vX.Y.Z - <date>, puts - N/A under any empty Features/Fixes heading, and starts a fresh empty ## Unreleased above it. If the version already has an entry, the file is left alone. If there's nothing to release, the workflow warns, or fails when require_changelog is set.
  • Commits build: release vX.Y.Z (version files plus CHANGELOG.md), creates the annotated vX.Y.Z tag, and pushes the commit and tag together in one atomic push.
  • Branch protection: checkout and push use RELEASE_TOKEN, a token from an account allowed to bypass the branch protection on main. The workflow's own GITHUB_TOKEN is read-only.
  • How the release starts: because the tag is pushed with a token other than GITHUB_TOKEN, the push triggers release.yml, which shows up as its own run.

Updated: Release workflow (.github/workflows/release.yml)

  • Still triggered by v* tag pushes, from Prepare Release or from make release.
  • Checks out the tag and stops if it doesn't match the version in pyproject.toml.
  • Uploads to PyPI with twine using the PYPI_DEPLOY_TOKEN secret. Only the wheel and source package are uploaded, because dist/ also holds the Storm package JSON files. --skip-existing lets a release be re-run safely.
  • The PyPI upload runs before the GitHub Release is created, so a failed upload doesn't leave a release with no package.
  • Release notes come from the matching CHANGELOG.md entry, with GitHub's auto-generated notes added below.

Other

  • scripts/changelog.py: has two commands. notes <version> prints a version's entry. release <version> [date] renames the Unreleased section to that version.
  • make release now runs the same changelog step and commits CHANGELOG.md.
  • CHANGELOG.md: adds a ## Unreleased section that describes this PR.
  • README and doc/contributing.md:
    • document the CI release process and the secrets it needs (PYPI_DEPLOY_TOKEN, DOCS_DISPATCH_TOKEN, RELEASE_TOKEN);
    • add a Changelog section for contributors that explains the ## Unreleased header;
    • remove the outdated line saying CI doesn't publish to PyPI.

Setup

  • PYPI_DEPLOY_TOKEN and RELEASE_TOKEN have both been added.
  • The account that owns RELEASE_TOKEN must be allowed to bypass the branch protection rule on main.

Testing

  • The YAML of all workflows parses.
  • scripts/changelog.py was tested locally against a copy of CHANGELOG.md: rolling Unreleased, filling empty headings with N/A, skipping when the entry already exists, failing on a missing entry, and extracting notes.
  • The workflows themselves haven't run on GitHub yet; the first real release will be their first run.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KBLBzhhavuuhR5JQy6eH8h

Prepare Release now turns the '## Unreleased' CHANGELOG section into the new
version's entry and commits it with the version bump. An optional
RELEASE_TOKEN secret is used to push the release commit and tag when the
default branch is protected; the tag push then triggers release.yml itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KBLBzhhavuuhR5JQy6eH8h
main is protected, so Prepare Release now requires the RELEASE_TOKEN secret
and fails early without it. Dropping the GITHUB_TOKEN fallback also removes
the need for release.yml to be callable via workflow_call: the tag pushed
with RELEASE_TOKEN triggers it directly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KBLBzhhavuuhR5JQy6eH8h
@gormaniac
gormaniac merged commit 6f51157 into main Nov 1, 2026
2 checks passed
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.

2 participants