From e5259e2f5c06d9931b1a3bc35101ec9f9dc9d1a0 Mon Sep 17 00:00:00 2001 From: Ori Kotek Date: Tue, 18 Jul 2023 10:17:09 +0300 Subject: [PATCH 1/3] Small refactor --- pr_agent/git_providers/bitbucket_provider.py | 8 ++++++++ pr_agent/git_providers/git_provider.py | 8 ++++++++ pr_agent/git_providers/github_provider.py | 6 ++++++ pr_agent/git_providers/gitlab_provider.py | 8 ++++++++ pr_agent/tools/pr_reviewer.py | 8 ++++---- 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/pr_agent/git_providers/bitbucket_provider.py b/pr_agent/git_providers/bitbucket_provider.py index e9946aa9..86e445ac 100644 --- a/pr_agent/git_providers/bitbucket_provider.py +++ b/pr_agent/git_providers/bitbucket_provider.py @@ -25,6 +25,11 @@ class BitbucketProvider: if pr_url: self.set_pr(pr_url) + def is_supported(self, capability: str) -> bool: + if capability == 'get_issue_comments': + return False + return True + def set_pr(self, pr_url: str): self.workspace_slug, self.repo_slug, self.pr_num = self._parse_pr_url(pr_url) self.pr = self._get_pr() @@ -74,6 +79,9 @@ class BitbucketProvider: def get_user_id(self): return 0 + def get_issue_comments(self): + raise NotImplementedError("Bitbucket provider does not support issue comments yet") + @staticmethod def _parse_pr_url(pr_url: str) -> Tuple[str, int]: parsed_url = urlparse(pr_url) diff --git a/pr_agent/git_providers/git_provider.py b/pr_agent/git_providers/git_provider.py index ae39cc74..4beba204 100644 --- a/pr_agent/git_providers/git_provider.py +++ b/pr_agent/git_providers/git_provider.py @@ -21,6 +21,10 @@ class FilePatchInfo: class GitProvider(ABC): + @abstractmethod + def is_supported(self, capability: str) -> bool: + pass + @abstractmethod def get_diff_files(self) -> list[FilePatchInfo]: pass @@ -62,6 +66,10 @@ class GitProvider(ABC): def get_pr_description(self): pass + @abstractmethod + def get_issue_comments(self): + pass + def get_main_pr_language(languages, files) -> str: """ diff --git a/pr_agent/git_providers/github_provider.py b/pr_agent/git_providers/github_provider.py index 4f7d44bc..76f3a818 100644 --- a/pr_agent/git_providers/github_provider.py +++ b/pr_agent/git_providers/github_provider.py @@ -23,6 +23,9 @@ class GithubProvider(GitProvider): self.set_pr(pr_url) self.last_commit_id = list(self.pr.get_commits())[-1] + def is_supported(self, capability: str) -> bool: + return True + def set_pr(self, pr_url: str): self.repo, self.pr_num = self._parse_pr_url(pr_url) self.pr = self._get_pr() @@ -161,6 +164,9 @@ class GithubProvider(GitProvider): notifications = self.github_client.get_user().get_notifications(since=since) return notifications + def get_issue_comments(self): + return self.pr.get_issue_comments() + @staticmethod def _parse_pr_url(pr_url: str) -> Tuple[str, int]: parsed_url = urlparse(pr_url) diff --git a/pr_agent/git_providers/gitlab_provider.py b/pr_agent/git_providers/gitlab_provider.py index 07a25e2f..c33016cc 100644 --- a/pr_agent/git_providers/gitlab_provider.py +++ b/pr_agent/git_providers/gitlab_provider.py @@ -31,6 +31,11 @@ class GitLabProvider(GitProvider): self.RE_HUNK_HEADER = re.compile( r"^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@[ ]?(.*)") + def is_supported(self, capability: str) -> bool: + if capability == 'get_issue_comments': + return False + return True + @property def pr(self): '''The GitLab terminology is merge request (MR) instead of pull request (PR)''' @@ -203,6 +208,9 @@ class GitLabProvider(GitProvider): def get_pr_description(self): return self.mr.description + def get_issue_comments(self): + raise NotImplementedError("GitLab provider does not support issue comments yet") + def _parse_merge_request_url(self, merge_request_url: str) -> Tuple[int, int]: parsed_url = urlparse(merge_request_url) diff --git a/pr_agent/tools/pr_reviewer.py b/pr_agent/tools/pr_reviewer.py index b086c9c0..e11a2042 100644 --- a/pr_agent/tools/pr_reviewer.py +++ b/pr_agent/tools/pr_reviewer.py @@ -9,7 +9,7 @@ from pr_agent.algo.pr_processing import get_pr_diff from pr_agent.algo.token_handler import TokenHandler from pr_agent.algo.utils import convert_to_markdown, try_fix_json from pr_agent.config_loader import settings -from pr_agent.git_providers import get_git_provider, GithubProvider +from pr_agent.git_providers import get_git_provider from pr_agent.git_providers.git_provider import get_main_pr_language from pr_agent.servers.help import bot_help_text, actions_help_text @@ -22,8 +22,8 @@ class PRReviewer: self.git_provider.get_languages(), self.git_provider.get_files() ) self.is_answer = is_answer - if self.is_answer and type(self.git_provider) != GithubProvider: - raise Exception("Answer mode is only supported for Github for now") + if self.is_answer and not self.git_provider.is_supported("get_issue_comments"): + raise Exception(f"Answer mode is not supported for {settings.config.git_provider} for now") answer_str = question_str = self._get_user_answers() self.ai_handler = AiHandler() self.patches_diff = None @@ -139,7 +139,7 @@ class PRReviewer: def _get_user_answers(self): answer_str = question_str = "" if self.is_answer: - discussion_messages = self.git_provider.pr.get_issue_comments() + discussion_messages = self.git_provider.get_issue_comments() for message in discussion_messages.reversed: if "Questions to better understand the PR:" in message.body: question_str = message.body From a994ec1427ee016f1a0ae1054a777ad3036c573f Mon Sep 17 00:00:00 2001 From: Ori Kotek Date: Tue, 18 Jul 2023 10:19:32 +0300 Subject: [PATCH 2/3] Call PRAgent from github_action_runner.py --- pr_agent/servers/github_action_runner.py | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/pr_agent/servers/github_action_runner.py b/pr_agent/servers/github_action_runner.py index 56a7bb5e..31a4800d 100644 --- a/pr_agent/servers/github_action_runner.py +++ b/pr_agent/servers/github_action_runner.py @@ -3,6 +3,7 @@ import json import os import re +from pr_agent.agent.pr_agent import PRAgent from pr_agent.config_loader import settings from pr_agent.tools.pr_code_suggestions import PRCodeSuggestions from pr_agent.tools.pr_description import PRDescription @@ -54,26 +55,7 @@ async def run_action(): pr_url = event_payload.get("issue", {}).get("pull_request", {}).get("url", None) if pr_url: body = comment_body.strip().lower() - if any(cmd in body for cmd in ["/answer"]): - await PRReviewer(pr_url, is_answer=True).review() - elif any(cmd in body for cmd in ["/review", "/review_pr", "/reflect_and_review"]): - if settings.pr_reviewer.ask_and_reflect or \ - any(cmd in body for cmd in ["/reflect_and_review"]): - await PRInformationFromUser(pr_url).generate_questions() - else: - await PRReviewer(pr_url).review() - elif any(cmd in body for cmd in ["/describe", "/describe_pr"]): - await PRDescription(pr_url).describe() - elif any(cmd in body for cmd in ["/improve", "/improve_code"]): - await PRCodeSuggestions(pr_url).suggest() - elif any(cmd in body for cmd in ["/ask", "/ask_question"]): - pattern = r'(/ask|/ask_question)\s*(.*)' - matches = re.findall(pattern, comment_body, re.IGNORECASE) - if matches: - question = matches[0][1] - await PRQuestions(pr_url, question).answer() - else: - print(f"Unknown command: {body}") + await PRAgent().handle_request(pr_url, body) if __name__ == '__main__': From fdeae9c2095353722f1d62fdcd3a8a8cb2e0447d Mon Sep 17 00:00:00 2001 From: Ori Kotek Date: Tue, 18 Jul 2023 10:20:52 +0300 Subject: [PATCH 3/3] Update pr_agent/agent/pr_agent.py --- pr_agent/agent/pr_agent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pr_agent/agent/pr_agent.py b/pr_agent/agent/pr_agent.py index 3709db1f..672a7a94 100644 --- a/pr_agent/agent/pr_agent.py +++ b/pr_agent/agent/pr_agent.py @@ -16,7 +16,7 @@ class PRAgent: if any(cmd in request for cmd in ["/answer"]): await PRReviewer(pr_url, is_answer=True).review() elif any(cmd in request for cmd in ["/review", "/review_pr", "/reflect_and_review"]): - if settings.pr_reviewer.ask_and_reflect or any(cmd in request for cmd in ["/reflect_and_review"]): + if settings.pr_reviewer.ask_and_reflect or "/reflect_and_review" in request: await PRInformationFromUser(pr_url).generate_questions() else: await PRReviewer(pr_url).review()