Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .github/workflows/publish-python-sdk.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Publish Python SDK

on:
push:
branches: [main]
paths:
- "packages/python-sdk/pyproject.toml"
- "packages/python-sdk/agentstate/**"
workflow_dispatch:
inputs:
dry_run:
description: "Dry run (skip actual publish)"
required: false
default: "false"

permissions:
contents: read
id-token: write

jobs:
publish:
name: Build & Publish
runs-on: ubuntu-latest
defaults:
run:
working-directory: packages/python-sdk

steps:
- uses: actions/checkout@v7

- uses: actions/setup-python@v7
with:
python-version: "3.14"

- name: Install test dependencies
run: python -m pip install -e ".[dev]"

- name: Unit tests
run: python -m pytest -q

- name: Install build tooling
run: python -m pip install build

- name: Build distributions
run: python -m build

- name: Check if version already published
id: check-version
run: |
PKG_NAME=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['name'])")
PKG_VERSION=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
echo "pkg_name=${PKG_NAME}" >> "$GITHUB_OUTPUT"
echo "pkg_version=${PKG_VERSION}" >> "$GITHUB_OUTPUT"
if curl -sf "https://pypi.org/pypi/${PKG_NAME}/${PKG_VERSION}/json" > /dev/null; then
echo "already_published=true" >> "$GITHUB_OUTPUT"
echo "::notice::${PKG_NAME}==${PKG_VERSION} already on PyPI — skipping publish"
else
echo "already_published=false" >> "$GITHUB_OUTPUT"
echo "Publishing ${PKG_NAME}==${PKG_VERSION}"
fi
Comment on lines +54 to +60

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Any PyPI lookup failure other than a successful response, including a transient 5xx, timeout, rate limit, or network outage, is treated as already_published=false, so the workflow proceeds to publishing instead of failing or retrying the version check.

Triggers: When PyPI is temporarily unavailable or returns a non-404 error.

Suggested fix: Distinguish a genuine 404 from other curl/HTTP failures and fail or retry the check for unexpected responses.

Suggested change
if curl -sf "https://pypi.org/pypi/${PKG_NAME}/${PKG_VERSION}/json" > /dev/null; then
echo "already_published=true" >> "$GITHUB_OUTPUT"
echo "::notice::${PKG_NAME}==${PKG_VERSION} already on PyPI — skipping publish"
else
echo "already_published=false" >> "$GITHUB_OUTPUT"
echo "Publishing ${PKG_NAME}==${PKG_VERSION}"
fi
HTTP_STATUS=$(curl -sS -o /dev/null -w '%{http_code}' "https://pypi.org/pypi/${PKG_NAME}/${PKG_VERSION}/json") || {
echo "::error::Failed to check whether ${PKG_NAME}==${PKG_VERSION} is already on PyPI" >&2
exit 1
}
if [ "$HTTP_STATUS" = "200" ]; then
echo "already_published=true" >> "$GITHUB_OUTPUT"
echo "::notice::${PKG_NAME}==${PKG_VERSION} already on PyPI — skipping publish"
elif [ "$HTTP_STATUS" = "404" ]; then
echo "already_published=false" >> "$GITHUB_OUTPUT"
echo "Publishing ${PKG_NAME}==${PKG_VERSION}"
else
echo "::error::Unexpected HTTP ${HTTP_STATUS} while checking PyPI for ${PKG_NAME}==${PKG_VERSION}" >&2
exit 1
fi


- name: Publish (dry run)
if: steps.check-version.outputs.already_published == 'false' && github.event.inputs.dry_run == 'true'
run: echo "::notice::Dry run — skipping publish of ${{ steps.check-version.outputs.pkg_name }}==${{ steps.check-version.outputs.pkg_version }}"

- name: Publish
if: steps.check-version.outputs.already_published == 'false' && github.event.inputs.dry_run != 'true'
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-to-upload: packages/python-sdk/dist/*
Comment on lines +68 to +70

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The check-then-publish sequence is not atomic: two workflow runs for the same package version can both receive a 404 from PyPI and then both attempt to publish, causing one run to fail with a duplicate-release error.

Triggers: When multiple pushes or manual dispatches for the same version run concurrently.

Suggested fix: Add workflow concurrency serialization or pass skip-existing: true to the PyPI publish action.

Suggested change
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-to-upload: packages/python-sdk/dist/*
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-to-upload: packages/python-sdk/dist/*
skip-existing: true

Loading