Skip to content

Release Guide

This guide is manual-first. It covers token-based PyPI releases.

Release Policy

  • Use SemVer: MAJOR.MINOR.PATCH.
  • Package version is generated automatically from git tags via setuptools-scm.
  • Use annotated git tags in the form vX.Y.Z.
  • Tag and package version must match exactly (for example, tag v0.1.1 produces package version 0.1.1).
  • Never reuse a version number after it has been uploaded to PyPI.

One-Time Setup

Accounts and project names

  1. Create/verify account on:
  2. PyPI: https://pypi.org/
  3. Ensure package name stacksats is available/owned by this project.

Local tooling

Use Python 3.11+ and install packaging tools:

python -m pip install --upgrade pip
python -m pip install --upgrade build twine

Local token handling (default)

Use PyPI API tokens locally only. Do not commit them.

Example with environment variables:

export TWINE_USERNAME=__token__
export TWINE_PASSWORD="<pypi-token>"

If your local workflow uses PYPI_API_KEY in .env, map it at runtime:

export TWINE_USERNAME=__token__
export TWINE_PASSWORD="${PYPI_API_KEY}"

Manual Release Checklist

1) Prepare release branch/PR

  1. Update CHANGELOG.md (required):
  2. Add user-visible changes under ## [Unreleased].
  3. Before tagging, move unreleased entries into the new vX.Y.Z section with the release date.
  4. Start a fresh ## [Unreleased] section for follow-up work.
  5. Ensure CI/tests are green.
  6. Merge to main.

2) Local preflight checks

From repository root:

bash scripts/release_check.sh

This should run lint, tests, build, and twine check.

If your environment has constrained SSL trust roots, scripts/release_check.sh will: - Fall back to already-installed local build/twine when tool refresh via pip fails. - Retry package build with python -m build --no-isolation only when isolated-build failure looks SSL-related. - Still fail normally for non-SSL build errors.

3) Build artifacts

rm -rf dist/ build/ .eggs/ *.egg-info
python -m build
python -m twine check dist/*

4) Publish to PyPI (default)

bash scripts/publish_pypi_manual.sh

5) Tag release

git tag -a vX.Y.Z -m "Release vX.Y.Z"
git push origin vX.Y.Z

The tag is the source of truth for the version. No manual version bump is required.

6) Post-release verification

  • Verify package page on PyPI.
  • Install from PyPI in a fresh virtual environment.
  • Verify entry points:
  • stacksats
  • stacksats-plot-mvrv
  • stacksats-plot-weights

CI Workflow Notes

  • Pull requests run packaging checks (package-check-pr.yml).
  • Pushes to main run packaging checks (package-check.yml).
  • PyPI publishing is manual only via scripts/publish_pypi_manual.sh.
  • Pull requests also run docs quality checks (docs-check.yml):
  • markdown lint
  • spelling checks
  • link checks
  • docs reference checks
  • strict docs build
  • Pushes to main publish docs to GitHub Pages via docs-pages.yml.

GitHub Pages Source

Configure Pages source to GitHub Actions.

End-to-End Validation Runbook

Use this sequence after workflows are merged:

  1. Open a PR with release notes/changelog updates and verify package-check-pr.yml passes.
  2. Create and push annotated tag vX.Y.Z.
  3. Run bash scripts/publish_pypi_manual.sh.
  4. Verify package page on PyPI.
  5. Install from PyPI in a fresh virtual environment and run command smoke tests.

Expected results:

  • Manual publish succeeds with local PYPI_API_KEY.
  • Local build and twine check pass before upload.

Operational Notes

  • Do not commit PyPI tokens or store them in repository files.
  • Keep scripts/publish_pypi_manual.sh as the default release path.
  • If a release fails after version/tag creation, bump to the next version and retry; do not overwrite versions.
  • Keep contributor and policy docs current:
  • CONTRIBUTING.md
  • SECURITY.md
  • CODE_OF_CONDUCT.md