Skip to content

refactor: 라인별 코드리뷰로 변경 #61

refactor: 라인별 코드리뷰로 변경

refactor: 라인별 코드리뷰로 변경 #61

Workflow file for this run

name: Gemini Automated Code Review
on:
pull_request:
types: [opened, synchronize, reopened]
branches: [main]
push:
branches:
- main
workflow_dispatch:
inputs:
pr_number:
description: "리뷰할 PR 번호 (수동 실행 시 필수)"
required: true
jobs:
code-review:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
env:
GH_TOKEN: ${{ github.token }}
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install GitHub CLI
run: sudo apt-get install -y gh jq
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install GoogleGenerativeAI SDK
run: npm install @google/generative-ai@latest
- name: Get git diff for PR
if: github.event_name == 'pull_request'
run: |
echo "EVENT_TYPE=pull_request" >> $GITHUB_ENV
echo "PR_NUMBER=${{ github.event.pull_request.number }}" >> $GITHUB_ENV
git fetch origin "${{ github.event.pull_request.base.ref }}"
git fetch origin "${{ github.event.pull_request.head.ref }}"
git diff --unified=0 "origin/${{ github.event.pull_request.base.ref }}" "origin/${{ github.event.pull_request.head.ref }}" > diff.txt
- name: Get git diff for manual PR review
if: github.event_name == 'workflow_dispatch'
run: |
PR_NUMBER="${{ github.event.inputs.pr_number }}"
echo "EVENT_TYPE=pull_request" >> $GITHUB_ENV
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV
BASE=$(gh pr view $PR_NUMBER --json baseRefName -q .baseRefName)
HEAD=$(gh pr view $PR_NUMBER --json headRefName -q .headRefName)
git fetch origin $BASE
git fetch origin $HEAD
git diff --unified=0 origin/$BASE origin/$HEAD > diff.txt
- name: Detect PR for push event
if: github.event_name == 'push'
run: |
PR_NUMBER=$(gh pr list --state open --json number,headRefName \
--jq ".[] | select(.headRefName==\"${GITHUB_REF_NAME}\") | .number")
if [ -z "$PR_NUMBER" ]; then
echo "Push된 커밋과 연결된 PR을 찾을 수 없습니다."
exit 1
fi
echo "EVENT_TYPE=pull_request" >> $GITHUB_ENV
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV
BASE=$(gh pr view $PR_NUMBER --json baseRefName -q .baseRefName)
HEAD=$(gh pr view $PR_NUMBER --json headRefName -q .headRefName)
git fetch origin $BASE
git fetch origin $HEAD
git diff --unified=0 origin/$BASE origin/$HEAD > diff.txt
- name: Run Gemini Review (File-based Chunking)
id: gemini_review
uses: actions/github-script@v7
with:
script: |
const fs = require("fs");
const { GoogleGenerativeAI } = require("@google/generative-ai");
const rawDiff = fs.readFileSync("diff.txt", "utf8");
const fileDiffs = rawDiff
.split("diff --git")
.slice(1)
.map(block => "diff --git" + block);
const tsDiffs = fileDiffs.filter(block =>
/a\/src\/.*\.(ts|tsx)/.test(block)
);
console.log("Filtered ts/tsx files:", tsDiffs.length);
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
let allComments = [];
for (let i = 0; i < tsDiffs.length; i++) {
const diffBlock = tsDiffs[i];
const prompt = `
당신은 시니어 프론트엔드 개발자입니다.
아래는 특정 파일의 diff입니다.
**src/ 내부의 .ts / .tsx 파일만 리뷰합니다.**
JSON 배열 형식만 출력하세요:
[
{
"path": "파일경로",
"line": 라인번호,
"text": "리뷰내용",
"side": "RIGHT"
}
]
JSON 외 텍스트 금지.
<file diff ${i + 1}/${tsDiffs.length}>
${diffBlock}
</file diff>
`;
console.log("Reviewing file " + (i + 1));
try {
const result = await model.generateContent(prompt);
const text = result.response.text();
const parsed = JSON.parse(text);
allComments.push(...parsed);
} catch (err) {
console.log("⚠️ Gemini error for file", i + 1);
console.log(err);
}
}
fs.writeFileSync("review_result.txt", JSON.stringify(allComments, null, 2));
console.log("Review saved!");
- name: Add PR Review Comments
uses: nbaztec/add-pr-review-comment@v1.0.7
with:
comments: ${{ steps.gemini_review.outputs.comment }}
repo-token: ${{ secrets.GITHUB_TOKEN }}
repo-token-user-login: "github-actions[bot]"
allow-repeats: false