Skip to content

Commit 07127b9

Browse files
committed
ci(release): use package-scoped publish tags
1 parent 4785685 commit 07127b9

1 file changed

Lines changed: 40 additions & 24 deletions

File tree

.github/workflows/release.yaml

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ name: "Publish release to PyPI"
33
on:
44
push:
55
tags:
6-
# Publish on any tag starting with a `v`, e.g., v0.0.1a2
7-
- v*
6+
# Publish package-scoped releases, e.g., tangle-cli-v0.1.1 or tangle-api-v0.1.0.
7+
- "tangle-cli-v*"
8+
- "tangle-api-v*"
89

910
jobs:
1011
run:
@@ -52,21 +53,39 @@ jobs:
5253
run: |
5354
cli_wheel="$(echo dist/tangle_cli-*.whl)"
5455
uv run --isolated --no-project --find-links dist --with "${cli_wheel}[native]" tangle-cli version
55-
- name: Determine packages to publish
56+
- name: Determine package to publish
5657
id: publish-plan
5758
run: |
5859
python - <<'PY'
5960
import json
6061
import os
62+
import sys
6163
import urllib.error
6264
import urllib.request
6365
from pathlib import Path
6466
import tomllib
6567
66-
packages = [
67-
("tangle-cli", "pyproject.toml", "dist/tangle_cli-*", "publish_cli"),
68-
("tangle-api", "packages/tangle-api/pyproject.toml", "dist/tangle_api-*", "publish_api"),
69-
]
68+
tag = os.environ["GITHUB_REF_NAME"]
69+
release_packages = {
70+
"tangle-cli-v": ("tangle-cli", "pyproject.toml", "dist/tangle_cli-*"),
71+
"tangle-api-v": ("tangle-api", "packages/tangle-api/pyproject.toml", "dist/tangle_api-*"),
72+
}
73+
74+
for tag_prefix, package_config in release_packages.items():
75+
if tag.startswith(tag_prefix):
76+
package, pyproject_path, dist_glob = package_config
77+
tag_version = tag.removeprefix(tag_prefix)
78+
break
79+
else:
80+
supported_tags = ", ".join(f"{prefix}*" for prefix in release_packages)
81+
sys.exit(f"Unsupported release tag {tag!r}. Expected one of: {supported_tags}.")
82+
83+
package_version = tomllib.loads(Path(pyproject_path).read_text())["project"]["version"]
84+
if tag_version != package_version:
85+
sys.exit(
86+
f"Release tag {tag!r} declares {package} version {tag_version}, "
87+
f"but {pyproject_path} declares {package_version}."
88+
)
7089
7190
def version_exists(package: str, version: str) -> bool:
7291
url = f"https://pypi.org/pypi/{package}/json"
@@ -79,21 +98,18 @@ jobs:
7998
raise
8099
return version in data.get("releases", {})
81100
82-
github_output = Path(os.environ["GITHUB_OUTPUT"])
83-
with github_output.open("a") as output:
84-
for package, pyproject_path, dist_glob, output_name in packages:
85-
version = tomllib.loads(Path(pyproject_path).read_text())["project"]["version"]
86-
exists = version_exists(package, version)
87-
should_publish = not exists
88-
print(
89-
f"{package} {version}: "
90-
f"{'publish ' + dist_glob if should_publish else 'skip; version already exists on PyPI'}"
91-
)
92-
print(f"{output_name}={'true' if should_publish else 'false'}", file=output)
101+
should_publish = not version_exists(package, package_version)
102+
print(
103+
f"{tag}: "
104+
f"{'publish ' + dist_glob if should_publish else package + ' ' + package_version + ' already exists on PyPI; skipping'}"
105+
)
106+
107+
with Path(os.environ["GITHUB_OUTPUT"]).open("a") as output:
108+
print(f"package={package}", file=output)
109+
print(f"version={package_version}", file=output)
110+
print(f"dist_glob={dist_glob}", file=output)
111+
print(f"should_publish={'true' if should_publish else 'false'}", file=output)
93112
PY
94-
- name: Publish tangle-cli
95-
if: steps.publish-plan.outputs.publish_cli == 'true'
96-
run: uv publish dist/tangle_cli-*
97-
- name: Publish tangle-api
98-
if: steps.publish-plan.outputs.publish_api == 'true'
99-
run: uv publish dist/tangle_api-*
113+
- name: Publish selected package
114+
if: steps.publish-plan.outputs.should_publish == 'true'
115+
run: uv publish ${{ steps.publish-plan.outputs.dist_glob }}

0 commit comments

Comments
 (0)