Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .github/workflows/review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: "Pull Request Reviewer"

on:
pull_request:
types: [opened, synchronize]

jobs:
review:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Run PR Reviewer
uses: ./
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ACTION_CONTEXT: 'CODE_REVIEW'
EXCLUDE_EXTENSIONS: 'lock'
INCLUDE_EXTENSIONS: 'php, js, jsx, ts, tsx, css, scss, html, json'
EXCLUDE_PATHS: 'node_modules/,vendor/,build/,dist/'
72 changes: 55 additions & 17 deletions AiHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ const { OpenAI } = require('openai');
const core = require("@actions/core");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What: The addition of 'instructions' as a parameter in the constructor is a change that should also have a validation check.

Why: Ensuring that all parameters passed to the constructor are validated can prevent runtime errors and ensure the integrity of the data.

How: Add validation logic to check if 'instructions' is either a string or undefined before assigning it to 'this.instructions'.

class AiHelper {
prDetails;
instructions;

constructor(apiKey, prDetails) {
constructor(apiKey, prDetails, instructions) {
this.openai = new OpenAI({ apiKey });
this.prDetails = prDetails;
this.instructions = instructions;
}

async checkCommentResolved(patch, commentText) {
Expand Down Expand Up @@ -285,14 +287,17 @@ class AiHelper {
for (const comments of prComments) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What: The new comment formatting for review comments does not provide validation for the 'severity' and 'priority' fields.

Why: Lack of validation allows potential for unexpected data to be processed, which can lead to confusion or errors when the comment is generated.

How: Implement checks to ensure 'severity' and 'priority' are among the expected values (e.g., 'High', 'Medium', 'Low'). You can use a utility function like isValidSeverity(severity) to validate these.

for (const comment of comments) {
const {commit_id, side, line, path, review_comment} = comment;
const {what, why, how} = review_comment;
const {pointer, severity, priority, what, why, how} = review_comment;

if( existingPrComments.length > 0 && this.checkSimilarComment(existingPrComments, what ) ) {
core.info("Comment already exists, skipping ❎");
continue;
}

await githubHelper.createReviewComment(commit_id, side, line, path, `**What:** ${what}\n\n\n**Why:** ${why}\n\n\n**How:** ${how}\n\n`);
// Compose the comment with pointer and severity at the top
const commentBody = `${pointer} **[${severity} | ${priority}]**\n\n**What:** ${what}\n\n**Why:** ${why}\n\n**How:** ${how}`;

await githubHelper.createReviewComment(commit_id, side, line, path, commentBody);

core.info("Comment added ✅");
}
Expand All @@ -307,34 +312,52 @@ class AiHelper {

## Ensure that the code is reviewed with emphasis on the following key areas:

- **Security**: Look for potential vulnerabilities such as SQL injection, XSS, CSRF, or insecure handling of data. Verify that proper authentication and authorization checks are implemented.
- **Security**: Look for potential vulnerabilities such as SQL injection, XSS, CSRF, or insecure handling of data. Verify that proper authentication and authorization checks are implemented. Focus on security issues relevant to the detected programming language (e.g., XSS for JavaScript, SQLi for PHP, etc.).
- **Performance**: Identify any code that could impact the performance negatively. Check for resource-intensive operations, inefficient algorithms, or unnecessary complexity that could be simplified.
- **Refactorization**: Evaluate the code for readability, maintainability, and adherence to coding standards. Suggest ways to improve the structure of the code to enhance future maintenance.
- **Optimization**: Look for opportunities to optimize the code for speed and efficiency without sacrificing readability or security. Consider memory usage, execution time, and processing power.

## Review Steps

1. **Identify Language/Framework:** Identify the programming language and framework used in the code.
2. **Review Diff:** Analyze changes line by line, noting additions/removals.
3. **Check Efficiency:** Spot inefficiencies and suggest improvements.
4. **Logic & Bugs:** Find logical errors or bugs; recommend fixes.
5. **Security:** Identify vulnerabilities and suggest mitigations.
6 **Performance:** Detect bottlenecks; propose enhancements, use of built-in functions.
7. .**Avoid Non Impacting** STRICTLY Avoid giving feedback on non-impacting changes like formatting, comments, ensuring code quality, etc.
6. **Performance:** Detect bottlenecks; propose enhancements, use of built-in functions.
7. **STRICTLY Avoid** giving feedback on non-impacting changes like formatting, comments, or minor code style issues.
8. **Only provide comments that are actionable, relevant, and have a clear suggested solution.**
9. **For each issue, assign a severity (High, Medium, Low) and a pointer at the top:**
- ⚠️ Potential issue (for bugs, security, or performance)
- 🛠️ Refactor suggestion (for maintainability, readability, or optimization)
10. **Each comment must include:**
- Pointer (⚠️ or 🛠️) at the top
- Severity (High/Medium/Low)
- Priority (High/Medium/Low)
- What: The issue
- Why: Why it matters
- How: A clear, practical suggested solution (with code if possible)

You can use PR title and description for more context.
You can use PR title, description and instructions for more context.

#PR title:
\`\`\`
```
${this.prDetails.prTitle}
\`\`\`
```

#PR description:
\`\`\`
```
${this.prDetails.prDescription}
\`\`\`

`;
```
`;

if (this.instructions) {
systemPrompt += `
#Instructions:
```
${this.instructions}
```
`;
}

return this.openai.chat.completions.create({
model: 'gpt-4o-mini',
Expand Down Expand Up @@ -376,20 +399,35 @@ class AiHelper {
"type": "object",
"description": "The review comment that the reviewer has left on the code snippet. It should be specific, actionable, and focused on a single issue. It should also consider the developer’s perspective and provide constructive feedback that helps them understand the problem and improve their code quality.",
"properties": {
"pointer": {
"type": "string",
"description": "Pointer at the top of the comment: either '⚠️ Potential issue' or '🛠️ Refactor suggestion'"
},
"severity": {
"type": "string",
"description": "Severity of the issue: High, Medium, or Low"
},
"priority": {
"type": "string",
"description": "Priority of the issue: High, Medium, or Low"
},
"what": {
"type": "string",
"description": "Describes the issue that the reviewer has identified in the code snippet. It should be specific, actionable, and focused on a single problem. It should also consider the developer’s perspective and provide constructive feedback that helps them understand the issue and improve their code quality."
"description": "Describes the issue that the reviewer has identified in the code snippet. It should be specific, actionable, and focused on a single problem."
},
"why": {
"type": "string",
"description": "Explains why the issue is important and what the reviewer hopes to achieve by addressing it. It should provide context on the problem and explain how it aligns with the project’s goals, coding standards, or best practices. It should also consider the developer’s perspective and explain the benefits of making the change."
"description": "Explains why the issue is important and what the reviewer hopes to achieve by addressing it."
},
"how": {
"type": "string",
"description": "Provides a clear and concise explanation of how to fix the issue. It can include code snippets, links to documentation, or other resources that help the developer understand the problem and implement the suggested change. It should be detailed enough to guide the developer through the process but not so prescriptive that it stifles creativity or learning. It should also consider the developer’s level of expertise and provide additional context or explanations as needed."
"description": "Provides a clear and concise explanation of how to fix the issue. It can include code snippets, links to documentation, or other resources."
}
},
"required": [
"pointer",
"severity",
"priority",
"what",
"why",
"how"
Expand Down
14 changes: 14 additions & 0 deletions GithubHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,20 @@ class GitHubHelper {
throw error;
}
}

async getFileContent(path) {
try {
const { data } = await this.octokit.rest.repos.getContent({
owner: this.owner,
repo: this.repo,
path,
});
return Buffer.from(data.content, 'base64').toString();
} catch (error) {
core.error(error.message);
return null;
}
}
}

module.exports = GitHubHelper;
4 changes: 3 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,9 @@ async function main() {
prDescription: pullRequestData.body,
};

const aiHelper = new AiHelper(openaiApiKey, prDetails);
const instructions = await githubHelper.getFileContent('instructions.md');

const aiHelper = new AiHelper(openaiApiKey, prDetails, instructions);
const reviewer = new PullRequestReviewer(owner, repo, pull_number, githubHelper, aiHelper);

core.info('--------------------------------------');
Expand Down
36 changes: 36 additions & 0 deletions instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Project Overview

This project is a GitHub Action designed to automate pull request (PR) code reviews using OpenAI's GPT models. It analyzes code changes, provides feedback on potential issues, and helps maintain code quality.

# Tech Stack

- **Language:** Node.js (v20)
- **Core Libraries:**
- `@actions/core`: For creating GitHub Actions.
- `@actions/github`: For interacting with the GitHub API.
- `openai`: For making requests to the OpenAI API.
- `axios`: For making HTTP requests (e.g., to JIRA).

# Key Files

- `index.js`: The main entry point for the action. It handles inputs, sets up helpers, and orchestrates the review process.
- `AiHelper.js`: Contains all logic related to interacting with the OpenAI API. This includes generating review comments, summarizing PRs, and checking comment status.
- `GithubHelper.js`: A wrapper for the GitHub API, simplifying tasks like fetching PR data, listing files, and creating comments.
- `action.yml`: The metadata file for the GitHub Action, defining inputs, outputs, and branding.
- `workflow.yml`: An example workflow file demonstrating how to use this action.

# Coding Conventions

- **Style:** Follow the existing code style (naming conventions, indentation, etc.).
- **Error Handling:** Ensure all asynchronous operations have proper `try...catch` blocks to handle potential errors gracefully.
- **Comments:** Add JSDoc-style comments to new functions to explain their purpose, parameters, and return values.
- **Dependencies:** Minimize adding new dependencies unless absolutely necessary.

# Review Focus Areas

When reviewing PRs for this project, pay special attention to:

1. **Prompt Engineering:** The system prompts in `AiHelper.js` are critical. Ensure they are clear, concise, and provide sufficient context for the AI to generate high-quality reviews.
2. **API Usage:** Verify that the GitHub and OpenAI APIs are used correctly and efficiently.
3. **Input Handling:** Ensure all action inputs from `action.yml` are handled correctly and have sensible defaults.
4. **Security:** Since this action handles API keys and repository data, ensure no sensitive information is logged or exposed.
Loading