Octokit을 곁들인 Pull Request 리마인더 봇 만들기

Jeongkuk Seo
sjk5766
Published in
7 min readJan 28, 2024

MSA로 Repository가 여러 개로 분리된 환경에 있다. 현재 총 6개의 백엔드 Repository가 있고, 개발자 수가 적어서 모든 리뷰 요청에 내가 리뷰어로 할당된다.

매일 아침 출근하면 두 가지 방법으로 리뷰를 한다.
1. https://github.com/pulls/review-requested 링크를 클릭하면 나에게 새로 할당 된 리뷰를 볼 수 있는데, 만약 Comment, Approve, Request Changes를 했다면 노출되지 않는다.
2. 리뷰를 한 번에 Approve 하는 경우도 있지만, Comment로 수정 요청을 하는 경우도 빈번하다. 문제는 한 번 Comment를 달았던 리뷰를 찾으려면 Slack code-review 채널에서 스크롤을 올려가며 찾거나, 내가 각각의 Repository에 들어가 pulls 페이지에 들어가 내가 Comment를 남긴 리뷰 중 놓친 리뷰가 없는지 확인해야 한다.

아침에 출근한 시점에 나에게 할당 된 리뷰 중, 내가 승인하지 않은 PR 목록을 Slack 에서 볼 수 있으면 좋겠다는 생각이 들었고 CTO 님에게 이야기 했더니 흔쾌히 OK라고 대답해 주셔서 해당 글을 쓰게 되었다.

결과 예시

리뷰가 있을 때는 Repository 단위로 묶어서 요청자와 링크를 보내고, 리뷰가 없을 경우는 비어있는 메시지 보다는 아래와 같이 칭찬의 메시지를 넣었다. 개인적으로 이름이 리뷰 비서보다는 조금 센스 있는 이름을 넣고 싶은데 아직 찾지 못했다. 역시 네이밍은 어렵다.

예시 코드

여기서 확인이 가능하다. 예시 코드는 config 값을 적절히 넣고 JS 파일을 실행시키면 해당 Repository의 PR 중 나에게 할당된 PR을 Slack으로 보내도록 작성되어 있다.

요구사항

  • MSA로 분리된 여러 Repository 정보에 접근할 수 있어야 한다.
  • 내가 리뷰어로 할당 된 PR 중 open 상태이고 draft가 아니며 승인하지 않은 모든 PR 목록을 얻어와야 한다.
  • 어떤 회사를 가더라도 설정 값(Github 인증 값, Slack 관련)만 변경하면 동작해야 한다.

기술 선정

찾아보니 PyGithub가 정보도 많고 사용하기 편해보였다. 하지만 사내 기술 스택이 JS다 보니 유지보수 하기 편하도록 Github REST API를 제공하는 Octokit을 사용해서 만들기로 결정했다.

Slack으로 메시지를 보내는 방법은 회사에선 이미 사용하던 hook을 사용했지만 예시 코드에서는 slack/web-api 모듈을 사용했다.

Slack으로 메시지를 받기 위한 과정

보통은 합류한 회사에서 이미 Slack이나 Github 연동이 되어 있기 때문에 필요할지는 모르겠다. 혹시나 Slack에서 Workspace를 새로 만들고, Slack token을 이용해 메시지를 받기 위한 절차가 궁금하다면 이 문서를 참고하길 바란다.

특정 PR에서 나의 리뷰 상태를 찾는 과정

Slack으로 리뷰 목록을 전달할 때 내가 승인한 PR은 제외, Comment를 남긴 리뷰는 포함하려면 특정 리뷰에 대한 나의 리뷰 상태(Approve, Comment, Request Changes)를 알 수 있어야 한다.

이 정보를 찾는데 가장 시간이 오래 걸렸으나 결국 원하는 기능을 찾을 수 없어서, 2개의 API 응답을 통해 보고 리뷰 상태를 판단하도록 했다. 이 과정에서 어떤 문제가 있었고 어떻게 했는지 정리해보겠다.

NodeJS에서 octokit을 설치하고 아래와 같이 특정 Repository의 pull request 정보를 가져올 수 있다.

const prs = await octokit.request('GET /repos/{owner}/{repo}/pulls', {
owner,
repo,
headers: { 'X-GitHub-Api-Version': '2022-11-28' },
});

API를 호출하면 응답 값에서 requested_reviewers 배열을 볼 수 있는데 처음에는 이게 해당 Pull Request에 할당된 리뷰어 목록인 줄 알았다.

"requested_reviewers": [
{
"login": "ggugi",
"id": 1,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/other_user_happy.gif",
"gravatar_id": "",
"type": "User",
"site_admin": false
},
{
"login": "heidi",
"id": 2,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/other_user_happy.gif",
"gravatar_id": "",
"type": "User",
"site_admin": false
}
],

최종적으로 테스트를 했을 때 알게 되었는데 내가 어떤 리뷰에 Comment를 남겼다면 나에게 리뷰가 할당되어 있음에도 requested_reviewers 배열에 내 정보가 포함되지 않는다. 그렇다면 이 배열에 내 githubId가 포함된다면 내가 리뷰해야 할 목록에 포함된다.

그렇다면 Comment를 남긴 PR은 어떻게 찾을까? 아래 API로 특정 Pull Request에 남긴 리뷰 정보를 알 수 있다.

const reviews = await octokit.request(
'GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews',
{
owner,
repo,
pull_number: pullNumber,
headers: { 'X-GitHub-Api-Version': '2022-11-28' },
}
);

이 API는 Pull Request에 남긴 리뷰를 응답하므로 여기에 포함된다면 적어도 1번은 Comment를 남기거나, Approve 하거나, Request Changes를 요청했다는 의미가 된다.

[
{
"id": 80,
"node_id": "MDE3OlB1bGxSZXF1ZXN0UmV2aWV3ODA=",
"user": {
"login": "octocat",
"id": 1
},
"body": "Here is the body for the review.",
"state": "APPROVED",
"submitted_at": "2019-11-17T17:43:43Z",
"commit_id": "ecdd80bb57125d7ba9641ffaa4d7d2c19d3f3091",
"author_association": "COLLABORATOR"
}
]

이 응답 목록에서 user.id가 내 githubId와 일치하는 리뷰 중, 상태가 Approve인 리뷰가 없다면 아직 승인하지 않았다는 의미이므로 내가 리뷰해야 할 목록에 포함된다.

위에서 2개의 API를 소개했는데 두 개의 API 응답 정보를 통해 나에게 리뷰 요청이 왔지만, 아무런 액션을 하지 않은 리뷰 + Comment를 남겼지만 Approve 하지 않은 리뷰 목록을 추출했다.

물론 이것도 완벽하진 않다. 가령 리뷰를 예전에 승인했는데, 리뷰를 재 요청하는 경우는 응답에 Approve인게 있어서 알림 목록에 포함되지 않는다. 이것까지 해결하려면 각 리뷰어마다 submitted_at로 정렬해서 가장 최신의 상태를 봐야 한다. 내 경우, 일하는 환경에선 드문 경우라 이 경우는 예외로 두었다.

정리하며

보통 회사에 합류하면 코드 리뷰에 대한 상호 작용을 Slack으로 전송하는 시스템이 구축된 경우가 많아서 가끔 머릿속으로 이런건 구체적으로 어떻게 하지? 궁금함이 있었는데 이번에 어떤 방식 으로 동작 하는지 알게 되었다.

또 혹시나 Slack에서 놓친 코드 리뷰 때문에 같이 일하는 팀 멤버들의 작업 진행이 더뎌지는 경우가 많이 줄어 들 것 같다. 개인으로도 앞으로 github Repository마다 페이지를 들어갈 일이 없을 것 같아 기분이 좋다.

--

--