Skip to content

ci(PLT-1250): tag-triggered PyPI release pipeline#133

Merged
eywalker merged 9 commits into
devfrom
eywalker/plt-1250-set-up-tag-triggered-cicd-pipeline-for-v010rc1-pypi-release
Apr 8, 2026
Merged

ci(PLT-1250): tag-triggered PyPI release pipeline#133
eywalker merged 9 commits into
devfrom
eywalker/plt-1250-set-up-tag-triggered-cicd-pipeline-for-v010rc1-pypi-release

Conversation

@kurodo3

@kurodo3 kurodo3 Bot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Migrates build backend from setuptools+setuptools-scm to hatchling+hatch-vcs (identical auto-versioning from git tags, matches starfix-python pattern)
  • Fixes Homepage URL (walkerlabnauticalab) in pyproject.toml
  • Adds publish.yml: tag-triggered pipeline (v[0-9]+.[0-9]+.[0-9]+*) with sequential job chain: test → license-check → build → publish-testpypi → publish-pypi → GitHub Release (OIDC, no secrets)
  • Adds license-check and dependency-review jobs to run-tests.yml CI (mirrors starfix-python ci.yml)
  • pip-licenses>=5.0.0 added to dev deps

License gate

All dependency licenses are checked against an approved permissive allowlist (MIT, Apache-2.0, BSD variants, ISC, PSF) on every push, PR, and tag. Copyleft licenses (GPL, AGPL, LGPL) are denied on PRs via actions/dependency-review-action@v4. The --partial-match flag handles free-form license strings from packages.

Note: the license gate uses uv sync --locked --dev (no optional extras). If a new optional extra introduces a copyleft transitive dependency, it would not be caught by this gate. This is a documented trade-off.

Manual setup (already done by @eywalker)

  • PyPI Trusted Publisher configured (publish.yml, environment pypi)
  • TestPyPI Trusted Publisher configured (publish.yml, environment testpypi)
  • GitHub Environments pypi and testpypi created in repo settings

Test plan

  • CI passes on this PR (test, license-check, dependency-review)
  • After merge to dev, push a v0.1.0rc1 tag and verify the publish workflow triggers and completes
  • Confirm pip install orcapod==0.1.0rc1 works from PyPI

Closes PLT-1250

kurodo3 Bot and others added 4 commits April 8, 2026 06:09
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@codecov

codecov Bot commented Apr 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a tag-triggered release pipeline to publish orcapod to TestPyPI/PyPI using OIDC Trusted Publishing, while migrating packaging to hatchling + hatch-vcs for tag-based versioning.

Changes:

  • Switch build backend from setuptools/setuptools-scm to hatchling/hatch-vcs and update project homepage URL.
  • Add tag-triggered publish.yml workflow with a test → license check → build → publish (TestPyPI then PyPI) → GitHub Release chain.
  • Add license checking and dependency review jobs to the main CI workflow; add pip-licenses to dev dependencies/lockfile.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

File Description
pyproject.toml Migrates build backend to hatch + VCS-based versioning; adds pip-licenses dev dependency; updates homepage URL.
uv.lock Locks pip-licenses (+ transitive prettytable) and updates extras resolution entries.
.github/workflows/run-tests.yml Adds license-check and dependency-review jobs; adjusts checkout depth for hatch-vcs.
.github/workflows/publish.yml Adds tag-triggered release workflow for build/publish/release using OIDC.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/publish.yml Outdated
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+*"

Copilot AI Apr 8, 2026

Copy link

Choose a reason for hiding this comment

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

The tag filter uses a regex-like pattern (with +), but GitHub Actions tag filters are glob patterns (no + quantifier). As written, this will only match tags that literally contain + characters (e.g., v1+.2+.3+...) and will not trigger for tags like v0.1.0 or v0.1.0rc1. Use a glob-compatible pattern (e.g., v[0-9]*.[0-9]*.[0-9]* or a simpler v* if acceptable).

Suggested change
- "v[0-9]+.[0-9]+.[0-9]+*"
- "v[0-9]*.[0-9]*.[0-9]*"

Copilot uses AI. Check for mistakes.
Comment thread pyproject.toml Outdated
[build-system]
requires = ["setuptools>=64", "wheel", "setuptools-scm>=8"]
build-backend = "setuptools.build_meta"
requires = ["hatchling", "hatch-vcs"]

Copilot AI Apr 8, 2026

Copy link

Choose a reason for hiding this comment

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

build-system.requires no longer specifies minimum versions. Since the previous config pinned minimums (e.g., setuptools>=64, setuptools-scm>=8), consider adding minimum versions for hatchling/hatch-vcs as well to avoid builds breaking on older environments (and to document the expected feature set for source = "vcs" and the vcs hook).

Suggested change
requires = ["hatchling", "hatch-vcs"]
requires = ["hatchling>=1.21.0", "hatch-vcs>=0.4.0"]

Copilot uses AI. Check for mistakes.
…cense allowlist)

- Pin hatchling>=1.21.0 and hatch-vcs>=0.4.0 in build-system.requires
- Fix publish.yml tag glob: replace regex `+` quantifier with glob `*`
  (GitHub Actions uses fnmatch globs, not regex; `v[0-9]+` matched literal `+`)
- Expand pip-licenses --allow-only to cover legacy PyPI metadata strings:
  "Apache Software License", "BSD License", "BSD", "Python Software Foundation License"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
name: Publish to PyPI

on:
push:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed: changed to "v[0-9]*.[0-9]*.[0-9]*" using glob * quantifiers. GitHub Actions tag filters use fnmatch-style globs, not regex — the previous + was treated as a literal character and would never have triggered. The updated pattern matches v0.1.0, v1.2.3, and pre-releases like v0.1.0rc1.

Comment thread pyproject.toml
@@ -1,6 +1,6 @@
[build-system]
requires = ["setuptools>=64", "wheel", "setuptools-scm>=8"]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed: pinned hatchling>=1.21.0 and hatch-vcs>=0.4.0. These minimums ensure the source = "vcs" option (added in hatch-vcs 0.3.0) and the VCS hook are available, matching the spirit of the previous setuptools>=64/setuptools-scm>=8 pins.

@kurodo3

kurodo3 Bot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor Author

Review response — dbd8724

All Copilot review comments addressed in commit dbd8724:

1. Tag filter glob pattern (publish.yml)
Fixed "v[0-9]+.[0-9]+.[0-9]+*""v[0-9]*.[0-9]*.[0-9]*". GitHub Actions tag filters are fnmatch globs, not regexes — + has no special meaning and was being matched literally. The updated pattern correctly triggers on v0.1.0, v1.2.3, and pre-release tags like v0.1.0rc1.

2. Build tool minimum versions (pyproject.toml)
Pinned hatchling>=1.21.0 and hatch-vcs>=0.4.0 in [build-system].requires. These versions ensure the source = "vcs" configuration and VCS version file hook are available, maintaining the same intent as the previous setuptools>=64/setuptools-scm>=8 pins.

3. License allowlist expanded (both workflows)
Also expanded pip-licenses --allow-only to cover legacy PyPI metadata strings that --partial-match couldn't match against SPDX identifiers alone: added Apache Software License, BSD License, BSD, and Python Software Foundation License.

kurodo3 Bot and others added 3 commits April 8, 2026 15:03
Several packages report non-SPDX license strings that --partial-match
couldn't match against the original allowlist:
- ray, msgpack, asttokens: "Apache 2.0" (not "Apache-2.0")
- filelock: "Unlicense" (public domain dedication)
- hypothesis: "MPL-2.0"
- certifi: "Mozilla Public License 2.0 (MPL 2.0)"
- psycopg: "LGPL-3.0-only" (existing intentional dep, safe under Python dynamic linking)

Added all required strings to both publish.yml and run-tests.yml.
Verified locally: exit code 0 with no violations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
License check takes ~5s vs 3+ minutes for tests. Failing fast on a
disallowed dependency before burning CI minutes is the right order.

- publish.yml: license-check → test → build → publish
- run-tests.yml: license-check → test → spiral-integration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eliminates the duplicated license-check job definition across
publish.yml and run-tests.yml. Both now delegate to
.github/workflows/_license-check.yml via workflow_call, so the
allowlist only needs updating in one place.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@eywalker eywalker merged commit be1787e into dev Apr 8, 2026
11 checks passed
@eywalker eywalker deleted the eywalker/plt-1250-set-up-tag-triggered-cicd-pipeline-for-v010rc1-pypi-release branch May 18, 2026 21:14
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.

2 participants