Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 34 additions & 7 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,42 @@ Optionally add a tag-only deployment branch policy and a required reviewer so an

## Publishing a version

1. Bump the version in `pyproject.toml`, `src/falsegreen/scanner.py` (`__version__`), and `src/falsegreen/__init__.py` in lockstep.
2. Move the `[Unreleased]` entries in `CHANGELOG.md` under the new version with today's date. Update the footer comparison links:
`main` is a protected branch: direct pushes are rejected, every change lands
through a pull request with the test CI (`test (3.8/3.11/3.13)`) green, and
commits on `main` must be signed. A release is prepared on a branch, merged via
PR, and only then tagged. The tag push and the GitHub release are not blocked by
branch protection (they act on `refs/tags/*`, not on `main`).

### Prepare the release on a branch

1. Branch off `main`: `git checkout main && git pull && git checkout -b release/X.Y.Z`.
2. Bump the version in lockstep in **all four** places (the `test_version_lockstep`
test fails on any mismatch): `pyproject.toml`, `src/falsegreen/scanner.py`
(`__version__`), `CITATION.cff` (`version:`), and `src/falsegreen/__init__.py`
(it re-exports `__version__` from `scanner`, so no separate string to edit, but
confirm the import still resolves). Set `CITATION.cff` `date-released` to today.
3. Move the `[Unreleased]` entries in `CHANGELOG.md` under the new version with
today's date. Update the footer comparison links:
- `[Unreleased]` line: change `vPREV...HEAD` to `vX.Y.Z...HEAD`
- Add `[X.Y.Z]: .../compare/vPREV...vX.Y.Z`
3. Update the pre-commit `rev` in `README.md` to `vX.Y.Z`.
4. Run the self-scan: `python -m falsegreen src tests`. It must report zero HIGH findings before the tag is created.
5. Commit everything: `git add -A && git commit -m "release: X.Y.Z"`.
6. Tag and push: `git tag -a vX.Y.Z -m "falsegreen vX.Y.Z" && git push origin main --tags`.
7. Create the GitHub release: `gh release create vX.Y.Z --generate-notes` (or paste the CHANGELOG section manually). Publishing the release fires `release.yml`, which builds and uploads to PyPI.
4. Update the pre-commit `rev` in `README.md` to `vX.Y.Z`.
5. Run the self-scan: `python -m falsegreen src tests`. It must report zero HIGH
findings. Run `pytest -q` and `ruff check src tests` too.
6. Commit (signed) and push the branch: `git commit -S -am "[no-issue] release: X.Y.Z"`
then `git push -u origin release/X.Y.Z`.

### Merge and publish

7. Open the PR: `gh pr create --base main --title "[no-issue] release: X.Y.Z"`.
Wait for the three `test (...)` checks to pass, then merge (squash):
`gh pr merge --squash --delete-branch`. The squash commit on `main` is signed
by GitHub (verified), satisfying the signed-commits rule.
8. Sync and tag the **merged** commit on `main` (not the branch commit — squash
creates a new SHA): `git checkout main && git pull && git tag -a vX.Y.Z -m
"falsegreen vX.Y.Z" && git push origin vX.Y.Z`.
9. Create the GitHub release: `gh release create vX.Y.Z --generate-notes` (or paste
the CHANGELOG section manually). Publishing the release fires `release.yml`,
which builds and uploads to PyPI via OIDC.

Confirm the version is live: <https://pypi.org/project/falsegreen/>

Expand Down
Loading