Skip to content

Commit a233f3a

Browse files
mnriemCopilot
andauthored
feat: add PyPI publishing workflow and readme metadata (#2915)
* feat: add PyPI publishing workflow and readme metadata - Add readme = "README.md" to pyproject.toml for PyPI project description - Add manual publish-pypi.yml workflow using trusted publishers (OIDC) - Update release.yml install instructions to prefer PyPI The publish workflow is manually triggered after a release, checks out the specified tag, verifies version consistency, builds with uv, and publishes using trusted publishing (no API tokens required). Prerequisites before first use: - Take ownership of the specify-cli PyPI project (#2908) - Create a 'pypi' environment in repo settings - Configure trusted publisher on PyPI for this repo/workflow Closes #2908 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address PR review feedback on publish workflow - Add actions: read permission (required for artifact upload/download) - Move version check after uv install and use uv run python (ensures Python >=3.11 with tomllib is available regardless of runner image) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: use absolute URLs for README images (PyPI compatibility) PyPI does not host images from the repository, so relative paths like ./media/logo.webp render as broken images. Switch to absolute raw.githubusercontent.com URLs so images display on both GitHub and PyPI. Ref: pypi/warehouse#5246 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address second review round - Convert remaining /media/ image path to absolute URL for PyPI - Pin release install to specific version (specify-cli==X.Y.Z) - Align setup-uv to v8.2.0 matching rest of CI Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address third review round - Use job-level permissions: actions:write on build (for upload-artifact), actions:read on publish (for download-artifact) - Include both @latest and pinned version in release notes - Add note that PyPI may lag behind the GitHub release Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: add contents:read to build job, clarify manual publish - Build job needs contents:read for checkout (job-level perms replace workflow-level) - Clarify that PyPI publishing is manually triggered, not automatic Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: force tag resolution and validate before checkout Move tag format validation before checkout and use refs/tags/ prefix to ensure we always check out a tag, not a branch with the same name. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address review - links, install cmd, python pin - Convert all relative .md links in README to absolute GitHub URLs for PyPI rendering compatibility - Fix release notes: use 'uv tool install specify-cli' (no @latest) - Pin Python 3.13 via uv python install for deterministic builds and use python3 directly instead of uv run Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address review - python setup, docs alignment, publish flag - Use actions/setup-python (pinned v6, Python 3.13) instead of uv python install for deterministic builds - Use python instead of python3 for setup-python compatibility - Remove unsupported --trusted-publishing always flag from uv publish (OIDC is auto-detected with id-token: write) - Update README install to lead with PyPI, source as fallback - Update installation guide: replace PyPI disclaimer with official package note, add PyPI as primary install method - Release notes: pin to exact version, clarify PyPI timing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: clarify PyPI availability timing in docs - README: note source install is useful when PyPI version lags - Installation guide: explain PyPI follows GitHub releases and may lag briefly; source installs are always immediately available Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: quote version specifier in release notes install command uv tool install accepts PEP 508 specifiers when quoted. Add quotes around 'specify-cli==VERSION' so users can copy-paste directly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: use specify-cli@latest consistently Use @latest to force a fresh PyPI resolve (bypasses uv's cached tool version), matching the issue acceptance criteria. Source install remains as fallback when PyPI lags. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: pin release notes to exact version, clarify manual publish Release notes (versioned changelog) must always reference the specific release version, not @latest. Use 'specify-cli==VERSION' for reproducibility. Also clarify that PyPI publishing is 'performed after' (not 'follows') each release, making the manual nature clearer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: keep source install as primary, PyPI as alternative Until PyPI ownership is fully transferred and first publish is confirmed, source installs from GitHub remain the primary recommended method. PyPI install is listed as a convenient alternative. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: align checkout pin, soften PyPI wording, absolute links - Align actions/checkout to v7.0.0 (same SHA as test.yml/release.yml) - Remove assertion that PyPI is published by maintainers (ownership transfer still pending); keep as availability statement - Use 'once published for this release' wording in release notes - Convert remaining relative links in README to absolute URLs for PyPI rendering Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: align docs and release notes with pre-transfer state - docs/installation.md: qualify PyPI as available 'once official publishing is enabled' (ownership transfer still pending) - release.yml: use specify-cli@VERSION syntax (consistent with README/docs @latest form) - PR description updated to match Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: revert release notes to match main The release.yml release notes template should not change in this PR. PyPI install instructions can be added to release notes in a future PR once publishing is confirmed working. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: revert README and installation docs to match main Do not mention PyPI in documentation until the first official PyPI release has been published. This PR only adds the workflow and readme metadata in pyproject.toml. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: fail fast if build produces no artifacts Add if-no-files-found: error to upload-artifact so a missing/empty dist/ directory fails the build job immediately rather than causing a confusing failure in the publish job. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: align artifact action pins with repo lockfiles Update upload-artifact to v7.0.1 and download-artifact to v8.0.1, matching the pins used in the repo's gh-aw workflow lockfiles. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Manfred Riem <mnriem@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 826e193 commit a233f3a

2 files changed

Lines changed: 81 additions & 0 deletions

File tree

.github/workflows/publish-pypi.yml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: Publish to PyPI
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
tag:
7+
description: 'Release tag to publish (e.g., v0.10.1)'
8+
required: true
9+
type: string
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
build:
16+
runs-on: ubuntu-latest
17+
permissions:
18+
contents: read
19+
actions: write
20+
steps:
21+
- name: Verify tag format
22+
run: |
23+
TAG="${{ inputs.tag }}"
24+
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
25+
echo "Error: '$TAG' is not a valid release tag (expected vX.Y.Z)"
26+
exit 1
27+
fi
28+
29+
- name: Checkout release tag
30+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
31+
with:
32+
ref: refs/tags/${{ inputs.tag }}
33+
34+
- name: Install uv
35+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
36+
37+
- name: Set up Python
38+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
39+
with:
40+
python-version: "3.13"
41+
42+
- name: Verify tag matches package version
43+
run: |
44+
TAG_VERSION="${{ inputs.tag }}"
45+
TAG_VERSION="${TAG_VERSION#v}"
46+
PROJECT_VERSION="$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml","rb"))["project"]["version"])')"
47+
if [[ "$TAG_VERSION" != "$PROJECT_VERSION" ]]; then
48+
echo "Error: Tag version ($TAG_VERSION) does not match pyproject.toml version ($PROJECT_VERSION)"
49+
exit 1
50+
fi
51+
52+
- name: Build package
53+
run: uv build
54+
55+
- name: Upload build artifacts
56+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
57+
with:
58+
name: dist
59+
path: dist/
60+
if-no-files-found: error
61+
62+
publish:
63+
needs: build
64+
runs-on: ubuntu-latest
65+
environment: pypi
66+
permissions:
67+
id-token: write
68+
actions: read
69+
steps:
70+
- name: Download build artifacts
71+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
72+
with:
73+
name: dist
74+
path: dist/
75+
76+
- name: Install uv
77+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
78+
79+
- name: Publish to PyPI
80+
run: uv publish

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
name = "specify-cli"
33
version = "0.11.5.dev0"
44
description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)."
5+
readme = "README.md"
56
requires-python = ">=3.11"
67
dependencies = [
78
"typer>=0.24.0",

0 commit comments

Comments
 (0)