Repository navigation
Anchor a relative TaskEnv dependencies_from to the author's file (v0.… #22
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "Publish release to PyPI" | |
| on: | |
| push: | |
| tags: | |
| # Publish package-scoped releases, e.g., tangle-cli-v0.1.1 or tangle-api-v0.1.0. | |
| - "tangle-cli-v*" | |
| - "tangle-api-v*" | |
| jobs: | |
| run: | |
| runs-on: ubuntu-latest | |
| environment: | |
| name: pypi | |
| permissions: | |
| id-token: write | |
| contents: read | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 | |
| - name: Install Python 3.13 | |
| run: uv python install 3.13 | |
| - name: Build tangle-cli | |
| run: uv build | |
| - name: Build tangle-api | |
| run: uv build --package tangle-api | |
| # Check that basic features work and we didn't miss to include crucial files. | |
| # Use package-specific globs so adding tangle-api artifacts does not change | |
| # which distribution is installed for tangle-cli smoke tests. | |
| - name: Smoke test tangle-cli wheel | |
| run: | | |
| uv run --isolated --no-project --find-links dist --with dist/tangle_cli-*.whl tangle version | |
| uv run --isolated --no-project --find-links dist --with dist/tangle_cli-*.whl tangle-cli version | |
| - name: Smoke test tangle-cli source distribution | |
| run: | | |
| uv run --isolated --no-project --find-links dist --with dist/tangle_cli-*.tar.gz tangle version | |
| uv run --isolated --no-project --find-links dist --with dist/tangle_cli-*.tar.gz tangle-cli version | |
| - name: Smoke test tangle-api wheel | |
| run: | | |
| uv run --isolated --no-project \ | |
| --with dist/tangle_cli-*.whl \ | |
| --with dist/tangle_api-*.whl \ | |
| python -c "import importlib.metadata as m; import tangle_cli; import tangle_api.generated.models; import tangle_api.schema; print(f'tangle-cli {m.version(\"tangle-cli\")} with tangle-api {m.version(\"tangle-api\")}')" | |
| - name: Smoke test tangle-api source distribution | |
| run: | | |
| uv run --isolated --no-project \ | |
| --with dist/tangle_cli-*.tar.gz \ | |
| --with dist/tangle_api-*.tar.gz \ | |
| python -c "import importlib.metadata as m; import tangle_cli; import tangle_api.generated.models; import tangle_api.schema; print(f'tangle-cli {m.version(\"tangle-cli\")} with tangle-api {m.version(\"tangle-api\")}')" | |
| - name: Smoke test native extra compatibility alias from local dist | |
| run: | | |
| cli_wheel="$(echo dist/tangle_cli-*.whl)" | |
| uv run --isolated --no-project --find-links dist --with "${cli_wheel}[native]" tangle-cli version | |
| - name: Determine package to publish | |
| id: publish-plan | |
| run: | | |
| python - <<'PY' | |
| import json | |
| import os | |
| import sys | |
| import urllib.error | |
| import urllib.request | |
| from pathlib import Path | |
| import tomllib | |
| tag = os.environ["GITHUB_REF_NAME"] | |
| release_packages = { | |
| "tangle-cli-v": ("tangle-cli", "pyproject.toml", "dist/tangle_cli-*"), | |
| "tangle-api-v": ("tangle-api", "packages/tangle-api/pyproject.toml", "dist/tangle_api-*"), | |
| } | |
| for tag_prefix, package_config in release_packages.items(): | |
| if tag.startswith(tag_prefix): | |
| package, pyproject_path, dist_glob = package_config | |
| tag_version = tag.removeprefix(tag_prefix) | |
| break | |
| else: | |
| supported_tags = ", ".join(f"{prefix}*" for prefix in release_packages) | |
| sys.exit(f"Unsupported release tag {tag!r}. Expected one of: {supported_tags}.") | |
| package_version = tomllib.loads(Path(pyproject_path).read_text())["project"]["version"] | |
| if tag_version != package_version: | |
| sys.exit( | |
| f"Release tag {tag!r} declares {package} version {tag_version}, " | |
| f"but {pyproject_path} declares {package_version}." | |
| ) | |
| def version_exists(package: str, version: str) -> bool: | |
| url = f"https://pypi.org/pypi/{package}/json" | |
| try: | |
| with urllib.request.urlopen(url, timeout=20) as response: | |
| data = json.load(response) | |
| except urllib.error.HTTPError as error: | |
| if error.code == 404: | |
| return False | |
| raise | |
| return version in data.get("releases", {}) | |
| should_publish = not version_exists(package, package_version) | |
| print( | |
| f"{tag}: " | |
| f"{'publish ' + dist_glob if should_publish else package + ' ' + package_version + ' already exists on PyPI; skipping'}" | |
| ) | |
| with Path(os.environ["GITHUB_OUTPUT"]).open("a") as output: | |
| print(f"package={package}", file=output) | |
| print(f"version={package_version}", file=output) | |
| print(f"dist_glob={dist_glob}", file=output) | |
| print(f"should_publish={'true' if should_publish else 'false'}", file=output) | |
| PY | |
| - name: Publish selected package | |
| if: steps.publish-plan.outputs.should_publish == 'true' | |
| run: uv publish ${{ steps.publish-plan.outputs.dist_glob }} |