PR Review Workflows: Splitting New PR Creation and Updates
You:
Yes, I am wondering now if we should have two different workflows based on different events, such as the creation of a new PR and the synchronization or updates, so that we could have different workflows and we could share
ChatGPT:
"That's a sharp idea—splitting workflows for new PR creation and PR updates gives you finer control while avoiding unnecessary overlap. By modularizing shared logic, we ensure efficiency, maintainability, and reuse across both workflows. Let’s set this up cleanly."
Why Separate Workflows?
-
Event-Specific Actions:
- New PRs: Handle comprehensive reviews, initial scoring, and first-round feedback.
- Updates: Focus on re-analyzing modified diffs, resolving comments, and recalculating scores.
-
Performance Optimization:
- Reduce redundant processing (e.g., analyzing unchanged files during updates).
- Trigger only the relevant parts of the workflow.
-
Shared Logic:
- Avoid duplicating code for tasks like diff parsing, AI analysis, or comment posting by centralizing reusable steps.
Workflow Design
1. Workflow for New PR Creation
Trigger on the opened event to:
- Analyze the full diff.
- Generate initial comments and scores.
- Create an overview summary.
2. Workflow for PR Updates
Trigger on the synchronize event to:
- Detect and process only modified or new changes.
- Resolve or follow up on prior comments.
- Recalculate the risk score dynamically.
3. Shared Logic as Reusable GitHub Actions
Encapsulate shared logic (e.g., AI analysis, comment management) into custom GitHub Actions, which both workflows can use.
Workflow Implementation
1. Workflow for New PR Creation
name: AI-Powered New PR Review
on:
pull_request:
types:
- opened
jobs:
new-pr-review:
runs-on: ubuntu-latest
steps:
# Step 1: Checkout code
- name: Checkout code
uses: actions/checkout@v3
# Step 2: Install dependencies
- name: Install dependencies
run: npm install
# Step 3: Analyze new PR
- name: Analyze full PR diff
uses: ./actions/ai-analyze-pr # Custom shared action
with:
event_type: "opened"
pr_number: ${{ github.event.pull_request.number }}
repo_owner: ${{ github.repository_owner }}
repo_name: ${{ github.event.repository.name }}
base_branch: ${{ github.event.pull_request.base.ref }}
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2. Workflow for PR Updates
name: AI-Powered PR Update Review
on:
pull_request:
types:
- synchronize
jobs:
update-pr-review:
runs-on: ubuntu-latest
steps:
# Step 1: Checkout code
- name: Checkout code
uses: actions/checkout@v3
# Step 2: Install dependencies
- name: Install dependencies
run: npm install
# Step 3: Re-analyze updated PR
- name: Analyze updated PR diff
uses: ./actions/ai-analyze-pr # Custom shared action
with:
event_type: "synchronize"
pr_number: ${{ github.event.pull_request.number }}
repo_owner: ${{ github.repository_owner }}
repo_name: ${{ github.event.repository.name }}
base_branch: ${{ github.event.pull_request.base.ref }}
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Shared Logic as a Custom GitHub Action
Encapsulate the reusable logic (e.g., parsing diffs, AI analysis, posting comments) into a custom GitHub Action (ai-analyze-pr).
Action Definition (action.yml)
name: AI Analyze PR
description: Analyze pull request diffs using AI and post comments.
inputs:
event_type:
description: The event type (e.g., "opened", "synchronize").
required: true
pr_number:
description: The pull request number.
required: true
repo_owner:
description: The repository owner.
required: true
repo_name:
description: The repository name.
required: true
base_branch:
description: The base branch of the pull request.
required: true
runs:
using: "node16"
main: "index.js"
Shared Logic Implementation (index.js)
const { execSync } = require('child_process');
const { Octokit } = require('@octokit/rest');
const axios = require('axios');
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
async function main() {
const eventType = process.env.INPUT_EVENT_TYPE; // "opened" or "synchronize"
const prNumber = process.env.INPUT_PR_NUMBER;
const repoOwner = process.env.INPUT_REPO_OWNER;
const repoName = process.env.INPUT_REPO_NAME;
const baseBranch = process.env.INPUT_BASE_BRANCH;
console.log(`Processing PR #${prNumber} for event: ${eventType}`);
// Step 1: Get changed files
const changedFiles = execSync(`git diff --name-only origin/${baseBranch}`).toString().split('\n').filter(Boolean);
// Step 2: Analyze diffs
const comments = [];
for (const fileName of changedFiles) {
console.log(`Analyzing file: ${fileName}`);
const diff = execSync(`git diff origin/${baseBranch} -- ${fileName}`).toString();
// Generate AI review
const aiResponse = await analyzeWithAI(diff, fileName);
comments.push({ fileName, comment: aiResponse });
}
// Step 3: Post comments
for (const { fileName, comment } of comments) {
await postComment(prNumber, repoOwner, repoName, fileName, comment);
}
console.log('AI-powered PR review completed.');
}
async function analyzeWithAI(diff, fileName) {
const response = await axios.post(
'https://api.openai.com/v1/chat/completions',
{
model: 'gpt-4',
messages: [
{ role: 'system', content: 'You are an AI reviewing code changes in a pull request.' },
{ role: 'user', content: `Review this diff for the file ${fileName}:\n\n${diff}` },
],
},
{
headers: {
Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
'Content-Type': 'application/json',
},
}
);
return response.data.choices[0].message.content;
}
async function postComment(prNumber, repoOwner, repoName, fileName, comment) {
await octokit.pulls.createReviewComment({
owner: repoOwner,
repo: repoName,
pull_number: prNumber,
path: fileName,
side: 'RIGHT',
body: comment,
line: 1, // Default to line 1 (adjust based on parsed diff)
});
}
main().catch((error) => {
console.error('Error during PR analysis:', error);
process.exit(1);
});
Benefits of Separate Workflows
-
Tailored Event Handling:
- New PR workflows handle comprehensive first-pass reviews.
- Update workflows focus only on changes, reducing redundant work.
-
Shared Logic Reuse:
- Encapsulating core logic in a custom GitHub Action ensures maintainability and reuse.
-
Improved Performance:
- Only process diffs relevant to the event type (e.g., new diffs for updates).
Next Steps
- Deploy the Shared Action:
- Publish
ai-analyze-prto your GitHub Marketplace or npm for reuse.
- Publish
- Enhance Update Workflow:
- Add logic to resolve or follow up on previous comments.
- Dynamically adjust risk scores based on updates.
- Optimize Comment Management:
- Track and update comments instead of duplicating them.
Let me know if you'd like to dig deeper into any specific part of this architecture—this setup is ready to scale! 🚀