22import sys
33import traceback
44from functools import wraps
5+ from PyBugReporter .src .DiscordBot import DiscordBot
56
67from python_graphql_client import GraphqlClient
78
@@ -25,20 +26,31 @@ class BugHandler:
2526 repoName : str = ''
2627 orgName : str = ''
2728 test : bool = False
29+ useDiscord : bool = False
30+ botToken : str = ''
31+ channelId : str | int = ''
2832
29- def __init__ (self , githubKey : str , repoName : str , orgName : str , test : bool ) -> None :
33+ def __init__ (self , githubKey : str , repoName : str , orgName : str , test : bool , useDiscord : bool = False , botToken : str = "" , channelId : str | int = "" ) -> None :
3034 """Saves the given information in the BugHandler object.
3135
3236 Args:
3337 githubKey (str): the key to use to make the issue
3438 repoName (str): the name of the repo to report to
3539 orgName (str): the organization of the repo
3640 test (bool): whether or not bugs in this code should actually be reported
41+ useDiscord (bool): whether to send the bug report to Discord
42+ botToken (str): the token for the Discord bot
43+ channelId (str | int): the ID of the Discord channel to send messages to
3744 """
3845 self .githubKey = githubKey
3946 self .repoName = repoName
4047 self .orgName = orgName
4148 self .test = test
49+ self .useDiscord = useDiscord
50+
51+ if useDiscord :
52+ self .botToken = botToken
53+ self .channelId = channelId
4254
4355class BugReporter :
4456 """Sends errors to their corresponding repos.
@@ -64,7 +76,7 @@ def __init__(self, repoName: str, extraInfo: bool, **kwargs) -> None:
6476 self .kwargs = kwargs
6577
6678 @classmethod
67- def setVars (cls , githubKey : str , repoName : str , orgName : str , test : bool ) -> None :
79+ def setVars (cls , githubKey : str , repoName : str , orgName : str , test : bool , useDiscord : bool = False , botToken : str = "" , channelId : str = "" ) -> None :
6880 """Sets the necessary variables to make bug reports.
6981
7082 Args:
@@ -73,7 +85,7 @@ def setVars(cls, githubKey: str, repoName: str, orgName: str, test: bool) -> Non
7385 orgName (str): the name of the organization
7486 test (bool): whether to run in testing mode
7587 """
76- cls .handlers [repoName ] = BugHandler (githubKey , repoName , orgName , test )
88+ cls .handlers [repoName ] = BugHandler (githubKey , repoName , orgName , test , useDiscord , botToken , channelId )
7789
7890 def __call__ (self , func : callable ) -> None :
7991 """Decorator that catches exceptions and sends a bug report to the github repository.
@@ -118,26 +130,51 @@ def _handleError(self, e: Exception, repoName: str, *args, **kwargs) -> None:
118130 if self .extraInfo :
119131 description += f"\n Extra Info: { self .kwargs } "
120132
133+ # shortened description for discord if too long (shortens the error text)
134+ start = f"# { title } \n \n Type: { excType } \n Error text: "
135+ compress = f"{ e } \n Traceback: { traceback .format_exc ()} "
136+ end = f"\n \n Function Name: { functionName } \n Arguments: { args } \n Keyword Arguments: { kwargs } "
137+ if self .extraInfo :
138+ end += f"\n Extra Info: { self .kwargs } "
139+
140+ staticLength = len (start ) + len (end )
141+ if staticLength > 2000 :
142+ shortDescription = f"# { title } \n \n " + description [:2000 - len (f"# { title } \n \n " ) - 3 ] + "..."
143+ else :
144+ shortDescription = f"{ start } { compress [:2000 - staticLength ]} { end } "
145+
146+ print (f"SHORT DESCRIPTION with length { len (shortDescription )} :\n { shortDescription } " )
147+
148+
121149 # Check if we need to send a bug report
122150 if not self .handlers [repoName ].test :
123- self ._sendBugReport (repoName , title , description )
151+ self ._sendBugReport (repoName , title , description , shortDescription )
124152
125153 print (title )
126154 print (description )
127155 raise e
128156
129- def _sendBugReport (self , repoName : str , errorTitle : str , errorMessage : str ) -> None :
157+ def _sendBugReport (self , repoName : str , errorTitle : str , errorMessage : str , shortErrorMessage : str ) -> None :
130158 """Sends a bug report to the Github repository.
131159
132160 Args:
133161 errorTitle (str): the title of the error
134162 errorMessage (str): the error message
135- """
163+ """
164+ asyncio .run (self ._sendBugReport_async (repoName , errorTitle , errorMessage , shortErrorMessage ))
165+
166+ async def _sendBugReport_async (self , repoName : str , errorTitle : str , errorMessage : str , shortErrorMessage : str ) -> None :
167+ """Sends a bug report to the Github repository asynchronously.
168+
169+ Args:
170+ errorTitle (str): the title of the error
171+ errorMessage (str): the error message
172+ """
136173 client = GraphqlClient (endpoint = "https://api.github.com/graphql" )
137174 headers = {"Authorization" : f"Bearer { self .handlers [repoName ].githubKey } " }
138175
139176 # query variables
140- repoId = self ._getRepoId (self .handlers [repoName ])
177+ repoId = await self ._getRepoId_async (self .handlers [repoName ])
141178 bugLabel = "LA_kwDOJ3JPj88AAAABU1q15w"
142179 autoLabel = "LA_kwDOJ3JPj88AAAABU1q2DA"
143180
@@ -171,10 +208,15 @@ def _sendBugReport(self, repoName: str, errorTitle: str, errorMessage: str) -> N
171208 }
172209 }
173210
174- issueExists = self ._checkIfIssueExists (self .handlers [repoName ], errorTitle )
211+ issueExists = await self ._checkIfIssueExists_async (self .handlers [repoName ], errorTitle )
175212
176- if (issueExists == False ):
177- result = asyncio .run (client .execute_async (query = createIssue , variables = variables , headers = headers ))
213+ # Send to Discord if applicable
214+ if self .handlers [repoName ].useDiscord :
215+ discordBot = DiscordBot (self .handlers [repoName ].botToken , self .handlers [repoName ].channelId )
216+ await discordBot .send_message (shortErrorMessage , issueExists )
217+
218+ if (not issueExists ):
219+ result = await client .execute_async (query = createIssue , variables = variables , headers = headers )
178220 print ('\n This error has been reported to the Tree Growth team.\n ' )
179221
180222 issueId = result ['data' ]['createIssue' ]['issue' ]['id' ] # Extract the issue ID
@@ -191,20 +233,19 @@ def _sendBugReport(self, repoName: str, errorTitle: str, errorMessage: str) -> N
191233 """
192234
193235 # Replace with your actual project ID
194- projectId = self .getProjectId (repoName , "Tree Growth Projects" )
236+ projectId = await self .getProjectId_async (repoName , "Tree Growth Projects" )
195237
196238 variables = {
197239 "projectId" : projectId ,
198240 "contentId" : issueId
199241 }
200242
201243 # Execute the mutation to add the issue to the project
202- asyncio . run ( client .execute_async (query = addToProject , variables = variables , headers = headers ) )
244+ await client .execute_async (query = addToProject , variables = variables , headers = headers )
203245 else :
204246 print ('\n Our team is already aware of this issue.\n ' )
205247
206- def getProjectId (self , repoName : str , projectName : str ) -> str :
207- """Retrieves the GitHub project ID for a specified repository and project name."""
248+ async def getProjectId_async (self , repoName : str , projectName : str ) -> str :
208249 client = GraphqlClient (endpoint = "https://api.github.com/graphql" )
209250 headers = {"Authorization" : f"Bearer { self .handlers [repoName ].githubKey } " }
210251
@@ -228,7 +269,7 @@ def getProjectId(self, repoName: str, projectName: str) -> str:
228269 }
229270
230271 # Execute the query
231- response = asyncio . run ( client .execute_async (query = query , variables = variables , headers = headers ) )
272+ response = await client .execute_async (query = query , variables = variables , headers = headers )
232273 projects = response ["data" ]["repository" ]["projectsV2" ]["nodes" ]
233274
234275 # Find the project with the matching name and return its ID
@@ -238,7 +279,7 @@ def getProjectId(self, repoName: str, projectName: str) -> str:
238279
239280 raise ValueError (f"Project '{ projectName } ' not found in repository '{ repoName } '." )
240281
241- def _checkIfIssueExists (self , handler : BugHandler , errorTitle : str ) -> bool :
282+ async def _checkIfIssueExists_async (self , handler : BugHandler , errorTitle : str ) -> bool :
242283 """Checks if an issue already exists in the repository.
243284
244285 Args:
@@ -276,7 +317,7 @@ def _checkIfIssueExists(self, handler: BugHandler, errorTitle: str) -> bool:
276317 "labels" : autoLabel ,
277318 }
278319
279- result = asyncio . run ( client .execute_async (query = findIssue , variables = variables , headers = headers ) )
320+ result = await client .execute_async (query = findIssue , variables = variables , headers = headers )
280321 nodes = result ['data' ]['organization' ]['repository' ]['issues' ]['nodes' ]
281322
282323 index = 0
@@ -292,7 +333,7 @@ def _checkIfIssueExists(self, handler: BugHandler, errorTitle: str) -> bool:
292333
293334 return issueExists
294335
295- def _getRepoId (self , handler : BugHandler ) -> str :
336+ async def _getRepoId_async (self , handler : BugHandler ) -> str :
296337 """Gets the repository ID.
297338
298339 Args:
@@ -318,7 +359,7 @@ def _getRepoId(self, handler: BugHandler) -> str:
318359 "name" : handler .repoName
319360 }
320361
321- repoID = asyncio . run ( client .execute_async (query = getID , variables = variables , headers = headers ) )
362+ repoID = await client .execute_async (query = getID , variables = variables , headers = headers )
322363 return repoID ['data' ]['repository' ]['id' ]
323364
324365 @classmethod
0 commit comments