Publish Python Preview to TestPyPI #2468
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 Preview to TestPyPI | |
| # Triggered when the build workflow completes. Runs in the base repo context, | |
| # so it has access to secrets even for fork PRs. The code executed here comes | |
| # from the base branch, not the fork — only the built wheel artifacts come | |
| # from the fork's workflow run. | |
| on: | |
| workflow_run: | |
| workflows: ["Build Python Preview"] | |
| types: [completed] | |
| permissions: | |
| contents: read | |
| # Pinned Python build toolchain — see .github/python-toolchain.env, which is the | |
| # single place these two values are recorded, along with the green run they came | |
| # from. Change one, change them all: the python-toolchain-pins job in | |
| # lint-release-workflows.yml fails if any workflow's literal disagrees with that file. | |
| # | |
| # Audited alongside build-python-preview.yml: this job only uploads the wheels | |
| # that workflow already built, so it never touches a lockfile. | |
| env: | |
| UV_VERSION: "0.12.1" | |
| PYTHON_VERSION: "3.12" | |
| jobs: | |
| publish: | |
| runs-on: ubuntu-latest | |
| if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request' | |
| environment: pypi | |
| permissions: | |
| actions: read | |
| pull-requests: write | |
| steps: | |
| - name: Download dist artifacts | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| name: python-preview-dist | |
| path: dist-preview/ | |
| run-id: ${{ github.event.workflow_run.id }} | |
| github-token: ${{ github.token }} | |
| - name: Download PR metadata | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| name: python-preview-metadata | |
| path: pr-metadata/ | |
| run-id: ${{ github.event.workflow_run.id }} | |
| github-token: ${{ github.token }} | |
| - name: Read PR metadata | |
| id: meta | |
| # These three files come from a workflow_run artifact, which on a fork PR is | |
| # produced by the fork's own run — so they are untrusted input reaching a job | |
| # that holds `pull-requests: write`. Validate the shape before it becomes a step | |
| # output: `echo "k=$(cat f)"` exits 0 even when `cat` fails, so a missing file | |
| # silently yielded an empty value, and a value containing a newline would set | |
| # arbitrary extra outputs. A single grouped redirect also satisfies SC2129, | |
| # which reviewdog reports at error level now that this file is in the | |
| # actionlint scope. | |
| run: | | |
| set -euo pipefail | |
| pr=$(tr -d '\n' < pr-metadata/pr-number) | |
| version=$(tr -d '\n' < pr-metadata/version) | |
| sha=$(tr -d '\n' < pr-metadata/sha) | |
| [[ "$pr" =~ ^[0-9]+$ ]] || { echo "::error::bad pr-number: '$pr'"; exit 1; } | |
| [[ "$sha" =~ ^[0-9a-f]{40}$ ]] || { echo "::error::bad sha: '$sha'"; exit 1; } | |
| [[ "$version" =~ ^0\.0\.0\.dev[0-9]+$ ]] || { echo "::error::bad version: '$version'"; exit 1; } | |
| { | |
| echo "pr-number=$pr" | |
| echo "version=$version" | |
| echo "sha=$sha" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 | |
| with: | |
| version: ${{ env.UV_VERSION }} | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Publish all packages to TestPyPI | |
| run: | | |
| echo "Publishing artifacts:" | |
| ls -1 dist-preview/ | |
| uv publish \ | |
| --publish-url https://test.pypi.org/legacy/ \ | |
| --check-url https://test.pypi.org/simple/ \ | |
| dist-preview/* | |
| env: | |
| UV_PUBLISH_TOKEN: ${{ secrets.TEST_PYPI_API_TOKEN }} | |
| - name: Find existing preview comment | |
| if: always() | |
| id: find-comment | |
| uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0 | |
| with: | |
| issue-number: ${{ steps.meta.outputs.pr-number }} | |
| comment-author: 'github-actions[bot]' | |
| body-includes: '<!-- ag-ui-python-preview -->' | |
| - name: Post or update install instructions | |
| if: success() | |
| uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0 | |
| with: | |
| comment-id: ${{ steps.find-comment.outputs.comment-id }} | |
| issue-number: ${{ steps.meta.outputs.pr-number }} | |
| edit-mode: replace | |
| body: | | |
| <!-- ag-ui-python-preview --> | |
| ## Python Preview Packages | |
| Version `${{ steps.meta.outputs.version }}` published to [TestPyPI](https://test.pypi.org). | |
| > **Warning**: These packages are built from contributor code that may not yet have been vetted for correctness or security. Install at your own risk and do not use in production. | |
| ### Install with uv | |
| Add the TestPyPI index to your `pyproject.toml`: | |
| ```toml | |
| [[tool.uv.index]] | |
| name = "testpypi" | |
| url = "https://test.pypi.org/simple/" | |
| explicit = true | |
| ``` | |
| Then install the packages you need: | |
| ```bash | |
| # Core SDK | |
| uv add 'ag-ui-protocol==${{ steps.meta.outputs.version }}' --index testpypi | |
| # Integrations (each already depends on the matching ag-ui-protocol preview) | |
| uv add 'ag-ui-langgraph==${{ steps.meta.outputs.version }}' --index testpypi | |
| uv add 'ag-ui-crewai==${{ steps.meta.outputs.version }}' --index testpypi | |
| # NOTE: ag-ui-agent-spec depends on pyagentspec (git-only, not on PyPI). | |
| # You will need to install pyagentspec separately from its git repo. | |
| uv add 'ag-ui-agent-spec==${{ steps.meta.outputs.version }}' --index testpypi | |
| uv add 'ag_ui_adk==${{ steps.meta.outputs.version }}' --index testpypi | |
| uv add 'ag_ui_strands==${{ steps.meta.outputs.version }}' --index testpypi | |
| ``` | |
| ### Install with pip | |
| ```bash | |
| pip install \ | |
| --index-url https://test.pypi.org/simple/ \ | |
| --extra-index-url https://pypi.org/simple/ \ | |
| ag-ui-protocol==${{ steps.meta.outputs.version }} | |
| ``` | |
| > Use `--extra-index-url https://pypi.org/simple/` so pip can resolve | |
| > transitive dependencies (pydantic, fastapi, etc.) from real PyPI. | |
| --- | |
| _Commit: ${{ steps.meta.outputs.sha }}_ | |
| - name: Post failure comment | |
| if: failure() | |
| uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0 | |
| with: | |
| comment-id: ${{ steps.find-comment.outputs.comment-id }} | |
| issue-number: ${{ steps.meta.outputs.pr-number }} | |
| edit-mode: replace | |
| body: | | |
| <!-- ag-ui-python-preview --> | |
| ## Python Preview Packages — Publish Failed | |
| Preview publish failed for commit ${{ steps.meta.outputs.sha }}. | |
| See the [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details. |