Publish Python SDK to PyPI #3
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
| name: Publish Python SDK to PyPI | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: Existing annotated sdk-vX.Y.Z tag contained in GitHub main | |
| required: true | |
| type: string | |
| permissions: {} | |
| concurrency: | |
| group: publish-pypi-agenttool-sdk | |
| cancel-in-progress: false | |
| jobs: | |
| prepare: | |
| name: Build and verify exact Python distributions | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Check out the annotated SDK release tag | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| ref: ${{ inputs.tag }} | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Set up Bun 1.3.5 | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 | |
| with: | |
| bun-version: 1.3.5 | |
| - name: Set up Python 3.14.5 | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: 3.14.5 | |
| - name: Set up uv 0.9.26 without a shared cache | |
| uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4 | |
| with: | |
| version: 0.9.26 | |
| enable-cache: false | |
| - name: Prepare exact distributions without publication authority | |
| shell: bash | |
| env: | |
| RELEASE_TAG: ${{ inputs.tag }} | |
| run: | | |
| set -euo pipefail | |
| output="${RUNNER_TEMP}/agenttool-pypi-release" | |
| bun bin/pypi-release.ts prepare \ | |
| --tag "$RELEASE_TAG" \ | |
| --output "$output" | |
| - name: Transfer the exact release receipt | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | |
| with: | |
| name: pypi-release-receipt-${{ github.run_id }} | |
| path: ${{ runner.temp }}/agenttool-pypi-release/receipt.json | |
| if-no-files-found: error | |
| compression-level: 0 | |
| retention-days: 1 | |
| - name: Transfer the exact wheel independently | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | |
| with: | |
| name: pypi-release-wheel-${{ github.run_id }} | |
| path: ${{ runner.temp }}/agenttool-pypi-release/dist/*.whl | |
| if-no-files-found: error | |
| compression-level: 0 | |
| retention-days: 1 | |
| - name: Transfer the exact source distribution independently | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | |
| with: | |
| name: pypi-release-sdist-${{ github.run_id }} | |
| path: ${{ runner.temp }}/agenttool-pypi-release/dist/*.tar.gz | |
| if-no-files-found: error | |
| compression-level: 0 | |
| retention-days: 1 | |
| preflight: | |
| name: Check exact public PyPI state | |
| needs: prepare | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: read | |
| outputs: | |
| publish_required: ${{ steps.registry.outputs.publish_required }} | |
| wheel_required: ${{ steps.registry.outputs.wheel_required }} | |
| sdist_required: ${{ steps.registry.outputs.sdist_required }} | |
| steps: | |
| - name: Check out the same annotated SDK release tag | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| ref: ${{ inputs.tag }} | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Set up Bun 1.3.5 | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 | |
| with: | |
| bun-version: 1.3.5 | |
| - name: Set up Python 3.14.5 | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: 3.14.5 | |
| - name: Download the prepared receipt | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6 | |
| with: | |
| name: pypi-release-receipt-${{ github.run_id }} | |
| path: ${{ runner.temp }}/agenttool-pypi-release | |
| - name: Download the prepared wheel | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6 | |
| with: | |
| name: pypi-release-wheel-${{ github.run_id }} | |
| path: ${{ runner.temp }}/agenttool-pypi-release/dist | |
| - name: Download the prepared source distribution | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6 | |
| with: | |
| name: pypi-release-sdist-${{ github.run_id }} | |
| path: ${{ runner.temp }}/agenttool-pypi-release/dist | |
| - name: Decide whether exact publication is still required | |
| id: registry | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| bun bin/pypi-release.ts check \ | |
| --receipt "${RUNNER_TEMP}/agenttool-pypi-release/receipt.json" | |
| publish: | |
| name: Approve and publish exact Python distributions | |
| needs: preflight | |
| if: ${{ needs.preflight.outputs.publish_required == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 10 | |
| environment: pypi | |
| permissions: | |
| id-token: write | |
| steps: | |
| - name: Download the missing wheel only | |
| if: ${{ needs.preflight.outputs.wheel_required == 'true' }} | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6 | |
| with: | |
| name: pypi-release-wheel-${{ github.run_id }} | |
| path: ${{ runner.temp }}/agenttool-pypi-upload | |
| - name: Download the missing source distribution only | |
| if: ${{ needs.preflight.outputs.sdist_required == 'true' }} | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6 | |
| with: | |
| name: pypi-release-sdist-${{ github.run_id }} | |
| path: ${{ runner.temp }}/agenttool-pypi-upload | |
| - name: Publish through PyPI trusted publishing | |
| uses: pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247 # v1.14.1 | |
| with: | |
| packages-dir: ${{ runner.temp }}/agenttool-pypi-upload | |
| skip-existing: true | |
| verify: | |
| name: Re-download and verify exact public PyPI bytes | |
| needs: | |
| - preflight | |
| - publish | |
| if: ${{ always() && needs.preflight.result == 'success' && (needs.publish.result == 'success' || needs.publish.result == 'skipped') }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Check out the same annotated SDK release tag | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| ref: ${{ inputs.tag }} | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Set up Bun 1.3.5 | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 | |
| with: | |
| bun-version: 1.3.5 | |
| - name: Set up Python 3.14.5 | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: 3.14.5 | |
| - name: Download the prepared receipt | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6 | |
| with: | |
| name: pypi-release-receipt-${{ github.run_id }} | |
| path: ${{ runner.temp }}/agenttool-pypi-release | |
| - name: Download the prepared wheel | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6 | |
| with: | |
| name: pypi-release-wheel-${{ github.run_id }} | |
| path: ${{ runner.temp }}/agenttool-pypi-release/dist | |
| - name: Download the prepared source distribution | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6 | |
| with: | |
| name: pypi-release-sdist-${{ github.run_id }} | |
| path: ${{ runner.temp }}/agenttool-pypi-release/dist | |
| - name: Verify public hashes and archive identities without package execution | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| bun bin/pypi-release.ts verify \ | |
| --receipt "${RUNNER_TEMP}/agenttool-pypi-release/receipt.json" | |
| - name: Record the non-secret verified release receipt | |
| if: ${{ always() }} | |
| shell: bash | |
| run: | | |
| receipt="${RUNNER_TEMP}/agenttool-pypi-release/receipt.json" | |
| if test -f "$receipt"; then | |
| { | |
| echo '## PyPI release receipt' | |
| echo '```json' | |
| cat "$receipt" | |
| echo '```' | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| fi |