Skip to content

Commit b676dd3

Browse files
authored
Merge pull request #17 from aerospike-community/fix/release-pypi-metadata-guard
ci: guard PyPI metadata and document retagging
2 parents f044c83 + e9bbbb2 commit b676dd3

3 files changed

Lines changed: 62 additions & 3 deletions

File tree

.github/workflows/release.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ jobs:
8484
- name: Build sdist and wheel
8585
run: python -m pip install build && python -m build
8686

87+
- name: Validate PyPI-compatible metadata
88+
run: python scripts/validate_pypi_metadata.py
89+
8790
- name: Upload distributions
8891
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
8992
with:

RELEASING.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,20 @@ In https://github.com/aerospike-community/adk-aerospike/settings/environments:
4444
1. Bump version in **both** `pyproject.toml` and `src/adk_aerospike/__init__.py`.
4545
2. Update `CHANGELOG.md`.
4646
3. Merge to `main`.
47-
4. Tag and push:
47+
4. Tag the **current `main` HEAD** (after your release PR is merged) and push:
4848

4949
```bash
50-
git tag v0.0.1
51-
git push origin v0.0.1
50+
git checkout main && git pull
51+
git tag v0.0.2
52+
git push origin v0.0.2
53+
```
54+
55+
If a tag already exists on an older commit, delete it locally and on GitHub before re-tagging:
56+
57+
```bash
58+
git tag -d v0.0.2
59+
git push origin :refs/tags/v0.0.2
60+
git tag v0.0.2 && git push origin v0.0.2
5261
```
5362

5463
5. In GitHub Actions, open the **Release** workflow run; approve the **pypi** environment deployment if reviewers are configured.
@@ -71,14 +80,19 @@ In https://github.com/aerospike-community/adk-aerospike/settings/environments:
7180
```bash
7281
python -m pip install build
7382
python -m build
83+
python scripts/validate_pypi_metadata.py
7484
pip install dist/adk_aerospike-*.whl
7585
```
7686

87+
Benchmark harness deps are **not** in the PyPI package — install with `pip install -r benchmarks/requirements.txt`.
88+
7789
## Troubleshooting
7890

7991
| Symptom | Likely cause |
8092
| --- | --- |
8193
| Publish job fails immediately on OIDC | Trusted publisher owner/repo/workflow/environment mismatch |
8294
| “File already exists” on upload | Version not bumped; PyPI versions are immutable |
8395
| Tag/job fails at version check | Tag `v0.0.2` but `pyproject.toml` still `0.0.1` |
96+
| `400 Can't have direct dependency` on upload | Tag points at a commit before the fix, or `[benchmark]` / git URL still in `pyproject.toml`; run `python scripts/validate_pypi_metadata.py` after `python -m build` |
97+
| Validate step fails on release | Wheel still embeds VCS deps — remove optional extras with git URLs from `pyproject.toml` |
8498
| Environment never appears | Workflow must reference `environment: name: pypi` on the publish job |

scripts/validate_pypi_metadata.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/usr/bin/env python3
2+
"""Fail if built wheel/sdist metadata contains PyPI-forbidden VCS direct deps."""
3+
4+
from __future__ import annotations
5+
6+
import sys
7+
import zipfile
8+
from pathlib import Path
9+
10+
11+
def _check_metadata(text: str, label: str) -> list[str]:
12+
errors: list[str] = []
13+
if "git+" in text or " @ git" in text:
14+
errors.append(f"{label}: VCS/direct URL dependency in metadata")
15+
if "Extra: benchmark" in text and "ai-ecosystem-benchmark" in text:
16+
errors.append(f"{label}: [benchmark] extra still in metadata (use benchmarks/requirements.txt)")
17+
return errors
18+
19+
20+
def main() -> int:
21+
dist = Path("dist")
22+
if not dist.is_dir():
23+
print("dist/ not found; run python -m build first", file=sys.stderr)
24+
return 1
25+
26+
errors: list[str] = []
27+
for whl in sorted(dist.glob("*.whl")):
28+
with zipfile.ZipFile(whl) as zf:
29+
meta_name = next(n for n in zf.namelist() if n.endswith(".dist-info/METADATA"))
30+
errors.extend(_check_metadata(zf.read(meta_name).decode(), whl.name))
31+
32+
if errors:
33+
for err in errors:
34+
print(err, file=sys.stderr)
35+
return 1
36+
37+
print("PyPI metadata OK")
38+
return 0
39+
40+
41+
if __name__ == "__main__":
42+
sys.exit(main())

0 commit comments

Comments
 (0)