Skip to content
Merged
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
73 changes: 18 additions & 55 deletions .github/workflows/publish-dev.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
name: Publish Dev

# Tag every commit on main as ``renderers-v<next>.dev<N>`` and publish the
# wheel to PyPI as a pre-release. ``<next>`` is the latest release tag with
# its patch bumped; ``<N>`` is the number of commits since that release so
# each main commit maps to a unique PEP 440 dev version.
#
# Building from the freshly-created tag means hatch-vcs resolves the version
# cleanly (no ``+gHASH`` local segment), which PyPI requires.
# Every push to main publishes a pre-release wheel to PyPI. The version
# is derived at build time by hatch-vcs from ``git describe`` distance
# to the latest stable ``renderers-v<MAJOR>.<MINOR>.<PATCH>`` tag (see
# ``[tool.hatch.version.raw-options]`` in pyproject.toml) — no per-commit
# tag is created. ``local_scheme = "no-local-version"`` strips the
# ``+gHASH`` segment so PyPI accepts the wheel directly.

on:
push:
Expand All @@ -17,68 +16,30 @@ concurrency:
cancel-in-progress: false

jobs:
tag:
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
tag: ${{ steps.compute.outputs.tag }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Compute next dev tag
id: compute
run: |
set -euo pipefail
LATEST_RELEASE=$(git tag --list 'renderers-v*' --sort=-v:refname \
| grep -Ev '(dev|rc|a[0-9]|b[0-9])' \
| head -1)
if [ -z "$LATEST_RELEASE" ]; then
echo "No release tag matching 'renderers-v<MAJOR.MINOR.PATCH>' found" >&2
exit 1
fi
BASE=${LATEST_RELEASE#renderers-v}
MAJOR=$(echo "$BASE" | cut -d. -f1)
MINOR=$(echo "$BASE" | cut -d. -f2)
PATCH=$(echo "$BASE" | cut -d. -f3)
NEXT="${MAJOR}.${MINOR}.$((PATCH + 1))"
N=$(git rev-list --count "${LATEST_RELEASE}..HEAD")
TAG="renderers-v${NEXT}.dev${N}"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "Computed tag: ${TAG} (base=${LATEST_RELEASE}, commits=${N})"

- name: Create and push tag
env:
TAG: ${{ steps.compute.outputs.tag }}
run: |
set -euo pipefail
if git ls-remote --exit-code --tags origin "refs/tags/${TAG}" >/dev/null 2>&1; then
echo "Tag ${TAG} already exists on origin — nothing to do" >&2
exit 0
fi
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git tag -a "$TAG" -m "Automated dev release ${TAG}"
git push origin "$TAG"

# Build (no OIDC) → publish (OIDC only). The build job runs ``uv build``
# with ``contents: read`` only so a poisoned build-time dep cannot mint
# the OIDC token. The publish job has ``id-token: write`` and the
# pypi-prod environment but no source checkout — it only downloads the
# prebuilt artifact and runs the SHA-pinned pypa publish action.
build:
needs: tag
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
# hatch-vcs needs the full tag history to resolve the version
# from the latest stable tag's distance.
fetch-depth: 0
ref: refs/tags/${{ needs.tag.outputs.tag }}

- uses: astral-sh/setup-uv@v7

- name: Build renderers
run: uv build

- name: Show derived version
run: ls -1 dist/

- name: Upload dist artifacts
uses: actions/upload-artifact@v4
with:
Expand All @@ -102,3 +63,5 @@ jobs:

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
with:
skip-existing: true
16 changes: 16 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,22 @@ tag-pattern = '^renderers-v(?P<version>.+)$'
# only fires when the resolver has nothing to go on.
fallback-version = "0.0.0"

[tool.hatch.version.raw-options]
# Only stable ``renderers-v<MAJOR>.<MINOR>.<PATCH>`` tags participate in
# version resolution; legacy per-commit ``.devN`` tags are excluded.
# Untagged commits get a clean PEP 440 dev version derived from distance
# to the latest stable tag (e.g. ``0.1.8.dev46``), with no ``+gHASH``
# local segment so PyPI accepts the wheel directly. setuptools-scm
# refuses to bump a pre-existing ``.devN`` tag, so matching only stable
# tags also unblocks local ``uv lock`` / ``uv build`` on untagged
# branches. Mirrors verifiers' setup.
local_scheme = "no-local-version"
git_describe_command = [
"git", "describe", "--tags", "--long",
"--match", "renderers-v[0-9]*.[0-9]*.[0-9]*",
"--exclude", "*dev*",
]

[tool.hatch.build.hooks.vcs]
# Write the resolved version to a Python file so it can be inspected
# at runtime via ``renderers.__version__`` without re-parsing the
Expand Down
4 changes: 2 additions & 2 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading