Release process

This page is for maintainers preparing a PyMetaAnalysis release. Releases are tag-driven: an accepted vX.Y.Z tag builds the distributions, publishes them to PyPI with short-lived OpenID Connect credentials, and creates a GitHub Release containing the same artifacts.

One-time repository configuration

GitHub Pages

In repository Settings > Pages, select GitHub Actions as the publishing source. The pages.yml workflow then builds the strict MkDocs site from main and deploys it through the protected github-pages environment.

PyPI trusted publisher

Create the PyMetaAnalysis project or a pending publisher on PyPI with these values:

Field Value
PyPI project PyMetaAnalysis
GitHub owner ZhaoboDing
Repository PyMetaAnalysis
Workflow release.yml
Environment pypi

Create a GitHub environment named pypi and require maintainer approval where the repository plan supports it. Protect release tags matching v*. The publishing job receives only id-token: write; no long-lived PyPI token is stored in GitHub.

See the PyPI documentation for creating a project with a trusted publisher and its GitHub Actions security guidance.

Prepare a release pull request

  1. Confirm the distribution name is still available for the first release.
  2. Review public API and report-schema changes since the previous release.
  3. Set the same final version in src/meta_analyze/_version.py and CITATION.cff. Hatchling reads the package version dynamically from _version.py.
  4. Move the relevant CHANGELOG.md entries from Unreleased to a dated heading such as ## X.Y.Z - YYYY-MM-DD.
  5. Run the complete validation suite.

The local consistency check is:

python tools/check_release.py

For a proposed tag, add:

python tools/check_release.py --tag vX.Y.Z

The tag check rejects development versions, version mismatches, and releases without a dated changelog heading.

The tag-triggered release workflow independently installs the test extra and runs the full branch-coverage suite before building distributions. A tag cannot reach the PyPI environment merely because it belongs to main; the tagged source must pass this release-time test gate.

Validate the candidate

python -m ruff format --check .
python -m ruff check .
actionlint
python -m mypy
python -m pytest --cov=meta_analyze --cov-branch --cov-report=term-missing
python -m mkdocs build --strict
python tools/execute_notebooks.py
python -m build
python tools/inspect_distribution.py dist
python benchmarks/benchmark_core.py

For the 1.0 stabilization cycle, independent external statistical review is a release gate: follow the roadmap acceptance matrix and review checklist. Earlier 0.x releases did not require this gate. Release notes and the validation status must accurately describe the evidence for the released commit and must not imply that a formal audit has occurred when it has not.

The 0.10 foundation batch does not bump the version. Remind the maintainer before changing version metadata in a release PR. RC preparation must also verify prerelease metadata, installation selection, and tag handling; do not assume final-version smoke commands exercise an RC. Creating a development draft PR does not authorize merging, tagging, or PyPI publication.

Statistical release acceptance checks

Before preparing any release version commit, confirm that:

  • every statistical change has formula documentation, boundary tests, and an independent comparison where an appropriate implementation is available;
  • committed R fixtures still reproduce from their adjacent generator scripts, with every intentional cross-software difference explained;
  • public API, result, report-schema, methods, limitations, interoperability, and validation documentation agree with the behavior being released;
  • example notebooks and performance benchmarks cover new public workflows where appropriate; and
  • the complete validation suite above passes with the final release metadata.

Only after these checks pass should the release pull request set the final version and create its dated changelog heading.

Tag and publish

After the release pull request is merged, update local main and tag the merge commit:

git switch main
git pull --ff-only
git tag -a vX.Y.Z -m "PyMetaAnalysis X.Y.Z"
git push origin vX.Y.Z

The release workflow then:

  1. verifies that the tag commit belongs to main;
  2. checks version and changelog consistency;
  3. builds and inspects the wheel and source distribution;
  4. runs the release performance benchmark against the built wheel;
  5. publishes the distributions through PyPI Trusted Publishing;
  6. creates a GitHub Release with distributions and benchmark output.

Never replace an existing release artifact or reuse a published version. If a release is defective, fix it and publish a new version.

Post-release checks

In a clean environment:

python -m venv .release-smoke
.release-smoke/Scripts/python -m pip install PyMetaAnalysis
.release-smoke/Scripts/python -c "import meta_analyze as ma; print(ma.__version__)"

Use .release-smoke/bin/python instead on POSIX systems. Confirm the PyPI page, GitHub Release, documentation site, citation metadata, and installation command all refer to the same version.