Skip to content

Commit 97003f9

Browse files
committed
fix: AI PR 리뷰가 우리 글로벌 규칙 체크하도록 수정
1 parent 156e9c7 commit 97003f9

File tree

1 file changed

+62
-119
lines changed

1 file changed

+62
-119
lines changed

.github/workflows/ai-pr-review.yml

Lines changed: 62 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,138 +1,81 @@
1-
name: AI PR Review
1+
name: AI Code Review
22

33
on:
44
pull_request:
5-
types: [opened, synchronize, reopened]
5+
types: [opened, synchronize]
66

77
jobs:
88
ai-review:
99
runs-on: ubuntu-latest
10-
if: github.actor != 'dependabot[bot]'
1110
permissions:
1211
contents: read
1312
pull-requests: write
14-
issues: write
1513

1614
steps:
17-
- name: Checkout code
18-
uses: actions/checkout@v4
19-
with:
20-
fetch-depth: 0
21-
22-
- name: AI Code Review
23-
uses: actions/github-script@v7
24-
with:
25-
script: |
26-
const OPENROUTER_API_KEY = '${{ secrets.OPENROUTER_API_KEY }}';
27-
28-
const diff = await github.rest.repos.compareCommits({
29-
owner: context.repo.owner,
30-
repo: context.repo.repo,
31-
base: context.payload.pull_request.base.sha,
32-
head: context.payload.pull_request.head.sha
33-
});
34-
35-
const filesToReview = diff.data.files.filter(file =>
36-
file.patch &&
37-
!file.filename.includes('test/') &&
38-
!file.filename.includes('build/') &&
39-
(file.filename.endsWith('.kt') ||
40-
file.filename.endsWith('.kts') ||
41-
file.filename.endsWith('.java') ||
42-
file.filename.endsWith('.yml') ||
43-
file.filename.endsWith('.yaml') ||
44-
file.filename.endsWith('.md'))
45-
);
46-
47-
if (filesToReview.length === 0) {
48-
console.log('No files to review');
49-
return;
50-
}
51-
52-
console.log(`Found ${filesToReview.length} files to review`);
53-
54-
let overallReview = `## 🤖 AI 코드 리뷰\n\n`;
55-
56-
let allChanges = '';
57-
const filesSummary = [];
58-
59-
for (const file of filesToReview) {
60-
filesSummary.push(`- ${file.filename} (+${file.additions}/-${file.deletions})`);
61-
allChanges += `\n### ${file.filename}\n`;
62-
allChanges += `\`\`\`diff\n${file.patch}\n\`\`\`\n`;
63-
}
64-
65-
try {
66-
const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
67-
method: 'POST',
68-
headers: {
69-
'Authorization': `Bearer ${OPENROUTER_API_KEY}`,
70-
'Content-Type': 'application/json'
71-
},
72-
body: JSON.stringify({
73-
model: 'x-ai/grok-4-fast:free',
74-
messages: [{
75-
role: 'system',
76-
content: `코드 리뷰어입니다. 다음 규칙만 검토하세요:
15+
- uses: actions/checkout@v4
16+
with:
17+
fetch-depth: 0
18+
19+
- uses: actions/github-script@v7
20+
env:
21+
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
22+
with:
23+
script: |
24+
const diff = await github.rest.repos.compareCommits({
25+
owner: context.repo.owner,
26+
repo: context.repo.repo,
27+
base: context.payload.pull_request.base.sha,
28+
head: context.payload.pull_request.head.sha
29+
});
7730
78-
## 검토 항목
31+
const kotlinFiles = diff.data.files.filter(file =>
32+
(file.filename.endsWith('.kt') || file.filename.endsWith('.kts')) && file.patch
33+
);
34+
35+
if (kotlinFiles.length === 0) return;
36+
37+
for (const file of kotlinFiles.slice(0, 3)) {
38+
const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
39+
method: 'POST',
40+
headers: {
41+
'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`,
42+
'Content-Type': 'application/json'
43+
},
44+
body: JSON.stringify({
45+
model: 'x-ai/grok-4-fast:free',
46+
messages: [{
47+
role: 'system',
48+
content: `코드 리뷰어입니다. 다음 규칙을 검토하세요:
49+
50+
## 필수 검토 항목
7951
1. **글로벌 익셉션 처리**: @ControllerAdvice 사용, 표준 에러 응답
8052
2. **ApiResponse 사용**: 모든 API는 ApiResponse<T>로 감싸서 응답
8153
3. **Kotlin 최적화**: data class, null safety, when 표현식, 확장함수 등
8254
4. **ktlint 규칙**: 포맷팅, 네이밍 컨벤션
8355

8456
## 응답 형식
85-
### ✅ 준수사항
86-
- [잘 지켜진 부분]
87-
88-
### ❌ 위반사항
89-
- [파일:라인] 문제점과 수정방법
90-
91-
**점수**: X/10`
92-
}, {
93-
role: 'user',
94-
content: `다음 PR의 변경사항을 리뷰해주세요:
95-
96-
PR 제목: ${{ github.event.pull_request.title }}
97-
PR 설명: ${{ github.event.pull_request.body }}
98-
99-
변경된 파일:
100-
${filesSummary.join('\n')}
101-
102-
전체 변경사항:
103-
${allChanges}`
104-
}],
105-
temperature: 0.3
106-
})
107-
});
108-
109-
if (response.ok) {
110-
const result = await response.json();
111-
overallReview += result.choices[0].message.content + '\n\n';
112-
console.log('✅ API review completed successfully!');
113-
} else {
114-
const errorText = await response.text();
115-
console.error('API request failed:', response.status, errorText);
116-
overallReview += `> ⚠️ 리뷰 실패: ${response.status} - ${errorText}\n\n`;
117-
}
118-
} catch (error) {
119-
console.error('Error during review:', error);
120-
overallReview += `> ⚠️ 리뷰 실패: ${error.message}\n\n`;
121-
}
122-
123-
overallReview += `---\n`;
124-
overallReview += `<details>\n<summary>💡 리뷰 정보</summary>\n\n`;
125-
overallReview += `- 모델: Grok-4-fast\n`;
126-
overallReview += `- 리뷰 시간: ${new Date().toLocaleString('ko-KR', {timeZone: 'Asia/Seoul'})}\n`;
127-
overallReview += `- PR: #${{ github.event.number }}\n\n`;
128-
overallReview += `</details>`;
129-
130-
await github.rest.pulls.createReview({
131-
owner: context.repo.owner,
132-
repo: context.repo.repo,
133-
pull_number: context.payload.pull_request.number,
134-
body: overallReview,
135-
event: 'COMMENT'
136-
});
137-
138-
console.log(`✅ Review completed for ${filesToReview.length} files!`);
57+
🟢 **좋은점**: [규칙을 잘 지킨 부분]
58+
🟡 **개선사항**: [더 좋게 할 수 있는 부분]
59+
🔴 **문제점**: [반드시 수정해야 할 부분]`
60+
}, {
61+
role: 'user',
62+
content: `파일: ${file.filename}\n\n변경사항:\n${file.patch}`
63+
}],
64+
max_tokens: 500,
65+
temperature: 0
66+
})
67+
});
68+
69+
if (response.ok) {
70+
const result = await response.json();
71+
const review = result.choices[0].message.content;
72+
73+
await github.rest.pulls.createReview({
74+
owner: context.repo.owner,
75+
repo: context.repo.repo,
76+
pull_number: context.payload.pull_request.number,
77+
body: `## 🤖 AI 리뷰 - \`${file.filename}\`\n\n${review}`,
78+
event: 'COMMENT'
79+
});
80+
}
81+
}

0 commit comments

Comments
 (0)