Repository navigation
130 lines (125 loc) · 5.45 KB
/
Copy pathpublish-python.yml
File metadata and controls
130 lines (125 loc) · 5.45 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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
name: Publish Python
on:
workflow_dispatch:
inputs:
dry_run:
description: "Build and verify without publishing"
required: false
default: "true"
permissions:
contents: read
jobs:
build:
name: Build and verify Python distributions
runs-on: ubuntu-latest
outputs:
version: ${{ steps.metadata.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install packaging tools
run: python -m pip install maturin==1.15.0 twine==7.0.0
- name: Build from source distribution
run: maturin build --release --locked --sdist
- name: Verify build preserved the patched lockfile
run: git diff --exit-code -- Cargo.lock
- name: Inspect distribution identity
id: metadata
run: |
python <<'PYTHON'
import email.parser
import os
import pathlib
import zipfile
wheels = list(pathlib.Path("target/wheels").glob("*.whl"))
assert len(wheels) == 1
with zipfile.ZipFile(wheels[0]) as wheel:
metadata = email.parser.BytesParser().parsebytes(wheel.read(next(name for name in wheel.namelist() if name.endswith(".dist-info/METADATA"))))
assert metadata["Name"] == "markkit"
with open(os.environ["GITHUB_OUTPUT"], "a") as output:
print(f"version={metadata['Version']}", file=output)
print(f"markkit {metadata['Version']} from {os.environ['GITHUB_SHA']}")
PYTHON
- name: Verify distributions and native import
run: |
python -m twine check --strict target/wheels/*.whl target/wheels/*.tar.gz
python -m venv "$RUNNER_TEMP/markkit-wheel-smoke"
"$RUNNER_TEMP/markkit-wheel-smoke/bin/python" -m pip install --no-deps target/wheels/*.whl
"$RUNNER_TEMP/markkit-wheel-smoke/bin/python" -c 'import importlib.metadata, importlib.util, markkit; assert importlib.metadata.metadata("markkit")["Name"] == "markkit"; assert importlib.util.find_spec("markkit_python") is None; assert markkit.extract_html_sync("<h1>Smoke</h1>").strip() == "# Smoke"'
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: python-distributions
path: |
target/wheels/*.whl
target/wheels/*.tar.gz
if-no-files-found: error
publish:
name: Publish Python package with OIDC
needs: build
if: inputs.dry_run != 'true'
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: python-distributions
path: dist
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # release/v1
with:
packages-dir: dist/
verify:
name: Verify public PyPI installation
needs: [build, publish]
runs-on: ubuntu-latest
env:
MARKKIT_VERSION: ${{ needs.build.outputs.version }}
steps:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: python-distributions
path: dist
- name: Download the published wheel
run: |
for attempt in 1 2 3 4 5; do
if python -m pip download --no-cache-dir --only-binary=:all: --no-deps --dest registry "markkit==$MARKKIT_VERSION"; then
break
fi
if [ "$attempt" -eq 5 ]; then exit 1; fi
sleep 10
done
- name: Verify public files match the build
run: |
python <<'PYTHON'
import hashlib
import json
import os
import pathlib
import urllib.request
version = os.environ["MARKKIT_VERSION"]
with urllib.request.urlopen(f"https://pypi.org/pypi/markkit/{version}/json") as response:
published = json.load(response)
assert published["info"]["name"] == "markkit"
assert published["info"]["version"] == version
digests = {entry["filename"]: entry["digests"]["sha256"] for entry in published["urls"]}
for artifact in pathlib.Path("dist").iterdir():
assert digests[artifact.name] == hashlib.sha256(artifact.read_bytes()).hexdigest()
for wheel in pathlib.Path("registry").glob("*.whl"):
assert digests[wheel.name] == hashlib.sha256(wheel.read_bytes()).hexdigest()
print(f"Public markkit {version} distributions match the build")
PYTHON
- name: Install and smoke-test the public wheel
run: |
python -m venv "$RUNNER_TEMP/markkit-public-smoke"
"$RUNNER_TEMP/markkit-public-smoke/bin/python" -m pip install --no-index --no-deps registry/*.whl
"$RUNNER_TEMP/markkit-public-smoke/bin/python" -c 'import importlib.metadata, importlib.util, markkit; assert importlib.metadata.version("markkit") == __import__("os").environ["MARKKIT_VERSION"]; assert importlib.util.find_spec("markkit_python") is None; assert markkit.extract_html_sync("<h1>Published smoke</h1>").strip() == "# Published smoke"; print("Public markkit import and native extraction PASS")'