-
Notifications
You must be signed in to change notification settings - Fork 0
146 lines (116 loc) · 4.52 KB
/
release-python.yml
File metadata and controls
146 lines (116 loc) · 4.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# .github/workflows/release-python.yml
name: Release (PyPI + versioned docs)
# CANNOT REUSE - COPY THIS TO A PYPI PROJECT AND ADJUST AS NEEDED.
# Designed to run only on version tags (e.g., vx.y.z).
# Final step before distribution.
# It builds distribution files, runs tests, prepares release, and publishes.
# IMPORTANT: The PyPI project must enable Trusted Publishers and recognize this repository.
# CI PHASES A-B-C-D:
# - Assemble: Install dependencies, verify environment setup
# - Baseline: Core validation (types exist, lint passes, tests pass)
# - Coverage: Generate coverage / testing reports
# - Deploy: Build package and docs (sanity checks for release readiness)
on:
push:
tags:
- "v*.*.*"
permissions:
contents: write # create the GitHub Release, push docs
id-token: write # PyPI Trusted Publishing (OIDC)
env:
PYTHONUNBUFFERED: "1" # real-time logging
PYTHONIOENCODING: "utf-8"
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
build-and-release:
runs-on: ubuntu-latest
environment: pypi
timeout-minutes: 30
steps:
# ------------------- ASSEMBLE -------------------
- name: A1) Checkout (with tag history)
uses: actions/checkout@v6
with:
fetch-depth: 0 # Full history for tags
- name: A2) Install uv (with caching)
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: A3) Pin Python version for consistency
run: uv python pin 3.12
- name: A4) Display version information
run: |
python --version
uv --version
uv pip list | head -n 50
- name: A5) Sync to install dependencies
run: |
uv sync --extra dev --extra docs --upgrade
# ------------------- BASELINE / TESTS -------------------
- name: B1) Validate pyproject
run: uvx validate-pyproject
- name: B2) Ruff lint (check only)
run: uvx ruff check .
- name: B3) Pyright (type check)
run: uv run pyright
- name: B4) Deptry (dependency check)
run: uvx deptry .
# ------------------- COVERAGE (TESTING) -------------------
- name: C1) Run tests (pytest; coverage per pytest.ini)
run: uv run pytest -q
# ------------ DEPLOY (BUILD, RELEASE, DOCS) -------------------
- name: D1) Extract plain version from tag (no leading 'v')
id: ver
shell: bash
run: echo "plain=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
- name: D2) Build sdist + wheel
env:
SETUPTOOLS_SCM_PRETEND_VERSION: ${{ steps.ver.outputs.plain }}
run: uv build
- name: D3) Ensure built artifact version matches tag
shell: bash
run: |
set -e
TAG="${{ steps.ver.outputs.plain }}"
echo "Tag version: $TAG"
ls dist
# Check that at least one artifact embeds the same version
if ! ls dist/*"$TAG"*.whl dist/*"$TAG"*.tar.gz >/dev/null 2>&1; then
echo "ERROR: Built artifact version does not match tag $TAG"
exit 1
fi
echo "Artifact version matches tag."
- name: D4) Validate built artifacts
run: uv run twine check dist/*
- name: D5) List dist artifacts
run: ls -lah dist
- name: D6) Create GitHub Release and upload artifacts
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }} # e.g., vx.y.z
name: ${{ github.ref_name }}
generate_release_notes: true
files: |
dist/*.whl
dist/*.tar.gz
draft: false
prerelease: false
make_latest: true
- name: D7) Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
- name: D8) Ensure 'latest' is not a version (self-heal)
if: hashFiles('mkdocs.yml', 'mkdocs.yaml') != ''
run: uv run mike delete latest --push || true
- name: D9) Deploy docs with Mike for this version and set latest
if: hashFiles('mkdocs.yml', 'mkdocs.yaml') != ''
run: |
set -e
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
VERSION="${{ steps.ver.outputs.plain }}"
echo "Deploying docs for version: $VERSION"
uv run mike deploy --push --update-aliases "$VERSION" latest
uv run mike set-default --push latest
- name: D10) Show mike versions (after)
if: hashFiles('mkdocs.yml', 'mkdocs.yaml') != ''
run: uv run mike list