fix: AI PR 리뷰 워크플로우 완전 수정 #4
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: AI PR Review | ||
| on: | ||
| pull_request: | ||
| types: [opened, synchronize, reopened] | ||
| jobs: | ||
| ai-review: | ||
| runs-on: ubuntu-latest | ||
| if: github.actor != 'dependabot[bot]' | ||
| permissions: | ||
| contents: read | ||
| pull-requests: write | ||
| issues: write | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| - name: AI Code Review | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const OPENROUTER_API_KEY = '${{ secrets.OPENROUTER_API_KEY }}'; | ||
| const diff = await github.rest.repos.compareCommits({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| base: context.payload.pull_request.base.sha, | ||
| head: context.payload.pull_request.head.sha | ||
| }); | ||
| const filesToReview = diff.data.files.filter(file => | ||
| file.patch && | ||
| !file.filename.includes('test/') && | ||
| !file.filename.includes('build/') && | ||
| (file.filename.endsWith('.kt') || | ||
| file.filename.endsWith('.kts') || | ||
| file.filename.endsWith('.java') || | ||
| file.filename.endsWith('.yml') || | ||
| file.filename.endsWith('.yaml') || | ||
| file.filename.endsWith('.md')) | ||
| ); | ||
| if (filesToReview.length === 0) { | ||
| console.log('No files to review'); | ||
| return; | ||
| } | ||
| console.log(`Found ${filesToReview.length} files to review`); | ||
| let overallReview = `## 🤖 AI 코드 리뷰\n\n`; | ||
| let allChanges = ''; | ||
| const filesSummary = []; | ||
| for (const file of filesToReview) { | ||
| filesSummary.push(`- ${file.filename} (+${file.additions}/-${file.deletions})`); | ||
| allChanges += `\n### ${file.filename}\n`; | ||
| allChanges += `\`\`\`diff\n${file.patch}\n\`\`\`\n`; | ||
| } | ||
| try { | ||
| const response = await fetch('https://openrouter.ai/api/v1/chat/completions', { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Authorization': `Bearer ${OPENROUTER_API_KEY}`, | ||
| 'Content-Type': 'application/json' | ||
| }, | ||
| body: JSON.stringify({ | ||
| model: 'x-ai/grok-4-fast:free', | ||
| messages: [{ | ||
| role: 'system', | ||
| content: `코드 리뷰어입니다. 다음 규칙만 검토하세요: | ||
| ## 검토 항목 | ||
| 1. **글로벌 익셉션 처리**: @ControllerAdvice 사용, 표준 에러 응답 | ||
| 2. **ApiResponse 사용**: 모든 API는 ApiResponse<T>로 감싸서 응답 | ||
| 3. **Kotlin 최적화**: data class, null safety, when 표현식, 확장함수 등 | ||
| 4. **ktlint 규칙**: 포맷팅, 네이밍 컨벤션 | ||
| ## 응답 형식 | ||
| ### ✅ 준수사항 | ||
| - [잘 지켜진 부분] | ||
| ### ❌ 위반사항 | ||
| - [파일:라인] 문제점과 수정방법 | ||
| **점수**: X/10` | ||
| }, { | ||
| role: 'user', | ||
| content: `다음 PR의 변경사항을 리뷰해주세요: | ||
| PR 제목: ${{ github.event.pull_request.title }} | ||
| PR 설명: ${{ github.event.pull_request.body }} | ||
| 변경된 파일: | ||
| ${filesSummary.join('\n')} | ||
| 전체 변경사항: | ||
| ${allChanges}` | ||
| }], | ||
| temperature: 0.3 | ||
| }) | ||
| }); | ||
| if (response.ok) { | ||
| const result = await response.json(); | ||
| overallReview += result.choices[0].message.content + '\n\n'; | ||
| console.log('✅ API review completed successfully!'); | ||
| } else { | ||
| const errorText = await response.text(); | ||
| console.error('API request failed:', response.status, errorText); | ||
| overallReview += `> ⚠️ 리뷰 실패: ${response.status} - ${errorText}\n\n`; | ||
| } | ||
| } catch (error) { | ||
| console.error('Error during review:', error); | ||
| overallReview += `> ⚠️ 리뷰 실패: ${error.message}\n\n`; | ||
| } | ||
| overallReview += `---\n`; | ||
| overallReview += `<details>\n<summary>💡 리뷰 정보</summary>\n\n`; | ||
| overallReview += `- 모델: Grok-4-fast\n`; | ||
| overallReview += `- 리뷰 시간: ${new Date().toLocaleString('ko-KR', {timeZone: 'Asia/Seoul'})}\n`; | ||
| overallReview += `- PR: #${{ github.event.number }}\n\n`; | ||
| overallReview += `</details>`; | ||
| await github.rest.pulls.createReview({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| pull_number: context.payload.pull_request.number, | ||
| body: overallReview, | ||
| event: 'COMMENT' | ||
| }); | ||
| console.log(`✅ Review completed for ${filesToReview.length} files!`); | ||