From fd90a464190a06f4306530236f48697ddb7950fb Mon Sep 17 00:00:00 2001 From: Felix Schwarz Date: Sat, 11 Jul 2026 11:41:39 +0200 Subject: [PATCH] add release workflow which publishes releases to github --- .github/workflows/release.yml | 46 +++++++++++++++++++++++++++ _ensure_dist_files_use_version.py | 52 +++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 _ensure_dist_files_use_version.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..a99bc93 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,46 @@ +name: Publish release to PyPI + +on: + push: + tags: + - "v*" + +jobs: + publish: + runs-on: ubuntu-latest + environment: + name: pypi + permissions: + id-token: write + contents: read + + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Install uv + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + with: + version: "0.11.28" + + - name: Install Python + run: uv python install 3.14 + + - name: Build sdist and wheel + run: uv build + + - name: Check dist versions match tag + run: python _ensure_dist_files_use_version.py "${GITHUB_REF_NAME#v}" dist/*.whl dist/*.tar.gz + + - name: Smoke test wheel + run: > + uv run --isolated --no-project --with dist/*.whl + python -c "from dotmap import DotMap; assert DotMap(a=1).a == 1" + + - name: Smoke test sdist + run: > + uv run --isolated --no-project --with dist/*.tar.gz + python -c "from dotmap import DotMap; assert DotMap(a=1).a == 1" + + - name: Publish to PyPI + run: uv publish --trusted-publishing always diff --git a/_ensure_dist_files_use_version.py b/_ensure_dist_files_use_version.py new file mode 100644 index 0000000..ab92e86 --- /dev/null +++ b/_ensure_dist_files_use_version.py @@ -0,0 +1,52 @@ +import email +import pathlib +import sys +import tarfile +import zipfile + + +def _wheel_version(path: str) -> str: + with zipfile.ZipFile(path) as zf: + metadata_name = next( + name for name in zf.namelist() if name.endswith(".dist-info/METADATA") + ) + return email.message_from_bytes(zf.read(metadata_name))["Version"] + + +def _sdist_version(path: str) -> str: + with tarfile.open(path, "r:gz") as tf: + pkg_info = next( + member + for member in tf.getmembers() + if pathlib.Path(member.name).name == "PKG-INFO" + ) + return email.message_from_bytes(tf.extractfile(pkg_info).read())["Version"] + + +def main() -> int: + if len(sys.argv) < 3: + raise SystemExit( + "usage: python _ensure_dist_files_use_version.py ..." + ) + + expected = sys.argv[1] + files = sys.argv[2:] + validated = [] + + for path in files: + if path.endswith(".whl"): + actual = _wheel_version(path) + elif path.endswith(".tar.gz"): + actual = _sdist_version(path) + else: + raise AssertionError(f"unsupported distribution file: {path}") + + assert actual == expected, f"{path} has version {actual!r} != expected {expected!r}" + validated.append(f"{path}={actual}") + + print("validated dist versions:", ", ".join(validated)) + return 0 + + +if __name__ == "__main__": + sys.exit(main())