Skip to content

Commit 4673f18

Browse files
committed
feat: 코드 리뷰어 지침 및 출력 형식 개선
1 parent 06a1d76 commit 4673f18

2 files changed

Lines changed: 91 additions & 57 deletions

File tree

action/index.cjs

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -150395,7 +150395,7 @@ const OPENAI_API_KEY = "OPENAI_API_KEY";
150395150395
const MAX_PATCH_COUNT = process.env.MAX_PATCH_LENGTH
150396150396
? +process.env.MAX_PATCH_LENGTH
150397150397
: Infinity;
150398-
const MAX_FILE_COUNT = 20;
150398+
const MAX_FILE_COUNT = 30;
150399150399
// 파일 본문을 가져올 때 허용하는 최대 크기 (바이트 단위)
150400150400
// 너무 큰 파일은 그대로 두되, 이후 prompt 구성 단계에서 잘라냅니다.
150401150401
const MAX_FILE_BYTES = process.env.MAX_FILE_BYTES
@@ -150648,8 +150648,12 @@ const robot = (app) => {
150648150648
let globalContext = null;
150649150649
{
150650150650
const prTitle = pull_request.title || "(no title)";
150651-
const changedFileList = changedFiles.map(f => `- ${f.filename} (${f.status})`).join("\n");
150652-
const summary = overallReview?.summary ? `\n\n## 변경 요약\n${overallReview.summary}` : "";
150651+
const changedFileList = changedFiles
150652+
.map((f) => `- ${f.filename} (${f.status})`)
150653+
.join("\n");
150654+
const summary = overallReview?.summary
150655+
? `\n\n## 변경 요약\n${overallReview.summary}`
150656+
: "";
150653150657
// meta 모드: 메타데이터만 제공 (제목/커밋 메시지/파일 목록)
150654150658
if (GLOBAL_CONTEXT_MODE === "meta") {
150655150659
globalContext = [
@@ -150661,13 +150665,17 @@ const robot = (app) => {
150661150665
}
150662150666
else {
150663150667
// full 모드: 전체 diff 발췌를 소량만 포함 (하위 호환)
150664-
const diffDigest = aggregatedPatch ? truncateForPrompt(aggregatedPatch, allocateBudget(MAX_GLOBAL_CONTEXT_CHARS, 0.3)) : "";
150668+
const diffDigest = aggregatedPatch
150669+
? truncateForPrompt(aggregatedPatch, allocateBudget(MAX_GLOBAL_CONTEXT_CHARS, 0.3))
150670+
: "";
150665150671
globalContext = [
150666150672
`## PR 제목\n${prTitle}`,
150667150673
`\n## 커밋 메시지(집계)\n${truncateForPrompt(aggregatedCommitMessages, allocateBudget(MAX_GLOBAL_CONTEXT_CHARS, 0.3))}`,
150668150674
`\n## 변경 파일 목록\n${changedFileList}`,
150669150675
summary,
150670-
diffDigest ? `\n\n## 전체 diff (일부 발췌)\n\n\`\`\`diff\n${diffDigest}\n\`\`\`` : "",
150676+
diffDigest
150677+
? `\n\n## 전체 diff (일부 발췌)\n\n\`\`\`diff\n${diffDigest}\n\`\`\``
150678+
: "",
150671150679
].join("\n");
150672150680
}
150673150681
}
@@ -150705,7 +150713,8 @@ const robot = (app) => {
150705150713
try {
150706150714
// Only fetch content for reasonably sized files (octokit returns size in metadata, but we guard by prompt length later)
150707150715
fullContent = await fetchFileContent(context, file.filename, context.payload.pull_request.head.sha);
150708-
if (fullContent && Buffer.byteLength(fullContent, "utf-8") > MAX_FILE_BYTES) {
150716+
if (fullContent &&
150717+
Buffer.byteLength(fullContent, "utf-8") > MAX_FILE_BYTES) {
150709150718
// Keep but it will be truncated by buildReviewInput/truncateForPrompt
150710150719
}
150711150720
}
@@ -150728,7 +150737,7 @@ const robot = (app) => {
150728150737
}
150729150738
// Compute position against the PR-wide patch to avoid misalignment
150730150739
const prWidePatch = prFilePatchByPath.get(file.filename) || patch;
150731-
if (!prWidePatch || !prWidePatch.includes('@@')) {
150740+
if (!prWidePatch || !prWidePatch.includes("@@")) {
150732150741
inlineFallback.push(`\n### ${file.filename}\n${res.review_comment}`);
150733150742
continue;
150734150743
}
@@ -150795,8 +150804,11 @@ const robot = (app) => {
150795150804
if (overallReview && overallReview.summary) {
150796150805
body = `<!-- chatgpt-summary:v1 -->\n${overallReview.summary}`;
150797150806
}
150798-
if (typeof inlineFallback !== "undefined" && inlineFallback.length) {
150799-
body += `\n\n---\n⚠️ 인라인 주석을 diff에 고정하지 못해 본문에 첨부합니다 (422).` + inlineFallback.join("\n");
150807+
if (typeof inlineFallback !== "undefined" &&
150808+
inlineFallback.length) {
150809+
body +=
150810+
`\n\n---\n⚠️ 인라인 주석을 diff에 고정하지 못해 본문에 첨부합니다 (422).` +
150811+
inlineFallback.join("\n");
150800150812
}
150801150813
else if (ress.length) {
150802150814
body += `\n\n(인라인 코멘트가 위치 불일치로 생략되었습니다.)`;
@@ -150886,30 +150898,41 @@ class Chat {
150886150898
generateSystemPrompt(type) {
150887150899
const prompts = {
150888150900
review: `
150889-
당신은 시니어 개발자입니다. 코드 변경(diff)을 리뷰하세요.
150890-
150891-
⚠️ 출력은 반드시 **JSON 하나만** 내야 합니다(코드펜스/추가 텍스트 금지). 스키마는 아래와 같습니다. **필드는 정확히 이 두 개만 포함하세요. 다른 키를 추가하지 마세요.**
150892-
{
150893-
"lgtm": boolean,
150894-
"review_comment": string
150895-
}
150896-
150897-
150898-
규칙:
150899-
- 중요 문제/제안만 포함하세요 (사소한 스타일/포맷 지적 금지).
150900-
- **스코프 준수:** 이 파일의 Diff에 포함된 변경 내용만 다룹니다. 다른 파일/일반론 언급 금지.
150901-
- **근거 제시:** 각 지적은 반드시 Diff의 추가된 코드(+ 라인)에 근거해, 해당 코드 스니펫을 인라인 코드로 포함하세요.
150902-
- Diff에 근거하지 못하는 내용은 **작성하지 마세요**.
150903-
- **추측/가정(예: "정의되어 있지 않을 수 있음", "null일 수 있음", "~라면 확인이 필요합니다." 등)만으로 문제를 지적하지 마세요. 실제 추가된 코드에 명확히 드러난 문제만 언급하세요.**
150904-
- **확인/질문(예: '의도 확인 필요', '이 값이 맞는지 확인해 주세요' 등)만을 위한 코멘트는 남기지 마세요.**
150905-
- 문제가 없으면 { "lgtm": true, "review_comment": "" } 로 **정확히** 답하세요.
150906-
- 문제가 있으면 lgtm=false로 두고, review_comment는 한국어 + Markdown 불릿으로 간결히 작성하세요.
150907-
150908-
권장 레이아웃(리뷰 코멘트 본문, 선택적):
150909-
### 📌 Review Summary
150910-
- **🐞 잠재적 버그**: ...
150911-
- **🚀 성능**: ...
150912-
- **🧠 가독성/유지보수성**: ...
150901+
당신은 코드 리뷰어입니다. **진짜 문제만** 짧게 지적하세요.
150902+
150903+
⚠️ 출력 형식 (JSON만, 코드펜스 없이):
150904+
{ "lgtm": boolean, "review_comment": string }
150905+
150906+
---
150907+
150908+
### ✅ 지적할 것 (ONLY these):
150909+
| 심각도 | 유형 | 예시 |
150910+
|--------|------|------|
150911+
| 🔴 높음 | 런타임 버그/크래시 | null 역참조, 정의되지 않은 변수 사용 |
150912+
| 🔴 높음 | 보안 취약점 | SQL 인젝션, XSS, 인증/인가 누락 |
150913+
| 🟠 중간 | 문법 오류/오타 | 변수명 오타, 잘못된 연산자, 누락된 문자 |
150914+
| 🟠 중간 | 명백한 로직 오류 | 조건 반전, off-by-one, 무한 루프 |
150915+
150916+
### ❌ 절대 지적하지 않을 것:
150917+
- 스타일/포맷팅 (린터 영역)
150918+
- 성능 제안 (명백한 O(n²) 등이 아닌 이상)
150919+
- "~하면 좋을 것 같다", "~를 고려해보세요" 식의 선호 기반 제안
150920+
- 의도적으로 보이는 코드 (빈 catch 블록, 하드코딩된 설정값, 특정 패턴)
150921+
- 추측성 코멘트 ("~일 수 있음", "~인지 확인 필요", "누락 가능성")
150922+
- 컨텍스트 없이 판단할 수 없는 사항
150923+
150924+
---
150925+
150926+
### 규칙:
150927+
1. Diff의 '+' 라인에 **명확히 드러난 문제만** 지적. 추측/가정 금지.
150928+
2. 각 지적에 해당 코드 스니펫을 인라인 코드로 포함하세요.
150929+
3. 의도적인 코드는 개발자의 선택으로 존중하고 지적하지 마세요.
150930+
4. **심각도 🔴 높음 또는 🟠 중간인 이슈가 있을 때만 lgtm=false**
150931+
5. 문제가 없으면 반드시: { "lgtm": true, "review_comment": "" }
150932+
150933+
### review_comment 작성 형식 (문제 있을 때):
150934+
- \`해당 코드\` - [🔴] 문제 설명
150935+
- 예: \`if (x = 1)\` - 할당 연산자(\`=\`) 사용됨, 비교 연산자(\`===\`) 의도인지 확인
150913150936

150914150937
Diff 형식: '-' 삭제, '+' 추가, 나머지 맥락.
150915150938
`,

src/chat.ts

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,30 +30,41 @@ export class Chat {
3030
private generateSystemPrompt(type: "review" | "summary"): string {
3131
const prompts = {
3232
review: `
33-
당신은 시니어 개발자입니다. 코드 변경(diff)을 리뷰하세요.
34-
35-
⚠️ 출력은 반드시 **JSON 하나만** 내야 합니다(코드펜스/추가 텍스트 금지). 스키마는 아래와 같습니다. **필드는 정확히 이 두 개만 포함하세요. 다른 키를 추가하지 마세요.**
36-
{
37-
"lgtm": boolean,
38-
"review_comment": string
39-
}
40-
41-
42-
규칙:
43-
- 중요 문제/제안만 포함하세요 (사소한 스타일/포맷 지적 금지).
44-
- **스코프 준수:** 이 파일의 Diff에 포함된 변경 내용만 다룹니다. 다른 파일/일반론 언급 금지.
45-
- **근거 제시:** 각 지적은 반드시 Diff의 추가된 코드(+ 라인)에 근거해, 해당 코드 스니펫을 인라인 코드로 포함하세요.
46-
- Diff에 근거하지 못하는 내용은 **작성하지 마세요**.
47-
- **추측/가정(예: "정의되어 있지 않을 수 있음", "null일 수 있음", "~라면 확인이 필요합니다." 등)만으로 문제를 지적하지 마세요. 실제 추가된 코드에 명확히 드러난 문제만 언급하세요.**
48-
- **확인/질문(예: '의도 확인 필요', '이 값이 맞는지 확인해 주세요' 등)만을 위한 코멘트는 남기지 마세요.**
49-
- 문제가 없으면 { "lgtm": true, "review_comment": "" } 로 **정확히** 답하세요.
50-
- 문제가 있으면 lgtm=false로 두고, review_comment는 한국어 + Markdown 불릿으로 간결히 작성하세요.
51-
52-
권장 레이아웃(리뷰 코멘트 본문, 선택적):
53-
### 📌 Review Summary
54-
- **🐞 잠재적 버그**: ...
55-
- **🚀 성능**: ...
56-
- **🧠 가독성/유지보수성**: ...
33+
당신은 코드 리뷰어입니다. **진짜 문제만** 짧게 지적하세요.
34+
35+
⚠️ 출력 형식 (JSON만, 코드펜스 없이):
36+
{ "lgtm": boolean, "review_comment": string }
37+
38+
---
39+
40+
### ✅ 지적할 것 (ONLY these):
41+
| 심각도 | 유형 | 예시 |
42+
|--------|------|------|
43+
| 🔴 높음 | 런타임 버그/크래시 | null 역참조, 정의되지 않은 변수 사용 |
44+
| 🔴 높음 | 보안 취약점 | SQL 인젝션, XSS, 인증/인가 누락 |
45+
| 🟠 중간 | 문법 오류/오타 | 변수명 오타, 잘못된 연산자, 누락된 문자 |
46+
| 🟠 중간 | 명백한 로직 오류 | 조건 반전, off-by-one, 무한 루프 |
47+
48+
### ❌ 절대 지적하지 않을 것:
49+
- 스타일/포맷팅 (린터 영역)
50+
- 성능 제안 (명백한 O(n²) 등이 아닌 이상)
51+
- "~하면 좋을 것 같다", "~를 고려해보세요" 식의 선호 기반 제안
52+
- 의도적으로 보이는 코드 (빈 catch 블록, 하드코딩된 설정값, 특정 패턴)
53+
- 추측성 코멘트 ("~일 수 있음", "~인지 확인 필요", "누락 가능성")
54+
- 컨텍스트 없이 판단할 수 없는 사항
55+
56+
---
57+
58+
### 규칙:
59+
1. Diff의 '+' 라인에 **명확히 드러난 문제만** 지적. 추측/가정 금지.
60+
2. 각 지적에 해당 코드 스니펫을 인라인 코드로 포함하세요.
61+
3. 의도적인 코드는 개발자의 선택으로 존중하고 지적하지 마세요.
62+
4. **심각도 🔴 높음 또는 🟠 중간인 이슈가 있을 때만 lgtm=false**
63+
5. 문제가 없으면 반드시: { "lgtm": true, "review_comment": "" }
64+
65+
### review_comment 작성 형식 (문제 있을 때):
66+
- \`해당 코드\` - [🔴] 문제 설명
67+
- 예: \`if (x = 1)\` - 할당 연산자(\`=\`) 사용됨, 비교 연산자(\`===\`) 의도인지 확인
5768
5869
Diff 형식: '-' 삭제, '+' 추가, 나머지 맥락.
5970
`,

0 commit comments

Comments
 (0)