-
GitHub 오픈소스 PR 리뷰, 놓치지 않는 자동화 시스템 만들기IT 2026. 4. 12. 21:00
PR 리뷰를 왜 놓치게 되는가
오픈소스 프로젝트의 메인테이너 역할을 맡고 있으면, PR(Pull Request) 리뷰는 중요하지만 긴급하지 않은 업무에 속하기 쉽다. 본업이 따로 있으니 GitHub 알림은 메일함 저 너머로 밀려나고, 일주일쯤 지나서야 "아, 리뷰 요청이 와 있었네" 하게 된다.
문제는 이게 단순한 지연이 아니라는 점이다.
- 기여자 이탈: 리뷰가 늦어지면 기여자가 흥미를 잃고 PR을 포기한다
- 컨텍스트 유실: 며칠 지난 PR을 열면 "이게 뭐였지?" 하며 다시 파악해야 한다
- 리뷰 부채 누적: 미뤄둔 PR이 쌓이면 한꺼번에 처리해야 하는 압박이 생긴다
GitHub 자체 알림이나 이메일 노티도 있지만, 수십 개의 리포에서 쏟아지는 알림 속에서 내가 리뷰해야 하는 PR만 골라서 판단하기는 쉽지 않다. 결국 필요한 건 "오늘 리뷰할 PR이 있는지 매일 알려주고, 그 자리에서 바로 처리할 수 있는 시스템"이었다.
설계 목표
만들고 싶은 시스템의 요구사항을 정리하면 이렇다.
- 매일 정해진 시간에 자동 확인: PR이 있을 때만 알림, 없으면 조용히
- 변경 내용 요약 제공: PR 제목뿐 아니라 diff를 분석해서 핵심 변경사항을 파악할 수 있게
- 모바일에서 즉시 처리: 텔레그램 메시지로 받고, 답장만으로 승인·거절·보류 처리
- 거절 시 정중한 영어 코멘트 자동 생성: 한국어로 짧게 사유만 쓰면 영어로 변환
- 처리 이력 기록: 나중에 리뷰 통계를 낼 수 있도록 로그 축적
전체 아키텍처
시스템은 크게 두 파트로 나뉜다.
파트 1: 매일 아침 자동 확인 (cron + 셸 스크립트)
매일 오전 10시에 cron이 셸 스크립트를 실행한다. 이 스크립트가 하는 일은 단순하다.
- GitHub CLI(
gh)로 대상 리포의 open PR 목록을 조회한다 - PR이 없으면 그대로 종료한다 (알림 없음)
- PR이 있으면 각 PR의 diff를 가져온다
- AI 에이전트(OpenClaw)에게 diff 요약을 맡긴다
- 요약 결과를 텔레그램으로 전송한다
핵심은 PR이 없으면 아무 일도 하지 않는다는 점이다. 매일 "오늘은 PR 없습니다" 같은 메시지를 받으면 금세 무시하게 된다. 알림이 올 때만 주의를 기울이면 되도록 설계했다.
파트 2: 텔레그램에서 즉시 처리 (AI 에이전트 스킬)
텔레그램으로 알림을 받은 후, 같은 채팅방에서 바로 응답하면 AI 에이전트가 GitHub API를 호출해서 리뷰 액션을 수행한다. 승인하면 머지까지, 거절하면 정중한 코멘트까지 자동으로 처리된다.
구현 상세
1단계: PR 조회와 diff 요약
cron 스크립트의 핵심 로직은 이렇다.
# GitHub CLI로 open PR 조회 gh pr list --repo [대상리포] --state open \ --json number,title,author,createdAt,additions,deletions,changedFiles # 각 PR의 diff를 가져와서 AI에게 요약 요청 gh pr diff [PR번호] --repo [대상리포]gh pr list의--json옵션이 편리하다. 필요한 필드만 골라서 JSON으로 받을 수 있어서 파싱이 간단하다. diff는 최대 3,000자까지만 잘라서 AI에게 넘기는데, 문서 리포 특성상 대부분의 PR이 이 범위 안에 들어온다.AI가 생성한 요약은 상태 파일(
pending_prs.json)에 함께 저장된다. 이 파일이 cron 스크립트와 AI 에이전트 사이의 브릿지 역할을 한다. cron이 쓰고, 에이전트가 읽는 구조다.2단계: 텔레그램 알림
알림 메시지는 이런 형태로 온다.
📋 PR 알림 #2323 Add new package documentation by contributor123 | 2026-04-02 변경: 패키지 매니저에 새 패키지 문서 추가. API 레퍼런스 문서 다수 신규 작성. 파일: +2089 -0 (23 files) (생략) 승인: #번호 승인 거절: #번호 거절: 사유 보류: #번호 보류각 PR마다 제목, 작성자, 날짜, AI 요약, 변경 통계가 포함된다. 메시지 하단에는 응답 형식 가이드가 붙어 있어서, 처음 보는 사람도 바로 사용할 수 있다.
3단계: 승인/거절/보류 처리
텔레그램에서 응답하면 AI 에이전트가 메시지를 파싱해서 해당 액션을 수행한다.
승인 (
#2323 승인):- PR 상태 확인 (이미 머지/종료되었는지)
gh pr review --approve로 승인gh pr merge로 머지- 상태 파일에서 해당 PR 제거
거절 (
#2323 거절: API 형식이 기존과 다름):- 한국어 사유를 영어로 정중하게 변환
gh pr review --request-changes로 리뷰 코멘트 등록- 상태 파일에서 해당 PR 제거
보류 (
#2323 보류):- 아무 GitHub 액션도 하지 않음
- 상태 파일에 PR 유지 → 다음날 알림에서 다시 표시
거절 플로우에서 가장 마음에 드는 부분은 한국어 → 영어 정중 변환이다. "API 형식이 다름"이라고 짧게 쓰면, AI가 이런 식으로 바꿔준다.
"Thank you for this contribution! I noticed that the API documentation format differs from our existing conventions. Could you please adjust the formatting to match the patterns used in other docs? Happy to help if you have any questions."
오픈소스에서 기여자에게 변경을 요청할 때 톤이 중요한데, 바쁠 때 짧게 쓴 한국어가 정중한 영어 리뷰로 변환되니 커뮤니케이션 부담이 크게 줄었다.
4단계: 액션 로그
모든 승인/거절/보류 처리는 JSONL(줄 단위 JSON) 형식으로 기록된다.
{"timestamp": "2026-04-03T10:30:00+09:00", "action": "approve", "pr_number": 2323, ...} {"timestamp": "2026-04-04T11:15:00+09:00", "action": "reject", "pr_number": 2324, ...} (생략)JSONL을 선택한 이유는 append가 간단하고(한 줄 추가), 나중에
jq나 Python pandas로 통계를 뽑기 편하기 때문이다. 월별 승인율, 평균 리뷰 소요 시간, 자주 거절하는 패턴 같은 분석이 가능해진다.상태 파일이라는 브릿지
이 시스템에서 미묘한 설계 포인트가 하나 있다. cron 스크립트와 AI 에이전트는 서로 다른 프로세스다. cron은 정해진 시간에 독립적으로 실행되고, AI 에이전트는 텔레그램 메시지가 올 때 실행된다. 이 둘 사이에 세션이나 메모리 공유가 없다.
이 간극을 메우는 게
pending_prs.json상태 파일이다.{ "checked_at": "2026-04-03T10:00:00+09:00", "prs": [ { "number": 2323, "title": "Add new package documentation", "author": "contributor123", "summary": "패키지 매니저에 새 패키지 문서 추가...", (생략) } ] }cron이 이 파일을 쓰고, AI 에이전트가 읽는다. 파일이 없거나 오래된 경우에는 에이전트가 직접 GitHub API를 호출해서 최신 정보를 가져오도록 fallback을 두었다. 원자적 쓰기(임시 파일에 쓴 후
mv로 교체)를 사용해서 반쯤 쓰인 파일을 읽는 상황도 방지했다.실제 사용 경험
아침에 출근길 지하철에서 텔레그램 알림을 확인한다. PR이 올라와 있으면 AI가 요약해준 내용을 읽고, 30초 안에 판단할 수 있다.
- 문서 추가 PR이고 형식도 맞으면 →
#2323 승인한 줄 입력 - 좀 더 살펴봐야 하면 →
#2323 보류로 미뤄두고 사무실에서 확인 - 명확한 문제가 있으면 →
#2323 거절: 이미지 경로가 깨져있음
PR이 없는 날은 알림 자체가 안 오니까 신경 쓸 것이 없다. 이전에는 "혹시 PR 와있나?" 하고 GitHub를 들여다보는 습관적 확인이 필요했는데, 그 인지 부하가 사라졌다.
구현에 사용한 도구들
도구 역할 GitHub CLI ( gh)PR 조회, 리뷰, 머지 cron 매일 10시 스케줄링 텔레그램 Bot API 알림 전송 OpenClaw diff 요약, 거절 사유 변환, 명령 파싱 Python JSON 처리, 상태 관리 JSONL 액션 로그 포맷 특별히 복잡한 인프라가 필요하지 않다. 리눅스 서버 한 대에
gh와 텔레그램 봇, 그리고 OpenClaw가 있으면 동일한 시스템을 구축할 수 있다.확장 가능성
현재는 단일 리포를 대상으로 하지만, 구조적으로 확장하기 쉽다.
- 다중 리포 지원: cron 스크립트에 리포 목록을 배열로 넣으면 여러 프로젝트를 한 번에 모니터링할 수 있다
- 자동 승인 규칙: 특정 작성자의 typo fix PR은 자동 승인하는 등의 규칙 추가
- 리뷰 통계 대시보드: JSONL 로그를 기반으로 월간 리뷰 현황을 시각화
- CI 연동: CI가 통과한 PR만 알림에 포함하도록 필터링
마무리
이 시스템의 핵심 가치는 "리뷰를 잊지 않게 해주는 것"이 아니라, "리뷰의 마찰을 줄여주는 것"이다. GitHub을 열고, PR을 찾고, diff를 읽고, 코멘트를 작성하는 일련의 과정이 텔레그램 한 줄 답장으로 압축된다.
오픈소스 메인테이너로서 기여자에게 빠르게 피드백을 줄 수 있게 되었고, 거절할 때도 정중한 톤을 유지할 수 있게 되었다. 사소하지만 반복적인 업무를 자동화하면, 그 시간만큼이 아니라 그 업무를 기억하고 있어야 하는 인지 비용까지 절약된다.
이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.
'IT' 카테고리의 다른 글
LangGraph 에이전트에 Langfuse 붙이기 — LLM 앱의 블랙박스를 유리상자로 (0) 2026.04.16 Chain이 아니라 Graph — LangGraph로 AI 에이전트를 만드는 이유 (0) 2026.04.16 아카라이브 알파카 채널과 AI 모델 이름의 계보 (0) 2026.04.14 Gemma 4 로컬 AI 스택 완전 정복 — DGX Spark에서 돌려본 솔직한 후기 (1) 2026.04.13 GPU에서 LLM까지, 추론 스택 완전 해부 (0) 2026.04.13 AI 코딩 에이전트의 자기 진화 학습 시스템 — 실수를 기억하고 성장하는 에이전트 만들기 (1) 2026.04.11 Qdrant 벡터 DB, 임베디드 모드에서 Docker 서버로 전환한 이유 — 로컬 RAG 시스템 구축 삽질기 (0) 2026.04.10 캘린더 싱크의 중복 지옥, event_id로 탈출하기 — Google Calendar → Obsidian 자동화 삽질기 (1) 2026.04.09 Claude Code가 플랜을 짜는 방법 - Plan Mode 내부 동작 원리 (0) 2026.04.08 axios에 악성코드가 심어졌다 - 북한 해커의 npm 공급망 공격 분석 (2) 2026.04.07