fix: handle existing sync PRs in upstream-sync workflow
Add idempotency to the merge-upstream job: 1. Check for existing open PR from chore/upstream-sync-* branch 2. If PR exists and branch is up to date with upstream → skip 3. If PR exists but upstream has new commits → checkout existing branch, merge new upstream commits, run Claude to review/test 4. If no PR exists → create new branch (existing behavior) Also update Claude's prompt to handle both create and update PR cases, so it knows to push to the existing PR branch instead of creating a duplicate. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
88e7747d2f
commit
b1524d7857
2 files changed
+108
-14
No files matched your search
@@ -187,6 +187,27 @@ jobs:
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
token: ${{ secrets.CLAUDE_BOT_TOKEN }}
|
||||
- name: Check for existing sync PR
|
||||
id: existing-pr
|
||||
run: |-
|
||||
# Search for open PRs from chore/upstream-sync-* branches
|
||||
RESPONSE=$(curl -s \
|
||||
-H "Authorization: token ${{ secrets.CLAUDE_BOT_TOKEN }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}/pulls?state=open&limit=50")
|
||||
|
||||
PR_BRANCH=$(echo "$RESPONSE" | jq -r '[.[] | select(.head.ref | startswith("chore/upstream-sync-"))] | .[0].head.ref // ""')
|
||||
|
||||
if [ -n "$PR_BRANCH" ]; then
|
||||
PR_NUMBER=$(echo "$RESPONSE" | jq -r '[.[] | select(.head.ref | startswith("chore/upstream-sync-"))] | .[0].number')
|
||||
echo "Found existing sync PR #$PR_NUMBER on branch $PR_BRANCH"
|
||||
echo "pr_exists=true" >> "$GITHUB_OUTPUT"
|
||||
echo "pr_branch=$PR_BRANCH" >> "$GITHUB_OUTPUT"
|
||||
echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "No existing sync PR found"
|
||||
echo "pr_exists=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
- name: Prepare upstream merge
|
||||
id: prepare
|
||||
run: |-
|
||||
@@ -196,6 +217,29 @@ jobs:
|
||||
git remote add upstream https://github.com/anthropics/claude-code-action.git
|
||||
git fetch upstream main --quiet
|
||||
|
||||
# Check if existing PR branch is already up to date with upstream
|
||||
if [ "${{ steps.existing-pr.outputs.pr_exists }}" = "true" ]; then
|
||||
PR_BRANCH="${{ steps.existing-pr.outputs.pr_branch }}"
|
||||
git checkout "$PR_BRANCH"
|
||||
|
||||
# Check if upstream/main is already merged into the PR branch
|
||||
BEHIND=$(git rev-list "$PR_BRANCH"..upstream/main --count)
|
||||
if [ "$BEHIND" -eq 0 ]; then
|
||||
echo "Existing PR branch $PR_BRANCH is already up to date with upstream"
|
||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Existing PR branch $PR_BRANCH is $BEHIND commits behind upstream — updating"
|
||||
BRANCH="$PR_BRANCH"
|
||||
else
|
||||
BRANCH="chore/upstream-sync-$(date +%Y%m%d)"
|
||||
git checkout -b "$BRANCH"
|
||||
fi
|
||||
|
||||
echo "skip=false" >> "$GITHUB_OUTPUT"
|
||||
echo "branch=$BRANCH" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Files our fork has modified vs upstream
|
||||
FORK_FILES=$(git log upstream/main..main --name-only --pretty=format: | sort -u | grep -v '^$')
|
||||
echo "=== Fork-modified files ==="
|
||||
@@ -226,10 +270,6 @@ jobs:
|
||||
echo "${AFFECTED:-(none)}" >> "$GITHUB_OUTPUT"
|
||||
echo "EOF" >> "$GITHUB_OUTPUT"
|
||||
|
||||
BRANCH="chore/upstream-sync-$(date +%Y%m%d)"
|
||||
git checkout -b "$BRANCH"
|
||||
echo "branch=$BRANCH" >> "$GITHUB_OUTPUT"
|
||||
|
||||
if git merge upstream/main --no-edit; then
|
||||
echo "merge_clean=true" >> "$GITHUB_OUTPUT"
|
||||
echo "Merge completed cleanly"
|
||||
@@ -252,9 +292,12 @@ jobs:
|
||||
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
|
||||
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
|
||||
fi
|
||||
if: steps.prepare.outputs.skip != 'true'
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
if: steps.prepare.outputs.skip != 'true'
|
||||
- name: 'Claude: review merge and create PR'
|
||||
if: steps.prepare.outputs.skip != 'true'
|
||||
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/actions/claude-code-action@main
|
||||
with:
|
||||
prompt: |-
|
||||
@@ -264,6 +307,7 @@ jobs:
|
||||
- Branch: ${{ steps.prepare.outputs.branch }}
|
||||
- ${{ needs.check-upstream.outputs.behind }} commits behind upstream, ${{ needs.check-upstream.outputs.ahead }} commits ahead (our Forgejo changes)
|
||||
- Tracking issue: #${{ needs.check-upstream.outputs.issue_number }}
|
||||
- Existing PR: ${{ steps.existing-pr.outputs.pr_exists }} (if true, PR #${{ steps.existing-pr.outputs.pr_number }} already exists — update it instead of creating a new one)
|
||||
- Merge was attempted. Status: ${{ steps.prepare.outputs.merge_clean }} (true = clean, false = has conflicts)
|
||||
|
||||
## Impact analysis
|
||||
@@ -294,8 +338,10 @@ jobs:
|
||||
2. Run typecheck: bun run typecheck
|
||||
3. Check formatting: bun run format:check — if issues, fix with bun run format
|
||||
4. Commit any remaining changes and push the branch
|
||||
5. Create a PR targeting main via the Forgejo API:
|
||||
POST $GITHUB_API_URL/repos/$GITHUB_REPOSITORY/pulls
|
||||
5. Push the branch, then create or update the PR:
|
||||
- If existing PR is "true": PR #${{ steps.existing-pr.outputs.pr_number }} already exists. Just push the branch — the PR updates automatically.
|
||||
Optionally update the PR body via PATCH $GITHUB_API_URL/repos/$GITHUB_REPOSITORY/pulls/${{ steps.existing-pr.outputs.pr_number }}
|
||||
- If existing PR is "false": Create a new PR via POST $GITHUB_API_URL/repos/$GITHUB_REPOSITORY/pulls
|
||||
Auth: token $GITHUB_TOKEN
|
||||
Title: "chore: merge ${{ needs.check-upstream.outputs.behind }} upstream commits from anthropics/claude-code-action"
|
||||
Body should include:
|
||||
|
||||
Reference in new issue
Block a user