Skip to content

Publish threadplane-middleware (Python) #5

Publish threadplane-middleware (Python)

Publish threadplane-middleware (Python) #5

# Staged PyPI publish workflow for threadplane-middleware (Python package).
#
# This workflow uses PyPI TRUSTED PUBLISHING (OIDC) — no API token secret is
# required. GitHub exchanges its OIDC token for a short-lived PyPI upload
# credential automatically when the job has `id-token: write`.
#
# To enable trusted publishing on PyPI:
# 1. Log into PyPI under the **cacheplane** organization.
# 2. Navigate to threadplane-middleware → Settings → "Trusted Publishers".
# 3. Add a **Pending Publisher** with:
# Repository: cacheplane/angular-agent-framework
# Workflow: publish-middleware-python.yml
# Environment: (leave blank, or set to "pypi" if you create one)
# 4. The FIRST-EVER publish must be bootstrapped locally by a maintainer
# using a PyPI API token (`uv publish --token <tok> dist/*`). After that
# initial upload creates the project on PyPI, all subsequent releases use
# OIDC from this workflow — no secret needed.
#
# This workflow is MANUALLY TRIGGERED ONLY — it will never run automatically
# on push or pull_request. A maintainer must dispatch it from the Actions tab
# (or via `gh workflow run`) after verifying the release is ready.
#
# Inputs:
# dry_run (default: true) — when true, `uv publish --dry-run` is used and
# nothing is uploaded to PyPI. Set to false only for a real release.
name: Publish threadplane-middleware (Python)
on:
# STAGED: dispatch manually only. Never add push: or pull_request: triggers.
workflow_dispatch:
inputs:
dry_run:
description: "Dry run — skip actual upload to PyPI (default: true)"
type: boolean
default: true
concurrency:
group: publish-middleware-python
cancel-in-progress: false
permissions:
contents: read
jobs:
build-and-publish:
name: Build and publish threadplane-middleware
runs-on: ubuntu-latest
permissions:
id-token: write # Required for OIDC trusted publishing to PyPI
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install uv
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
version: "latest"
- name: Run tests before publishing
working-directory: packages/threadplane-middleware
run: |
uv venv
uv pip install -e '.[test]'
uv run pytest -q
- name: Build distribution
working-directory: packages/threadplane-middleware
run: uv build
- name: Publish to PyPI (dry run)
if: ${{ inputs.dry_run == true }}
working-directory: packages/threadplane-middleware
run: uv publish --dry-run dist/*
# uv publish, not the pypa action: the pinned action image's twine
# rejected the Metadata-Version 2.5 that current `uv build` emits
# ("InvalidDistribution: '2.5' is not a valid metadata version"), while
# the dry-run path — which already uses uv — passed. One toolchain for
# build, dry-run, and publish removes that skew permanently. PyPI
# trusted publishing is bound to repo + workflow filename, so the same
# OIDC token works; uv picks it up via --trusted-publishing.
- name: Publish to PyPI (real release — OIDC trusted publishing)
if: ${{ inputs.dry_run == false }}
working-directory: packages/threadplane-middleware
run: uv publish --trusted-publishing always dist/*