Compare commits

..

7 Commits

Author SHA1 Message Date
9770f4709a few more changes suggested by AI implemented 2023-08-19 16:26:15 +03:00
35afe758e9 revert back conf 2023-08-19 16:16:16 +03:00
50125ae57f various changes as outcomes from AI review 2023-08-19 16:12:48 +03:00
6595c3e0c9 2 more /improve good suggestions 2023-08-19 15:47:45 +03:00
fdd16f6c75 raize exception when no diffs in MR 2023-08-19 15:40:40 +03:00
7b7e913195 to changes suggested by /improve with my small touch 2023-08-19 15:31:02 +03:00
5477469a91 in order to have exact sha's we have to find correct diff for this change
otherwise gitlab web doesn't able show diff on page and return 500 or 400 errors based on different scenarios
2023-08-19 15:06:22 +03:00
8 changed files with 38 additions and 60 deletions

View File

@ -18,18 +18,6 @@ docker run --rm -it -e OPENAI.KEY=<your key> -e GITHUB.USER_TOKEN=<your token> c
```
docker run --rm -it -e OPENAI.KEY=<your key> -e GITHUB.USER_TOKEN=<your token> codiumai/pr-agent --pr_url <pr_url> ask "<your question>"
```
Note: If you want to ensure you're running a specific version of the Docker image, consider using the image's digest.
The digest is a unique identifier for a specific version of an image. You can pull and run an image using its digest by referencing it like so: repository@sha256:digest. Always ensure you're using the correct and trusted digest for your operations.
1. To request a review for a PR using a specific digest, run the following command:
```bash
docker run --rm -it -e OPENAI.KEY=<your key> -e GITHUB.USER_TOKEN=<your token> codiumai/pr-agent@sha256:71b5ee15df59c745d352d84752d01561ba64b6d51327f97d46152f0c58a5f678 --pr_url <pr_url> review
```
2. To ask a question about a PR using the same digest, run the following command:
```bash
docker run --rm -it -e OPENAI.KEY=<your key> -e GITHUB.USER_TOKEN=<your token> codiumai/pr-agent@sha256:71b5ee15df59c745d352d84752d01561ba64b6d51327f97d46152f0c58a5f678 --pr_url <pr_url> ask "<your question>"
```
Possible questions you can ask include:
@ -63,24 +51,7 @@ jobs:
OPENAI_KEY: ${{ secrets.OPENAI_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
** if you want to pin your action to a specific commit for stability reasons
```yaml
on:
pull_request:
issue_comment:
jobs:
pr_agent_job:
runs-on: ubuntu-latest
name: Run pr agent on every pull request, respond to user comments
steps:
- name: PR Agent action step
id: pragent
uses: Codium-ai/pr-agent@<commit_sha>
env:
OPENAI_KEY: ${{ secrets.OPENAI_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
2. Add the following secret to your repository under `Settings > Secrets`:
```

View File

@ -15,7 +15,6 @@ from pr_agent.tools.pr_update_changelog import PRUpdateChangelog
from pr_agent.tools.pr_config import PRConfig
command2class = {
"auto_review": PRReviewer,
"answer": PRReviewer,
"review": PRReviewer,
"review_pr": PRReviewer,
@ -71,8 +70,6 @@ class PRAgent:
if notify:
notify()
await PRReviewer(pr_url, is_answer=True, args=args).run()
elif action == "auto_review":
await PRReviewer(pr_url, is_auto=True, args=args).run()
elif action in command2class:
if notify:
notify()

View File

@ -245,12 +245,14 @@ def update_settings_from_args(args: List[str]) -> List[str]:
arg = arg.strip()
if arg.startswith('--'):
arg = arg.strip('-').strip()
vals = arg.split('=', 1)
vals = arg.split('=')
if len(vals) != 2:
logging.error(f'Invalid argument format: {arg}')
other_args.append(arg)
continue
key, value = _fix_key_value(*vals)
key, value = vals
key = key.strip().upper()
value = value.strip()
get_settings().set(key, value)
logging.info(f'Updated setting {key} to: "{value}"')
else:
@ -258,16 +260,6 @@ def update_settings_from_args(args: List[str]) -> List[str]:
return other_args
def _fix_key_value(key: str, value: str):
key = key.strip().upper()
value = value.strip()
try:
value = yaml.safe_load(value)
except Exception as e:
logging.error(f"Failed to parse YAML for config override {key}={value}", exc_info=e)
return key, value
def load_yaml(review_text: str) -> dict:
review_text = review_text.removeprefix('```yaml').rstrip('`')
try:

View File

@ -14,6 +14,9 @@ from .git_provider import EDIT_TYPE, FilePatchInfo, GitProvider
logger = logging.getLogger()
class DiffNotFoundError(Exception):
"""Raised when the diff for a merge request cannot be found."""
pass
class GitLabProvider(GitProvider):
@ -56,7 +59,7 @@ class GitLabProvider(GitProvider):
self.last_diff = self.mr.diffs.list(get_all=True)[-1]
except IndexError as e:
logger.error(f"Could not get diff for merge request {self.id_mr}")
raise ValueError(f"Could not get diff for merge request {self.id_mr}") from e
raise DiffNotFoundError(f"Could not get diff for merge request {self.id_mr}") from e
def _get_pr_file_content(self, file_path: str, branch: str) -> str:
@ -150,16 +153,20 @@ class GitLabProvider(GitProvider):
def create_inline_comments(self, comments: list[dict]):
raise NotImplementedError("Gitlab provider does not support publishing inline comments yet")
def send_inline_comment(self, body, edit_type, found, relevant_file, relevant_line_in_file, source_line_no,
target_file, target_line_no):
def send_inline_comment(self,body: str,edit_type: str,found: bool,relevant_file: str,relevant_line_in_file: int,
source_line_no: int, target_file: str,target_line_no: int) -> None:
if not found:
logging.info(f"Could not find position for {relevant_file} {relevant_line_in_file}")
else:
d = self.last_diff
# in order to have exact sha's we have to find correct diff for this change
diff = self.get_relevant_diff(relevant_file, relevant_line_in_file)
if diff is None:
logger.error(f"Could not get diff for merge request {self.id_mr}")
raise DiffNotFoundError(f"Could not get diff for merge request {self.id_mr}")
pos_obj = {'position_type': 'text',
'new_path': target_file.filename,
'old_path': target_file.old_filename if target_file.old_filename else target_file.filename,
'base_sha': d.base_commit_sha, 'start_sha': d.start_commit_sha, 'head_sha': d.head_commit_sha}
'base_sha': diff.base_commit_sha, 'start_sha': diff.start_commit_sha, 'head_sha': diff.head_commit_sha}
if edit_type == 'deletion':
pos_obj['old_line'] = source_line_no - 1
elif edit_type == 'addition':
@ -171,6 +178,23 @@ class GitLabProvider(GitProvider):
self.mr.discussions.create({'body': body,
'position': pos_obj})
def get_relevant_diff(self, relevant_file: str, relevant_line_in_file: int) -> Optional[dict]:
changes = self.mr.changes() # Retrieve the changes for the merge request once
if not changes:
logging.error('No changes found for the merge request.')
return None
all_diffs = self.mr.diffs.list(get_all=True)
if not all_diffs:
logging.error('No diffs found for the merge request.')
return None
for diff in all_diffs:
for change in changes['changes']:
if change['new_path'] == relevant_file and relevant_line_in_file in change['diff']:
return diff
logging.debug(
f'No relevant diff found for {relevant_file} {relevant_line_in_file}. Falling back to last diff.')
return self.last_diff # fallback to last_diff if no relevant diff is found
def publish_code_suggestions(self, code_suggestions: list):
for suggestion in code_suggestions:
try:

View File

@ -93,7 +93,7 @@ async def handle_request(body: Dict[str, Any]):
api_url = pull_request.get("url")
if not api_url:
return {}
await agent.handle_request(api_url, "/auto_review")
await agent.handle_request(api_url, "/review")
return {}

View File

@ -19,7 +19,6 @@ require_security_review=true
num_code_suggestions=3
inline_code_comments = false
ask_and_reflect=false
automatic_review=true
extra_instructions = ""
[pr_description] # /describe #

View File

@ -23,7 +23,7 @@ class PRReviewer:
"""
The PRReviewer class is responsible for reviewing a pull request and generating feedback using an AI model.
"""
def __init__(self, pr_url: str, is_answer: bool = False, is_auto: bool = False, args: list = None):
def __init__(self, pr_url: str, is_answer: bool = False, args: list = None):
"""
Initialize the PRReviewer object with the necessary attributes and objects to review a pull request.
@ -40,7 +40,6 @@ class PRReviewer:
)
self.pr_url = pr_url
self.is_answer = is_answer
self.is_auto = is_auto
if self.is_answer and not self.git_provider.is_supported("get_issue_comments"):
raise Exception(f"Answer mode is not supported for {get_settings().config.git_provider} for now")
@ -94,12 +93,8 @@ class PRReviewer:
"""
Review the pull request and generate feedback.
"""
if self.is_auto and not get_settings().pr_reviewer.automatic_review:
logging.info(f'Automatic review is disabled {self.pr_url}')
return None
logging.info(f'Reviewing PR: {self.pr_url} ...')
logging.info('Reviewing PR...')
if get_settings().config.publish_output:
self.git_provider.publish_comment("Preparing review...", is_temporary=True)

View File

@ -14,4 +14,4 @@ GitPython~=3.1.32
litellm~=0.1.351
PyYAML==6.0
starlette-context==0.3.6
litellm~=0.1.351
litellm~=0.1.351