Add manual PR review trigger via issue comments (#1959)

# READ CAREFULLY THEN REMOVE

Remove bullet points that are not relevant.

PLEASE REFRAIN FROM USING AI TO WRITE YOUR CODE AND PR DESCRIPTION. IF YOU DO USE AI TO WRITE YOUR CODE PLEASE PROVIDE A DESCRIPTION AND REVIEW IT CAREFULLY. MAKE SURE YOU UNDERSTAND THE CODE YOU ARE SUBMITTING USING AI.

- Pull requests that do not follow these guidelines will be closed without review or comment.
- If you use AI to write your PR description your pr will be close without review or comment.
- If you are unsure about anything, feel free to ask for clarification.

## Description

Please provide a clear description of your changes.

---

## Type of Change

Please delete options that are not relevant.

- [ ] 🐛 Bug fix (non-breaking change which fixes an issue)
- [ ]  New feature (non-breaking change which adds functionality)
- [ ] 💥 Breaking change (fix or feature with breaking changes)
- [ ] 📝 Documentation update
- [ ] 🎨 UI/UX improvement
- [ ] 🔒 Security enhancement
- [ ]  Performance improvement

## Areas Affected

Please check all that apply:

- [ ] Email Integration (Gmail, IMAP, etc.)
- [ ] User Interface/Experience
- [ ] Authentication/Authorization
- [ ] Data Storage/Management
- [ ] API Endpoints
- [ ] Documentation
- [ ] Testing Infrastructure
- [ ] Development Workflow
- [ ] Deployment/Infrastructure

## Testing Done

Describe the tests you've done:

- [ ] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] Manual testing performed
- [ ] Cross-browser testing (if UI changes)
- [ ] Mobile responsiveness verified (if UI changes)

## Security Considerations

For changes involving data or authentication:

- [ ] No sensitive data is exposed
- [ ] Authentication checks are in place
- [ ] Input validation is implemented
- [ ] Rate limiting is considered (if applicable)

## Checklist

- [ ] I have read the [CONTRIBUTING](https://github.com/Mail-0/Zero/blob/staging/.github/CONTRIBUTING.md) document
- [ ] My code follows the project's style guidelines
- [ ] I have performed a self-review of my code
- [ ] I have commented my code, particularly in complex areas
- [ ] I have updated the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix/feature works
- [ ] All tests pass locally
- [ ] Any dependent changes are merged and published

## Additional Notes

Add any other context about the pull request here.

## Screenshots/Recordings

Add screenshots or recordings here if applicable.

---

_By submitting this pull request, I confirm that my contribution is made under the terms of the project's license._

    
<!-- This is an auto-generated description by cubic. -->
---

## Summary by cubic
Added support for triggering automated PR reviews by commenting `/review` on a pull request, allowing manual review requests in addition to automatic triggers.

- **New Features**
  - Detects `/review` comments on PRs and runs the Ampcode review workflow.
  - Posts review results and reactions to indicate review status.

<!-- End of auto-generated description by cubic. -->
This commit is contained in:
Adam
2025-08-08 11:55:18 -07:00
committed by GitHub
parent 4e2cfdfd29
commit 9b96b64fff

View File

@@ -4,6 +4,8 @@ on:
pull_request:
types: [opened, ready_for_review, synchronize]
branches: [main, staging]
issue_comment:
types: [created]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -16,19 +18,27 @@ permissions:
jobs:
ampcode-review:
if: github.event.pull_request.draft == false
if: github.event_name == 'pull_request' && github.event.pull_request.draft == false
timeout-minutes: 15
runs-on: ubuntu-latest
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: ${{ github.event.pull_request.head.sha }}
ref: ${{ steps.pr-context.outputs.pr_sha }}
fetch-depth: 0
- name: Setup Node.js
@@ -50,8 +60,8 @@ jobs:
- name: Get changed files
id: changed-files
run: |
git fetch origin ${{ github.event.pull_request.base.ref }}
CHANGED_FILES=$(git diff --name-only origin/${{ github.event.pull_request.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 "")
git fetch origin ${{ steps.pr-context.outputs.pr_base_ref }}
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
@@ -62,13 +72,12 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Add a reaction to indicate review has started
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/${{ github.event.pull_request.number }}/reactions"
"https://api.github.com/repos/${{ github.repository }}/issues/${{ steps.pr-context.outputs.pr_number }}/reactions"
echo "Added 👀 reaction to indicate review has started"
@@ -79,16 +88,12 @@ jobs:
run: |
echo "Running ampcode review on changed files..."
# Create a temporary file with the changed files list
echo "${{ steps.changed-files.outputs.changed_files }}" > changed_files.txt
# Run ampcode review on the changed files with specific instructions for line-level feedback
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")
# Save review output to file
echo "$REVIEW_OUTPUT" > ampcode_review.txt
# Display review output for debugging
echo "=== Ampcode Review Output ==="
cat ampcode_review.txt
echo "=== End Review Output ==="
@@ -98,24 +103,18 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Check if review output exists and is not empty
if [ ! -f ampcode_review.txt ] || [ ! -s ampcode_review.txt ]; then
echo "No review output found or file is empty"
exit 0
fi
# Read the review output
REVIEW_CONTENT=$(cat ampcode_review.txt)
# Parse the review content for line-specific comments
# Look for patterns like "file.ts:123:issue description"
echo "$REVIEW_CONTENT" | grep -E '^[^:]+:[0-9]+:' > line_comments.txt || true
# If no line-specific comments found, create a general comment
if [ ! -s line_comments.txt ]; then
echo "No line-specific comments found, creating general review comment"
# Create a general PR review comment
jq -n \
--arg content "$REVIEW_CONTENT" \
--arg run_id "${{ github.run_id }}" \
@@ -125,39 +124,32 @@ jobs:
"event": "COMMENT"
}' > review_comment.json
# Post the general review comment
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/${{ github.event.pull_request.number }}/reviews"
"https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr-context.outputs.pr_number }}/reviews"
echo "General review comment posted successfully"
exit 0
fi
# Process line-specific comments
echo "Processing line-specific comments..."
# Initialize arrays for the review
declare -a comments=()
comment_count=0
# Read line comments and create GitHub review comments
while IFS= read -r line; do
# Parse the line: file:line:comment
file_path=$(echo "$line" | cut -d: -f1)
line_number=$(echo "$line" | cut -d: -f2)
comment_text=$(echo "$line" | cut -d: -f3-)
# Skip if file doesn't exist or line number is invalid
if [ ! -f "$file_path" ] || ! [[ "$line_number" =~ ^[0-9]+$ ]]; then
echo "Skipping invalid comment: $line"
continue
fi
# Create the comment object
comment_obj=$(jq -n \
--arg path "$file_path" \
--arg line "$line_number" \
@@ -174,9 +166,7 @@ jobs:
echo "Added comment for $file_path:$line_number"
done < line_comments.txt
# If we have comments, create the review
if [ $comment_count -gt 0 ]; then
# Create the review payload
jq -n \
--arg body "## 🤖 Automated Code Review by Ampcode\n\nI've reviewed the changes and found $comment_count issue(s) that need attention. Please review the inline comments below.\n\n---\n*Generated by [Ampcode](https://ampcode.com) • [View Workflow](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})*" \
--arg event "REQUEST_CHANGES" \
@@ -187,13 +177,12 @@ jobs:
"comments": $comments
}' > review_payload.json
# Post the review with line-specific comments
curl -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/${{ github.event.pull_request.number }}/reviews"
"https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr-context.outputs.pr_number }}/reviews"
echo "Posted review with $comment_count line-specific comments"
else
@@ -205,20 +194,18 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Add a reaction to indicate review has completed
curl -X POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
-H "Content-Type: application/json" \
-d '{"content":"white_check_mark"}' \
"https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/reactions"
"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: |
# Clean up temporary files
rm -f changed_files.txt ampcode_review.txt review_comment.json review_payload.json line_comments.txt
echo "Cleanup completed"
@@ -226,10 +213,231 @@ jobs:
if: always()
run: |
echo "=== Ampcode PR Review Summary ==="
echo "PR Number: ${{ github.event.pull_request.number }}"
echo "PR Title: ${{ github.event.pull_request.title }}"
echo "Base Branch: ${{ github.event.pull_request.base.ref }}"
echo "Head Branch: ${{ github.event.pull_request.head.ref }}"
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 ${{ steps.pr-context.outputs.pr_base_ref }}
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 Line-Specific Comments
if: steps.check-pr.outputs.is_pr == 'true' && steps.changed-files.outputs.changed_files != ''
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
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)
echo "$REVIEW_CONTENT" | grep -E '^[^:]+:[0-9]+:' > line_comments.txt || true
if [ ! -s line_comments.txt ]; then
echo "No line-specific comments found, creating general review 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\nI'\''ve analyzed the changes in this PR using AI-powered code review. Here are my findings:\n\n### 📋 Review Results\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"
echo "General review comment posted successfully"
exit 0
fi
echo "Processing line-specific comments..."
declare -a comments=()
comment_count=0
while IFS= read -r line; do
file_path=$(echo "$line" | cut -d: -f1)
line_number=$(echo "$line" | cut -d: -f2)
comment_text=$(echo "$line" | cut -d: -f3-)
if [ ! -f "$file_path" ] || ! [[ "$line_number" =~ ^[0-9]+$ ]]; then
echo "Skipping invalid comment: $line"
continue
fi
comment_obj=$(jq -n \
--arg path "$file_path" \
--arg line "$line_number" \
--arg body "🤖 **Ampcode Review:** $comment_text" \
'{
"path": $path,
"line": ($line | tonumber),
"body": $body
}')
comments+=("$comment_obj")
comment_count=$((comment_count + 1))
echo "Added comment for $file_path:$line_number"
done < line_comments.txt
if [ $comment_count -gt 0 ]; then
jq -n \
--arg body "## 🤖 Automated Code Review by Ampcode\n\nI've reviewed the changes and found $comment_count issue(s) that need attention. Please review the inline comments below.\n\n---\n*Generated by [Ampcode](https://ampcode.com) • [View Workflow](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})*" \
--arg event "REQUEST_CHANGES" \
--argjson comments "$(printf '%s\n' "${comments[@]}" | jq -s .)" \
'{
"body": $body,
"event": $event,
"comments": $comments
}' > review_payload.json
curl -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"
echo "Posted review with $comment_count line-specific comments"
else
echo "No valid line-specific comments to post"
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":"white_check_mark"}' \
"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 line_comments.txt
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 ==="