-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreview.py
More file actions
105 lines (86 loc) · 2.86 KB
/
Copy pathreview.py
File metadata and controls
105 lines (86 loc) · 2.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
"""Entry point for the AI PR Reviewer GitHub Action."""
from __future__ import annotations
import logging
import sys
from reviewer.config import Config
from reviewer.exceptions import ReviewerError
from reviewer.filters import filter_pr_files
from reviewer.github_client import GitHubClient, post_or_update_comment
from reviewer.prompt import build_prompt, get_system_prompt
from reviewer.providers import call_llm_with_fallback, get_provider
logging.basicConfig(
level=logging.INFO,
format="%(levelname)s | %(message)s",
)
log = logging.getLogger("ai-pr-reviewer")
def main() -> None:
cfg = Config.from_env()
github = GitHubClient(token=cfg.github_token, repo=cfg.repo)
log.info(
"Reviewing PR #%s on %s (providers=%s, language=%s)",
cfg.pr_number,
cfg.repo,
",".join(cfg.llm_providers),
cfg.language,
)
raw_files = github.get_pr_files(cfg.pr_number)
log.info("Fetched %d file(s) from GitHub API.", len(raw_files))
files, skipped = filter_pr_files(
raw_files,
ignore_patterns=cfg.ignore_patterns,
max_files=cfg.max_files,
)
if not files:
log.info("No reviewable files — posting 'nothing to review'.")
post_or_update_comment(
github,
pr_number=cfg.pr_number,
review_body=(
"## AI Code Review\n\nNothing to review — no reviewable file changes in this PR."
),
)
return
log.info(
"Reviewing %d file(s) (%d skipped).",
len(files),
len(skipped),
)
prompt = build_prompt(
files,
pr_title=cfg.pr_title,
pr_body=cfg.pr_body,
language=cfg.language,
total_files=len(raw_files),
skipped=skipped,
)
provider_chain: list[tuple] = []
for i, (name, key) in enumerate(zip(cfg.llm_providers, cfg.llm_api_keys)):
model = cfg.llm_model if i == 0 else ""
provider = get_provider(name=name, api_key=key, model=model)
system_prompt = get_system_prompt(provider=name)
provider_chain.append((provider, system_prompt))
review = call_llm_with_fallback(provider_chain, user=prompt)
post_or_update_comment(
github,
pr_number=cfg.pr_number,
review_body=review,
)
log.info("Review posted successfully.")
def entrypoint() -> None:
"""Wrap main() with error handling for CLI usage."""
try:
main()
except ReviewerError as exc:
log.error("[%s] %s", exc.code, exc.message)
sys.exit(1)
except Exception as exc:
log.critical(
"Unexpected error — this is likely a bug. "
"Please report it at https://github.com/AndreaBonn/ai-pr-reviewer/issues. "
"Details: %s: %s",
type(exc).__name__,
exc,
)
sys.exit(2)
if __name__ == "__main__":
entrypoint()