Skip to content

Commit 80c9353

Browse files
committed
docs: document conventional commits and the approval-gated release flow
1 parent 9ca2c1a commit 80c9353

2 files changed

Lines changed: 57 additions & 18 deletions

File tree

‎CONTRIBUTING.md‎

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,32 @@ make install # environment + pre-commit hooks
2323
covers details such as running the integration tests and serving the docs
2424
locally.
2525

26+
## Commit messages
27+
28+
Commits follow [Conventional Commits](https://www.conventionalcommits.org/):
29+
`type(scope): subject`, for example `fix: correct sidebar collapse on small
30+
screens`. The scope is optional. A local `commit-msg` hook (installed by
31+
`make install`) rejects malformed messages, because they drive the automated
32+
release below.
33+
34+
| Type | Release effect |
35+
| ---- | -------------- |
36+
| `feat` | minor release |
37+
| `fix`, `perf` | patch release |
38+
| `BREAKING CHANGE:` footer, or `!` after the type | major release |
39+
| `docs`, `chore`, `test`, `refactor`, `ci`, `style`, `build` | no release |
40+
2641
## Releasing
2742

28-
Releases are fully automated with
29-
[python-semantic-release](https://python-semantic-release.readthedocs.io/):
30-
every push to `main` is analyzed, and conventional commits decide the
31-
outcome. `fix:` commits trigger a patch release, `feat:` a minor release
32-
and a `BREAKING CHANGE:` footer (or `!` after the type) a major release;
33-
other types (`chore:`, `docs:`, `ci:`, ...) release nothing. CI then
34-
updates the changelog, tags, builds, publishes to PyPI via trusted
35-
publishing and deploys the versioned docs. No manual version bumping or
36-
tagging.
43+
There is no standing release branch: work goes `feature branch -> main`.
44+
Every pull request into `main` runs the checks, the integration suite, and a
45+
bot comment predicting the version a merge would release. Merging starts the
46+
release job, which pauses on the `pypi` GitHub environment for a required
47+
reviewer to approve; approve and
48+
[python-semantic-release](https://python-semantic-release.readthedocs.io/)
49+
bumps the version (in `pyproject.toml`, never edited by hand), updates the
50+
changelog, tags, builds, publishes to PyPI via trusted publishing and deploys
51+
the versioned docs. Reject the approval and nothing ships.
3752

3853
## AI Guidelines
3954

‎docs/dev.md‎

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ Requires [uv](https://docs.astral.sh/uv/) and `git`.
2222
uv run pre-commit install
2323
```
2424

25+
`pre-commit install` wires both hook stages (`pre-commit` and `commit-msg`);
26+
the latter enforces the commit message format below.
27+
2528
## Quality checks
2629

2730
Lock consistency, linting and formatting (pre-commit incl. ruff), static
@@ -137,17 +140,38 @@ strict build that fails on any warning:
137140
uv build
138141
```
139142

140-
## Releasing
143+
## Commit messages
144+
145+
Commits follow [Conventional Commits](https://www.conventionalcommits.org/):
146+
`type(scope): subject`, scope optional. The local `commit-msg` hook (see
147+
Setup) rejects malformed messages, because they drive the automated release
148+
below.
141149

142-
Releases are fully automated
143-
([python-semantic-release](https://python-semantic-release.readthedocs.io/)):
144-
conventional commits on `main` decide the version bump (`fix:` patch,
145-
`feat:` minor, `BREAKING CHANGE:`/`!` major), CI updates the changelog,
146-
tags `vX.Y.Z`, builds, publishes to PyPI via trusted publishing and
147-
deploys the versioned docs. The package version is derived from the tag
148-
by `hatch-vcs`; nothing is bumped manually.
150+
| Type | Release effect |
151+
| ---- | -------------- |
152+
| `feat` | minor release |
153+
| `fix`, `perf` | patch release |
154+
| `BREAKING CHANGE:` footer, or `!` after the type | major release |
155+
| `docs`, `chore`, `test`, `refactor`, `ci`, `style`, `build` | no release |
156+
157+
## Releasing
149158

150-
To preview what the next release would be:
159+
There is no standing release branch: work goes `feature branch -> main`
160+
directly. Every pull request into `main` runs `main.yml` (quality, tests,
161+
docs), the integration suite, and a `version-preview` job that comments the
162+
version a merge would release, computed with the same conventional commits.
163+
164+
Merging to `main` starts the release job
165+
(`on-release-main.yml`), which pauses on the `pypi` GitHub environment for a
166+
required reviewer to approve -- this is the deliberate-release control, in
167+
place of a staging branch. Once approved,
168+
[python-semantic-release](https://python-semantic-release.readthedocs.io/)
169+
bumps the static version in `pyproject.toml` and `CITATION.cff` (never edited
170+
by hand), updates `CHANGELOG.md`, relocks `uv.lock`, commits, tags `vX.Y.Z`,
171+
builds, publishes to PyPI via trusted publishing and deploys the versioned
172+
docs. Reject the approval and nothing ships.
173+
174+
To preview what the next release would be locally:
151175

152176
```bash
153177
uv run semantic-release --noop version

0 commit comments

Comments
 (0)