Update git fetch command to use --prune flag in PR review workflows #4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Ampcode PR Review | |
| on: | |
| pull_request: | |
| types: [opened, ready_for_review, synchronize] | |
| branches: [main, staging] | |
| issue_comment: | |
| types: [created] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| jobs: | |
| ampcode-review: | |
| if: github.event_name == 'pull_request' && github.event.pull_request.draft == false | |
| timeout-minutes: 15 | |
| runs-on: ${{ vars.RUNNER_IMAGE || 'ubuntu-latest' }} | |
| strategy: | |
| matrix: | |
| review-chunk: [1] | |
| max-parallel: 3 | |
| steps: | |
| - name: Set PR context | |
| id: pr-context | |
| run: | | |
| echo "pr_number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT | |
| echo "pr_sha=${{ github.event.pull_request.head.sha }}" >> $GITHUB_OUTPUT | |
| echo "pr_base_ref=${{ github.event.pull_request.base.ref }}" >> $GITHUB_OUTPUT | |
| echo "trigger_type=automatic" >> $GITHUB_OUTPUT | |
| - name: Checkout PR branch | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ steps.pr-context.outputs.pr_sha }} | |
| fetch-depth: 0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Install Ampcode CLI | |
| run: | | |
| npm install -g @sourcegraph/amp | |
| amp --version | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| - name: Install project dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Get changed files | |
| id: changed-files | |
| run: | | |
| git fetch origin --prune | |
| CHANGED_FILES=$(git diff --name-only origin/${{ steps.pr-context.outputs.pr_base_ref }}..HEAD | grep -E '\.(ts|tsx|js|jsx|py|go|java|cpp|c|h|hpp|rs|rb|php|cs|swift|kt|scala|clj|hs|ml|fs|elm|dart|lua|r|sql|sh|bash|zsh|fish|ps1|bat|cmd|yaml|yml|json|toml|ini|cfg|conf|xml|html|css|scss|sass|less|styl|vue|svelte|astro|md|mdx|tex|latex|bib|org|rst|adoc|asciidoc|wiki|txt)$' | head -50 || echo "") | |
| echo "changed_files<<EOF" >> $GITHUB_OUTPUT | |
| echo "$CHANGED_FILES" >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| echo "Changed files count: $(echo "$CHANGED_FILES" | wc -l)" | |
| - name: Add Review Started Reaction | |
| if: steps.changed-files.outputs.changed_files != '' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| curl -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{"content":"eyes"}' \ | |
| "https://api.github.com/repos/${{ github.repository }}/issues/${{ steps.pr-context.outputs.pr_number }}/reactions" | |
| echo "Added 👀 reaction to indicate review has started" | |
| - name: Run Ampcode Review | |
| if: steps.changed-files.outputs.changed_files != '' | |
| env: | |
| AMP_API_KEY: ${{ secrets.AMPCODE_API_KEY }} | |
| run: | | |
| echo "Running ampcode review on changed files..." | |
| echo "${{ steps.changed-files.outputs.changed_files }}" > changed_files.txt | |
| REVIEW_OUTPUT=$(amp -x "Review the following files for code quality, potential bugs, security issues, performance concerns, and best practices. For each issue found, provide the specific file path and line number where the issue occurs. Format your response as: FILE:line_number:issue_description. Focus on providing specific, actionable feedback with exact line numbers. Files to review: $(cat changed_files.txt | tr '\n' ' ')" 2>&1 || echo "Ampcode review failed") | |
| echo "$REVIEW_OUTPUT" > ampcode_review.txt | |
| echo "=== Ampcode Review Output ===" | |
| cat ampcode_review.txt | |
| echo "=== End Review Output ===" | |
| - name: Parse and Post Comments with Python | |
| if: steps.changed-files.outputs.changed_files != '' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| COMMIT_SHA: ${{ steps.pr-context.outputs.pr_sha }} | |
| run: | | |
| if [ ! -f ampcode_review.txt ] || [ ! -s ampcode_review.txt ]; then | |
| echo "No review output found or file is empty" | |
| exit 0 | |
| fi | |
| REVIEW_CONTENT=$(cat ampcode_review.txt) | |
| # Extract line-specific comments in format FILE:line_number:issue_description | |
| echo "$REVIEW_CONTENT" | grep -E '^[[:space:]-]*[^[:space:]]+\.[a-zA-Z0-9]+[[:space:]]*[: ]+[Ll]?[iI]?[nN]?[eE]?[[:space:]]*[0-9]+' > line_comments.txt || true | |
| if [ ! -s line_comments.txt ]; then | |
| echo "No line-specific comments found, creating multiple smaller comments" | |
| # Split the review content into smaller chunks and create multiple comments | |
| echo "$REVIEW_CONTENT" | awk ' | |
| BEGIN { | |
| chunk_size = 1000 | |
| chunk_count = 0 | |
| current_chunk = "" | |
| line_count = 0 | |
| } | |
| { | |
| if (length(current_chunk) + length($0) > chunk_size && current_chunk != "") { | |
| chunk_count++ | |
| print "=== CHUNK " chunk_count " ===" > "chunk_" chunk_count ".txt" | |
| print current_chunk > "chunk_" chunk_count ".txt" | |
| current_chunk = $0 | |
| line_count = 1 | |
| } else { | |
| if (current_chunk != "") current_chunk = current_chunk "\n" | |
| current_chunk = current_chunk $0 | |
| line_count++ | |
| } | |
| } | |
| END { | |
| if (current_chunk != "") { | |
| chunk_count++ | |
| print "=== CHUNK " chunk_count " ===" > "chunk_" chunk_count ".txt" | |
| print current_chunk > "chunk_" chunk_count ".txt" | |
| } | |
| print chunk_count > "total_chunks.txt" | |
| }' | |
| TOTAL_CHUNKS=$(cat total_chunks.txt 2>/dev/null || echo "0") | |
| if [ "$TOTAL_CHUNKS" -gt 0 ]; then | |
| echo "Creating $TOTAL_CHUNKS smaller review comments..." | |
| for i in $(seq 1 $TOTAL_CHUNKS); do | |
| if [ -f "chunk_$i.txt" ]; then | |
| CHUNK_CONTENT=$(cat "chunk_$i.txt") | |
| jq -n \ | |
| --arg content "$CHUNK_CONTENT" \ | |
| --arg run_id "${{ github.run_id }}" \ | |
| --arg repo "${{ github.repository }}" \ | |
| --arg chunk_num "$i" \ | |
| --arg total_chunks "$TOTAL_CHUNKS" \ | |
| '{ | |
| "body": ("## 🤖 Automated Code Review by Ampcode (Part " + $chunk_num + "/" + $total_chunks + ")\n\n**Review Summary:**\n\n```\n" + $content + "\n```\n\n### 🔍 Key Areas Reviewed\n- Code quality and best practices\n- Potential bugs and security issues\n- Performance considerations\n- Maintainability and readability\n\n### 📝 Notes\n- This is an automated review generated by Ampcode AI\n- Please review the suggestions and apply them as appropriate\n- For questions about specific recommendations, feel free to ask!\n\n---\n*Generated by [Ampcode](https://ampcode.com) • [View Workflow](https://github.com/" + $repo + "/actions/runs/" + $run_id + ")*"), | |
| "event": "COMMENT" | |
| }' > "review_comment_$i.json" | |
| curl -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d @"review_comment_$i.json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr-context.outputs.pr_number }}/reviews" | |
| echo "Posted review comment part $i/$TOTAL_CHUNKS" | |
| sleep 1 | |
| fi | |
| done | |
| else | |
| # Fallback to single comment if chunking failed | |
| jq -n \ | |
| --arg content "$REVIEW_CONTENT" \ | |
| --arg run_id "${{ github.run_id }}" \ | |
| --arg repo "${{ github.repository }}" \ | |
| '{ | |
| "body": ("## 🤖 Automated Code Review by Ampcode\n\n**Review Summary:**\n\n```\n" + $content + "\n```\n\n### 🔍 Key Areas Reviewed\n- Code quality and best practices\n- Potential bugs and security issues\n- Performance considerations\n- Maintainability and readability\n\n### 📝 Notes\n- This is an automated review generated by Ampcode AI\n- Please review the suggestions and apply them as appropriate\n- For questions about specific recommendations, feel free to ask!\n\n---\n*Generated by [Ampcode](https://ampcode.com) • [View Workflow](https://github.com/" + $repo + "/actions/runs/" + $run_id + ")*"), | |
| "event": "COMMENT" | |
| }' > review_comment.json | |
| curl -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d @review_comment.json \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr-context.outputs.pr_number }}/reviews" | |
| fi | |
| echo "Multiple smaller review comments posted successfully" | |
| exit 0 | |
| fi | |
| echo "Processing line-specific comments..." | |
| # Get the actual diff to compute GitHub diff positions | |
| git diff origin/${{ steps.pr-context.outputs.pr_base_ref }}..HEAD > actual_diff.patch | |
| # Fetch PR files with GitHub-calculated patch chunks for exact diff positions | |
| curl -s \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github+json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr-context.outputs.pr_number }}/files?per_page=100" \ | |
| > pr_files.json | |
| # Install TypeScript dependencies and run the parser script | |
| cd .github/scripts | |
| npm install | |
| npm run build | |
| node dist/parse-review-comments.js | |
| cd ../.. | |
| if [ -f review_payload.json ]; then | |
| response=$(curl -s -w "\n%{http_code}" -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d @review_payload.json \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr-context.outputs.pr_number }}/reviews") | |
| http_code=$(echo "$response" | tail -n1) | |
| body=$(echo "$response" | head -n -1) | |
| if [ "$http_code" = "200" ] || [ "$http_code" = "201" ]; then | |
| echo "Posted review with inline comments successfully" | |
| else | |
| echo "Posting review failed (HTTP $http_code). Falling back to multiple smaller comments." | |
| echo "$body" | |
| # Fall back to multiple smaller comments | |
| echo "$REVIEW_CONTENT" | awk ' | |
| BEGIN { | |
| chunk_size = 1000 | |
| chunk_count = 0 | |
| current_chunk = "" | |
| } | |
| { | |
| if (length(current_chunk) + length($0) > chunk_size && current_chunk != "") { | |
| chunk_count++ | |
| print "=== CHUNK " chunk_count " ===" > "chunk_" chunk_count ".txt" | |
| print current_chunk > "chunk_" chunk_count ".txt" | |
| current_chunk = $0 | |
| } else { | |
| if (current_chunk != "") current_chunk = current_chunk "\n" | |
| current_chunk = current_chunk $0 | |
| } | |
| } | |
| END { | |
| if (current_chunk != "") { | |
| chunk_count++ | |
| print "=== CHUNK " chunk_count " ===" > "chunk_" chunk_count ".txt" | |
| print current_chunk > "chunk_" chunk_count ".txt" | |
| } | |
| print chunk_count > "total_chunks.txt" | |
| }' | |
| TOTAL_CHUNKS=$(cat total_chunks.txt 2>/dev/null || echo "0") | |
| if [ "$TOTAL_CHUNKS" -gt 0 ]; then | |
| for i in $(seq 1 $TOTAL_CHUNKS); do | |
| if [ -f "chunk_$i.txt" ]; then | |
| CHUNK_CONTENT=$(cat "chunk_$i.txt") | |
| jq -n \ | |
| --arg content "$CHUNK_CONTENT" \ | |
| --arg run_id "${{ github.run_id }}" \ | |
| --arg repo "${{ github.repository }}" \ | |
| --arg chunk_num "$i" \ | |
| --arg total_chunks "$TOTAL_CHUNKS" \ | |
| '{ | |
| "body": ("## 🤖 Automated Code Review by Ampcode (Part " + $chunk_num + "/" + $total_chunks + ")\n\n**Review Summary:**\n\n```\n" + $content + "\n```\n\n---\n*Generated by [Ampcode](https://ampcode.com) • [View Workflow](https://github.com/" + $repo + "/actions/runs/" + $run_id + ")*"), | |
| "event": "COMMENT" | |
| }' > "review_comment_fallback_$i.json" | |
| curl -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d @"review_comment_fallback_$i.json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr-context.outputs.pr_number }}/reviews" | |
| echo "Posted fallback review comment part $i/$TOTAL_CHUNKS" | |
| sleep 1 | |
| fi | |
| done | |
| fi | |
| fi | |
| else | |
| echo "No valid inline comments; posting multiple smaller review comments" | |
| echo "$REVIEW_CONTENT" | awk ' | |
| BEGIN { | |
| chunk_size = 1000 | |
| chunk_count = 0 | |
| current_chunk = "" | |
| } | |
| { | |
| if (length(current_chunk) + length($0) > chunk_size && current_chunk != "") { | |
| chunk_count++ | |
| print "=== CHUNK " chunk_count " ===" > "chunk_" chunk_count ".txt" | |
| print current_chunk > "chunk_" chunk_count ".txt" | |
| current_chunk = $0 | |
| } else { | |
| if (current_chunk != "") current_chunk = current_chunk "\n" | |
| current_chunk = current_chunk $0 | |
| } | |
| } | |
| END { | |
| if (current_chunk != "") { | |
| chunk_count++ | |
| print "=== CHUNK " chunk_count " ===" > "chunk_" chunk_count ".txt" | |
| print current_chunk > "chunk_" chunk_count ".txt" | |
| } | |
| print chunk_count > "total_chunks.txt" | |
| }' | |
| TOTAL_CHUNKS=$(cat total_chunks.txt 2>/dev/null || echo "0") | |
| if [ "$TOTAL_CHUNKS" -gt 0 ]; then | |
| for i in $(seq 1 $TOTAL_CHUNKS); do | |
| if [ -f "chunk_$i.txt" ]; then | |
| CHUNK_CONTENT=$(cat "chunk_$i.txt") | |
| jq -n \ | |
| --arg content "$CHUNK_CONTENT" \ | |
| --arg run_id "${{ github.run_id }}" \ | |
| --arg repo "${{ github.repository }}" \ | |
| --arg chunk_num "$i" \ | |
| --arg total_chunks "$TOTAL_CHUNKS" \ | |
| '{ | |
| "body": ("## 🤖 Automated Code Review by Ampcode (Part " + $chunk_num + "/" + $total_chunks + ")\n\n**Review Summary:**\n\n```\n" + $content + "\n```\n\n---\n*Generated by [Ampcode](https://ampcode.com) • [View Workflow](https://github.com/" + $repo + "/actions/runs/" + $run_id + ")*"), | |
| "event": "COMMENT" | |
| }' > "review_comment_$i.json" | |
| curl -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d @"review_comment_$i.json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr-context.outputs.pr_number }}/reviews" | |
| echo "Posted review comment part $i/$TOTAL_CHUNKS" | |
| sleep 1 | |
| fi | |
| done | |
| else | |
| # Final fallback to single comment | |
| jq -n \ | |
| --arg content "$REVIEW_CONTENT" \ | |
| --arg run_id "${{ github.run_id }}" \ | |
| --arg repo "${{ github.repository }}" \ | |
| '{ | |
| "body": ("## 🤖 Automated Code Review by Ampcode\n\n**Review Summary:**\n\n```\n" + $content + "\n```\n\n---\n*Generated by [Ampcode](https://ampcode.com) • [View Workflow](https://github.com/" + $repo + "/actions/runs/" + $run_id + ")*"), | |
| "event": "COMMENT" | |
| }' > review_comment.json | |
| curl -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d @review_comment.json \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr-context.outputs.pr_number }}/reviews" | |
| fi | |
| fi | |
| - name: Add Review Completed Reaction | |
| if: always() && steps.changed-files.outputs.changed_files != '' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| curl -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{"content":"hooray"}' \ | |
| "https://api.github.com/repos/${{ github.repository }}/issues/${{ steps.pr-context.outputs.pr_number }}/reactions" | |
| echo "Added ✅ reaction to indicate review has completed" | |
| - name: Cleanup | |
| if: always() | |
| run: | | |
| rm -f changed_files.txt ampcode_review.txt review_comment.json review_payload.json review_comment_fallback.json line_comments.txt actual_diff.patch | |
| rm -f chunk_*.txt total_chunks.txt review_comment_*.json review_comment_fallback_*.json | |
| echo "Cleanup completed" | |
| - name: Summary | |
| if: always() | |
| run: | | |
| echo "=== Ampcode PR Review Summary ===" | |
| echo "PR Number: ${{ steps.pr-context.outputs.pr_number }}" | |
| echo "Trigger Type: ${{ steps.pr-context.outputs.trigger_type }}" | |
| echo "Changed Files: $(echo '${{ steps.changed-files.outputs.changed_files }}' | wc -l)" | |
| echo "Review Status: $([ -f ampcode_review.txt ] && echo 'Completed' || echo 'Skipped')" | |
| echo "=== End Summary ===" | |
| manual-review: | |
| if: github.event_name == 'issue_comment' && contains(github.event.comment.body, '/review') | |
| timeout-minutes: 15 | |
| runs-on: ${{ vars.RUNNER_IMAGE || 'ubuntu-latest' }} | |
| strategy: | |
| matrix: | |
| review-chunk: [1] | |
| max-parallel: 3 | |
| steps: | |
| - name: Check if comment is on a PR | |
| id: check-pr | |
| run: | | |
| if [[ "${{ github.event.issue.pull_request }}" == "" ]]; then | |
| echo "This is not a PR, skipping review" | |
| echo "is_pr=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| else | |
| echo "is_pr=true" >> $GITHUB_OUTPUT | |
| echo "PR URL: ${{ github.event.issue.pull_request.url }}" | |
| fi | |
| - name: Set PR context | |
| if: steps.check-pr.outputs.is_pr == 'true' | |
| id: pr-context | |
| run: | | |
| echo "pr_number=${{ github.event.issue.number }}" >> $GITHUB_OUTPUT | |
| echo "pr_sha=${{ github.event.pull_request.head.sha }}" >> $GITHUB_OUTPUT | |
| echo "pr_base_ref=${{ github.event.pull_request.base.ref }}" >> $GITHUB_OUTPUT | |
| echo "trigger_type=manual" >> $GITHUB_OUTPUT | |
| echo "comment_author=${{ github.event.comment.user.login }}" >> $GITHUB_OUTPUT | |
| - name: Checkout PR branch | |
| if: steps.check-pr.outputs.is_pr == 'true' | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ steps.pr-context.outputs.pr_sha }} | |
| fetch-depth: 0 | |
| - name: Setup Node.js | |
| if: steps.check-pr.outputs.is_pr == 'true' | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Install Ampcode CLI | |
| if: steps.check-pr.outputs.is_pr == 'true' | |
| run: | | |
| npm install -g @sourcegraph/amp | |
| amp --version | |
| - name: Setup pnpm | |
| if: steps.check-pr.outputs.is_pr == 'true' | |
| uses: pnpm/action-setup@v4 | |
| - name: Install project dependencies | |
| if: steps.check-pr.outputs.is_pr == 'true' | |
| run: pnpm install --frozen-lockfile | |
| - name: Get changed files | |
| if: steps.check-pr.outputs.is_pr == 'true' | |
| id: changed-files | |
| run: | | |
| git fetch origin --prune | |
| CHANGED_FILES=$(git diff --name-only origin/${{ steps.pr-context.outputs.pr_base_ref }}..HEAD | grep -E '\.(ts|tsx|js|jsx|py|go|java|cpp|c|h|hpp|rs|rb|php|cs|swift|kt|scala|clj|hs|ml|fs|elm|dart|lua|r|sql|sh|bash|zsh|fish|ps1|bat|cmd|yaml|yml|json|toml|ini|cfg|conf|xml|html|css|scss|sass|less|styl|vue|svelte|astro|md|mdx|tex|latex|bib|org|rst|adoc|asciidoc|wiki|txt)$' | head -50 || echo "") | |
| echo "changed_files<<EOF" >> $GITHUB_OUTPUT | |
| echo "$CHANGED_FILES" >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| echo "Changed files count: $(echo "$CHANGED_FILES" | wc -l)" | |
| - name: Add Review Started Reaction | |
| if: steps.check-pr.outputs.is_pr == 'true' && steps.changed-files.outputs.changed_files != '' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| curl -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{"content":"eyes"}' \ | |
| "https://api.github.com/repos/${{ github.repository }}/issues/${{ steps.pr-context.outputs.pr_number }}/reactions" | |
| echo "Added 👀 reaction to indicate review has started" | |
| - name: Run Ampcode Review | |
| if: steps.check-pr.outputs.is_pr == 'true' && steps.changed-files.outputs.changed_files != '' | |
| env: | |
| AMP_API_KEY: ${{ secrets.AMPCODE_API_KEY }} | |
| run: | | |
| echo "Running ampcode review on changed files..." | |
| echo "${{ steps.changed-files.outputs.changed_files }}" > changed_files.txt | |
| REVIEW_OUTPUT=$(amp -x "Review the following files for code quality, potential bugs, security issues, performance concerns, and best practices. For each issue found, provide the specific file path and line number where the issue occurs. Format your response as: FILE:line_number:issue_description. Focus on providing specific, actionable feedback with exact line numbers. Files to review: $(cat changed_files.txt | tr '\n' ' ')" 2>&1 || echo "Ampcode review failed") | |
| echo "$REVIEW_OUTPUT" > ampcode_review.txt | |
| echo "=== Ampcode Review Output ===" | |
| cat ampcode_review.txt | |
| echo "=== End Review Output ===" | |
| - name: Parse and Post Comments with Python | |
| if: steps.check-pr.outputs.is_pr == 'true' && steps.changed-files.outputs.changed_files != '' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| COMMIT_SHA: ${{ steps.pr-context.outputs.pr_sha }} | |
| run: | | |
| if [ ! -f ampcode_review.txt ] || [ ! -s ampcode_review.txt ]; then | |
| echo "No review output found or file is empty" | |
| exit 0 | |
| fi | |
| REVIEW_CONTENT=$(cat ampcode_review.txt) | |
| # Extract line-specific comments in format FILE:line_number:issue_description | |
| echo "$REVIEW_CONTENT" | grep -E '^[[:space:]-]*[^[:space:]]+\.[a-zA-Z0-9]+[[:space:]]*[: ]+[Ll]?[iI]?[nN]?[eE]?[[:space:]]*[0-9]+' > line_comments.txt || true | |
| if [ ! -s line_comments.txt ]; then | |
| echo "No line-specific comments found, creating multiple smaller comments" | |
| # Split the review content into smaller chunks and create multiple comments | |
| echo "$REVIEW_CONTENT" | awk ' | |
| BEGIN { | |
| chunk_size = 1000 | |
| chunk_count = 0 | |
| current_chunk = "" | |
| line_count = 0 | |
| } | |
| { | |
| if (length(current_chunk) + length($0) > chunk_size && current_chunk != "") { | |
| chunk_count++ | |
| print "=== CHUNK " chunk_count " ===" > "chunk_" chunk_count ".txt" | |
| print current_chunk > "chunk_" chunk_count ".txt" | |
| current_chunk = $0 | |
| line_count = 1 | |
| } else { | |
| if (current_chunk != "") current_chunk = current_chunk "\n" | |
| current_chunk = current_chunk $0 | |
| line_count++ | |
| } | |
| } | |
| END { | |
| if (current_chunk != "") { | |
| chunk_count++ | |
| print "=== CHUNK " chunk_count " ===" > "chunk_" chunk_count ".txt" | |
| print current_chunk > "chunk_" chunk_count ".txt" | |
| } | |
| print chunk_count > "total_chunks.txt" | |
| }' | |
| TOTAL_CHUNKS=$(cat total_chunks.txt 2>/dev/null || echo "0") | |
| if [ "$TOTAL_CHUNKS" -gt 0 ]; then | |
| echo "Creating $TOTAL_CHUNKS smaller review comments..." | |
| for i in $(seq 1 $TOTAL_CHUNKS); do | |
| if [ -f "chunk_$i.txt" ]; then | |
| CHUNK_CONTENT=$(cat "chunk_$i.txt") | |
| jq -n \ | |
| --arg content "$CHUNK_CONTENT" \ | |
| --arg run_id "${{ github.run_id }}" \ | |
| --arg repo "${{ github.repository }}" \ | |
| --arg chunk_num "$i" \ | |
| --arg total_chunks "$TOTAL_CHUNKS" \ | |
| '{ | |
| "body": ("## 🤖 Automated Code Review by Ampcode (Part " + $chunk_num + "/" + $total_chunks + ")\n\n**Review Summary:**\n\n```\n" + $content + "\n```\n\n### 🔍 Key Areas Reviewed\n- Code quality and best practices\n- Potential bugs and security issues\n- Performance considerations\n- Maintainability and readability\n\n### 📝 Notes\n- This is an automated review generated by Ampcode AI\n- Please review the suggestions and apply them as appropriate\n- For questions about specific recommendations, feel free to ask!\n\n---\n*Generated by [Ampcode](https://ampcode.com) • [View Workflow](https://github.com/" + $repo + "/actions/runs/" + $run_id + ")*"), | |
| "event": "COMMENT" | |
| }' > "review_comment_$i.json" | |
| curl -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d @"review_comment_$i.json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr-context.outputs.pr_number }}/reviews" | |
| echo "Posted review comment part $i/$TOTAL_CHUNKS" | |
| sleep 1 | |
| fi | |
| done | |
| else | |
| # Fallback to single comment if chunking failed | |
| jq -n \ | |
| --arg content "$REVIEW_CONTENT" \ | |
| --arg run_id "${{ github.run_id }}" \ | |
| --arg repo "${{ github.repository }}" \ | |
| '{ | |
| "body": ("## 🤖 Automated Code Review by Ampcode\n\n**Review Summary:**\n\n```\n" + $content + "\n```\n\n### 🔍 Key Areas Reviewed\n- Code quality and best practices\n- Potential bugs and security issues\n- Performance considerations\n- Maintainability and readability\n\n### 📝 Notes\n- This is an automated review generated by Ampcode AI\n- Please review the suggestions and apply them as appropriate\n- For questions about specific recommendations, feel free to ask!\n\n---\n*Generated by [Ampcode](https://ampcode.com) • [View Workflow](https://github.com/" + $repo + "/actions/runs/" + $run_id + ")*"), | |
| "event": "COMMENT" | |
| }' > review_comment.json | |
| curl -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d @review_comment.json \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr-context.outputs.pr_number }}/reviews" | |
| fi | |
| echo "Multiple smaller review comments posted successfully" | |
| exit 0 | |
| fi | |
| echo "Processing line-specific comments..." | |
| git diff origin/${{ steps.pr-context.outputs.pr_base_ref }}..HEAD > actual_diff.patch | |
| # Fetch PR files with GitHub-calculated patch chunks for exact diff positions | |
| curl -s \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github+json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr-context.outputs.pr_number }}/files?per_page=100" \ | |
| > pr_files.json | |
| # Install TypeScript dependencies and run the parser script | |
| cd .github/scripts | |
| npm install | |
| npm run build | |
| node dist/parse-review-comments.js | |
| cd ../.. | |
| if [ -f review_payload.json ]; then | |
| response=$(curl -s -w "\n%{http_code}" -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d @review_payload.json \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr-context.outputs.pr_number }}/reviews") | |
| http_code=$(echo "$response" | tail -n1) | |
| body=$(echo "$response" | head -n -1) | |
| if [ "$http_code" = "200" ] || [ "$http_code" = "201" ]; then | |
| echo "Posted review with inline comments successfully" | |
| else | |
| echo "Posting review failed (HTTP $http_code). Falling back to multiple smaller comments." | |
| echo "$body" | |
| # Fall back to multiple smaller comments | |
| echo "$REVIEW_CONTENT" | awk ' | |
| BEGIN { | |
| chunk_size = 1000 | |
| chunk_count = 0 | |
| current_chunk = "" | |
| } | |
| { | |
| if (length(current_chunk) + length($0) > chunk_size && current_chunk != "") { | |
| chunk_count++ | |
| print "=== CHUNK " chunk_count " ===" > "chunk_" chunk_count ".txt" | |
| print current_chunk > "chunk_" chunk_count ".txt" | |
| current_chunk = $0 | |
| } else { | |
| if (current_chunk != "") current_chunk = current_chunk "\n" | |
| current_chunk = current_chunk $0 | |
| } | |
| } | |
| END { | |
| if (current_chunk != "") { | |
| chunk_count++ | |
| print "=== CHUNK " chunk_count " ===" > "chunk_" chunk_count ".txt" | |
| print current_chunk > "chunk_" chunk_count ".txt" | |
| } | |
| print chunk_count > "total_chunks.txt" | |
| }' | |
| TOTAL_CHUNKS=$(cat total_chunks.txt 2>/dev/null || echo "0") | |
| if [ "$TOTAL_CHUNKS" -gt 0 ]; then | |
| for i in $(seq 1 $TOTAL_CHUNKS); do | |
| if [ -f "chunk_$i.txt" ]; then | |
| CHUNK_CONTENT=$(cat "chunk_$i.txt") | |
| jq -n \ | |
| --arg content "$CHUNK_CONTENT" \ | |
| --arg run_id "${{ github.run_id }}" \ | |
| --arg repo "${{ github.repository }}" \ | |
| --arg chunk_num "$i" \ | |
| --arg total_chunks "$TOTAL_CHUNKS" \ | |
| '{ | |
| "body": ("## 🤖 Automated Code Review by Ampcode (Part " + $chunk_num + "/" + $total_chunks + ")\n\n**Review Summary:**\n\n```\n" + $content + "\n```\n\n---\n*Generated by [Ampcode](https://ampcode.com) • [View Workflow](https://github.com/" + $repo + "/actions/runs/" + $run_id + ")*"), | |
| "event": "COMMENT" | |
| }' > "review_comment_fallback_$i.json" | |
| curl -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d @"review_comment_fallback_$i.json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr-context.outputs.pr_number }}/reviews" | |
| echo "Posted fallback review comment part $i/$TOTAL_CHUNKS" | |
| sleep 1 | |
| fi | |
| done | |
| fi | |
| fi | |
| else | |
| echo "No valid inline comments; posting multiple smaller review comments" | |
| echo "$REVIEW_CONTENT" | awk ' | |
| BEGIN { | |
| chunk_size = 1000 | |
| chunk_count = 0 | |
| current_chunk = "" | |
| } | |
| { | |
| if (length(current_chunk) + length($0) > chunk_size && current_chunk != "") { | |
| chunk_count++ | |
| print "=== CHUNK " chunk_count " ===" > "chunk_" chunk_count ".txt" | |
| print current_chunk > "chunk_" chunk_count ".txt" | |
| current_chunk = $0 | |
| } else { | |
| if (current_chunk != "") current_chunk = current_chunk "\n" | |
| current_chunk = current_chunk $0 | |
| } | |
| } | |
| END { | |
| if (current_chunk != "") { | |
| chunk_count++ | |
| print "=== CHUNK " chunk_count " ===" > "chunk_" chunk_count ".txt" | |
| print current_chunk > "chunk_" chunk_count ".txt" | |
| } | |
| print chunk_count > "total_chunks.txt" | |
| }' | |
| TOTAL_CHUNKS=$(cat total_chunks.txt 2>/dev/null || echo "0") | |
| if [ "$TOTAL_CHUNKS" -gt 0 ]; then | |
| for i in $(seq 1 $TOTAL_CHUNKS); do | |
| if [ -f "chunk_$i.txt" ]; then | |
| CHUNK_CONTENT=$(cat "chunk_$i.txt") | |
| jq -n \ | |
| --arg content "$CHUNK_CONTENT" \ | |
| --arg run_id "${{ github.run_id }}" \ | |
| --arg repo "${{ github.repository }}" \ | |
| --arg chunk_num "$i" \ | |
| --arg total_chunks "$TOTAL_CHUNKS" \ | |
| '{ | |
| "body": ("## 🤖 Automated Code Review by Ampcode (Part " + $chunk_num + "/" + $total_chunks + ")\n\n**Review Summary:**\n\n```\n" + $content + "\n```\n\n---\n*Generated by [Ampcode](https://ampcode.com) • [View Workflow](https://github.com/" + $repo + "/actions/runs/" + $run_id + ")*"), | |
| "event": "COMMENT" | |
| }' > "review_comment_$i.json" | |
| curl -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d @"review_comment_$i.json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr-context.outputs.pr_number }}/reviews" | |
| echo "Posted review comment part $i/$TOTAL_CHUNKS" | |
| sleep 1 | |
| fi | |
| done | |
| else | |
| # Final fallback to single comment | |
| jq -n \ | |
| --arg content "$REVIEW_CONTENT" \ | |
| --arg run_id "${{ github.run_id }}" \ | |
| --arg repo "${{ github.repository }}" \ | |
| '{ | |
| "body": ("## 🤖 Automated Code Review by Ampcode\n\n**Review Summary:**\n\n```\n" + $content + "\n```\n\n---\n*Generated by [Ampcode](https://ampcode.com) • [View Workflow](https://github.com/" + $repo + "/actions/runs/" + $run_id + ")*"), | |
| "event": "COMMENT" | |
| }' > review_comment.json | |
| curl -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d @review_comment.json \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr-context.outputs.pr_number }}/reviews" | |
| fi | |
| fi | |
| - name: Add Review Completed Reaction | |
| if: always() && steps.check-pr.outputs.is_pr == 'true' && steps.changed-files.outputs.changed_files != '' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| curl -X POST \ | |
| -H "Authorization: token $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{"content":"hooray"}' \ | |
| "https://api.github.com/repos/${{ github.repository }}/issues/${{ steps.pr-context.outputs.pr_number }}/reactions" | |
| echo "Added ✅ reaction to indicate review has completed" | |
| - name: Cleanup | |
| if: always() && steps.check-pr.outputs.is_pr == 'true' | |
| run: | | |
| rm -f changed_files.txt ampcode_review.txt review_comment.json review_payload.json review_comment_fallback.json line_comments.txt actual_diff.patch | |
| rm -f chunk_*.txt total_chunks.txt review_comment_*.json review_comment_fallback_*.json | |
| echo "Cleanup completed" | |
| - name: Summary | |
| if: always() && steps.check-pr.outputs.is_pr == 'true' | |
| run: | | |
| echo "=== Ampcode Manual PR Review Summary ===" | |
| echo "PR Number: ${{ steps.pr-context.outputs.pr_number }}" | |
| echo "Trigger Type: ${{ steps.pr-context.outputs.trigger_type }}" | |
| echo "Comment Author: ${{ steps.pr-context.outputs.comment_author }}" | |
| echo "Changed Files: $(echo '${{ steps.changed-files.outputs.changed_files }}' | wc -l)" | |
| echo "Review Status: $([ -f ampcode_review.txt ] && echo 'Completed' || echo 'Skipped')" | |
| echo "=== End Summary ===" |