Skip to content

Commit cdaa40b

Browse files
committed
feat: automate upstream sync and merge
1 parent 24b3192 commit cdaa40b

2 files changed

Lines changed: 150 additions & 0 deletions

File tree

.gitattributes

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Keep fork-local workflow customizations on upstream merges.
2+
# The sync workflow registers the 'ours' driver (a no-op) so that any upstream
3+
# changes conflicting with local edits under .github/workflows/ are auto-resolved
4+
# in favor of the fork's version.
5+
#
6+
# Note: this only covers *conflicting* paths. A brand-new workflow file added
7+
# upstream will still land on master — disable it by hand if needed.
8+
.github/workflows/** merge=ours
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
name: Sync with upstream graphprotocol/graph-node
2+
3+
on:
4+
schedule:
5+
- cron: '0 7 * * 1' # Monday 07:00 UTC
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: write
10+
pull-requests: write
11+
12+
env:
13+
UPSTREAM_URL: https://github.com/graphprotocol/graph-node.git
14+
UPSTREAM_BRANCH: master
15+
REVIEWER: vladzr
16+
17+
jobs:
18+
sync:
19+
runs-on: ubuntu-latest
20+
timeout-minutes: 15
21+
steps:
22+
- name: Checkout fork (full history)
23+
uses: actions/checkout@v4
24+
with:
25+
fetch-depth: 0
26+
27+
- name: Configure git identity
28+
run: |
29+
git config user.name "github-actions[bot]"
30+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
31+
32+
- name: Register 'ours' merge driver
33+
# .gitattributes maps .github/workflows/** to merge=ours; this makes that
34+
# driver a no-op so the fork's version wins on conflicts.
35+
run: git config merge.ours.driver true
36+
37+
- name: Add upstream and fetch
38+
run: |
39+
git remote add upstream "$UPSTREAM_URL"
40+
git fetch upstream "$UPSTREAM_BRANCH"
41+
42+
- name: Check for new commits
43+
id: check
44+
run: |
45+
if git merge-base --is-ancestor "upstream/$UPSTREAM_BRANCH" HEAD; then
46+
echo "up_to_date=true" >> "$GITHUB_OUTPUT"
47+
echo "Already up to date with upstream/$UPSTREAM_BRANCH — nothing to do."
48+
else
49+
echo "up_to_date=false" >> "$GITHUB_OUTPUT"
50+
echo "Commits to sync:"
51+
git log --oneline "HEAD..upstream/$UPSTREAM_BRANCH" | head -50
52+
fi
53+
54+
- name: Create branch and merge upstream
55+
if: steps.check.outputs.up_to_date != 'true'
56+
id: merge
57+
run: |
58+
BRANCH="sync-upstream-$(date -u +%Y%m%d)"
59+
echo "branch=$BRANCH" >> "$GITHUB_OUTPUT"
60+
echo "pre_merge_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
61+
# If a prior same-day run left a branch behind, replace it.
62+
git push origin --delete "$BRANCH" 2>/dev/null || true
63+
git checkout -b "$BRANCH"
64+
if ! git merge --no-ff --no-edit "upstream/$UPSTREAM_BRANCH"; then
65+
echo "::error::Merge failed — conflict outside .github/workflows/. Resolve manually."
66+
git status
67+
git diff --name-only --diff-filter=U
68+
exit 1
69+
fi
70+
71+
- name: Detect newly-added workflow files
72+
if: steps.check.outputs.up_to_date != 'true'
73+
id: new_workflows
74+
run: |
75+
ADDED=$(git diff --name-only --diff-filter=A \
76+
"${{ steps.merge.outputs.pre_merge_sha }}..HEAD" -- .github/workflows/)
77+
if [ -z "$ADDED" ]; then
78+
echo "any=false" >> "$GITHUB_OUTPUT"
79+
echo "No new workflow files — safe to auto-merge."
80+
else
81+
echo "any=true" >> "$GITHUB_OUTPUT"
82+
{
83+
echo "list<<NEW_WF_EOF"
84+
echo "$ADDED"
85+
echo "NEW_WF_EOF"
86+
} >> "$GITHUB_OUTPUT"
87+
echo "New workflow files from upstream — auto-merge will be skipped:"
88+
echo "$ADDED"
89+
fi
90+
91+
- name: Push branch
92+
if: steps.check.outputs.up_to_date != 'true'
93+
run: git push -u origin "${{ steps.merge.outputs.branch }}"
94+
95+
- name: Open PR
96+
if: steps.check.outputs.up_to_date != 'true'
97+
env:
98+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
99+
NEW_WF_ANY: ${{ steps.new_workflows.outputs.any }}
100+
NEW_WF_LIST: ${{ steps.new_workflows.outputs.list }}
101+
BRANCH: ${{ steps.merge.outputs.branch }}
102+
run: |
103+
if gh pr view "$BRANCH" --json number >/dev/null 2>&1; then
104+
echo "PR already exists for $BRANCH — leaving it alone."
105+
exit 0
106+
fi
107+
108+
if [ "$NEW_WF_ANY" = "true" ]; then
109+
NOTICE="New upstream workflow files detected — auto-merge skipped. Review and decide whether to keep or disable each:
110+
111+
\`\`\`
112+
$NEW_WF_LIST
113+
\`\`\`"
114+
115+
else
116+
NOTICE="No new workflow files from upstream — auto-merge enabled. docker-publish will be dispatched after merge."
117+
fi
118+
119+
BODY="Weekly automated sync with upstream \`graphprotocol/graph-node\` \`master\`.
120+
121+
$NOTICE
122+
123+
Fork-local workflow customizations are preserved via \`.gitattributes\` (\`merge=ours\` on \`.github/workflows/**\`)."
124+
125+
gh pr create \
126+
--base master \
127+
--head "$BRANCH" \
128+
--title "Sync with graphprotocol/graph-node master ($(date -u +%Y-%m-%d))" \
129+
--body "$BODY" \
130+
--reviewer "$REVIEWER"
131+
132+
- name: Auto-merge PR (no new workflows)
133+
if: steps.check.outputs.up_to_date != 'true' && steps.new_workflows.outputs.any == 'false'
134+
env:
135+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
136+
run: gh pr merge "${{ steps.merge.outputs.branch }}" --merge --delete-branch
137+
138+
- name: Dispatch docker-publish on master
139+
if: steps.check.outputs.up_to_date != 'true' && steps.new_workflows.outputs.any == 'false'
140+
env:
141+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
142+
run: gh workflow run docker-publish.yml --ref master

0 commit comments

Comments
 (0)