Skip to content

Commit 06a1d76

Browse files
authored
Merge pull request #1 from fastfive-dev/feature/max-file-count
feat: MAX_FILE_COUNT ์ตœ๋Œ€ ํŒŒ์ผ ์ˆ˜๋ฅผ 20์—์„œ 30์œผ๋กœ ์ฆ๊ฐ€
2 parents f558d96 + ca53357 commit 06a1d76

1 file changed

Lines changed: 97 additions & 37 deletions

File tree

โ€Žsrc/bot.tsโ€Ž

Lines changed: 97 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ const OPENAI_API_KEY = "OPENAI_API_KEY";
88
const MAX_PATCH_COUNT = process.env.MAX_PATCH_LENGTH
99
? +process.env.MAX_PATCH_LENGTH
1010
: Infinity;
11-
const MAX_FILE_COUNT = 20;
11+
const MAX_FILE_COUNT = 30;
1212

1313
// ํŒŒ์ผ ๋ณธ๋ฌธ์„ ๊ฐ€์ ธ์˜ฌ ๋•Œ ํ—ˆ์šฉํ•˜๋Š” ์ตœ๋Œ€ ํฌ๊ธฐ (๋ฐ”์ดํŠธ ๋‹จ์œ„)
1414
// ๋„ˆ๋ฌด ํฐ ํŒŒ์ผ์€ ๊ทธ๋Œ€๋กœ ๋‘๋˜, ์ดํ›„ prompt ๊ตฌ์„ฑ ๋‹จ๊ณ„์—์„œ ์ž˜๋ผ๋ƒ…๋‹ˆ๋‹ค.
1515
const MAX_FILE_BYTES = process.env.MAX_FILE_BYTES
1616
? +process.env.MAX_FILE_BYTES
1717
: 64 * 1024; // ๊ธฐ๋ณธ 64KB
1818

19-
// ํ”„๋กฌํ”„ํŠธ์— ํฌํ•จํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ๋Œ€ ๋ฌธ์ž ์ˆ˜ (๊ฐ€๋“œ๋ ˆ์ผ)
19+
// ํ”„๋กฌํ”„ํŠธ์— ํฌํ•จํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ๋Œ€ ๋ฌธ์ž ์ˆ˜ (๊ฐ€๋“œ๋ ˆ์ผ)
2020
// ์ด ๊ฐ’์„ ๋„˜์–ด๊ฐ€๋ฉด ์ค‘๊ฐ„ ๋ถ€๋ถ„์„ ์ž˜๋ผ๋‚ด๊ณ  ์•ž/๋’ค ์ผ๋ถ€๋งŒ ๋‚จ๊น๋‹ˆ๋‹ค.
2121
const MAX_CONTEXT_CHARS = process.env.MAX_CONTEXT_CHARS
2222
? +process.env.MAX_CONTEXT_CHARS
@@ -36,7 +36,7 @@ const GLOBAL_CONTEXT_MODE = process.env.GLOBAL_CONTEXT_MODE || "meta"; // meta |
3636
const fetchFileContent = async (
3737
context: Context,
3838
path: string,
39-
ref: string,
39+
ref: string
4040
): Promise<string | null> => {
4141
try {
4242
const repo = context.repo();
@@ -77,18 +77,28 @@ const buildReviewInput = (
7777
filename: string,
7878
content: string | null,
7979
patch: string,
80-
globalContext: string | null,
80+
globalContext: string | null
8181
): string => {
8282
const parts: string[] = [];
8383

8484
// ํŒŒ์ผ๋ณ„ ๋ฆฌ๋ทฐ ์ง€์นจ์„ ์ตœ์ƒ๋‹จ์— ๋ช…์‹œํ•ด ์ „์—ญ ์ปจํ…์ŠคํŠธ ํŽธํ–ฅ์„ ์ค„์ž„ (STRICT)
8585
parts.push("## ๋ฆฌ๋ทฐ ์ง€์นจ (STRICT)");
8686
parts.push("๋‹ค์Œ์„ ๋ฐ˜๋“œ์‹œ ์ค€์ˆ˜ํ•˜์„ธ์š” โ€” ์–ด๊ธฐ๋ฉด ์‚ฐ์ถœ๋ฌผ์€ ์‹คํŒจ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค.");
87-
parts.push("- **์Šค์ฝ”ํ”„: ์ด ํŒŒ์ผ์˜ Diff๋งŒ** ๋‹ค๋ฃน๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํŒŒ์ผ/์ผ๋ฐ˜๋ก  ์–ธ๊ธ‰ ๊ธˆ์ง€.");
88-
parts.push("- **๊ทผ๊ฑฐ ํ•„์ˆ˜:** ๋ชจ๋“  ์ง€์ ์€ Diff์˜ `+`(์ถ”๊ฐ€) ๋ผ์ธ์— ๊ทผ๊ฑฐํ•ด, ํ•ด๋‹น ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์„ ์ธ๋ผ์ธ ์ฝ”๋“œ๋กœ ํฌํ•จํ•˜์„ธ์š”.");
89-
parts.push("- **์ „์—ญ ์ปจํ…์ŠคํŠธ๋Š” ์ฐธ๊ณ ์šฉ**์ž…๋‹ˆ๋‹ค. ์Šค์ฝ”ํ”„๋ฅผ ๋ฒ—์–ด๋‚œ ๋‚ด์šฉ์ด ํ•„์š”ํ•˜๋ฉด ๊ทธ ํ•ญ๋ชฉ์€ **์ž‘์„ฑํ•˜์ง€ ๋งˆ์„ธ์š”**.");
90-
parts.push("- **์šฐ์„ ์ˆœ์œ„:** ๋ฒ„๊ทธ/๋ณด์•ˆ/์„ฑ๋Šฅ/ํ…Œ์ŠคํŠธ ์ค‘์‹ฌ. ์‚ฌ์†Œํ•œ ์Šคํƒ€์ผ/๊ฐœ์ธ ์ทจํ–ฅ ๊ธˆ์ง€.");
91-
parts.push("- **์Šค์ฝ”ํ”„ ์œ„๋ฐ˜ ๋ฐฉ์ง€:** ๋‹ค๋ฅธ ํŒŒ์ผ์ด๋‚˜ ์ผ๋ฐ˜ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค๋งŒ์„ ์–ธ๊ธ‰ํ•˜๋ ค ํ•  ๊ฒฝ์šฐ, ํ•ด๋‹น ์ฝ”๋ฉ˜ํŠธ๋Š” ์ƒ๋žตํ•ฉ๋‹ˆ๋‹ค.");
87+
parts.push(
88+
"- **์Šค์ฝ”ํ”„: ์ด ํŒŒ์ผ์˜ Diff๋งŒ** ๋‹ค๋ฃน๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํŒŒ์ผ/์ผ๋ฐ˜๋ก  ์–ธ๊ธ‰ ๊ธˆ์ง€."
89+
);
90+
parts.push(
91+
"- **๊ทผ๊ฑฐ ํ•„์ˆ˜:** ๋ชจ๋“  ์ง€์ ์€ Diff์˜ `+`(์ถ”๊ฐ€) ๋ผ์ธ์— ๊ทผ๊ฑฐํ•ด, ํ•ด๋‹น ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์„ ์ธ๋ผ์ธ ์ฝ”๋“œ๋กœ ํฌํ•จํ•˜์„ธ์š”."
92+
);
93+
parts.push(
94+
"- **์ „์—ญ ์ปจํ…์ŠคํŠธ๋Š” ์ฐธ๊ณ ์šฉ**์ž…๋‹ˆ๋‹ค. ์Šค์ฝ”ํ”„๋ฅผ ๋ฒ—์–ด๋‚œ ๋‚ด์šฉ์ด ํ•„์š”ํ•˜๋ฉด ๊ทธ ํ•ญ๋ชฉ์€ **์ž‘์„ฑํ•˜์ง€ ๋งˆ์„ธ์š”**."
95+
);
96+
parts.push(
97+
"- **์šฐ์„ ์ˆœ์œ„:** ๋ฒ„๊ทธ/๋ณด์•ˆ/์„ฑ๋Šฅ/ํ…Œ์ŠคํŠธ ์ค‘์‹ฌ. ์‚ฌ์†Œํ•œ ์Šคํƒ€์ผ/๊ฐœ์ธ ์ทจํ–ฅ ๊ธˆ์ง€."
98+
);
99+
parts.push(
100+
"- **์Šค์ฝ”ํ”„ ์œ„๋ฐ˜ ๋ฐฉ์ง€:** ๋‹ค๋ฅธ ํŒŒ์ผ์ด๋‚˜ ์ผ๋ฐ˜ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค๋งŒ์„ ์–ธ๊ธ‰ํ•˜๋ ค ํ•  ๊ฒฝ์šฐ, ํ•ด๋‹น ์ฝ”๋ฉ˜ํŠธ๋Š” ์ƒ๋žตํ•ฉ๋‹ˆ๋‹ค."
101+
);
92102

93103
parts.push(`\n# File: ${filename}`);
94104

@@ -102,15 +112,19 @@ const buildReviewInput = (
102112
if (content) {
103113
parts.push("\n## ํ˜„์žฌ ํŒŒ์ผ ๋‚ด์šฉ (truncated)");
104114
parts.push("```");
105-
parts.push(truncateForPrompt(content, allocateBudget(MAX_CONTEXT_CHARS, 0.5)));
115+
parts.push(
116+
truncateForPrompt(content, allocateBudget(MAX_CONTEXT_CHARS, 0.5))
117+
);
106118
parts.push("```");
107119
}
108120

109121
// (์„ ํƒ) PR ์ „์—ญ ์ปจํ…์ŠคํŠธ๋Š” ๋งจ ์•„๋ž˜์— ์œ„์น˜์‹œ์ผœ ์˜ํ–ฅ ์ตœ์†Œํ™”
110122
if (globalContext) {
111123
parts.push("\n---\n");
112124
parts.push("# PR ์ „์—ญ ์ปจํ…์ŠคํŠธ (์ฐธ๊ณ ์šฉ)");
113-
parts.push(truncateForPrompt(globalContext, allocateBudget(MAX_CONTEXT_CHARS, 0.4)));
125+
parts.push(
126+
truncateForPrompt(globalContext, allocateBudget(MAX_CONTEXT_CHARS, 0.4))
127+
);
114128
}
115129

116130
return parts.join("\n");
@@ -163,7 +177,7 @@ export const robot = (app: Probot) => {
163177
owner: repo.owner,
164178
repo: repo.repo,
165179
name: OPENAI_API_KEY,
166-
},
180+
}
167181
)) as any;
168182

169183
if (!data?.value) {
@@ -230,7 +244,7 @@ export const robot = (app: Probot) => {
230244
"compareCommits, base:",
231245
context.payload.pull_request.base.sha,
232246
"head:",
233-
context.payload.pull_request.head.sha,
247+
context.payload.pull_request.head.sha
234248
);
235249
log.debug("compareCommits.commits:", commits);
236250
log.debug("compareCommits.files", changedFiles);
@@ -254,8 +268,8 @@ export const robot = (app: Probot) => {
254268
pull_number: pull_request.number,
255269
});
256270

257-
hasSummaryReview = reviews.data.some(
258-
(review) => review.body?.includes("<!-- chatgpt-summary:v1 -->"),
271+
hasSummaryReview = reviews.data.some((review) =>
272+
review.body?.includes("<!-- chatgpt-summary:v1 -->")
259273
);
260274

261275
if (hasSummaryReview) {
@@ -310,7 +324,7 @@ export const robot = (app: Probot) => {
310324
let inlineFallback: string[] = [];
311325

312326
if (isFileCountWithinLimit) {
313-
const aggregatedPatch = changedFiles
327+
const aggregatedPatch = changedFiles
314328
.filter(
315329
(file) =>
316330
(file.status === "modified" || file.status === "added") &&
@@ -335,26 +349,43 @@ export const robot = (app: Probot) => {
335349
let globalContext: string | null = null;
336350
{
337351
const prTitle = pull_request.title || "(no title)";
338-
const changedFileList = changedFiles.map(f => `- ${f.filename} (${f.status})`).join("\n");
339-
const summary = overallReview?.summary ? `\n\n## ๋ณ€๊ฒฝ ์š”์•ฝ\n${overallReview.summary}` : "";
352+
const changedFileList = changedFiles
353+
.map((f) => `- ${f.filename} (${f.status})`)
354+
.join("\n");
355+
const summary = overallReview?.summary
356+
? `\n\n## ๋ณ€๊ฒฝ ์š”์•ฝ\n${overallReview.summary}`
357+
: "";
340358

341359
// meta ๋ชจ๋“œ: ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋งŒ ์ œ๊ณต (์ œ๋ชฉ/์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€/ํŒŒ์ผ ๋ชฉ๋ก)
342360
if (GLOBAL_CONTEXT_MODE === "meta") {
343361
globalContext = [
344362
`## PR ์ œ๋ชฉ\n${prTitle}`,
345-
`\n## ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€(์ง‘๊ณ„)\n${truncateForPrompt(aggregatedCommitMessages, allocateBudget(MAX_GLOBAL_CONTEXT_CHARS, 0.4))}`,
363+
`\n## ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€(์ง‘๊ณ„)\n${truncateForPrompt(
364+
aggregatedCommitMessages,
365+
allocateBudget(MAX_GLOBAL_CONTEXT_CHARS, 0.4)
366+
)}`,
346367
`\n## ๋ณ€๊ฒฝ ํŒŒ์ผ ๋ชฉ๋ก\n${changedFileList}`,
347368
summary,
348369
].join("\n");
349370
} else {
350371
// full ๋ชจ๋“œ: ์ „์ฒด diff ๋ฐœ์ทŒ๋ฅผ ์†Œ๋Ÿ‰๋งŒ ํฌํ•จ (ํ•˜์œ„ ํ˜ธํ™˜)
351-
const diffDigest = aggregatedPatch ? truncateForPrompt(aggregatedPatch, allocateBudget(MAX_GLOBAL_CONTEXT_CHARS, 0.3)) : "";
372+
const diffDigest = aggregatedPatch
373+
? truncateForPrompt(
374+
aggregatedPatch,
375+
allocateBudget(MAX_GLOBAL_CONTEXT_CHARS, 0.3)
376+
)
377+
: "";
352378
globalContext = [
353379
`## PR ์ œ๋ชฉ\n${prTitle}`,
354-
`\n## ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€(์ง‘๊ณ„)\n${truncateForPrompt(aggregatedCommitMessages, allocateBudget(MAX_GLOBAL_CONTEXT_CHARS, 0.3))}`,
380+
`\n## ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€(์ง‘๊ณ„)\n${truncateForPrompt(
381+
aggregatedCommitMessages,
382+
allocateBudget(MAX_GLOBAL_CONTEXT_CHARS, 0.3)
383+
)}`,
355384
`\n## ๋ณ€๊ฒฝ ํŒŒ์ผ ๋ชฉ๋ก\n${changedFileList}`,
356385
summary,
357-
diffDigest ? `\n\n## ์ „์ฒด diff (์ผ๋ถ€ ๋ฐœ์ทŒ)\n\n\`\`\`diff\n${diffDigest}\n\`\`\`` : "",
386+
diffDigest
387+
? `\n\n## ์ „์ฒด diff (์ผ๋ถ€ ๋ฐœ์ทŒ)\n\n\`\`\`diff\n${diffDigest}\n\`\`\``
388+
: "",
358389
].join("\n");
359390
}
360391
}
@@ -388,7 +419,9 @@ export const robot = (app: Probot) => {
388419
}
389420

390421
if (!patch || patch.length > MAX_PATCH_COUNT) {
391-
log.info(`${file.filename} skipped caused by its diff is too large`);
422+
log.info(
423+
`${file.filename} skipped caused by its diff is too large`
424+
);
392425
continue;
393426
}
394427

@@ -398,16 +431,24 @@ export const robot = (app: Probot) => {
398431
fullContent = await fetchFileContent(
399432
context,
400433
file.filename,
401-
context.payload.pull_request.head.sha,
434+
context.payload.pull_request.head.sha
402435
);
403-
if (fullContent && Buffer.byteLength(fullContent, "utf-8") > MAX_FILE_BYTES) {
436+
if (
437+
fullContent &&
438+
Buffer.byteLength(fullContent, "utf-8") > MAX_FILE_BYTES
439+
) {
404440
// Keep but it will be truncated by buildReviewInput/truncateForPrompt
405441
}
406442
} catch (e) {
407443
log.debug(`content fetch failed for ${file.filename}`, e);
408444
}
409445

410-
const reviewInput = buildReviewInput(file.filename, fullContent, patch, globalContext);
446+
const reviewInput = buildReviewInput(
447+
file.filename,
448+
fullContent,
449+
patch,
450+
globalContext
451+
);
411452

412453
try {
413454
const res = await chat?.codeReview(reviewInput);
@@ -420,20 +461,28 @@ export const robot = (app: Probot) => {
420461

421462
if (!res.lgtm || (res.lgtm && REVIEW_ON_LGTM)) {
422463
if (!commentablePaths.has(file.filename)) {
423-
log.info(`PR ํŒŒ์ผ์— patch๊ฐ€ ์—†์–ด ${file.filename}์— ๋Œ€ํ•œ ์ฝ”๋ฉ˜ํŠธ ์ƒ๋žต`);
424-
inlineFallback.push(`\n### ${file.filename}\n${res.review_comment}`);
464+
log.info(
465+
`PR ํŒŒ์ผ์— patch๊ฐ€ ์—†์–ด ${file.filename}์— ๋Œ€ํ•œ ์ฝ”๋ฉ˜ํŠธ ์ƒ๋žต`
466+
);
467+
inlineFallback.push(
468+
`\n### ${file.filename}\n${res.review_comment}`
469+
);
425470
continue;
426471
}
427472
// Compute position against the PR-wide patch to avoid misalignment
428473
const prWidePatch = prFilePatchByPath.get(file.filename) || patch;
429-
if (!prWidePatch || !prWidePatch.includes('@@')) {
430-
inlineFallback.push(`\n### ${file.filename}\n${res.review_comment}`);
474+
if (!prWidePatch || !prWidePatch.includes("@@")) {
475+
inlineFallback.push(
476+
`\n### ${file.filename}\n${res.review_comment}`
477+
);
431478
continue;
432479
}
433480

434481
const position = firstChangedPosition(prWidePatch);
435482
if (!Number.isSafeInteger(position) || position <= 0) {
436-
inlineFallback.push(`\n### ${file.filename}\n${res.review_comment}`);
483+
inlineFallback.push(
484+
`\n### ${file.filename}\n${res.review_comment}`
485+
);
437486
continue;
438487
}
439488
ress.push({
@@ -448,7 +497,9 @@ export const robot = (app: Probot) => {
448497
log.error(`๋ฆฌ๋ทฐ ์‹คํŒจ: ${file.filename} (status=${status})`);
449498
if (data) {
450499
try {
451-
log.error(`GitHub API error payload: ${JSON.stringify(data, null, 2)}`);
500+
log.error(
501+
`GitHub API error payload: ${JSON.stringify(data, null, 2)}`
502+
);
452503
} catch {}
453504
}
454505
log.error("์›์‹œ ์˜ค๋ฅ˜:", e);
@@ -482,7 +533,11 @@ export const robot = (app: Probot) => {
482533
const data = e?.response?.data;
483534
log.error(`๋ฆฌ๋ทฐ ์ƒ์„ฑ ์‹คํŒจ (status=${status})`);
484535
if (data) {
485-
try { log.error(`GitHub API error payload: ${JSON.stringify(data, null, 2)}`); } catch {}
536+
try {
537+
log.error(
538+
`GitHub API error payload: ${JSON.stringify(data, null, 2)}`
539+
);
540+
} catch {}
486541
}
487542

488543
if (status === 422) {
@@ -492,8 +547,13 @@ export const robot = (app: Probot) => {
492547
body = `<!-- chatgpt-summary:v1 -->\n${overallReview.summary}`;
493548
}
494549

495-
if (typeof inlineFallback !== "undefined" && inlineFallback.length) {
496-
body += `\n\n---\nโš ๏ธ ์ธ๋ผ์ธ ์ฃผ์„์„ diff์— ๊ณ ์ •ํ•˜์ง€ ๋ชปํ•ด ๋ณธ๋ฌธ์— ์ฒจ๋ถ€ํ•ฉ๋‹ˆ๋‹ค (422).` + inlineFallback.join("\n");
550+
if (
551+
typeof inlineFallback !== "undefined" &&
552+
inlineFallback.length
553+
) {
554+
body +=
555+
`\n\n---\nโš ๏ธ ์ธ๋ผ์ธ ์ฃผ์„์„ diff์— ๊ณ ์ •ํ•˜์ง€ ๋ชปํ•ด ๋ณธ๋ฌธ์— ์ฒจ๋ถ€ํ•ฉ๋‹ˆ๋‹ค (422).` +
556+
inlineFallback.join("\n");
497557
} else if (ress.length) {
498558
body += `\n\n(์ธ๋ผ์ธ ์ฝ”๋ฉ˜ํŠธ๊ฐ€ ์œ„์น˜ ๋ถˆ์ผ์น˜๋กœ ์ƒ๋žต๋˜์—ˆ์Šต๋‹ˆ๋‹ค.)`;
499559
}
@@ -523,7 +583,7 @@ export const robot = (app: Probot) => {
523583
log.info("successfully reviewed", context.payload.pull_request.html_url);
524584

525585
return "success";
526-
},
586+
}
527587
);
528588
};
529589

@@ -537,7 +597,7 @@ const matchPatterns = (patterns: string[], path: string) => {
537597
: pattern.startsWith("**")
538598
? pattern
539599
: "**/" + pattern,
540-
{ dot: true, nocase: true },
600+
{ dot: true, nocase: true }
541601
);
542602
} catch {
543603
// if the pattern is not a valid glob pattern, try to match it as a regular expression

0 commit comments

Comments
ย (0)