add support for local file cr

This commit is contained in:
shenchucheng 2024-08-20 20:22:12 +08:00
parent f513e7925d
commit 13f0e6b3dd
2 changed files with 52 additions and 23 deletions

View file

@ -4,7 +4,9 @@
import json
import re
from pathlib import Path
import aiofiles
from unidiff import PatchSet
from metagpt.actions.action import Action
@ -16,6 +18,7 @@ from metagpt.ext.cr.utils.cleaner import (
from metagpt.ext.cr.utils.schema import Point
from metagpt.logs import logger
from metagpt.utils.common import parse_json_code_block
from metagpt.utils.report import EditorReporter
CODE_REVIEW_PROMPT_TEMPLATE = """
NOTICE
@ -193,16 +196,26 @@ class CodeReview(Action):
patched_file_path = patched_file.path
for c in comments_batch:
c["commented_file"] = patched_file_path
comments += comments_batch
comments.extend(comments_batch)
return comments
async def run(self, patch: PatchSet, points: list[Point]):
async def run(self, patch: PatchSet, points: list[Point], output_file: str):
patch: PatchSet = rm_patch_useless_part(patch)
patch: PatchSet = add_line_num_on_patch(patch)
result = []
comments = await self.cr_by_points(patch=patch, points=points)
async with EditorReporter(enable_llm_stream=True) as reporter:
log_cr_output_path = Path(output_file).with_suffix(".log")
await reporter.async_report(
{"src_path": str(log_cr_output_path), "filename": log_cr_output_path.name}, "meta"
)
comments = await self.cr_by_points(patch=patch, points=points)
log_cr_output_path.parent.mkdir(exist_ok=True, parents=True)
async with aiofiles.open(log_cr_output_path, "w", encoding="utf-8") as f:
await f.write(json.dumps(comments, ensure_ascii=False, indent=2))
await reporter.async_report(log_cr_output_path)
if len(comments) != 0:
comments = self.format_comments(comments, points, patch)
comments = await self.confirm_comments(patch=patch, comments=comments, points=points)
@ -210,4 +223,14 @@ class CodeReview(Action):
if comment["code"]:
if not (comment["code"].isspace()):
result.append(comment)
async with EditorReporter() as reporter:
src_path = output_file
cr_output_path = Path(output_file)
await reporter.async_report(
{"type": "CodeReview", "src_path": src_path, "filename": cr_output_path.name}, "meta"
)
async with aiofiles.open(cr_output_path, "w", encoding="utf-8") as f:
await f.write(json.dumps(comments, ensure_ascii=False, indent=2))
await reporter.async_report(cr_output_path)
return result

View file

@ -1,3 +1,4 @@
import difflib
import json
from pathlib import Path
from typing import Optional
@ -22,35 +23,34 @@ class CodeReview:
async def review(
self,
patch_path: str,
cr_output_file: str,
cr_point_file: Optional[str] = None,
output_file: str,
point_file: Optional[str] = None,
) -> str:
"""Review a PR and save code review comments.
Notes:
If the user does not specify an output path, saved it using a relative path in the current working directory.
Args:
patch_path: The local path of the patch file or the url of the pull request. Example: "/data/xxx-pr-1.patch", "https://github.com/xx/XX/pull/1362"
cr_output_file: Output file path where code review comments will be saved. Example: "cr/xxx-pr-1.json"
cr_point_file: File path for specifying code review points. If not specified, this parameter is not passed..
patch_path: The local path of the patch file or the URL of the pull request.
output_file: Output file path where code review comments will be saved.
point_file: File path for specifying code review points. If not specified, this parameter does not need to be passed.
Examples:
>>> cr = CodeReview()
>>> await cr.review(patch_path="https://github.com/geekan/MetaGPT/pull/136", output_file="cr/MetaGPT_136.json")
>>> await cr.review(patch_path="/data/uploads/dev-master.diff", output_file="cr/dev-master.json")
>>> await cr.review(patch_path="/data/uploads/main.py", output_file="cr/main.json")
"""
patch = await self._get_patch_content(patch_path)
cr_point_file = cr_point_file if cr_point_file else Path(metagpt.ext.cr.__file__).parent / "points.json"
async with aiofiles.open(cr_point_file, "rb") as f:
point_file = point_file if point_file else Path(metagpt.ext.cr.__file__).parent / "points.json"
async with aiofiles.open(point_file, "rb") as f:
cr_point_content = await f.read()
cr_points = [Point(**i) for i in json.loads(cr_point_content)]
async with EditorReporter(enable_llm_stream=True) as reporter:
src_path = cr_output_file
cr_output_path = Path(cr_output_file)
await reporter.async_report(
{"type": "CodeReview", "src_path": src_path, "filename": cr_output_path.name}, "meta"
)
comments = await CodeReview_().run(patch, cr_points)
cr_output_path.parent.mkdir(exist_ok=True, parents=True)
async with aiofiles.open(cr_output_path, "w", encoding="utf-8") as f:
await f.write(json.dumps(comments, ensure_ascii=False))
await reporter.async_report(cr_output_path)
return f"The number of defects: {len(comments)} and the comments are stored in {cr_output_file}"
comments = await CodeReview_().run(patch, cr_points, output_file)
return f"The number of defects: {len(comments)} and the comments are stored in {output_file}"
async def fix(
self,
@ -88,6 +88,12 @@ class CodeReview:
async with aiofiles.open(patch_path, encoding="utf-8") as f:
patch_file_content = await f.read()
await EditorReporter().async_report(patch_path)
if not patch_path.endswith((".diff", "patch")):
name = Path(patch_path).name
patch_file_content = "".join(
difflib.unified_diff([], patch_file_content.splitlines(keepends=True), "/dev/null", f"b/{name}"),
)
patch_file_content = f"diff --git a/{name} b/{name}\n{patch_file_content}"
patch: PatchSet = PatchSet(patch_file_content)
return patch