Skip to content

Publish Python package #61

Publish Python package

Publish Python package #61

Workflow file for this run

name: Publish Python package
on:
workflow_dispatch:
inputs:
target:
description: "Publish target"
required: true
type: choice
options:
- testpypi
- pypi
default: testpypi
release:
types: [published]
jobs:
build:
name: Build distributions
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.14"
- uses: actions/setup-node@v4
with:
node-version: "22"
- name: Install build tooling
run: |
python -m pip install --upgrade pip
python -m pip install ".[dev]" twine
- name: Ruff
run: python -m ruff check .
- name: Type check
run: python -m mypy
- name: Test
run: python -m pytest
- name: Coverage
run: python -m pytest --cov=codex_usage_tracker --cov-report=term-missing
- name: Compile
run: python -m compileall src
- name: Dashboard JavaScript syntax
run: |
for file in src/codex_usage_tracker/plugin_data/dashboard/dashboard*.js; do
node --check "$file"
done
- name: Release readiness
run: python scripts/check_release.py
- name: Whitespace
run: git diff --check
- name: Build wheel and sdist
run: |
rm -rf dist build *.egg-info src/*.egg-info
python -m build
python -m twine check dist/*
python scripts/check_release.py --dist
- name: Show distribution files
run: |
ls -la dist
python - <<'PY'
from pathlib import Path
import hashlib
for path in sorted(Path("dist").iterdir()):
digest = hashlib.sha256(path.read_bytes()).hexdigest()
print(f"{digest} {path}")
PY
- name: Upload dist artifacts
uses: actions/upload-artifact@v4
with:
name: python-dist
path: dist/*
if-no-files-found: error
publish-testpypi:
name: Publish to TestPyPI
needs: build
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
environment:
name: testpypi
url: https://test.pypi.org/project/codex-usage-tracking/
permissions:
id-token: write
steps:
- name: Verify PyPI publish ref
run: |
echo "event=$GITHUB_EVENT_NAME"
echo "ref=$GITHUB_REF"
echo "sha=$GITHUB_SHA"
if [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ]; then
case "$GITHUB_REF" in
refs/heads/main|refs/tags/*)
;;
*)
echo "Manual PyPI publishing must run from main or a tag ref." >&2
exit 1
;;
esac
fi
- name: Download dist artifacts
uses: actions/download-artifact@v4
with:
name: python-dist
path: dist
- name: Check target package version
id: package-version
env:
PACKAGE_INDEX_JSON_URL: https://test.pypi.org/pypi/codex-usage-tracking/json
PACKAGE_INDEX_NAME: TestPyPI
run: |
python - <<'PY'
import json
import os
import urllib.error
import urllib.request
from pathlib import Path
versions = set()
for path in Path("dist").iterdir():
name = path.name
if name.endswith(".tar.gz") and name.startswith("codex_usage_tracking-"):
versions.add(name.removeprefix("codex_usage_tracking-").removesuffix(".tar.gz"))
elif name.endswith(".whl") and name.startswith("codex_usage_tracking-"):
versions.add(name.split("-")[1])
if len(versions) != 1:
raise SystemExit(f"expected one distribution version, found {sorted(versions)}")
version = versions.pop()
url = os.environ["PACKAGE_INDEX_JSON_URL"]
index_name = os.environ["PACKAGE_INDEX_NAME"]
try:
with urllib.request.urlopen(url, timeout=30) as response:
payload = json.load(response)
except urllib.error.HTTPError as exc:
if exc.code == 404:
exists = False
else:
raise
else:
exists = version in payload.get("releases", {})
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output:
output.write(f"version={version}\n")
output.write(f"exists={str(exists).lower()}\n")
if exists:
print(f"codex-usage-tracking {version} already exists on {index_name}; skipping upload.")
else:
print(f"codex-usage-tracking {version} is not present on {index_name}; upload will run.")
PY
- name: Publish package distributions to TestPyPI
if: steps.package-version.outputs.exists != 'true'
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
print-hash: true
publish-pypi:
name: Publish to PyPI
needs: build
runs-on: ubuntu-latest
if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.target == 'pypi')
environment:
name: pypi
url: https://pypi.org/project/codex-usage-tracking/
permissions:
id-token: write
steps:
- name: Verify PyPI publish ref
run: |
echo "event=$GITHUB_EVENT_NAME"
echo "ref=$GITHUB_REF"
echo "sha=$GITHUB_SHA"
if [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ]; then
case "$GITHUB_REF" in
refs/heads/main|refs/tags/*)
;;
*)
echo "Manual PyPI publishing must run from main or a tag ref." >&2
exit 1
;;
esac
fi
- name: Download dist artifacts
uses: actions/download-artifact@v4
with:
name: python-dist
path: dist
- name: Check target package version
id: package-version
env:
PACKAGE_INDEX_JSON_URL: https://pypi.org/pypi/codex-usage-tracking/json
PACKAGE_INDEX_NAME: PyPI
run: |
python - <<'PY'
import json
import os
import urllib.error
import urllib.request
from pathlib import Path
versions = set()
for path in Path("dist").iterdir():
name = path.name
if name.endswith(".tar.gz") and name.startswith("codex_usage_tracking-"):
versions.add(name.removeprefix("codex_usage_tracking-").removesuffix(".tar.gz"))
elif name.endswith(".whl") and name.startswith("codex_usage_tracking-"):
versions.add(name.split("-")[1])
if len(versions) != 1:
raise SystemExit(f"expected one distribution version, found {sorted(versions)}")
version = versions.pop()
url = os.environ["PACKAGE_INDEX_JSON_URL"]
index_name = os.environ["PACKAGE_INDEX_NAME"]
try:
with urllib.request.urlopen(url, timeout=30) as response:
payload = json.load(response)
except urllib.error.HTTPError as exc:
if exc.code == 404:
exists = False
else:
raise
else:
exists = version in payload.get("releases", {})
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output:
output.write(f"version={version}\n")
output.write(f"exists={str(exists).lower()}\n")
if exists:
print(f"codex-usage-tracking {version} already exists on {index_name}; skipping upload.")
else:
print(f"codex-usage-tracking {version} is not present on {index_name}; upload will run.")
PY
- name: Publish package distributions to PyPI
if: steps.package-version.outputs.exists != 'true'
uses: pypa/gh-action-pypi-publish@release/v1
with:
print-hash: true