Skip to content

#76: publish releases to PyPI, with a TestPyPI rehearsal - #79

Draft
craigmcchesney wants to merge 1 commit into
mainfrom
feat/76-pypi-publish
Draft

craigmcchesney wants to merge 1 commit into
mainfrom
feat/76-pypi-publish

Conversation

@craigmcchesney

Copy link
Copy Markdown
Collaborator

Closes #76. Implements plan/tickets/76/plan.md (merged in #78).

Draft until the manual setup is done. Do not merge before manual steps 1–3 of the plan:
pending trusted publishers on pypi.org (environment pypi) and test.pypi.org (environment testpypi),
and the pypi GitHub environment with its required reviewer, "prevent self-review" off, and a rel-*
tag rule. A job naming a missing environment creates it unprotected.

Changes

  • release.yml
    • publish-pypi is enabled on rel-* tag pushes, with needs: [build, publish-github-release] (D4).
    • Both uploads set skip-existing: true (D3a).
    • A post-upload check compares the index's digests against SHA256SUMS (D5).
    • New publish-testpypi job behind a testpypi dispatch input (D3).
    • Dispatch builds drop the local version segment (verified locally: 1.16.1.dev66).
    • release-dist retention goes from 7 to 30 days (D2).
  • .github/scripts/check-index-digests.py: the digest check, which self-tests on each run.
    • It deviates from the plan by being a script rather than inline shell; the plan's D5 records why.
    • The publish jobs sparse-checkout .github/scripts for it, which adds contents: read.
    • Tested locally against real PyPI (sigstore 3.5.0): it passes on matching files, fails on a changed digest, and fails on a version the index doesn't have.
  • pyproject.toml: Documentation and Changelog URLs (D7).
  • Docs
    • README leads with pip install dp-python-lib and uses quoted extras and absolute blob/main links.
    • README.env has a new "Installing from PyPI" section with the --no-deps / --ignore-missing recipe.
    • The cookbook quotes its extras.
    • NEXT.md gets a Publish releases to PyPI (enable the disabled publish-pypi job) #76 section, an updated ## Installing, and an approval step in the cut checklist.
    • CLAUDE.md describes the enabled flow.

Verification

  • Pin-check grep is empty; actionlint is clean apart from a pre-existing SC2012 info note.
  • ruff check, ruff format --check, mypy src/, cookbook checker (129 snippets), release-notes checker, pytest tests/unit (968 passed).
  • Dispatch-override build gives 1.16.1.dev66; twine check --strict passes.
  • After the manual setup: dispatch from this branch with testpypi=true.
    • The build has no local version, the upload and digest check pass, and the test.pypi.org page renders with working links.
    • In a clean venv, pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ "dp-python-lib==<dev version>" installs and imports MldpClient.
  • A dispatch with testpypi=false stops after build/sign, with both publish jobs skipped.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UCxWh2HqjqhsmLwSJbJAWE

- release.yml: enable publish-pypi on rel-* tags, after the GitHub Release
  (needs publish-github-release), with skip-existing and a post-upload digest
  check against SHA256SUMS.  New publish-testpypi job behind a testpypi
  dispatch input; dispatch builds drop the local version segment.
  release-dist retention 7 -> 30 days to match the approval window.
- .github/scripts/check-index-digests.py: the digest check (self-tested).
- pyproject.toml: Documentation and Changelog URLs.
- README: lead with pip install from PyPI, quoted extras, absolute links.
- README.env: installing from PyPI and verifying a pip download.
- Cookbook: quote the extras.  NEXT.md: #76 section, Installing, and the
  approval step in the cut checklist.  CLAUDE.md: the enabled flow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UCxWh2HqjqhsmLwSJbJAWE
Copilot AI balanced review requested due to automatic review settings October 5, 2026 19:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Note

Copilot was unable to run its full agentic suite in this review.

Copilot review overview

Review effort: Lite
Findings: 2 Medium severity

Open (2)
What changed in this PR

This PR enables publishing signed release artifacts to PyPI/TestPyPI via Trusted Publishing and updates project documentation to reflect PyPI installation and verification guidance.

Changes:

  • Enable PyPI publishing (and optional TestPyPI rehearsal) in the release workflow, including a post-upload digest verification step.
  • Add a digest-checking script to confirm PyPI serves exactly the signed artifacts.
  • Update READMEs/cookbook/release notes to document PyPI installs, quoting extras, and verification steps.
File Description
pyproject.toml Adds Documentation/Changelog project URLs for better package metadata.
plan/​tickets/​76/​plan.md Updates Issue #76 plan status and implementation notes for digest checking.
doc/​release-notes/​NEXT.md Adds release-notes section and checklist updates for PyPI publishing flow.
doc/​cookbook/​query.md Quotes extras in pip install command to avoid zsh globbing.
doc/​cookbook/​conventions.md Same extras quoting fix in conventions recipe.
doc/​cookbook/​README.md Quotes editable extras install for zsh compatibility.
README.md Updates install instructions to PyPI and fixes links for non-GitHub renderers.
README.env Adds “Installing from PyPI” verification instructions and updates notes.
CLAUDE.md Updates release workflow documentation and examples to include PyPI publish path.
.github/​workflows/​release.yml Enables publish jobs for PyPI/TestPyPI and adds digest verification + longer artifact retention.
.github/​scripts/​check-index-digests.py New script to compare SHA256SUMS against the index JSON API digests.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

if not line.strip():
continue
digest, name = line.split(maxsplit=1)
sums[name.lstrip("*")] = digest.lower()
Comment on lines +108 to +115
set -euo pipefail
# A rehearsal builds an untagged commit, which setuptools-scm versions with a local
# segment (1.16.1.dev61+g496f0e0). PyPI and TestPyPI both reject local versions, so
# a dispatch drops it (1.16.1.dev61) to stay uploadable to TestPyPI. A tag build has
# no local segment and is left alone.
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
export SETUPTOOLS_SCM_OVERRIDES_FOR_DP_PYTHON_LIB='{local_scheme="no-local-version"}'
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish releases to PyPI (enable the disabled publish-pypi job)

2 participants