|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Explains a staging/production trunk fork and prints the heal command. |
| 3 | +# Expects origin/main = staging main and production/main = production main, |
| 4 | +# plus GITHUB_REPOSITORY (staging) and PRODUCTION_REPO (production). |
| 5 | +set -uo pipefail |
| 6 | + |
| 7 | +STAGING_REPO="$GITHUB_REPOSITORY" |
| 8 | +MERGE_MSG="chore: merge staging main into production to heal trunk fork" |
| 9 | +# A squash PR cannot heal the fork: only a real merge commit makes staging an |
| 10 | +# ancestor of production again, so this pushes past production's PR rule. |
| 11 | +HEAL="git clone -q https://github.com/${STAGING_REPO}.git heal-fork && cd heal-fork && git remote add production https://github.com/${PRODUCTION_REPO}.git && git fetch -q production main && git checkout -B heal-fork production/main && git merge --no-ff origin/main -m \"${MERGE_MSG}\" && git push production heal-fork:main" |
| 12 | +RESYNC="gh workflow run stlc-sync.yml -R ${STAGING_REPO}" |
| 13 | + |
| 14 | +if git merge-tree --write-tree origin/main production/main >/dev/null 2>&1; then |
| 15 | + CLEAN=true |
| 16 | +else |
| 17 | + CLEAN=false |
| 18 | +fi |
| 19 | + |
| 20 | +{ |
| 21 | + echo "### Staging and production main have forked" |
| 22 | + echo |
| 23 | + echo "Each trunk has commits the other lacks, so neither back-sync nor promote can fast-forward. Every run of both fails until the fork is healed." |
| 24 | + echo |
| 25 | + echo "**Only on staging** (\`${STAGING_REPO}\`):" |
| 26 | + echo '```' |
| 27 | + git log --format='%h %an %s' production/main..origin/main |
| 28 | + echo '```' |
| 29 | + echo "**Only on production** (\`${PRODUCTION_REPO}\`):" |
| 30 | + echo '```' |
| 31 | + git log --format='%h %an %s' origin/main..production/main |
| 32 | + echo '```' |
| 33 | + if [ "$CLEAN" = true ]; then |
| 34 | + echo "They merge cleanly. Heal by pushing a merge commit to production main, with an identity that can bypass its pull-request rule (a squash-merged PR does not restore ancestry):" |
| 35 | + echo '```' |
| 36 | + echo "$HEAL" |
| 37 | + echo '```' |
| 38 | + echo "Then back-sync fast-forwards staging onto it:" |
| 39 | + echo '```' |
| 40 | + echo "$RESYNC" |
| 41 | + echo '```' |
| 42 | + else |
| 43 | + echo "They **conflict**, so the heal needs a hand-resolved merge: run the command below without the final \`git push\`, resolve and commit, then push \`heal-fork\` to production main and run \`${RESYNC}\`." |
| 44 | + echo '```' |
| 45 | + echo "$HEAL" |
| 46 | + echo '```' |
| 47 | + fi |
| 48 | +} >> "${GITHUB_STEP_SUMMARY:-/dev/stdout}" |
| 49 | + |
| 50 | +if [ "$CLEAN" = true ]; then |
| 51 | + echo "::error title=Trunks forked (clean merge)::staging and production main have diverged. Heal: push a merge commit to production main, then re-run back-sync. See the job summary for the commits involved.%0A%0A${HEAL}%0A%0A${RESYNC}" |
| 52 | +else |
| 53 | + echo "::error title=Trunks forked (conflicting)::staging and production main have diverged and do not merge cleanly. Hand-resolve a merge of staging main into production main, push it, then run: ${RESYNC}. See the job summary." |
| 54 | +fi |
0 commit comments