Skip to content

Commit 40aa2ca

Browse files
committed
feat: 코드 리뷰 및 요약 기능 개선 (코멘트 형식 및 출력 구조 변경)
1 parent 3b21a2e commit 40aa2ca

2 files changed

Lines changed: 298 additions & 78 deletions

File tree

src/bot.ts

Lines changed: 77 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -409,8 +409,16 @@ export const robot = (app: Probot) => {
409409
const isFileCountWithinLimit = changedFiles.length <= MAX_FILE_COUNT;
410410

411411
const ress = [];
412-
let overallReview: { summary: string } | null = null;
413-
// 인라인 코멘트가 위치 불일치(예: 422)로 실패할 경우, 본문 코멘트로 대체하기 위해 누적하는 버퍼
412+
type SummaryResult = {
413+
changeType: string;
414+
title: string;
415+
summary: string;
416+
walkthrough: Array<{ file: string; changes: string; intent: string }>;
417+
affectedAreas: string[];
418+
risks: Array<{ level: string; description: string }>;
419+
testingNotes: string | null;
420+
};
421+
let overallReview: SummaryResult | null = null;
414422
let inlineFallback: string[] = [];
415423

416424
if (isFileCountWithinLimit) {
@@ -434,16 +442,12 @@ export const robot = (app: Probot) => {
434442
}
435443

436444
const prTitle = pull_request.title || "(no title)";
437-
const summary = overallReview?.summary
438-
? `\n## 변경 요약\n${overallReview.summary}`
439-
: "";
440445
const prMeta = [
441446
`## PR 제목\n${prTitle}`,
442447
`\n## 커밋 메시지\n${truncateForPrompt(
443448
aggregatedCommitMessages,
444449
allocateBudget(MAX_GLOBAL_CONTEXT_CHARS, 0.3)
445450
)}`,
446-
summary,
447451
].join("\n");
448452

449453
let prFilePatchByPath = new Map<string, string>();
@@ -531,33 +535,41 @@ export const robot = (app: Probot) => {
531535
}
532536

533537
if (!res.lgtm || (res.lgtm && REVIEW_ON_LGTM)) {
538+
const formatCommentBody = (c: typeof res.comments[0]) => {
539+
const severityEmoji = c.severity === "critical" ? "🔴" : "🟠";
540+
return `${severityEmoji} **[${c.category}]** ${c.body}`;
541+
};
542+
534543
if (!commentablePaths.has(file.filename)) {
535544
log.info(
536545
`PR 파일에 patch가 없어 ${file.filename}에 대한 코멘트 생략`
537546
);
538-
const fallbackBody = res.comments.map((c) => c.body).join("\n");
547+
const fallbackBody = res.comments.map(formatCommentBody).join("\n");
539548
inlineFallback.push(`\n### ${file.filename}\n${fallbackBody}`);
540549
continue;
541550
}
542551

543552
const prWidePatch = prFilePatchByPath.get(file.filename) || patch;
544553
if (!prWidePatch || !prWidePatch.includes("@@")) {
545-
const fallbackBody = res.comments.map((c) => c.body).join("\n");
554+
const fallbackBody = res.comments.map(formatCommentBody).join("\n");
546555
inlineFallback.push(`\n### ${file.filename}\n${fallbackBody}`);
547556
continue;
548557
}
549558

550559
for (const comment of res.comments) {
551560
const position = comment.line;
561+
const severityEmoji = comment.severity === "critical" ? "🔴" : "🟠";
562+
const formattedBody = `${severityEmoji} **[${comment.category}]** ${comment.body}`;
563+
552564
if (!Number.isSafeInteger(position) || position <= 0) {
553565
inlineFallback.push(
554-
`\n### ${file.filename}\n${comment.body}`
566+
`\n### ${file.filename}\n${formattedBody}`
555567
);
556568
continue;
557569
}
558570
ress.push({
559571
path: file.filename,
560-
body: comment.body,
572+
body: formattedBody,
561573
position,
562574
});
563575
}
@@ -578,10 +590,63 @@ export const robot = (app: Probot) => {
578590
}
579591
}
580592

593+
const formatSummaryBody = (review: SummaryResult): string => {
594+
const changeTypeEmoji: Record<string, string> = {
595+
feature: "✨",
596+
bugfix: "🐛",
597+
refactor: "♻️",
598+
docs: "📝",
599+
test: "🧪",
600+
chore: "🔧",
601+
};
602+
const riskEmoji: Record<string, string> = {
603+
high: "🔴",
604+
medium: "🟠",
605+
low: "🟡",
606+
};
607+
608+
const parts: string[] = [];
609+
parts.push(`## ${changeTypeEmoji[review.changeType] || "📋"} ${review.title}`);
610+
parts.push("");
611+
parts.push(review.summary);
612+
613+
if (review.walkthrough.length > 0) {
614+
parts.push("");
615+
parts.push("### 📂 변경 파일");
616+
parts.push("| 파일 | 변경 내용 | 의도 |");
617+
parts.push("|------|----------|------|");
618+
for (const w of review.walkthrough) {
619+
parts.push(`| \`${w.file}\` | ${w.changes} | ${w.intent} |`);
620+
}
621+
}
622+
623+
if (review.affectedAreas.length > 0) {
624+
parts.push("");
625+
parts.push(`### 🎯 영향 범위`);
626+
parts.push(review.affectedAreas.map((a) => `- ${a}`).join("\n"));
627+
}
628+
629+
if (review.risks.length > 0) {
630+
parts.push("");
631+
parts.push("### ⚠️ 리스크");
632+
for (const r of review.risks) {
633+
parts.push(`- ${riskEmoji[r.level] || "⚪"} **${r.level.toUpperCase()}**: ${r.description}`);
634+
}
635+
}
636+
637+
if (review.testingNotes) {
638+
parts.push("");
639+
parts.push("### 🧪 테스트 참고사항");
640+
parts.push(review.testingNotes);
641+
}
642+
643+
return parts.join("\n");
644+
};
645+
581646
try {
582647
let body = "LGTM 👍";
583648
if (overallReview && overallReview.summary) {
584-
body = `<!-- chatgpt-summary:v1 -->\n${overallReview.summary}`;
649+
body = `<!-- chatgpt-summary:v1 -->\n${formatSummaryBody(overallReview)}`;
585650
} else if (ress.length) {
586651
body = "Code review by ChatGPT";
587652
}
@@ -615,7 +680,7 @@ export const robot = (app: Probot) => {
615680
try {
616681
let body = "LGTM 👍";
617682
if (overallReview && overallReview.summary) {
618-
body = `<!-- chatgpt-summary:v1 -->\n${overallReview.summary}`;
683+
body = `<!-- chatgpt-summary:v1 -->\n${formatSummaryBody(overallReview)}`;
619684
}
620685

621686
if (

0 commit comments

Comments
 (0)