Add Stage 1 workflow for external PR info collection
- Collects PR information without requiring secrets - Triggers on pull_request events and @claude-review-ext comments - Uploads PR details as artifact for secure processing
This commit is contained in:
parent
46e8358422
commit
d64745991b
231
.github/workflows/claude-review-ext-stage1.yml
vendored
Normal file
231
.github/workflows/claude-review-ext-stage1.yml
vendored
Normal file
@ -0,0 +1,231 @@
|
||||
name: Claude Review External - Stage 1 (PR Info Collection)
|
||||
|
||||
# This workflow runs on pull requests from forks
|
||||
# It collects PR information and saves it as an artifact for Stage 2
|
||||
# No secrets are available or needed in this stage
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_review_comment:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
collect-pr-info:
|
||||
# Only trigger on specific conditions
|
||||
# For PRs: always collect info
|
||||
# For comments: only when @claude-review-ext is mentioned
|
||||
if: |
|
||||
github.event_name == 'pull_request' ||
|
||||
(
|
||||
(github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment') &&
|
||||
contains(github.event.comment.body, '@claude-review-ext')
|
||||
)
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
steps:
|
||||
- name: Checkout PR code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# For PRs, this automatically checks out the merge commit
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Collect PR Information
|
||||
id: pr-info
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
|
||||
let prNumber, prTitle, prBody, prAuthor, baseBranch, headBranch, headSha;
|
||||
let triggerPhrase = '';
|
||||
let commentBody = '';
|
||||
let commentId = null;
|
||||
let commentAuthor = '';
|
||||
|
||||
if (context.eventName === 'pull_request') {
|
||||
prNumber = context.payload.pull_request.number;
|
||||
prTitle = context.payload.pull_request.title;
|
||||
prBody = context.payload.pull_request.body || '';
|
||||
prAuthor = context.payload.pull_request.user.login;
|
||||
baseBranch = context.payload.pull_request.base.ref;
|
||||
headBranch = context.payload.pull_request.head.ref;
|
||||
headSha = context.payload.pull_request.head.sha;
|
||||
} else if (context.eventName === 'issue_comment') {
|
||||
// For issue comments on PRs
|
||||
const issue = context.payload.issue;
|
||||
if (!issue.pull_request) {
|
||||
console.log('Not a PR comment, skipping');
|
||||
return;
|
||||
}
|
||||
|
||||
prNumber = issue.number;
|
||||
triggerPhrase = '@claude-review-ext';
|
||||
commentBody = context.payload.comment.body;
|
||||
commentId = context.payload.comment.id;
|
||||
commentAuthor = context.payload.comment.user.login;
|
||||
|
||||
// Fetch full PR details
|
||||
const { data: pr } = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: prNumber
|
||||
});
|
||||
|
||||
prTitle = pr.title;
|
||||
prBody = pr.body || '';
|
||||
prAuthor = pr.user.login;
|
||||
baseBranch = pr.base.ref;
|
||||
headBranch = pr.head.ref;
|
||||
headSha = pr.head.sha;
|
||||
} else if (context.eventName === 'pull_request_review_comment') {
|
||||
prNumber = context.payload.pull_request.number;
|
||||
prTitle = context.payload.pull_request.title;
|
||||
prBody = context.payload.pull_request.body || '';
|
||||
prAuthor = context.payload.pull_request.user.login;
|
||||
baseBranch = context.payload.pull_request.base.ref;
|
||||
headBranch = context.payload.pull_request.head.ref;
|
||||
headSha = context.payload.pull_request.head.sha;
|
||||
triggerPhrase = '@claude-review-ext';
|
||||
commentBody = context.payload.comment.body;
|
||||
commentId = context.payload.comment.id;
|
||||
commentAuthor = context.payload.comment.user.login;
|
||||
}
|
||||
|
||||
// Get list of changed files
|
||||
const { data: files } = await github.rest.pulls.listFiles({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: prNumber
|
||||
});
|
||||
|
||||
const changedFiles = files.map(f => ({
|
||||
filename: f.filename,
|
||||
status: f.status,
|
||||
additions: f.additions,
|
||||
deletions: f.deletions,
|
||||
changes: f.changes,
|
||||
patch: f.patch
|
||||
}));
|
||||
|
||||
// Get diff
|
||||
const { data: diff } = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: prNumber,
|
||||
mediaType: {
|
||||
format: 'diff'
|
||||
}
|
||||
});
|
||||
|
||||
const prInfo = {
|
||||
prNumber,
|
||||
prTitle,
|
||||
prBody,
|
||||
prAuthor,
|
||||
baseBranch,
|
||||
headBranch,
|
||||
headSha,
|
||||
triggerPhrase,
|
||||
commentBody,
|
||||
commentId,
|
||||
commentAuthor,
|
||||
changedFiles,
|
||||
diff,
|
||||
eventName: context.eventName,
|
||||
repository: `${context.repo.owner}/${context.repo.repo}`,
|
||||
triggeredAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
// Save to file
|
||||
fs.writeFileSync('pr-info.json', JSON.stringify(prInfo, null, 2));
|
||||
|
||||
console.log(`Collected info for PR #${prNumber} by ${prAuthor}`);
|
||||
console.log(`Changed files: ${changedFiles.length}`);
|
||||
console.log(`Event: ${context.eventName}`);
|
||||
if (triggerPhrase) {
|
||||
console.log(`Triggered by: ${commentAuthor} with phrase: ${triggerPhrase}`);
|
||||
}
|
||||
|
||||
// Set outputs for job summary
|
||||
core.setOutput('pr_number', prNumber);
|
||||
core.setOutput('pr_author', prAuthor);
|
||||
core.setOutput('changed_files_count', changedFiles.length);
|
||||
|
||||
- name: Run Basic Validation
|
||||
id: validation
|
||||
run: |
|
||||
echo "Running basic validation checks..."
|
||||
|
||||
# Check if this is from a fork
|
||||
IS_FORK="${{ github.event.pull_request.head.repo.fork }}"
|
||||
echo "Is from fork: $IS_FORK"
|
||||
|
||||
# Count files changed
|
||||
CHANGED_FILES=$(jq '.changedFiles | length' pr-info.json)
|
||||
echo "Files changed: $CHANGED_FILES"
|
||||
|
||||
# Check file types
|
||||
echo "File types changed:"
|
||||
jq -r '.changedFiles[].filename' pr-info.json | sed 's/.*\.//' | sort | uniq -c
|
||||
|
||||
# Check for potential issues
|
||||
LARGE_DIFF=false
|
||||
if [ "$CHANGED_FILES" -gt 100 ]; then
|
||||
LARGE_DIFF=true
|
||||
echo "⚠️ Large PR detected: $CHANGED_FILES files changed"
|
||||
fi
|
||||
|
||||
echo "is_fork=$IS_FORK" >> $GITHUB_OUTPUT
|
||||
echo "large_diff=$LARGE_DIFF" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Upload PR Information
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pr-info-${{ github.event.pull_request.number || github.event.issue.number }}
|
||||
path: pr-info.json
|
||||
retention-days: 1
|
||||
|
||||
- name: Post Status Comment
|
||||
if: github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const prNumber = ${{ steps.pr-info.outputs.pr_number }};
|
||||
const isFork = '${{ steps.validation.outputs.is_fork }}' === 'true';
|
||||
const filesCount = ${{ steps.pr-info.outputs.changed_files_count }};
|
||||
|
||||
let statusMessage = `🔄 **Claude Review Stage 1 Complete**\n\n`;
|
||||
statusMessage += `- PR: #${prNumber}\n`;
|
||||
statusMessage += `- Author: @${{ steps.pr-info.outputs.pr_author }}\n`;
|
||||
statusMessage += `- Files Changed: ${filesCount}\n`;
|
||||
statusMessage += `- Fork Status: ${isFork ? '🔱 External Fork' : '✅ Direct Branch'}\n\n`;
|
||||
statusMessage += `📋 Stage 2 (Claude Review) will run automatically after this workflow completes.\n`;
|
||||
statusMessage += `This two-stage process ensures secure handling of forked PRs.`;
|
||||
|
||||
// Post comment
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: prNumber,
|
||||
body: statusMessage
|
||||
});
|
||||
|
||||
- name: Job Summary
|
||||
run: |
|
||||
echo "## Claude Review Stage 1 Summary" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **PR Number**: #${{ steps.pr-info.outputs.pr_number }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **Author**: @${{ steps.pr-info.outputs.pr_author }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **Files Changed**: ${{ steps.pr-info.outputs.changed_files_count }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **From Fork**: ${{ steps.validation.outputs.is_fork }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **Large PR**: ${{ steps.validation.outputs.large_diff }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "✅ PR information collected and uploaded as artifact for Stage 2 processing." >> $GITHUB_STEP_SUMMARY
|
||||
Loading…
Reference in New Issue
Block a user