Skip to content

Commit 9f3a581

Browse files
committed
ci: add DDMAL workflow for syncing with RISM changes
- This workflow runs every Monday at 3am montreal time. - An issue will be created if rebase or push fails - Previous related issues will be closed if the latest run passes. refs: Neon/issues/1347
1 parent b741a12 commit 9f3a581

File tree

1 file changed

+232
-0
lines changed

1 file changed

+232
-0
lines changed
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
name: Sync with RISM Upstream
2+
3+
on:
4+
# Run automatically every Monday at 07:00 UTC (3am in Montreal)
5+
schedule:
6+
- cron: "0 7 * * 1"
7+
8+
# Allow manual triggering
9+
workflow_dispatch:
10+
inputs:
11+
force_rebase:
12+
description: "Force rebase even if no new commits detected"
13+
required: false
14+
default: false
15+
type: boolean
16+
17+
jobs:
18+
sync-upstream:
19+
runs-on: ubuntu-latest
20+
# Only run this workflow on the DDMAL/verovio repository
21+
if: github.repository == 'DDMAL/verovio'
22+
23+
steps:
24+
- name: Checkout repository
25+
uses: actions/checkout@v4
26+
with:
27+
# Fetch full history for proper rebasing
28+
fetch-depth: 0
29+
# Use a personal access token with repo permissions
30+
token: ${{ secrets.GITHUB_TOKEN }}
31+
ref: develop
32+
33+
- name: Configure Git
34+
run: |
35+
git config user.name "github-actions[bot]"
36+
git config user.email "github-actions[bot]@users.noreply.github.com"
37+
38+
- name: Add upstream remote
39+
run: |
40+
# Check if upstream remote already exists
41+
if git remote get-url upstream 2>/dev/null; then
42+
echo "Upstream remote already exists"
43+
git remote set-url upstream https://github.com/rism-digital/verovio.git
44+
else
45+
echo "Adding upstream remote"
46+
git remote add upstream https://github.com/rism-digital/verovio.git
47+
fi
48+
49+
- name: Fetch upstream changes
50+
run: |
51+
echo "Fetching upstream changes..."
52+
git fetch upstream develop
53+
54+
- name: Check for new commits
55+
id: check_commits
56+
run: |
57+
# Get the latest commit hash from upstream
58+
UPSTREAM_COMMIT=$(git rev-parse upstream/develop)
59+
60+
# Get the latest commit hash from our develop branch
61+
LOCAL_COMMIT=$(git rev-parse develop)
62+
63+
echo "Upstream commit: $UPSTREAM_COMMIT"
64+
echo "Local commit: $LOCAL_COMMIT"
65+
66+
# Check if there are new commits to sync
67+
if [ "$UPSTREAM_COMMIT" != "$LOCAL_COMMIT" ]; then
68+
echo "new_commits=true" >> $GITHUB_OUTPUT
69+
echo "New commits detected in upstream"
70+
71+
# Count the number of commits behind
72+
COMMITS_BEHIND=$(git rev-list --count develop..upstream/develop)
73+
echo "commits_behind=$COMMITS_BEHIND" >> $GITHUB_OUTPUT
74+
echo "Local branch is $COMMITS_BEHIND commits behind upstream"
75+
else
76+
echo "new_commits=false" >> $GITHUB_OUTPUT
77+
echo "No new commits in upstream"
78+
echo "commits_behind=0" >> $GITHUB_OUTPUT
79+
fi
80+
81+
- name: Check for local uncommitted changes
82+
# It's a good practice to check if the runner is in a dirty state before running a rebase
83+
if: steps.check_commits.outputs.new_commits == 'true' || github.event.inputs.force_rebase == 'true'
84+
run: |
85+
if [ -n "$(git status --porcelain)" ]; then
86+
echo "Error: Working directory has uncommitted changes"
87+
git status
88+
exit 1
89+
fi
90+
91+
- name: Rebase onto upstream
92+
if: steps.check_commits.outputs.new_commits == 'true' || github.event.inputs.force_rebase == 'true'
93+
run: |
94+
echo "Starting rebase onto upstream/develop..."
95+
96+
# Attempt to rebase
97+
if git rebase upstream/develop; then
98+
echo "βœ… Rebase successful!"
99+
else
100+
echo "❌ Rebase failed due to conflicts"
101+
echo "Aborting rebase..."
102+
git rebase --abort
103+
104+
# Set failure type
105+
echo "SYNC_FAILED=rebase" >> $GITHUB_ENV
106+
exit 1
107+
fi
108+
109+
- name: Push rebased changes
110+
if: (steps.check_commits.outputs.new_commits == 'true' || github.event.inputs.force_rebase == 'true') && env.SYNC_FAILED == ''
111+
# force-with-lease is used to avoid overwriting changes that have been pushed and not yet merged to upstream
112+
run: |
113+
echo "Pushing rebased changes to origin/develop..."
114+
if ! git push --force-with-lease origin develop; then
115+
echo "❌ Push failed"
116+
echo "SYNC_FAILED=push" >> $GITHUB_ENV
117+
exit 1
118+
fi
119+
120+
- name: Create issue on sync failure
121+
if: failure() && env.SYNC_FAILED != ''
122+
uses: actions/github-script@v7
123+
with:
124+
script: |
125+
const failureType = process.env.SYNC_FAILED || 'unknown';
126+
127+
// Determine failure-specific details
128+
let title, failureReason, manualSteps;
129+
130+
if (failureType === 'rebase') {
131+
title = `🚨 Verovio Upstream Sync Failed - Rebase Conflicts`;
132+
failureReason = 'merge conflicts during rebase';
133+
manualSteps = `1. Go to the DDMAL/verovio repository
134+
2. Fetch the latest upstream changes: \`git fetch upstream develop\`
135+
3. Rebase manually: \`git rebase upstream/develop\`
136+
4. Resolve any conflicts
137+
5. Push the rebased branch: \`git push --force-with-lease origin develop\``;
138+
} else if (failureType === 'push') {
139+
title = `🚨 Verovio Upstream Sync Failed - Push Error`;
140+
failureReason = 'push failure (likely due to permission issues)';
141+
manualSteps = `1. Check if the GitHub token has \`workflow\` scope permissions
142+
2. Verify the workflow file hasn't been modified in a way that requires approval
143+
3. If using GITHUB_TOKEN, consider switching to a PAT or GitHub App with workflow permissions
144+
4. Try running the workflow again manually
145+
5. If the issue persists, check the workflow run logs for details`;
146+
} else {
147+
title = `🚨 Verovio Upstream Sync Failed`;
148+
failureReason = 'an unknown error';
149+
manualSteps = `1. Check the workflow run logs for details
150+
2. Verify repository permissions and token scopes
151+
3. Try running the workflow manually`;
152+
}
153+
154+
const body = `## Automatic upstream sync failed in DDMAL/verovio
155+
156+
The scheduled rebase onto \`rism-digital/verovio:develop\` failed due to ${failureReason}.
157+
158+
**Details:**
159+
- Repository: ${{ github.repository }}
160+
- Failure type: ${failureType}
161+
- Upstream commits to sync: ${{ steps.check_commits.outputs.commits_behind }}
162+
- Workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
163+
164+
**Manual action required:**
165+
${manualSteps}
166+
167+
This issue will be automatically closed when the next successful sync occurs.`;
168+
169+
// Check if an issue already exists in DDMAL/Neon
170+
const existingIssues = await github.rest.issues.listForRepo({
171+
owner: 'DDMAL',
172+
repo: 'Neon',
173+
labels: ['verovio-upstream-sync-failure'],
174+
state: 'open'
175+
});
176+
177+
if (existingIssues.data.length === 0) {
178+
await github.rest.issues.create({
179+
owner: 'DDMAL',
180+
repo: 'Neon',
181+
title: title,
182+
body: body,
183+
labels: ['verovio-upstream-sync-failure', 'automation']
184+
});
185+
}
186+
187+
- name: Close existing sync failure issues
188+
if: success() && (steps.check_commits.outputs.new_commits == 'true' || github.event.inputs.force_rebase == 'true') && env.SYNC_FAILED == ''
189+
uses: actions/github-script@v7
190+
with:
191+
script: |
192+
// Close any existing upstream sync failure issues in DDMAL/Neon
193+
const existingIssues = await github.rest.issues.listForRepo({
194+
owner: 'DDMAL',
195+
repo: 'Neon',
196+
labels: ['verovio-upstream-sync-failure'],
197+
state: 'open'
198+
});
199+
200+
for (const issue of existingIssues.data) {
201+
await github.rest.issues.createComment({
202+
owner: 'DDMAL',
203+
repo: 'Neon',
204+
issue_number: issue.number,
205+
body: 'βœ… Verovio upstream sync completed successfully. Closing this issue.'
206+
});
207+
208+
await github.rest.issues.update({
209+
owner: 'DDMAL',
210+
repo: 'Neon',
211+
issue_number: issue.number,
212+
state: 'closed'
213+
});
214+
}
215+
216+
- name: Summary
217+
if: always()
218+
run: |
219+
if [ "${{ steps.check_commits.outputs.new_commits }}" = "true" ] || [ "${{ github.event.inputs.force_rebase }}" = "true" ]; then
220+
if [ "$SYNC_FAILED" = "rebase" ]; then
221+
echo "❌ Sync failed due to rebase conflicts"
222+
echo "πŸ“ An issue has been created for manual intervention"
223+
elif [ "$SYNC_FAILED" = "push" ]; then
224+
echo "❌ Sync failed due to push error"
225+
echo "πŸ“ An issue has been created for manual intervention"
226+
else
227+
echo "βœ… Successfully synced ${{ steps.check_commits.outputs.commits_behind }} commits from upstream"
228+
echo "πŸš€ Changes pushed to develop branch"
229+
fi
230+
else
231+
echo "ℹ️ No new commits to sync"
232+
fi

0 commit comments

Comments
Β (0)