Compare commits

..

14 Commits

Author SHA1 Message Date
b7172df700 Remove most pics from repo 2023-07-17 16:52:23 +03:00
768bd40ad8 Remove most pics from repo 2023-07-17 16:50:27 +03:00
fa421fd169 Merge pull request #75 from Codium-ai/bugfix/rename_get_description
get_description was removed
2023-07-17 10:32:01 +03:00
e0ae5c945e get_description was removed 2023-07-17 10:30:44 +03:00
865888e4e8 Merge pull request #74 from Codium-ai/update-gifs
Update GIFs
2023-07-17 09:35:06 +03:00
3b7cfe7bc5 Merge pull request #73 from Codium-ai/hl/clean_comments
Clean comments
2023-07-17 09:33:49 +03:00
262f9dddbc Merge pull request #72 from Codium-ai/tr/minor_fixes
Minor fixes
2023-07-17 09:33:18 +03:00
fa706b6e96 update gifs 2023-07-17 09:30:45 +03:00
ff51ab0946 Add files via upload 2023-07-17 09:27:41 +03:00
7884aa2348 Clean 2023-07-17 09:25:38 +03:00
8f3520807c minor fixes
minor fixes
2023-07-17 08:42:18 +03:00
2dfd34bd61 Merge pull request #71 from Codium-ai/Minor-spelling-fix
Minor Spelling Fix
2023-07-17 08:08:45 +03:00
48f569bef0 Update README.md 2023-07-17 02:39:58 +03:00
a20fb9cc0c Merge pull request #70 from Codium-ai/hl/gitlab_code_suggestion
GitLab Code Suggestions Integration
2023-07-17 02:11:30 +03:00
26 changed files with 71 additions and 66 deletions

View File

@ -1,2 +1,3 @@
venv/
pr_agent/settings/.secrets.toml
pics/

View File

@ -39,4 +39,4 @@ We use [tiktoken](https://github.com/openai/tiktoken) to tokenize the patches af
4. If we haven't reached the max token length, add the `deleted files` to the prompt until the prompt reaches the max token length (hard stop), skip the rest of the patches.
### Example
![](./pics/git_patch_logic.png)
![](https://codium.ai/images/git_patch_logic.png)

View File

@ -27,25 +27,25 @@ CodiumAI `PR-Agent` is an open-source tool aiming to help developers review PRs
<h4>Describe:</h4>
<div align="center">
<p float="center">
<img src="./pics/describe.gif" width="800">
<img src="https://codium.ai/images/describe.gif" width="800">
</p>
</div>
<h4>Review:</h4>
<div align="center">
<p float="center">
<img src="./pics/review.gif" width="800">
<img src="https://codium.ai/images/review.gif" width="800">
</p>
</div>
<h4>Ask:</h4>
<div align="center">
<p float="center">
<img src="./pics/ask.gif" width="800">
<img src="https://codium.ai/images/ask.gif" width="800">
</p>
</div>
<h4>Improve:</h4>
<div align="center">
<p float="center">
<img src="./pics/improve.gif" width="800">
<img src="https://codium.ai/images/improve.gif" width="800">
</p>
</div>
<div align="left">
@ -64,28 +64,28 @@ CodiumAI `PR-Agent` is an open-source tool aiming to help developers review PRs
Experience GPT-4 powered PR review on your public GitHub repository with our hosted PR-Agent. To try it, just mention `@CodiumAI-Agent` and add the desired command in any PR comment! The agent will generate a response based on your command.
![Review generation process](./pics/demo.gif)
![Review generation process](https://codium.ai/images/demo.gif)
To set up your own PR-Agent, see the [Quickstart](#Quickstart) section
---
## Overview
`PR-Agent` offers extensive pull request functionalities across various git providers:
| | | Github | Gitlab | Bitbucket |
|-------|---------------------------------------------|--------|--------|-----------|
| TOOLS | Review | | | |
| | ⮑ Inline review | | | |
| | Ask | | | |
| | Auto-Description | | | |
| | Improve Code | | | |
| | | GitHub | Gitlab | Bitbucket |
|-------|---------------------------------------------|:------:|:------:|:---------:|
| TOOLS | Review | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| | ⮑ Inline review | :white_check_mark: | :white_check_mark: | |
| | Ask | :white_check_mark: | :white_check_mark: | |
| | Auto-Description | :white_check_mark: | | |
| | Improve Code | :white_check_mark: | :white_check_mark: | |
| | | | | |
| USAGE | CLI | | | |
| | Tagging bot | | | |
| | Actions | | | |
| USAGE | CLI | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| | Tagging bot | :white_check_mark: | :white_check_mark: | |
| | Actions | :white_check_mark: | | |
| | | | | |
| CORE | PR compression | | | |
| | Repo language prioritization | | | |
| | Adaptive and token-aware<br />file patch fitting | | | |
| CORE | PR compression | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| | Repo language prioritization | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| | Adaptive and token-aware<br />file patch fitting | :white_check_mark: | :white_check_mark: | :white_check_mark: |
Examples for invoking the different tools via the [CLI](#quickstart):
- **Review**: python cli.py --pr-url=<pr_url> review
@ -95,7 +95,7 @@ Examples for invoking the different tools via the [CLI](#quickstart):
"<pr_url>" is the url of the relevant PR (for example: https://github.com/Codium-ai/pr-agent/pull/50).
In the [configuration](./CONFIGURATION.md) file you can select your git provider (Github, Gitlab, Bitbucket), and further configure the different tools.
In the [configuration](./CONFIGURATION.md) file you can select your git provider (GitHub, Gitlab, Bitbucket), and further configure the different tools.
## Quickstart
@ -111,25 +111,25 @@ There are several ways to use PR-Agent. Let's start with the simplest one:
Here are several ways to install and run PR-Agent:
- [Method 1: Use Docker image (no installation required)](INSTALL.md#method-1-use-docker-image-no-installation-required)
- [Method 2: Run as a Github Action](INSTALL.md#method-2-run-as-a-github-action)
- [Method 2: Run as a GitHub Action](INSTALL.md#method-2-run-as-a-github-action)
- [Method 3: Run from source](INSTALL.md#method-3-run-from-source)
- [Method 4: Run as a polling server](INSTALL.md#method-4-run-as-a-polling-server)
- Request reviews by tagging your Github user on a PR
- [Method 5: Run as a Github App](INSTALL.md#method-5-run-as-a-github-app)
- Request reviews by tagging your GitHub user on a PR
- [Method 5: Run as a GitHub App](INSTALL.md#method-5-run-as-a-github-app)
- Allowing you to automate the review process on your private or public repositories
## Usage and Tools
**PR-Agent** provides four types of interactions ("tools"): `"PR Reviewer"`, `"PR Q&A"`, `"PR Description"` and `"PR Code Sueggestions"`.
- The "PR Reviewer" tool automatically analyzes PRs, and provides different types of feedback.
- The "PR Ask" tool answers free-text questions about the PR.
- The "PR Reviewer" tool automatically analyzes PRs, and provides various types of feedback.
- The "PR Q&A" tool answers free-text questions about the PR.
- The "PR Description" tool automatically sets the PR Title and body.
- The "PR Code Suggestion" tool provide inline code suggestions for the PR that can be applied and committed.
## How it works
![PR-Agent Tools](./pics/pr_agent_overview.png)
![PR-Agent Tools](https://codium.ai/images/pr_agent_overview.png)
Check out the [PR Compression strategy](./PR_COMPRESSION.md) page for more details on how we convert a code diff to a manageable LLM prompt

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 335 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 MiB

View File

@ -14,10 +14,10 @@ def run():
parser = argparse.ArgumentParser(description='AI based pull request analyzer', usage="""\
Usage: cli.py --pr-url <URL on supported git hosting service> <command> [<args>].
For example:
- cli.py --pr-url xxx review
- cli.py --pr-url xxx describe
- cli.py --pr-url xxx improve
- cli.py --pr-url xxx ask "write me a poem about this PR"
- cli.py --pr-url=... review
- cli.py --pr-url=... describe
- cli.py --pr-url=... improve
- cli.py --pr-url=... ask "write me a poem about this PR"
Supported commands:
review / review_pr - Add a review that includes a summary of the PR and specific suggestions for improvement.

View File

@ -123,26 +123,11 @@ class GitLabProvider(GitProvider):
range = relevant_lines_end - relevant_lines_start + 1
body = body.replace('```suggestion', f'```suggestion:-0+{range}')
d = self.last_diff
#
# 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}
lines = target_file.head_file.splitlines()
relevant_line_in_file = lines[relevant_lines_start - 1]
edit_type, found, source_line_no, target_file, target_line_no = self.find_in_file(target_file, relevant_line_in_file)
self.send_inline_comment(body, edit_type, found, relevant_file, relevant_line_in_file, source_line_no,
target_file, target_line_no)
# if lines[relevant_lines_start][0] == '-':
# pos_obj['old_line'] = relevant_lines_start
# elif lines[relevant_lines_start][0] == '+':
# pos_obj['new_line'] = relevant_lines_start
# else:
# pos_obj['new_line'] = relevant_lines_start
# pos_obj['old_line'] = relevant_lines_start
# self.mr.discussions.create({'body': body,
# 'position': pos_obj})
def search_line(self, relevant_file, relevant_line_in_file):
target_file = None

View File

@ -1,8 +1,8 @@
[config]
model="gpt-4-0613"
git_provider="github"
publish_review=true
verbosity_level=2 # 0,1,2
publish_output=true
verbosity_level=0 # 0,1,2
[pr_reviewer]
require_focused_review=true
@ -11,6 +11,9 @@ require_security_review=true
num_code_suggestions=3
inline_code_comments = true
[pr_description]
publish_description_as_comment=false
[pr_questions]
[pr_code_suggestions]

View File

@ -2,8 +2,11 @@
system="""You are CodiumAI-PR-Reviewer, a language model designed to review git pull requests.
Your task is to provide constructive and concise feedback for the PR, and also provide meaningfull code suggestions to improve the new PR code (the '+' lines).
- Provide up to {{ num_code_suggestions }} code suggestions.
{%- if num_code_suggestions > 0 %}
- Try to focus on important suggestions like fixing code problems, issues and bugs. As a second priority, provide suggestions for meaningfull code improvements, like performance, vulnerability, modularity, and best practices.
- Suggestions should focus on improving the new added code lines.
- Make sure not to provide suggestions repeating modifications already implemented in the new PR code (the '+' lines).
{%- endif %}
You must use the following JSON schema to format your answer:
```json
@ -35,6 +38,7 @@ You must use the following JSON schema to format your answer:
"type": "string",
"description": "General suggestions and feedback for the contributors and maintainers of this PR. May include important suggestions for the overall structure, primary purpose, best practices, critical bugs, and other aspects of the PR. Explain your suggestions."
},
{%- if num_code_suggestions > 0 %}
"Code suggestions": {
"type": "array",
"maxItems": {{ num_code_suggestions }},
@ -54,6 +58,7 @@ You must use the following JSON schema to format your answer:
}
}
},
{%- endif %}
{%- if require_security %}
"Security concerns": {
"type": "string",
@ -82,6 +87,7 @@ Example output:
"PR Feedback":
{
"General PR suggestions": "..., `xxx`...",
{%- if num_code_suggestions > 0 %}
"Code suggestions": [
{
"relevant file": "directory/xxx.py",
@ -90,6 +96,7 @@ Example output:
},
...
]
{%- endif %}
{%- if require_security %},
"Security concerns": "No, because ..."
{%- endif %}

View File

@ -42,7 +42,7 @@ class PRCodeSuggestions:
assert type(self.git_provider) != BitbucketProvider, "Bitbucket is not supported for now"
logging.info('Generating code suggestions for PR...')
if settings.config.publish_review:
if settings.config.publish_output:
self.git_provider.publish_comment("Preparing review...", is_temporary=True)
logging.info('Getting PR diff...')
@ -56,7 +56,7 @@ class PRCodeSuggestions:
self.prediction = await self._get_prediction()
logging.info('Preparing PR review...')
data = self._prepare_pr_code_suggestions()
if settings.config.publish_review:
if settings.config.publish_output:
logging.info('Pushing PR review...')
self.git_provider.remove_initial_comment()
logging.info('Pushing inline code comments...')

View File

@ -36,16 +36,19 @@ class PRDescription:
async def describe(self):
logging.info('Generating a PR description...')
if settings.config.publish_review:
if settings.config.publish_output:
self.git_provider.publish_comment("Preparing pr description...", is_temporary=True)
logging.info('Getting PR diff...')
self.patches_diff = get_pr_diff(self.git_provider, self.token_handler)
logging.info('Getting AI prediction...')
self.prediction = await self._get_prediction()
logging.info('Preparing answer...')
pr_title, pr_body = self._prepare_pr_answer()
if settings.config.publish_review:
pr_title, pr_body, markdown_text = self._prepare_pr_answer()
if settings.config.publish_output:
logging.info('Pushing answer...')
if settings.pr_description.publish_description_as_comment:
self.git_provider.publish_comment(markdown_text)
else:
self.git_provider.publish_description(pr_title, pr_body)
self.git_provider.remove_initial_comment()
return ""
@ -66,10 +69,11 @@ class PRDescription:
def _prepare_pr_answer(self):
data = json.loads(self.prediction)
markdown_text = ""
for key, value in data.items():
markdown_text += f"## {key}\n\n"
markdown_text += f"{value}\n\n"
pr_body = ""
# for key, value in data.items():
# markdown_text += f"## {key}\n\n"
# markdown_text += f"{value}\n\n"
title = data['PR Title']
del data['PR Title']
for key, value in data.items():
@ -80,4 +84,4 @@ class PRDescription:
pr_body += f"**{value}**\n\n___\n"
if settings.config.verbosity_level >= 2:
logging.info(f"title:\n{title}\n{pr_body}")
return title, pr_body
return title, pr_body, markdown_text

View File

@ -21,7 +21,7 @@ class PRInformationFromUser:
self.vars = {
"title": self.git_provider.pr.title,
"branch": self.git_provider.get_pr_branch(),
"description": self.git_provider.get_description(),
"description": self.git_provider.get_pr_description(),
"language": self.main_pr_language,
"diff": "", # empty diff for initial calculation
}
@ -34,7 +34,7 @@ class PRInformationFromUser:
async def generate_questions(self):
logging.info('Generating question to the user...')
if settings.config.publish_review:
if settings.config.publish_output:
self.git_provider.publish_comment("Preparing answer...", is_temporary=True)
logging.info('Getting PR diff...')
self.patches_diff = get_pr_diff(self.git_provider, self.token_handler)
@ -42,7 +42,7 @@ class PRInformationFromUser:
self.prediction = await self._get_prediction()
logging.info('Preparing questions...')
pr_comment = self._prepare_pr_answer()
if settings.config.publish_review:
if settings.config.publish_output:
logging.info('Pushing questions...')
self.git_provider.publish_comment(pr_comment)
self.git_provider.remove_initial_comment()

View File

@ -36,7 +36,7 @@ class PRQuestions:
async def answer(self):
logging.info('Answering a PR question...')
if settings.config.publish_review:
if settings.config.publish_output:
self.git_provider.publish_comment("Preparing answer...", is_temporary=True)
logging.info('Getting PR diff...')
self.patches_diff = get_pr_diff(self.git_provider, self.token_handler)
@ -44,7 +44,7 @@ class PRQuestions:
self.prediction = await self._get_prediction()
logging.info('Preparing answer...')
pr_comment = self._prepare_pr_answer()
if settings.config.publish_review:
if settings.config.publish_output:
logging.info('Pushing answer...')
self.git_provider.publish_comment(pr_comment)
self.git_provider.remove_initial_comment()

View File

@ -43,7 +43,7 @@ class PRReviewer:
async def review(self):
logging.info('Reviewing PR...')
if settings.config.publish_review:
if settings.config.publish_output:
self.git_provider.publish_comment("Preparing review...", is_temporary=True)
logging.info('Getting PR diff...')
self.patches_diff = get_pr_diff(self.git_provider, self.token_handler)
@ -51,7 +51,7 @@ class PRReviewer:
self.prediction = await self._get_prediction()
logging.info('Preparing PR review...')
pr_comment = self._prepare_pr_review()
if settings.config.publish_review:
if settings.config.publish_output:
logging.info('Pushing PR review...')
self.git_provider.publish_comment(pr_comment)
self.git_provider.remove_initial_comment()
@ -89,7 +89,9 @@ class PRReviewer:
del data['PR Feedback']['Security concerns']
data['PR Analysis']['Security concerns'] = val
if settings.config.git_provider == 'github' and settings.pr_reviewer.inline_code_comments:
if settings.config.git_provider == 'github' and \
settings.pr_reviewer.inline_code_comments and \
'Code suggestions' in data['PR Feedback']:
del data['PR Feedback']['Code suggestions']
markdown_text = convert_to_markdown(data)
@ -107,6 +109,9 @@ class PRReviewer:
return markdown_text
def _publish_inline_code_comments(self):
if settings.pr_reviewer.num_code_suggestions == 0:
return
review = self.prediction.strip()
try:
data = json.loads(review)