Skip to content

Commit 8d7619b

Browse files
committed
Add GitHub Actions PyPI release workflow
1 parent def2afc commit 8d7619b

3 files changed

Lines changed: 130 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
name: Release
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
build:
12+
name: Build distributions
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- name: Checkout repository
17+
uses: actions/checkout@v4
18+
with:
19+
fetch-depth: 0
20+
21+
- name: Set up Python
22+
uses: actions/setup-python@v5
23+
with:
24+
python-version: "3.13"
25+
26+
- name: Set up uv
27+
uses: astral-sh/setup-uv@v8.1.0
28+
with:
29+
enable-cache: true
30+
31+
- name: Validate release tag matches package version
32+
env:
33+
RELEASE_TAG: ${{ github.event.release.tag_name }}
34+
run: |
35+
set -euo pipefail
36+
PACKAGE_VERSION="$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')"
37+
EXPECTED_TAG="v${PACKAGE_VERSION}"
38+
39+
if [ "${RELEASE_TAG}" != "${EXPECTED_TAG}" ]; then
40+
echo "Release tag ${RELEASE_TAG} does not match expected tag ${EXPECTED_TAG} derived from project version ${PACKAGE_VERSION}."
41+
exit 1
42+
fi
43+
44+
- name: Validate release commit is on main
45+
env:
46+
RELEASE_TAG: ${{ github.event.release.tag_name }}
47+
run: |
48+
set -euo pipefail
49+
git fetch --no-tags origin main
50+
RELEASE_SHA="$(git rev-list -n 1 "refs/tags/${RELEASE_TAG}")"
51+
52+
if ! git merge-base --is-ancestor "${RELEASE_SHA}" origin/main; then
53+
echo "Release tag ${RELEASE_TAG} points to commit ${RELEASE_SHA}, which is not contained in origin/main."
54+
exit 1
55+
fi
56+
57+
- name: Build source distribution and wheel
58+
run: uv build --sdist --wheel --out-dir dist
59+
60+
- name: Validate built artifacts
61+
run: uvx twine check dist/*
62+
63+
- name: Upload built distributions
64+
uses: actions/upload-artifact@v4
65+
with:
66+
name: python-package-distributions
67+
path: dist/
68+
69+
publish:
70+
name: Publish to PyPI
71+
runs-on: ubuntu-latest
72+
needs: build
73+
environment:
74+
name: pypi
75+
url: https://pypi.org/project/wagtail-honeypot/
76+
permissions:
77+
id-token: write
78+
79+
steps:
80+
- name: Download built distributions
81+
uses: actions/download-artifact@v4
82+
with:
83+
name: python-package-distributions
84+
path: dist/
85+
86+
- name: Publish distributions to PyPI
87+
uses: pypa/gh-action-pypi-publish@release/v1
88+
with:
89+
packages-dir: dist/

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file.
1414
- Update contributor and agent documentation for the new development workflow
1515
- Update the honeypot field documentation for the `aria-hidden="true"` accessibility attribute
1616
- Sync the Ruff pre-commit hook version with the locked Ruff release and correct the developer doc Wagtail baseline
17+
- Publish PyPI releases from GitHub Actions with trusted publishing and a protected `pypi` environment
1718

1819
## [1.2.1] - 2026-02-05
1920

docs/developer.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,46 @@ make lint
7070
make format
7171
```
7272

73+
## Release process
74+
75+
PyPI releases are published from GitHub Actions after a GitHub Release is published.
76+
77+
Prepare the release from `main`, not `release`:
78+
79+
```bash
80+
git switch main
81+
git pull origin main
82+
```
83+
84+
Before creating the release:
85+
86+
- Update `project.version` in `pyproject.toml`
87+
- Update `CHANGELOG` for the release
88+
- Ensure the commit you intend to release is on `main`
89+
90+
Create and push the release tag using the `vX.Y.Z` format:
91+
92+
```bash
93+
git tag vX.Y.Z
94+
git push origin vX.Y.Z
95+
```
96+
97+
Then publish the matching GitHub Release for that tag. The `Release` workflow will:
98+
99+
- Verify the GitHub Release tag exactly matches `v{project.version}`
100+
- Verify the tagged commit is contained in `origin/main`
101+
- Build the sdist and wheel
102+
- Run `twine check`
103+
- Wait for approval on the GitHub `pypi` environment before uploading to PyPI
104+
105+
Repository setup required for trusted publishing:
106+
107+
- Add a GitHub environment named `pypi`
108+
- Protect that environment with the required approval rules for your release process
109+
- Register the PyPI trusted publisher for repository `nm-packages/wagtail-honeypot`, workflow `.github/workflows/release.yml`, and environment `pypi`
110+
111+
After approving the `pypi` environment job, confirm both the source distribution and wheel appear on PyPI.
112+
73113
## Dependency management
74114

75115
Use `uv` to change contributor dependencies and keep the lockfile in sync:

0 commit comments

Comments
 (0)