mirror of
https://github.com/qodo-ai/pr-agent.git
synced 2025-07-08 23:00:43 +08:00
Merge commit 'e352c98ce83bfbd99078f62d8705eb938a6ba5b5' into hl/type_vs_labels
This commit is contained in:
32
INSTALL.md
32
INSTALL.md
@ -29,39 +29,43 @@ There are several ways to use PR-Agent:
|
|||||||
|
|
||||||
### Use Docker image (no installation required)
|
### Use Docker image (no installation required)
|
||||||
|
|
||||||
To request a review for a PR, or ask a question about a PR, you can run directly from the Docker image. Here's how:
|
A list of the relevant tools can be found in the [tools guide](./docs/TOOLS_GUIDE.md).
|
||||||
|
|
||||||
For GitHub:
|
To invoke a tool (for example `review`), you can run directly from the Docker image. Here's how:
|
||||||
|
|
||||||
|
- For GitHub:
|
||||||
```
|
```
|
||||||
docker run --rm -it -e OPENAI.KEY=<your key> -e GITHUB.USER_TOKEN=<your token> codiumai/pr-agent:latest --pr_url <pr_url> review
|
docker run --rm -it -e OPENAI.KEY=<your key> -e GITHUB.USER_TOKEN=<your token> codiumai/pr-agent:latest --pr_url <pr_url> review
|
||||||
```
|
```
|
||||||
For GitLab:
|
|
||||||
|
- For GitLab:
|
||||||
```
|
```
|
||||||
docker run --rm -it -e OPENAI.KEY=<your key> -e CONFIG.GIT_PROVIDER=gitlab -e GITLAB.PERSONAL_ACCESS_TOKEN=<your token> codiumai/pr-agent:latest --pr_url <pr_url> review
|
docker run --rm -it -e OPENAI.KEY=<your key> -e CONFIG.GIT_PROVIDER=gitlab -e GITLAB.PERSONAL_ACCESS_TOKEN=<your token> codiumai/pr-agent:latest --pr_url <pr_url> review
|
||||||
```
|
```
|
||||||
For BitBucket:
|
|
||||||
|
Note: If you have a dedicated GitLab instance, you need to specify the custom url as variable:
|
||||||
|
```
|
||||||
|
docker run --rm -it -e OPENAI.KEY=<your key> -e CONFIG.GIT_PROVIDER=gitlab -e GITLAB.PERSONAL_ACCESS_TOKEN=<your token> GITLAB.URL=<your gitlab instance url> codiumai/pr-agent:latest --pr_url <pr_url> review
|
||||||
|
```
|
||||||
|
|
||||||
|
- For BitBucket:
|
||||||
```
|
```
|
||||||
docker run --rm -it -e CONFIG.GIT_PROVIDER=bitbucket -e OPENAI.KEY=$OPENAI_API_KEY -e BITBUCKET.BEARER_TOKEN=$BITBUCKET_BEARER_TOKEN codiumai/pr-agent:latest --pr_url=<pr_url> review
|
docker run --rm -it -e CONFIG.GIT_PROVIDER=bitbucket -e OPENAI.KEY=$OPENAI_API_KEY -e BITBUCKET.BEARER_TOKEN=$BITBUCKET_BEARER_TOKEN codiumai/pr-agent:latest --pr_url=<pr_url> review
|
||||||
```
|
```
|
||||||
|
|
||||||
For other git providers, update CONFIG.GIT_PROVIDER accordingly, and check the `pr_agent/settings/.secrets_template.toml` file for the environment variables expected names and values.
|
For other git providers, update CONFIG.GIT_PROVIDER accordingly, and check the `pr_agent/settings/.secrets_template.toml` file for the environment variables expected names and values.
|
||||||
|
|
||||||
|
---
|
||||||
Similarly, to ask a question about a PR, run the following command:
|
|
||||||
```
|
|
||||||
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>"
|
|
||||||
```
|
|
||||||
|
|
||||||
A list of the relevant tools can be found in the [tools guide](./docs/TOOLS_GUIDE.md).
|
|
||||||
|
|
||||||
|
|
||||||
Note: If you want to ensure you're running a specific version of the Docker image, consider using the image's digest:
|
If you want to ensure you're running a specific version of the Docker image, consider using the image's digest:
|
||||||
```bash
|
```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
|
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
|
||||||
```
|
```
|
||||||
in addition, you can run a [specific released versions](./RELEASE_NOTES.md) of pr-agent, for example:
|
|
||||||
|
Or you can run a [specific released versions](./RELEASE_NOTES.md) of pr-agent, for example:
|
||||||
```
|
```
|
||||||
codiumai/pr-agent@v0.8
|
codiumai/pr-agent@v0.9
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -29,12 +29,26 @@ Under the section 'pr_reviewer', the [configuration file](./../pr_agent/settings
|
|||||||
#### Incremental Mode
|
#### Incremental Mode
|
||||||
For an incremental review, which only considers changes since the last PR-Agent review, this can be useful when working on the PR in an iterative manner, and you want to focus on the changes since the last review instead of reviewing the entire PR again, the following command can be used:
|
For an incremental review, which only considers changes since the last PR-Agent review, this can be useful when working on the PR in an iterative manner, and you want to focus on the changes since the last review instead of reviewing the entire PR again, the following command can be used:
|
||||||
```
|
```
|
||||||
/improve -i
|
/review -i
|
||||||
```
|
```
|
||||||
Note that the incremental mode is only available for GitHub.
|
Note that the incremental mode is only available for GitHub.
|
||||||
|
|
||||||
<kbd><img src=./../pics/incremental_review.png width="768"></kbd>
|
<kbd><img src=./../pics/incremental_review.png width="768"></kbd>
|
||||||
|
|
||||||
|
Under the section 'pr_reviewer', the [configuration file](./../pr_agent/settings/configuration.toml#L16) contains options to customize the 'review -i' tool.
|
||||||
|
These configurations can be used to control the rate at which the incremental review tool will create new review comments when invoked automatically, to prevent making too much noise in the PR.
|
||||||
|
- `minimal_commits_for_incremental_review`: Minimal number of commits since the last review that are required to create incremental review.
|
||||||
|
If there are less than the specified number of commits since the last review, the tool will not perform any action.
|
||||||
|
Default is 0 - the tool will always run, no matter how many commits since the last review.
|
||||||
|
- `minimal_minutes_for_incremental_review`: Minimal number of minutes that need to pass since the last reviewed commit to create incremental review.
|
||||||
|
If less that the specified number of minutes have passed between the last reviewed commit and running this command, the tool will not perform any action.
|
||||||
|
Default is 0 - the tool will always run, no matter how much time have passed since the last reviewed commit.
|
||||||
|
- `require_all_thresholds_for_incremental_review`: If set to true, all the previous thresholds must be met for incremental review to run. If false, only one is enough to run the tool.
|
||||||
|
For example, if `minimal_commits_for_incremental_review=2` and `minimal_minutes_for_incremental_review=2`, and we have 3 commits since the last review, but the last reviewed commit is from 1 minute ago:
|
||||||
|
When `require_all_thresholds_for_incremental_review=true` the incremental review __will not__ run, because only 1 out of 2 conditions were met (we have enough commits but the last review is too recent),
|
||||||
|
but when `require_all_thresholds_for_incremental_review=false` the incremental review __will__ run, because one condition is enough (we have 3 commits which is more than the configured 2).
|
||||||
|
Default is false - the tool will run as long as at least once conditions is met.
|
||||||
|
|
||||||
#### PR Reflection
|
#### PR Reflection
|
||||||
By invoking:
|
By invoking:
|
||||||
```
|
```
|
||||||
|
@ -32,8 +32,10 @@ class BitbucketProvider(GitProvider):
|
|||||||
self.repo = None
|
self.repo = None
|
||||||
self.pr_num = None
|
self.pr_num = None
|
||||||
self.pr = None
|
self.pr = None
|
||||||
|
self.pr_url = pr_url
|
||||||
self.temp_comments = []
|
self.temp_comments = []
|
||||||
self.incremental = incremental
|
self.incremental = incremental
|
||||||
|
self.diff_files = None
|
||||||
if pr_url:
|
if pr_url:
|
||||||
self.set_pr(pr_url)
|
self.set_pr(pr_url)
|
||||||
self.bitbucket_comment_api_url = self.pr._BitbucketBase__data["links"]["comments"]["href"]
|
self.bitbucket_comment_api_url = self.pr._BitbucketBase__data["links"]["comments"]["href"]
|
||||||
@ -44,6 +46,8 @@ class BitbucketProvider(GitProvider):
|
|||||||
url = (f"https://api.bitbucket.org/2.0/repositories/{self.workspace_slug}/{self.repo_slug}/src/"
|
url = (f"https://api.bitbucket.org/2.0/repositories/{self.workspace_slug}/{self.repo_slug}/src/"
|
||||||
f"{self.pr.destination_branch}/.pr_agent.toml")
|
f"{self.pr.destination_branch}/.pr_agent.toml")
|
||||||
response = requests.request("GET", url, headers=self.headers)
|
response = requests.request("GET", url, headers=self.headers)
|
||||||
|
if response.status_code == 404: # not found
|
||||||
|
return ""
|
||||||
contents = response.text.encode('utf-8')
|
contents = response.text.encode('utf-8')
|
||||||
return contents
|
return contents
|
||||||
except Exception:
|
except Exception:
|
||||||
@ -114,6 +118,9 @@ class BitbucketProvider(GitProvider):
|
|||||||
return [diff.new.path for diff in self.pr.diffstat()]
|
return [diff.new.path for diff in self.pr.diffstat()]
|
||||||
|
|
||||||
def get_diff_files(self) -> list[FilePatchInfo]:
|
def get_diff_files(self) -> list[FilePatchInfo]:
|
||||||
|
if self.diff_files:
|
||||||
|
return self.diff_files
|
||||||
|
|
||||||
diffs = self.pr.diffstat()
|
diffs = self.pr.diffstat()
|
||||||
diff_split = [
|
diff_split = [
|
||||||
"diff --git%s" % x for x in self.pr.diff().split("diff --git") if x.strip()
|
"diff --git%s" % x for x in self.pr.diff().split("diff --git") if x.strip()
|
||||||
@ -133,6 +140,7 @@ class BitbucketProvider(GitProvider):
|
|||||||
diff.new.path,
|
diff.new.path,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
self.diff_files = diff_files
|
||||||
return diff_files
|
return diff_files
|
||||||
|
|
||||||
def publish_comment(self, pr_comment: str, is_temporary: bool = False):
|
def publish_comment(self, pr_comment: str, is_temporary: bool = False):
|
||||||
@ -181,9 +189,29 @@ class BitbucketProvider(GitProvider):
|
|||||||
)
|
)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def generate_link_to_relevant_line_number(self, suggestion) -> str:
|
||||||
|
try:
|
||||||
|
relevant_file = suggestion['relevant file'].strip('`').strip("'")
|
||||||
|
relevant_line_str = suggestion['relevant line']
|
||||||
|
if not relevant_line_str:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
diff_files = self.get_diff_files()
|
||||||
|
position, absolute_position = find_line_number_of_relevant_line_in_file \
|
||||||
|
(diff_files, relevant_file, relevant_line_str)
|
||||||
|
|
||||||
|
if absolute_position != -1 and self.pr_url:
|
||||||
|
link = f"{self.pr_url}/#L{relevant_file}T{absolute_position}"
|
||||||
|
return link
|
||||||
|
except Exception as e:
|
||||||
|
if get_settings().config.verbosity_level >= 2:
|
||||||
|
get_logger().info(f"Failed adding line link, error: {e}")
|
||||||
|
|
||||||
|
return ""
|
||||||
|
|
||||||
def publish_inline_comments(self, comments: list[dict]):
|
def publish_inline_comments(self, comments: list[dict]):
|
||||||
for comment in comments:
|
for comment in comments:
|
||||||
self.publish_inline_comment(comment['body'], comment['start_line'], comment['path'])
|
self.publish_inline_comment(comment['body'], comment['position'], comment['path'])
|
||||||
|
|
||||||
def get_title(self):
|
def get_title(self):
|
||||||
return self.pr.title
|
return self.pr.title
|
||||||
|
@ -190,6 +190,13 @@ class IncrementalPR:
|
|||||||
def __init__(self, is_incremental: bool = False):
|
def __init__(self, is_incremental: bool = False):
|
||||||
self.is_incremental = is_incremental
|
self.is_incremental = is_incremental
|
||||||
self.commits_range = None
|
self.commits_range = None
|
||||||
self.first_new_commit_sha = None
|
self.first_new_commit = None
|
||||||
self.last_seen_commit_sha = None
|
self.last_seen_commit = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def first_new_commit_sha(self):
|
||||||
|
return None if self.first_new_commit is None else self.first_new_commit.sha
|
||||||
|
|
||||||
|
@property
|
||||||
|
def last_seen_commit_sha(self):
|
||||||
|
return None if self.last_seen_commit is None else self.last_seen_commit.sha
|
||||||
|
@ -66,10 +66,10 @@ class GithubProvider(GitProvider):
|
|||||||
first_new_commit_index = None
|
first_new_commit_index = None
|
||||||
for index in range(len(self.commits) - 1, -1, -1):
|
for index in range(len(self.commits) - 1, -1, -1):
|
||||||
if self.commits[index].commit.author.date > last_review_time:
|
if self.commits[index].commit.author.date > last_review_time:
|
||||||
self.incremental.first_new_commit_sha = self.commits[index].sha
|
self.incremental.first_new_commit = self.commits[index]
|
||||||
first_new_commit_index = index
|
first_new_commit_index = index
|
||||||
else:
|
else:
|
||||||
self.incremental.last_seen_commit_sha = self.commits[index].sha
|
self.incremental.last_seen_commit = self.commits[index]
|
||||||
break
|
break
|
||||||
return self.commits[first_new_commit_index:] if first_new_commit_index is not None else []
|
return self.commits[first_new_commit_index:] if first_new_commit_index is not None else []
|
||||||
|
|
||||||
|
@ -27,7 +27,8 @@ def apply_repo_settings(pr_url):
|
|||||||
get_settings().unset(section)
|
get_settings().unset(section)
|
||||||
get_settings().set(section, section_dict, merge=False)
|
get_settings().set(section, section_dict, merge=False)
|
||||||
get_logger().info(f"Applying repo settings for section {section}, contents: {contents}")
|
get_logger().info(f"Applying repo settings for section {section}, contents: {contents}")
|
||||||
|
except Exception as e:
|
||||||
|
get_logger().exception("Failed to apply repo settings", e)
|
||||||
finally:
|
finally:
|
||||||
if repo_settings_file:
|
if repo_settings_file:
|
||||||
try:
|
try:
|
||||||
|
@ -122,7 +122,7 @@ async def handle_request(body: Dict[str, Any], event: str):
|
|||||||
if body.get("requested_reviewer", {}).get("login", "") != bot_user:
|
if body.get("requested_reviewer", {}).get("login", "") != bot_user:
|
||||||
return {}
|
return {}
|
||||||
get_logger().info(f"Performing review for {api_url=} because of {event=} and {action=}")
|
get_logger().info(f"Performing review for {api_url=} because of {event=} and {action=}")
|
||||||
await _perform_commands(agent, body, api_url, log_context)
|
await _perform_commands("pr_commands", agent, body, api_url, log_context)
|
||||||
|
|
||||||
# handle pull_request event with synchronize action - "push trigger" for new commits
|
# handle pull_request event with synchronize action - "push trigger" for new commits
|
||||||
elif event == 'pull_request' and action == 'synchronize' and get_settings().github_app.handle_push_trigger:
|
elif event == 'pull_request' and action == 'synchronize' and get_settings().github_app.handle_push_trigger:
|
||||||
@ -174,7 +174,7 @@ async def handle_request(body: Dict[str, Any], event: str):
|
|||||||
get_logger().info(f"Skipping incremental review because there was no initial review for {api_url=} yet")
|
get_logger().info(f"Skipping incremental review because there was no initial review for {api_url=} yet")
|
||||||
return {}
|
return {}
|
||||||
get_logger().info(f"Performing incremental review for {api_url=} because of {event=} and {action=}")
|
get_logger().info(f"Performing incremental review for {api_url=} because of {event=} and {action=}")
|
||||||
await _perform_commands(agent, body, api_url, log_context)
|
await _perform_commands("push_commands", agent, body, api_url, log_context)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
# release the waiting task block
|
# release the waiting task block
|
||||||
@ -203,9 +203,9 @@ def _check_pull_request_event(action: str, body: dict, log_context: dict, bot_us
|
|||||||
return pull_request, api_url
|
return pull_request, api_url
|
||||||
|
|
||||||
|
|
||||||
async def _perform_commands(agent: PRAgent, body: dict, api_url: str, log_context: dict):
|
async def _perform_commands(commands_conf: str, agent: PRAgent, body: dict, api_url: str, log_context: dict):
|
||||||
apply_repo_settings(api_url)
|
apply_repo_settings(api_url)
|
||||||
commands = get_settings().github_app.pr_commands
|
commands = get_settings().get(f"github_app.{commands_conf}")
|
||||||
for command in commands:
|
for command in commands:
|
||||||
split_command = command.split(" ")
|
split_command = command.split(" ")
|
||||||
command = split_command[0]
|
command = split_command[0]
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from mangum import Mangum
|
from mangum import Mangum
|
||||||
|
from starlette.middleware import Middleware
|
||||||
|
from starlette_context.middleware import RawContextMiddleware
|
||||||
|
|
||||||
from pr_agent.log import setup_logger
|
from pr_agent.log import setup_logger
|
||||||
from pr_agent.servers.github_app import router
|
from pr_agent.servers.github_app import router
|
||||||
|
|
||||||
setup_logger()
|
setup_logger()
|
||||||
|
|
||||||
app = FastAPI()
|
middleware = [Middleware(RawContextMiddleware)]
|
||||||
|
app = FastAPI(middleware=middleware)
|
||||||
app.include_router(router)
|
app.include_router(router)
|
||||||
|
|
||||||
handler = Mangum(app, lifespan="off")
|
handler = Mangum(app, lifespan="off")
|
||||||
|
@ -26,6 +26,10 @@ ask_and_reflect=false
|
|||||||
automatic_review=true
|
automatic_review=true
|
||||||
remove_previous_review_comment=false
|
remove_previous_review_comment=false
|
||||||
extra_instructions = ""
|
extra_instructions = ""
|
||||||
|
# specific configurations for incremental review (/review -i)
|
||||||
|
require_all_thresholds_for_incremental_review=false
|
||||||
|
minimal_commits_for_incremental_review=0
|
||||||
|
minimal_minutes_for_incremental_review=0
|
||||||
|
|
||||||
[pr_description] # /describe #
|
[pr_description] # /describe #
|
||||||
publish_labels=true
|
publish_labels=true
|
||||||
@ -106,6 +110,9 @@ push_commands = [
|
|||||||
--pr_reviewer.num_code_suggestions=0 \
|
--pr_reviewer.num_code_suggestions=0 \
|
||||||
--pr_reviewer.inline_code_comments=false \
|
--pr_reviewer.inline_code_comments=false \
|
||||||
--pr_reviewer.remove_previous_review_comment=true \
|
--pr_reviewer.remove_previous_review_comment=true \
|
||||||
|
--pr_reviewer.require_all_thresholds_for_incremental_review=false \
|
||||||
|
--pr_reviewer.minimal_commits_for_incremental_review=5 \
|
||||||
|
--pr_reviewer.minimal_minutes_for_incremental_review=30 \
|
||||||
--pr_reviewer.extra_instructions='' \
|
--pr_reviewer.extra_instructions='' \
|
||||||
"""
|
"""
|
||||||
]
|
]
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
[pr_description_prompt]
|
[pr_description_prompt]
|
||||||
system="""You are CodiumAI-PR-Reviewer, a language model designed to review git pull requests.
|
system="""You are CodiumAI-PR-Reviewer, a language model designed to review git pull requests.
|
||||||
Your task is to provide full description of the PR content.
|
Your task is to provide full description of a Pull Request (PR) content.
|
||||||
- Make sure not to focus the new PR code (the '+' lines).
|
- Make sure to focus on the new PR code (the '+' lines).
|
||||||
- Notice that the 'Previous title', 'Previous description' and 'Commit messages' sections may be partial, simplistic, non-informative or not up-to-date. Hence, compare them to the PR diff code, and use them only as a reference.
|
- Notice that the 'Previous title', 'Previous description' and 'Commit messages' sections may be partial, simplistic, non-informative or not up-to-date. Hence, compare them to the PR diff code, and use them only as a reference.
|
||||||
- If needed, each YAML output should be in block scalar format ('|-')
|
- Emphasize first the most important changes, and then the less important ones.
|
||||||
|
- If needed, each YAML output should be in block scalar format ('|-')
|
||||||
{%- if extra_instructions %}
|
{%- if extra_instructions %}
|
||||||
|
|
||||||
Extra instructions from the user:
|
Extra instructions from the user:
|
||||||
@ -51,6 +52,7 @@ PR Main Files Walkthrough:
|
|||||||
changes in file:
|
changes in file:
|
||||||
type: string
|
type: string
|
||||||
description: minimal and concise description of the changes in the relevant file
|
description: minimal and concise description of the changes in the relevant file
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Example output:
|
Example output:
|
||||||
|
@ -257,7 +257,7 @@ class PRDescription:
|
|||||||
for file in value:
|
for file in value:
|
||||||
filename = file['filename'].replace("'", "`")
|
filename = file['filename'].replace("'", "`")
|
||||||
description = file['changes in file']
|
description = file['changes in file']
|
||||||
pr_body += f'`{filename}`: {description}\n'
|
pr_body += f'- `{filename}`: {description}\n'
|
||||||
if self.git_provider.is_supported("gfm_markdown"):
|
if self.git_provider.is_supported("gfm_markdown"):
|
||||||
pr_body +="</details>\n"
|
pr_body +="</details>\n"
|
||||||
else:
|
else:
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import copy
|
import copy
|
||||||
|
import datetime
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
|
|
||||||
@ -100,8 +101,7 @@ class PRReviewer:
|
|||||||
if self.is_auto and not get_settings().pr_reviewer.automatic_review:
|
if self.is_auto and not get_settings().pr_reviewer.automatic_review:
|
||||||
get_logger().info(f'Automatic review is disabled {self.pr_url}')
|
get_logger().info(f'Automatic review is disabled {self.pr_url}')
|
||||||
return None
|
return None
|
||||||
if self.is_auto and self.incremental.is_incremental and not self.incremental.first_new_commit_sha:
|
if self.incremental.is_incremental and not self._can_run_incremental_review():
|
||||||
get_logger().info(f"Incremental review is enabled for {self.pr_url} but there are no new commits")
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
get_logger().info(f'Reviewing PR: {self.pr_url} ...')
|
get_logger().info(f'Reviewing PR: {self.pr_url} ...')
|
||||||
@ -217,19 +217,6 @@ class PRReviewer:
|
|||||||
suggestion['relevant line'] = f"[{suggestion['relevant line']}]({link})"
|
suggestion['relevant line'] = f"[{suggestion['relevant line']}]({link})"
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
# try:
|
|
||||||
# relevant_file = suggestion['relevant file'].strip('`').strip("'")
|
|
||||||
# relevant_line_str = suggestion['relevant line']
|
|
||||||
# if not relevant_line_str:
|
|
||||||
# return ""
|
|
||||||
#
|
|
||||||
# position, absolute_position = find_line_number_of_relevant_line_in_file(
|
|
||||||
# self.git_provider.diff_files, relevant_file, relevant_line_str)
|
|
||||||
# if absolute_position != -1:
|
|
||||||
# suggestion[
|
|
||||||
# 'relevant line'] = f"{suggestion['relevant line']} (line {absolute_position})"
|
|
||||||
# except:
|
|
||||||
# pass
|
|
||||||
|
|
||||||
|
|
||||||
# Add incremental review section
|
# Add incremental review section
|
||||||
@ -347,3 +334,34 @@ class PRReviewer:
|
|||||||
self.git_provider.remove_comment(comment)
|
self.git_provider.remove_comment(comment)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
get_logger().exception(f"Failed to remove previous review comment, error: {e}")
|
get_logger().exception(f"Failed to remove previous review comment, error: {e}")
|
||||||
|
|
||||||
|
def _can_run_incremental_review(self) -> bool:
|
||||||
|
"""Checks if we can run incremental review according the various configurations and previous review"""
|
||||||
|
# checking if running is auto mode but there are no new commits
|
||||||
|
if self.is_auto and not self.incremental.first_new_commit_sha:
|
||||||
|
get_logger().info(f"Incremental review is enabled for {self.pr_url} but there are no new commits")
|
||||||
|
return False
|
||||||
|
# checking if there are enough commits to start the review
|
||||||
|
num_new_commits = len(self.incremental.commits_range)
|
||||||
|
num_commits_threshold = get_settings().pr_reviewer.minimal_commits_for_incremental_review
|
||||||
|
not_enough_commits = num_new_commits < num_commits_threshold
|
||||||
|
# checking if the commits are not too recent to start the review
|
||||||
|
recent_commits_threshold = datetime.datetime.now() - datetime.timedelta(
|
||||||
|
minutes=get_settings().pr_reviewer.minimal_minutes_for_incremental_review
|
||||||
|
)
|
||||||
|
last_seen_commit_date = (
|
||||||
|
self.incremental.last_seen_commit.commit.author.date if self.incremental.last_seen_commit else None
|
||||||
|
)
|
||||||
|
all_commits_too_recent = (
|
||||||
|
last_seen_commit_date > recent_commits_threshold if self.incremental.last_seen_commit else False
|
||||||
|
)
|
||||||
|
# check all the thresholds or just one to start the review
|
||||||
|
condition = any if get_settings().pr_reviewer.require_all_thresholds_for_incremental_review else all
|
||||||
|
if condition((not_enough_commits, all_commits_too_recent)):
|
||||||
|
get_logger().info(
|
||||||
|
f"Incremental review is enabled for {self.pr_url} but didn't pass the threshold check to run:"
|
||||||
|
f"\n* Number of new commits = {num_new_commits} (threshold is {num_commits_threshold})"
|
||||||
|
f"\n* Last seen commit date = {last_seen_commit_date} (threshold is {recent_commits_threshold})"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
Reference in New Issue
Block a user