Release #1
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
| name: Release (TestPyPI) | |
| on: | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| # Matches ci.yml: bash everywhere keeps the make recipes portable across the runner images. | |
| defaults: | |
| run: | |
| shell: bash | |
| jobs: | |
| release: | |
| name: Publish to TestPyPI | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: read | |
| # OIDC token for PyPI trusted publishing, scoped to this job so nothing else in the | |
| # workflow can mint one. Job-level permissions replace the workflow-level block outright, | |
| # so contents: read has to be repeated here for the checkout. | |
| id-token: write | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v6 | |
| with: | |
| enable-cache: true | |
| # The same target CI and the pre-push hook run, so the release path cannot drift from the | |
| # checks: it builds into dist/, validates the metadata with twine, and imports the wheel in | |
| # a throwaway environment. It leaves dist/ in place, which is what gets published below. | |
| - run: make dist-check | |
| # No username, password or token: the TestPyPI trusted publisher is matched on this | |
| # repository and on this workflow's filename, so renaming this file breaks publishing. | |
| # | |
| # Deliberately no skip-existing. A version already present on the index should fail the run | |
| # loudly rather than pass as a no-op, because neither index allows a version to be | |
| # re-uploaded once taken -- the fix is always a new version, never a retry. | |
| - name: Publish to TestPyPI | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| repository-url: https://test.pypi.org/legacy/ |