`push: [main]` workflows execute from main's copy of the file, so the hardened auto-backmerge.yml must live on main to govern real back-merges. This brings main's copy in line with next, carrying: - #673: scoped GSD_BOT_PR_TOKEN in the branch / open-PR steps. - #698/#699: admin-merge via the PAT, force-push guarded to chore/backmerge-main-to-next-* branches, `--jq '.[0].number // empty'` + capture-from-create-URL, non-fatal labels, no greenwashing, and loud failure on a genuine conflict. Identical content to next's auto-backmerge.yml (already reviewed/merged in #699). Merging this to main triggers the hardened workflow to back-merge main → next autonomously — the end-to-end validation. Closes #698 Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
61
.github/workflows/auto-backmerge.yml
vendored
61
.github/workflows/auto-backmerge.yml
vendored
@@ -56,7 +56,7 @@ jobs:
|
||||
if: steps.check.outputs.next_exists == 'true'
|
||||
id: branch
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_TOKEN: ${{ secrets.GSD_BOT_PR_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
SHORT_SHA=$(git rev-parse --short HEAD)
|
||||
@@ -71,6 +71,10 @@ jobs:
|
||||
EXISTING_BR=$(echo "$EXISTING_PR" | jq -r '.headRefName // empty')
|
||||
|
||||
if [ -n "$EXISTING_BR" ]; then
|
||||
case "$EXISTING_BR" in
|
||||
chore/backmerge-main-to-next-*) ;;
|
||||
*) echo "::error::refusing to operate on non-backmerge branch: $EXISTING_BR"; exit 1 ;;
|
||||
esac
|
||||
echo "Updating existing back-merge branch: $EXISTING_BR"
|
||||
git fetch origin "$EXISTING_BR":"$EXISTING_BR" || true
|
||||
git checkout "$EXISTING_BR"
|
||||
@@ -79,7 +83,7 @@ jobs:
|
||||
echo "::warning::Merge conflict back-merging main into existing back-merge branch. Human resolution required."
|
||||
exit 1
|
||||
}
|
||||
git push origin "$EXISTING_BR"
|
||||
git push --force origin "$EXISTING_BR"
|
||||
echo "branch=$EXISTING_BR" >> "$GITHUB_OUTPUT"
|
||||
echo "reused=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
@@ -87,28 +91,19 @@ jobs:
|
||||
git checkout -b "$BR" next
|
||||
# Bring main's commits onto next via a merge commit (preserves tag history).
|
||||
if ! git merge --no-edit -m "chore: back-merge main into next" origin/main; then
|
||||
echo "::warning::Conflict during initial back-merge main → next. Pushing the branch anyway so a maintainer can resolve via PR."
|
||||
# Abort and recreate as an empty branch with a CONFLICT marker — gives the maintainer a PR to work in.
|
||||
echo "::error::Cannot auto-back-merge main into next: merge conflict. A maintainer must back-merge manually (git checkout next; git merge origin/main; resolve; push)."
|
||||
git merge --abort || true
|
||||
git push origin "$BR"
|
||||
gh pr create \
|
||||
--base next \
|
||||
--head "$BR" \
|
||||
--title "chore: CONFLICT back-merging main → next (manual resolution required)" \
|
||||
--label automation \
|
||||
--label backmerge \
|
||||
--label needs-human \
|
||||
--body "main moved to ${SHORT_SHA} and cannot be auto-merged into next. Check out this branch locally, resolve the conflict, and push."
|
||||
exit 0
|
||||
exit 1
|
||||
fi
|
||||
git push origin "$BR"
|
||||
git push --force origin "$BR"
|
||||
echo "reused=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Open or update PR
|
||||
if: steps.check.outputs.next_exists == 'true' && steps.branch.outputs.reused != 'true'
|
||||
if: steps.check.outputs.next_exists == 'true'
|
||||
id: openpr
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_TOKEN: ${{ secrets.GSD_BOT_PR_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
BR: ${{ steps.branch.outputs.branch }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -123,21 +118,27 @@ jobs:
|
||||
Generated by \`.github/workflows/auto-backmerge.yml\`.
|
||||
EOF
|
||||
)
|
||||
gh pr create \
|
||||
--base next \
|
||||
--head "$BR" \
|
||||
--title "chore: back-merge main → next (${SHORT_SHA})" \
|
||||
--label automation \
|
||||
--label backmerge \
|
||||
--body "$BODY" \
|
||||
|| echo "::warning::Could not create back-merge PR (may already exist)."
|
||||
PR=$(gh pr list --base next --head "$BR" --state open --json number --jq '.[0].number // empty' 2>/dev/null || echo "")
|
||||
if [ -z "$PR" ]; then
|
||||
PR_URL=$(gh pr create \
|
||||
--base next \
|
||||
--head "$BR" \
|
||||
--title "chore: back-merge main → next (${SHORT_SHA})" \
|
||||
--body "$BODY")
|
||||
PR="${PR_URL##*/}"
|
||||
fi
|
||||
if [ -z "$PR" ]; then
|
||||
echo "::error::back-merge PR was not created"
|
||||
exit 1
|
||||
fi
|
||||
gh pr edit "$PR" --add-label automation --add-label backmerge || true
|
||||
echo "pr=$PR" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Enable auto-merge
|
||||
- name: Admin-merge the back-merge PR
|
||||
if: steps.check.outputs.next_exists == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
BR: ${{ steps.branch.outputs.branch }}
|
||||
GH_TOKEN: ${{ secrets.GSD_BOT_PR_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
PR: ${{ steps.openpr.outputs.pr }}
|
||||
run: |
|
||||
# Squash would lose the merge-commit context; use merge commit.
|
||||
gh pr merge --auto --merge "$BR" \
|
||||
|| echo "::warning::Could not enable auto-merge (PR may not exist yet or auto-merge is disabled on repo)."
|
||||
gh pr merge --admin --merge "$PR"
|
||||
|
||||
Reference in New Issue
Block a user