ci: add automated upstream sync workflow

- upstream-sync.yml: Daily check for syndicate/master updates
  - Rebases wylab commits onto upstream changes
  - Creates PR for CI verification
  - Creates issue if rebase conflicts occur

- upstream-sync-merge.yml: Auto-merge on CI success
  - Uses workflow_run trigger on build-test-debug completion
  - Merges PR with rebase method
  - Cleans up upstream-sync branch after merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Codex
2025-12-23 06:10:46 +01:00
parent f3d79333a0
commit 8a48801421
2 changed files with 157 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
name: Upstream Sync Auto-Merge
on:
workflow_run:
workflows: ["Build & Test"]
types: [completed]
branches: [upstream-sync]
jobs:
auto-merge:
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion == 'success'
steps:
- name: Find and merge upstream-sync PR
uses: actions/github-script@v7
with:
script: |
// Find open PR from upstream-sync branch
const { data: prs } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
head: `${context.repo.owner}:upstream-sync`,
state: 'open'
});
if (prs.length === 0) {
console.log('No open upstream-sync PR found');
return;
}
const pr = prs[0];
console.log(`Found PR #${pr.number}: ${pr.title}`);
// Merge the PR using rebase
try {
await github.rest.pulls.merge({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
merge_method: 'rebase'
});
console.log(`Successfully merged PR #${pr.number}`);
} catch (error) {
console.log(`Failed to merge: ${error.message}`);
throw error;
}
// Delete the upstream-sync branch after merge
try {
await github.rest.git.deleteRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: 'heads/upstream-sync'
});
console.log('Deleted upstream-sync branch');
} catch (error) {
console.log(`Failed to delete branch: ${error.message}`);
}
+99
View File
@@ -0,0 +1,99 @@
name: Upstream Sync
on:
schedule:
- cron: '0 6 * * *' # Daily at 6am UTC
workflow_dispatch: # Manual trigger
jobs:
check-and-sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- 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: |
git remote add syndicate https://github.com/space-syndicate/space-station-14.git
git fetch syndicate master
- name: Check for upstream updates
id: check
run: |
BEHIND=$(git rev-list HEAD..syndicate/master --count)
echo "behind=$BEHIND" >> $GITHUB_OUTPUT
if [ "$BEHIND" -gt 0 ]; then
echo "Upstream has $BEHIND new commits"
echo "has_updates=true" >> $GITHUB_OUTPUT
else
echo "Already up to date"
echo "has_updates=false" >> $GITHUB_OUTPUT
fi
- name: Rebase onto upstream
if: steps.check.outputs.has_updates == 'true'
id: rebase
run: |
# Create sync branch
git checkout -b upstream-sync
# Try rebase
if git rebase syndicate/master; then
echo "rebase_success=true" >> $GITHUB_OUTPUT
git push -f origin upstream-sync
else
git rebase --abort
echo "rebase_success=false" >> $GITHUB_OUTPUT
fi
- name: Create PR for CI verification
if: steps.check.outputs.has_updates == 'true' && steps.rebase.outputs.rebase_success == 'true'
uses: actions/github-script@v7
with:
script: |
const behind = '${{ steps.check.outputs.behind }}';
// Check if PR already exists
const { data: prs } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
head: `${context.repo.owner}:upstream-sync`,
state: 'open'
});
if (prs.length > 0) {
console.log('PR already exists, skipping creation');
return;
}
// Create PR
await github.rest.pulls.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Upstream sync: ${behind} new commits from syndicate/master`,
head: 'upstream-sync',
base: 'master',
body: `Automatic rebase of wylab commits onto updated syndicate/master.\n\n**${behind} new upstream commits**\n\nThis PR will be auto-merged when CI passes.`
});
- name: Create issue on rebase conflict
if: steps.check.outputs.has_updates == 'true' && steps.rebase.outputs.rebase_success == 'false'
uses: actions/github-script@v7
with:
script: |
const behind = '${{ steps.check.outputs.behind }}';
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Upstream sync failed - ${behind} commits behind`,
body: `Automatic rebase onto syndicate/master failed due to conflicts.\n\nManual intervention required:\n\`\`\`bash\ngit fetch syndicate\ngit rebase syndicate/master\n# resolve conflicts\ngit push --force-with-lease origin master\n\`\`\``,
labels: ['upstream-sync', 'needs-attention']
});