Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: release

# Publish to PyPI with OIDC trusted publishing. No token is stored anywhere.
#
# One-time setup on PyPI: add a trusted publisher for project "plexus-mesh",
# owner "HarperZ9", repo "plexus", workflow "release.yml", environment "pypi".
# For a project that does not exist yet, register it as a PENDING publisher; the
# first successful run creates the project. Then set the repository variable
# PYPI_ENABLED to 'true' and push a tag:
# git tag v0.2.0 && git push origin v0.2.0
#
# Actions are pinned by commit SHA, not by tag. A moving tag is a supply-chain
# hole, and this is a project about verifiable provenance.

on:
push:
tags: ["v*"]
release:
types: [published]
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
with:
python-version: "3.12"

- name: build sdist and wheel
run: |
python -m pip install --upgrade build
python -m build

- name: the tag must match the declared version
if: github.event_name != 'workflow_dispatch'
run: |
PKG_VER=$(python -c "import tomllib;print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
TAG_VER="${GITHUB_REF_NAME#v}"
if [ -n "$TAG_VER" ] && [ "$TAG_VER" != "$PKG_VER" ]; then
echo "tag $TAG_VER does not match pyproject $PKG_VER"; exit 1
fi
echo "version gate: tag $TAG_VER == pyproject $PKG_VER"

- name: artifact digests, recorded in the run log
run: |
python - <<'EOF'
import hashlib, pathlib
for p in sorted(pathlib.Path("dist").iterdir()):
print(f"sha256 {hashlib.sha256(p.read_bytes()).hexdigest()} {p.name}")
EOF

# Installs the wheel into a clean venv and resolves EVERY declared console
# script to a real callable. Stronger than `--version`: a package whose
# entry point names a missing function installs fine and fails at first
# use, and that is exactly the defect this step was written to catch.
- name: no broken release, resolve every entry point
run: |
python -m venv /tmp/smoke
/tmp/smoke/bin/pip install --upgrade pip
/tmp/smoke/bin/pip install "$(echo dist/*.whl)"
/tmp/smoke/bin/python - <<'EOF'
from importlib.metadata import distribution
d = distribution("plexus-mesh")
eps = [e for e in d.entry_points if e.group == "console_scripts"]
for e in eps:
fn = e.load()
assert callable(fn), f"{e.name} -> {e.value} is not callable"
print(f"entry point ok: {e.name} -> {e.value}")
print(f"plexus-mesh {d.version}: {len(eps)} entry point(s) resolved")
EOF

- name: the sdist must build a wheel too
run: |
python -m venv /tmp/sd
/tmp/sd/bin/pip install --upgrade pip build
/tmp/sd/bin/python -m build --wheel --outdir /tmp/sdout "$(echo dist/*.tar.gz)"
ls -l /tmp/sdout

- uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: dist
path: dist/

publish:
needs: build
# Stays skipped until the trusted publisher exists and PYPI_ENABLED is 'true',
# so a tag builds and smokes without a failing publish run beforehand.
if: ${{ vars.PYPI_ENABLED == 'true' }}
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write # OIDC. No token, no secret.
steps:
- uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
name: dist
path: dist/
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
with:
# PEP 740 attestations: the index records who built these bytes and
# from which workflow, verifiable without trusting us.
attestations: true
Loading