Skip to content

Commit b4e5c02

Browse files
Sodawyxclaude
andcommitted
feat(release): publish sdist + wheel to PyPI on tag push
Adds two jobs to the release workflow so every v* tag also lands the package on PyPI alongside the binary GitHub Release: - build-dist: builds sdist + wheel with `python -m build`, verifies the tag version appears in the filenames, and runs `twine check` before uploading as an artifact. - publish-pypi: gated by the `pypi` GitHub environment; downloads the artifact and uploads via pypa/gh-action-pypi-publish using the PYPI_API_TOKEN repository secret. The existing `release` job now filters downloaded artifacts to `agentrun-*` so it doesn't pick up python-dist. Setup required once per repo: - Create a PyPI project-scoped API token for `agentrun-cli` and add it as the `PYPI_API_TOKEN` Actions secret. - (Optional, recommended) Configure the `pypi` environment with required reviewers so every publish needs manual approval. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent e46d5bb commit b4e5c02

1 file changed

Lines changed: 89 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ jobs:
174174
- uses: actions/download-artifact@v4
175175
with:
176176
path: dist
177+
pattern: agentrun-*
177178
merge-multiple: true
178179

179180
- name: List artifacts
@@ -201,3 +202,91 @@ jobs:
201202
dist/agentrun-*.zip
202203
dist/agentrun-*.sha256
203204
dist/SHA256SUMS
205+
206+
# ---------------------------------------------------------------------
207+
# Build sdist + wheel for PyPI. Runs in parallel with the binary build
208+
# matrix; decoupled so a PyPI outage does not block the GitHub Release
209+
# (and vice versa).
210+
# ---------------------------------------------------------------------
211+
build-dist:
212+
name: Build sdist + wheel
213+
needs: verify-version
214+
runs-on: ubuntu-latest
215+
steps:
216+
- uses: actions/checkout@v4
217+
with:
218+
ref: ${{ needs.verify-version.outputs.tag }}
219+
fetch-depth: 0 # setuptools-scm needs full history + tags
220+
221+
- uses: actions/setup-python@v5
222+
with:
223+
python-version: ${{ env.PYTHON_VERSION }}
224+
225+
- name: Build sdist + wheel
226+
run: |
227+
python -m pip install --upgrade pip build
228+
python -m build --sdist --wheel --outdir dist-pypi
229+
ls -lh dist-pypi/
230+
231+
- name: Verify built artifacts carry the tag version
232+
run: |
233+
VERSION="${{ needs.verify-version.outputs.version }}"
234+
# Filenames follow PEP 440 / wheel spec: agentrun_cli-<version>-py3-none-any.whl
235+
# and agentrun_cli-<version>.tar.gz. Bail out if the version string is absent.
236+
if ! ls dist-pypi/ | grep -q "agentrun_cli-${VERSION}"; then
237+
echo "::error::Built artifacts in dist-pypi/ do not contain version ${VERSION}:"
238+
ls dist-pypi/
239+
exit 1
240+
fi
241+
242+
- name: Check metadata with twine
243+
run: |
244+
python -m pip install twine
245+
python -m twine check dist-pypi/*
246+
247+
- uses: actions/upload-artifact@v4
248+
with:
249+
name: python-dist
250+
path: dist-pypi/*
251+
retention-days: 7
252+
if-no-files-found: error
253+
254+
# ---------------------------------------------------------------------
255+
# Publish sdist + wheel to PyPI.
256+
#
257+
# Auth: uses the PYPI_API_TOKEN repository secret. The secret must be a
258+
# PyPI project-scoped token (account → Add API token → scope:
259+
# "agentrun-cli"). Add it at Settings → Secrets and variables → Actions.
260+
#
261+
# Hardening (recommended once the first release lands):
262+
# - Configure the `pypi` environment with required reviewers, so every
263+
# publish requires a manual approval.
264+
# - Migrate to PyPI trusted publishing (OIDC): drop the token, add
265+
# `id-token: write` to permissions, replace the `password:` input
266+
# with no input at all. See: https://docs.pypi.org/trusted-publishers/
267+
# ---------------------------------------------------------------------
268+
publish-pypi:
269+
name: Publish to PyPI
270+
needs: [verify-version, build-dist]
271+
runs-on: ubuntu-latest
272+
environment:
273+
name: pypi
274+
url: https://pypi.org/p/agentrun-cli
275+
steps:
276+
- uses: actions/download-artifact@v4
277+
with:
278+
name: python-dist
279+
path: dist-pypi
280+
281+
- name: List artifacts to upload
282+
run: ls -lh dist-pypi/
283+
284+
- name: Publish to PyPI
285+
uses: pypa/gh-action-pypi-publish@release/v1
286+
with:
287+
packages-dir: dist-pypi
288+
password: ${{ secrets.PYPI_API_TOKEN }}
289+
# Fail loudly if the version already exists on PyPI; re-uploading
290+
# is prevented by PyPI anyway, and silent skips mask tag reuse.
291+
skip-existing: false
292+
verify-metadata: true

0 commit comments

Comments
 (0)