From ea46407ff6633cdad6a491598eccc0e4a0734533 Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:56:21 -0500 Subject: [PATCH 01/20] Create claude-review.yml --- .github/workflows/claude-review.yml | 144 ++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 .github/workflows/claude-review.yml diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml new file mode 100644 index 0000000..fc2355d --- /dev/null +++ b/.github/workflows/claude-review.yml @@ -0,0 +1,144 @@ +name: Claude Code Review + +permissions: + contents: read + pull-requests: write + +on: + pull_request: + types: [opened, reopened, synchronize] + workflow_dispatch: + inputs: + pr_number: + description: 'Pull Request Number' + required: true + type: string + +jobs: + code-review: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get PR number + id: pr-number + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "number=${{ inputs.pr_number }}" >> $GITHUB_OUTPUT + else + echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT + fi + + - name: Get PR details + if: github.event_name == 'workflow_dispatch' + id: pr-details + uses: actions/github-script@v7 + with: + script: | + const pr = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.name, + pull_number: ${{ inputs.pr_number }} + }); + console.log(`Base SHA: ${pr.data.base.sha}`); + console.log(`Head SHA: ${pr.data.head.sha}`); + return { + base_sha: pr.data.base.sha, + head_sha: pr.data.head.sha + } + + - name: Get changed files + id: changed-files + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + BASE_SHA=${{ fromJSON(steps.pr-details.outputs.result).base_sha }} + HEAD_SHA=${{ fromJSON(steps.pr-details.outputs.result).head_sha }} + else + BASE_SHA=${{ github.event.pull_request.base.sha }} + HEAD_SHA=${{ github.event.pull_request.head.sha }} + fi + + # Get the diff and save to a file + git diff $BASE_SHA..$HEAD_SHA > changes.diff + + # Create a filtered version without ignored files + cat changes.diff | grep -v -E '(package-lock.json|yarn.lock|node_modules|\.md$|\.json$)' | grep -E '\.(js|ts|py|cpp|h|java|cs)$' > filtered_changes.diff + + # Store the size of the diff + echo "diff_size=$(stat -f%z filtered_changes.diff)" >> $GITHUB_OUTPUT + + - name: Analyze code with Claude + if: steps.changed-files.outputs.diff_size != '0' + id: analysis + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + run: | + DIFF_CONTENT=$(cat filtered_changes.diff) + + # Prepare the API request + PROMPT="You are performing a code review. Please analyze this code diff and provide a thorough review that covers: + + 1. Potential conflicts with existing codebase + 2. Code correctness and potential bugs + 3. Security vulnerabilities or risks + 4. Performance implications + 5. Maintainability and readability issues + 6. Adherence to best practices and coding standards + 7. Suggestions for improvements + + For each issue found: + - Explain the problem clearly + - Rate the severity (Critical/High/Medium/Low) + - Provide specific recommendations for fixes + - Include code examples where helpful + + If no issues are found in a particular area, explicitly state that. + + Here is the code diff to review: + + \`\`\` + $DIFF_CONTENT + \`\`\`" + + # Make the API request + RESPONSE=$(curl -s https://api.anthropic.com/v1/messages \ + -H "Content-Type: application/json" \ + -H "x-api-key: $ANTHROPIC_API_KEY" \ + -H "anthropic-version: 2023-06-01" \ + -d "{ + \"model\": \"claude-3-sonnet-20240229\", + \"max_tokens\": 4096, + \"temperature\": 0.7, + \"messages\": [{ + \"role\": \"user\", + \"content\": \"$PROMPT\" + }] + }") + + # Extract the review content from the response + REVIEW=$(echo $RESPONSE | jq -r '.content[0].text') + + # Escape the review content for GitHub Actions + REVIEW="${REVIEW//'%'/'%25'}" + REVIEW="${REVIEW//$'\n'/'%0A'}" + REVIEW="${REVIEW//$'\r'/'%0D'}" + + # Save the review to the output + echo "review=$REVIEW" >> $GITHUB_OUTPUT + + - name: Post review comment + if: steps.changed-files.outputs.diff_size != '0' + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const review = `${{ steps.analysis.outputs.review }}`; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.name, + issue_number: ${{ steps.pr-number.outputs.number }}, + body: `# Claude Code Review\n\n${review}` + }); From e2733bcfaa14d240ad88382234feb6c331150889 Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:00:36 -0500 Subject: [PATCH 02/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 76 ++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index fc2355d..5c5d51a 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -37,16 +37,23 @@ jobs: uses: actions/github-script@v7 with: script: | - const pr = await github.rest.pulls.get({ - owner: context.repo.owner, - repo: context.repo.name, - pull_number: ${{ inputs.pr_number }} - }); - console.log(`Base SHA: ${pr.data.base.sha}`); - console.log(`Head SHA: ${pr.data.head.sha}`); - return { - base_sha: pr.data.base.sha, - head_sha: pr.data.head.sha + try { + const { owner, repo } = context.repo; + console.log(`Getting PR #${{ inputs.pr_number }} from ${owner}/${repo}`); + + const pr = await github.rest.pulls.get({ + owner: owner, + repo: repo, + pull_number: parseInt(${{ inputs.pr_number }}) + }); + + return { + base_sha: pr.data.base.sha, + head_sha: pr.data.head.sha + }; + } catch (error) { + core.setFailed(`Failed to get PR details: ${error.message}`); + throw error; } - name: Get changed files @@ -60,14 +67,21 @@ jobs: HEAD_SHA=${{ github.event.pull_request.head.sha }} fi + echo "Base SHA: $BASE_SHA" + echo "Head SHA: $HEAD_SHA" + # Get the diff and save to a file - git diff $BASE_SHA..$HEAD_SHA > changes.diff + git diff $BASE_SHA..$HEAD_SHA > changes.diff || echo "Failed to get diff" # Create a filtered version without ignored files - cat changes.diff | grep -v -E '(package-lock.json|yarn.lock|node_modules|\.md$|\.json$)' | grep -E '\.(js|ts|py|cpp|h|java|cs)$' > filtered_changes.diff + cat changes.diff | grep -v -E '(package-lock.json|yarn.lock|node_modules|\.md$|\.json$)' | grep -E '\.(js|ts|py|cpp|h|java|cs)$' > filtered_changes.diff || true # Store the size of the diff - echo "diff_size=$(stat -f%z filtered_changes.diff)" >> $GITHUB_OUTPUT + if [ -f filtered_changes.diff ]; then + echo "diff_size=$(wc -c < filtered_changes.diff)" >> $GITHUB_OUTPUT + else + echo "diff_size=0" >> $GITHUB_OUTPUT + fi - name: Analyze code with Claude if: steps.changed-files.outputs.diff_size != '0' @@ -108,7 +122,7 @@ jobs: -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -d "{ - \"model\": \"claude-3-sonnet-20240229\", + \"model\": \"claude-3-sonnet-20241022\", \"max_tokens\": 4096, \"temperature\": 0.7, \"messages\": [{ @@ -117,8 +131,13 @@ jobs: }] }") - # Extract the review content from the response - REVIEW=$(echo $RESPONSE | jq -r '.content[0].text') + # Extract the review content from the response and handle potential errors + if echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null; then + REVIEW=$(echo "$RESPONSE" | jq -r '.content[0].text') + else + echo "Error in Claude API response: $RESPONSE" + exit 1 + fi # Escape the review content for GitHub Actions REVIEW="${REVIEW//'%'/'%25'}" @@ -134,11 +153,20 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - const review = `${{ steps.analysis.outputs.review }}`; - - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.name, - issue_number: ${{ steps.pr-number.outputs.number }}, - body: `# Claude Code Review\n\n${review}` - }); + try { + const { owner, repo } = context.repo; + const prNumber = ${{ steps.pr-number.outputs.number }}; + const review = `${{ steps.analysis.outputs.review }}`; + + console.log(`Posting review to PR #${prNumber} in ${owner}/${repo}`); + + await github.rest.issues.createComment({ + owner: owner, + repo: repo, + issue_number: prNumber, + body: `# Claude Code Review\n\n${review}` + }); + } catch (error) { + core.setFailed(`Failed to post review: ${error.message}`); + throw error; + } From 563b96a85cb6a467692da0b5428f3ce5df22e481 Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:04:08 -0500 Subject: [PATCH 03/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 66 +++++++++++------------------ 1 file changed, 25 insertions(+), 41 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index 5c5d51a..5c691f3 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -56,33 +56,6 @@ jobs: throw error; } - - name: Get changed files - id: changed-files - run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - BASE_SHA=${{ fromJSON(steps.pr-details.outputs.result).base_sha }} - HEAD_SHA=${{ fromJSON(steps.pr-details.outputs.result).head_sha }} - else - BASE_SHA=${{ github.event.pull_request.base.sha }} - HEAD_SHA=${{ github.event.pull_request.head.sha }} - fi - - echo "Base SHA: $BASE_SHA" - echo "Head SHA: $HEAD_SHA" - - # Get the diff and save to a file - git diff $BASE_SHA..$HEAD_SHA > changes.diff || echo "Failed to get diff" - - # Create a filtered version without ignored files - cat changes.diff | grep -v -E '(package-lock.json|yarn.lock|node_modules|\.md$|\.json$)' | grep -E '\.(js|ts|py|cpp|h|java|cs)$' > filtered_changes.diff || true - - # Store the size of the diff - if [ -f filtered_changes.diff ]; then - echo "diff_size=$(wc -c < filtered_changes.diff)" >> $GITHUB_OUTPUT - else - echo "diff_size=0" >> $GITHUB_OUTPUT - fi - - name: Analyze code with Claude if: steps.changed-files.outputs.diff_size != '0' id: analysis @@ -91,8 +64,12 @@ jobs: run: | DIFF_CONTENT=$(cat filtered_changes.diff) - # Prepare the API request - PROMPT="You are performing a code review. Please analyze this code diff and provide a thorough review that covers: + # Escape the diff content for JSON + DIFF_CONTENT_ESCAPED=$(echo "$DIFF_CONTENT" | jq -Rs .) + + # Create the prompt with escaped content + PROMPT=$(cat << 'EOL' + You are performing a code review. Please analyze this code diff and provide a thorough review that covers: 1. Potential conflicts with existing codebase 2. Code correctness and potential bugs @@ -112,30 +89,37 @@ jobs: Here is the code diff to review: - \`\`\` - $DIFF_CONTENT - \`\`\`" + ``` + EOL + ) + + # Prepare the API request body using jq + REQUEST_BODY=$(jq -n \ + --arg prompt "$PROMPT" \ + --arg diff "$DIFF_CONTENT" \ + '{ + "model": "claude-3-sonnet-20241022", + "max_tokens": 4096, + "temperature": 0.7, + "messages": [{ + "role": "user", + "content": ($prompt + $diff + "\n```") + }] + }') # Make the API request RESPONSE=$(curl -s https://api.anthropic.com/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ - -d "{ - \"model\": \"claude-3-sonnet-20241022\", - \"max_tokens\": 4096, - \"temperature\": 0.7, - \"messages\": [{ - \"role\": \"user\", - \"content\": \"$PROMPT\" - }] - }") + -d "$REQUEST_BODY") # Extract the review content from the response and handle potential errors if echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null; then REVIEW=$(echo "$RESPONSE" | jq -r '.content[0].text') else echo "Error in Claude API response: $RESPONSE" + echo "Request body was: $REQUEST_BODY" exit 1 fi From 77b72e2ba864e756709889eca525c41b455ee170 Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:11:10 -0500 Subject: [PATCH 04/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 117 +++++++++++++++++----------- 1 file changed, 71 insertions(+), 46 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index 5c691f3..b928cd0 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -32,30 +32,74 @@ jobs: fi - name: Get PR details - if: github.event_name == 'workflow_dispatch' id: pr-details uses: actions/github-script@v7 with: script: | try { const { owner, repo } = context.repo; - console.log(`Getting PR #${{ inputs.pr_number }} from ${owner}/${repo}`); + const prNumber = ${{ steps.pr-number.outputs.number }}; + + console.log(`Getting PR #${prNumber} from ${owner}/${repo}`); const pr = await github.rest.pulls.get({ owner: owner, repo: repo, - pull_number: parseInt(${{ inputs.pr_number }}) + pull_number: prNumber + }); + + console.log('PR Details:', { + base: pr.data.base.ref, + base_sha: pr.data.base.sha, + head: pr.data.head.ref, + head_sha: pr.data.head.sha }); return { base_sha: pr.data.base.sha, - head_sha: pr.data.head.sha + head_sha: pr.data.head.sha, + base_ref: pr.data.base.ref, + head_ref: pr.data.head.ref }; } catch (error) { core.setFailed(`Failed to get PR details: ${error.message}`); throw error; } + - name: Generate diff + id: changed-files + run: | + # Configure git to fetch PR refs + git config --local --add remote.origin.fetch "+refs/pull/*/head:refs/remotes/origin/pr/*" + git fetch origin + + BASE_SHA="${{ fromJSON(steps.pr-details.outputs.result).base_sha }}" + HEAD_SHA="${{ fromJSON(steps.pr-details.outputs.result).head_sha }}" + + echo "Comparing $BASE_SHA..$HEAD_SHA" + + # Get the diff + git diff "$BASE_SHA" "$HEAD_SHA" > changes.diff + + # Filter the diff for specific file types + if [ -s changes.diff ]; then + cat changes.diff | grep -v -E '(package-lock.json|yarn.lock|node_modules|\.md$|\.json$)' | grep -E '\.(js|ts|py|cpp|h|java|cs)$' > filtered_changes.diff || true + + if [ -s filtered_changes.diff ]; then + DIFF_SIZE=$(wc -c < filtered_changes.diff) + echo "Found $DIFF_SIZE bytes of relevant changes" + echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT + echo "Preview of changes:" + head -n 5 filtered_changes.diff + else + echo "No relevant file changes found" + echo "diff_size=0" >> $GITHUB_OUTPUT + fi + else + echo "No changes found" + echo "diff_size=0" >> $GITHUB_OUTPUT + fi + - name: Analyze code with Claude if: steps.changed-files.outputs.diff_size != '0' id: analysis @@ -64,12 +108,9 @@ jobs: run: | DIFF_CONTENT=$(cat filtered_changes.diff) - # Escape the diff content for JSON - DIFF_CONTENT_ESCAPED=$(echo "$DIFF_CONTENT" | jq -Rs .) - - # Create the prompt with escaped content - PROMPT=$(cat << 'EOL' - You are performing a code review. Please analyze this code diff and provide a thorough review that covers: + # Create the request body using jq + REQUEST_BODY=$(jq -n \ + --arg content "You are performing a code review. Please analyze this code diff and provide a thorough review that covers: 1. Potential conflicts with existing codebase 2. Code correctness and potential bugs @@ -89,21 +130,16 @@ jobs: Here is the code diff to review: - ``` - EOL - ) - - # Prepare the API request body using jq - REQUEST_BODY=$(jq -n \ - --arg prompt "$PROMPT" \ - --arg diff "$DIFF_CONTENT" \ + \`\`\` + $DIFF_CONTENT + \`\`\`" \ '{ "model": "claude-3-sonnet-20241022", "max_tokens": 4096, "temperature": 0.7, "messages": [{ "role": "user", - "content": ($prompt + $diff + "\n```") + "content": $content }] }') @@ -114,22 +150,19 @@ jobs: -H "anthropic-version: 2023-06-01" \ -d "$REQUEST_BODY") - # Extract the review content from the response and handle potential errors if echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null; then REVIEW=$(echo "$RESPONSE" | jq -r '.content[0].text') + + # Escape the review content for GitHub Actions + REVIEW="${REVIEW//'%'/'%25'}" + REVIEW="${REVIEW//$'\n'/'%0A'}" + REVIEW="${REVIEW//$'\r'/'%0D'}" + + echo "review=$REVIEW" >> $GITHUB_OUTPUT else echo "Error in Claude API response: $RESPONSE" - echo "Request body was: $REQUEST_BODY" exit 1 fi - - # Escape the review content for GitHub Actions - REVIEW="${REVIEW//'%'/'%25'}" - REVIEW="${REVIEW//$'\n'/'%0A'}" - REVIEW="${REVIEW//$'\r'/'%0D'}" - - # Save the review to the output - echo "review=$REVIEW" >> $GITHUB_OUTPUT - name: Post review comment if: steps.changed-files.outputs.diff_size != '0' @@ -137,20 +170,12 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - try { - const { owner, repo } = context.repo; - const prNumber = ${{ steps.pr-number.outputs.number }}; - const review = `${{ steps.analysis.outputs.review }}`; - - console.log(`Posting review to PR #${prNumber} in ${owner}/${repo}`); - - await github.rest.issues.createComment({ - owner: owner, - repo: repo, - issue_number: prNumber, - body: `# Claude Code Review\n\n${review}` - }); - } catch (error) { - core.setFailed(`Failed to post review: ${error.message}`); - throw error; - } + const review = `${{ steps.analysis.outputs.review }}`; + const prNumber = ${{ steps.pr-number.outputs.number }}; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.name, + issue_number: prNumber, + body: `# Claude Code Review\n\n${review}` + }); From 841588bc0b9fb8b828f978ce7ad8827cdce2213c Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:16:28 -0500 Subject: [PATCH 05/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index b928cd0..dbeb2b5 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -134,7 +134,7 @@ jobs: $DIFF_CONTENT \`\`\`" \ '{ - "model": "claude-3-sonnet-20241022", + "model": "claude-3-sonnet-20240229", "max_tokens": 4096, "temperature": 0.7, "messages": [{ @@ -144,12 +144,15 @@ jobs: }') # Make the API request + echo "Sending request to Claude API..." RESPONSE=$(curl -s https://api.anthropic.com/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -d "$REQUEST_BODY") + echo "Response received, checking for content..." + if echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null; then REVIEW=$(echo "$RESPONSE" | jq -r '.content[0].text') @@ -165,7 +168,7 @@ jobs: fi - name: Post review comment - if: steps.changed-files.outputs.diff_size != '0' + if: success() && steps.changed-files.outputs.diff_size != '0' uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} From d116b401166f51f7832eb50363e167d640546321 Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:18:56 -0500 Subject: [PATCH 06/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index dbeb2b5..458d0b7 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -89,6 +89,13 @@ jobs: DIFF_SIZE=$(wc -c < filtered_changes.diff) echo "Found $DIFF_SIZE bytes of relevant changes" echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT + + # Store the diff content for the next step + DIFF_CONTENT=$(cat filtered_changes.diff) + echo "diff_content<> $GITHUB_OUTPUT + echo "$DIFF_CONTENT" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + echo "Preview of changes:" head -n 5 filtered_changes.diff else @@ -106,7 +113,8 @@ jobs: env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} run: | - DIFF_CONTENT=$(cat filtered_changes.diff) + # Get the diff content from the previous step + DIFF_CONTENT="${{ steps.changed-files.outputs.diff_content }}" # Create the request body using jq REQUEST_BODY=$(jq -n \ @@ -155,13 +163,9 @@ jobs: if echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null; then REVIEW=$(echo "$RESPONSE" | jq -r '.content[0].text') - - # Escape the review content for GitHub Actions - REVIEW="${REVIEW//'%'/'%25'}" - REVIEW="${REVIEW//$'\n'/'%0A'}" - REVIEW="${REVIEW//$'\r'/'%0D'}" - - echo "review=$REVIEW" >> $GITHUB_OUTPUT + echo "review<> $GITHUB_OUTPUT + echo "$REVIEW" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT else echo "Error in Claude API response: $RESPONSE" exit 1 @@ -173,12 +177,13 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | + const { owner, repo } = context.repo; const review = `${{ steps.analysis.outputs.review }}`; const prNumber = ${{ steps.pr-number.outputs.number }}; await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.name, + owner: owner, + repo: repo, issue_number: prNumber, body: `# Claude Code Review\n\n${review}` }); From 6b358f78f81e2af0914f1e4181249c0d65c44987 Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:21:23 -0500 Subject: [PATCH 07/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 85 +++++++++++++---------------- 1 file changed, 39 insertions(+), 46 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index 458d0b7..ec2097d 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -48,13 +48,6 @@ jobs: pull_number: prNumber }); - console.log('PR Details:', { - base: pr.data.base.ref, - base_sha: pr.data.base.sha, - head: pr.data.head.ref, - head_sha: pr.data.head.sha - }); - return { base_sha: pr.data.base.sha, head_sha: pr.data.head.sha, @@ -66,8 +59,8 @@ jobs: throw error; } - - name: Generate diff - id: changed-files + - name: Generate diff and prepare review + id: prepare run: | # Configure git to fetch PR refs git config --local --add remote.origin.fetch "+refs/pull/*/head:refs/remotes/origin/pr/*" @@ -78,45 +71,48 @@ jobs: echo "Comparing $BASE_SHA..$HEAD_SHA" - # Get the diff - git diff "$BASE_SHA" "$HEAD_SHA" > changes.diff + # Create a temporary directory for our files + mkdir -p /tmp/review - # Filter the diff for specific file types - if [ -s changes.diff ]; then - cat changes.diff | grep -v -E '(package-lock.json|yarn.lock|node_modules|\.md$|\.json$)' | grep -E '\.(js|ts|py|cpp|h|java|cs)$' > filtered_changes.diff || true + # Get the full diff and store it + git diff "$BASE_SHA" "$HEAD_SHA" > /tmp/review/changes.diff + + # Count total lines in diff + TOTAL_LINES=$(wc -l < /tmp/review/changes.diff) + echo "Total diff lines: $TOTAL_LINES" + + # Create filtered version + cat /tmp/review/changes.diff | \ + grep -v -E '(package-lock.json|yarn.lock|node_modules|\.md$|\.json$)' | \ + grep -E '\.(js|ts|py|cpp|h|java|cs)$' > /tmp/review/filtered.diff || true + + if [ -s /tmp/review/filtered.diff ]; then + DIFF_SIZE=$(wc -c < /tmp/review/filtered.diff) + echo "Found $DIFF_SIZE bytes of relevant changes" + echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT - if [ -s filtered_changes.diff ]; then - DIFF_SIZE=$(wc -c < filtered_changes.diff) - echo "Found $DIFF_SIZE bytes of relevant changes" - echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT - - # Store the diff content for the next step - DIFF_CONTENT=$(cat filtered_changes.diff) - echo "diff_content<> $GITHUB_OUTPUT - echo "$DIFF_CONTENT" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - - echo "Preview of changes:" - head -n 5 filtered_changes.diff - else - echo "No relevant file changes found" - echo "diff_size=0" >> $GITHUB_OUTPUT - fi + # Base64 encode the diff to preserve newlines and special characters + ENCODED_DIFF=$(base64 -w 0 /tmp/review/filtered.diff) + echo "diff_content=$ENCODED_DIFF" >> $GITHUB_OUTPUT + + echo "Preview of changes:" + head -n 5 /tmp/review/filtered.diff else - echo "No changes found" + echo "No relevant file changes found" echo "diff_size=0" >> $GITHUB_OUTPUT fi - name: Analyze code with Claude - if: steps.changed-files.outputs.diff_size != '0' + if: steps.prepare.outputs.diff_size != '0' id: analysis env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} run: | - # Get the diff content from the previous step - DIFF_CONTENT="${{ steps.changed-files.outputs.diff_content }}" + # Decode the diff content + echo "${{ steps.prepare.outputs.diff_content }}" | base64 -d > /tmp/review/decoded.diff + DIFF_CONTENT=$(cat /tmp/review/decoded.diff) - # Create the request body using jq + # Create request body REQUEST_BODY=$(jq -n \ --arg content "You are performing a code review. Please analyze this code diff and provide a thorough review that covers: @@ -159,31 +155,28 @@ jobs: -H "anthropic-version: 2023-06-01" \ -d "$REQUEST_BODY") - echo "Response received, checking for content..." - if echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null; then - REVIEW=$(echo "$RESPONSE" | jq -r '.content[0].text') - echo "review<> $GITHUB_OUTPUT - echo "$REVIEW" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT + # Base64 encode the review to preserve formatting + REVIEW=$(echo "$RESPONSE" | jq -r '.content[0].text' | base64 -w 0) + echo "review=$REVIEW" >> $GITHUB_OUTPUT else echo "Error in Claude API response: $RESPONSE" exit 1 fi - name: Post review comment - if: success() && steps.changed-files.outputs.diff_size != '0' + if: success() && steps.prepare.outputs.diff_size != '0' uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const { owner, repo } = context.repo; - const review = `${{ steps.analysis.outputs.review }}`; + const review = Buffer.from('${{ steps.analysis.outputs.review }}', 'base64').toString(); const prNumber = ${{ steps.pr-number.outputs.number }}; await github.rest.issues.createComment({ - owner: owner, - repo: repo, + owner, + repo, issue_number: prNumber, body: `# Claude Code Review\n\n${review}` }); From a530395a60c6dbd24cfdcbc474b812c77db7e2be Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:24:30 -0500 Subject: [PATCH 08/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 96 ++++++++++++----------------- 1 file changed, 40 insertions(+), 56 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index ec2097d..efed2d2 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -59,7 +59,7 @@ jobs: throw error; } - - name: Generate diff and prepare review + - name: Generate full diff id: prepare run: | # Configure git to fetch PR refs @@ -74,78 +74,60 @@ jobs: # Create a temporary directory for our files mkdir -p /tmp/review - # Get the full diff and store it - git diff "$BASE_SHA" "$HEAD_SHA" > /tmp/review/changes.diff + # Get the full diff with context and store it + git diff -U10 "$BASE_SHA" "$HEAD_SHA" > /tmp/review/full.diff - # Count total lines in diff - TOTAL_LINES=$(wc -l < /tmp/review/changes.diff) - echo "Total diff lines: $TOTAL_LINES" - - # Create filtered version - cat /tmp/review/changes.diff | \ - grep -v -E '(package-lock.json|yarn.lock|node_modules|\.md$|\.json$)' | \ - grep -E '\.(js|ts|py|cpp|h|java|cs)$' > /tmp/review/filtered.diff || true + # Create filtered version for relevant files only + cat /tmp/review/full.diff | \ + awk '/^diff --git/{p=0} /\.(js|ts|py|cpp|h|java|cs)$/{p=1} p' | \ + grep -v -E '^diff --git .*(package-lock\.json|yarn\.lock|\.md|\.json)' > /tmp/review/filtered.diff if [ -s /tmp/review/filtered.diff ]; then DIFF_SIZE=$(wc -c < /tmp/review/filtered.diff) echo "Found $DIFF_SIZE bytes of relevant changes" echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT - # Base64 encode the diff to preserve newlines and special characters - ENCODED_DIFF=$(base64 -w 0 /tmp/review/filtered.diff) - echo "diff_content=$ENCODED_DIFF" >> $GITHUB_OUTPUT + # Store full diff content in the output + { + echo 'diff_content<> $GITHUB_OUTPUT echo "Preview of changes:" - head -n 5 /tmp/review/filtered.diff + head -n 10 /tmp/review/filtered.diff else echo "No relevant file changes found" echo "diff_size=0" >> $GITHUB_OUTPUT fi + - name: Debug diff content + if: steps.prepare.outputs.diff_size != '0' + run: | + echo "Full diff content:" + echo "${{ steps.prepare.outputs.diff_content }}" + - name: Analyze code with Claude if: steps.prepare.outputs.diff_size != '0' id: analysis env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} run: | - # Decode the diff content - echo "${{ steps.prepare.outputs.diff_content }}" | base64 -d > /tmp/review/decoded.diff - DIFF_CONTENT=$(cat /tmp/review/decoded.diff) + DIFF_CONTENT="${{ steps.prepare.outputs.diff_content }}" - # Create request body - REQUEST_BODY=$(jq -n \ - --arg content "You are performing a code review. Please analyze this code diff and provide a thorough review that covers: - - 1. Potential conflicts with existing codebase - 2. Code correctness and potential bugs - 3. Security vulnerabilities or risks - 4. Performance implications - 5. Maintainability and readability issues - 6. Adherence to best practices and coding standards - 7. Suggestions for improvements - - For each issue found: - - Explain the problem clearly - - Rate the severity (Critical/High/Medium/Low) - - Provide specific recommendations for fixes - - Include code examples where helpful - - If no issues are found in a particular area, explicitly state that. - - Here is the code diff to review: - - \`\`\` - $DIFF_CONTENT - \`\`\`" \ - '{ - "model": "claude-3-sonnet-20240229", - "max_tokens": 4096, - "temperature": 0.7, - "messages": [{ - "role": "user", - "content": $content - }] - }') + # Create request body using cat and a heredoc to preserve formatting + REQUEST_BODY=$(cat << 'EOF' | jq -c . + { + "model": "claude-3-sonnet-20240229", + "max_tokens": 4096, + "temperature": 0.7, + "messages": [{ + "role": "user", + "content": "You are performing a code review. Please analyze this code diff and provide a thorough review that covers:\n\n1. Potential conflicts with existing codebase\n2. Code correctness and potential bugs\n3. Security vulnerabilities or risks\n4. Performance implications\n5. Maintainability and readability issues\n6. Adherence to best practices and coding standards\n7. Suggestions for improvements\n\nFor each issue found:\n- Explain the problem clearly\n- Rate the severity (Critical/High/Medium/Low)\n- Provide specific recommendations for fixes\n- Include code examples where helpful\n\nIf no issues are found in a particular area, explicitly state that.\n\nHere is the code diff to review:\n\n\`\`\`\n${DIFF_CONTENT}\n\`\`\`" + }] + } + EOF + ) # Make the API request echo "Sending request to Claude API..." @@ -156,9 +138,11 @@ jobs: -d "$REQUEST_BODY") if echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null; then - # Base64 encode the review to preserve formatting - REVIEW=$(echo "$RESPONSE" | jq -r '.content[0].text' | base64 -w 0) - echo "review=$REVIEW" >> $GITHUB_OUTPUT + { + echo 'review<> $GITHUB_OUTPUT else echo "Error in Claude API response: $RESPONSE" exit 1 @@ -171,7 +155,7 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const { owner, repo } = context.repo; - const review = Buffer.from('${{ steps.analysis.outputs.review }}', 'base64').toString(); + const review = `${{ steps.analysis.outputs.review }}`; const prNumber = ${{ steps.pr-number.outputs.number }}; await github.rest.issues.createComment({ From 0168e32da6a867f1ac9f9277c98a8a9c9c9fd4da Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:26:23 -0500 Subject: [PATCH 09/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 81 +++++++++++------------------ 1 file changed, 30 insertions(+), 51 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index efed2d2..4011177 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -59,8 +59,10 @@ jobs: throw error; } - - name: Generate full diff - id: prepare + - name: Generate and analyze diff + id: analysis + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} run: | # Configure git to fetch PR refs git config --local --add remote.origin.fetch "+refs/pull/*/head:refs/remotes/origin/pr/*" @@ -71,85 +73,62 @@ jobs: echo "Comparing $BASE_SHA..$HEAD_SHA" - # Create a temporary directory for our files - mkdir -p /tmp/review + # Get the diff with context + git diff -U10 "$BASE_SHA" "$HEAD_SHA" > diff_full.txt - # Get the full diff with context and store it - git diff -U10 "$BASE_SHA" "$HEAD_SHA" > /tmp/review/full.diff - - # Create filtered version for relevant files only - cat /tmp/review/full.diff | \ + # Filter for relevant files + cat diff_full.txt | \ awk '/^diff --git/{p=0} /\.(js|ts|py|cpp|h|java|cs)$/{p=1} p' | \ - grep -v -E '^diff --git .*(package-lock\.json|yarn\.lock|\.md|\.json)' > /tmp/review/filtered.diff + grep -v -E '^diff --git .*(package-lock\.json|yarn\.lock|\.md|\.json)' > diff_filtered.txt - if [ -s /tmp/review/filtered.diff ]; then - DIFF_SIZE=$(wc -c < /tmp/review/filtered.diff) - echo "Found $DIFF_SIZE bytes of relevant changes" - echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT - - # Store full diff content in the output - { - echo 'diff_content<> $GITHUB_OUTPUT - - echo "Preview of changes:" - head -n 10 /tmp/review/filtered.diff - else - echo "No relevant file changes found" + if [ ! -s diff_filtered.txt ]; then + echo "No relevant changes found" echo "diff_size=0" >> $GITHUB_OUTPUT + exit 0 fi - - - name: Debug diff content - if: steps.prepare.outputs.diff_size != '0' - run: | - echo "Full diff content:" - echo "${{ steps.prepare.outputs.diff_content }}" - - - name: Analyze code with Claude - if: steps.prepare.outputs.diff_size != '0' - id: analysis - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - run: | - DIFF_CONTENT="${{ steps.prepare.outputs.diff_content }}" - # Create request body using cat and a heredoc to preserve formatting - REQUEST_BODY=$(cat << 'EOF' | jq -c . + DIFF_SIZE=$(wc -c < diff_filtered.txt) + echo "Found $DIFF_SIZE bytes of relevant changes" + echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT + + # Prepare the diff content for the API request + DIFF_CONTENT=$(cat diff_filtered.txt) + + # Create the API request using a heredoc + REQUEST=$(cat << EOF { "model": "claude-3-sonnet-20240229", "max_tokens": 4096, "temperature": 0.7, "messages": [{ "role": "user", - "content": "You are performing a code review. Please analyze this code diff and provide a thorough review that covers:\n\n1. Potential conflicts with existing codebase\n2. Code correctness and potential bugs\n3. Security vulnerabilities or risks\n4. Performance implications\n5. Maintainability and readability issues\n6. Adherence to best practices and coding standards\n7. Suggestions for improvements\n\nFor each issue found:\n- Explain the problem clearly\n- Rate the severity (Critical/High/Medium/Low)\n- Provide specific recommendations for fixes\n- Include code examples where helpful\n\nIf no issues are found in a particular area, explicitly state that.\n\nHere is the code diff to review:\n\n\`\`\`\n${DIFF_CONTENT}\n\`\`\`" + "content": "You are performing a code review. Please analyze this code diff and provide a thorough review that covers:\n\n1. Potential conflicts with existing codebase\n2. Code correctness and potential bugs\n3. Security vulnerabilities or risks\n4. Performance implications\n5. Maintainability and readability issues\n6. Adherence to best practices and coding standards\n7. Suggestions for improvements\n\nFor each issue found:\n- Explain the problem clearly\n- Rate the severity (Critical/High/Medium/Low)\n- Provide specific recommendations for fixes\n- Include code examples where helpful\n\nIf no issues are found in a particular area, explicitly state that.\n\nHere is the code diff to review:\n\n\`\`\`\n$DIFF_CONTENT\n\`\`\`" }] } EOF ) - + # Make the API request echo "Sending request to Claude API..." RESPONSE=$(curl -s https://api.anthropic.com/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ - -d "$REQUEST_BODY") + -d "$REQUEST") if echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null; then - { - echo 'review<> $GITHUB_OUTPUT + # Save the review to a file to preserve formatting + echo "$RESPONSE" | jq -r '.content[0].text' > review.txt + echo 'review<> $GITHUB_OUTPUT + cat review.txt >> $GITHUB_OUTPUT + echo 'EOF' >> $GITHUB_OUTPUT else echo "Error in Claude API response: $RESPONSE" exit 1 fi - name: Post review comment - if: success() && steps.prepare.outputs.diff_size != '0' + if: success() && steps.analysis.outputs.diff_size != '0' uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} From dbad4cf822101833dae710f2b415d53aabb107ea Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:27:35 -0500 Subject: [PATCH 10/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 53 +++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index 4011177..010f474 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -91,22 +91,44 @@ jobs: echo "Found $DIFF_SIZE bytes of relevant changes" echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT - # Prepare the diff content for the API request - DIFF_CONTENT=$(cat diff_filtered.txt) + # Prepare prompt and diff content + PROMPT="You are performing a code review. Please analyze this code diff and provide a thorough review that covers: + + 1. Potential conflicts with existing codebase + 2. Code correctness and potential bugs + 3. Security vulnerabilities or risks + 4. Performance implications + 5. Maintainability and readability issues + 6. Adherence to best practices and coding standards + 7. Suggestions for improvements + + For each issue found: + - Explain the problem clearly + - Rate the severity (Critical/High/Medium/Low) + - Provide specific recommendations for fixes + - Include code examples where helpful + + If no issues are found in a particular area, explicitly state that. + + Here is the code diff to review: + + \`\`\` + $(cat diff_filtered.txt) + \`\`\`" - # Create the API request using a heredoc - REQUEST=$(cat << EOF - { - "model": "claude-3-sonnet-20240229", - "max_tokens": 4096, - "temperature": 0.7, - "messages": [{ - "role": "user", - "content": "You are performing a code review. Please analyze this code diff and provide a thorough review that covers:\n\n1. Potential conflicts with existing codebase\n2. Code correctness and potential bugs\n3. Security vulnerabilities or risks\n4. Performance implications\n5. Maintainability and readability issues\n6. Adherence to best practices and coding standards\n7. Suggestions for improvements\n\nFor each issue found:\n- Explain the problem clearly\n- Rate the severity (Critical/High/Medium/Low)\n- Provide specific recommendations for fixes\n- Include code examples where helpful\n\nIf no issues are found in a particular area, explicitly state that.\n\nHere is the code diff to review:\n\n\`\`\`\n$DIFF_CONTENT\n\`\`\`" - }] - } - EOF - ) + # Create the API request using jq to properly escape the content + echo "Creating API request..." + REQUEST=$(jq -n \ + --arg prompt "$PROMPT" \ + '{ + "model": "claude-3-sonnet-20240229", + "max_tokens": 4096, + "temperature": 0.7, + "messages": [{ + "role": "user", + "content": $prompt + }] + }') # Make the API request echo "Sending request to Claude API..." @@ -124,6 +146,7 @@ jobs: echo 'EOF' >> $GITHUB_OUTPUT else echo "Error in Claude API response: $RESPONSE" + echo "Request was: $REQUEST" exit 1 fi From 597894a80afa52829f5a51a065716097bb34570b Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:31:47 -0500 Subject: [PATCH 11/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 132 +--------------------------- 1 file changed, 3 insertions(+), 129 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index 010f474..2fd7138 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -22,133 +22,7 @@ jobs: with: fetch-depth: 0 - - name: Get PR number - id: pr-number - run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - echo "number=${{ inputs.pr_number }}" >> $GITHUB_OUTPUT - else - echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT - fi - - - name: Get PR details - id: pr-details - uses: actions/github-script@v7 - with: - script: | - try { - const { owner, repo } = context.repo; - const prNumber = ${{ steps.pr-number.outputs.number }}; - - console.log(`Getting PR #${prNumber} from ${owner}/${repo}`); - - const pr = await github.rest.pulls.get({ - owner: owner, - repo: repo, - pull_number: prNumber - }); - - return { - base_sha: pr.data.base.sha, - head_sha: pr.data.head.sha, - base_ref: pr.data.base.ref, - head_ref: pr.data.head.ref - }; - } catch (error) { - core.setFailed(`Failed to get PR details: ${error.message}`); - throw error; - } - - - name: Generate and analyze diff - id: analysis - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - run: | - # Configure git to fetch PR refs - git config --local --add remote.origin.fetch "+refs/pull/*/head:refs/remotes/origin/pr/*" - git fetch origin - - BASE_SHA="${{ fromJSON(steps.pr-details.outputs.result).base_sha }}" - HEAD_SHA="${{ fromJSON(steps.pr-details.outputs.result).head_sha }}" - - echo "Comparing $BASE_SHA..$HEAD_SHA" - - # Get the diff with context - git diff -U10 "$BASE_SHA" "$HEAD_SHA" > diff_full.txt - - # Filter for relevant files - cat diff_full.txt | \ - awk '/^diff --git/{p=0} /\.(js|ts|py|cpp|h|java|cs)$/{p=1} p' | \ - grep -v -E '^diff --git .*(package-lock\.json|yarn\.lock|\.md|\.json)' > diff_filtered.txt - - if [ ! -s diff_filtered.txt ]; then - echo "No relevant changes found" - echo "diff_size=0" >> $GITHUB_OUTPUT - exit 0 - fi - - DIFF_SIZE=$(wc -c < diff_filtered.txt) - echo "Found $DIFF_SIZE bytes of relevant changes" - echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT - - # Prepare prompt and diff content - PROMPT="You are performing a code review. Please analyze this code diff and provide a thorough review that covers: - - 1. Potential conflicts with existing codebase - 2. Code correctness and potential bugs - 3. Security vulnerabilities or risks - 4. Performance implications - 5. Maintainability and readability issues - 6. Adherence to best practices and coding standards - 7. Suggestions for improvements - - For each issue found: - - Explain the problem clearly - - Rate the severity (Critical/High/Medium/Low) - - Provide specific recommendations for fixes - - Include code examples where helpful - - If no issues are found in a particular area, explicitly state that. - - Here is the code diff to review: - - \`\`\` - $(cat diff_filtered.txt) - \`\`\`" - - # Create the API request using jq to properly escape the content - echo "Creating API request..." - REQUEST=$(jq -n \ - --arg prompt "$PROMPT" \ - '{ - "model": "claude-3-sonnet-20240229", - "max_tokens": 4096, - "temperature": 0.7, - "messages": [{ - "role": "user", - "content": $prompt - }] - }') - - # Make the API request - echo "Sending request to Claude API..." - RESPONSE=$(curl -s https://api.anthropic.com/v1/messages \ - -H "Content-Type: application/json" \ - -H "x-api-key: $ANTHROPIC_API_KEY" \ - -H "anthropic-version: 2023-06-01" \ - -d "$REQUEST") - - if echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null; then - # Save the review to a file to preserve formatting - echo "$RESPONSE" | jq -r '.content[0].text' > review.txt - echo 'review<> $GITHUB_OUTPUT - cat review.txt >> $GITHUB_OUTPUT - echo 'EOF' >> $GITHUB_OUTPUT - else - echo "Error in Claude API response: $RESPONSE" - echo "Request was: $REQUEST" - exit 1 - fi + # Previous steps remain the same until the post review comment... - name: Post review comment if: success() && steps.analysis.outputs.diff_size != '0' @@ -157,12 +31,12 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const { owner, repo } = context.repo; - const review = `${{ steps.analysis.outputs.review }}`; + const review = JSON.parse(JSON.stringify(`${{ steps.analysis.outputs.review }}`)); const prNumber = ${{ steps.pr-number.outputs.number }}; await github.rest.issues.createComment({ owner, repo, issue_number: prNumber, - body: `# Claude Code Review\n\n${review}` + body: "# Claude Code Review\n\n" + review.replace(/\\([\s\S])|(")/g, '\\$1$2') }); From 7eecd72130f66f76fb2a2d859a0c1dbefc79593c Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:35:34 -0500 Subject: [PATCH 12/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 144 +++++++++++++++++++++++++--- 1 file changed, 131 insertions(+), 13 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index 2fd7138..966a761 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -18,25 +18,143 @@ jobs: code-review: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 with: fetch-depth: 0 - # Previous steps remain the same until the post review comment... + - name: Get PR number + id: pr-number + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "number=${{ inputs.pr_number }}" >> $GITHUB_OUTPUT + else + echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT + fi + + - name: Get PR details + id: pr-details + uses: actions/github-script@v7 + with: + script: | + try { + const { owner, repo } = context.repo; + const prNumber = ${{ steps.pr-number.outputs.number }}; + + console.log(`Getting PR #${prNumber} from ${owner}/${repo}`); + + const pr = await github.rest.pulls.get({ + owner: owner, + repo: repo, + pull_number: prNumber + }); + + return { + base_sha: pr.data.base.sha, + head_sha: pr.data.head.sha, + base_ref: pr.data.base.ref, + head_ref: pr.data.head.ref + }; + } catch (error) { + core.setFailed(`Failed to get PR details: ${error.message}`); + throw error; + } + + - name: Generate diff + id: diff + run: | + # Configure git to fetch PR refs + git config --local --add remote.origin.fetch "+refs/pull/*/head:refs/remotes/origin/pr/*" + git fetch origin + + BASE_SHA="${{ fromJSON(steps.pr-details.outputs.result).base_sha }}" + HEAD_SHA="${{ fromJSON(steps.pr-details.outputs.result).head_sha }}" + + echo "Comparing $BASE_SHA..$HEAD_SHA" + + # Get the full diff with context + git diff -U10 "$BASE_SHA" "$HEAD_SHA" > diff_full.txt + + # Filter for relevant files + cat diff_full.txt | \ + awk '/^diff --git/{p=0} /\.(js|ts|py|cpp|h|java|cs)$/{p=1} p' | \ + grep -v -E '^diff --git .*(package-lock\.json|yarn\.lock|\.md|\.json)' > diff_filtered.txt + + if [ ! -s diff_filtered.txt ]; then + echo "No relevant changes found" + echo "diff_size=0" >> $GITHUB_OUTPUT + exit 0 + fi + + DIFF_SIZE=$(wc -c < diff_filtered.txt) + echo "Found $DIFF_SIZE bytes of relevant changes" + echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT + + # Base64 encode the diff to preserve formatting + ENCODED_DIFF=$(base64 -w 0 diff_filtered.txt) + echo "diff_content=$ENCODED_DIFF" >> $GITHUB_OUTPUT + + - name: Analyze with Claude + if: steps.diff.outputs.diff_size != '0' + id: analysis + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + run: | + # Decode the diff content + DIFF_CONTENT=$(echo "${{ steps.diff.outputs.diff_content }}" | base64 -d) + + # Create request JSON using jq + REQUEST=$(jq -n \ + --arg diff "$DIFF_CONTENT" \ + '{ + model: "claude-3-sonnet-20240229", + max_tokens: 4096, + temperature: 0.7, + messages: [{ + role: "user", + content: "You are performing a code review. Please analyze this code diff and provide a thorough review that covers:\n\n1. Potential conflicts with existing codebase\n2. Code correctness and potential bugs\n3. Security vulnerabilities or risks\n4. Performance implications\n5. Maintainability and readability issues\n6. Adherence to best practices and coding standards\n7. Suggestions for improvements\n\nFor each issue found:\n- Explain the problem clearly\n- Rate the severity (Critical/High/Medium/Low)\n- Provide specific recommendations for fixes\n- Include code examples where helpful\n\nIf no issues are found in a particular area, explicitly state that.\n\nHere is the code diff to review:\n\n```\n" + $diff + "\n```" + }] + }') + + # Make the API request + echo "Sending request to Claude API..." + RESPONSE=$(curl -s https://api.anthropic.com/v1/messages \ + -H "Content-Type: application/json" \ + -H "x-api-key: $ANTHROPIC_API_KEY" \ + -H "anthropic-version: 2023-06-01" \ + -d "$REQUEST") + + if echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null; then + # Save the review text + REVIEW=$(echo "$RESPONSE" | jq -r '.content[0].text') + { + echo 'review<> $GITHUB_OUTPUT + else + echo "Error in Claude API response: $RESPONSE" + exit 1 + fi - name: Post review comment - if: success() && steps.analysis.outputs.diff_size != '0' + if: success() && steps.diff.outputs.diff_size != '0' uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - const { owner, repo } = context.repo; - const review = JSON.parse(JSON.stringify(`${{ steps.analysis.outputs.review }}`)); - const prNumber = ${{ steps.pr-number.outputs.number }}; - - await github.rest.issues.createComment({ - owner, - repo, - issue_number: prNumber, - body: "# Claude Code Review\n\n" + review.replace(/\\([\s\S])|(")/g, '\\$1$2') - }); + try { + const { owner, repo } = context.repo; + const review = `${{ steps.analysis.outputs.review }}`; + const prNumber = ${{ steps.pr-number.outputs.number }}; + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body: "# Claude Code Review\n\n" + review + }); + } catch (error) { + core.setFailed(`Failed to post review: ${error.message}`); + throw error; + } From 554bf7a00d9986a55fad2dae46288f1bd520a624 Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:38:21 -0500 Subject: [PATCH 13/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 114 +++++++++++++++------------- 1 file changed, 63 insertions(+), 51 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index 966a761..78f2ec2 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -18,8 +18,7 @@ jobs: code-review: runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: fetch-depth: 0 @@ -60,8 +59,10 @@ jobs: throw error; } - - name: Generate diff - id: diff + - name: Generate diff and analyze + id: analysis + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} run: | # Configure git to fetch PR refs git config --local --add remote.origin.fetch "+refs/pull/*/head:refs/remotes/origin/pr/*" @@ -90,71 +91,82 @@ jobs: echo "Found $DIFF_SIZE bytes of relevant changes" echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT - # Base64 encode the diff to preserve formatting - ENCODED_DIFF=$(base64 -w 0 diff_filtered.txt) - echo "diff_content=$ENCODED_DIFF" >> $GITHUB_OUTPUT - - - name: Analyze with Claude - if: steps.diff.outputs.diff_size != '0' - id: analysis - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - run: | - # Decode the diff content - DIFF_CONTENT=$(echo "${{ steps.diff.outputs.diff_content }}" | base64 -d) + # Prepare the diff content + DIFF_CONTENT=$(cat diff_filtered.txt) - # Create request JSON using jq - REQUEST=$(jq -n \ - --arg diff "$DIFF_CONTENT" \ + # Create the JSON payload + read -r -d '' PROMPT << EOM + You are performing a code review. Please analyze this code diff and provide a thorough review that covers: + + 1. Potential conflicts with existing codebase + 2. Code correctness and potential bugs + 3. Security vulnerabilities or risks + 4. Performance implications + 5. Maintainability and readability issues + 6. Adherence to best practices and coding standards + 7. Suggestions for improvements + + For each issue found: + - Explain the problem clearly + - Rate the severity (Critical/High/Medium/Low) + - Provide specific recommendations for fixes + - Include code examples where helpful + + If no issues are found in a particular area, explicitly state that. + + Here is the code diff to review: + + \`\`\` + ${DIFF_CONTENT} + \`\`\` + EOM + + # Create API request JSON + REQUEST_JSON=$(jq -n \ + --arg prompt "$PROMPT" \ '{ - model: "claude-3-sonnet-20240229", - max_tokens: 4096, - temperature: 0.7, - messages: [{ - role: "user", - content: "You are performing a code review. Please analyze this code diff and provide a thorough review that covers:\n\n1. Potential conflicts with existing codebase\n2. Code correctness and potential bugs\n3. Security vulnerabilities or risks\n4. Performance implications\n5. Maintainability and readability issues\n6. Adherence to best practices and coding standards\n7. Suggestions for improvements\n\nFor each issue found:\n- Explain the problem clearly\n- Rate the severity (Critical/High/Medium/Low)\n- Provide specific recommendations for fixes\n- Include code examples where helpful\n\nIf no issues are found in a particular area, explicitly state that.\n\nHere is the code diff to review:\n\n```\n" + $diff + "\n```" - }] + "model": "claude-3-sonnet-20240229", + "max_tokens": 4096, + "temperature": 0.7, + "messages": [ + { + "role": "user", + "content": $prompt + } + ] }') - # Make the API request + # Make API request and capture response in a file to preserve formatting echo "Sending request to Claude API..." RESPONSE=$(curl -s https://api.anthropic.com/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ - -d "$REQUEST") + -d "$REQUEST_JSON") if echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null; then - # Save the review text - REVIEW=$(echo "$RESPONSE" | jq -r '.content[0].text') - { - echo 'review<> $GITHUB_OUTPUT + echo 'review<> $GITHUB_OUTPUT + echo "$RESPONSE" | jq -r '.content[0].text' >> $GITHUB_OUTPUT + echo 'EOF' >> $GITHUB_OUTPUT else echo "Error in Claude API response: $RESPONSE" + echo "Request was: $REQUEST_JSON" exit 1 fi - name: Post review comment - if: success() && steps.diff.outputs.diff_size != '0' + if: success() && steps.analysis.outputs.diff_size != '0' uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - try { - const { owner, repo } = context.repo; - const review = `${{ steps.analysis.outputs.review }}`; - const prNumber = ${{ steps.pr-number.outputs.number }}; - - await github.rest.issues.createComment({ - owner, - repo, - issue_number: prNumber, - body: "# Claude Code Review\n\n" + review - }); - } catch (error) { - core.setFailed(`Failed to post review: ${error.message}`); - throw error; - } + const { owner, repo } = context.repo; + const review = `${{ steps.analysis.outputs.review }}`; + const prNumber = ${{ steps.pr-number.outputs.number }}; + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body: "# Claude Code Review\n\n" + review + }); From f6b3929932f7191289e0e60c9dc5313ff91ba7d3 Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:40:15 -0500 Subject: [PATCH 14/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 58 +++++++++++++---------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index 78f2ec2..76bfb34 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -73,30 +73,23 @@ jobs: echo "Comparing $BASE_SHA..$HEAD_SHA" - # Get the full diff with context - git diff -U10 "$BASE_SHA" "$HEAD_SHA" > diff_full.txt + # Get the diff + DIFF_CONTENT=$(git diff -U10 "$BASE_SHA" "$HEAD_SHA" | \ + grep -v -E '^diff --git .*(package-lock\.json|yarn\.lock|\.md|\.json)' | \ + grep -E '\.(js|ts|py|cpp|h|java|cs)$') - # Filter for relevant files - cat diff_full.txt | \ - awk '/^diff --git/{p=0} /\.(js|ts|py|cpp|h|java|cs)$/{p=1} p' | \ - grep -v -E '^diff --git .*(package-lock\.json|yarn\.lock|\.md|\.json)' > diff_filtered.txt - - if [ ! -s diff_filtered.txt ]; then + if [ -z "$DIFF_CONTENT" ]; then echo "No relevant changes found" echo "diff_size=0" >> $GITHUB_OUTPUT exit 0 fi - DIFF_SIZE=$(wc -c < diff_filtered.txt) + DIFF_SIZE=${#DIFF_CONTENT} echo "Found $DIFF_SIZE bytes of relevant changes" echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT - # Prepare the diff content - DIFF_CONTENT=$(cat diff_filtered.txt) - - # Create the JSON payload - read -r -d '' PROMPT << EOM - You are performing a code review. Please analyze this code diff and provide a thorough review that covers: + # Create prompt + PROMPT="You are performing a code review. Please analyze this code diff and provide a thorough review that covers: 1. Potential conflicts with existing codebase 2. Code correctness and potential bugs @@ -117,40 +110,39 @@ jobs: Here is the code diff to review: \`\`\` - ${DIFF_CONTENT} - \`\`\` - EOM + $DIFF_CONTENT + \`\`\`" - # Create API request JSON - REQUEST_JSON=$(jq -n \ + # Create API request + REQUEST=$(jq -n \ --arg prompt "$PROMPT" \ '{ "model": "claude-3-sonnet-20240229", "max_tokens": 4096, "temperature": 0.7, - "messages": [ - { - "role": "user", - "content": $prompt - } - ] + "messages": [{ + "role": "user", + "content": $prompt + }] }') - # Make API request and capture response in a file to preserve formatting + # Call API echo "Sending request to Claude API..." RESPONSE=$(curl -s https://api.anthropic.com/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ - -d "$REQUEST_JSON") + -d "$REQUEST") + # Process response if echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null; then - echo 'review<> $GITHUB_OUTPUT - echo "$RESPONSE" | jq -r '.content[0].text' >> $GITHUB_OUTPUT - echo 'EOF' >> $GITHUB_OUTPUT + { + echo 'review<> $GITHUB_OUTPUT else echo "Error in Claude API response: $RESPONSE" - echo "Request was: $REQUEST_JSON" exit 1 fi @@ -161,8 +153,8 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const { owner, repo } = context.repo; - const review = `${{ steps.analysis.outputs.review }}`; const prNumber = ${{ steps.pr-number.outputs.number }}; + const review = `${{ steps.analysis.outputs.review }}`; await github.rest.issues.createComment({ owner, From 2039026133287db615dc81896d30495392590dec Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:43:21 -0500 Subject: [PATCH 15/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 65 +++++++++++++---------------- 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index 76bfb34..b1db72e 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -73,60 +73,50 @@ jobs: echo "Comparing $BASE_SHA..$HEAD_SHA" - # Get the diff - DIFF_CONTENT=$(git diff -U10 "$BASE_SHA" "$HEAD_SHA" | \ - grep -v -E '^diff --git .*(package-lock\.json|yarn\.lock|\.md|\.json)' | \ - grep -E '\.(js|ts|py|cpp|h|java|cs)$') + # Generate the full diff + git diff -U10 "$BASE_SHA" "$HEAD_SHA" > full_diff.txt - if [ -z "$DIFF_CONTENT" ]; then + # Use awk to properly capture full context of relevant files + awk ' + BEGIN { found=0; buffer="" } + /^diff --git/ { + if (found) { print buffer } + found=0; buffer="" + if ($0 ~ /\.(js|ts|py|cpp|h|java|cs)$/ && $0 !~ /(package-lock\.json|yarn\.lock|\.md|\.json)/) { + found=1 + } + } + { if (found) buffer = buffer $0 "\n" } + END { if (found) print buffer } + ' full_diff.txt > filtered_diff.txt + + # Check if we have any relevant changes + if [ ! -s filtered_diff.txt ]; then echo "No relevant changes found" echo "diff_size=0" >> $GITHUB_OUTPUT exit 0 fi - DIFF_SIZE=${#DIFF_CONTENT} + # Get file size and content + DIFF_SIZE=$(wc -c < filtered_diff.txt) echo "Found $DIFF_SIZE bytes of relevant changes" echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT - # Create prompt - PROMPT="You are performing a code review. Please analyze this code diff and provide a thorough review that covers: - - 1. Potential conflicts with existing codebase - 2. Code correctness and potential bugs - 3. Security vulnerabilities or risks - 4. Performance implications - 5. Maintainability and readability issues - 6. Adherence to best practices and coding standards - 7. Suggestions for improvements - - For each issue found: - - Explain the problem clearly - - Rate the severity (Critical/High/Medium/Low) - - Provide specific recommendations for fixes - - Include code examples where helpful - - If no issues are found in a particular area, explicitly state that. - - Here is the code diff to review: - - \`\`\` - $DIFF_CONTENT - \`\`\`" - - # Create API request + # Create the API request + DIFF_CONTENT=$(cat filtered_diff.txt) REQUEST=$(jq -n \ - --arg prompt "$PROMPT" \ + --arg diff "$DIFF_CONTENT" \ '{ "model": "claude-3-sonnet-20240229", "max_tokens": 4096, "temperature": 0.7, "messages": [{ "role": "user", - "content": $prompt + "content": "You are performing a code review. Please analyze this code diff and provide a thorough review that covers:\n\n1. Potential conflicts with existing codebase\n2. Code correctness and potential bugs\n3. Security vulnerabilities or risks\n4. Performance implications\n5. Maintainability and readability issues\n6. Adherence to best practices and coding standards\n7. Suggestions for improvements\n\nFor each issue found:\n- Explain the problem clearly\n- Rate the severity (Critical/High/Medium/Low)\n- Provide specific recommendations for fixes\n- Include code examples where helpful\n\nIf no issues are found in a particular area, explicitly state that.\n\nHere is the code diff to review:\n\n```\n" + $diff + "\n```" }] }') - # Call API + # Call the API echo "Sending request to Claude API..." RESPONSE=$(curl -s https://api.anthropic.com/v1/messages \ -H "Content-Type: application/json" \ @@ -134,7 +124,7 @@ jobs: -H "anthropic-version: 2023-06-01" \ -d "$REQUEST") - # Process response + # Process the response if echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null; then { echo 'review<> $GITHUB_OUTPUT else echo "Error in Claude API response: $RESPONSE" + echo "Request was: $REQUEST" exit 1 fi @@ -153,8 +144,8 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const { owner, repo } = context.repo; - const prNumber = ${{ steps.pr-number.outputs.number }}; const review = `${{ steps.analysis.outputs.review }}`; + const prNumber = ${{ steps.pr-number.outputs.number }}; await github.rest.issues.createComment({ owner, From f55efc315d6b2d38b9e49b3b6f3fd0e880372569 Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:45:06 -0500 Subject: [PATCH 16/20] Update claude-review.yml From 3e4429d34cc27f58e9c52a0132402942c179b504 Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:47:26 -0500 Subject: [PATCH 17/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 44 ++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index b1db72e..446e03e 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -75,7 +75,7 @@ jobs: # Generate the full diff git diff -U10 "$BASE_SHA" "$HEAD_SHA" > full_diff.txt - + # Use awk to properly capture full context of relevant files awk ' BEGIN { found=0; buffer="" } @@ -101,18 +101,42 @@ jobs: DIFF_SIZE=$(wc -c < filtered_diff.txt) echo "Found $DIFF_SIZE bytes of relevant changes" echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT + + # Create prompt text + PROMPT_TEXT="You are performing a code review. Please analyze this code diff and provide a thorough review that covers: + + 1. Potential conflicts with existing codebase + 2. Code correctness and potential bugs + 3. Security vulnerabilities or risks + 4. Performance implications + 5. Maintainability and readability issues + 6. Adherence to best practices and coding standards + 7. Suggestions for improvements + + For each issue found: + - Explain the problem clearly + - Rate the severity (Critical/High/Medium/Low) + - Provide specific recommendations for fixes + - Include code examples where helpful + + If no issues are found in a particular area, explicitly state that. + + Here is the code diff to review: + + \`\`\` + $(cat filtered_diff.txt) + \`\`\`" - # Create the API request - DIFF_CONTENT=$(cat filtered_diff.txt) + # Create API request with proper string handling REQUEST=$(jq -n \ - --arg diff "$DIFF_CONTENT" \ + --arg prompt "$PROMPT_TEXT" \ '{ - "model": "claude-3-sonnet-20240229", - "max_tokens": 4096, - "temperature": 0.7, - "messages": [{ - "role": "user", - "content": "You are performing a code review. Please analyze this code diff and provide a thorough review that covers:\n\n1. Potential conflicts with existing codebase\n2. Code correctness and potential bugs\n3. Security vulnerabilities or risks\n4. Performance implications\n5. Maintainability and readability issues\n6. Adherence to best practices and coding standards\n7. Suggestions for improvements\n\nFor each issue found:\n- Explain the problem clearly\n- Rate the severity (Critical/High/Medium/Low)\n- Provide specific recommendations for fixes\n- Include code examples where helpful\n\nIf no issues are found in a particular area, explicitly state that.\n\nHere is the code diff to review:\n\n```\n" + $diff + "\n```" + model: "claude-3-sonnet-20240229", + max_tokens: 4096, + temperature: 0.7, + messages: [{ + role: "user", + content: $prompt }] }') From d7e65438d33c0f91a950b3cc8664d21967d4625a Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:51:01 -0500 Subject: [PATCH 18/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 45 +++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index 446e03e..0df36fc 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -102,8 +102,9 @@ jobs: echo "Found $DIFF_SIZE bytes of relevant changes" echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT - # Create prompt text - PROMPT_TEXT="You are performing a code review. Please analyze this code diff and provide a thorough review that covers: + # Create prompt text in a file for better handling + cat > prompt.txt << 'EOL' + You are performing a code review. Please analyze this code diff and provide a thorough review that covers: 1. Potential conflicts with existing codebase 2. Code correctness and potential bugs @@ -123,20 +124,22 @@ jobs: Here is the code diff to review: - \`\`\` - $(cat filtered_diff.txt) - \`\`\`" + ``` + EOL + + cat filtered_diff.txt >> prompt.txt + echo '```' >> prompt.txt - # Create API request with proper string handling - REQUEST=$(jq -n \ - --arg prompt "$PROMPT_TEXT" \ + # Create API request + REQUEST_JSON=$(jq -n \ + --arg content "$(cat prompt.txt)" \ '{ model: "claude-3-sonnet-20240229", max_tokens: 4096, temperature: 0.7, messages: [{ role: "user", - content: $prompt + content: $content }] }') @@ -146,7 +149,7 @@ jobs: -H "Content-Type: application/json" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ - -d "$REQUEST") + -d "$REQUEST_JSON") # Process the response if echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null; then @@ -157,10 +160,28 @@ jobs: } >> $GITHUB_OUTPUT else echo "Error in Claude API response: $RESPONSE" - echo "Request was: $REQUEST" + echo "Request was: $REQUEST_JSON" exit 1 fi + - name: Process review + if: success() && steps.analysis.outputs.diff_size != '0' + id: process-review + uses: actions/github-script@v7 + with: + script: | + const review = `${{ steps.analysis.outputs.review }}`; + + // Process review text to properly escape code blocks + const processedReview = review + .replace(/```/g, '\\`\\`\\`') + .replace(/`([^`]+)`/g, '\\`$1\\`') + .replace(/\${/g, '\\${'); + + return { + text: processedReview + }; + - name: Post review comment if: success() && steps.analysis.outputs.diff_size != '0' uses: actions/github-script@v7 @@ -168,8 +189,8 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const { owner, repo } = context.repo; - const review = `${{ steps.analysis.outputs.review }}`; const prNumber = ${{ steps.pr-number.outputs.number }}; + const review = ${{ steps.process-review.outputs.result }}.text; await github.rest.issues.createComment({ owner, From 7282c199c6a03183392c238654534961e747943c Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:54:25 -0500 Subject: [PATCH 19/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 49 +++++++++++------------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index 0df36fc..be98726 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -102,8 +102,11 @@ jobs: echo "Found $DIFF_SIZE bytes of relevant changes" echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT - # Create prompt text in a file for better handling - cat > prompt.txt << 'EOL' + # Prepare content for API request + DIFF_CONTENT=$(cat filtered_diff.txt) + + # Create prompt in a way that preserves formatting + PROMPT=$(cat << 'EOL' You are performing a code review. Please analyze this code diff and provide a thorough review that covers: 1. Potential conflicts with existing codebase @@ -126,20 +129,19 @@ jobs: ``` EOL + ) - cat filtered_diff.txt >> prompt.txt - echo '```' >> prompt.txt - # Create API request - REQUEST_JSON=$(jq -n \ - --arg content "$(cat prompt.txt)" \ + REQUEST=$(jq -n \ + --arg prompt "$PROMPT" \ + --arg diff "$DIFF_CONTENT" \ '{ model: "claude-3-sonnet-20240229", max_tokens: 4096, temperature: 0.7, messages: [{ role: "user", - content: $content + content: ($prompt + "\n" + $diff + "\n```") }] }') @@ -149,7 +151,7 @@ jobs: -H "Content-Type: application/json" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ - -d "$REQUEST_JSON") + -d "$REQUEST") # Process the response if echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null; then @@ -160,28 +162,10 @@ jobs: } >> $GITHUB_OUTPUT else echo "Error in Claude API response: $RESPONSE" - echo "Request was: $REQUEST_JSON" + echo "Request was: $REQUEST" exit 1 fi - - name: Process review - if: success() && steps.analysis.outputs.diff_size != '0' - id: process-review - uses: actions/github-script@v7 - with: - script: | - const review = `${{ steps.analysis.outputs.review }}`; - - // Process review text to properly escape code blocks - const processedReview = review - .replace(/```/g, '\\`\\`\\`') - .replace(/`([^`]+)`/g, '\\`$1\\`') - .replace(/\${/g, '\\${'); - - return { - text: processedReview - }; - - name: Post review comment if: success() && steps.analysis.outputs.diff_size != '0' uses: actions/github-script@v7 @@ -190,11 +174,16 @@ jobs: script: | const { owner, repo } = context.repo; const prNumber = ${{ steps.pr-number.outputs.number }}; - const review = ${{ steps.process-review.outputs.result }}.text; + + // Prepare review text + const reviewText = `${{ steps.analysis.outputs.review }}` + .replace(/(?<=[\s\n])`([^`]+)`(?=[\s\n])/g, '\\`$1\\`') + .replace(/```/g, '\\`\\`\\`') + .replace(/\${/g, '\\${'); await github.rest.issues.createComment({ owner, repo, issue_number: prNumber, - body: "# Claude Code Review\n\n" + review + body: "# Claude Code Review\n\n" + reviewText }); From d1541cda773693cf66284bf38ff3eb26a8121de2 Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Tue, 10 Dec 2024 19:00:58 -0500 Subject: [PATCH 20/20] Update claude-review.yml --- .github/workflows/claude-review.yml | 171 ++-------------------------- 1 file changed, 8 insertions(+), 163 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index be98726..ddaaa83 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -5,8 +5,11 @@ permissions: pull-requests: write on: + # Run on new/updated PRs pull_request: types: [opened, reopened, synchronize] + + # Allow manual triggers for existing PRs workflow_dispatch: inputs: pr_number: @@ -17,173 +20,15 @@ on: jobs: code-review: runs-on: ubuntu-latest + steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - - - name: Get PR number - id: pr-number - run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - echo "number=${{ inputs.pr_number }}" >> $GITHUB_OUTPUT - else - echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT - fi - - - name: Get PR details - id: pr-details - uses: actions/github-script@v7 - with: - script: | - try { - const { owner, repo } = context.repo; - const prNumber = ${{ steps.pr-number.outputs.number }}; - - console.log(`Getting PR #${prNumber} from ${owner}/${repo}`); - - const pr = await github.rest.pulls.get({ - owner: owner, - repo: repo, - pull_number: prNumber - }); - - return { - base_sha: pr.data.base.sha, - head_sha: pr.data.head.sha, - base_ref: pr.data.base.ref, - head_ref: pr.data.head.ref - }; - } catch (error) { - core.setFailed(`Failed to get PR details: ${error.message}`); - throw error; - } - - - name: Generate diff and analyze - id: analysis - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - run: | - # Configure git to fetch PR refs - git config --local --add remote.origin.fetch "+refs/pull/*/head:refs/remotes/origin/pr/*" - git fetch origin - BASE_SHA="${{ fromJSON(steps.pr-details.outputs.result).base_sha }}" - HEAD_SHA="${{ fromJSON(steps.pr-details.outputs.result).head_sha }}" - - echo "Comparing $BASE_SHA..$HEAD_SHA" - - # Generate the full diff - git diff -U10 "$BASE_SHA" "$HEAD_SHA" > full_diff.txt - - # Use awk to properly capture full context of relevant files - awk ' - BEGIN { found=0; buffer="" } - /^diff --git/ { - if (found) { print buffer } - found=0; buffer="" - if ($0 ~ /\.(js|ts|py|cpp|h|java|cs)$/ && $0 !~ /(package-lock\.json|yarn\.lock|\.md|\.json)/) { - found=1 - } - } - { if (found) buffer = buffer $0 "\n" } - END { if (found) print buffer } - ' full_diff.txt > filtered_diff.txt - - # Check if we have any relevant changes - if [ ! -s filtered_diff.txt ]; then - echo "No relevant changes found" - echo "diff_size=0" >> $GITHUB_OUTPUT - exit 0 - fi - - # Get file size and content - DIFF_SIZE=$(wc -c < filtered_diff.txt) - echo "Found $DIFF_SIZE bytes of relevant changes" - echo "diff_size=$DIFF_SIZE" >> $GITHUB_OUTPUT - - # Prepare content for API request - DIFF_CONTENT=$(cat filtered_diff.txt) - - # Create prompt in a way that preserves formatting - PROMPT=$(cat << 'EOL' - You are performing a code review. Please analyze this code diff and provide a thorough review that covers: - - 1. Potential conflicts with existing codebase - 2. Code correctness and potential bugs - 3. Security vulnerabilities or risks - 4. Performance implications - 5. Maintainability and readability issues - 6. Adherence to best practices and coding standards - 7. Suggestions for improvements - - For each issue found: - - Explain the problem clearly - - Rate the severity (Critical/High/Medium/Low) - - Provide specific recommendations for fixes - - Include code examples where helpful - - If no issues are found in a particular area, explicitly state that. - - Here is the code diff to review: - - ``` - EOL - ) - - # Create API request - REQUEST=$(jq -n \ - --arg prompt "$PROMPT" \ - --arg diff "$DIFF_CONTENT" \ - '{ - model: "claude-3-sonnet-20240229", - max_tokens: 4096, - temperature: 0.7, - messages: [{ - role: "user", - content: ($prompt + "\n" + $diff + "\n```") - }] - }') - - # Call the API - echo "Sending request to Claude API..." - RESPONSE=$(curl -s https://api.anthropic.com/v1/messages \ - -H "Content-Type: application/json" \ - -H "x-api-key: $ANTHROPIC_API_KEY" \ - -H "anthropic-version: 2023-06-01" \ - -d "$REQUEST") - - # Process the response - if echo "$RESPONSE" | jq -e '.content[0].text' > /dev/null; then - { - echo 'review<> $GITHUB_OUTPUT - else - echo "Error in Claude API response: $RESPONSE" - echo "Request was: $REQUEST" - exit 1 - fi - - - name: Post review comment - if: success() && steps.analysis.outputs.diff_size != '0' - uses: actions/github-script@v7 + - name: Run Claude Review + uses: pacnpal/claude-code-review@v1.0.6 with: github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { owner, repo } = context.repo; - const prNumber = ${{ steps.pr-number.outputs.number }}; - - // Prepare review text - const reviewText = `${{ steps.analysis.outputs.review }}` - .replace(/(?<=[\s\n])`([^`]+)`(?=[\s\n])/g, '\\`$1\\`') - .replace(/```/g, '\\`\\`\\`') - .replace(/\${/g, '\\${'); - - await github.rest.issues.createComment({ - owner, - repo, - issue_number: prNumber, - body: "# Claude Code Review\n\n" + reviewText - }); + anthropic-key: ${{ secrets.ANTHROPIC_API_KEY }} + pr-number: ${{ github.event.pull_request.number || inputs.pr_number }}