ci: add release workflow (manual dispatch: cz bump + tag + Gitea release)
Cutting a release is now a workflow, not a local command. Uses uv/commitizen (actions/setup-python is broken on the current runners). Supports auto-detect or forced increment, and a dry_run mode.
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
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)
|
||||
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"
|
||||
Reference in New Issue
Block a user