170 lines
6.5 KiB
YAML
170 lines
6.5 KiB
YAML
name: Auto Main Release Tag
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
workflow_dispatch:
|
|
|
|
concurrency:
|
|
group: auto-main-release-${{ github.ref }}
|
|
cancel-in-progress: false
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
env:
|
|
GIT_CONFIG_COUNT: "1"
|
|
GIT_CONFIG_KEY_0: core.hooksPath
|
|
GIT_CONFIG_VALUE_0: /dev/null
|
|
|
|
jobs:
|
|
tag-and-bump:
|
|
name: Tag current main + prepare next patch version
|
|
runs-on: [self-hosted, Linux, X64, light, cpu40]
|
|
timeout-minutes: 20
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Skip release-prep commits
|
|
id: skip
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
msg="$(git log -1 --pretty=%B | tr -d '\r')"
|
|
if [[ "${msg}" == *"[skip ci]"* && "${msg}" == chore\(release\):\ prepare\ v* ]]; then
|
|
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "skip=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Enforce release automation actor policy
|
|
if: steps.skip.outputs.skip != 'true'
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
actor="${GITHUB_ACTOR}"
|
|
actor_lc="$(echo "${actor}" | tr '[:upper:]' '[:lower:]')"
|
|
allowed_actors_lc="theonlyhennygod,jordanthejet"
|
|
if [[ ",${allowed_actors_lc}," != *",${actor_lc},"* ]]; then
|
|
echo "::error::Only maintainer actors (${allowed_actors_lc}) can trigger main release tagging. Actor: ${actor}"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Resolve current and next version
|
|
if: steps.skip.outputs.skip != 'true'
|
|
id: version
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
current_version="$(awk '
|
|
BEGIN { in_pkg=0 }
|
|
/^\[package\]/ { in_pkg=1; next }
|
|
in_pkg && /^\[/ { in_pkg=0 }
|
|
in_pkg && $1 == "version" {
|
|
value=$3
|
|
gsub(/"/, "", value)
|
|
print value
|
|
exit
|
|
}
|
|
' Cargo.toml)"
|
|
|
|
if [[ -z "${current_version}" ]]; then
|
|
echo "::error::Failed to resolve current package version from Cargo.toml"
|
|
exit 1
|
|
fi
|
|
if [[ ! "${current_version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
echo "::error::Cargo.toml version must be strict semver X.Y.Z (found: ${current_version})"
|
|
exit 1
|
|
fi
|
|
|
|
IFS='.' read -r major minor patch <<< "${current_version}"
|
|
next_patch="$((patch + 1))"
|
|
next_version="${major}.${minor}.${next_patch}"
|
|
|
|
{
|
|
echo "current=${current_version}"
|
|
echo "next=${next_version}"
|
|
echo "tag=v${current_version}"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Verify tag does not already exist
|
|
id: tag_check
|
|
if: steps.skip.outputs.skip != 'true'
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
tag="${{ steps.version.outputs.tag }}"
|
|
if git ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null 2>&1; then
|
|
echo "::warning::Release tag ${tag} already exists on origin; skipping auto-tag/bump for this push."
|
|
echo "exists=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "exists=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Create and push annotated release tag
|
|
if: steps.skip.outputs.skip != 'true' && steps.tag_check.outputs.exists != 'true'
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
tag="${{ steps.version.outputs.tag }}"
|
|
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
|
|
git tag -a "${tag}" -m "Release ${tag}"
|
|
git push origin "refs/tags/${tag}"
|
|
|
|
- name: Bump Cargo version for next release
|
|
if: steps.skip.outputs.skip != 'true' && steps.tag_check.outputs.exists != 'true'
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
next="${{ steps.version.outputs.next }}"
|
|
|
|
awk -v new_version="${next}" '
|
|
BEGIN { in_pkg=0; done=0 }
|
|
/^\[package\]/ { in_pkg=1 }
|
|
in_pkg && /^\[/ && $0 !~ /^\[package\]/ { in_pkg=0 }
|
|
in_pkg && $1 == "version" && done == 0 {
|
|
sub(/"[^"]+"/, "\"" new_version "\"")
|
|
done=1
|
|
}
|
|
{ print }
|
|
' Cargo.toml > Cargo.toml.tmp
|
|
mv Cargo.toml.tmp Cargo.toml
|
|
|
|
awk -v new_version="${next}" '
|
|
BEGIN { in_pkg=0; zc_pkg=0; done=0 }
|
|
/^\[\[package\]\]/ { in_pkg=1; zc_pkg=0 }
|
|
in_pkg && /^name = "zeroclaw"$/ { zc_pkg=1 }
|
|
in_pkg && zc_pkg && /^version = "/ && done == 0 {
|
|
sub(/"[^"]+"/, "\"" new_version "\"")
|
|
done=1
|
|
}
|
|
{ print }
|
|
' Cargo.lock > Cargo.lock.tmp
|
|
mv Cargo.lock.tmp Cargo.lock
|
|
|
|
- name: Commit and push next-version prep
|
|
if: steps.skip.outputs.skip != 'true' && steps.tag_check.outputs.exists != 'true'
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
next="${{ steps.version.outputs.next }}"
|
|
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
|
|
git add Cargo.toml Cargo.lock
|
|
if git diff --cached --quiet; then
|
|
echo "No version changes detected; nothing to commit."
|
|
exit 0
|
|
fi
|
|
|
|
git commit -m "chore(release): prepare v${next} [skip ci]"
|
|
git push origin HEAD:main
|