Skip to content

Commit 482cd7c

Browse files
authored
Merge pull request #1651 from qodo-ai/es/github_publish_non_pr_comment
Add support for publishing comments on issues in GitHub provider
2 parents fcd9416 + 991a866 commit 482cd7c

File tree

2 files changed

+38
-6
lines changed

2 files changed

+38
-6
lines changed

pr_agent/git_providers/github_provider.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from typing import Optional, Tuple
1111
from urllib.parse import urlparse
1212

13+
from github.Issue import Issue
1314
from github import AppAuthentication, Auth, Github, GithubException
1415
from retry import retry
1516
from starlette_context import context
@@ -42,6 +43,7 @@ def __init__(self, pr_url: Optional[str] = None):
4243
self.repo = None
4344
self.pr_num = None
4445
self.pr = None
46+
self.issue_main = None
4547
self.github_user_id = None
4648
self.diff_files = None
4749
self.git_files = None
@@ -51,9 +53,29 @@ def __init__(self, pr_url: Optional[str] = None):
5153
self.pr_commits = list(self.pr.get_commits())
5254
self.last_commit_id = self.pr_commits[-1]
5355
self.pr_url = self.get_pr_url() # pr_url for github actions can be as api.github.com, so we need to get the url from the pr object
54-
else:
56+
elif pr_url and 'issue' in pr_url: #url is an issue
57+
self.issue_main = self._get_issue_handle(pr_url)
58+
else: #Instantiated the provider without a PR / Issue
5559
self.pr_commits = None
5660

61+
def _get_issue_handle(self, issue_url) -> Optional[Issue]:
62+
repo_name, issue_number = self._parse_issue_url(issue_url)
63+
if not repo_name or not issue_number:
64+
get_logger().error(f"Given url: {issue_url} is not a valid issue.")
65+
return None
66+
# else: Check if can get a valid Repo handle:
67+
try:
68+
repo_obj = self.github_client.get_repo(repo_name)
69+
if not repo_obj:
70+
get_logger().error(f"Given url: {issue_url}, belonging to owner/repo: {repo_name} does "
71+
f"not have a valid repository: {self.get_git_repo_url(issue_url)}")
72+
return None
73+
# else: Valid repo handle:
74+
return repo_obj.get_issue(issue_number)
75+
except Exception as e:
76+
get_logger().exception(f"Failed to get an issue object for issue: {issue_url}, belonging to owner/repo: {repo_name}")
77+
return None
78+
5779
def get_incremental_commits(self, incremental=IncrementalPR(False)):
5880
self.incremental = incremental
5981
if self.incremental.is_incremental:
@@ -344,10 +366,19 @@ def publish_persistent_comment(self, pr_comment: str,
344366
self.publish_persistent_comment_full(pr_comment, initial_header, update_header, name, final_update_message)
345367

346368
def publish_comment(self, pr_comment: str, is_temporary: bool = False):
369+
if not self.pr and not self.issue_main:
370+
get_logger().error("Cannot publish a comment if missing PR/Issue context")
371+
return None
372+
347373
if is_temporary and not get_settings().config.publish_output_progress:
348374
get_logger().debug(f"Skipping publish_comment for temporary comment: {pr_comment}")
349375
return None
350376
pr_comment = self.limit_output_characters(pr_comment, self.max_comment_chars)
377+
378+
# In case this is an issue, can publish the comment on the issue.
379+
if self.issue_main:
380+
return self.issue_main.create_comment(pr_comment)
381+
351382
response = self.pr.create_issue_comment(pr_comment)
352383
if hasattr(response, "user") and hasattr(response.user, "login"):
353384
self.github_user_id = response.user.login
@@ -731,11 +762,11 @@ def _parse_pr_url(self, pr_url: str) -> Tuple[str, int]:
731762
def _parse_issue_url(self, issue_url: str) -> Tuple[str, int]:
732763
parsed_url = urlparse(issue_url)
733764

734-
if 'github.com' not in parsed_url.netloc:
735-
raise ValueError("The provided URL is not a valid GitHub URL")
765+
if parsed_url.path.startswith('/api/v3'): #Check if came from github app
766+
parsed_url = urlparse(issue_url.replace("/api/v3", ""))
736767

737768
path_parts = parsed_url.path.strip('/').split('/')
738-
if 'api.github.com' in parsed_url.netloc:
769+
if 'api.github.com' in parsed_url.netloc or '/api/v3' in issue_url: #Check if came from github app
739770
if len(path_parts) < 5 or path_parts[3] != 'issues':
740771
raise ValueError("The provided URL does not appear to be a GitHub ISSUE URL")
741772
repo_name = '/'.join(path_parts[1:3])

pr_agent/tools/pr_help_docs.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ def aggregate_documentation_files_for_prompt_contents(base_path: str, doc_files:
101101

102102
def format_markdown_q_and_a_response(question_str: str, response_str: str, relevant_sections: List[Dict[str, str]],
103103
supported_suffixes: List[str], base_url_prefix: str, base_url_suffix: str="") -> str:
104+
base_url_prefix = base_url_prefix.strip('/') #Sanitize base_url_prefix
104105
answer_str = ""
105106
answer_str += f"### Question: \n{question_str}\n\n"
106107
answer_str += f"### Answer:\n{response_str.strip()}\n\n"
@@ -114,9 +115,9 @@ def format_markdown_q_and_a_response(question_str: str, response_str: str, relev
114115
if str(section['relevant_section_header_string']).strip():
115116
markdown_header = format_markdown_header(section['relevant_section_header_string'])
116117
if base_url_prefix:
117-
answer_str += f"> - {base_url_prefix}{file}{base_url_suffix}#{markdown_header}\n"
118+
answer_str += f"> - {base_url_prefix}/{file}{base_url_suffix}#{markdown_header}\n"
118119
else:
119-
answer_str += f"> - {base_url_prefix}{file}{base_url_suffix}\n"
120+
answer_str += f"> - {base_url_prefix}/{file}{base_url_suffix}\n"
120121
return answer_str
121122

122123
def format_markdown_header(header: str) -> str:

0 commit comments

Comments
 (0)