Skip to content

Commit 3a5d1fa

Browse files
committed
test(examples): add opt-in container runtime e2e test for code review
1 parent 6ec93f4 commit 3a5d1fa

3 files changed

Lines changed: 144 additions & 0 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#!/usr/bin/env python3
2+
# Tencent is pleased to support the open source community by making tRPC-Agent-Python available.
3+
#
4+
# Copyright (C) 2026 Tencent. All rights reserved.
5+
#
6+
# tRPC-Agent-Python is licensed under Apache-2.0.
7+
"""Automated code review agent CLI.
8+
9+
Usage:
10+
python run_agent.py review --fixture security_eval --runtime local --dry-run
11+
python run_agent.py review --diff-file change.diff --runtime container
12+
python run_agent.py show --task-id <id>
13+
"""
14+
import argparse
15+
import asyncio
16+
import json
17+
import sys
18+
from pathlib import Path
19+
20+
sys.path.insert(0, str(Path(__file__).resolve().parent))
21+
22+
from agent.config import is_dry_run # noqa: E402
23+
from review.diff_input import load_diff # noqa: E402
24+
from review.pipeline import ReviewOptions, run_review # noqa: E402
25+
from storage.store import ReviewStore # noqa: E402
26+
27+
28+
def _build_parser() -> argparse.ArgumentParser:
29+
parser = argparse.ArgumentParser(description="Automated code review agent")
30+
sub = parser.add_subparsers(dest="command", required=True)
31+
32+
review = sub.add_parser("review", help="run a code review")
33+
review.add_argument("--diff-file", help="path to a unified diff / PR patch")
34+
review.add_argument("--repo-path", help="git repo; reviews `git diff HEAD`")
35+
review.add_argument("--fixture", help="bundled fixture name (e.g. security_eval)")
36+
review.add_argument("--runtime", default="container",
37+
choices=["local", "container", "cube"],
38+
help="sandbox runtime (default: container; local is dev-only)")
39+
review.add_argument("--dry-run", action="store_true",
40+
help="use the deterministic fake model (no API key needed)")
41+
review.add_argument("--db-url", default="sqlite:///code_review.db")
42+
review.add_argument("--output-dir", default="out")
43+
review.add_argument("--no-llm", action="store_true", help="skip the LLM step")
44+
45+
show = sub.add_parser("show", help="print a stored review task by id")
46+
show.add_argument("--task-id", required=True)
47+
show.add_argument("--db-url", default="sqlite:///code_review.db")
48+
return parser
49+
50+
51+
async def main(argv=None) -> int:
52+
args = _build_parser().parse_args(argv)
53+
if args.command == "review":
54+
diff_text, input_type, input_ref = load_diff(
55+
diff_file=args.diff_file, repo_path=args.repo_path, fixture=args.fixture)
56+
dry_run = is_dry_run(args.dry_run)
57+
if dry_run and not args.dry_run:
58+
print("no TRPC_AGENT_API_KEY configured; falling back to --dry-run mode")
59+
result = await run_review(ReviewOptions(
60+
diff_text=diff_text, input_type=input_type, input_ref=input_ref,
61+
runtime=args.runtime, dry_run=dry_run, db_url=args.db_url,
62+
output_dir=args.output_dir, enable_llm=not args.no_llm))
63+
print(f"task_id={result.task_id}")
64+
print(f"conclusion={result.report['conclusion']}")
65+
print(f"report_json={result.json_path}")
66+
print(f"report_md={result.md_path}")
67+
return 0
68+
69+
store = ReviewStore(db_url=args.db_url)
70+
try:
71+
bundle = await store.get_task_bundle(args.task_id)
72+
finally:
73+
await store.close()
74+
if bundle["task"] is None:
75+
print(f"task {args.task_id!r} not found", file=sys.stderr)
76+
return 1
77+
print(json.dumps(bundle, indent=2, ensure_ascii=False, default=str))
78+
return 0
79+
80+
81+
if __name__ == "__main__":
82+
sys.exit(asyncio.run(main()))
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Tencent is pleased to support the open source community by making tRPC-Agent-Python available.
2+
#
3+
# Copyright (C) 2026 Tencent. All rights reserved.
4+
#
5+
# tRPC-Agent-Python is licensed under Apache-2.0.
6+
"""CLI smoke tests (invoke main() in-process)."""
7+
import json
8+
9+
import run_agent
10+
11+
12+
async def test_cli_review_and_show(tmp_path, capsys):
13+
db_url = f"sqlite:///{tmp_path}/cr.db"
14+
code = await run_agent.main([
15+
"review", "--fixture", "security_eval", "--runtime", "local", "--dry-run",
16+
"--db-url", db_url, "--output-dir", str(tmp_path / "out")])
17+
assert code == 0
18+
out = capsys.readouterr().out
19+
assert "task_id=" in out
20+
task_id = out.split("task_id=")[1].split()[0].strip()
21+
22+
code = await run_agent.main(["show", "--task-id", task_id, "--db-url", db_url])
23+
assert code == 0
24+
bundle = json.loads(capsys.readouterr().out)
25+
assert bundle["task"]["id"] == task_id
26+
assert bundle["findings"]
27+
28+
29+
async def test_cli_show_unknown_task(tmp_path, capsys):
30+
db_url = f"sqlite:///{tmp_path}/cr.db"
31+
code = await run_agent.main(["show", "--task-id", "missing", "--db-url", db_url])
32+
assert code == 1
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Tencent is pleased to support the open source community by making tRPC-Agent-Python available.
2+
#
3+
# Copyright (C) 2026 Tencent. All rights reserved.
4+
#
5+
# tRPC-Agent-Python is licensed under Apache-2.0.
6+
"""Opt-in container-runtime e2e test. Enable with CR_CONTAINER_TESTS=1."""
7+
import os
8+
import shutil
9+
from pathlib import Path
10+
11+
import pytest
12+
13+
from review.pipeline import ReviewOptions, run_review
14+
15+
EXAMPLE_ROOT = Path(__file__).resolve().parents[1]
16+
17+
pytestmark = pytest.mark.skipif(
18+
not (shutil.which("docker") and os.getenv("CR_CONTAINER_TESTS") == "1"),
19+
reason="docker not available or CR_CONTAINER_TESTS != 1")
20+
21+
22+
async def test_container_review_security_fixture(tmp_path):
23+
result = await run_review(ReviewOptions(
24+
diff_text=(EXAMPLE_ROOT / "fixtures" / "security_eval.diff").read_text(),
25+
input_type="fixture", input_ref="security_eval.diff",
26+
runtime="container", dry_run=True,
27+
db_url=f"sqlite:///{tmp_path}/cr.db",
28+
output_dir=str(tmp_path / "out")))
29+
assert result.report["conclusion"] == "blocked"
30+
assert any(f["category"] == "security" for f in result.report["findings"])

0 commit comments

Comments
 (0)