2121import requests
2222import traceback
2323from os import getenv
24- from typing import Dict , Any
24+ from typing import Dict , Any , Optional
2525
2626GITHUB_TOKEN = getenv ('GITHUB_TOKEN' )
2727
@@ -115,6 +115,38 @@ def get_pr_content(self, repo_owner: str, repo_name: str, pr_number: int) -> Dic
115115 logging .error (f"Error fetching PR content: { str (e )} " )
116116 traceback .print_exc ()
117117 return None
118+
119+ def add_pr_comments (self , repo_owner : str , repo_name : str , pr_number : int , comment : str ) -> Dict [str , Any ]:
120+ """Add a comment to a pull request.
121+
122+ Args:
123+ repo_owner: The owner of the GitHub repository
124+ repo_name: The name of the GitHub repository
125+ pr_number: The number of the pull request to comment on
126+ comment: The content of the comment
127+
128+ Returns:
129+ A dictionary containing the added comment's metadata
130+ """
131+ logging .info (f"Adding comment to PR { repo_owner } /{ repo_name } #{ pr_number } " )
132+
133+ # Construct the comments URL
134+ comments_url = f"https://api.github.com/repos/{ repo_owner } /{ repo_name } /issues/{ pr_number } /comments"
135+
136+ try :
137+ # Add the comment
138+ response = requests .post (comments_url , headers = self ._get_headers (), json = {'body' : comment })
139+ response .raise_for_status ()
140+ comment_data = response .json ()
141+
142+ logging .info (f"Comment added successfully" )
143+ return comment_data
144+
145+ except Exception as e :
146+ logging .error (f"Error adding comment: { str (e )} " )
147+ traceback .print_exc ()
148+ return None
149+
118150 def update_pr_description (self , repo_owner : str , repo_name : str , pr_number : int , new_title : str , new_description : str ) -> Dict [str , Any ]:
119151 """Update the description of a pull request.
120152
@@ -130,7 +162,6 @@ def update_pr_description(self, repo_owner: str, repo_name: str, pr_number: int,
130162 """
131163 logging .info (f"Updating PR description for { repo_owner } /{ repo_name } #{ pr_number } " )
132164
133-
134165 # Construct the PR URL
135166 pr_url = self ._get_pr_url (repo_owner , repo_name , pr_number )
136167 try :
@@ -149,49 +180,54 @@ def update_pr_description(self, repo_owner: str, repo_name: str, pr_number: int,
149180 traceback .print_exc ()
150181 return None
151182
152- def create_issue (self , repo_owner : str , repo_name : str , title : str , body : str ) -> Dict [str , Any ]:
183+ def create_issue (self , repo_owner : str , repo_name : str , title : str , body : str , labels : list [ str ] ) -> Dict [str , Any ]:
153184 """Create a new issue in the specified GitHub repository.
154185
155186 Args:
156187 repo_owner: The owner of the GitHub repository
157188 repo_name: The name of the GitHub repository
158189 title: The title of the issue
159- body: The body content of the issue
190+ body: The body content of the issue, this should include description, why, details, references
191+ if there is a PR number, add resolve by PR number
192+ labels: A list of labels to apply to the issue
160193 Returns:
161194 A dictionary containing the created issue's metadata
162195 """
163196 logging .info (f"Creating issue in { repo_owner } /{ repo_name } " )
164197
165198 # Construct the issues URL
166199 issues_url = f"https://api.github.com/repos/{ repo_owner } /{ repo_name } /issues"
167-
200+
168201 try :
169202 # Create the issue
203+ issue_labels = ['mcp' ] if not labels else labels + ['mcp' ]
170204 response = requests .post (issues_url , headers = self ._get_headers (), json = {
171205 'title' : title ,
172206 'body' : body ,
173- 'labels' : [ 'mcp' ]
207+ 'labels' : issue_labels
174208 })
175209 response .raise_for_status ()
176210 issue_data = response .json ()
177211
178212 logging .info (f"Issue created successfully" )
179213 return issue_data
180-
214+
181215 except Exception as e :
182216 logging .error (f"Error creating issue: { str (e )} " )
183217 traceback .print_exc ()
184218 return None
185219
186- def update_issue (self , repo_owner : str , repo_name : str , issue_number : int , title : str , body : str , state : str = 'open' ) -> Dict [str , Any ]:
220+ def update_issue (self , repo_owner : str , repo_name : str , issue_number : int , title : str , body : str , labels : list [ str ] = [], state : str = 'open' ) -> Dict [str , Any ]:
187221 """Update an existing issue in the specified GitHub repository.
188-
222+
189223 Args:
190224 repo_owner: The owner of the GitHub repository
191225 repo_name: The name of the GitHub repository
192226 issue_number: The number of the issue to update
193227 title: The new title of the issue
194228 body: The new body content of the issue
229+ labels: A list of labels to apply to the issue
230+ state: The new state of the issue (open/closed)
195231 Returns:
196232 A dictionary containing the updated issue's metadata
197233 """
@@ -205,6 +241,7 @@ def update_issue(self, repo_owner: str, repo_name: str, issue_number: int, title
205241 response = requests .patch (issue_url , headers = self ._get_headers (), json = {
206242 'title' : title ,
207243 'body' : body ,
244+ 'labels' : labels ,
208245 'state' : state
209246 })
210247 response .raise_for_status ()
@@ -218,40 +255,40 @@ def update_issue(self, repo_owner: str, repo_name: str, issue_number: int, title
218255
219256 def get_latest_sha (self , repo_owner : str , repo_name : str ) -> Optional [str ]:
220257 """Fetch the latest commit SHA from the specified GitHub repository.
221-
258+
222259 Args:
223260 repo_owner: The owner of the GitHub repository
224261 repo_name: The name of the GitHub repository
225262 Returns:
226263 The latest commit SHA as a string, or None if no commits are found
227264 """
228265 logging .info (f"Fetching latest commit SHA for { repo_owner } /{ repo_name } " )
229-
266+
230267 # Construct the commits URL
231268 commits_url = f"https://api.github.com/repos/{ repo_owner } /{ repo_name } /commits"
232-
269+
233270 try :
234271 # Fetch the latest commit
235272 response = requests .get (commits_url , headers = self ._get_headers ())
236273 response .raise_for_status ()
237274 commits_data = response .json ()
238-
275+
239276 if commits_data :
240277 latest_sha = commits_data [0 ]['sha' ]
241278 logging .info (f"Latest commit SHA fetched successfully" )
242279 return latest_sha
243280 else :
244281 logging .warning ("No commits found in the repository" )
245282 return None
246-
283+
247284 except Exception as e :
248285 logging .error (f"Error fetching latest commit SHA: { str (e )} " )
249286 traceback .print_exc ()
250287 return None
251-
288+
252289 def create_tag (self , repo_owner : str , repo_name : str , tag_name : str , message : str ) -> Dict [str , Any ]:
253290 """Create a new tag in the specified GitHub repository.
254-
291+
255292 Args:
256293 repo_owner: The owner of the GitHub repository
257294 repo_name: The name of the GitHub repository
@@ -268,7 +305,7 @@ def create_tag(self, repo_owner: str, repo_name: str, tag_name: str, message: st
268305 latest_sha = self .get_latest_sha (repo_owner , repo_name )
269306 if not latest_sha :
270307 raise ValueError ("Failed to fetch the latest commit SHA" )
271-
308+
272309 # Create the tag
273310 response = requests .post (tags_url , headers = self ._get_headers (), json = {
274311 'ref' : f'refs/tags/{ tag_name } ' ,
@@ -277,18 +314,18 @@ def create_tag(self, repo_owner: str, repo_name: str, tag_name: str, message: st
277314 })
278315 response .raise_for_status ()
279316 tag_data = response .json ()
280-
317+
281318 logging .info (f"Tag created successfully" )
282319 return tag_data
283-
320+
284321 except Exception as e :
285322 logging .error (f"Error creating tag: { str (e )} " )
286323 traceback .print_exc ()
287324 return None
288325
289326 def create_release (self , repo_owner : str , repo_name : str , tag_name : str , release_name : str , body : str ) -> Dict [str , Any ]:
290327 """Create a new release in the specified GitHub repository.
291-
328+
292329 Args:
293330 repo_owner: The owner of the GitHub repository
294331 repo_name: The name of the GitHub repository
@@ -299,10 +336,10 @@ def create_release(self, repo_owner: str, repo_name: str, tag_name: str, release
299336 A dictionary containing the created release's metadata
300337 """
301338 logging .info (f"Creating release { release_name } in { repo_owner } /{ repo_name } " )
302-
339+
303340 # Construct the releases URL
304341 releases_url = f"https://api.github.com/repos/{ repo_owner } /{ repo_name } /releases"
305-
342+
306343 try :
307344 # Create the release
308345 response = requests .post (releases_url , headers = self ._get_headers (), json = {
@@ -315,10 +352,10 @@ def create_release(self, repo_owner: str, repo_name: str, tag_name: str, release
315352 })
316353 response .raise_for_status ()
317354 release_data = response .json ()
318-
355+
319356 logging .info (f"Release created successfully" )
320357 return release_data
321-
358+
322359 except Exception as e :
323360 logging .error (f"Error creating release: { str (e )} " )
324361 traceback .print_exc ()
0 commit comments