Skip to content

Commit ff2cac7

Browse files
committed
Merge branch 'dev' into codex-init
2 parents 34c6d96 + f7b4e3a commit ff2cac7

10 files changed

Lines changed: 103 additions & 60 deletions

app/github/route.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { handleGithubAuth } from "@lib/handleGithubAuth"
22
import { replyIssueComment } from "@lib/replyIssueComment"
33
import { summarizePullRequest } from "@lib/summarizePullRequest"
4+
import { codexCommand } from "@utils/constants"
45
import { NextRequest, NextResponse } from "next/server"
56

67
export const fetchCache = "force-no-store"
@@ -15,7 +16,7 @@ export async function POST(req: NextRequest) {
1516

1617
await summarizePullRequest(payload, octokit)
1718
} else if (payload.action == "created") {
18-
if (payload.comment.body.includes("/ask-codex")) {
19+
if (payload.comment.body.includes(codexCommand)) {
1920
// If a comment is created, reply to it
2021
const octokit = await handleGithubAuth(payload)
2122

constants.json

Lines changed: 0 additions & 7 deletions
This file was deleted.

lib/joinStringsUntilMaxLength.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
export function joinStringsUntilMaxLength(
22
parsedFiles: string[],
33
maxLength: number
4-
): string {
5-
let combinedString = ""
4+
) {
5+
let codeDiff = ""
66
let currentLength = 0
7+
let maxLengthExceeded = false
78

89
for (const file of parsedFiles) {
910
const fileLength = file.length
1011

1112
if (currentLength + fileLength <= maxLength) {
12-
combinedString += file
13+
codeDiff += file
1314
currentLength += fileLength
1415
} else {
16+
maxLengthExceeded = true
1517
const remainingLength = maxLength - currentLength
16-
combinedString += file.slice(0, remainingLength)
18+
codeDiff += file.slice(0, remainingLength)
1719
break
1820
}
1921
}
2022

21-
return combinedString
23+
return { codeDiff, maxLengthExceeded }
2224
}

lib/replyIssueComment.ts

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,80 @@
11
import { Octokit } from "@octokit/rest"
22
import { ChatCompletionRequestMessage } from "openai-streams"
3+
import { codexCommand } from "../utils/constants"
34
import { generateChatGpt } from "../utils/generateChatGpt"
45
import { getCodeDiff } from "../utils/getCodeDiff"
56

6-
export const startDescription = "\n\n<!-- start pr-codex -->"
7-
export const endDescription = "<!-- end pr-codex -->"
87
const systemPrompt =
9-
"You are a Git diff assistant. Given a code diff, you answer any question related to it. Be concise. Always wrap file names, functions, objects and similar in backticks (`)."
8+
"You are a Git diff assistant. Given a code diff, you answer any question related to it. Be concise. Use line breaks and lists to improve readability. Always wrap file names, functions, objects and similar in backticks (`)."
109

1110
export async function replyIssueComment(payload: any, octokit: Octokit) {
1211
// Get relevant PR information
13-
const { repository, issue, sender, comment } = payload
12+
const { repository, issue, sender, comment, pull_request } = payload
1413

15-
const question = comment.body.split("/ask-codex")[1].trim()
14+
const question = comment.body.split(codexCommand)[1].trim()
1615

1716
if (question) {
18-
const { owner, repo, issue_number } = {
17+
const { owner, repo, number, diff_hunk } = {
1918
owner: repository.owner.login,
2019
repo: repository.name,
21-
issue_number: issue.number
20+
number: issue?.number ?? pull_request.number,
21+
diff_hunk: comment?.diff_hunk
2222
}
2323

24-
// Get the diff content using Octokit and GitHub API
25-
const { codeDiff } = await getCodeDiff(owner, repo, issue_number, octokit)
24+
// Get the diff content
25+
const { codeDiff } = diff_hunk
26+
? { codeDiff: diff_hunk }
27+
: await getCodeDiff(owner, repo, number, octokit)
2628

2729
// If there are changes, trigger workflow
2830
if (codeDiff?.length != 0) {
2931
const messages: ChatCompletionRequestMessage[] = [
3032
{
3133
role: "system",
32-
content: systemPrompt
34+
content: `${systemPrompt}\n\nHere is the code diff:\n\n${codeDiff}`
3335
},
3436
{
3537
role: "user",
36-
content: `${question}\n\nHere is the code diff:\n\n${codeDiff}`
38+
content: `${question}`
3739
}
3840
]
3941

4042
const codexResponse = await generateChatGpt(messages)
4143

4244
const description = `> ${question}\n\n@${sender.login} ${codexResponse}`
4345

44-
await octokit.issues.createComment({
45-
owner,
46-
repo,
47-
issue_number,
48-
body: description
49-
})
46+
if (diff_hunk) {
47+
const { commit_id, path, line, side, start_line, start_side, id } = {
48+
commit_id: comment.commit_id,
49+
path: comment.path,
50+
line: comment.line,
51+
side: comment.side,
52+
start_line: comment.start_line,
53+
start_side: comment.start_side,
54+
id: comment.id
55+
}
56+
57+
await octokit.pulls.createReviewComment({
58+
owner,
59+
repo,
60+
pull_number: number,
61+
body: description,
62+
commit_id,
63+
path,
64+
line,
65+
side,
66+
start_line,
67+
start_side,
68+
in_reply_to: id
69+
})
70+
} else {
71+
await octokit.issues.createComment({
72+
owner,
73+
repo,
74+
issue_number: number,
75+
body: description
76+
})
77+
}
5078

5179
return codexResponse
5280
}

lib/summarizePullRequest.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import { Octokit } from "@octokit/rest"
22
import { ChatCompletionRequestMessage } from "openai-streams"
3+
import {
4+
codexCommand,
5+
endDescription,
6+
startDescription
7+
} from "../utils/constants"
38
import { generateChatGpt } from "../utils/generateChatGpt"
49
import { getCodeDiff } from "../utils/getCodeDiff"
510

6-
export const startDescription = "\n\n<!-- start pr-codex -->"
7-
export const endDescription = "<!-- end pr-codex -->"
811
const systemPrompt =
9-
'You are a Git diff assistant. Always begin with "This PR". Given a code diff, you provide a simple description in prose, in less than 300 chars, which sums up the changes. Continue with "\n\n### Detailed summary\n" and make a comprehensive list of all changes, excluding any eventual skipped files. Be concise. Always wrap file names, functions, objects and similar in backticks (`).'
12+
"You are a Git diff assistant. Given a code diff, you provide a clear and concise description of its content. Always wrap file names, functions, objects and similar in backticks (`)."
1013

1114
export async function summarizePullRequest(payload: any, octokit: Octokit) {
1215
// Get relevant PR information
@@ -18,7 +21,7 @@ export async function summarizePullRequest(payload: any, octokit: Octokit) {
1821
}
1922

2023
// Get the diff content using Octokit and GitHub API
21-
const { codeDiff, skippedFiles } = await getCodeDiff(
24+
const { codeDiff, skippedFiles, maxLengthExceeded } = await getCodeDiff(
2225
owner,
2326
repo,
2427
pull_number,
@@ -30,11 +33,12 @@ export async function summarizePullRequest(payload: any, octokit: Octokit) {
3033
const messages: ChatCompletionRequestMessage[] = [
3134
{
3235
role: "system",
33-
content: systemPrompt
36+
content: `${systemPrompt}\n\nHere is the code diff:\n\n${codeDiff}`
3437
},
3538
{
3639
role: "user",
37-
content: `Here is the code diff:\n\n${codeDiff}`
40+
content:
41+
'Starting with "This PR", clearly explain the focus of this PR in prose, in less than 300 characters. Then follow up with "\n\n### Detailed summary\n" and make a comprehensive list of all changes.'
3842
}
3943
]
4044

@@ -55,7 +59,11 @@ export async function summarizePullRequest(payload: any, octokit: Octokit) {
5559
", "
5660
)}`
5761
: ""
58-
}\n\n${endDescription}`
62+
}${
63+
maxLengthExceeded
64+
? "\n\n> The code diff in this PR exceeds the max number of characters, so this overview may be incomplete."
65+
: ""
66+
}\n\n✨ Ask PR-Codex anything about this PR by commenting with \`${codexCommand}{your question}\`\n\n${endDescription}`
5967

6068
const description = hasCodexCommented
6169
? pr.body.split(startDescription)[0] +

utils/constants.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
1-
import envConstants from "constants.json"
2-
3-
type Addresses = {}
4-
type Constants = {}
5-
6-
export const constants: Constants = envConstants.values
7-
8-
export const addresses: Addresses =
9-
envConstants.addresses[process.env.NEXT_PUBLIC_CHAIN_ID]
10-
11-
export default constants
1+
export const startDescription = "\n\n<!-- start pr-codex -->"
2+
export const endDescription = "<!-- end pr-codex -->"
3+
export const codexCommand = "/codex "
4+
export const maxChanges = 1000
5+
export const maxCodeDiff = 11500

utils/getCodeDiff.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import { Octokit } from "@octokit/rest"
22
import { joinStringsUntilMaxLength } from "../lib/joinStringsUntilMaxLength"
3+
import { maxChanges, maxCodeDiff } from "./constants"
34
import { parseDiff } from "./parseDiff"
45

5-
const maxChanges = 1000
6-
const maxCodeDiff = 10000
7-
86
export const getCodeDiff = async (
97
owner: string,
108
repo: string,
@@ -26,7 +24,11 @@ export const getCodeDiff = async (
2624
// If the number of changes in a file is greater than `maxChanges` changes, the file will be skipped.
2725
// The codeDiff is the joined string of parsed files, up to a max length of `maxCodeDiff`.
2826
const { parsedFiles, skippedFiles } = parseDiff(diffContent, maxChanges)
29-
const codeDiff = joinStringsUntilMaxLength(parsedFiles, maxCodeDiff)
3027

31-
return { codeDiff, skippedFiles }
28+
const { codeDiff, maxLengthExceeded } = joinStringsUntilMaxLength(
29+
parsedFiles,
30+
maxCodeDiff
31+
)
32+
33+
return { codeDiff, skippedFiles, maxLengthExceeded }
3234
}

utils/github/testPayloadComment.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { codexCommand } from "../../utils/constants"
2+
13
export const testPayloadComment = {
24
installation: { id: 35293807 },
35
action: "created",
@@ -6,7 +8,7 @@ export const testPayloadComment = {
68
},
79

810
comment: {
9-
body: "/ask-codex Describe the changes in the homepage UI"
11+
body: `${codexCommand}what changes have been done in the homepage?`
1012
},
1113
sender: {
1214
login: "jjranalli"

utils/github/testPayloadSyncPr.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import { endDescription, startDescription } from "@lib/summarizePullRequest"
1+
import { startDescription, endDescription } from "../../utils/constants"
22

33
export const testPayloadSyncPr = {
44
installation: { id: 35293807 },
55
action: "synchronize",
66
pull_request: {
77
diff_url: "https://github.com/decentralizedlabs/pr-codex/pull/4.diff",
88
number: 4,
9-
// body: null,
9+
body: null,
1010
// body: "\n\n<!-- start pr-codex -->\n\n## PR-Codex overview\nThis PR adds a new feature to the project: a GitHub app that explains and summarizes PR code diffs. It includes a new `github/route.ts` file and updates several existing files, including `README.md`, `Homepage.tsx`, `DefaultHead.tsx`, `AppLayout.tsx`, `Footer.tsx`, and `Navbar.tsx`.\n\n> The following files were skipped due to too many changes: `package-lock.json`.\n\n<!-- end pr-codex -->",
11-
body: "<!-- start -->\n\nthis is a test",
11+
// body: "<!-- start -->\n\nthis is a test",
1212
// body:
1313
// "<!-- start -->\n\nthis is a test" +
1414
// startDescription +

utils/parseDiff.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,31 @@ type FileChange = { parsedFiles: string[]; skippedFiles: string[] }
33
export function parseDiff(diff: string, maxChanges: number): FileChange {
44
let skippedFiles: string[] = []
55
const files = diff.split(/diff --git /).slice(1)
6-
const parsedFiles = files.map((file) => {
6+
7+
const parsedFiles = files.flatMap((file) => {
78
const lines = file.split("\n")
9+
810
const filepath = lines[0].split(" ")[1]
9-
const mainContent = lines.slice(4)
11+
12+
// Don't consider diff in deleted files
13+
if (lines[1].startsWith("deleted")) return `deleted ${filepath}`
14+
15+
const mainContent = lines.slice(6).map((line) => {
16+
if (line.startsWith("+") || line.startsWith("-")) {
17+
const trimContent = line.slice(1).trim()
18+
return line[0] + trimContent
19+
} else return line.trim()
20+
})
1021
const changes = mainContent.filter(
1122
(line) => line.startsWith("+") || line.startsWith("-")
1223
).length
1324

1425
if (changes <= maxChanges) {
15-
return file
26+
return `${filepath}\n${mainContent.join("\n")}`
1627
}
1728
skippedFiles.push(`\`${filepath.slice(2)}\``)
29+
return []
1830
})
31+
1932
return { parsedFiles, skippedFiles }
2033
}

0 commit comments

Comments
 (0)