Skip to content

Upload Python Package #32

Upload Python Package

Upload Python Package #32

name: Upload Python Package
on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: "Release tag to publish, for example v0.4.0"
required: true
type: string
concurrency:
group: python-publish-${{ github.workflow }}-${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
cancel-in-progress: false
permissions:
contents: read
jobs:
deploy:
# PyPI trusted publishing requires a GitHub-hosted runner.
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }}
- uses: astral-sh/setup-uv@v7
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install dependencies
run: uv sync --dev --frozen
- name: Validate release tag
env:
RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.event.release.tag_name }}
run: |
set -euo pipefail
uv run python - <<'PY'
import os
import re
import subprocess
import sys
import tomllib
release_tag = os.environ.get("RELEASE_TAG", "")
if not re.fullmatch(r"v\d+\.\d+\.\d+(?:\.post\d+|\.post)?", release_tag):
sys.exit(
f"Release tags must match vX.Y.Z or vX.Y.Z.postN; received {release_tag or '<missing>'}."
)
with open("pyproject.toml", "rb") as handle:
version = tomllib.load(handle)["project"]["version"]
expected = f"v{version}"
if release_tag != expected:
sys.exit(
f"Release tag {release_tag} does not match pyproject version {version}; expected {expected}."
)
tagged_commit = subprocess.run(
["git", "tag", "--points-at", "HEAD"],
check=True,
capture_output=True,
text=True,
).stdout.splitlines()
if release_tag not in tagged_commit:
sys.exit(f"Checked-out commit is not tagged with {release_tag}.")
print(f"Release tag {release_tag} matches pyproject.toml.")
PY
- name: Ensure version is not already published
run: |
set -euo pipefail
version="$(uv run python -c 'import tomllib; print(tomllib.load(open("pyproject.toml","rb"))["project"]["version"])')"
status="$(curl -s -o /dev/null -w '%{http_code}' "https://pypi.org/pypi/manim-voiceover/$version/json")"
if [ "$status" = "200" ]; then
echo "manim-voiceover@$version is already published on PyPI."
exit 1
fi
echo "Publishing manim-voiceover@$version"
- name: Validate package
run: |
uv run ruff format --check .
uv run ruff check .
uv run ty check src/manim_voiceover
uv run mypy
uv run pytest --cov=manim_voiceover --cov-fail-under=85
- name: Build distributions
run: uv build
- name: Publish to PyPI
run: uv publish --trusted-publishing always