Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
231 changes: 231 additions & 0 deletions .github/workflows/ddmal-sync-upstream.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
name: Sync with RISM Upstream

on:
# Run automatically every Monday at 07:00 UTC (3am in Montreal)
schedule:
- cron: "0 7 * * 1"

# Allow manual triggering
workflow_dispatch:
inputs:
force_rebase:
description: "Force rebase even if no new commits detected"
required: false
default: false
type: boolean

jobs:
sync-upstream:
runs-on: ubuntu-latest
# Only run this workflow on the DDMAL/verovio repository
if: github.repository == 'DDMAL/verovio'

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
# Fetch full history for proper rebasing
fetch-depth: 0
# Use a personal access token with repo permissions
token: ${{ secrets.GITHUB_TOKEN }}
ref: develop

- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Add upstream remote
run: |
# Check if upstream remote already exists
if git remote get-url upstream 2>/dev/null; then
echo "Upstream remote already exists"
git remote set-url upstream https://github.com/rism-digital/verovio.git
else
echo "Adding upstream remote"
git remote add upstream https://github.com/rism-digital/verovio.git
fi

- name: Fetch upstream changes
run: |
echo "Fetching upstream changes..."
git fetch upstream develop

- name: Check for new commits
id: check_commits
run: |
# Get the latest commit hash from upstream
UPSTREAM_COMMIT=$(git rev-parse upstream/develop)

# Get the latest commit hash from our develop branch
LOCAL_COMMIT=$(git rev-parse develop)

echo "Upstream commit: $UPSTREAM_COMMIT"
echo "Local commit: $LOCAL_COMMIT"

# Check if there are new commits to sync
if [ "$UPSTREAM_COMMIT" != "$LOCAL_COMMIT" ]; then
echo "new_commits=true" >> $GITHUB_OUTPUT
echo "New commits detected in upstream"

# Count the number of commits behind
COMMITS_BEHIND=$(git rev-list --count develop..upstream/develop)
echo "commits_behind=$COMMITS_BEHIND" >> $GITHUB_OUTPUT
echo "Local branch is $COMMITS_BEHIND commits behind upstream"
else
echo "new_commits=false" >> $GITHUB_OUTPUT
echo "No new commits in upstream"
echo "commits_behind=0" >> $GITHUB_OUTPUT
fi

- name: Check for local uncommitted changes
# It's a good practice to check if the runner is in a dirty state before running a rebase
if: steps.check_commits.outputs.new_commits == 'true' || github.event.inputs.force_rebase == 'true'
run: |
if [ -n "$(git status --porcelain)" ]; then
echo "Error: Working directory has uncommitted changes"
git status
exit 1
fi

- name: Rebase onto upstream
if: steps.check_commits.outputs.new_commits == 'true' || github.event.inputs.force_rebase == 'true'
run: |
echo "Starting rebase onto upstream/develop..."

# Attempt to rebase
if git rebase upstream/develop; then
echo "✅ Rebase successful!"
else
echo "❌ Rebase failed due to conflicts"
echo "Aborting rebase..."
git rebase --abort

# Set failure type
echo "SYNC_FAILED=rebase" >> $GITHUB_ENV
exit 1
fi

- name: Push rebased changes
if: (steps.check_commits.outputs.new_commits == 'true' || github.event.inputs.force_rebase == 'true') && env.SYNC_FAILED == ''
# force-with-lease is used to avoid overwriting changes that have been pushed and not yet merged to upstream
run: |
echo "Pushing rebased changes to origin/develop..."
if ! git push --force-with-lease origin develop; then
echo "❌ Push failed"
echo "SYNC_FAILED=push" >> $GITHUB_ENV
exit 1
fi

- name: Create issue on sync failure
if: env.SYNC_FAILED != ''
uses: actions/github-script@v7
with:
script: |
const failureType = process.env.SYNC_FAILED || 'unknown';

// Determine failure-specific details
let title, failureReason, manualSteps;

if (failureType === 'rebase') {
title = `🚨 Verovio Upstream Sync Failed - Rebase Conflicts`;
failureReason = 'merge conflicts during rebase';
manualSteps = `1. Go to the DDMAL/verovio repository
2. Fetch the latest upstream changes: \`git fetch upstream develop\`
3. Rebase manually: \`git rebase upstream/develop\`
4. Resolve any conflicts
5. Push the rebased branch: \`git push --force-with-lease origin develop\``;
} else if (failureType === 'push') {
title = `🚨 Verovio Upstream Sync Failed - Push Error`;
failureReason = 'push failure (likely due to permission issues)';
manualSteps = `1. Check if the GitHub token has \`workflow\` scope permissions
2. Verify the workflow file hasn't been modified in a way that requires approval
3. If using GITHUB_TOKEN, consider switching to a PAT or GitHub App with workflow permissions
4. Try running the workflow again manually
5. If the issue persists, check the workflow run logs for details`;
} else {
title = `🚨 Verovio Upstream Sync Failed`;
failureReason = 'an unknown error';
manualSteps = `1. Check the workflow run logs for details
2. Verify repository permissions and token scopes
3. Try running the workflow manually`;
}

const body = `## Automatic upstream sync failed in DDMAL/verovio

The scheduled rebase onto \`rism-digital/verovio:develop\` failed due to ${failureReason}.

**Details:**
- Repository: ${{ github.repository }}
- Failure type: ${failureType}
- Upstream commits to sync: ${{ steps.check_commits.outputs.commits_behind }}
- Workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}

**Manual action required:**
${manualSteps}

This issue will be automatically closed when the next successful sync occurs.`;

// Check if an issue already exists in DDMAL/Neon
const existingIssues = await github.rest.issues.listForRepo({
owner: 'DDMAL',
repo: 'Neon',
labels: ['verovio-upstream-sync-failure'],
state: 'open'
});

if (existingIssues.data.length === 0) {
await github.rest.issues.create({
owner: 'DDMAL',
repo: 'Neon',
title: title,
body: body,
labels: ['verovio-upstream-sync-failure', 'automation']
});
}

- name: Close existing sync failure issues
if: (steps.check_commits.outputs.new_commits == 'true' || github.event.inputs.force_rebase == 'true') && env.SYNC_FAILED == ''
uses: actions/github-script@v7
with:
script: |
// Close any existing upstream sync failure issues in DDMAL/Neon
const existingIssues = await github.rest.issues.listForRepo({
owner: 'DDMAL',
repo: 'Neon',
labels: ['verovio-upstream-sync-failure'],
state: 'open'
});

for (const issue of existingIssues.data) {
await github.rest.issues.createComment({
owner: 'DDMAL',
repo: 'Neon',
issue_number: issue.number,
body: '✅ Verovio upstream sync completed successfully. Closing this issue.'
});

await github.rest.issues.update({
owner: 'DDMAL',
repo: 'Neon',
issue_number: issue.number,
state: 'closed'
});
}

- name: Summary
run: |
if [ "${{ steps.check_commits.outputs.new_commits }}" = "true" ] || [ "${{ github.event.inputs.force_rebase }}" = "true" ]; then
if [ "$SYNC_FAILED" = "rebase" ]; then
echo "❌ Sync failed due to rebase conflicts"
echo "📝 An issue has been created for manual intervention"
elif [ "$SYNC_FAILED" = "push" ]; then
echo "❌ Sync failed due to push error"
echo "📝 An issue has been created for manual intervention"
else
echo "✅ Successfully synced ${{ steps.check_commits.outputs.commits_behind }} commits from upstream"
echo "🚀 Changes pushed to develop branch"
fi
else
echo "ℹ️ No new commits to sync"
fi