Publish to PyPI #24
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: Publish to PyPI | |
| on: | |
| push: | |
| tags: | |
| - 'v[0-9]*' | |
| # Retry an existing tag without moving it. A publish can fail for reasons that | |
| # have nothing to do with the code — a stale action pin, a PyPI outage — and | |
| # with only the tag trigger the choices were to delete and re-push the tag or | |
| # to burn a version number on a CI fix. Neither is a good answer to | |
| # "the upload failed, run it again". | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: Existing tag to build and publish (e.g. v1.2.3) | |
| required: true | |
| type: string | |
| concurrency: | |
| group: pypi-publish-${{ inputs.tag || github.ref_name }} | |
| cancel-in-progress: false | |
| permissions: | |
| contents: read | |
| jobs: | |
| build: | |
| name: Build distribution | |
| runs-on: ubuntu-latest | |
| env: | |
| # The tag being released, whether it arrived by push or by dispatch. | |
| TAG: ${{ inputs.tag || github.ref_name }} | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| ref: ${{ inputs.tag || github.ref_name }} | |
| - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 | |
| with: | |
| python-version: '3.12' | |
| - name: Install build tooling | |
| run: python -m pip install --upgrade build twine | |
| - name: Verify tag matches pyproject version | |
| run: | | |
| if [[ ! "$TAG" =~ ^v[0-9] ]]; then | |
| echo "Release tag '$TAG' must start with 'v' followed by a digit (e.g. v1.0.0)" >&2 | |
| exit 1 | |
| fi | |
| tag="${TAG#v}" | |
| pkg_version=$(python -c "import tomllib,pathlib; print(tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['version'])") | |
| if [ "$tag" != "$pkg_version" ]; then | |
| echo "Release tag ($tag) does not match pyproject.toml version ($pkg_version)" >&2 | |
| exit 1 | |
| fi | |
| - name: Build sdist and wheel | |
| run: python -m build | |
| - name: Check distribution metadata | |
| run: python -m twine check --strict dist/* | |
| - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 | |
| with: | |
| name: dist | |
| path: dist/ | |
| publish: | |
| name: Publish to PyPI | |
| needs: build | |
| runs-on: ubuntu-latest | |
| environment: | |
| name: pypi | |
| url: https://pypi.org/p/hotdata-framework | |
| permissions: | |
| id-token: write | |
| steps: | |
| - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 | |
| with: | |
| name: dist | |
| path: dist/ | |
| # v1.13.0's bundled twine rejects `Metadata-Version: 2.5`, which current | |
| # hatchling emits: `InvalidDistribution: '2.5' is not a valid metadata | |
| # version`. The build job's own `twine check --strict` passes, because it | |
| # pip-installs a current twine — so the failure appears only at upload, | |
| # after the tag is already public. | |
| - name: Publish via Trusted Publishing | |
| uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2 |