diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5624d19..ea2ca73 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,5 +1,13 @@ name: Release +# Release is triggered by pushing a vX.Y.Z tag. +# +# PREREQUISITE: Before tagging, merge develop → main via PR. +# The tag must point to a commit on main, NOT develop. +# GitFlow: develop (default) → PR → main → tag → release. +# +# This workflow does NOT sync main — main must already be up to date. + on: push: tags: @@ -10,46 +18,32 @@ env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true jobs: - sync-main: - name: Sync main ← tag commit + verify-main: + name: Verify tag is on main runs-on: ubuntu-latest - # Blocking: main MUST be synced before release artifacts are built. - # If main can't be fast-forwarded, the release aborts to prevent - # stale install.sh / mismatched main branch. - # (Hardened after uteke issue #325 — same pattern caused main to get - # stuck at old version while release proceeded.) - if: startsWith(github.ref, 'refs/tags/v') - permissions: - contents: write steps: - uses: actions/checkout@v6 with: fetch-depth: 0 - - - name: Fast-forward main to tag commit - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Check tag is on main run: | - # Fetch main branch ref so merge-base can check ancestry. git fetch origin main - TAG_SHA=$(git rev-parse "${{ github.ref }}^{commit}") - echo "Tag commit: $TAG_SHA" - - # Check if main is an ancestor of TAG_SHA (safe fast-forward). - # If main is NOT an ancestor, abort — force-updating would - # rewrite history and potentially lose commits. - if git merge-base --is-ancestor origin/main "$TAG_SHA" 2>/dev/null; then - git push origin "$TAG_SHA:refs/heads/main" - echo "✅ main fast-forwarded to $TAG_SHA" + MAIN_SHA=$(git rev-parse origin/main) + echo "Tag: $TAG_SHA" + echo "main: $MAIN_SHA" + if [ "$TAG_SHA" = "$MAIN_SHA" ]; then + echo "✅ Tag is main HEAD" + elif git merge-base --is-ancestor "$TAG_SHA" origin/main 2>/dev/null; then + echo "✅ Tag commit $TAG_SHA is in main history" else - echo "::error::main is not an ancestor of tag commit. Refusing to force-update." - echo "Manual intervention required: merge develop into main first." + echo "::error::Tag commit $TAG_SHA is NOT on main." + echo "Merge develop → main via PR before tagging." exit 1 fi build-release: - needs: sync-main + needs: [verify-main] name: Build ${{ matrix.target }} runs-on: ${{ matrix.os }} strategy: @@ -125,7 +119,7 @@ jobs: publish-crates: name: Publish to crates.io - needs: [sync-main] + needs: [verify-main] runs-on: ubuntu-latest permissions: id-token: write