|
| 1 | +# Keep this fork current with its upstream. Two phases: |
| 2 | +# 1. Fast-forward the mirror branch (master) to upstream — always safe, it |
| 3 | +# carries none of our work. |
| 4 | +# 2. Merge the mirror into our patched work branch. A clean merge is pushed |
| 5 | +# automatically; a conflicting one opens a standing PR for manual |
| 6 | +# resolution instead of clobbering the macOS patches. |
| 7 | +# A GITHUB_TOKEN push does not spawn workflow runs, so after a clean merge we |
| 8 | +# dispatch the build explicitly (workflow_dispatch via the API is the documented |
| 9 | +# exception to that rule) to rebuild against the merged upstream. |
| 10 | +name: Upstream sync |
| 11 | + |
| 12 | +on: |
| 13 | + schedule: |
| 14 | + - cron: "17 4 * * *" |
| 15 | + workflow_dispatch: |
| 16 | + |
| 17 | +permissions: |
| 18 | + contents: write |
| 19 | + pull-requests: write |
| 20 | + actions: write |
| 21 | + |
| 22 | +concurrency: |
| 23 | + group: upstream-sync |
| 24 | + cancel-in-progress: false |
| 25 | + |
| 26 | +env: |
| 27 | + UPSTREAM: beyond-all-reason/RecoilEngine |
| 28 | + MIRROR_BRANCH: master |
| 29 | + WORK_BRANCH: main |
| 30 | + BUILD_WORKFLOW: macos-build-gpu.yml |
| 31 | + |
| 32 | +jobs: |
| 33 | + sync: |
| 34 | + runs-on: ubuntu-latest |
| 35 | + steps: |
| 36 | + - name: Checkout work branch |
| 37 | + uses: actions/checkout@v6 |
| 38 | + with: |
| 39 | + ref: ${{ env.WORK_BRANCH }} |
| 40 | + fetch-depth: 0 |
| 41 | + |
| 42 | + - name: Fast-forward mirror branch to upstream |
| 43 | + env: |
| 44 | + GH_TOKEN: ${{ github.token }} |
| 45 | + run: | |
| 46 | + set -euo pipefail |
| 47 | + gh repo sync "${GITHUB_REPOSITORY}" \ |
| 48 | + --branch "${MIRROR_BRANCH}" --source "${UPSTREAM}" |
| 49 | +
|
| 50 | + - name: Auto-merge upstream into work branch (clean only) |
| 51 | + id: merge |
| 52 | + run: | |
| 53 | + set -euo pipefail |
| 54 | + git config user.name "github-actions[bot]" |
| 55 | + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" |
| 56 | + git fetch origin "${MIRROR_BRANCH}" |
| 57 | + BEFORE="$(git rev-parse HEAD)" |
| 58 | + if git merge --no-edit "origin/${MIRROR_BRANCH}"; then |
| 59 | + AFTER="$(git rev-parse HEAD)" |
| 60 | + if [ "$BEFORE" = "$AFTER" ]; then |
| 61 | + echo "Already up to date with ${MIRROR_BRANCH}." |
| 62 | + echo "result=unchanged" >> "$GITHUB_OUTPUT" |
| 63 | + else |
| 64 | + git push origin "HEAD:${WORK_BRANCH}" |
| 65 | + echo "Merged upstream cleanly and pushed." |
| 66 | + echo "result=merged" >> "$GITHUB_OUTPUT" |
| 67 | + fi |
| 68 | + else |
| 69 | + git merge --abort |
| 70 | + echo "::warning::Upstream merge into ${WORK_BRANCH} conflicts; opening a resolution PR." |
| 71 | + echo "result=conflict" >> "$GITHUB_OUTPUT" |
| 72 | + fi |
| 73 | +
|
| 74 | + - name: Open resolution PR on conflict |
| 75 | + if: steps.merge.outputs.result == 'conflict' |
| 76 | + env: |
| 77 | + GH_TOKEN: ${{ github.token }} |
| 78 | + run: | |
| 79 | + set -euo pipefail |
| 80 | + EXISTING="$(gh pr list --repo "${GITHUB_REPOSITORY}" --state open \ |
| 81 | + --base "${WORK_BRANCH}" --head "${MIRROR_BRANCH}" --json number --jq 'length')" |
| 82 | + if [ "$EXISTING" = "0" ]; then |
| 83 | + gh pr create --repo "${GITHUB_REPOSITORY}" \ |
| 84 | + --base "${WORK_BRANCH}" --head "${MIRROR_BRANCH}" \ |
| 85 | + --title "Sync upstream into ${WORK_BRANCH}" \ |
| 86 | + --body "Automated upstream sync hit conflicts. Merge \`${MIRROR_BRANCH}\` (now level with ${UPSTREAM}) into \`${WORK_BRANCH}\` and resolve here." |
| 87 | + else |
| 88 | + echo "Resolution PR already open." |
| 89 | + fi |
| 90 | +
|
| 91 | + - name: Trigger build after clean merge |
| 92 | + if: steps.merge.outputs.result == 'merged' && env.BUILD_WORKFLOW != '' |
| 93 | + env: |
| 94 | + GH_TOKEN: ${{ github.token }} |
| 95 | + run: | |
| 96 | + set -euo pipefail |
| 97 | + gh workflow run "${BUILD_WORKFLOW}" \ |
| 98 | + --repo "${GITHUB_REPOSITORY}" --ref "${WORK_BRANCH}" |
0 commit comments