fix: use bot token for issue creation and link PRs to tracking issues

Three fixes in the upstream-sync workflow:

1. Replace github.token with CLAUDE_BOT_TOKEN in the check-upstream
   job. The default runner token on Forgejo doesn't have issue-write
   permissions, so issues were silently failing to create.

2. Output the tracking issue number from check-upstream and pass it
   to the merge-upstream job. Claude's prompt now includes the issue
   reference and instructs it to add "Closes #N" in the PR body.

3. Capture the issue number from both create and update paths so
   the merge job always has it available.

Also cleaned up 6 duplicate upstream-sync labels created by previous
runs that used the unprivileged token.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Vlad MocanuandClaude Opus 4.6 committed 2026-02-27 13:12:35 +02:00
1 parent bc063f62f0
commit 88e7747d2f
2 files changed
+29 -14

No files matched your search

+15 -7
View File
@@ -232,6 +232,7 @@ _claude_action_url = h.gha_action_url("actions", "claude-code-action", versions.
_merge_branch_ref = h.gha_steps("prepare", "branch") _merge_branch_ref = h.gha_steps("prepare", "branch")
_merge_behind_ref = h.gha_needs("check-upstream", "behind") _merge_behind_ref = h.gha_needs("check-upstream", "behind")
_merge_ahead_ref = h.gha_needs("check-upstream", "ahead") _merge_ahead_ref = h.gha_needs("check-upstream", "ahead")
_merge_issue_ref = h.gha_needs("check-upstream", "issue_number")
_merge_clean_ref = h.gha_steps("prepare", "merge_clean") _merge_clean_ref = h.gha_steps("prepare", "merge_clean")
_merge_affected_ref = h.gha_steps("prepare", "affected_files") _merge_affected_ref = h.gha_steps("prepare", "affected_files")
@@ -241,6 +242,7 @@ You are automating an upstream sync for our Forgejo fork of anthropics/claude-co
## Current state ## Current state
- Branch: ${_merge_branch_ref} - Branch: ${_merge_branch_ref}
- ${_merge_behind_ref} commits behind upstream, ${_merge_ahead_ref} commits ahead (our Forgejo changes) - ${_merge_behind_ref} commits behind upstream, ${_merge_ahead_ref} commits ahead (our Forgejo changes)
- Tracking issue: #${_merge_issue_ref}
- Merge was attempted. Status: ${_merge_clean_ref} (true = clean, false = has conflicts) - Merge was attempted. Status: ${_merge_clean_ref} (true = clean, false = has conflicts)
## Impact analysis ## Impact analysis
@@ -276,6 +278,7 @@ The fewer upstream files we modify, the fewer conflicts in the next sync.
Auth: token ${"$"}GITHUB_TOKEN Auth: token ${"$"}GITHUB_TOKEN
Title: "chore: merge ${_merge_behind_ref} upstream commits from anthropics/claude-code-action" Title: "chore: merge ${_merge_behind_ref} upstream commits from anthropics/claude-code-action"
Body should include: Body should include:
- "Closes #${_merge_issue_ref}" on its own line (links PR to the tracking issue)
- Summary of notable upstream changes - Summary of notable upstream changes
- Impact assessment: which fork files (if any) were affected - Impact assessment: which fork files (if any) were affected
- List of conflicts resolved (if any) - List of conflicts resolved (if any)
@@ -301,6 +304,7 @@ _upstream_sync_workflow = {
needs_sync = h.gha_steps("compare", "needs_sync") needs_sync = h.gha_steps("compare", "needs_sync")
behind = h.gha_steps("compare", "behind") behind = h.gha_steps("compare", "behind")
ahead = h.gha_steps("compare", "ahead") ahead = h.gha_steps("compare", "ahead")
issue_number = h.gha_steps("sync-issue", "issue_number")
} }
steps = [ steps = [
checkout_mod.checkout() | {"with" = {"fetch-depth" = "0"}} checkout_mod.checkout() | {"with" = {"fetch-depth" = "0"}}
@@ -360,7 +364,7 @@ fi"""
id = "existing" id = "existing"
run = """\ run = """\
RESPONSE=${"$"}(curl -s \\ RESPONSE=${"$"}(curl -s \\
-H "Authorization: token ${h.gha_github("token")}" \\ -H "Authorization: token ${h.gha_secret("CLAUDE_BOT_TOKEN")}" \\
-H "Content-Type: application/json" \\ -H "Content-Type: application/json" \\
"${h.gha_env("GITHUB_API_URL")}/repos/${h.gha_github("repository")}/issues?state=open&labels=upstream-sync&limit=1") "${h.gha_env("GITHUB_API_URL")}/repos/${h.gha_github("repository")}/issues?state=open&labels=upstream-sync&limit=1")
@@ -382,7 +386,7 @@ fi"""
run = """\ run = """\
curl -s -o /dev/null -w "%{http_code}" \\ curl -s -o /dev/null -w "%{http_code}" \\
-X POST \\ -X POST \\
-H "Authorization: token ${h.gha_github("token")}" \\ -H "Authorization: token ${h.gha_secret("CLAUDE_BOT_TOKEN")}" \\
-H "Content-Type: application/json" \\ -H "Content-Type: application/json" \\
-d '{"name":"upstream-sync","color":"#0075ca","description":"Upstream sync tracking"}' \\ -d '{"name":"upstream-sync","color":"#0075ca","description":"Upstream sync tracking"}' \\
"${h.gha_env("GITHUB_API_URL")}/repos/${h.gha_github("repository")}/labels" || true""" "${h.gha_env("GITHUB_API_URL")}/repos/${h.gha_github("repository")}/labels" || true"""
@@ -390,6 +394,7 @@ curl -s -o /dev/null -w "%{http_code}" \\
{ {
name = "Create or update sync issue" name = "Create or update sync issue"
"if" = h.gha_steps_eq("compare", "needs_sync", "true") "if" = h.gha_steps_eq("compare", "needs_sync", "true")
id = "sync-issue"
run = """\ run = """\
BEHIND="${h.gha_steps("compare", "behind")}" BEHIND="${h.gha_steps("compare", "behind")}"
AHEAD="${h.gha_steps("compare", "ahead")}" AHEAD="${h.gha_steps("compare", "ahead")}"
@@ -448,19 +453,22 @@ if [ "${h.gha_steps("existing", "issue_exists")}" = "true" ]; then
ISSUE_NUMBER="${h.gha_steps("existing", "issue_number")}" ISSUE_NUMBER="${h.gha_steps("existing", "issue_number")}"
curl -s -o /dev/null \\ curl -s -o /dev/null \\
-X PATCH \\ -X PATCH \\
-H "Authorization: token ${h.gha_github("token")}" \\ -H "Authorization: token ${h.gha_secret("CLAUDE_BOT_TOKEN")}" \\
-H "Content-Type: application/json" \\ -H "Content-Type: application/json" \\
-d "${"$"}(jq -n --arg title "${"$"}TITLE" --arg body "${"$"}BODY" '{title: ${"$"}title, body: ${"$"}body}')" \\ -d "${"$"}(jq -n --arg title "${"$"}TITLE" --arg body "${"$"}BODY" '{title: ${"$"}title, body: ${"$"}body}')" \\
"${h.gha_env("GITHUB_API_URL")}/repos/${h.gha_github("repository")}/issues/${"$"}{ISSUE_NUMBER}" "${h.gha_env("GITHUB_API_URL")}/repos/${h.gha_github("repository")}/issues/${"$"}{ISSUE_NUMBER}"
echo "Updated existing issue #${"$"}{ISSUE_NUMBER}" echo "Updated existing issue #${"$"}{ISSUE_NUMBER}"
echo "issue_number=${"$"}{ISSUE_NUMBER}" >> "${"$"}GITHUB_OUTPUT"
else else
curl -s -o /dev/null \\ RESPONSE=${"$"}(curl -s \\
-X POST \\ -X POST \\
-H "Authorization: token ${h.gha_github("token")}" \\ -H "Authorization: token ${h.gha_secret("CLAUDE_BOT_TOKEN")}" \\
-H "Content-Type: application/json" \\ -H "Content-Type: application/json" \\
-d "${"$"}(jq -n --arg title "${"$"}TITLE" --arg body "${"$"}BODY" '{title: ${"$"}title, body: ${"$"}body, labels: [{"name": "upstream-sync"}]}')" \\ -d "${"$"}(jq -n --arg title "${"$"}TITLE" --arg body "${"$"}BODY" '{title: ${"$"}title, body: ${"$"}body, labels: [{"name": "upstream-sync"}]}')" \\
"${h.gha_env("GITHUB_API_URL")}/repos/${h.gha_github("repository")}/issues" "${h.gha_env("GITHUB_API_URL")}/repos/${h.gha_github("repository")}/issues")
echo "Created new upstream sync issue" ISSUE_NUMBER=${"$"}(echo "${"$"}RESPONSE" | jq '.number')
echo "Created new upstream sync issue #${"$"}{ISSUE_NUMBER}"
echo "issue_number=${"$"}{ISSUE_NUMBER}" >> "${"$"}GITHUB_OUTPUT"
fi""" fi"""
} }
] ]
+14 -7
View File
@@ -18,6 +18,7 @@ jobs:
needs_sync: ${{ steps.compare.outputs.needs_sync }} needs_sync: ${{ steps.compare.outputs.needs_sync }}
behind: ${{ steps.compare.outputs.behind }} behind: ${{ steps.compare.outputs.behind }}
ahead: ${{ steps.compare.outputs.ahead }} ahead: ${{ steps.compare.outputs.ahead }}
issue_number: ${{ steps.sync-issue.outputs.issue_number }}
steps: steps:
- name: Checkout - name: Checkout
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/xternal/checkout@v6.0.2 uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/xternal/checkout@v6.0.2
@@ -72,7 +73,7 @@ jobs:
id: existing id: existing
run: |- run: |-
RESPONSE=$(curl -s \ RESPONSE=$(curl -s \
-H "Authorization: token ${{ github.token }}" \ -H "Authorization: token ${{ secrets.CLAUDE_BOT_TOKEN }}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
"${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}/issues?state=open&labels=upstream-sync&limit=1") "${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}/issues?state=open&labels=upstream-sync&limit=1")
@@ -92,12 +93,13 @@ jobs:
run: |- run: |-
curl -s -o /dev/null -w "%{http_code}" \ curl -s -o /dev/null -w "%{http_code}" \
-X POST \ -X POST \
-H "Authorization: token ${{ github.token }}" \ -H "Authorization: token ${{ secrets.CLAUDE_BOT_TOKEN }}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"name":"upstream-sync","color":"#0075ca","description":"Upstream sync tracking"}' \ -d '{"name":"upstream-sync","color":"#0075ca","description":"Upstream sync tracking"}' \
"${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}/labels" || true "${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}/labels" || true
- name: Create or update sync issue - name: Create or update sync issue
if: steps.compare.outputs.needs_sync == 'true' if: steps.compare.outputs.needs_sync == 'true'
id: sync-issue
run: |- run: |-
BEHIND="${{ steps.compare.outputs.behind }}" BEHIND="${{ steps.compare.outputs.behind }}"
AHEAD="${{ steps.compare.outputs.ahead }}" AHEAD="${{ steps.compare.outputs.ahead }}"
@@ -156,19 +158,22 @@ jobs:
ISSUE_NUMBER="${{ steps.existing.outputs.issue_number }}" ISSUE_NUMBER="${{ steps.existing.outputs.issue_number }}"
curl -s -o /dev/null \ curl -s -o /dev/null \
-X PATCH \ -X PATCH \
-H "Authorization: token ${{ github.token }}" \ -H "Authorization: token ${{ secrets.CLAUDE_BOT_TOKEN }}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d "$(jq -n --arg title "$TITLE" --arg body "$BODY" '{title: $title, body: $body}')" \ -d "$(jq -n --arg title "$TITLE" --arg body "$BODY" '{title: $title, body: $body}')" \
"${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}/issues/${ISSUE_NUMBER}" "${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}/issues/${ISSUE_NUMBER}"
echo "Updated existing issue #${ISSUE_NUMBER}" echo "Updated existing issue #${ISSUE_NUMBER}"
echo "issue_number=${ISSUE_NUMBER}" >> "$GITHUB_OUTPUT"
else else
curl -s -o /dev/null \ RESPONSE=$(curl -s \
-X POST \ -X POST \
-H "Authorization: token ${{ github.token }}" \ -H "Authorization: token ${{ secrets.CLAUDE_BOT_TOKEN }}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d "$(jq -n --arg title "$TITLE" --arg body "$BODY" '{title: $title, body: $body, labels: [{"name": "upstream-sync"}]}')" \ -d "$(jq -n --arg title "$TITLE" --arg body "$BODY" '{title: $title, body: $body, labels: [{"name": "upstream-sync"}]}')" \
"${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}/issues" "${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}/issues")
echo "Created new upstream sync issue" ISSUE_NUMBER=$(echo "$RESPONSE" | jq '.number')
echo "Created new upstream sync issue #${ISSUE_NUMBER}"
echo "issue_number=${ISSUE_NUMBER}" >> "$GITHUB_OUTPUT"
fi fi
merge-upstream: merge-upstream:
name: Auto-merge Upstream name: Auto-merge Upstream
@@ -258,6 +263,7 @@ jobs:
## Current state ## Current state
- Branch: ${{ steps.prepare.outputs.branch }} - Branch: ${{ steps.prepare.outputs.branch }}
- ${{ needs.check-upstream.outputs.behind }} commits behind upstream, ${{ needs.check-upstream.outputs.ahead }} commits ahead (our Forgejo changes) - ${{ 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 }}
- Merge was attempted. Status: ${{ steps.prepare.outputs.merge_clean }} (true = clean, false = has conflicts) - Merge was attempted. Status: ${{ steps.prepare.outputs.merge_clean }} (true = clean, false = has conflicts)
## Impact analysis ## Impact analysis
@@ -293,6 +299,7 @@ jobs:
Auth: token $GITHUB_TOKEN Auth: token $GITHUB_TOKEN
Title: "chore: merge ${{ needs.check-upstream.outputs.behind }} upstream commits from anthropics/claude-code-action" Title: "chore: merge ${{ needs.check-upstream.outputs.behind }} upstream commits from anthropics/claude-code-action"
Body should include: Body should include:
- "Closes #${{ needs.check-upstream.outputs.issue_number }}" on its own line (links PR to the tracking issue)
- Summary of notable upstream changes - Summary of notable upstream changes
- Impact assessment: which fork files (if any) were affected - Impact assessment: which fork files (if any) were affected
- List of conflicts resolved (if any) - List of conflicts resolved (if any)