-
Notifications
You must be signed in to change notification settings - Fork 0
121 lines (96 loc) · 3.69 KB
/
Copy pathrelease.yml
File metadata and controls
121 lines (96 loc) · 3.69 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
# .github/workflows/release.yml
name: Release (PyPI)
# WHY: Publish a tagged release to PyPI and create a GitHub Release.
# REQ: Trigger ONLY on version tags like v1.2.3.
# REQ: PyPI project must be configured for Trusted Publishing (OIDC).
on:
push:
tags:
- "v*.*.*" # WHY: Trigger on version tags like 'vx.y.z'.
permissions: # WHY: Use least privileges required.
contents: write # WHY: Create GitHub Release + push gh-pages for mike
id-token: write # WHY: PyPI Trusted Publishing (OIDC)
env:
PYTHONUNBUFFERED: "1" # WHY: Real-time logging.
PYTHONIOENCODING: "utf-8" # WHY: Ensure UTF-8 encoding so docs with international characters work.
UV_PYTHON: "3.14"
jobs:
build-and-release:
runs-on: ubuntu-latest
timeout-minutes: 30
environment: pypi # WHY: Use 'pypi' environment for PyPI publishing; ignore warnings.
steps:
# === ASSEMBLE ===
- name: A1) Checkout this repository with full history and tags
uses: actions/checkout@v6
with:
fetch-depth: 0
fetch-tags: true
ref: ${{ github.ref }}
- name: A2) Install uv (with caching and uv.lock awareness)
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
- name: A3) Install Python 3.14
run: uv python install 3.14
- name: A4) Display versions
run: |
uv --version
uv run python --version
- name: A5) Sync to install all dependencies
# REQ: dev extra SHOULD include ruff/pyright/pytest/deptry (as used below).
# REQ: docs extra MUST include project documentation toolchain.
run: |
uv sync --extra dev --extra docs --upgrade
# === BASELINE CHECKS (VALIDATE ONLY) ===
- name: B1) Ruff format (check only)
run: uv run ruff format --check .
- name: B2) Ruff lint (no fixes)
run: uv run ruff check .
- name: B3) Validate project.toml
run: uvx validate-pyproject
- name: B4) Pyright (type check)
run: uv run pyright
- name: B5) Deptry (dependency check)
run: uvx deptry .
# === DEPLOY (BUILD, RELEASE, DOCS, PACKAGE) ===
- 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
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
# WHY: Twine checks package metadata before publishing.
# Install it only here so it is not required for normal local development.
run: uv tool 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 (Trusted Publishing)
uses: pypa/gh-action-pypi-publish@release/v1