mirror of
https://github.com/qodo-ai/pr-agent.git
synced 2025-07-04 12:50:38 +08:00
Merge pull request #1153 from Codium-ai/tr/protections2
Tr/protections2
This commit is contained in:
@ -130,18 +130,6 @@ class AzureDevopsProvider(GitProvider):
|
||||
def get_pr_description_full(self) -> str:
|
||||
return self.pr.description
|
||||
|
||||
def delete_comment(self, comment):
|
||||
try:
|
||||
self.azure_devops_client.delete_comment(
|
||||
repository_id=self.repo_slug,
|
||||
pull_request_id=self.pr_num,
|
||||
thread_id=comment.thread_id,
|
||||
comment_id=comment.id,
|
||||
project=self.workspace_slug,
|
||||
)
|
||||
except Exception as e:
|
||||
get_logger().exception(f"Failed to delete comment, error: {e}")
|
||||
|
||||
def edit_comment(self, comment, body: str):
|
||||
try:
|
||||
self.azure_devops_client.update_comment(
|
||||
|
@ -208,9 +208,6 @@ class GitProvider(ABC):
|
||||
def get_comment_url(self, comment) -> str:
|
||||
return ""
|
||||
|
||||
def delete_comment(self, comment):
|
||||
comment.delete()
|
||||
|
||||
#### labels operations ####
|
||||
@abstractmethod
|
||||
def publish_labels(self, labels):
|
||||
|
@ -452,8 +452,8 @@ class GithubProvider(GitProvider):
|
||||
|
||||
def edit_comment_from_comment_id(self, comment_id: int, body: str):
|
||||
try:
|
||||
body = self.limit_output_characters(body, self.max_comment_chars)
|
||||
# self.pr.get_issue_comment(comment_id).edit(body)
|
||||
body = self.limit_output_characters(body, self.max_comment_chars)
|
||||
headers, data_patch = self.pr._requester.requestJsonAndCheck(
|
||||
"PATCH", f"{self.base_url}/repos/{self.repo}/issues/comments/{comment_id}",
|
||||
input={"body": body}
|
||||
@ -463,8 +463,8 @@ class GithubProvider(GitProvider):
|
||||
|
||||
def reply_to_comment_from_comment_id(self, comment_id: int, body: str):
|
||||
try:
|
||||
body = self.limit_output_characters(body, self.max_comment_chars)
|
||||
# self.pr.get_issue_comment(comment_id).edit(body)
|
||||
body = self.limit_output_characters(body, self.max_comment_chars)
|
||||
headers, data_patch = self.pr._requester.requestJsonAndCheck(
|
||||
"POST", f"{self.base_url}/repos/{self.repo}/pulls/{self.pr_num}/comments/{comment_id}/replies",
|
||||
input={"body": body}
|
||||
@ -490,6 +490,7 @@ class GithubProvider(GitProvider):
|
||||
)
|
||||
for comment in file_comments:
|
||||
comment['commit_id'] = self.last_commit_id.sha
|
||||
comment['body'] = self.limit_output_characters(comment['body'], self.max_comment_chars)
|
||||
|
||||
found = False
|
||||
for existing_comment in existing_comments:
|
||||
@ -592,7 +593,7 @@ class GithubProvider(GitProvider):
|
||||
)
|
||||
return data_patch.get("id", None)
|
||||
except Exception as e:
|
||||
get_logger().exception(f"Failed to add eyes reaction, error: {e}")
|
||||
get_logger().warning(f"Failed to add eyes reaction, error: {e}")
|
||||
return None
|
||||
|
||||
def remove_reaction(self, issue_comment_id: int, reaction_id: str) -> bool:
|
||||
@ -829,8 +830,11 @@ class GithubProvider(GitProvider):
|
||||
"""
|
||||
line_start = component_range.line_start + 1
|
||||
line_end = component_range.line_end + 1
|
||||
# link = (f"https://github.com/{self.repo}/blob/{self.last_commit_id.sha}/{filepath}/"
|
||||
# f"#L{line_start}-L{line_end}")
|
||||
link = (f"{self.base_url_html}/{self.repo}/blob/{self.last_commit_id.sha}/{filepath}/"
|
||||
f"#L{line_start}-L{line_end}")
|
||||
|
||||
return link
|
||||
|
||||
def get_pr_id(self):
|
||||
|
@ -1,4 +1,5 @@
|
||||
import asyncio
|
||||
import traceback
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import aiohttp
|
||||
@ -35,6 +36,7 @@ async def polling_loop():
|
||||
user_id = git_provider.get_user_id()
|
||||
agent = PRAgent()
|
||||
get_settings().set("CONFIG.PUBLISH_OUTPUT_PROGRESS", False)
|
||||
get_settings().set("pr_description.publish_description_as_comment", True)
|
||||
|
||||
try:
|
||||
deployment_type = get_settings().github.deployment_type
|
||||
@ -92,7 +94,8 @@ async def polling_loop():
|
||||
comment_body = comment['body'] if 'body' in comment else ''
|
||||
commenter_github_user = comment['user']['login'] \
|
||||
if 'user' in comment else ''
|
||||
get_logger().info(f"Commenter: {commenter_github_user}\nComment: {comment_body}")
|
||||
get_logger().info(f"Polling, pr_url: {pr_url}",
|
||||
artifact={"comment": comment_body})
|
||||
user_tag = "@" + user_id
|
||||
if user_tag not in comment_body:
|
||||
continue
|
||||
@ -100,7 +103,8 @@ async def polling_loop():
|
||||
comment_id = comment['id']
|
||||
git_provider.set_pr(pr_url)
|
||||
success = await agent.handle_request(pr_url, rest_of_comment,
|
||||
notify=lambda: git_provider.add_eyes_reaction(comment_id)) # noqa E501
|
||||
notify=lambda: git_provider.add_eyes_reaction(
|
||||
comment_id)) # noqa E501
|
||||
if not success:
|
||||
git_provider.set_pr(pr_url)
|
||||
|
||||
@ -108,7 +112,8 @@ async def polling_loop():
|
||||
print(f"Failed to fetch notifications. Status code: {response.status}")
|
||||
|
||||
except Exception as e:
|
||||
get_logger().error(f"Exception during processing of a notification: {e}")
|
||||
get_logger().error(f"Polling exception during processing of a notification: {e}",
|
||||
artifact={"traceback": traceback.format_exc()})
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -52,6 +52,7 @@ class PRCodeSuggestions:
|
||||
self.ai_handler.main_pr_language = self.main_language
|
||||
self.patches_diff = None
|
||||
self.prediction = None
|
||||
self.pr_url = pr_url
|
||||
self.cli_mode = cli_mode
|
||||
self.vars = {
|
||||
"title": self.git_provider.pr.title,
|
||||
@ -81,6 +82,10 @@ class PRCodeSuggestions:
|
||||
|
||||
async def run(self):
|
||||
try:
|
||||
if not self.git_provider.get_files():
|
||||
get_logger().info(f"PR has no files: {self.pr_url}, skipping code suggestions")
|
||||
return None
|
||||
|
||||
get_logger().info('Generating code suggestions for PR...')
|
||||
relevant_configs = {'pr_code_suggestions': dict(get_settings().pr_code_suggestions),
|
||||
'config': dict(get_settings().config)}
|
||||
@ -159,6 +164,8 @@ class PRCodeSuggestions:
|
||||
self.push_inline_code_suggestions(data)
|
||||
if self.progress_response:
|
||||
self.progress_response.delete()
|
||||
else:
|
||||
get_logger().info('Code suggestions generated for PR, but not published since publish_output is False.')
|
||||
except Exception as e:
|
||||
get_logger().error(f"Failed to generate code suggestions for PR, error: {e}")
|
||||
if self.progress_response:
|
||||
@ -177,6 +184,7 @@ class PRCodeSuggestions:
|
||||
final_update_message=True,
|
||||
max_previous_comments=4,
|
||||
progress_response=None):
|
||||
|
||||
if isinstance(self.git_provider, AzureDevopsProvider): # get_latest_commit_url is not supported yet
|
||||
if progress_response:
|
||||
self.git_provider.edit_comment(progress_response, pr_comment)
|
||||
@ -256,7 +264,7 @@ class PRCodeSuggestions:
|
||||
get_logger().info(f"Persistent mode - updating comment {comment_url} to latest {name} message")
|
||||
if progress_response: # publish to 'progress_response' comment, because it refreshes immediately
|
||||
self.git_provider.edit_comment(progress_response, pr_comment_updated)
|
||||
self.git_provider.delete_comment(comment)
|
||||
self.git_provider.remove_comment(comment)
|
||||
else:
|
||||
self.git_provider.edit_comment(comment, pr_comment_updated)
|
||||
return
|
||||
@ -361,12 +369,14 @@ class PRCodeSuggestions:
|
||||
one_sentence_summary_list = []
|
||||
for i, suggestion in enumerate(data['code_suggestions']):
|
||||
try:
|
||||
needed_keys = ['one_sentence_summary', 'label', 'relevant_file', 'relevant_lines_start', 'relevant_lines_end']
|
||||
needed_keys = ['one_sentence_summary', 'label', 'relevant_file', 'relevant_lines_start',
|
||||
'relevant_lines_end']
|
||||
is_valid_keys = True
|
||||
for key in needed_keys:
|
||||
if key not in suggestion:
|
||||
is_valid_keys = False
|
||||
get_logger().debug(f"Skipping suggestion {i + 1}, because it does not contain '{key}':\n'{suggestion}")
|
||||
get_logger().debug(
|
||||
f"Skipping suggestion {i + 1}, because it does not contain '{key}':\n'{suggestion}")
|
||||
break
|
||||
if not is_valid_keys:
|
||||
continue
|
||||
@ -529,7 +539,7 @@ class PRCodeSuggestions:
|
||||
get_logger().error(f"Error getting PR diff for suggestion {i} in call {j}, error: {e}")
|
||||
self.data = data
|
||||
else:
|
||||
get_logger().error(f"Error getting PR diff")
|
||||
get_logger().warning(f"Empty PR diff list")
|
||||
self.data = data = None
|
||||
return data
|
||||
|
||||
|
@ -508,7 +508,8 @@ extra_file_yaml =
|
||||
|
||||
def _prepare_file_labels(self):
|
||||
file_label_dict = {}
|
||||
if not self.data or 'pr_files' not in self.data:
|
||||
if (not self.data or not isinstance(self.data, dict) or
|
||||
'pr_files' not in self.data or not self.data['pr_files']):
|
||||
return file_label_dict
|
||||
for file in self.data['pr_files']:
|
||||
try:
|
||||
|
@ -96,6 +96,10 @@ class PRReviewer:
|
||||
|
||||
async def run(self) -> None:
|
||||
try:
|
||||
if not self.git_provider.get_files():
|
||||
get_logger().info(f"PR has no files: {self.pr_url}, skipping review")
|
||||
return None
|
||||
|
||||
if self.incremental.is_incremental and not self._can_run_incremental_review():
|
||||
return None
|
||||
|
||||
@ -158,7 +162,7 @@ class PRReviewer:
|
||||
get_logger().debug(f"PR diff", diff=self.patches_diff)
|
||||
self.prediction = await self._get_prediction(model)
|
||||
else:
|
||||
get_logger().error(f"Error getting PR diff")
|
||||
get_logger().warning(f"Empty diff for PR: {self.pr_url}")
|
||||
self.prediction = None
|
||||
|
||||
async def _get_prediction(self, model: str) -> str:
|
||||
|
Reference in New Issue
Block a user