Prep v0.2.2 #10
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # .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 (frozen) | |
| # 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 --frozen | |
| # === 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: uv run validate-pyproject pyproject.toml | |
| - name: B4) Pyright (type check) | |
| run: uv run pyright | |
| # === 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 |