Skip to content

Latest commit

 

History

History
91 lines (74 loc) · 4.44 KB

File metadata and controls

91 lines (74 loc) · 4.44 KB

Releasing heormodel

How to cut a release after a PR merges to main. Release often: a single bug fix or small feature is enough to justify a patch release.

After every merge to main

Every PR that changes behavior adds one line under ## [Unreleased] in CHANGELOG.md, linking to the PR. Nothing else is required; main is always releasable.

Cutting a release

  1. Pick the version bump under semantic versioning: patch for fixes, minor for backward-compatible features, major for breaking changes.
  2. On main, update version in pyproject.toml.
  3. In CHANGELOG.md, rename ## [Unreleased] to ## [X.Y.Z] - YYYY-MM-DD, add a fresh empty ## [Unreleased] above it, and update the link references at the bottom of the file.
  4. Commit as Release vX.Y.Z, merge to main through a pull request.
  5. On merge, the Release workflow (.github/workflows/release.yml) runs its tag job: reads the version from pyproject.toml, tags the merge commit vX.Y.Z, and creates a GitHub release from the matching CHANGELOG.md section, using the RELEASE_TOKEN secret (see one-time setup below) so the release is attributed to the repository owner rather than github-actions[bot]. Its publish job then builds the package with uv build and publishes it to PyPI. Both jobs run in the same workflow deliberately, so the publish job's PyPI trusted-publisher identity is always release.yml, whichever job triggered it.
  6. If a publish is ever stuck for a tag that already has a GitHub release (check the Release workflow runs in the Actions tab), trigger .github/workflows/release.yml manually: Actions -> Release -> Run workflow, entering the tag (e.g. v0.7.0). This runs only the publish job, since tag is skipped for a manual workflow_dispatch run.

One-time release attribution setup

The tag job authenticates as the repository owner rather than the default github-actions[bot], so the GitHub release it creates shows as released by the owner. Create a fine-grained personal access token, scoped to this repository only, with the Contents: Read and write repository permission (under github.com/settings/personal-access-tokens), then add it as a repository secret named RELEASE_TOKEN (Settings -> Secrets and variables -> Actions -> New repository secret). Rotate it before expiry; the workflow fails the tag job's gh calls if it lapses.

One-time PyPI setup

The release workflow publishes via PyPI trusted publishing, no API token stored in the repo. On the heormodel project's PyPI page, under Publishing, add a trusted publisher for this repository:

  • Owner: pedroliman, repository: heormodel
  • Workflow file: release.yml
  • Environment: pypi

Zenodo archive

Every GitHub release also archives to Zenodo with a DOI, once the one-time setup below is done. No workflow step is needed: Zenodo's GitHub integration registers its own repository webhook (under Settings -> Webhooks) that fires on the release: published event directly, independent of GitHub Actions.

Zenodo reads archive metadata from .zenodo.json; GitHub's own "Cite this repository" button reads CITATION.cff. When both files are present, Zenodo uses .zenodo.json and ignores CITATION.cff. Update .zenodo.json if the title, authors, or keywords change; there is no version field to keep in sync; each archived record takes its version from the release tag.

One-time setup, done by the repository owner on zenodo.org (cannot be scripted, requires the owner's GitHub OAuth login):

  1. Sign in at zenodo.org with the GitHub account that owns this repository, and open the GitHub integration settings.
  2. Click "Sync now" if heormodel is not in the repository list yet.
  3. Toggle heormodel on. This is a one-time step; every release published afterward archives automatically.
  4. After the first archive completes, copy the "concept DOI" badge Zenodo shows for the repository (the one that always resolves to the latest version) into the README's badge row.

Checks before releasing

CI (.github/workflows/ci.yml) runs ruff, mypy, pytest, and the doctest suite on every push and PR to main. Do not tag a release on top of a red main.