name: 코드 리뷰
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
permissions:
pull-requests: write
contents: read
issues: write
jobs:
code-review:
runs-on: ubuntu-latest
# 드래프트 PR은 자동 코드 리뷰 건너뛰기
if: github.event.pull_request.draft == false
steps:
- name: 리포지토리 체크아웃
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- name: Cursor CLI 설치
run: |
curl https://cursor.com/install -fsS | bash
echo "$HOME/.cursor/bin" >> $GITHUB_PATH
- name: git 사용자 정보 설정
run: |
git config user.name "Cursor 에이전트"
git config user.email "cursoragent@cursor.com"
- name: 자동 코드 리뷰 실행
env:
CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }}
MODEL: gpt-5
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BLOCKING_REVIEW: ${{ vars.BLOCKING_REVIEW || 'false' }}
run: |
cursor-agent --force --model "$MODEL" --output-format=text --print 'GitHub Actions 러너에서 자동 코드 리뷰를 수행 중이야. gh CLI는 GH_TOKEN으로 인증되어 있고 사용 가능해. 풀 리퀘스트에 코멘트를 남길 수 있어.
컨텍스트:
- 리포지토리: ${{ github.repository }}
- PR 번호: ${{ github.event.pull_request.number }}
- PR 헤드 SHA: ${{ github.event.pull_request.head.sha }}
- PR 베이스 SHA: ${{ github.event.pull_request.base.sha }}
- 차단 리뷰: ${{ env.BLOCKING_REVIEW }}
목표:
1) 기존 리뷰 코멘트를 다시 확인하고 해결됐으면 resolved로 답장해.
2) 현재 PR diff를 리뷰하고 명확하고 심각도가 높은 이슈만 표시해.
3) 변경된 라인에만 아주 짧은 인라인 코멘트(1~2문장)와 끝에 간단한 요약을 남겨.
절차:
- 기존 코멘트 가져오기: gh pr view --json comments
- diff 가져오기: gh pr diff
- 인라인 위치 계산을 위한 패치 포함 변경 파일 가져오기: gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files --paginate --jq '.[] | {filename,patch}'
- 각 이슈에 대한 정확한 인라인 앵커 계산(파일 경로 + diff 위치). 코멘트는 반드시 diff의 변경된 라인에 인라인으로 달고, 최상위 코멘트로 달면 안 돼.
- 이 봇이 작성한 이전의 최상위 "문제 없음" 스타일 코멘트를 감지해(본문이 "✅ no issues", "No issues found", "LGTM"과 유사한 경우 매칭).
- 이번 실행에서 이슈가 발견되고 과거 "문제 없음" 코멘트가 있으면:
- 혼란을 피하기 위해 제거하는 걸 우선해:
- 최상위 해당 코멘트 삭제 시도: gh api -X DELETE repos/${{ github.repository }}/issues/comments/<comment_id>
- 삭제가 불가하면 GraphQL(minimizeComment)로 최소화하거나 "[Superseded by new findings]" 접두사를 붙여 편집해.
- 삭제/최소화 모두 불가하면 이렇게 답장해: "⚠️ 대체됨: 최신 커밋에서 이슈가 발견됐어"
- 이전에 보고된 이슈가 인접한 변경으로 해결된 것 같으면, 이렇게 답장해: ✅ 최근 변경으로 이 이슈가 해결된 것으로 보여
- 다음만 분석:
- null/undefined 역참조
- 리소스 누수(닫히지 않은 파일 또는 연결)
- 인젝션(SQL/XSS)
- 동시성/경쟁 상태
- 중요 작업의 오류 처리 누락
- 잘못된 동작을 유발하는 명백한 로직 오류
- 측정 가능한 영향이 있는 명확한 성능 안티패턴
- 명백한 보안 취약점
- 중복 방지: 동일하거나 인접한 라인에 유사한 피드백이 이미 있으면 건너뛰어.
코멘트 규칙:
- 인라인 코멘트 최대 10개; 가장 중요한 이슈에 우선순위를 둬
- 코멘트당 하나의 이슈; 정확히 변경된 라인에 배치해
- 모든 이슈 코멘트는 반드시 인라인(PR diff의 파일과 위치에 고정)
- 자연스러운 톤으로 구체적이고 실행 가능하게; 자동화나 확신도 언급 금지
- 이모지 사용: 🚨 중대 🔒 보안 ⚡ 성능 ⚠️ 로직 ✅ 해결 ✨ 개선
제출:
- 보고할 이슈가 없고 기존의 "문제 없음" 최상위 코멘트가 이미 있으면(예: "✅ no issues", "No issues found", "LGTM") 새 코멘트를 제출하지 마. 중복을 피하기 위해 건너뛰어.
- 보고할 이슈가 없고 이전 "문제 없음" 코멘트도 없으면, 간단한 요약 코멘트 하나로 문제 없음을 알려.
- 보고할 이슈가 있고 이전 "문제 없음" 코멘트가 있으면, 새 리뷰 제출 전에 그 코멘트를 삭제/최소화/대체됨으로 표시해.
- 보고할 이슈가 있으면, 인라인 코멘트만 포함한 리뷰 하나와 선택적 간결 요약 본문을 제출해. 인라인을 보장하려면 GitHub Reviews API를 사용해:
- 다음 형식의 코멘트 JSON 배열을 구성: [{ "path": "<file>", "position": <diff_position>, "body": "..." }]
- 다음으로 제출: gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews -f event=COMMENT -f body="$SUMMARY" -f comments='[$COMMENTS_JSON]'
- 사용 금지: gh pr review --approve 또는 --request-changes
차단 동작:
- BLOCKING_REVIEW가 true이고 🚨 또는 🔒 이슈가 하나라도 올라왔으면: echo "CRITICAL_ISSUES_FOUND=true" >> $GITHUB_ENV
- 그 외에는: echo "CRITICAL_ISSUES_FOUND=false" >> $GITHUB_ENV
- 마지막에 항상 CRITICAL_ISSUES_FOUND를 설정해
'
- name: 차단 리뷰 결과 확인
if: env.BLOCKING_REVIEW == 'true'
run: |
echo "중대한 이슈가 있는지 확인 중..."
echo "CRITICAL_ISSUES_FOUND: ${CRITICAL_ISSUES_FOUND:-unset}"
if [ "${CRITICAL_ISSUES_FOUND:-false}" = "true" ]; then
echo "❌ 중대한 이슈가 발견됐고 차단 리뷰가 활성화되어 있어. 워크플로를 실패 처리할게."
exit 1
else
echo "✅ 차단되는 이슈는 발견되지 않았어."
fi