Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 51 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
run: python -m build

- name: Upload release artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: python-package-distributions
path: dist/
Expand All @@ -58,18 +58,56 @@ jobs:

steps:
- name: Download release artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
name: python-package-distributions
path: dist/

- name: Check whether version already exists on PyPI
id: check-pypi-version
env:
PACKAGE_NAME: oacp-cli
PACKAGE_VERSION: ${{ github.ref_name }}
run: |
python - <<'PY'
import json
import os
import urllib.error
import urllib.request

package = os.environ["PACKAGE_NAME"]
version = os.environ["PACKAGE_VERSION"].removeprefix("v")
url = f"https://pypi.org/pypi/{package}/json"

try:
with urllib.request.urlopen(url) as response:
releases = json.load(response).get("releases", {})
except urllib.error.HTTPError as exc:
if exc.code == 404:
releases = {}
else:
raise

version_exists = version in releases
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh:
fh.write(f"version_exists={'true' if version_exists else 'false'}\n")

if version_exists:
print(f"PyPI already has {package} {version}; skipping publish.")
else:
print(f"PyPI does not have {package} {version}; proceeding with publish.")
PY

- name: Publish to PyPI
if: steps.check-pypi-version.outputs.version_exists != 'true'
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0

- name: Skip duplicate PyPI publish
if: steps.check-pypi-version.outputs.version_exists == 'true'
run: echo "PyPI already has ${GITHUB_REF_NAME#v}; skipping upload."

github-release:
needs:
- build
- publish-pypi
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
Expand All @@ -79,12 +117,17 @@ jobs:
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Download release artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
name: python-package-distributions
path: dist/

- name: Create GitHub Release
- name: Create or update GitHub Release
env:
GH_TOKEN: ${{ github.token }}
run: gh release create "${GITHUB_REF_NAME}" dist/* --generate-notes --verify-tag
run: |
if gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1; then
gh release upload "${GITHUB_REF_NAME}" dist/* --clobber
else
gh release create "${GITHUB_REF_NAME}" dist/* --generate-notes --verify-tag
fi
24 changes: 20 additions & 4 deletions tests/test_github_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,29 @@ def test_release_workflow_publishes_with_trusted_publishing() -> None:
publish_job = workflow["jobs"]["publish-pypi"]
assert publish_job["environment"]["name"] == "pypi"
assert publish_job["permissions"]["id-token"] == "write"
assert publish_job["steps"][0]["uses"].startswith("actions/download-artifact@")
assert publish_job["steps"][-1]["uses"].startswith("pypa/gh-action-pypi-publish@")
publish_step_names = {step["name"]: step for step in publish_job["steps"]}
assert publish_step_names["Download release artifacts"]["uses"].startswith(
"actions/download-artifact@"
)
assert publish_step_names["Check whether version already exists on PyPI"]["id"] == (
"check-pypi-version"
)
assert publish_step_names["Publish to PyPI"]["if"] == (
"steps.check-pypi-version.outputs.version_exists != 'true'"
)
assert publish_step_names["Publish to PyPI"]["uses"].startswith(
"pypa/gh-action-pypi-publish@"
)
assert publish_step_names["Skip duplicate PyPI publish"]["if"] == (
"steps.check-pypi-version.outputs.version_exists == 'true'"
)

release_job = workflow["jobs"]["github-release"]
assert set(release_job["needs"]) == {"build", "publish-pypi"}
assert release_job["needs"] == "build"
assert release_job["permissions"]["contents"] == "write"
release_step_names = {step["name"]: step for step in release_job["steps"]}
assert release_step_names["Check out repository"]["uses"].startswith("actions/checkout@")
assert release_step_names["Download release artifacts"]["uses"].startswith("actions/download-artifact@")
assert "gh release create" in release_step_names["Create GitHub Release"]["run"]
assert "gh release view" in release_step_names["Create or update GitHub Release"]["run"]
assert "gh release upload" in release_step_names["Create or update GitHub Release"]["run"]
assert "gh release create" in release_step_names["Create or update GitHub Release"]["run"]