Skip to content

Commit

Permalink
split PRcomments into 2 diff types
Browse files Browse the repository at this point in the history
  • Loading branch information
suitedaces committed Dec 27, 2023
1 parent 7a5d619 commit 9fa5fff
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 38 deletions.
20 changes: 13 additions & 7 deletions src/handlers/PRCommentHandler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { GitHubService } from '../services/GitHubService';
import { OpenAIService } from '../services/OpenAIService';
import { createPRCommentResponsePrompt } from '../utils/prompts';
import { PRMetadata, File } from '../utils/types';
import { PRMetadata, File, PRCommentEvent } from '../utils/types';
import parseDiff from 'parse-diff';

export class PRCommentHandler {
Expand All @@ -13,20 +13,26 @@ export class PRCommentHandler {
}
) {}

async handleCommentEvent(eventPath: string): Promise<void> {
async handleCommentEvent(eventPayload: string): Promise<void> {
// Fetch PR metadata
const prDetails: PRMetadata = await this.gitHubService.getPRMetadata(eventPath);
const comment = prDetails.comment;
const prDetails: PRMetadata = await this.gitHubService.getPRMetadata(eventPayload);
const comment: PRCommentEvent = JSON.parse(eventPayload).comment;

// TODO: remove
await this.gitHubService.addReactionToComment(prDetails.owner, prDetails.repo, comment.id, 'laugh');

// Check if Dexter is mentioned in the comment, if not then skip
if (!comment.body.includes('Dexter','dexter','dexter-ai')) {
if (!comment.body?.includes('dexter')) {
console.log('Dexter not mentioned, skipping response...');
return;
}

}

if (!comment.user) {
console.log('Comment user is undefined, skipping response...');
return;
}

// Add reaction to the comment
await this.gitHubService.addReactionToComment(prDetails.owner, prDetails.repo, comment.id, 'eyes');

Expand All @@ -46,7 +52,7 @@ export class PRCommentHandler {
const aiResponse = await this.aiService.getAIPullRequestCommentResponse(prompt, this.appConfig.OPENAI_API_MODEL);

// Process AI response and create a comment reply
const replyMessage = aiResponse || `Sorry, can't help you with that, ${comment.user.login} (blame OpenAI!) 😭`;
const replyMessage = aiResponse || `Sorry, can't help you with that, ${comment.user?.login} (blame OpenAI!) 😭`;

// Reply to the comment in the PR
await this.gitHubService.createReviewCommentReply(prDetails.owner, prDetails.repo, prDetails.pull_number, comment.id, replyMessage);
Expand Down
10 changes: 5 additions & 5 deletions src/handlers/PRHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { GitHubService } from '../services/GitHubService';
import { OpenAIService } from '../services/OpenAIService';
import { PRMetadata, File, PRComment } from '../utils/types';
import { PRMetadata, File, PRCommentRequest } from '../utils/types';
import { filterFiles } from '../utils/utils';
import { createPRReviewPrompt } from '../utils/prompts';
import parseDiff from 'parse-diff';
Expand Down Expand Up @@ -50,13 +50,13 @@ export class PRHandler {
}

// TODO: Make this faster
private async analyzeDiffAndGenerateComments(files: File[], prDetails: PRMetadata): Promise<PRComment[]> {
const comments: PRComment[] = [];
private async analyzeDiffAndGenerateComments(files: File[], prDetails: PRMetadata): Promise<PRCommentRequest[]> {
const comments: PRCommentRequest[] = [];
for (const file of files) {
if (file.to === "/dev/null") continue; // Ignore deleted files

for (const chunk of file.chunks) {
const fileChunkComments: PRComment[] = [];
const fileChunkComments: PRCommentRequest[] = [];

// Generate a prompt for AI review
const prompt = createPRReviewPrompt(file, chunk, prDetails);
Expand All @@ -68,7 +68,7 @@ export class PRHandler {
);

if (aiResponse && aiResponse.length > 0) {
const fileComments: PRComment[] = aiResponse.map(
const fileComments: PRCommentRequest[] = aiResponse.map(
({ lineNumber, reviewComment }) => ({
body: reviewComment,
path: file.to,
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const event = {
// Handle pull request events
await prHandler.handlePullRequest(event.payload);
} else if (event.eventName === 'issue_comment') {
// Handle PR comment events
await prCommentHandler.handleCommentEvent(event.payload);
}

Expand Down
51 changes: 31 additions & 20 deletions src/services/GitHubService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Octokit } from "@octokit/rest";
import { PRMetadata, PRComment } from '../utils/types';
import { PRMetadata, PRCommentEvent, PRCommentRequest } from '../utils/types';
import { readFileSync } from "fs";

export class GitHubService {
Expand All @@ -15,40 +15,51 @@ export class GitHubService {
async getPRMetadata(eventPath: string): Promise<PRMetadata> {
try {
const event = JSON.parse(readFileSync(eventPath, "utf8"));

const repository = event.repository;

console.log('\nRepository: ', repository)

const number = event.number;

if (!repository || typeof number !== 'number') {
const pullNumber = event.pull_request.number; // Renamed from 'number' to 'pullNumber'

if (!repository || typeof pullNumber !== 'number') {
throw new Error("Invalid event data. Repository or PR number is missing.");
}


// Fetch PR details
const prResponse = await this.octokit.pulls.get({
owner: repository.owner.login,
repo: repository.name,
pull_number: number,
pull_number: pullNumber,
});

console.log('\nPR Response: ', prResponse)


// Fetch PR comments
const commentsResponse = await this.octokit.issues.listComments({
owner: repository.owner.login,
repo: repository.name,
issue_number: pullNumber,
});

// Map comments to PRComment format
const comments: PRCommentEvent[] = commentsResponse.data.map(comment => ({
body: comment.body ? comment.body : "",
user: comment.user ? { login: comment.user.login, id: comment.user.id } : undefined,
id: comment.id,
}));

return {
owner: repository.owner.login,
repo: repository.name,
pull_number: number,
pull_number: pullNumber,
title: prResponse.data.title ?? "",
description: prResponse.data.body ?? ""
};

description: prResponse.data.body ?? "",
comments: comments ? comments : [],
}

} catch (error) {
console.error("Error fetching PR details:", error);
throw error;
}
}


async getPRComments(owner: string, repo: string, pull_number: number): Promise<string> {
async getPRComments(owner: string, repo: string, pull_number: number): Promise<string> {
try {
const comments = await this.octokit.issues.listComments({
owner,
Expand All @@ -60,7 +71,7 @@ export class GitHubService {
console.error(`Error fetching comments for PR #${pull_number}:`, error);
throw error;
}
}
}

async getDiff(owner: string, repo: string, pull_number: number): Promise<string | null> {
try {
Expand All @@ -81,7 +92,7 @@ export class GitHubService {
owner: string,
repo: string,
pull_number: number,
comments: PRComment[]
comments: PRCommentRequest[]
): Promise<void> {
try {
await this.octokit.pulls.createReview({
Expand Down
4 changes: 2 additions & 2 deletions src/utils/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function createBasePrompt(prDetails: PRMetadata): string {
export function createPRReviewPrompt(file: File, chunk: Chunk, prDetails: PRMetadata): string {
const basePrompt = createBasePrompt(prDetails);
const instructions = `Your current task is to give high quality comments on the Pull Request based on the instructions given. Respond in JSON format: {"reviews": [{"lineNumber": <line_number>, "reviewComment": "<review comment>"}]}. \n\n`;
const codeDiff = `Code to Review (File: ${file.path}): \n\`\`\`\ndiff ${chunk.content} ${chunk.changes.map(c => `${c.ln ? c.ln : c.ln2} ${c.content}`).join("\n")}\n\`\`\`\n\n`;
const codeDiff = `Code to Review (File: ${file.to}): \n\`\`\`\ndiff ${chunk.content} ${chunk.changes.map(c => `${c.ln ? c.ln : c.ln2} ${c.content}`).join("\n")}\n\`\`\`\n\n`;
const prompt = `${basePrompt}${instructions}${codeDiff}`;
console.log("Prompt: \n", prompt);
return prompt;
Expand All @@ -26,7 +26,7 @@ export function createPRCommentResponsePrompt(prDetails: PRMetadata, discussionT

for (const file of codeDiffs) {
for (const chunk of file.chunks) {
const codeDiff = `Code to Review (File: ${file.path}): \n\`\`\`\ndiff ${chunk.content} ${chunk.changes.map(c => `${c.ln || c.ln2}: ${c.content}`).join("\n")}\n\`\`\`\n`;
const codeDiff = `Code to Review (File: ${file.to}): \n\`\`\`\ndiff ${chunk.content} ${chunk.changes.map(c => `${c.ln || c.ln2}: ${c.content}`).join("\n")}\n\`\`\`\n`;
codeDiffContext += codeDiff + '\n';
}
}
Expand Down
18 changes: 14 additions & 4 deletions src/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ export interface PRMetadata {
pull_number: number;
title: string;
description: string;
}
comments?: PRCommentEvent[];
}

export interface GithubUser {
login: string;
id: number;
}

export interface File {
to: string;
Expand All @@ -22,10 +28,14 @@ export interface Change {
content: string;
}

export interface PRComment {
export interface PRCommentRequest {
body: string;
path: string;
position: number;
in_reply_to?: number;
comment_id?: number;
}

export interface PRCommentEvent {
body: string;
user?: GithubUser;
id: number;
}

0 comments on commit 9fa5fff

Please sign in to comment.