Profile picture

[Python] Github PR 코드 리뷰 봇 구현하기

JaehyoJJAng2024년 06월 18일

개요

팀 프로젝트가 아닌 개인 프로젝트를 진행하다보면 PR 없이 오직 push로만 코드 업데이트를 하는 경우가 꽤 있다.

이번에는 외롭지 않은 개인 프로젝트를 진행해보기 위해서

PR 요청 시 코드 리뷰를 받아볼 수 있도록 AI를 적용해보려고 한다.
image


시나리오

  • PR이 생성되거나 업데이트되면 Github Actions가 트리거 됨.
  • Github Actions는 저장소를 체크아웃하고, 파이썬 설정 및 필요한 패키지를 설치함.
  • review_pr.py 스크립트가 실행됨.
  • 스크립트는 PR에서 변경된 파일을 가져와 OpenAI API로 리뷰를 요청함.
  • OpenAI API의 응답을 PR 코멘트로 작성함

워크플로우 작성

이 파일은 .github/workflows 디렉토리에 저장하자. PR이 열리거나 업데이트될 때 파이썬 스크립트를 실행하도록 설정한다.

name: Review PR

on:
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  review:
    runs-on: ubuntu-latest

    steps:
    - name: "1. Checkout repository"
      uses: actions/checkout@v2

    - name: "2. Set up Python"
      uses: actions/setup-python@v2
      with:
        python-version: '3.x'

    - name: "3. Install dependencies"
      run: |
        python -m pip install --upgrade pip
        python -m pip install -r requirements.txt

    - name: "4. Run PR review script"
      env:
        OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
        GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
      run: |
        python review_pr.py

PR 추적

먼저 레포지토리 정보를 가져와야 한다.

g = Github(github_token)

repo = g.get_repo(repo_name)
Repository(full_name="JaehyoJJAng/pr-review-bot")

repo 변수를 출력하면 위처럼 Repository 객체 정보가 출력된다.


그리고 open된 PR 목록을 가져온 후 출력해보면

open_prs = repo.get_pulls(state='open', sort='created', direction='desc')
<github.PaginatedList.PaginatedList object at 0x746dfcd5add0>

PaginatedList 객체가 반환된다.


이걸 반복문을 사용해 PR 정보 값을 가져올 수 있는데

for pr in open_prs:
    print(pr) 
PullRequest(title="리뷰용 파이썬 파일", number=3)

위와 같은 데이터가 반환되며


이걸 아래와 같이 PullRequest 객체의 속성에 접근해 값을 빼올 수 있다.

for pr in open_prs:
    print(pr.title, pr.number)
리뷰용 파이썬 파일 3

위 내용을 바탕으로 리뷰된 PR은 건너뛰는 예외 처리 로직을 구현하고 리뷰 수행 함수를 실행하면 된다.

for pr in open_prs:    
    # 이미 리뷰된 PR은 건너뜀. 예: 특정 레이블이 붙어 있는 경우
    if any(label.name == "reviewed" for label in pr.labels):
        continue

    # 리뷰를 수행하고 해당 PR에 레이블을 추가
    review_pr(repo_name, pr.number)
    pr.add_to_labels('reviewed')
  • 1. PR의 라벨 확인
    • pr.labels는 PR에 붙어있는 모든 라벨의 리스트를 반환합니다.
    • 각 라벨은 label 객체이며, label.name 속성으로 라벨의 이름에 접근할 수 있습니다.
  • 2. 라벨 이름이 'reviewed'인지 확인
    • any(label.name == "reviewed" for label in pr.labels)는 PR의 라벨 중 하나라도 reviewed 라는 이름을 가진 라벨이 있는지 확인하는 조건문입니다.
    • any 함수는 주어진 조건을 만족하는 요소가 하나라도 있으면 True를 반환합니다.
    • 리스트 컴프리헨션 for label in pr.labels를 통해 PR의 모든 라벨을 순회하면서 label.name == "reviewed" 조건을 확인합니다.
  • 3. 조건을 만족하면 PR을 건너뜁니다:
    • continue 키워드는 현재 반복(iteration)을 중단하고 다음 반복으로 넘어가게 합니다.
    • 즉, PR의 라벨 중 'reviewed' 라벨이 있다면, 해당 PR은 이미 리뷰된 것으로 간주하고, 다음 PR로 넘어갑니다.

왜 필요한가?

  • 리뷰 중복 방지: 이미 리뷰된 PR을 다시 리뷰하는 것을 방지합니다. 이렇게 하면 중복 작업을 줄이고, 불필요한 리뷰를 피할 수 있습니다.
  • 라벨로 상태 관리: PR의 상태를 라벨로 관리할 수 있습니다. 예를 들어, 'reviewed' 라벨을 붙여서 해당 PR이 이미 리뷰되었음을 표시할 수 있습니다.

전체 코드

https://github.com/JaehyoJJAng/pr-review-bot


Loading script...