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