From 7badea5a73121b21a7617d7ef76147489166b07e Mon Sep 17 00:00:00 2001 From: scs0209 Date: Sat, 28 Jun 2025 13:40:40 +0900 Subject: [PATCH 1/7] =?UTF-8?q?docs:=20Gemini=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EA=B0=80=EC=9D=B4=EB=93=9C=EB=9D=BC?= =?UTF-8?q?=EC=9D=B8=20=EB=B0=8F=20=EC=9E=90=EB=8F=99=20=EB=A6=AC=EB=B7=B0?= =?UTF-8?q?=20=EC=8B=9C=EC=8A=A4=ED=85=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Gemini Code Assistant 문서 생성: 자동 코드 리뷰 프로세스 설명 - 커스텀 리뷰 가이드라인 추가: 코딩 컨벤션, 베스트 프랙티스, 가독성, 성능, 에러 처리, 테스트 항목 포함 - GitHub Actions 워크플로우 수정: 코드 리뷰 자동화 및 리뷰 결과 댓글 작성 기능 추가 - 리뷰 품질 향상 처리: 코드 예시 품질 검증 및 통계 분석 기능 추가 --- .gemini/styleguide.md | 34 + .github/workflows/code-review.yml | 1018 ++++++++++++++--------------- gemini.md | 14 + 3 files changed, 557 insertions(+), 509 deletions(-) create mode 100644 .gemini/styleguide.md create mode 100644 gemini.md diff --git a/.gemini/styleguide.md b/.gemini/styleguide.md new file mode 100644 index 00000000..fa8ae40c --- /dev/null +++ b/.gemini/styleguide.md @@ -0,0 +1,34 @@ +# Gemini Code Assistant: 자동 코드 리뷰 가이드라인 + +**리뷰 언어:** 모든 리뷰 코멘트는 한국어로 작성합니다. + +## 1. 전반적인 원칙 + +- **가독성:** 코드는 명확하고 이해하기 쉬워야 합니다. 복잡한 로직에는 주석을 추가하여 다른 개발자가 쉽게 이해할 수 있도록 합니다. +- **일관성:** 프로젝트 전반의 코딩 스타일과 구조를 일관되게 유지합니다. 새로운 코드는 기존 코드의 컨벤션을 따릅니다. +- **단순성 (KISS):** 불필요하게 복잡한 설계나 코드는 지양하고, 최대한 단순하게 구현합니다. + +## 2. TypeScript & Next.js + +- **타입 정의:** `any` 타입 사용을 최소화하고, 가능한 구체적인 타입을 정의합니다. `interface`와 `type`을 적절히 구분하여 사용합니다. +- **Next.js 컨벤션:** + - App Router의 최신 컨벤션(서버 컴포넌트, 클라이언트 컴포넌트)을 올바르게 사용하고 있는지 확인합니다. + - 데이터 페칭은 `fetcher.ts`의 공통 함수를 통해 이루어져야 합니다. 직접적인 `fetch` API 사용은 지양하고, `fetcher.ts`를 사용했는지 확인합니다. + - API 라우트 핸들러는 명확하고 안전하게 작성되었는지 확인합니다. +- **React Best Practices:** + - React Hooks의 규칙(Rules of Hooks)을 준수하는지 확인합니다. + - 컴포넌트는 단일 책임 원칙(SRP)을 따르도록 작게 분리합니다. + - 상태 관리 로직이 명확하고 효율적인지 검토합니다. + +## 3. 테스트 (Vitest) + +- **테스트 커버리지:** 중요한 비즈니스 로직과 컴포넌트는 반드시 테스트 코드로 커버되어야 합니다. +- **테스트 케이스:** 테스트 케이스는 명확하게 작성되어야 하며, 성공 케이스와 에러 케이스를 모두 포함하는지 확인합니다. (`describe`, `it`, `expect` 구조) +- **모킹(Mocking):** 외부 의존성은 적절히 모킹하여 테스트의 독립성을 보장하는지 확인합니다. + +## 4. 보안 + +- **입력 값 검증:** 사용자 입력이나 외부 API 응답과 같이 신뢰할 수 없는 데이터는 항상 검증하고 이스케이프 처리하여 XSS(Cross-Site Scripting) 공격을 방지하는지 확인합니다. +- **API 보안:** API 엔드포인트가 적절한 인증 및 인가 절차를 거치는지 확인합니다. +- **민감 정보 노출:** API 키, 비밀번호 등의 민감한 정보가 코드에 하드코딩되거나 클라이언트에 노출되지 않았는지 확인합니다. `.env` 파일과 환경 변수를 올바르게 사용하는지 검토합니다. +- **의존성 관리:** 알려진 보안 취약점이 있는 라이브러리를 사용하지 않는지 확인합니다. diff --git a/.github/workflows/code-review.yml b/.github/workflows/code-review.yml index c496effc..f06d86cc 100644 --- a/.github/workflows/code-review.yml +++ b/.github/workflows/code-review.yml @@ -17,627 +17,627 @@ jobs: with: fetch-depth: 0 - - name: 시스템 정보 확인 - run: | - echo "=== 시스템 정보 ===" - uname -a - free -h - df -h + # - name: 시스템 정보 확인 + # run: | + # echo "=== 시스템 정보 ===" + # uname -a + # free -h + # df -h - - name: Ollama 설치 및 설정 - run: | - echo "Ollama 설치 중..." - curl -fsSL https://ollama.ai/install.sh | sh + # - name: Ollama 설치 및 설정 + # run: | + # echo "Ollama 설치 중..." + # curl -fsSL https://ollama.ai/install.sh | sh - echo "Ollama 서버 시작..." - ollama serve & + # echo "Ollama 서버 시작..." + # ollama serve & - # 서버 시작 대기 (더 안정적인 방법) - echo "서버 시작 대기 중..." - for i in {1..30}; do - if curl -s http://localhost:11434/api/version >/dev/null 2>&1; then - echo "Ollama 서버가 준비되었습니다." - break - fi - echo "대기 중... ($i/30)" - sleep 2 - done + # # 서버 시작 대기 (더 안정적인 방법) + # echo "서버 시작 대기 중..." + # for i in {1..30}; do + # if curl -s http://localhost:11434/api/version >/dev/null 2>&1; then + # echo "Ollama 서버가 준비되었습니다." + # break + # fi + # echo "대기 중... ($i/30)" + # sleep 2 + # done - # 연결 확인 - echo "Ollama 연결 테스트..." - curl -s http://localhost:11434/api/version || exit 1 + # # 연결 확인 + # echo "Ollama 연결 테스트..." + # curl -s http://localhost:11434/api/version || exit 1 - # 경량 모델 사용 - echo "모델 다운로드 중..." - ollama pull qwen2.5-coder:1.5b + # # 경량 모델 사용 + # echo "모델 다운로드 중..." + # ollama pull qwen2.5-coder:1.5b - # 한국어 테스트 - echo "한국어 테스트..." - echo "안녕하세요. 한국어로 인사해주세요." | ollama run qwen2.5-coder:1.5b + # # 한국어 테스트 + # echo "한국어 테스트..." + # echo "안녕하세요. 한국어로 인사해주세요." | ollama run qwen2.5-coder:1.5b - - name: 변경된 파일 분석 및 우선순위 설정 - run: | - echo "변경된 파일 확인 및 분석..." - git fetch origin ${{ github.base_ref }} + # - name: 변경된 파일 분석 및 우선순위 설정 + # run: | + # echo "변경된 파일 확인 및 분석..." + # git fetch origin ${{ github.base_ref }} - # 모든 변경된 파일 찾기 - all_changed_files=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} | grep -E '\.(py|js|ts|jsx|tsx|java|cpp|c|h|php|rb|go|rs|kt|swift|dart|scala)$' || true) + # # 모든 변경된 파일 찾기 + # all_changed_files=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} | grep -E '\.(py|js|ts|jsx|tsx|java|cpp|c|h|php|rb|go|rs|kt|swift|dart|scala)$' || true) - if [ -n "$all_changed_files" ]; then - echo "전체 변경된 파일:" - echo "$all_changed_files" + # if [ -n "$all_changed_files" ]; then + # echo "전체 변경된 파일:" + # echo "$all_changed_files" - # 파일 분석 및 우선순위 설정 - > file_analysis.txt - > large_files.txt + # # 파일 분석 및 우선순위 설정 + # > file_analysis.txt + # > large_files.txt - total_files=0 + # total_files=0 - for file in $all_changed_files; do - total_files=$((total_files + 1)) + # for file in $all_changed_files; do + # total_files=$((total_files + 1)) - if [ -f "$file" ]; then - # 파일 크기 확인 (KB) - file_size=$(du -k "$file" 2>/dev/null | cut -f1 || echo "0") + # if [ -f "$file" ]; then + # # 파일 크기 확인 (KB) + # file_size=$(du -k "$file" 2>/dev/null | cut -f1 || echo "0") - # 변경 라인 수 확인 - changed_lines=$(git diff --numstat ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} -- "$file" | awk '{print $1+$2}' || echo "0") + # # 변경 라인 수 확인 + # changed_lines=$(git diff --numstat ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} -- "$file" | awk '{print $1+$2}' || echo "0") - # 우선순위 점수 계산 (변경 라인 수 * 10 + 파일 크기) - priority_score=$((changed_lines * 10 + file_size)) + # # 우선순위 점수 계산 (변경 라인 수 * 10 + 파일 크기) + # priority_score=$((changed_lines * 10 + file_size)) - echo "$priority_score:$file:$file_size:$changed_lines" >> file_analysis.txt + # echo "$priority_score:$file:$file_size:$changed_lines" >> file_analysis.txt - # 대용량 파일 체크 (100KB 이상 또는 1000라인 이상 변경) - if [ "$file_size" -gt 100 ] || [ "$changed_lines" -gt 1000 ]; then - echo "$file" >> large_files.txt - echo "⚠️ 대용량 파일 감지: $file (크기: ${file_size}KB, 변경: ${changed_lines}라인)" - fi - else - # 삭제된 파일 (낮은 우선순위) - echo "1:$file:0:0" >> file_analysis.txt - fi - done + # # 대용량 파일 체크 (100KB 이상 또는 1000라인 이상 변경) + # if [ "$file_size" -gt 100 ] || [ "$changed_lines" -gt 1000 ]; then + # echo "$file" >> large_files.txt + # echo "⚠️ 대용량 파일 감지: $file (크기: ${file_size}KB, 변경: ${changed_lines}라인)" + # fi + # else + # # 삭제된 파일 (낮은 우선순위) + # echo "1:$file:0:0" >> file_analysis.txt + # fi + # done - # 우선순위별 정렬 (높은 점수부터) - sort -nr file_analysis.txt > sorted_files.txt + # # 우선순위별 정렬 (높은 점수부터) + # sort -nr file_analysis.txt > sorted_files.txt - echo "=== 파일 처리 계획 ===" - echo "총 파일 수: $total_files" + # echo "=== 파일 처리 계획 ===" + # echo "총 파일 수: $total_files" - # 파일 수에 따른 동적 처리 전략 - if [ $total_files -le 5 ]; then - # 5개 이하: 모든 파일 상세 리뷰 - max_files=$total_files - review_mode="detailed" - echo "모드: 전체 상세 리뷰 ($total_files 파일)" - elif [ $total_files -le 15 ]; then - # 15개 이하: 모든 파일 처리, 큰 파일만 간략 리뷰 - max_files=$total_files - review_mode="mixed" - echo "모드: 혼합 리뷰 ($total_files 파일)" - else - # 15개 초과: 상위 15개만 처리 - max_files=15 - review_mode="priority" - echo "⚠️ 모드: 우선순위 리뷰 (상위 $max_files/$total_files 파일)" - fi + # # 파일 수에 따른 동적 처리 전략 + # if [ $total_files -le 5 ]; then + # # 5개 이하: 모든 파일 상세 리뷰 + # max_files=$total_files + # review_mode="detailed" + # echo "모드: 전체 상세 리뷰 ($total_files 파일)" + # elif [ $total_files -le 15 ]; then + # # 15개 이하: 모든 파일 처리, 큰 파일만 간략 리뷰 + # max_files=$total_files + # review_mode="mixed" + # echo "모드: 혼합 리뷰 ($total_files 파일)" + # else + # # 15개 초과: 상위 15개만 처리 + # max_files=15 + # review_mode="priority" + # echo "⚠️ 모드: 우선순위 리뷰 (상위 $max_files/$total_files 파일)" + # fi - # 처리할 파일 목록 생성 - > review_files.txt - processed_files=0 - while IFS=':' read -r score file size lines && [ $processed_files -lt $max_files ]; do - echo "$file:$size:$lines:$score" >> review_files.txt - processed_files=$((processed_files + 1)) - echo "처리 예정: $file (점수: $score, 크기: ${size}KB, 변경: ${lines}라인)" - done < sorted_files.txt + # # 처리할 파일 목록 생성 + # > review_files.txt + # processed_files=0 + # while IFS=':' read -r score file size lines && [ $processed_files -lt $max_files ]; do + # echo "$file:$size:$lines:$score" >> review_files.txt + # processed_files=$((processed_files + 1)) + # echo "처리 예정: $file (점수: $score, 크기: ${size}KB, 변경: ${lines}라인)" + # done < sorted_files.txt - skipped_files=$((total_files - processed_files)) - if [ $skipped_files -gt 0 ]; then - echo "⚠️ $skipped_files 개 파일을 건너뜁니다." - fi + # skipped_files=$((total_files - processed_files)) + # if [ $skipped_files -gt 0 ]; then + # echo "⚠️ $skipped_files 개 파일을 건너뜁니다." + # fi - echo "TOTAL_FILES=$total_files" >> $GITHUB_ENV - echo "PROCESSED_FILES=$processed_files" >> $GITHUB_ENV - echo "SKIPPED_FILES=$skipped_files" >> $GITHUB_ENV - echo "REVIEW_MODE=$review_mode" >> $GITHUB_ENV - else - echo "리뷰할 코드 파일이 없습니다." - echo "TOTAL_FILES=0" >> $GITHUB_ENV - echo "PROCESSED_FILES=0" >> $GITHUB_ENV - echo "SKIPPED_FILES=0" >> $GITHUB_ENV - echo "REVIEW_MODE=none" >> $GITHUB_ENV - fi + # echo "TOTAL_FILES=$total_files" >> $GITHUB_ENV + # echo "PROCESSED_FILES=$processed_files" >> $GITHUB_ENV + # echo "SKIPPED_FILES=$skipped_files" >> $GITHUB_ENV + # echo "REVIEW_MODE=$review_mode" >> $GITHUB_ENV + # else + # echo "리뷰할 코드 파일이 없습니다." + # echo "TOTAL_FILES=0" >> $GITHUB_ENV + # echo "PROCESSED_FILES=0" >> $GITHUB_ENV + # echo "SKIPPED_FILES=0" >> $GITHUB_ENV + # echo "REVIEW_MODE=none" >> $GITHUB_ENV + # fi - - name: 적응형 코드 리뷰 실행 - run: | - if [ -f "review_files.txt" ] && [ -s "review_files.txt" ]; then - echo "적응형 리뷰 시작 (모드: $REVIEW_MODE)..." - > review.txt + # - name: 적응형 코드 리뷰 실행 + # run: | + # if [ -f "review_files.txt" ] && [ -s "review_files.txt" ]; then + # echo "적응형 리뷰 시작 (모드: $REVIEW_MODE)..." + # > review.txt - # 시작 시간 기록 - start_time=$(date +%s) - max_duration=700 # 11분 30초 제한 (여유시간 확보) + # # 시작 시간 기록 + # start_time=$(date +%s) + # max_duration=700 # 11분 30초 제한 (여유시간 확보) - file_num=0 + # file_num=0 - while IFS=':' read -r file size lines score; do - current_time=$(date +%s) - elapsed=$((current_time - start_time)) - file_num=$((file_num + 1)) + # while IFS=':' read -r file size lines score; do + # current_time=$(date +%s) + # elapsed=$((current_time - start_time)) + # file_num=$((file_num + 1)) - # 시간 체크 - if [ $elapsed -gt $max_duration ]; then - echo "⚠️ 시간 제한 도달 - 리뷰 중단 ($file_num/$PROCESSED_FILES)" - echo "TIME_LIMIT_REACHED=true" >> $GITHUB_ENV - break - fi + # # 시간 체크 + # if [ $elapsed -gt $max_duration ]; then + # echo "⚠️ 시간 제한 도달 - 리뷰 중단 ($file_num/$PROCESSED_FILES)" + # echo "TIME_LIMIT_REACHED=true" >> $GITHUB_ENV + # break + # fi - echo "=== 파일 $file_num/$PROCESSED_FILES: $file 처리 중 ===" - echo "=== $file 리뷰 ===" >> review.txt - echo "" >> review.txt + # echo "=== 파일 $file_num/$PROCESSED_FILES: $file 처리 중 ===" + # echo "=== $file 리뷰 ===" >> review.txt + # echo "" >> review.txt - # 파일 존재 확인 - if [ ! -f "$file" ]; then - echo "📋 삭제된 파일: $file" >> review.txt - echo "" >> review.txt - echo "---" >> review.txt - echo "" >> review.txt - continue - fi + # # 파일 존재 확인 + # if [ ! -f "$file" ]; then + # echo "📋 삭제된 파일: $file" >> review.txt + # echo "" >> review.txt + # echo "---" >> review.txt + # echo "" >> review.txt + # continue + # fi - # 파일 확장자별 언어 감지 - case "$file" in - *.py) language="Python" ;; - *.js|*.jsx) language="JavaScript" ;; - *.ts|*.tsx) language="TypeScript" ;; - *) language="Unknown" ;; - esac + # # 파일 확장자별 언어 감지 + # case "$file" in + # *.py) language="Python" ;; + # *.js|*.jsx) language="JavaScript" ;; + # *.ts|*.tsx) language="TypeScript" ;; + # *) language="Unknown" ;; + # esac - # 변경 내용 추출 (크기에 따라 조정) - if [ "$size" -gt 50 ] || [ "$lines" -gt 500 ]; then - # 대용량 파일: 변경 부분만 - echo "📊 대용량 파일 (${size}KB, ${lines}라인 변경) - 핵심 변경사항 분석" >> review.txt - diff_content=$(git diff ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} -- "$file" | head -80) - review_type="summary" - else - # 일반 파일: 상세 분석 - diff_content=$(git diff ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} -- "$file" | head -150) - review_type="detailed" - fi + # # 변경 내용 추출 (크기에 따라 조정) + # if [ "$size" -gt 50 ] || [ "$lines" -gt 500 ]; then + # # 대용량 파일: 변경 부분만 + # echo "📊 대용량 파일 (${size}KB, ${lines}라인 변경) - 핵심 변경사항 분석" >> review.txt + # diff_content=$(git diff ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} -- "$file" | head -80) + # review_type="summary" + # else + # # 일반 파일: 상세 분석 + # diff_content=$(git diff ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} -- "$file" | head -150) + # review_type="detailed" + # fi - if [ -n "$diff_content" ]; then - # 리뷰 모드에 따른 프롬프트 설정 - if [ "$review_type" = "detailed" ] && [ "$REVIEW_MODE" = "detailed" ]; then - # 상세 리뷰 프롬프트 (코드 예시 포함) - review_prompt="다음 ${language} 코드 변경사항을 상세히 분석하고 한국어로 리뷰해주세요: + # if [ -n "$diff_content" ]; then + # # 리뷰 모드에 따른 프롬프트 설정 + # if [ "$review_type" = "detailed" ] && [ "$REVIEW_MODE" = "detailed" ]; then + # # 상세 리뷰 프롬프트 (코드 예시 포함) + # review_prompt="다음 ${language} 코드 변경사항을 상세히 분석하고 한국어로 리뷰해주세요: - $diff_content + # $diff_content - 다음 형식으로 답변해주세요: - 🚨 위험도: [낮음/보통/높음/긴급] + # 다음 형식으로 답변해주세요: + # 🚨 위험도: [낮음/보통/높음/긴급] - 🔍 주요 발견사항: - - (구체적인 이슈들 나열) + # 🔍 주요 발견사항: + # - (구체적인 이슈들 나열) - 🔒 보안 및 안정성: - - (보안 관련 체크사항) + # 🔒 보안 및 안정성: + # - (보안 관련 체크사항) - ⚡ 성능 영향: - - (성능 관련 분석) + # ⚡ 성능 영향: + # - (성능 관련 분석) - 💡 권장사항: - - (개선 제안사항) + # 💡 권장사항: + # - (개선 제안사항) - 📝 개선 코드 예시: - 만약 문제가 있는 부분이 있다면, 구체적인 개선 코드 예시를 제공해주세요: + # 📝 개선 코드 예시: + # 만약 문제가 있는 부분이 있다면, 구체적인 개선 코드 예시를 제공해주세요: - \`\`\`${language,,} - // 개선 전 (문제가 있는 코드) - [기존 코드 일부] + # \`\`\`${language,,} + # // 개선 전 (문제가 있는 코드) + # [기존 코드 일부] - // 개선 후 (권장 코드) - [개선된 코드] - \`\`\` + # // 개선 후 (권장 코드) + # [개선된 코드] + # \`\`\` - 개선 이유: (왜 이렇게 개선해야 하는지 설명) + # 개선 이유: (왜 이렇게 개선해야 하는지 설명) - 핵심적이고 실용적인 내용으로 답변해주세요." - timeout_duration=120 - else - # 간략 리뷰 프롬프트 (코드 예시 포함) - review_prompt="다음 ${language} 코드 변경사항을 간결하게 한국어로 리뷰해주세요: + # 핵심적이고 실용적인 내용으로 답변해주세요." + # timeout_duration=120 + # else + # # 간략 리뷰 프롬프트 (코드 예시 포함) + # review_prompt="다음 ${language} 코드 변경사항을 간결하게 한국어로 리뷰해주세요: - $diff_content + # $diff_content - 다음 형식으로 답변해주세요: - 🚨 위험도: [낮음/보통/높음/긴급] - 🔍 주요 이슈: (핵심 이슈 1-2개) - 💡 권장사항: (주요 개선사항 1-2개) + # 다음 형식으로 답변해주세요: + # 🚨 위험도: [낮음/보통/높음/긴급] + # 🔍 주요 이슈: (핵심 이슈 1-2개) + # 💡 권장사항: (주요 개선사항 1-2개) - 📝 핵심 개선 예시: - 가장 중요한 개선사항이 있다면 간단한 코드 예시 포함: - \`\`\`${language,,} - // 개선 전 → 개선 후 - [간단한 before/after 코드] - \`\`\` + # 📝 핵심 개선 예시: + # 가장 중요한 개선사항이 있다면 간단한 코드 예시 포함: + # \`\`\`${language,,} + # // 개선 전 → 개선 후 + # [간단한 before/after 코드] + # \`\`\` - 간결하고 핵심적인 내용만 포함해주세요." - timeout_duration=90 - fi + # 간결하고 핵심적인 내용만 포함해주세요." + # timeout_duration=90 + # fi - echo "리뷰 진행 중... (제한시간: ${timeout_duration}초)" + # echo "리뷰 진행 중... (제한시간: ${timeout_duration}초)" - # AI 리뷰 실행 (타임아웃 적용) - if timeout ${timeout_duration}s bash -c "echo '$review_prompt' | ollama run qwen2.5-coder:1.5b" >> review.txt 2>/dev/null; then - echo "✅ 리뷰 완료: $file" - else - echo "⚠️ 리뷰 시간 초과: $file (${timeout_duration}초)" >> review.txt - echo "⚠️ 타임아웃: $file" - fi - else - echo "변경 내용이 감지되지 않았습니다." >> review.txt - fi + # # AI 리뷰 실행 (타임아웃 적용) + # if timeout ${timeout_duration}s bash -c "echo '$review_prompt' | ollama run qwen2.5-coder:1.5b" >> review.txt 2>/dev/null; then + # echo "✅ 리뷰 완료: $file" + # else + # echo "⚠️ 리뷰 시간 초과: $file (${timeout_duration}초)" >> review.txt + # echo "⚠️ 타임아웃: $file" + # fi + # else + # echo "변경 내용이 감지되지 않았습니다." >> review.txt + # fi - echo "" >> review.txt - echo "---" >> review.txt - echo "" >> review.txt + # echo "" >> review.txt + # echo "---" >> review.txt + # echo "" >> review.txt - # 진행 상황 출력 - remaining_time=$((max_duration - elapsed)) - echo "진행률: $file_num/$PROCESSED_FILES 완료 (남은 시간: ${remaining_time}초)" + # # 진행 상황 출력 + # remaining_time=$((max_duration - elapsed)) + # echo "진행률: $file_num/$PROCESSED_FILES 완료 (남은 시간: ${remaining_time}초)" - done < review_files.txt + # done < review_files.txt - # 최종 통계 - end_time=$(date +%s) - total_duration=$((end_time - start_time)) - echo "리뷰 완료 - 실제 처리: $file_num/$PROCESSED_FILES 파일, 소요시간: ${total_duration}초" + # # 최종 통계 + # end_time=$(date +%s) + # total_duration=$((end_time - start_time)) + # echo "리뷰 완료 - 실제 처리: $file_num/$PROCESSED_FILES 파일, 소요시간: ${total_duration}초" - echo "REVIEW_DURATION=$total_duration" >> $GITHUB_ENV - echo "ACTUAL_PROCESSED=$file_num" >> $GITHUB_ENV + # echo "REVIEW_DURATION=$total_duration" >> $GITHUB_ENV + # echo "ACTUAL_PROCESSED=$file_num" >> $GITHUB_ENV - else - echo "리뷰할 파일이 없습니다." - echo "## 📝 리뷰 결과 + # else + # echo "리뷰할 파일이 없습니다." + # echo "## 📝 리뷰 결과 - 이번 Pull Request에서는 리뷰할 코드 파일 변경사항이 없습니다. + # 이번 Pull Request에서는 리뷰할 코드 파일 변경사항이 없습니다. - 검토 대상 파일 형식: Python, JavaScript, TypeScript, Java, C/C++, PHP, Ruby, Go, Rust, Kotlin, Swift, Dart, Scala" > review.txt - fi + # 검토 대상 파일 형식: Python, JavaScript, TypeScript, Java, C/C++, PHP, Ruby, Go, Rust, Kotlin, Swift, Dart, Scala" > review.txt + # fi - - name: 코드 예시 품질 향상 처리 - run: | - if [ -f "review.txt" ] && [ -s "review.txt" ]; then - echo "코드 예시 품질 검증 중..." + # - name: 코드 예시 품질 향상 처리 + # run: | + # if [ -f "review.txt" ] && [ -s "review.txt" ]; then + # echo "코드 예시 품질 검증 중..." - # 코드 블록 개수 확인 - code_blocks=$(grep -c '\`\`\`' review.txt || echo "0") - echo "발견된 코드 블록: $code_blocks" + # # 코드 블록 개수 확인 + # code_blocks=$(grep -c '\`\`\`' review.txt || echo "0") + # echo "발견된 코드 블록: $code_blocks" - # 코드 예시가 포함된 리뷰인지 확인 - if grep -q "개선.*코드" review.txt || grep -q '\`\`\`' review.txt; then - echo "CODE_EXAMPLES_INCLUDED=true" >> $GITHUB_ENV - echo "✅ 코드 예시가 포함된 리뷰 생성됨" - else - echo "CODE_EXAMPLES_INCLUDED=false" >> $GITHUB_ENV - echo "ℹ️ 코드 예시 없이 일반 리뷰 생성됨" - fi + # # 코드 예시가 포함된 리뷰인지 확인 + # if grep -q "개선.*코드" review.txt || grep -q '\`\`\`' review.txt; then + # echo "CODE_EXAMPLES_INCLUDED=true" >> $GITHUB_ENV + # echo "✅ 코드 예시가 포함된 리뷰 생성됨" + # else + # echo "CODE_EXAMPLES_INCLUDED=false" >> $GITHUB_ENV + # echo "ℹ️ 코드 예시 없이 일반 리뷰 생성됨" + # fi - # 코드 예시 품질 점수 계산 - quality_score=0 + # # 코드 예시 품질 점수 계산 + # quality_score=0 - # 개선 전/후 비교가 있는지 확인 - if grep -q "개선.*전" review.txt && grep -q "개선.*후" review.txt; then - quality_score=$((quality_score + 30)) - echo "✅ Before/After 비교 포함 (+30점)" - fi + # # 개선 전/후 비교가 있는지 확인 + # if grep -q "개선.*전" review.txt && grep -q "개선.*후" review.txt; then + # quality_score=$((quality_score + 30)) + # echo "✅ Before/After 비교 포함 (+30점)" + # fi - # 구체적인 코드 설명이 있는지 확인 - if grep -q "개선.*이유" review.txt || grep -q "설명" review.txt; then - quality_score=$((quality_score + 20)) - echo "✅ 개선 설명 포함 (+20점)" - fi + # # 구체적인 코드 설명이 있는지 확인 + # if grep -q "개선.*이유" review.txt || grep -q "설명" review.txt; then + # quality_score=$((quality_score + 20)) + # echo "✅ 개선 설명 포함 (+20점)" + # fi - # 다양한 언어 지원 확인 - languages_found=$(grep -o '\`\`\`[a-zA-Z]*' review.txt | sort -u | wc -l || echo "0") - if [ "$languages_found" -gt 0 ]; then - quality_score=$((quality_score + 10)) - echo "✅ 언어별 코드 예시 포함 (+10점)" - fi + # # 다양한 언어 지원 확인 + # languages_found=$(grep -o '\`\`\`[a-zA-Z]*' review.txt | sort -u | wc -l || echo "0") + # if [ "$languages_found" -gt 0 ]; then + # quality_score=$((quality_score + 10)) + # echo "✅ 언어별 코드 예시 포함 (+10점)" + # fi - echo "코드 예시 품질 점수: $quality_score/60" - echo "CODE_QUALITY_SCORE=$quality_score" >> $GITHUB_ENV + # echo "코드 예시 품질 점수: $quality_score/60" + # echo "CODE_QUALITY_SCORE=$quality_score" >> $GITHUB_ENV - else - echo "리뷰 파일이 없습니다." - fi + # else + # echo "리뷰 파일이 없습니다." + # fi - - name: 리뷰 결과 댓글 작성 - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const fs = require('fs'); + # - name: 리뷰 결과 댓글 작성 + # uses: actions/github-script@v7 + # with: + # github-token: ${{ secrets.GITHUB_TOKEN }} + # script: | + # const fs = require('fs'); - try { - const review = fs.readFileSync('review.txt', 'utf8'); - const prNumber = context.payload.pull_request?.number || context.issue.number; + # try { + # const review = fs.readFileSync('review.txt', 'utf8'); + # const prNumber = context.payload.pull_request?.number || context.issue.number; - // 환경변수에서 통계 정보 가져오기 - const totalFiles = process.env.TOTAL_FILES || '0'; - const processedFiles = process.env.PROCESSED_FILES || '0'; - const actualProcessed = process.env.ACTUAL_PROCESSED || processedFiles; - const skippedFiles = process.env.SKIPPED_FILES || '0'; - const reviewDuration = process.env.REVIEW_DURATION || '0'; - const reviewMode = process.env.REVIEW_MODE || 'unknown'; - const timeLimitReached = process.env.TIME_LIMIT_REACHED === 'true'; - const codeExamplesIncluded = process.env.CODE_EXAMPLES_INCLUDED === 'true'; - const codeQualityScore = process.env.CODE_QUALITY_SCORE || '0'; + # // 환경변수에서 통계 정보 가져오기 + # const totalFiles = process.env.TOTAL_FILES || '0'; + # const processedFiles = process.env.PROCESSED_FILES || '0'; + # const actualProcessed = process.env.ACTUAL_PROCESSED || processedFiles; + # const skippedFiles = process.env.SKIPPED_FILES || '0'; + # const reviewDuration = process.env.REVIEW_DURATION || '0'; + # const reviewMode = process.env.REVIEW_MODE || 'unknown'; + # const timeLimitReached = process.env.TIME_LIMIT_REACHED === 'true'; + # const codeExamplesIncluded = process.env.CODE_EXAMPLES_INCLUDED === 'true'; + # const codeQualityScore = process.env.CODE_QUALITY_SCORE || '0'; - // 위험도 추출 (더 정확한 패턴 매칭) - const riskMatches = review.match(/🚨\s*위험도[^:]*:\s*\[?([^\]]+)\]?/gi) || []; - let highestRisk = '낮음'; - let riskCounts = { '긴급': 0, '높음': 0, '보통': 0, '낮음': 0 }; + # // 위험도 추출 (더 정확한 패턴 매칭) + # const riskMatches = review.match(/🚨\s*위험도[^:]*:\s*\[?([^\]]+)\]?/gi) || []; + # let highestRisk = '낮음'; + # let riskCounts = { '긴급': 0, '높음': 0, '보통': 0, '낮음': 0 }; - riskMatches.forEach(match => { - const risk = match.match(/\[?([^\]]+)\]?$/)[1].trim(); - if (risk.includes('긴급')) { - riskCounts['긴급']++; - highestRisk = '긴급'; - } else if (risk.includes('높음') && !highestRisk.includes('긴급')) { - riskCounts['높음']++; - highestRisk = '높음'; - } else if (risk.includes('보통') && !['긴급', '높음'].includes(highestRisk)) { - riskCounts['보통']++; - highestRisk = '보통'; - } else if (risk.includes('낮음') && highestRisk === '낮음') { - riskCounts['낮음']++; - } - }); + # riskMatches.forEach(match => { + # const risk = match.match(/\[?([^\]]+)\]?$/)[1].trim(); + # if (risk.includes('긴급')) { + # riskCounts['긴급']++; + # highestRisk = '긴급'; + # } else if (risk.includes('높음') && !highestRisk.includes('긴급')) { + # riskCounts['높음']++; + # highestRisk = '높음'; + # } else if (risk.includes('보통') && !['긴급', '높음'].includes(highestRisk)) { + # riskCounts['보통']++; + # highestRisk = '보통'; + # } else if (risk.includes('낮음') && highestRisk === '낮음') { + # riskCounts['낮음']++; + # } + # }); - // 위험도에 따른 이모지 - const getRiskEmoji = (risk) => { - if (risk.includes('긴급')) return '🚨'; - if (risk.includes('높음')) return '⚠️'; - if (risk.includes('보통')) return '⚡'; - return '✅'; - }; + # // 위험도에 따른 이모지 + # const getRiskEmoji = (risk) => { + # if (risk.includes('긴급')) return '🚨'; + # if (risk.includes('높음')) return '⚠️'; + # if (risk.includes('보통')) return '⚡'; + # return '✅'; + # }; - // 리뷰 모드 설명 - const getModeDescription = (mode) => { - switch(mode) { - case 'detailed': return '전체 상세 리뷰 (코드 예시 포함)'; - case 'mixed': return '혼합 모드 (대용량 파일 간략화)'; - case 'priority': return '우선순위 모드 (상위 파일만)'; - default: return '표준 모드'; - } - }; + # // 리뷰 모드 설명 + # const getModeDescription = (mode) => { + # switch(mode) { + # case 'detailed': return '전체 상세 리뷰 (코드 예시 포함)'; + # case 'mixed': return '혼합 모드 (대용량 파일 간략화)'; + # case 'priority': return '우선순위 모드 (상위 파일만)'; + # default: return '표준 모드'; + # } + # }; - // 코드 품질 등급 - const getQualityGrade = (score) => { - if (score >= 50) return 'A (우수)'; - if (score >= 30) return 'B (양호)'; - if (score >= 10) return 'C (보통)'; - return 'D (기본)'; - }; + # // 코드 품질 등급 + # const getQualityGrade = (score) => { + # if (score >= 50) return 'A (우수)'; + # if (score >= 30) return 'B (양호)'; + # if (score >= 10) return 'C (보통)'; + # return 'D (기본)'; + # }; - // 기존 AI 리뷰 댓글 확인 - const { data: comments } = await github.rest.issues.listComments({ - issue_number: prNumber, - owner: context.repo.owner, - repo: context.repo.repo, - }); + # // 기존 AI 리뷰 댓글 확인 + # const { data: comments } = await github.rest.issues.listComments({ + # issue_number: prNumber, + # owner: context.repo.owner, + # repo: context.repo.repo, + # }); - const botComment = comments.find(comment => - comment.user.login === 'github-actions[bot]' && - comment.body.includes('🤖 AI 코드 리뷰') - ); + # const botComment = comments.find(comment => + # comment.user.login === 'github-actions[bot]' && + # comment.body.includes('🤖 AI 코드 리뷰') + # ); - const reviewDate = new Date().toLocaleString('ko-KR', {timeZone: 'Asia/Seoul'}); - const riskEmoji = getRiskEmoji(highestRisk); + # const reviewDate = new Date().toLocaleString('ko-KR', {timeZone: 'Asia/Seoul'}); + # const riskEmoji = getRiskEmoji(highestRisk); - // 처리 효율성 계산 - const efficiency = totalFiles > 0 ? Math.round((actualProcessed / totalFiles) * 100) : 100; + # // 처리 효율성 계산 + # const efficiency = totalFiles > 0 ? Math.round((actualProcessed / totalFiles) * 100) : 100; - const commentBody = `## 🤖 AI 코드 리뷰 보고서 ${codeExamplesIncluded ? '📝' : ''} + # const commentBody = `## 🤖 AI 코드 리뷰 보고서 ${codeExamplesIncluded ? '📝' : ''} - - - - - - - - - - - - - - - - - - ${codeExamplesIncluded ? `` : ''} - ${skippedFiles > 0 ? `` : ''} - ${timeLimitReached ? `` : ''} - - - - - - - - - - - - -
📊 리뷰 개요상세 정보
최고 위험도${riskEmoji} ${highestRisk}
처리된 파일${actualProcessed}/${totalFiles}개 (${efficiency}%)
리뷰 모드${getModeDescription(reviewMode)}
코드 예시 품질📝 ${getQualityGrade(codeQualityScore)} (${codeQualityScore}/60점)
건너뛴 파일${skippedFiles}개
상태⚠️ 시간 제한 도달
처리 시간${reviewDuration}초
리뷰 시간${reviewDate}
AI 모델qwen2.5-coder:1.5b
+ # + # + # + # + # + # + # + # + # + # + # + # + # + # + # + # + # + # ${codeExamplesIncluded ? `` : ''} + # ${skippedFiles > 0 ? `` : ''} + # ${timeLimitReached ? `` : ''} + # + # + # + # + # + # + # + # + # + # + # + # + #
📊 리뷰 개요상세 정보
최고 위험도${riskEmoji} ${highestRisk}
처리된 파일${actualProcessed}/${totalFiles}개 (${efficiency}%)
리뷰 모드${getModeDescription(reviewMode)}
코드 예시 품질📝 ${getQualityGrade(codeQualityScore)} (${codeQualityScore}/60점)
건너뛴 파일${skippedFiles}개
상태⚠️ 시간 제한 도달
처리 시간${reviewDuration}초
리뷰 시간${reviewDate}
AI 모델qwen2.5-coder:1.5b
- ${Object.keys(riskCounts).some(key => riskCounts[key] > 0) ? ` - **위험도 분포:** - ${Object.entries(riskCounts).filter(([_, count]) => count > 0).map(([risk, count]) => `${getRiskEmoji(risk)} ${risk}: ${count}개 파일`).join(' • ')} - ` : ''} + # ${Object.keys(riskCounts).some(key => riskCounts[key] > 0) ? ` + # **위험도 분포:** + # ${Object.entries(riskCounts).filter(([_, count]) => count > 0).map(([risk, count]) => `${getRiskEmoji(risk)} ${risk}: ${count}개 파일`).join(' • ')} + # ` : ''} - ${codeExamplesIncluded ? ` - > 💡 **향상된 기능**: 이 리뷰에는 실제 코드 개선 예시가 포함되어 있습니다! - > 📝 Before/After 비교와 구체적인 개선 방법을 확인해보세요. + # ${codeExamplesIncluded ? ` + # > 💡 **향상된 기능**: 이 리뷰에는 실제 코드 개선 예시가 포함되어 있습니다! + # > 📝 Before/After 비교와 구체적인 개선 방법을 확인해보세요. - ` : ''} + # ` : ''} - ${skippedFiles > 0 || timeLimitReached ? ` - > ⚠️ **알림**: ${timeLimitReached ? '시간 제한으로 인해 일부 파일의 처리가 중단되었습니다.' : ''}${skippedFiles > 0 ? ` 총 ${skippedFiles}개 파일을 건너뛰었습니다.` : ''} - > 중요도가 높은 파일을 우선적으로 처리했습니다. + # ${skippedFiles > 0 || timeLimitReached ? ` + # > ⚠️ **알림**: ${timeLimitReached ? '시간 제한으로 인해 일부 파일의 처리가 중단되었습니다.' : ''}${skippedFiles > 0 ? ` 총 ${skippedFiles}개 파일을 건너뛰었습니다.` : ''} + # > 중요도가 높은 파일을 우선적으로 처리했습니다. - ` : ''} + # ` : ''} - --- + # --- - ## 📋 상세 리뷰 결과 + # ## 📋 상세 리뷰 결과 - ${review} + # ${review} - --- + # --- -
- 📊 적응형 처리 정보 + #
+ # 📊 적응형 처리 정보 - **처리 전략:** - - 📁 총 파일 수에 따른 동적 모드 선택 - - 🎯 변경량과 파일 크기 기반 우선순위 설정 - - 🔤 파일별 언어 자동 감지 및 맞춤형 프롬프트 - - ⏱️ 파일별 적응형 타임아웃 (상세: 120초, 간략: 90초) - - 🔄 실시간 시간 관리 및 진행률 모니터링 - - 📝 코드 개선 예시 자동 생성 + # **처리 전략:** + # - 📁 총 파일 수에 따른 동적 모드 선택 + # - 🎯 변경량과 파일 크기 기반 우선순위 설정 + # - 🔤 파일별 언어 자동 감지 및 맞춤형 프롬프트 + # - ⏱️ 파일별 적응형 타임아웃 (상세: 120초, 간략: 90초) + # - 🔄 실시간 시간 관리 및 진행률 모니터링 + # - 📝 코드 개선 예시 자동 생성 - **모드별 특징:** - - **전체 상세 (≤5파일)**: 모든 파일 상세 분석 + 코드 예시 - - **혼합 모드 (≤15파일)**: 대용량 파일 간략화 + 핵심 코드 예시 - - **우선순위 (>15파일)**: 상위 15개 파일만 처리 + # **모드별 특징:** + # - **전체 상세 (≤5파일)**: 모든 파일 상세 분석 + 코드 예시 + # - **혼합 모드 (≤15파일)**: 대용량 파일 간략화 + 핵심 코드 예시 + # - **우선순위 (>15파일)**: 상위 15개 파일만 처리 - **코드 예시 품질 평가:** - - Before/After 비교: ${review.includes('개선 전') && review.includes('개선 후') ? '✅' : '❌'} - - 개선 설명 포함: ${review.includes('개선 이유') || review.includes('설명') ? '✅' : '❌'} - - 언어별 맞춤형: ${review.includes('\`\`\`') ? '✅' : '❌'} - - 총 품질 점수: ${codeQualityScore}/60점 (${getQualityGrade(codeQualityScore)}) + # **코드 예시 품질 평가:** + # - Before/After 비교: ${review.includes('개선 전') && review.includes('개선 후') ? '✅' : '❌'} + # - 개선 설명 포함: ${review.includes('개선 이유') || review.includes('설명') ? '✅' : '❌'} + # - 언어별 맞춤형: ${review.includes('\`\`\`') ? '✅' : '❌'} + # - 총 품질 점수: ${codeQualityScore}/60점 (${getQualityGrade(codeQualityScore)}) -
+ #
-
- 📖 리뷰 가이드라인 + #
+ # 📖 리뷰 가이드라인 - **위험도 기준:** - - 🚨 **긴급**: 보안 취약점, 심각한 버그, 프로덕션 장애 가능성 - - ⚠️ **높음**: 성능 이슈, 데이터 손실 위험, 중요 로직 오류 - - ⚡ **보통**: 코드 품질 이슈, 가독성 문제, 경미한 버그 - - ✅ **낮음**: 스타일 이슈, 최적화 제안, 베스트 프랙티스 + # **위험도 기준:** + # - 🚨 **긴급**: 보안 취약점, 심각한 버그, 프로덕션 장애 가능성 + # - ⚠️ **높음**: 성능 이슈, 데이터 손실 위험, 중요 로직 오류 + # - ⚡ **보통**: 코드 품질 이슈, 가독성 문제, 경미한 버그 + # - ✅ **낮음**: 스타일 이슈, 최적화 제안, 베스트 프랙티스 - **검토 항목:** - - ✅ 코드 품질 및 가독성 - - 🔒 보안 및 안정성 검사 - - ⚡ 성능 영향 분석 - - 🛠️ 베스트 프랙티스 준수 - - 💡 개선 제안사항 - - 📝 **실제 코드 개선 예시 제공** + # **검토 항목:** + # - ✅ 코드 품질 및 가독성 + # - 🔒 보안 및 안정성 검사 + # - ⚡ 성능 영향 분석 + # - 🛠️ 베스트 프랙티스 준수 + # - 💡 개선 제안사항 + # - 📝 **실제 코드 개선 예시 제공** -
+ #
- > ⚠️ **주의사항**: 이는 AI 자동 리뷰입니다. 최종 코드 검토는 반드시 사람이 수행해주세요. + # > ⚠️ **주의사항**: 이는 AI 자동 리뷰입니다. 최종 코드 검토는 반드시 사람이 수행해주세요. - --- - *Generated by GitHub Actions • ${reviewDate} • ${actualProcessed}/${totalFiles} files processed in ${reviewDuration}s*`; + # --- + # *Generated by GitHub Actions • ${reviewDate} • ${actualProcessed}/${totalFiles} files processed in ${reviewDuration}s*`; - if (botComment) { - await github.rest.issues.updateComment({ - comment_id: botComment.id, - owner: context.repo.owner, - repo: context.repo.repo, - body: commentBody - }); - console.log('기존 리뷰 댓글을 업데이트했습니다.'); - } else { - await github.rest.issues.createComment({ - issue_number: prNumber, - owner: context.repo.owner, - repo: context.repo.repo, - body: commentBody - }); - console.log('새 리뷰 댓글을 작성했습니다.'); - } + # if (botComment) { + # await github.rest.issues.updateComment({ + # comment_id: botComment.id, + # owner: context.repo.owner, + # repo: context.repo.repo, + # body: commentBody + # }); + # console.log('기존 리뷰 댓글을 업데이트했습니다.'); + # } else { + # await github.rest.issues.createComment({ + # issue_number: prNumber, + # owner: context.repo.owner, + # repo: context.repo.repo, + # body: commentBody + # }); + # console.log('새 리뷰 댓글을 작성했습니다.'); + # } - // 높은 위험도 알림 - if (highestRisk.includes('긴급') || highestRisk.includes('높음')) { - core.warning(`⚠️ 높은 위험도 감지: ${highestRisk}`); - } + # // 높은 위험도 알림 + # if (highestRisk.includes('긴급') || highestRisk.includes('높음')) { + # core.warning(`⚠️ 높은 위험도 감지: ${highestRisk}`); + # } - // 처리 효율성 알림 - if (efficiency < 90) { - core.warning(`⚠️ 처리 효율성: ${efficiency}% (${actualProcessed}/${totalFiles} 파일 처리완료)`); - } + # // 처리 효율성 알림 + # if (efficiency < 90) { + # core.warning(`⚠️ 처리 효율성: ${efficiency}% (${actualProcessed}/${totalFiles} 파일 처리완료)`); + # } - } catch (error) { - console.error('댓글 작성 실패:', error.message); - core.setFailed(`댓글 작성에 실패했습니다: ${error.message}`); - } + # } catch (error) { + # console.error('댓글 작성 실패:', error.message); + # core.setFailed(`댓글 작성에 실패했습니다: ${error.message}`); + # } - - name: 리뷰 결과 및 성능 분석 - run: | - if [ -f "review.txt" ]; then - echo "=== 최종 리뷰 분석 ===" + # - name: 리뷰 결과 및 성능 분석 + # run: | + # if [ -f "review.txt" ]; then + # echo "=== 최종 리뷰 분석 ===" - # 위험도 분석 (대소문자 구분 없이) - if grep -qi "긴급" review.txt; then - echo "::error title=긴급 위험도 감지::코드에서 긴급 수정이 필요한 이슈가 발견되었습니다." - echo "FINAL_RISK_LEVEL=긴급" >> $GITHUB_ENV - elif grep -qi "높음" review.txt; then - echo "::warning title=높은 위험도 감지::코드에서 주의가 필요한 이슈가 발견되었습니다." - echo "FINAL_RISK_LEVEL=높음" >> $GITHUB_ENV - elif grep -qi "보통" review.txt; then - echo "::notice title=보통 위험도::일반적인 개선사항이 발견되었습니다." - echo "FINAL_RISK_LEVEL=보통" >> $GITHUB_ENV - else - echo "::notice title=낮은 위험도::코드 품질이 양호합니다." - echo "FINAL_RISK_LEVEL=낮음" >> $GITHUB_ENV - fi + # # 위험도 분석 (대소문자 구분 없이) + # if grep -qi "긴급" review.txt; then + # echo "::error title=긴급 위험도 감지::코드에서 긴급 수정이 필요한 이슈가 발견되었습니다." + # echo "FINAL_RISK_LEVEL=긴급" >> $GITHUB_ENV + # elif grep -qi "높음" review.txt; then + # echo "::warning title=높은 위험도 감지::코드에서 주의가 필요한 이슈가 발견되었습니다." + # echo "FINAL_RISK_LEVEL=높음" >> $GITHUB_ENV + # elif grep -qi "보통" review.txt; then + # echo "::notice title=보통 위험도::일반적인 개선사항이 발견되었습니다." + # echo "FINAL_RISK_LEVEL=보통" >> $GITHUB_ENV + # else + # echo "::notice title=낮은 위험도::코드 품질이 양호합니다." + # echo "FINAL_RISK_LEVEL=낮음" >> $GITHUB_ENV + # fi - # 상세 성능 통계 - echo "=== 처리 성능 통계 ===" - echo "- 총 파일 수: ${TOTAL_FILES:-0}" - echo "- 계획된 처리 파일: ${PROCESSED_FILES:-0}" - echo "- 실제 처리된 파일: ${ACTUAL_PROCESSED:-0}" - echo "- 건너뛴 파일: ${SKIPPED_FILES:-0}" - echo "- 총 처리 시간: ${REVIEW_DURATION:-0}초" - echo "- 리뷰 모드: ${REVIEW_MODE:-unknown}" + # # 상세 성능 통계 + # echo "=== 처리 성능 통계 ===" + # echo "- 총 파일 수: ${TOTAL_FILES:-0}" + # echo "- 계획된 처리 파일: ${PROCESSED_FILES:-0}" + # echo "- 실제 처리된 파일: ${ACTUAL_PROCESSED:-0}" + # echo "- 건너뛴 파일: ${SKIPPED_FILES:-0}" + # echo "- 총 처리 시간: ${REVIEW_DURATION:-0}초" + # echo "- 리뷰 모드: ${REVIEW_MODE:-unknown}" - # 처리 효율성 계산 - if [ "${TOTAL_FILES:-0}" -gt 0 ]; then - efficiency=$(( (${ACTUAL_PROCESSED:-0} * 100) / ${TOTAL_FILES:-1} )) - echo "- 처리 효율성: ${efficiency}%" + # # 처리 효율성 계산 + # if [ "${TOTAL_FILES:-0}" -gt 0 ]; then + # efficiency=$(( (${ACTUAL_PROCESSED:-0} * 100) / ${TOTAL_FILES:-1} )) + # echo "- 처리 효율성: ${efficiency}%" - if [ "$efficiency" -lt 80 ]; then - echo "::warning title=처리 효율성 낮음::${efficiency}%의 파일만 처리되었습니다." - fi - fi + # if [ "$efficiency" -lt 80 ]; then + # echo "::warning title=처리 효율성 낮음::${efficiency}%의 파일만 처리되었습니다." + # fi + # fi - # 시간 제한 체크 - if [ "${TIME_LIMIT_REACHED:-false}" = "true" ]; then - echo "::warning title=시간 제한 도달::일부 파일의 처리가 시간 제한으로 중단되었습니다." - fi + # # 시간 제한 체크 + # if [ "${TIME_LIMIT_REACHED:-false}" = "true" ]; then + # echo "::warning title=시간 제한 도달::일부 파일의 처리가 시간 제한으로 중단되었습니다." + # fi - # 리뷰 품질 확인 - review_lines=$(wc -l < review.txt) - review_size=$(wc -c < review.txt) - echo "- 리뷰 결과 크기: ${review_lines}줄, ${review_size}바이트" + # # 리뷰 품질 확인 + # review_lines=$(wc -l < review.txt) + # review_size=$(wc -c < review.txt) + # echo "- 리뷰 결과 크기: ${review_lines}줄, ${review_size}바이트" - if [ "$review_lines" -lt 20 ] && [ "${ACTUAL_PROCESSED:-0}" -gt 0 ]; then - echo "::warning title=리뷰 결과 부족::리뷰 내용이 예상보다 적습니다. AI 모델 응답 확인이 필요합니다." - fi + # if [ "$review_lines" -lt 20 ] && [ "${ACTUAL_PROCESSED:-0}" -gt 0 ]; then + # echo "::warning title=리뷰 결과 부족::리뷰 내용이 예상보다 적습니다. AI 모델 응답 확인이 필요합니다." + # fi - echo "=== 리뷰 완료 ===" + # echo "=== 리뷰 완료 ===" - else - echo "::error title=리뷰 실패::리뷰 파일이 생성되지 않았습니다." - exit 1 - fi \ No newline at end of file + # else + # echo "::error title=리뷰 실패::리뷰 파일이 생성되지 않았습니다." + # exit 1 + # fi \ No newline at end of file diff --git a/gemini.md b/gemini.md new file mode 100644 index 00000000..d1a2fc7f --- /dev/null +++ b/gemini.md @@ -0,0 +1,14 @@ +# Gemini Code Assistant: 자동 코드 리뷰 + +GitHub의 모든 Pull Request에 대해, 시니어 소프트웨어 엔지니어로서 철저한 코드 리뷰를 수행합니다. + +## 커스텀 리뷰 가이드라인 + +프로젝트의 특정 요구사항에 맞게 이 섹션을 수정하여 사용하세요. + +- **코딩 컨벤션:** 새로운 코드가 기존 프로젝트의 이름 지정, 서식, 구조 등 코딩 컨벤션을 준수하는지 확인합니다. +- **베스트 프랙티스:** 각 언어별 베스트 프랙티스(예: 객체 지향 프로그래밍의 SOLID 원칙, Python/JavaScript의 관용적 표현)를 따르는지 확인합니다. +- **가독성:** 코드가 이해하기 쉬운지, 변수 이름이 명확한지, 로직이 간단명료한지 검토합니다. +- **성능:** 명백한 성능 저하를 유발하는 부분이나 비효율적인 쿼리가 있는지 확인합니다. +- **에러 처리:** 에러 처리가 견고하게 구현되었는지, 처리되지 않은 예외가 있는지 확인합니다. +- **테스트:** 변경 사항이 새로운 테스트나 기존 테스트에 의해 충분히 커버되는지 확인합니다. From d1d6d108274154c3d8813263aa674fab01bb6387 Mon Sep 17 00:00:00 2001 From: scs0209 Date: Sat, 28 Jun 2025 13:45:28 +0900 Subject: [PATCH 2/7] =?UTF-8?q?docs:=20Gemini=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EA=B0=80=EC=9D=B4=EB=93=9C=EB=9D=BC?= =?UTF-8?q?=EC=9D=B8=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EB=B0=8F=20?= =?UTF-8?q?=EC=9E=90=EB=8F=99=20=EB=A6=AC=EB=B7=B0=20=EC=8B=9C=EC=8A=A4?= =?UTF-8?q?=ED=85=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 아키텍처 섹션 추가: Feature-Sliced Design(FSD) 원칙 준수 확인 항목 추가 - 기존 GitHub Actions 워크플로우 파일 삭제: 자동 리뷰 시스템 관련 파일 제거 --- .github/workflows/code-review.yml | 643 ------------------------------ gemini.md | 1 + 2 files changed, 1 insertion(+), 643 deletions(-) delete mode 100644 .github/workflows/code-review.yml diff --git a/.github/workflows/code-review.yml b/.github/workflows/code-review.yml deleted file mode 100644 index f06d86cc..00000000 --- a/.github/workflows/code-review.yml +++ /dev/null @@ -1,643 +0,0 @@ -name: AI 코드 리뷰 (개선된 버전) -on: - pull_request: - types: [opened, synchronize] - -permissions: - contents: read - pull-requests: write - issues: write - -jobs: - ai-code-review: - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - # - name: 시스템 정보 확인 - # run: | - # echo "=== 시스템 정보 ===" - # uname -a - # free -h - # df -h - - # - name: Ollama 설치 및 설정 - # run: | - # echo "Ollama 설치 중..." - # curl -fsSL https://ollama.ai/install.sh | sh - - # echo "Ollama 서버 시작..." - # ollama serve & - - # # 서버 시작 대기 (더 안정적인 방법) - # echo "서버 시작 대기 중..." - # for i in {1..30}; do - # if curl -s http://localhost:11434/api/version >/dev/null 2>&1; then - # echo "Ollama 서버가 준비되었습니다." - # break - # fi - # echo "대기 중... ($i/30)" - # sleep 2 - # done - - # # 연결 확인 - # echo "Ollama 연결 테스트..." - # curl -s http://localhost:11434/api/version || exit 1 - - # # 경량 모델 사용 - # echo "모델 다운로드 중..." - # ollama pull qwen2.5-coder:1.5b - - # # 한국어 테스트 - # echo "한국어 테스트..." - # echo "안녕하세요. 한국어로 인사해주세요." | ollama run qwen2.5-coder:1.5b - - # - name: 변경된 파일 분석 및 우선순위 설정 - # run: | - # echo "변경된 파일 확인 및 분석..." - # git fetch origin ${{ github.base_ref }} - - # # 모든 변경된 파일 찾기 - # all_changed_files=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} | grep -E '\.(py|js|ts|jsx|tsx|java|cpp|c|h|php|rb|go|rs|kt|swift|dart|scala)$' || true) - - # if [ -n "$all_changed_files" ]; then - # echo "전체 변경된 파일:" - # echo "$all_changed_files" - - # # 파일 분석 및 우선순위 설정 - # > file_analysis.txt - # > large_files.txt - - # total_files=0 - - # for file in $all_changed_files; do - # total_files=$((total_files + 1)) - - # if [ -f "$file" ]; then - # # 파일 크기 확인 (KB) - # file_size=$(du -k "$file" 2>/dev/null | cut -f1 || echo "0") - - # # 변경 라인 수 확인 - # changed_lines=$(git diff --numstat ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} -- "$file" | awk '{print $1+$2}' || echo "0") - - # # 우선순위 점수 계산 (변경 라인 수 * 10 + 파일 크기) - # priority_score=$((changed_lines * 10 + file_size)) - - # echo "$priority_score:$file:$file_size:$changed_lines" >> file_analysis.txt - - # # 대용량 파일 체크 (100KB 이상 또는 1000라인 이상 변경) - # if [ "$file_size" -gt 100 ] || [ "$changed_lines" -gt 1000 ]; then - # echo "$file" >> large_files.txt - # echo "⚠️ 대용량 파일 감지: $file (크기: ${file_size}KB, 변경: ${changed_lines}라인)" - # fi - # else - # # 삭제된 파일 (낮은 우선순위) - # echo "1:$file:0:0" >> file_analysis.txt - # fi - # done - - # # 우선순위별 정렬 (높은 점수부터) - # sort -nr file_analysis.txt > sorted_files.txt - - # echo "=== 파일 처리 계획 ===" - # echo "총 파일 수: $total_files" - - # # 파일 수에 따른 동적 처리 전략 - # if [ $total_files -le 5 ]; then - # # 5개 이하: 모든 파일 상세 리뷰 - # max_files=$total_files - # review_mode="detailed" - # echo "모드: 전체 상세 리뷰 ($total_files 파일)" - # elif [ $total_files -le 15 ]; then - # # 15개 이하: 모든 파일 처리, 큰 파일만 간략 리뷰 - # max_files=$total_files - # review_mode="mixed" - # echo "모드: 혼합 리뷰 ($total_files 파일)" - # else - # # 15개 초과: 상위 15개만 처리 - # max_files=15 - # review_mode="priority" - # echo "⚠️ 모드: 우선순위 리뷰 (상위 $max_files/$total_files 파일)" - # fi - - # # 처리할 파일 목록 생성 - # > review_files.txt - # processed_files=0 - # while IFS=':' read -r score file size lines && [ $processed_files -lt $max_files ]; do - # echo "$file:$size:$lines:$score" >> review_files.txt - # processed_files=$((processed_files + 1)) - # echo "처리 예정: $file (점수: $score, 크기: ${size}KB, 변경: ${lines}라인)" - # done < sorted_files.txt - - # skipped_files=$((total_files - processed_files)) - # if [ $skipped_files -gt 0 ]; then - # echo "⚠️ $skipped_files 개 파일을 건너뜁니다." - # fi - - # echo "TOTAL_FILES=$total_files" >> $GITHUB_ENV - # echo "PROCESSED_FILES=$processed_files" >> $GITHUB_ENV - # echo "SKIPPED_FILES=$skipped_files" >> $GITHUB_ENV - # echo "REVIEW_MODE=$review_mode" >> $GITHUB_ENV - # else - # echo "리뷰할 코드 파일이 없습니다." - # echo "TOTAL_FILES=0" >> $GITHUB_ENV - # echo "PROCESSED_FILES=0" >> $GITHUB_ENV - # echo "SKIPPED_FILES=0" >> $GITHUB_ENV - # echo "REVIEW_MODE=none" >> $GITHUB_ENV - # fi - - # - name: 적응형 코드 리뷰 실행 - # run: | - # if [ -f "review_files.txt" ] && [ -s "review_files.txt" ]; then - # echo "적응형 리뷰 시작 (모드: $REVIEW_MODE)..." - # > review.txt - - # # 시작 시간 기록 - # start_time=$(date +%s) - # max_duration=700 # 11분 30초 제한 (여유시간 확보) - - # file_num=0 - - # while IFS=':' read -r file size lines score; do - # current_time=$(date +%s) - # elapsed=$((current_time - start_time)) - # file_num=$((file_num + 1)) - - # # 시간 체크 - # if [ $elapsed -gt $max_duration ]; then - # echo "⚠️ 시간 제한 도달 - 리뷰 중단 ($file_num/$PROCESSED_FILES)" - # echo "TIME_LIMIT_REACHED=true" >> $GITHUB_ENV - # break - # fi - - # echo "=== 파일 $file_num/$PROCESSED_FILES: $file 처리 중 ===" - # echo "=== $file 리뷰 ===" >> review.txt - # echo "" >> review.txt - - # # 파일 존재 확인 - # if [ ! -f "$file" ]; then - # echo "📋 삭제된 파일: $file" >> review.txt - # echo "" >> review.txt - # echo "---" >> review.txt - # echo "" >> review.txt - # continue - # fi - - # # 파일 확장자별 언어 감지 - # case "$file" in - # *.py) language="Python" ;; - # *.js|*.jsx) language="JavaScript" ;; - # *.ts|*.tsx) language="TypeScript" ;; - # *) language="Unknown" ;; - # esac - - # # 변경 내용 추출 (크기에 따라 조정) - # if [ "$size" -gt 50 ] || [ "$lines" -gt 500 ]; then - # # 대용량 파일: 변경 부분만 - # echo "📊 대용량 파일 (${size}KB, ${lines}라인 변경) - 핵심 변경사항 분석" >> review.txt - # diff_content=$(git diff ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} -- "$file" | head -80) - # review_type="summary" - # else - # # 일반 파일: 상세 분석 - # diff_content=$(git diff ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} -- "$file" | head -150) - # review_type="detailed" - # fi - - # if [ -n "$diff_content" ]; then - # # 리뷰 모드에 따른 프롬프트 설정 - # if [ "$review_type" = "detailed" ] && [ "$REVIEW_MODE" = "detailed" ]; then - # # 상세 리뷰 프롬프트 (코드 예시 포함) - # review_prompt="다음 ${language} 코드 변경사항을 상세히 분석하고 한국어로 리뷰해주세요: - - # $diff_content - - # 다음 형식으로 답변해주세요: - # 🚨 위험도: [낮음/보통/높음/긴급] - - # 🔍 주요 발견사항: - # - (구체적인 이슈들 나열) - - # 🔒 보안 및 안정성: - # - (보안 관련 체크사항) - - # ⚡ 성능 영향: - # - (성능 관련 분석) - - # 💡 권장사항: - # - (개선 제안사항) - - # 📝 개선 코드 예시: - # 만약 문제가 있는 부분이 있다면, 구체적인 개선 코드 예시를 제공해주세요: - - # \`\`\`${language,,} - # // 개선 전 (문제가 있는 코드) - # [기존 코드 일부] - - # // 개선 후 (권장 코드) - # [개선된 코드] - # \`\`\` - - # 개선 이유: (왜 이렇게 개선해야 하는지 설명) - - # 핵심적이고 실용적인 내용으로 답변해주세요." - # timeout_duration=120 - # else - # # 간략 리뷰 프롬프트 (코드 예시 포함) - # review_prompt="다음 ${language} 코드 변경사항을 간결하게 한국어로 리뷰해주세요: - - # $diff_content - - # 다음 형식으로 답변해주세요: - # 🚨 위험도: [낮음/보통/높음/긴급] - # 🔍 주요 이슈: (핵심 이슈 1-2개) - # 💡 권장사항: (주요 개선사항 1-2개) - - # 📝 핵심 개선 예시: - # 가장 중요한 개선사항이 있다면 간단한 코드 예시 포함: - # \`\`\`${language,,} - # // 개선 전 → 개선 후 - # [간단한 before/after 코드] - # \`\`\` - - # 간결하고 핵심적인 내용만 포함해주세요." - # timeout_duration=90 - # fi - - # echo "리뷰 진행 중... (제한시간: ${timeout_duration}초)" - - # # AI 리뷰 실행 (타임아웃 적용) - # if timeout ${timeout_duration}s bash -c "echo '$review_prompt' | ollama run qwen2.5-coder:1.5b" >> review.txt 2>/dev/null; then - # echo "✅ 리뷰 완료: $file" - # else - # echo "⚠️ 리뷰 시간 초과: $file (${timeout_duration}초)" >> review.txt - # echo "⚠️ 타임아웃: $file" - # fi - # else - # echo "변경 내용이 감지되지 않았습니다." >> review.txt - # fi - - # echo "" >> review.txt - # echo "---" >> review.txt - # echo "" >> review.txt - - # # 진행 상황 출력 - # remaining_time=$((max_duration - elapsed)) - # echo "진행률: $file_num/$PROCESSED_FILES 완료 (남은 시간: ${remaining_time}초)" - - # done < review_files.txt - - # # 최종 통계 - # end_time=$(date +%s) - # total_duration=$((end_time - start_time)) - # echo "리뷰 완료 - 실제 처리: $file_num/$PROCESSED_FILES 파일, 소요시간: ${total_duration}초" - - # echo "REVIEW_DURATION=$total_duration" >> $GITHUB_ENV - # echo "ACTUAL_PROCESSED=$file_num" >> $GITHUB_ENV - - # else - # echo "리뷰할 파일이 없습니다." - # echo "## 📝 리뷰 결과 - - # 이번 Pull Request에서는 리뷰할 코드 파일 변경사항이 없습니다. - - # 검토 대상 파일 형식: Python, JavaScript, TypeScript, Java, C/C++, PHP, Ruby, Go, Rust, Kotlin, Swift, Dart, Scala" > review.txt - # fi - - # - name: 코드 예시 품질 향상 처리 - # run: | - # if [ -f "review.txt" ] && [ -s "review.txt" ]; then - # echo "코드 예시 품질 검증 중..." - - # # 코드 블록 개수 확인 - # code_blocks=$(grep -c '\`\`\`' review.txt || echo "0") - # echo "발견된 코드 블록: $code_blocks" - - # # 코드 예시가 포함된 리뷰인지 확인 - # if grep -q "개선.*코드" review.txt || grep -q '\`\`\`' review.txt; then - # echo "CODE_EXAMPLES_INCLUDED=true" >> $GITHUB_ENV - # echo "✅ 코드 예시가 포함된 리뷰 생성됨" - # else - # echo "CODE_EXAMPLES_INCLUDED=false" >> $GITHUB_ENV - # echo "ℹ️ 코드 예시 없이 일반 리뷰 생성됨" - # fi - - # # 코드 예시 품질 점수 계산 - # quality_score=0 - - # # 개선 전/후 비교가 있는지 확인 - # if grep -q "개선.*전" review.txt && grep -q "개선.*후" review.txt; then - # quality_score=$((quality_score + 30)) - # echo "✅ Before/After 비교 포함 (+30점)" - # fi - - # # 구체적인 코드 설명이 있는지 확인 - # if grep -q "개선.*이유" review.txt || grep -q "설명" review.txt; then - # quality_score=$((quality_score + 20)) - # echo "✅ 개선 설명 포함 (+20점)" - # fi - - # # 다양한 언어 지원 확인 - # languages_found=$(grep -o '\`\`\`[a-zA-Z]*' review.txt | sort -u | wc -l || echo "0") - # if [ "$languages_found" -gt 0 ]; then - # quality_score=$((quality_score + 10)) - # echo "✅ 언어별 코드 예시 포함 (+10점)" - # fi - - # echo "코드 예시 품질 점수: $quality_score/60" - # echo "CODE_QUALITY_SCORE=$quality_score" >> $GITHUB_ENV - - # else - # echo "리뷰 파일이 없습니다." - # fi - - # - name: 리뷰 결과 댓글 작성 - # uses: actions/github-script@v7 - # with: - # github-token: ${{ secrets.GITHUB_TOKEN }} - # script: | - # const fs = require('fs'); - - # try { - # const review = fs.readFileSync('review.txt', 'utf8'); - # const prNumber = context.payload.pull_request?.number || context.issue.number; - - # // 환경변수에서 통계 정보 가져오기 - # const totalFiles = process.env.TOTAL_FILES || '0'; - # const processedFiles = process.env.PROCESSED_FILES || '0'; - # const actualProcessed = process.env.ACTUAL_PROCESSED || processedFiles; - # const skippedFiles = process.env.SKIPPED_FILES || '0'; - # const reviewDuration = process.env.REVIEW_DURATION || '0'; - # const reviewMode = process.env.REVIEW_MODE || 'unknown'; - # const timeLimitReached = process.env.TIME_LIMIT_REACHED === 'true'; - # const codeExamplesIncluded = process.env.CODE_EXAMPLES_INCLUDED === 'true'; - # const codeQualityScore = process.env.CODE_QUALITY_SCORE || '0'; - - # // 위험도 추출 (더 정확한 패턴 매칭) - # const riskMatches = review.match(/🚨\s*위험도[^:]*:\s*\[?([^\]]+)\]?/gi) || []; - # let highestRisk = '낮음'; - # let riskCounts = { '긴급': 0, '높음': 0, '보통': 0, '낮음': 0 }; - - # riskMatches.forEach(match => { - # const risk = match.match(/\[?([^\]]+)\]?$/)[1].trim(); - # if (risk.includes('긴급')) { - # riskCounts['긴급']++; - # highestRisk = '긴급'; - # } else if (risk.includes('높음') && !highestRisk.includes('긴급')) { - # riskCounts['높음']++; - # highestRisk = '높음'; - # } else if (risk.includes('보통') && !['긴급', '높음'].includes(highestRisk)) { - # riskCounts['보통']++; - # highestRisk = '보통'; - # } else if (risk.includes('낮음') && highestRisk === '낮음') { - # riskCounts['낮음']++; - # } - # }); - - # // 위험도에 따른 이모지 - # const getRiskEmoji = (risk) => { - # if (risk.includes('긴급')) return '🚨'; - # if (risk.includes('높음')) return '⚠️'; - # if (risk.includes('보통')) return '⚡'; - # return '✅'; - # }; - - # // 리뷰 모드 설명 - # const getModeDescription = (mode) => { - # switch(mode) { - # case 'detailed': return '전체 상세 리뷰 (코드 예시 포함)'; - # case 'mixed': return '혼합 모드 (대용량 파일 간략화)'; - # case 'priority': return '우선순위 모드 (상위 파일만)'; - # default: return '표준 모드'; - # } - # }; - - # // 코드 품질 등급 - # const getQualityGrade = (score) => { - # if (score >= 50) return 'A (우수)'; - # if (score >= 30) return 'B (양호)'; - # if (score >= 10) return 'C (보통)'; - # return 'D (기본)'; - # }; - - # // 기존 AI 리뷰 댓글 확인 - # const { data: comments } = await github.rest.issues.listComments({ - # issue_number: prNumber, - # owner: context.repo.owner, - # repo: context.repo.repo, - # }); - - # const botComment = comments.find(comment => - # comment.user.login === 'github-actions[bot]' && - # comment.body.includes('🤖 AI 코드 리뷰') - # ); - - # const reviewDate = new Date().toLocaleString('ko-KR', {timeZone: 'Asia/Seoul'}); - # const riskEmoji = getRiskEmoji(highestRisk); - - # // 처리 효율성 계산 - # const efficiency = totalFiles > 0 ? Math.round((actualProcessed / totalFiles) * 100) : 100; - - # const commentBody = `## 🤖 AI 코드 리뷰 보고서 ${codeExamplesIncluded ? '📝' : ''} - - # - # - # - # - # - # - # - # - # - # - # - # - # - # - # - # - # - # ${codeExamplesIncluded ? `` : ''} - # ${skippedFiles > 0 ? `` : ''} - # ${timeLimitReached ? `` : ''} - # - # - # - # - # - # - # - # - # - # - # - # - #
📊 리뷰 개요상세 정보
최고 위험도${riskEmoji} ${highestRisk}
처리된 파일${actualProcessed}/${totalFiles}개 (${efficiency}%)
리뷰 모드${getModeDescription(reviewMode)}
코드 예시 품질📝 ${getQualityGrade(codeQualityScore)} (${codeQualityScore}/60점)
건너뛴 파일${skippedFiles}개
상태⚠️ 시간 제한 도달
처리 시간${reviewDuration}초
리뷰 시간${reviewDate}
AI 모델qwen2.5-coder:1.5b
- - # ${Object.keys(riskCounts).some(key => riskCounts[key] > 0) ? ` - # **위험도 분포:** - # ${Object.entries(riskCounts).filter(([_, count]) => count > 0).map(([risk, count]) => `${getRiskEmoji(risk)} ${risk}: ${count}개 파일`).join(' • ')} - # ` : ''} - - # ${codeExamplesIncluded ? ` - # > 💡 **향상된 기능**: 이 리뷰에는 실제 코드 개선 예시가 포함되어 있습니다! - # > 📝 Before/After 비교와 구체적인 개선 방법을 확인해보세요. - - # ` : ''} - - # ${skippedFiles > 0 || timeLimitReached ? ` - # > ⚠️ **알림**: ${timeLimitReached ? '시간 제한으로 인해 일부 파일의 처리가 중단되었습니다.' : ''}${skippedFiles > 0 ? ` 총 ${skippedFiles}개 파일을 건너뛰었습니다.` : ''} - # > 중요도가 높은 파일을 우선적으로 처리했습니다. - - # ` : ''} - - # --- - - # ## 📋 상세 리뷰 결과 - - # ${review} - - # --- - - #
- # 📊 적응형 처리 정보 - - # **처리 전략:** - # - 📁 총 파일 수에 따른 동적 모드 선택 - # - 🎯 변경량과 파일 크기 기반 우선순위 설정 - # - 🔤 파일별 언어 자동 감지 및 맞춤형 프롬프트 - # - ⏱️ 파일별 적응형 타임아웃 (상세: 120초, 간략: 90초) - # - 🔄 실시간 시간 관리 및 진행률 모니터링 - # - 📝 코드 개선 예시 자동 생성 - - # **모드별 특징:** - # - **전체 상세 (≤5파일)**: 모든 파일 상세 분석 + 코드 예시 - # - **혼합 모드 (≤15파일)**: 대용량 파일 간략화 + 핵심 코드 예시 - # - **우선순위 (>15파일)**: 상위 15개 파일만 처리 - - # **코드 예시 품질 평가:** - # - Before/After 비교: ${review.includes('개선 전') && review.includes('개선 후') ? '✅' : '❌'} - # - 개선 설명 포함: ${review.includes('개선 이유') || review.includes('설명') ? '✅' : '❌'} - # - 언어별 맞춤형: ${review.includes('\`\`\`') ? '✅' : '❌'} - # - 총 품질 점수: ${codeQualityScore}/60점 (${getQualityGrade(codeQualityScore)}) - - #
- - #
- # 📖 리뷰 가이드라인 - - # **위험도 기준:** - # - 🚨 **긴급**: 보안 취약점, 심각한 버그, 프로덕션 장애 가능성 - # - ⚠️ **높음**: 성능 이슈, 데이터 손실 위험, 중요 로직 오류 - # - ⚡ **보통**: 코드 품질 이슈, 가독성 문제, 경미한 버그 - # - ✅ **낮음**: 스타일 이슈, 최적화 제안, 베스트 프랙티스 - - # **검토 항목:** - # - ✅ 코드 품질 및 가독성 - # - 🔒 보안 및 안정성 검사 - # - ⚡ 성능 영향 분석 - # - 🛠️ 베스트 프랙티스 준수 - # - 💡 개선 제안사항 - # - 📝 **실제 코드 개선 예시 제공** - - #
- - # > ⚠️ **주의사항**: 이는 AI 자동 리뷰입니다. 최종 코드 검토는 반드시 사람이 수행해주세요. - - # --- - # *Generated by GitHub Actions • ${reviewDate} • ${actualProcessed}/${totalFiles} files processed in ${reviewDuration}s*`; - - # if (botComment) { - # await github.rest.issues.updateComment({ - # comment_id: botComment.id, - # owner: context.repo.owner, - # repo: context.repo.repo, - # body: commentBody - # }); - # console.log('기존 리뷰 댓글을 업데이트했습니다.'); - # } else { - # await github.rest.issues.createComment({ - # issue_number: prNumber, - # owner: context.repo.owner, - # repo: context.repo.repo, - # body: commentBody - # }); - # console.log('새 리뷰 댓글을 작성했습니다.'); - # } - - # // 높은 위험도 알림 - # if (highestRisk.includes('긴급') || highestRisk.includes('높음')) { - # core.warning(`⚠️ 높은 위험도 감지: ${highestRisk}`); - # } - - # // 처리 효율성 알림 - # if (efficiency < 90) { - # core.warning(`⚠️ 처리 효율성: ${efficiency}% (${actualProcessed}/${totalFiles} 파일 처리완료)`); - # } - - # } catch (error) { - # console.error('댓글 작성 실패:', error.message); - # core.setFailed(`댓글 작성에 실패했습니다: ${error.message}`); - # } - - # - name: 리뷰 결과 및 성능 분석 - # run: | - # if [ -f "review.txt" ]; then - # echo "=== 최종 리뷰 분석 ===" - - # # 위험도 분석 (대소문자 구분 없이) - # if grep -qi "긴급" review.txt; then - # echo "::error title=긴급 위험도 감지::코드에서 긴급 수정이 필요한 이슈가 발견되었습니다." - # echo "FINAL_RISK_LEVEL=긴급" >> $GITHUB_ENV - # elif grep -qi "높음" review.txt; then - # echo "::warning title=높은 위험도 감지::코드에서 주의가 필요한 이슈가 발견되었습니다." - # echo "FINAL_RISK_LEVEL=높음" >> $GITHUB_ENV - # elif grep -qi "보통" review.txt; then - # echo "::notice title=보통 위험도::일반적인 개선사항이 발견되었습니다." - # echo "FINAL_RISK_LEVEL=보통" >> $GITHUB_ENV - # else - # echo "::notice title=낮은 위험도::코드 품질이 양호합니다." - # echo "FINAL_RISK_LEVEL=낮음" >> $GITHUB_ENV - # fi - - # # 상세 성능 통계 - # echo "=== 처리 성능 통계 ===" - # echo "- 총 파일 수: ${TOTAL_FILES:-0}" - # echo "- 계획된 처리 파일: ${PROCESSED_FILES:-0}" - # echo "- 실제 처리된 파일: ${ACTUAL_PROCESSED:-0}" - # echo "- 건너뛴 파일: ${SKIPPED_FILES:-0}" - # echo "- 총 처리 시간: ${REVIEW_DURATION:-0}초" - # echo "- 리뷰 모드: ${REVIEW_MODE:-unknown}" - - # # 처리 효율성 계산 - # if [ "${TOTAL_FILES:-0}" -gt 0 ]; then - # efficiency=$(( (${ACTUAL_PROCESSED:-0} * 100) / ${TOTAL_FILES:-1} )) - # echo "- 처리 효율성: ${efficiency}%" - - # if [ "$efficiency" -lt 80 ]; then - # echo "::warning title=처리 효율성 낮음::${efficiency}%의 파일만 처리되었습니다." - # fi - # fi - - # # 시간 제한 체크 - # if [ "${TIME_LIMIT_REACHED:-false}" = "true" ]; then - # echo "::warning title=시간 제한 도달::일부 파일의 처리가 시간 제한으로 중단되었습니다." - # fi - - # # 리뷰 품질 확인 - # review_lines=$(wc -l < review.txt) - # review_size=$(wc -c < review.txt) - # echo "- 리뷰 결과 크기: ${review_lines}줄, ${review_size}바이트" - - # if [ "$review_lines" -lt 20 ] && [ "${ACTUAL_PROCESSED:-0}" -gt 0 ]; then - # echo "::warning title=리뷰 결과 부족::리뷰 내용이 예상보다 적습니다. AI 모델 응답 확인이 필요합니다." - # fi - - # echo "=== 리뷰 완료 ===" - - # else - # echo "::error title=리뷰 실패::리뷰 파일이 생성되지 않았습니다." - # exit 1 - # fi \ No newline at end of file diff --git a/gemini.md b/gemini.md index d1a2fc7f..9299e4cd 100644 --- a/gemini.md +++ b/gemini.md @@ -7,6 +7,7 @@ GitHub의 모든 Pull Request에 대해, 시니어 소프트웨어 엔지니어 프로젝트의 특정 요구사항에 맞게 이 섹션을 수정하여 사용하세요. - **코딩 컨벤션:** 새로운 코드가 기존 프로젝트의 이름 지정, 서식, 구조 등 코딩 컨벤션을 준수하는지 확인합니다. +- **아키텍처:** 코드가 Feature-Sliced Design (FSD) 원칙(예: 단방향 의존성, 슬라이스 격리)을 준수하는지 확인합니다. - **베스트 프랙티스:** 각 언어별 베스트 프랙티스(예: 객체 지향 프로그래밍의 SOLID 원칙, Python/JavaScript의 관용적 표현)를 따르는지 확인합니다. - **가독성:** 코드가 이해하기 쉬운지, 변수 이름이 명확한지, 로직이 간단명료한지 검토합니다. - **성능:** 명백한 성능 저하를 유발하는 부분이나 비효율적인 쿼리가 있는지 확인합니다. From 0cc3b83fe93df584d2e3eb39605b63d835cb7754 Mon Sep 17 00:00:00 2001 From: scs0209 Date: Sat, 28 Jun 2025 13:47:23 +0900 Subject: [PATCH 3/7] =?UTF-8?q?docs:=20Gemini=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EA=B0=80=EC=9D=B4=EB=93=9C=EB=9D=BC?= =?UTF-8?q?=EC=9D=B8=20=EC=98=81=EC=96=B4=20=EB=B2=88=EC=97=AD=20=EB=B0=8F?= =?UTF-8?q?=20=EB=82=B4=EC=9A=A9=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 리뷰 언어 및 전반적인 원칙 섹션을 영어로 번역 - TypeScript & Next.js, 테스트, 보안 섹션의 내용 영어로 업데이트 --- .gemini/styleguide.md | 46 +++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/.gemini/styleguide.md b/.gemini/styleguide.md index fa8ae40c..d06da9db 100644 --- a/.gemini/styleguide.md +++ b/.gemini/styleguide.md @@ -1,34 +1,34 @@ -# Gemini Code Assistant: 자동 코드 리뷰 가이드라인 +# Gemini Code Assistant: Auto Code Review Guidelines -**리뷰 언어:** 모든 리뷰 코멘트는 한국어로 작성합니다. +**Review Language:** All review comments must be written in Korean. -## 1. 전반적인 원칙 +## 1. General Principles -- **가독성:** 코드는 명확하고 이해하기 쉬워야 합니다. 복잡한 로직에는 주석을 추가하여 다른 개발자가 쉽게 이해할 수 있도록 합니다. -- **일관성:** 프로젝트 전반의 코딩 스타일과 구조를 일관되게 유지합니다. 새로운 코드는 기존 코드의 컨벤션을 따릅니다. -- **단순성 (KISS):** 불필요하게 복잡한 설계나 코드는 지양하고, 최대한 단순하게 구현합니다. +- **Readability:** Code must be clear and easy to understand. Add comments for complex logic to help other developers. +- **Consistency:** Maintain a consistent coding style and structure throughout the project. New code should follow the conventions of existing code. +- **Simplicity (KISS):** Avoid unnecessarily complex designs or code. Strive for the simplest possible implementation. ## 2. TypeScript & Next.js -- **타입 정의:** `any` 타입 사용을 최소화하고, 가능한 구체적인 타입을 정의합니다. `interface`와 `type`을 적절히 구분하여 사용합니다. -- **Next.js 컨벤션:** - - App Router의 최신 컨벤션(서버 컴포넌트, 클라이언트 컴포넌트)을 올바르게 사용하고 있는지 확인합니다. - - 데이터 페칭은 `fetcher.ts`의 공통 함수를 통해 이루어져야 합니다. 직접적인 `fetch` API 사용은 지양하고, `fetcher.ts`를 사용했는지 확인합니다. - - API 라우트 핸들러는 명확하고 안전하게 작성되었는지 확인합니다. +- **Type Definitions:** Minimize the use of the `any` type. Define specific types wherever possible. Use `interface` and `type` appropriately based on the context. +- **Next.js Conventions:** + - Ensure the correct use of modern App Router conventions (Server Components, Client Components). + - Data fetching must be performed through the common functions in `fetcher.ts`. Avoid direct use of the `fetch` API and verify that `fetcher.ts` is used instead. + - API route handlers must be written clearly and securely. - **React Best Practices:** - - React Hooks의 규칙(Rules of Hooks)을 준수하는지 확인합니다. - - 컴포넌트는 단일 책임 원칙(SRP)을 따르도록 작게 분리합니다. - - 상태 관리 로직이 명확하고 효율적인지 검토합니다. + - Adhere to the Rules of Hooks. + - Components should be small and follow the Single Responsibility Principle (SRP). + - State management logic should be clear and efficient. -## 3. 테스트 (Vitest) +## 3. Testing (Vitest) -- **테스트 커버리지:** 중요한 비즈니스 로직과 컴포넌트는 반드시 테스트 코드로 커버되어야 합니다. -- **테스트 케이스:** 테스트 케이스는 명확하게 작성되어야 하며, 성공 케이스와 에러 케이스를 모두 포함하는지 확인합니다. (`describe`, `it`, `expect` 구조) -- **모킹(Mocking):** 외부 의존성은 적절히 모킹하여 테스트의 독립성을 보장하는지 확인합니다. +- **Test Coverage:** Critical business logic and components must be covered by tests. +- **Test Cases:** Test cases should be written clearly and include both success and error scenarios (using `describe`, `it`, `expect` structure). +- **Mocking:** External dependencies must be properly mocked to ensure test independence. -## 4. 보안 +## 4. Security -- **입력 값 검증:** 사용자 입력이나 외부 API 응답과 같이 신뢰할 수 없는 데이터는 항상 검증하고 이스케이프 처리하여 XSS(Cross-Site Scripting) 공격을 방지하는지 확인합니다. -- **API 보안:** API 엔드포인트가 적절한 인증 및 인가 절차를 거치는지 확인합니다. -- **민감 정보 노출:** API 키, 비밀번호 등의 민감한 정보가 코드에 하드코딩되거나 클라이언트에 노출되지 않았는지 확인합니다. `.env` 파일과 환경 변수를 올바르게 사용하는지 검토합니다. -- **의존성 관리:** 알려진 보안 취약점이 있는 라이브러리를 사용하지 않는지 확인합니다. +- **Input Validation:** Always validate and sanitize untrusted data, such as user input or external API responses, to prevent XSS (Cross-Site Scripting) attacks. +- **API Security:** Ensure that API endpoints have proper authentication and authorization checks. +- **Sensitive Information Exposure:** Check that sensitive information like API keys or passwords is not hardcoded in the source code or exposed to the client. Verify the correct use of `.env` files and environment variables. +- **Dependency Management:** Do not use libraries with known security vulnerabilities. \ No newline at end of file From 80ff2581e32657219fff418746e2f9c6cb41067f Mon Sep 17 00:00:00 2001 From: scs0209 Date: Sat, 28 Jun 2025 13:56:28 +0900 Subject: [PATCH 4/7] =?UTF-8?q?chore:=20Gemini=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=96=B4=EC=8B=9C=EC=8A=A4=ED=84=B4=ED=8A=B8=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 자동 코드 리뷰를 위한 Gemini Code Assistant 구성 파일 생성 - PR 리뷰 트리거 이벤트 및 활성화할 기능 정의 --- .gemini/config.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .gemini/config.yaml diff --git a/.gemini/config.yaml b/.gemini/config.yaml new file mode 100644 index 00000000..d1fc6460 --- /dev/null +++ b/.gemini/config.yaml @@ -0,0 +1,17 @@ +# Gemini Code Assistant Configuration + +version: 1 + +# Defines the events that trigger a PR review. +# 'opened': When the PR is first opened. +# 'synchronize': When new commits are pushed to the PR. +on: + pull_request: + types: + - opened + - synchronize + +# Defines which features to enable. +enabled_features: + # Enables automatic code review. + auto_review: true From ed72dd04dae23d4e495135f97d202e1f65393b2a Mon Sep 17 00:00:00 2001 From: scs0209 Date: Sat, 28 Jun 2025 14:10:55 +0900 Subject: [PATCH 5/7] =?UTF-8?q?docs:=20Gemini=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EA=B0=80=EC=9D=B4=EB=93=9C=EB=9D=BC?= =?UTF-8?q?=EC=9D=B8=EC=97=90=20=EB=B3=B4=EC=95=88=20=ED=95=AD=EB=AA=A9=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SQL 인젝션, XSS 등 잠재적인 보안 취약점 확인 항목 추가 --- gemini.md | 1 + 1 file changed, 1 insertion(+) diff --git a/gemini.md b/gemini.md index 9299e4cd..2bb558a3 100644 --- a/gemini.md +++ b/gemini.md @@ -13,3 +13,4 @@ GitHub의 모든 Pull Request에 대해, 시니어 소프트웨어 엔지니어 - **성능:** 명백한 성능 저하를 유발하는 부분이나 비효율적인 쿼리가 있는지 확인합니다. - **에러 처리:** 에러 처리가 견고하게 구현되었는지, 처리되지 않은 예외가 있는지 확인합니다. - **테스트:** 변경 사항이 새로운 테스트나 기존 테스트에 의해 충분히 커버되는지 확인합니다. +- **보안:** SQL 인젝션, XSS(Cross-Site Scripting) 등 잠재적인 보안 취약점이 있는지 확인합니다. \ No newline at end of file From 529136874c17a1dbb1ebd8abdb81987b342fbe6f Mon Sep 17 00:00:00 2001 From: scs0209 Date: Sat, 28 Jun 2025 14:14:19 +0900 Subject: [PATCH 6/7] =?UTF-8?q?chore:=20Gemini=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=96=B4=EC=8B=9C=EC=8A=A4=ED=84=B4=ED=8A=B8=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=ED=8C=8C=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 자동 코드 리뷰 기능 활성화 방식 변경: PR 생성 시 및 이후 커밋에 대한 자동 리뷰 설정 추가 - 불필요한 주석 제거 및 설정 파일 간소화 --- .gemini/config.yaml | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/.gemini/config.yaml b/.gemini/config.yaml index d1fc6460..db9e36ef 100644 --- a/.gemini/config.yaml +++ b/.gemini/config.yaml @@ -1,17 +1,7 @@ -# Gemini Code Assistant Configuration - version: 1 - -# Defines the events that trigger a PR review. -# 'opened': When the PR is first opened. -# 'synchronize': When new commits are pushed to the PR. -on: - pull_request: - types: - - opened - - synchronize - -# Defines which features to enable. enabled_features: - # Enables automatic code review. - auto_review: true + auto_review: + # Enables auto-review on PR creation. + on_opening: true + # Enables auto-review on subsequent commits. + on_commit: true \ No newline at end of file From 968bfc96c82997d49c63d756d27e211938ea24bf Mon Sep 17 00:00:00 2001 From: scs0209 Date: Sat, 28 Jun 2025 14:17:34 +0900 Subject: [PATCH 7/7] =?UTF-8?q?chore:=20Gemini=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=96=B4=EC=8B=9C=EC=8A=A4=ED=84=B4=ED=8A=B8=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=ED=8C=8C=EC=9D=BC=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 자동 코드 리뷰 기능 활성화 방식 간소화 및 추가 기능 활성화 - 리뷰 댓글 심각도 설정 및 코드 리뷰 관련 설정 추가 - PR 생성 시 요약 및 코드 리뷰 활성화 설정 추가 --- .gemini/config.yaml | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/.gemini/config.yaml b/.gemini/config.yaml index db9e36ef..a1eea74a 100644 --- a/.gemini/config.yaml +++ b/.gemini/config.yaml @@ -1,7 +1,24 @@ version: 1 + enabled_features: - auto_review: - # Enables auto-review on PR creation. - on_opening: true - # Enables auto-review on subsequent commits. - on_commit: true \ No newline at end of file + auto_review: true + post_review_summary: true + inline_suggestions: true + review_pull_request: true + severity_level: true + +review_comment_severity: + critical: true + high: true + medium: true + low: false + +code_review: + disable: false + comment_severity_threshold: MEDIUM + max_review_comments: -1 + +pull_request_opened: + summary: true + code_review: true + help: false \ No newline at end of file