pr-agent /describe에 TODO/FIXME 스캐너 통합하기

.·2025년 5월 18일
0
post-thumbnail

팀 회의 중, PR에 /describe 명령어로 코드 내 TODO 항목을 자동 추출해서 보여주는 기능을 추가하면 좋겠다는 아이디어가 나왔다.

그래서 팀원들이 각자 로컬에서 테스트를 해보고, 최종적으로 PR을 리뷰해보기로 했다.

하지만 아쉽게도 메인 컨트리뷰터 분께서는 이 기능은 /describe가 아닌 /review에 들어가는 게 적절하다고 판단하셔서 방향이 바뀌게 되었다.

비록 머지되지는 않았지만, 그동안 직접 분석하고 구현한 과정을 기록해두고 싶어 이렇게 정리해본다!


기능 개요

/describe 명령 실행 시 PR의 diff 내에서 TODO 또는 FIXME 같은 주석을 자동으로 감지하여,
PR 설명 하단에 "TODOs Found in Diff" 섹션을 추가하는 기능을 구현했다.


구현 단계 요약

1. TODOCommentScanner 클래스 생성

파일: pr_agent/tools/todo_comment_scanner.py

→ PR diff의 추가된 라인만을 대상으로 설정된 키워드 (TODO, FIXME)가 포함된 주석을 탐색한다.

scanner = TODOCommentScanner(["TODO", "FIXME"])
scanner.scan(diff_str)  # → ["main.py:12 — # TODO: fix edge case"]
  • 정규표현식을 기반으로 라인을 필터링하고 형식을 통일시켜 반환하는 형식!

2. configuration.toml 설정 추가

파일: pr_agent/settings/configuration.toml

[pr_description]
scan_patterns = ["TODO", "FIXME"]

→ 그 다음 get_scan_patterns() 함수로 가져오도록 한다. 그러면 키워드를 하드코딩하지 않고 설정으로 분리하여 유연하게 관리 가능하다.


3. /describe 내부에서 호출 추가

파일: pr_agent/tools/pr_description.py

from pr_agent.tools.todo_comment_scanner import TODOCommentScanner
from pr_agent.config_loader import get_scan_patterns

# ...

patterns = get_scan_patterns()
scanner = TODOCommentScanner(patterns)
diff_str = self.patches_diff or ""
scan_results = scanner.scan(diff_str)
self.vars["scan_results"] = scan_results[:10] if scan_results else []

설정 기반으로 diff를 스캔하여 최대 10개까지 TODO 항목을 저장한다.


4. _prepare_pr_answer() 내부 추가

if self.vars.get("scan_results"):
    pr_body += "\n\n### 🔧 TODOs Found in Diff\n"
    for line in self.vars["scan_results"]:
        pr_body += f"- {line}\n"

마지막으로 PR 설명 텍스트에 bullet list로 TODO 항목들을 삽입한다.


다음으로 실제 테스트를 진행해보았다!

5. 단위 테스트 작성

파일: tests/unittest/test_todo_comment_scanner.py

import pytest
from pr_agent.tools.todo_comment_scanner import TODOCommentScanner

SAMPLE_DIFF = """\
diff --git a/foo.py b/foo.py
--- a/foo.py
+++ b/foo.py
@@ -1 +1,2 @@
 def fn():
+    # TODO: handle error
"""

def test_scan_detects_todo():
    scanner = TODOCommentScanner(["TODO"])
    assert scanner.scan(SAMPLE_DIFF) == ["foo.py:2 — # TODO: handle error"]

def test_scan_ignores_non_added_todo():
    diff = SAMPLE_DIFF.replace("+    # TODO", "     # TODO")
    assert TODOCommentScanner(["TODO"]).scan(diff) == []
  • diff 포맷을 기반으로 실제 TODO 탐지 여부를 확인하는 테스트 케이스 작성하였는데, 사진처럼

  • 테스트를 통과하는 모습을 살펴볼 수 있다.

실제 깃허브에서 확인해보자.

실제 모습

python3 -m pr_agent.cli --pr_url https://github.com/.../pr-agent/pull/7 describe

실행 시, 아래처럼 TODO 섹션이 자동으로 생성됨을 알 수 있다!


마무리

비록 /describe에는 반영되지 않았지만, 기능을 직접 구현해보고 LLM 기반 에이전트 코드베이스에서의 확장 포인트를 고민해볼 수 있었다.

다음엔 /review 명령에 이 기능을 반영하는 PR을 준비해볼 계획이다.
또한, 단순 정규표현식 탐지 외에도 LLM이 의미적으로 "수정이 필요한 주석"을 분류하도록 개선하는 것도 도전해보고 싶다!

0개의 댓글