ci(sync): auto-resolve recurring upstream conflicts, fix workflow restore

The weekly upstream sync hard-failed whenever upstream touched files the
fork diverges on (README branding) or removed a now-generated file
(tests/operations/index.mjs). It also had a latent bug: the workflow
restore ran 'git checkout HEAD -- .github/workflows/' *after* the merge
had already auto-committed, so HEAD was the merge commit and the restore
was a no-op.

- Merge with --no-commit so HEAD stays the pre-merge fork commit, making
  the workflow restore actually keep the fork's workflows.
- Auto-resolve the two recurring conflicts: keep the fork's README, and
  honour upstream deletions of generated/gitignored files.
- Fail loudly (and abort the merge) on any other, unexpected conflict
  instead of pushing a half-resolved tree.
- Exit cleanly when already up to date.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
J8k3 2026-06-15 08:21:03 -04:00
parent 6e85321409
commit 1045fcc3c5

View File

@ -15,11 +15,55 @@ jobs:
- name: Sync upstream - name: Sync upstream
run: | run: |
set -eo pipefail
git config user.email "github-actions[bot]@users.noreply.github.com" git config user.email "github-actions[bot]@users.noreply.github.com"
git config user.name "github-actions[bot]" git config user.name "github-actions[bot]"
git remote add upstream https://github.com/gchq/CyberChef.git git remote add upstream https://github.com/gchq/CyberChef.git
git fetch upstream git fetch upstream
git merge upstream/master
# Merge without committing so we can post-process the result before
# creating a single merge commit:
# - auto-resolve the conflicts this fork hits every week,
# - keep the fork's own workflow files (HEAD stays the pre-merge
# fork commit while --no-commit is in effect).
git merge --no-commit --no-ff upstream/master || true
if ! git rev-parse -q --verify MERGE_HEAD >/dev/null; then
echo "Already up to date with upstream."
exit 0
fi
# Resolve known, recurring conflicts; bail out loudly on anything
# unexpected so we never push a half-resolved tree to master.
unresolved=""
for f in $(git diff --name-only --diff-filter=U); do
if [ "$f" = "README.md" ]; then
# The fork's README intentionally diverges (jacobmarks.com
# branding + extra demo links); keep our version.
git checkout --ours -- "$f"
git add -- "$f"
echo "Resolved $f -> kept fork version"
elif ! git cat-file -e "upstream/master:$f" 2>/dev/null \
&& git check-ignore -q --no-index "$f"; then
# Generated/gitignored file that upstream has deleted (e.g.
# tests/operations/index.mjs is now produced by grunt
# configTests); honour the deletion.
git rm -q -- "$f"
echo "Resolved $f -> honoured upstream deletion (generated file)"
else
unresolved="$unresolved $f"
fi
done
if [ -n "$unresolved" ]; then
echo "::error::Unresolved merge conflicts need manual resolution:$unresolved"
git merge --abort
exit 1
fi
# Keep the fork's own workflow files instead of adopting upstream's.
git checkout HEAD -- .github/workflows/ git checkout HEAD -- .github/workflows/
git commit --amend --no-edit git add -A .github/workflows/
git commit --no-edit
git push origin master git push origin master