From 1045fcc3c5fe102dd31b801f29f40294a3e3130f Mon Sep 17 00:00:00 2001 From: J8k3 Date: Mon, 15 Jun 2026 08:21:03 -0400 Subject: [PATCH] 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) --- .github/workflows/sync_upstream.yml | 48 +++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sync_upstream.yml b/.github/workflows/sync_upstream.yml index 37af5b44..363cc9b0 100644 --- a/.github/workflows/sync_upstream.yml +++ b/.github/workflows/sync_upstream.yml @@ -15,11 +15,55 @@ jobs: - name: Sync upstream run: | + set -eo pipefail git config user.email "github-actions[bot]@users.noreply.github.com" git config user.name "github-actions[bot]" git remote add upstream https://github.com/gchq/CyberChef.git 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 commit --amend --no-edit + git add -A .github/workflows/ + + git commit --no-edit git push origin master