Skip to content
Open
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
111 changes: 111 additions & 0 deletions .github/workflows/sync-upstream.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
name: Sync upstream (anomalyco/opencode)

# Periodically catches this fork's `dev` branch up with anomalyco/opencode's
# `dev` branch and opens a PR for review. Never auto-merges: every run lands
# as a PR, whether the merge was clean or hit conflicts (conflict markers are
# committed as-is so a human can resolve them on the branch).

on:
schedule:
- cron: "0 6 * * 1" # every Monday 06:00 UTC
workflow_dispatch: {}

permissions:
contents: write
pull-requests: write

concurrency:
group: sync-upstream
cancel-in-progress: false

jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Checkout dev
uses: actions/checkout@v4
with:
ref: dev
fetch-depth: 0

- name: Configure git identity
run: |
git config user.name "lemoncode-bot"
git config user.email "<redacted-email>"

- name: Ensure upstream-sync label exists
env:
GH_TOKEN: ${{ github.token }}
run: |
gh label create upstream-sync --repo "$GITHUB_REPOSITORY" \
--color 5319e7 --description "Automated sync from anomalyco/opencode" 2>/dev/null || true

- name: Skip if a sync PR is already open
id: guard
env:
GH_TOKEN: ${{ github.token }}
run: |
existing=$(gh pr list --repo "$GITHUB_REPOSITORY" --state open --label upstream-sync --json number --jq 'length')
if [ "$existing" -gt 0 ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "::notice::An upstream-sync PR is already open — skipping this run."
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi

- name: Fetch upstream
if: steps.guard.outputs.skip == 'false'
run: |
git remote add upstream https://github.com/anomalyco/opencode.git
git fetch upstream dev

- name: Check for new upstream commits
if: steps.guard.outputs.skip == 'false'
id: diff
run: |
count=$(git rev-list --count dev..upstream/dev)
echo "count=$count" >> "$GITHUB_OUTPUT"
echo "$count new commit(s) on upstream/dev"

- name: Merge upstream into a sync branch
if: steps.guard.outputs.skip == 'false' && steps.diff.outputs.count != '0'
id: merge
run: |
branch="chore/sync-upstream-$(date -u +%Y%m%d)"
git checkout -b "$branch"
if git merge upstream/dev --no-edit; then
echo "conflicted=false" >> "$GITHUB_OUTPUT"
else
echo "conflicted=true" >> "$GITHUB_OUTPUT"
git diff --name-only --diff-filter=U > /tmp/conflicts.txt
git add -A
git commit -m "merge upstream/dev into $branch (unresolved conflicts, needs manual resolution)"
fi
echo "branch=$branch" >> "$GITHUB_OUTPUT"
git push -u origin "$branch"

- name: Open PR
if: steps.guard.outputs.skip == 'false' && steps.diff.outputs.count != '0'
env:
GH_TOKEN: ${{ github.token }}
run: |
count="${{ steps.diff.outputs.count }}"
branch="${{ steps.merge.outputs.branch }}"
if [ "${{ steps.merge.outputs.conflicted }}" = "true" ]; then
title="chore: sync upstream/dev — CONFLICTS need resolution"
{
echo "Automated weekly sync of \`upstream/dev\` (anomalyco/opencode), ${count} new commit(s)."
echo
echo "This merge hit conflicts. Conflict markers were committed as-is on \`${branch}\` — check out the branch, resolve, and push fixes to this PR."
echo
echo "Conflicted files:"
echo '```'
cat /tmp/conflicts.txt
echo '```'
} > /tmp/pr-body.md
else
title="chore: sync upstream/dev (${count} commits)"
echo "Automated weekly sync of \`upstream/dev\` (anomalyco/opencode), ${count} new commit(s). Merged cleanly — please review before merging." > /tmp/pr-body.md
fi
gh pr create --repo "$GITHUB_REPOSITORY" --base dev --head "$branch" \
--title "$title" --body-file /tmp/pr-body.md --label upstream-sync