b04e7be146
CI / Sync project version with tag (hand-pushed tags only) (pull_request) Has been skipped
CI / Publish package to Gitea package registry (pull_request) Has been skipped
CI / Type check (ty) (pull_request) Successful in 35s
CI / Format (ruff format) (pull_request) Successful in 36s
CI / Lint (ruff check) (pull_request) Successful in 39s
CI / Tests (pull_request) Successful in 3m26s
CI / Release (bump, changelog, badges, tag) on merge to master (pull_request) Has been skipped
release-commit.sh creates release tags with `git tag -a`, so
`git rev-parse "$TAG"` returns the annotated tag object's own SHA, not
the commit it points at. Comparing that directly against
`git rev-parse HEAD` was therefore always false, so the atomic
`git push --atomic origin HEAD:master refs/tags/$TAG` never fired — the
release job has been pushing the branch alone and silently dropping
every release tag (confirmed: v0.3.19 landed on master but was never
pushed as a tag). `^{commit}` dereferences the tag to its target commit
so the comparison actually matches.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NnotyatakKNS4NLjDbfYw1
194 lines
7.2 KiB
YAML
194 lines
7.2 KiB
YAML
name: CI
|
|
|
|
"on":
|
|
push:
|
|
branches: ["master"]
|
|
tags: ["**"]
|
|
pull_request: {}
|
|
|
|
env:
|
|
UV_CACHE_DIR: /uv-cache
|
|
|
|
jobs:
|
|
ruff-check:
|
|
name: Lint (ruff check)
|
|
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: docker.gitea.com/runner-images:ubuntu-latest
|
|
volumes:
|
|
- /srv/act-runner-cache/uv:/uv-cache
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: ./.gitea/actions/setup
|
|
- run: uv run ruff check .
|
|
|
|
ruff-format:
|
|
name: Format (ruff format)
|
|
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: docker.gitea.com/runner-images:ubuntu-latest
|
|
volumes:
|
|
- /srv/act-runner-cache/uv:/uv-cache
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: ./.gitea/actions/setup
|
|
- run: uv run ruff format --check .
|
|
|
|
type-check:
|
|
name: Type check (ty)
|
|
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: docker.gitea.com/runner-images:ubuntu-latest
|
|
volumes:
|
|
- /srv/act-runner-cache/uv:/uv-cache
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: ./.gitea/actions/setup
|
|
- run: uv run ty check .
|
|
|
|
test:
|
|
name: Tests
|
|
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
needs: [ruff-check, ruff-format, type-check]
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: docker.gitea.com/runner-images:ubuntu-latest
|
|
volumes:
|
|
- /srv/act-runner-cache/uv:/uv-cache
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: ./.gitea/actions/setup
|
|
- run: uv run pytest --cov --cov-report=term-missing --cov-report=xml
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: coverage-report
|
|
path: coverage.xml
|
|
|
|
release:
|
|
name: Release (bump, changelog, badges, tag) on merge to master
|
|
needs: [ruff-check, ruff-format, type-check, test]
|
|
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: docker.gitea.com/runner-images:ubuntu-latest
|
|
volumes:
|
|
- /srv/act-runner-cache/uv:/uv-cache
|
|
steps:
|
|
# CI_TOKEN needs write:repository scope (not just read) — this job
|
|
# pushes a commit and a tag to master, unlike ruff-check/ruff-format/
|
|
# type-check/test above, which only need to check out the repo.
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
token: ${{ secrets.CI_TOKEN }}
|
|
fetch-depth: 0
|
|
- name: Check whether this push is a merge commit
|
|
id: merge_check
|
|
run: |
|
|
PARENTS=$(git rev-parse HEAD^@ | wc -l)
|
|
echo "HEAD has $PARENTS parent(s)"
|
|
if [ "$PARENTS" -ge 2 ]; then
|
|
echo "is_merge=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "is_merge=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
- uses: ./.gitea/actions/setup
|
|
if: steps.merge_check.outputs.is_merge == 'true'
|
|
- name: Configure git identity
|
|
if: steps.merge_check.outputs.is_merge == 'true'
|
|
run: |
|
|
git config user.name "gitea-actions"
|
|
git config user.email "actions@git.larsbogner.de"
|
|
- name: Build the release commit
|
|
if: steps.merge_check.outputs.is_merge == 'true'
|
|
run: |
|
|
OLD_VERSION=$(git show "${{ github.event.before }}:pyproject.toml" 2>/dev/null | grep -m1 '^version = ' | sed -E 's/version = "(.*)"/\1/')
|
|
CURRENT_VERSION=$(uv version --short)
|
|
if [ -z "$OLD_VERSION" ]; then
|
|
echo "Could not read pyproject.toml at github.event.before; falling back to HEAD^1"
|
|
OLD_VERSION=$(git show "HEAD^1:pyproject.toml" | grep -m1 '^version = ' | sed -E 's/version = "(.*)"/\1/')
|
|
fi
|
|
if [ "$OLD_VERSION" = "$CURRENT_VERSION" ]; then
|
|
echo "Version unchanged by this merge ($CURRENT_VERSION); bumping patch"
|
|
.gitea/scripts/release-commit.sh
|
|
else
|
|
echo "Branch already bumped the version ($OLD_VERSION -> $CURRENT_VERSION); building release commit without bumping"
|
|
.gitea/scripts/release-commit.sh --no-bump
|
|
fi
|
|
- name: Push the release commit and its tag together
|
|
if: steps.merge_check.outputs.is_merge == 'true'
|
|
run: |
|
|
VERSION=$(uv version --short)
|
|
TAG="v$VERSION"
|
|
if git rev-parse "$TAG" >/dev/null 2>&1 && [ "$(git rev-parse "$TAG^{commit}")" = "$(git rev-parse HEAD)" ]; then
|
|
git push --atomic origin HEAD:master "refs/tags/$TAG"
|
|
else
|
|
echo "No new release commit/tag to push (already released, or nothing changed)"
|
|
git push origin HEAD:master
|
|
fi
|
|
|
|
sync-version-on-tag:
|
|
name: Sync project version with tag (hand-pushed tags only)
|
|
if: startsWith(github.ref, 'refs/tags/')
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: docker.gitea.com/runner-images:ubuntu-latest
|
|
volumes:
|
|
- /srv/act-runner-cache/uv:/uv-cache
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
token: ${{ secrets.CI_TOKEN }}
|
|
fetch-depth: 0
|
|
- name: Require the tagged commit to already be on master
|
|
run: |
|
|
git fetch origin master
|
|
if ! git merge-base --is-ancestor "${{ github.sha }}" origin/master; then
|
|
echo "::error::Tag ${GITHUB_REF_NAME} points at a commit not on master; refusing to publish an unreviewed tree. Push the commit to master first, or delete and re-push the tag once it is."
|
|
exit 1
|
|
fi
|
|
- uses: ./.gitea/actions/setup
|
|
- name: Check tag against project version, build a release commit if they differ
|
|
run: |
|
|
TAG_VERSION="${GITHUB_REF_NAME#v}"
|
|
CURRENT_VERSION=$(uv version --short)
|
|
if [ "$TAG_VERSION" = "$CURRENT_VERSION" ]; then
|
|
echo "Tag version matches project version ($CURRENT_VERSION)"
|
|
else
|
|
echo "Tag version ($TAG_VERSION) != project version ($CURRENT_VERSION); building a release commit"
|
|
git config user.name "gitea-actions"
|
|
git config user.email "actions@git.larsbogner.de"
|
|
.gitea/scripts/release-commit.sh "$TAG_VERSION"
|
|
git push origin HEAD:master
|
|
git push origin ":refs/tags/${GITHUB_REF_NAME}"
|
|
git tag -f "${GITHUB_REF_NAME}" HEAD
|
|
git push origin "refs/tags/${GITHUB_REF_NAME}"
|
|
fi
|
|
|
|
publish-package:
|
|
name: Publish package to Gitea package registry
|
|
needs: [sync-version-on-tag]
|
|
if: startsWith(github.ref, 'refs/tags/')
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: docker.gitea.com/runner-images:ubuntu-latest
|
|
volumes:
|
|
- /srv/act-runner-cache/uv:/uv-cache
|
|
steps:
|
|
# Check out by tag name (not the triggering SHA) since sync-version-on-tag
|
|
# may have force-moved the tag to a version-corrected commit.
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.ref_name }}
|
|
- uses: ./.gitea/actions/setup
|
|
- run: uv build
|
|
# CI_TOKEN needs write:package scope (in addition to write:repository,
|
|
# used elsewhere) for this upload to authenticate.
|
|
- run: |
|
|
uv publish \
|
|
--publish-url "https://git.larsbogner.de/api/packages/lars/pypi" \
|
|
--username gitea-actions \
|
|
--password "${{ secrets.CI_TOKEN }}"
|