cfd968aced
After cz bump changes the project version, regenerate uv.lock and amend it into the bump commit (moving the tag) so every release tag stays consistent and `uv sync --locked` works when the versioned image is built. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NGzHtDvJur9U7ysgRKRUTN
98 lines
3.8 KiB
YAML
98 lines
3.8 KiB
YAML
name: release
|
|
|
|
# Cut a release as an action, not a local command. Manually triggered ("Run
|
|
# workflow"): bumps the version from conventional commits (or a forced level),
|
|
# updates CHANGELOG.md, tags vX.Y.Z, pushes both, and creates a Gitea release.
|
|
# Uses uv/commitizen because actions/setup-python is broken on these runners.
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
increment:
|
|
description: "Bump level (auto = detect from conventional commits)"
|
|
required: false
|
|
default: auto
|
|
type: choice
|
|
options: [auto, PATCH, MINOR, MAJOR]
|
|
dry_run:
|
|
description: "Dry run — compute + show, but do NOT push or release"
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
jobs:
|
|
release:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
steps:
|
|
- name: Checkout (full history + tags)
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
# Needs push + release rights. The auto token works with contents:write;
|
|
# if your runner's token can't push, set a PAT secret RELEASE_TOKEN.
|
|
token: ${{ secrets.RELEASE_TOKEN || github.token }}
|
|
|
|
- name: Install uv (self-contained; avoids the broken setup-python)
|
|
run: |
|
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
|
|
|
- name: Git identity
|
|
run: |
|
|
git config user.name "release-bot"
|
|
git config user.email "release-bot@farhoodlabs.com"
|
|
|
|
- name: Bump version + changelog + tag
|
|
id: bump
|
|
run: |
|
|
before=$(uvx --from commitizen cz version --project)
|
|
args="--yes"
|
|
[ "${{ inputs.increment }}" != "auto" ] && args="$args --increment ${{ inputs.increment }}"
|
|
if [ "${{ inputs.dry_run }}" = "true" ]; then
|
|
echo "== DRY RUN =="
|
|
uvx --from commitizen cz bump $args --dry-run || true
|
|
echo "do_release=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
if uvx --from commitizen cz bump $args; then
|
|
after=$(uvx --from commitizen cz version --project)
|
|
# cz bump updates pyproject's version but not uv.lock's own-package
|
|
# entry, which would leave `uv sync --locked` failing at the release
|
|
# tag. Refresh the lock and fold it into the bump commit + tag.
|
|
uv lock
|
|
if ! git diff --quiet uv.lock; then
|
|
git add uv.lock
|
|
git commit --amend --no-edit
|
|
git tag -f "v$after"
|
|
fi
|
|
echo "version=$after" >> "$GITHUB_OUTPUT"
|
|
echo "do_release=true" >> "$GITHUB_OUTPUT"
|
|
echo "Bumped $before -> $after"
|
|
else
|
|
echo "No releasable commits since the last tag — nothing to do."
|
|
echo "do_release=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Push commit + tag
|
|
if: ${{ steps.bump.outputs.do_release == 'true' }}
|
|
run: git push origin HEAD:${{ github.ref_name }} --follow-tags
|
|
|
|
- name: Create Gitea release
|
|
if: ${{ steps.bump.outputs.do_release == 'true' }}
|
|
run: |
|
|
v="${{ steps.bump.outputs.version }}"
|
|
# Body = this version's section from CHANGELOG.md (fallback to a stub).
|
|
body=$(awk "/^## \\[$v\\]/{f=1;next} /^## \\[/{f=0} f" CHANGELOG.md)
|
|
[ -z "$body" ] && body="Release v$v"
|
|
jq -n --arg tag "v$v" --arg name "v$v" --arg body "$body" \
|
|
'{tag_name:$tag, name:$name, body:$body, draft:false, prerelease:false}' \
|
|
| curl -sf -X POST \
|
|
-H "Authorization: token ${{ secrets.RELEASE_TOKEN || github.token }}" \
|
|
-H "Content-Type: application/json" \
|
|
--data @- \
|
|
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases"
|
|
echo "Created release v$v"
|