GitHub Actions 설정을 시작하는 방법부터 차근차근 설명드리겠습니다.

1. GitHub 리포지토리에 .github/workflows 디렉토리 생성

먼저, GitHub Actions는 .github/workflows 디렉토리에 있는 YAML 파일을 기반으로 동작합니다. 리포지토리의 루트 디렉토리에 .github/workflows라는 폴더를 만들어야 합니다.

mkdir -p .github/workflows

2. GitHub Actions 워크플로우 파일 생성

이제 해당 디렉토리 안에 워크플로우를 정의하는 YAML 파일을 생성합니다. 예를 들어, ai-code-review.yml이라는 파일을 만들어 봅시다.

touch .github/workflows/ai-code-review.yml

파일을 생성했다면, 이 파일 안에 GitHub Actions 워크플로우를 설정합니다.

3. 기본 워크플로우 작성

GitHub Actions는 트리거 조건에 따라 작업을 실행합니다. 예를 들어, 브랜치에 푸시가 발생했을 때 실행되도록 워크플로우를 설정할 수 있습니다. 다음은 기본적인 푸시 이벤트가 발생했을 때 워크플로우를 실행하는 YAML 파일입니다.

name: AI Code Review  
on:  
  push:  
    branches-ignore:  
      - main  
  
jobs:  
  code_review:  
    runs-on: ubuntu-latest  
    steps:  
      - name: Checkout code  
        uses: actions/checkout@v3.5.3  
        with:  
          fetch-depth: 0  # 전체 히스토리를 가져옵니다  
  
      - name: Get branch name  
        id: branch-name  
        run: echo "branch=${GITHUB_REF#refs/heads/}" >> $GITHUB_OUTPUT  
  
      - name: Fetch and checkout branch  
        run: |  
          git fetch origin ${{ steps.branch-name.outputs.branch }}  
          git checkout ${{ steps.branch-name.outputs.branch }}  
          git pull origin ${{ steps.branch-name.outputs.branch }}  
  
      - name: Install Python  
        uses: actions/setup-python@v4.6.1  
        with:  
          python-version: '3.x'  
  
      - name: Install dependencies  
        run: |  
          python -m pip install --upgrade pip  
          pip install -r codereview_requirements.txt  
          pip install GitPython  
  
      - name: Run AI Code Review  
        id: review_step  
        env:  
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}  
        run: |  
          python .github/scripts/review_code.py > review_output.json  
          if [ $? -ne 0 ]; then  
            echo "Python script failed"  
            cat review_output.json  
            exit 1  
          fi  
  
      - name: Post review as a commit comment  
        uses: actions/github-script@v6  
        with:  
          github-token: ${{secrets.GITHUB_TOKEN}}  
          script: |  
            const fs = require('fs');  
            const review = JSON.parse(fs.readFileSync('review_output.json', 'utf8'));  
              
            let commentBody = `## AI 코드 리뷰\n\n### 요약\n${review.summary}\n\n`;  
            if (review.details.length > 0) {  
              commentBody += '### 세부 사항\n';  
              review.details.forEach(detail => {  
                commentBody += `#### ${detail.file}\n${detail.comment}\n\n`;  
              });  
            }  
              
            await github.rest.repos.createCommitComment({  
              owner: context.repo.owner,  
              repo: context.repo.repo,  
              commit_sha: context.sha,  
              body: commentBody  
            });

4. OpenAI API 통합 준비

GitHub Actions에서 OpenAI API를 사용하려면 OpenAI API 키가 필요합니다. 이 API 키는 보안이 중요한 정보이므로 GitHub Secrets에 저장해야 합니다.

  1. 리포지토리의 Settings > Secrets and variables > Actions로 이동합니다.
  2. New repository secret 버튼을 클릭합니다.
  3. NameOPENAI_API_KEY, Value에 OpenAI API 키를 입력하고 저장합니다.

이렇게 하면 GitHub Actions에서 보안상 중요한 값을 환경 변수로 사용할 수 있습니다.

5. Python 스크립트 작성

위 워크플로우에서 Python을 설치했으니, 이제 OpenAI API를 사용한 코드 리뷰 스크립트를 작성해야 합니다. 이를 위해 Python 스크립트를 작성하고, 워크플로우에서 실행되도록 할 수 있습니다.

예를 들어, .github/scripts/review_code.py라는 파일을 생성하고, 변경된 코드를 분석하는 Python 스크립트를 작성합니다.

import openai  
import os  
import json  
from git import Repo  
  
# OpenAI API 키 가져오기  
openai.api_key = os.getenv("OPENAI_API_KEY")  
  
def get_diff_content(file_path):  
    """Git diff 명령을 사용하여 특정 파일의 변경된 부분을 가져오는 함수"""  
    try:  
        repo = Repo(".")  
  
        # 원격 저장소 정보 갱신  
        origin = repo.remotes.origin  
        origin.fetch()  
  
        # 원격 브랜치와 로컬 HEAD 간의 diff를 가져옴  
        # 여기서 HEAD~1 대신, origin/main과 비교하여 현재 커밋의 변경사항을 가져옴  
        diff_content = repo.git.diff('origin/main', 'HEAD', file_path)  
  
        if diff_content:  
            return diff_content  
        else:  
            print(f"No changes detected in {file_path}.")  
            return None  
    except Exception as e:  
        print(f"Error getting diff for {file_path}: {e}")  
        return None  
  
  
def review_code(file_path, diff_content):  
    """OpenAI API로 변경된 부분에 대한 코드 리뷰 요청"""  
    try:  
        response = openai.ChatCompletion.create(  
            model="gpt-4o-mini",  
            messages=[  
                {"role": "system", "content": "You are a code reviewer. Always provide your feedback in Korean, regardless of the language of the question."},  
                {"role": "user", "content": f"""  
                Please review the following changes in the file:\n  
                File: {file_path}\n  
                Changes:\n{diff_content}\n  
                Provide detailed feedback based on the following criteria:  
                1. Are there any potential bugs introduced by these changes?                2. Are there sections with duplicated code or opportunities for reusable modules?                3. Does the code follow established coding conventions? Point out any inconsistencies.                4. Provide refactoring suggestions to improve code quality, readability, and maintainability.                5. Are there any performance issues? Suggest possible optimizations.                6. Could any security vulnerabilities be introduced by these changes?                7. Is the test coverage sufficient for these changes? If not, suggest additional test cases.                8. Are the comments and documentation adequate? Point out anything unclear or needing further explanation.  
                Only respond to relevant criteria and skip those that are unnecessary.                Your response should be exclusively in Korean.                """}  
            ]  
        )  
        return response.choices[0].message['content'].strip()  
    except Exception as e:  
        return f"Error during review of {file_path}: {str(e)}"  
  
def get_changed_files():  
    """원격 저장소와 로컬 저장소의 공통 조상을 기준으로 변경된 파일 목록을 가져오는 함수"""  
    try:  
        repo = Repo(".")  
  
        # 원격 저장소 정보 갱신  
        origin = repo.remotes.origin  
        origin.fetch()  
  
        # 현재 브랜치의 마지막 공통 조상을 기준으로 diff 수행  
        merge_base = repo.git.merge_base('origin/main', 'HEAD')  
        diff_index = repo.git.diff(merge_base, 'HEAD', '--name-only')  
  
        # 변경된 파일 목록 출력 및 반환  
        if not diff_index:  
            print("No changes found between the last common ancestor and the current commit.")  
            return []  
  
        # 파일 목록을 줄바꿈 기준으로 분리하고 빈 문자열 제거  
        changed_files = diff_index.splitlines()  
        return changed_files  
    except Exception as e:  
        print(f"Error occurred while fetching changed files: {e}")  
        return []  
  
def main():  
    try:  
        changed_files = get_changed_files()  
  
        if not changed_files:  
            print("No code changes detected.")  
            return  
  
        review_summary = "코드 리뷰가 완료되었습니다. 세부 사항은 아래를 참조하세요."  
        review_details = []  
  
        for file in changed_files:  
            if file.endswith(('.py', '.js', '.java', '.cpp', '.h')):  # 필요한 파일 확장자 추가  
                diff_content = get_diff_content(file)  
                if diff_content is not None:  
                    review = review_code(file, diff_content)  
                    review_details.append({"file": file, "comment": review})  
  
        output = {  
            "summary": review_summary,  
            "details": review_details  
        }  
  
        print(json.dumps(output, ensure_ascii=False, indent=2))  
    except Exception as e:  
        print(json.dumps({"error": str(e)}))  
  
if __name__ == "__main__":  
    main()

6. GitHub Actions에서 Python 스크립트 실행

이제 GitHub Actions에서 Python 스크립트를 실행하도록 설정해야 합니다. 다음과 같이 YAML 파일에 Python 스크립트를 실행하는 단계를 추가합니다.

    - name: Run AI Code Review  # Python 스크립트 실행 단계 추가
      run: python .github/scripts/review_code.py

7. GitHub에서 변경사항 푸시 및 확인

이제 위의 모든 설정을 완료했으면, GitHub 리포지토리에 푸시합니다.

git add .
git commit -m "Add AI code review action"
git push origin <your-branch>

푸시가 완료되면, GitHub Actions가 트리거되어 OpenAI API를 통해 코드 리뷰가 실행되고, 결과가 PR 코멘트로 표시되게 됩니다.