فهرست منبع

fix(ci): keep a refused Claude credential from reddening a pull request (#6585)

* fix(ci): keep a refused Claude credential from reddening a PR

An expired subscription ends the claude-code-action step with exit 0, so the
classifier that exists for "the API refused this run" never sees it -- its
condition is a failed step -- and the final "posted nothing" step reddens the
pull request although nothing is wrong with the repository.

Verified against five real runs (35159059540, 35184688775, 35185722358,
35186543654, 35187380192): step 8 success, step 10 found no cause, step 11
failure, transcript {"error":"oauth_org_not_allowed"} plus a result entry with
api_error_status 403. A usage-limited run carries 429 and a rejected
rate_limit_event, and a real review carries is_error false with no status, so
the 401/403 test fires on the refused credential alone.

* fix(ci): stop a refused credential reddening the issue analysis

The same exit-0 refusal reaches this workflow's "posted no reply" check, which
fails for the same reason and shows up as seven failed runs in a day. It never
attaches to a pull request -- the trigger excludes them -- so this is the same
step and the same 401/403 transcript test applied where the refusal lands.

Reported only as a warning annotation: nothing was analysed, and there is no
comment worth posting about a credential the maintainer has to renew.
BlindMaster24 11 ساعت پیش
والد
کامیت
1c0ce80e8e
2فایلهای تغییر یافته به همراه33 افزوده شده و 2 حذف شده
  1. 17 1
      .github/workflows/claude-issue-analyst.yml
  2. 16 1
      .github/workflows/claude-pr-review.yml

+ 17 - 1
.github/workflows/claude-issue-analyst.yml

@@ -437,8 +437,24 @@ jobs:
           path: ${{ runner.temp }}/claude-execution-output.json
           if-no-files-found: ignore
           retention-days: 7
-      - name: Fail if the analysis posted no reply
+      # A refused credential ends the action with exit 0, so the step below cannot
+      # tell it from a reply that landed: the transcript is the only place it appears.
+      - name: Report an analysis the credential refused
+        id: refused
         if: ${{ !cancelled() }}
+        env:
+          TRANSCRIPT: ${{ runner.temp }}/claude-execution-output.json
+          ISSUE: ${{ github.event.issue.number }}
+        run: |
+          set -euo pipefail
+          [ -f "$TRANSCRIPT" ] || exit 0
+          jq -e 'any(.[]; .type == "result" and ((.api_error_status // 0) == 401 or (.api_error_status // 0) == 403))' "$TRANSCRIPT" >/dev/null 2>&1 \
+            || jq -e 'any(.[]; ((.error // "") | test("^(oauth_|authentication_|invalid_api_key)")))' "$TRANSCRIPT" >/dev/null 2>&1 \
+            || exit 0
+          echo "skipped=true" >> "$GITHUB_OUTPUT"
+          echo "::warning::No analysis of #${ISSUE}: the Claude credential was refused, so this issue was not examined."
+      - name: Fail if the analysis posted no reply
+        if: ${{ !cancelled() && steps.refused.outputs.skipped != 'true' }}
         env:
           GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           REPO: ${{ github.repository }}

+ 16 - 1
.github/workflows/claude-pr-review.yml

@@ -228,10 +228,25 @@ jobs:
           echo "skipped=true" >> "$GITHUB_OUTPUT"
           echo "::notice::No review of #${PR}: ${reason}."
           gh pr comment "$PR" --repo "$REPO" --body "No review ran on this head: ${reason}. Nothing in this pull request was examined. A maintainer can ask for one with \`@claude review\`."
+      # A refused credential ends the action with exit 0, so the step above never
+      # sees it: the transcript is the only place that refusal appears.
+      - name: Report a review the credential refused
+        id: refused
+        if: ${{ !cancelled() }}
+        env:
+          TRANSCRIPT: ${{ runner.temp }}/claude-execution-output.json
+        run: |
+          set -euo pipefail
+          [ -f "$TRANSCRIPT" ] || exit 0
+          jq -e 'any(.[]; .type == "result" and ((.api_error_status // 0) == 401 or (.api_error_status // 0) == 403))' "$TRANSCRIPT" >/dev/null 2>&1 \
+            || jq -e 'any(.[]; ((.error // "") | test("^(oauth_|authentication_|invalid_api_key)")))' "$TRANSCRIPT" >/dev/null 2>&1 \
+            || exit 0
+          echo "skipped=true" >> "$GITHUB_OUTPUT"
+          echo "::warning::No review of #${PR}: the Claude credential was refused, so nothing in this pull request was examined."
       # updated_at, not created_at: a re-review may edit its earlier comment.
       # --paginate prints one jq count per page, so the pages are summed.
       - name: Fail if the review posted nothing
-        if: ${{ !cancelled() && steps.pinned-sha.outcome == 'success' && steps.reviewed.outputs.done != 'true' && steps.throttled.outputs.skipped != 'true' }}
+        if: ${{ !cancelled() && steps.pinned-sha.outcome == 'success' && steps.reviewed.outputs.done != 'true' && steps.throttled.outputs.skipped != 'true' && steps.refused.outputs.skipped != 'true' }}
         env:
           HEAD_SHA: ${{ steps.pinned-sha.outputs.sha }}
           STARTED_AT: ${{ steps.started.outputs.at }}