-
Notifications
You must be signed in to change notification settings - Fork 2
110 lines (97 loc) · 4.31 KB
/
Copy pathrelease.yml
File metadata and controls
110 lines (97 loc) · 4.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
name: release
# Publishes to PyPI via Trusted Publishing (OIDC). There is no API token anywhere in
# this repository, in GitHub secrets, or on any developer machine -- GitHub proves the
# workflow's identity to PyPI directly, and PyPI issues a short-lived credential for
# that single upload. Nothing to leak and nothing to rotate.
#
# One-time setup on PyPI is required before this can succeed; see docs in the release
# checklist section of CONTRIBUTING.md.
on:
push:
tags: ["v*"]
workflow_dispatch:
permissions:
contents: read
jobs:
build:
name: Build and verify
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: "3.12"
- name: Install build tooling
run: python -m pip install --upgrade pip build twine
- name: Verify the tag matches the packaged version
# Tagging v1.0.4 while pyproject still says 1.0.3 is a real and easy mistake,
# and PyPI version numbers can never be reused once published. Fail here, where
# it costs nothing, rather than after an irreversible upload.
if: startsWith(github.ref, 'refs/tags/')
run: |
TAG="${GITHUB_REF_NAME#v}"
PKG=$(python -c "import tomllib;print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
echo "tag=$TAG pyproject=$PKG"
if [ "$TAG" != "$PKG" ]; then
echo "::error::Tag v$TAG does not match pyproject version $PKG"
exit 1
fi
- name: Build
run: python -m build
- name: Check metadata renders on PyPI
run: python -m twine check dist/*
- name: Refuse to ship anything that should not be in the package
# The sdist should contain the library, its tests, and licence files. Datasets,
# benchmark artifacts, and notebooks with output have leaked into published
# packages before; this makes that a build failure rather than a discovery.
run: |
python - <<'PY'
import tarfile, glob, sys
sdist = glob.glob('dist/*.tar.gz')[0]
names = [n.split('/', 1)[1] for n in tarfile.open(sdist).getnames() if '/' in n]
banned = ('benchmarks/', 'results/', 'notebooks/', 'probes/', 'public/',
'sales/', 'legal/', 'docs/plans', 'dist/', '.env')
bad = [n for n in names
if n.startswith(banned) or n.endswith(('.db', '.pem', '.onnx'))]
if bad:
print('::error::sdist contains files that must not ship:', bad)
sys.exit(1)
print(f'sdist clean: {len(names)} files')
PY
- uses: actions/upload-artifact@v5
with:
name: dist
path: dist/
publish:
name: Publish to PyPI
needs: build
# Trusted Publishing has to be configured on PyPI before this job can do
# anything but fail with `invalid-publisher`. Until the repository variable
# PYPI_TRUSTED_PUBLISHER is set to "true", a tag still builds the artifacts and
# runs every gate above - it just skips the upload, so cutting a release by hand
# does not leave a red run on a repository whose whole pitch is verifiability.
# Set it once the publisher entry exists: gh variable set PYPI_TRUSTED_PUBLISHER --body true
if: vars.PYPI_TRUSTED_PUBLISHER == 'true'
runs-on: ubuntu-latest
# The environment gate is what makes Trusted Publishing safe: it scopes the OIDC
# identity, and it is where you add a manual approval rule if you ever want one.
environment:
name: pypi
url: https://pypi.org/project/genome-memory/
permissions:
id-token: write # required for OIDC; this is the whole mechanism
steps:
- uses: actions/download-artifact@v5
with:
name: dist
path: dist/
- name: Publish
uses: pypa/gh-action-pypi-publish@release/v1
# No `password:` here, deliberately. Omitting it is what selects Trusted
# Publishing over token auth.
with:
# A version already on PyPI is a no-op, not a failure: 1.1.0 was uploaded
# by hand before Trusted Publishing existed, and re-tagging a released
# version should be harmless. Versions are still immutable - this only
# skips a file that is already there.
skip-existing: true