From 02753c69b2e5be68b6b829e4d32b605c9d2689cc Mon Sep 17 00:00:00 2001 From: satendra-sr Date: Mon, 29 Jun 2026 13:18:18 +0530 Subject: [PATCH] fix(code-review): post review comment deterministically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In agent mode (the auto-detected mode for label-triggered reviews), claude-code-action does not manage a PR comment. Whether a review comment appeared therefore depended on Claude voluntarily running `gh pr comment` as its final step. Most runs did; some did not — those only wrote the review to the Actions step summary and left the PR with no comment (observed on dost-ai-voicebot #21). Make posting deterministic: - Reframe the prompt so Claude returns the review as its final message rather than instructing it to post a comment itself. - Drop `gh pr comment` from the model's allowed-tools (prevents a duplicate comment now that the workflow posts). - Add a "Post review comment" step that reads the action's execution_file output, extracts the final result, and publishes it as one PR comment using the action's github_token (keeps claude[bot] authorship). Honors use_sticky_comment by updating the same comment on re-runs. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/claude-code-review.yml | 52 ++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 16cfd57..98c274e 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -30,7 +30,9 @@ on: - If you see issues that should be separate PRs, note them briefly at the end 3. **Review Output Format - IMPORTANT** - Create ONE single comment with your complete review using this structure: + Provide your complete review as your FINAL message using this structure. + Do NOT post a PR comment yourself and do NOT create inline comments — the + workflow publishes your final message to the PR automatically as one comment. ## Code Review Summary @@ -46,8 +48,6 @@ on: ### What Looks Good - Brief positive notes - Do NOT create multiple inline comments. Put everything in ONE comment. - 4. **Focus Areas** (priority order) - Security vulnerabilities - Bugs and logic errors @@ -145,4 +145,48 @@ jobs: # DISABLED: See comment above in inputs section for details claude_args: | --model ${{ inputs.model || 'claude-sonnet-4-5-20250929' }} - --allowed-tools "${{ steps.sanitize.outputs.allowed_tools != '' && steps.sanitize.outputs.allowed_tools || 'Read,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)' }}" \ No newline at end of file + --allowed-tools "${{ steps.sanitize.outputs.allowed_tools != '' && steps.sanitize.outputs.allowed_tools || 'Read,Bash(gh pr diff:*),Bash(gh pr view:*)' }}" + + # Post the review deterministically. In agent mode the action does NOT manage a + # PR comment, so previously whether a comment appeared depended on Claude choosing + # to run `gh pr comment` itself — non-deterministic, and some runs only wrote the + # review to the Actions step summary. This step always publishes Claude's final + # message as a single PR comment (sticky: updates the same comment on re-runs). + - name: Post review comment + if: ${{ always() && steps.claude-review.outputs.execution_file != '' && github.event.pull_request.number }} + env: + GH_TOKEN: ${{ steps.claude-review.outputs.github_token || github.token }} + REPO: ${{ github.repository }} + PR: ${{ github.event.pull_request.number }} + EXECUTION_FILE: ${{ steps.claude-review.outputs.execution_file }} + STICKY: ${{ inputs.use_sticky_comment }} + MARKER: '' + run: | + set -euo pipefail + + # Extract Claude's final message from the execution log. The file is + # stream-json (JSONL); slurp + flatten also tolerates a JSON-array form. + review="$(jq -rs 'flatten | map(select(type == "object" and .type == "result")) | last | .result // empty' "$EXECUTION_FILE")" + + if [ -z "$review" ] || [ "$review" = "null" ]; then + echo "No review text found in execution output; nothing to post." + exit 0 + fi + + body_file="$(mktemp)" + printf '%s\n\n%s\n' "$MARKER" "$review" > "$body_file" + + # Sticky: reuse the existing review comment if one exists. + existing_id="" + if [ "$STICKY" = "true" ]; then + existing_id="$(gh api --paginate "repos/$REPO/issues/$PR/comments" \ + --jq ".[] | select(.body | startswith(\"$MARKER\")) | .id" | tail -n1)" + fi + + if [ -n "$existing_id" ]; then + echo "Updating existing review comment $existing_id" + gh api -X PATCH "repos/$REPO/issues/comments/$existing_id" -F body=@"$body_file" >/dev/null + else + echo "Creating new review comment" + gh pr comment "$PR" --repo "$REPO" --body-file "$body_file" + fi \ No newline at end of file