Writing detailed PR descriptions is often skipped due to time pressure, but it's crucial for code review efficiency. In this tutorial, you'll build an AI agent that automatically generates a PR description from the code diff whenever a pull request is opened. You'll use GitHub Actions and OpenAI's API. By the end, every new PR will have a clear, context-rich description without manual effort.
Step 1: Set Up Your OpenAI API Key
Generate an API key at platform.openai.com/api-keys. Then add it as a secret in your GitHub repository: go to Settings > Secrets and variables > Actions > New repository secret, name it OPENAI_API_KEY, and paste your key.
Step 2: Create the GitHub Actions Workflow
Inside your repo, create the file .github/workflows/pr-description.yml:
name: AI PR Description
on:
pull_request:
types: [opened, reopened, synchronize]
jobs:
generate-description:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- name: Generate description
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
run: node .github/scripts/generate-pr-description.jsThis workflow triggers on PR events and runs a Node.js script that will fetch the diff and call the API.
Step 3: Write the Node.js Script
Create the file .github/scripts/generate-pr-description.js:
const { Octokit } = require('@octokit/rest');
const { Configuration, OpenAIApi } = require('openai');
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
const openai = new OpenAIApi(new Configuration({ apiKey: process.env.OPENAI_API_KEY }));
async function main() {
const [owner, repo] = process.env.REPO.split('/');
const prNumber = parseInt(process.env.PR_NUMBER);
// Get PR diff
const { data: diff } = await octokit.rest.pulls.get({
owner,
repo,
pull_number: prNumber,
mediaType: { format: 'diff' },
});
// Truncate diff if too long (OpenAI context limit)
const maxLength = 15000;
const diffText = diff.length > maxLength ? diff.slice(0, maxLength) + '\n... (truncated)' : diff;
// Generate description using OpenAI
const prompt = `You are a senior developer writing a PR description. Based on the following code diff, write a summary in markdown:
- Purpose and context of the changes
- Key changes (bullet points)
- Any potential side effects or testing notes
Diff:
${diffText}`;
const response = await openai.createChatCompletion({
model: 'gpt-4o-mini',
messages: [
{ role: 'system', content: 'You write concise, informative PR descriptions.' },
{ role: 'user', content: prompt },
],
max_tokens: 500,
temperature: 0.3,
});
const description = response.data.choices[0].message.content;
// Update PR body
await octokit.rest.pulls.update({
owner,
repo,
pull_number: prNumber,
body: description,
});
console.log('PR description updated successfully.');
}
main().catch(err => {
console.error('Error:', err);
process.exit(1);
});Don't forget to add a package.json in .github/scripts/ with dependencies @octokit/rest and openai, then run npm install locally or let the workflow do it (the workflow runs npm ci but you need a lockfile). For simplicity, create the file with these dependencies listed and commit the lockfile.
Step 4: Test It
Create a new branch, make changes, and open a pull request. Watch the Actions tab; the job should run and update the PR description. You'll see the AI-generated text replace the default body.
You can customize the prompt to include ticket numbers, enforce a format, or request breaking changes notes. Consider adding a fallback if the API fails (e.g., keep the original body). This workflow integrates seamlessly with your existing process.
By automating PR descriptions, you eliminate a common friction point and allow developers to focus on what matters: writing great code.
Comments
No comments yet
Connect with Google to comment or reply.
Connect with Google