From 2783c0e7cdb083377a7f6c02471fc490603cb979 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 12 Mar 2025 21:26:45 +0000 Subject: [PATCH 01/16] Auto-updated version from 1.0.8b2 to 1.0.8b2.dev0 --- PyBugReporter/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PyBugReporter/_version.py b/PyBugReporter/_version.py index 5999c79..fcb5b76 100644 --- a/PyBugReporter/_version.py +++ b/PyBugReporter/_version.py @@ -1 +1 @@ -__version__ = '1.0.8b2' \ No newline at end of file +__version__ = '1.0.8b2.dev0' \ No newline at end of file From e953186638b96f8b76e214e79ef65281dc869836 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 12 Mar 2025 21:27:08 +0000 Subject: [PATCH 02/16] Auto-updated version from 1.0.9b0 to 1.0.9b0.dev0 --- PyBugReporter/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PyBugReporter/_version.py b/PyBugReporter/_version.py index a12ba52..fda245a 100644 --- a/PyBugReporter/_version.py +++ b/PyBugReporter/_version.py @@ -1 +1 @@ -__version__ = '1.0.9b0' \ No newline at end of file +__version__ = '1.0.9b0.dev0' \ No newline at end of file From 450660b3eda6751719d6cb6ddd57b9ac71138b3f Mon Sep 17 00:00:00 2001 From: Elijah Date: Thu, 15 May 2025 14:05:55 -0600 Subject: [PATCH 03/16] made bot --- .gitignore | 4 ++++ PyBugReporter/src/BugReporter.py | 21 ++++++++++++++++++--- PyBugReporter/src/DiscordBot.py | 21 +++++++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 PyBugReporter/src/DiscordBot.py diff --git a/.gitignore b/.gitignore index d59e7cd..ed7acc1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,7 @@ src/pip-delete-this-directory.txt **/.vs **/.vscode **/.DS_Store + +pbrVenv +src/lib +.env \ No newline at end of file diff --git a/PyBugReporter/src/BugReporter.py b/PyBugReporter/src/BugReporter.py index cdcd51e..e6eab78 100644 --- a/PyBugReporter/src/BugReporter.py +++ b/PyBugReporter/src/BugReporter.py @@ -2,6 +2,7 @@ import sys import traceback from functools import wraps +import DiscordBot from python_graphql_client import GraphqlClient @@ -25,8 +26,11 @@ class BugHandler: repoName: str = '' orgName: str = '' test: bool = False + useDiscord: bool = False + botToken: str = '' + channelId: str = '' - def __init__(self, githubKey: str, repoName: str, orgName: str, test: bool) -> None: + def __init__(self, githubKey: str, repoName: str, orgName: str, test: bool, useDiscord: bool = False, botToken = "", channelId: str = "") -> None: """Saves the given information in the BugHandler object. Args: @@ -39,6 +43,11 @@ def __init__(self, githubKey: str, repoName: str, orgName: str, test: bool) -> N self.repoName = repoName self.orgName = orgName self.test = test + self.useDiscord = useDiscord + + if useDiscord: + self.botToken = botToken + self.channelId = channelId class BugReporter: """Sends errors to their corresponding repos. @@ -64,7 +73,7 @@ def __init__(self, repoName: str, extraInfo: bool, **kwargs) -> None: self.kwargs = kwargs @classmethod - def setVars(cls, githubKey: str, repoName: str, orgName: str, test: bool) -> None: + def setVars(cls, githubKey: str, repoName: str, orgName: str, test: bool, useDiscord: bool = False, botToken: str = "") -> None: """Sets the necessary variables to make bug reports. Args: @@ -73,7 +82,7 @@ def setVars(cls, githubKey: str, repoName: str, orgName: str, test: bool) -> Non orgName (str): the name of the organization test (bool): whether to run in testing mode """ - cls.handlers[repoName] = BugHandler(githubKey, repoName, orgName, test) + cls.handlers[repoName] = BugHandler(githubKey, repoName, orgName, test, useDiscord, botToken) def __call__(self, func: callable) -> None: """Decorator that catches exceptions and sends a bug report to the github repository. @@ -200,6 +209,12 @@ def _sendBugReport(self, repoName: str, errorTitle: str, errorMessage: str) -> N # Execute the mutation to add the issue to the project asyncio.run(client.execute_async(query=addToProject, variables=variables, headers=headers)) + + # Send to Discord if applicable + if self.handlers[repoName].useDiscord: + discordBot = DiscordBot(self.handlers[repoName].botToken, self.handlers[repoName].channelId) + asyncio.run(discordBot.run()) + asyncio.run(discordBot.send_message( f"## {repoName}: {errorTitle}\n{errorMessage}")) else: print('\nOur team is already aware of this issue.\n') diff --git a/PyBugReporter/src/DiscordBot.py b/PyBugReporter/src/DiscordBot.py new file mode 100644 index 0000000..ac86083 --- /dev/null +++ b/PyBugReporter/src/DiscordBot.py @@ -0,0 +1,21 @@ +import discord + +class DiscordBot(discord.Client): + def __init__(self, token, channel_id): + self.token = token + self.channel_id = channel_id + intents = discord.Intents(send_messages = True, + change_nickname = True, + emojis = True, + guild_messages = True,) + super(intents=intents) + + async def send_message(self, message): + channel = self.get_channel(self.channel_id) + if channel: + await channel.send(message) + else: + print(f"Channel with ID {self.channel_id} not found.") + + def run(self): + self.run(self.token) \ No newline at end of file From e46d47af9ce95b781127dd1374995877e82193a1 Mon Sep 17 00:00:00 2001 From: Elijah Date: Thu, 15 May 2025 16:47:25 -0600 Subject: [PATCH 04/16] a bunch of fixes, it still doesnt work --- PyBugReporter/src/BugReporter.py | 53 ++++++++++++++++++-------------- PyBugReporter/src/DiscordBot.py | 23 ++++++++------ test.py | 9 +++++- 3 files changed, 52 insertions(+), 33 deletions(-) diff --git a/PyBugReporter/src/BugReporter.py b/PyBugReporter/src/BugReporter.py index e6eab78..62f8c78 100644 --- a/PyBugReporter/src/BugReporter.py +++ b/PyBugReporter/src/BugReporter.py @@ -2,7 +2,7 @@ import sys import traceback from functools import wraps -import DiscordBot +from PyBugReporter.src.DiscordBot import DiscordBot from python_graphql_client import GraphqlClient @@ -73,7 +73,7 @@ def __init__(self, repoName: str, extraInfo: bool, **kwargs) -> None: self.kwargs = kwargs @classmethod - def setVars(cls, githubKey: str, repoName: str, orgName: str, test: bool, useDiscord: bool = False, botToken: str = "") -> None: + def setVars(cls, githubKey: str, repoName: str, orgName: str, test: bool, useDiscord: bool = False, botToken: str = "", channelId: str = "") -> None: """Sets the necessary variables to make bug reports. Args: @@ -82,7 +82,7 @@ def setVars(cls, githubKey: str, repoName: str, orgName: str, test: bool, useDis orgName (str): the name of the organization test (bool): whether to run in testing mode """ - cls.handlers[repoName] = BugHandler(githubKey, repoName, orgName, test, useDiscord, botToken) + cls.handlers[repoName] = BugHandler(githubKey, repoName, orgName, test, useDiscord, botToken, channelId) def __call__(self, func: callable) -> None: """Decorator that catches exceptions and sends a bug report to the github repository. @@ -141,12 +141,21 @@ def _sendBugReport(self, repoName: str, errorTitle: str, errorMessage: str) -> N Args: errorTitle (str): the title of the error errorMessage (str): the error message - """ + """ + asyncio.run(self._sendBugReport_async(repoName, errorTitle, errorMessage)) + + async def _sendBugReport_async(self, repoName: str, errorTitle: str, errorMessage: str) -> None: + """Sends a bug report to the Github repository asynchronously. + + Args: + errorTitle (str): the title of the error + errorMessage (str): the error message + """ client = GraphqlClient(endpoint="https://api.github.com/graphql") headers = {"Authorization": f"Bearer {self.handlers[repoName].githubKey}"} # query variables - repoId = self._getRepoId(self.handlers[repoName]) + repoId = await self._getRepoId_async(self.handlers[repoName]) bugLabel = "LA_kwDOJ3JPj88AAAABU1q15w" autoLabel = "LA_kwDOJ3JPj88AAAABU1q2DA" @@ -180,10 +189,15 @@ def _sendBugReport(self, repoName: str, errorTitle: str, errorMessage: str) -> N } } - issueExists = self._checkIfIssueExists(self.handlers[repoName], errorTitle) + # Send to Discord if applicable + if self.handlers[repoName].useDiscord: + discordBot = DiscordBot(self.handlers[repoName].botToken, self.handlers[repoName].channelId) + await discordBot.send_message(f"## {repoName}: {errorTitle}\n{errorMessage}") - if (issueExists == False): - result = asyncio.run(client.execute_async(query=createIssue, variables=variables, headers=headers)) + issueExists = await self._checkIfIssueExists_async(self.handlers[repoName], errorTitle) + + if (not issueExists): + result = await client.execute_async(query=createIssue, variables=variables, headers=headers) print('\nThis error has been reported to the Tree Growth team.\n') issueId = result['data']['createIssue']['issue']['id'] # Extract the issue ID @@ -200,7 +214,7 @@ def _sendBugReport(self, repoName: str, errorTitle: str, errorMessage: str) -> N """ # Replace with your actual project ID - projectId = self.getProjectId(repoName, "Tree Growth Projects") + projectId = await self.getProjectId_async(repoName, "Tree Growth Projects") variables = { "projectId": projectId, @@ -208,18 +222,11 @@ def _sendBugReport(self, repoName: str, errorTitle: str, errorMessage: str) -> N } # Execute the mutation to add the issue to the project - asyncio.run(client.execute_async(query=addToProject, variables=variables, headers=headers)) - - # Send to Discord if applicable - if self.handlers[repoName].useDiscord: - discordBot = DiscordBot(self.handlers[repoName].botToken, self.handlers[repoName].channelId) - asyncio.run(discordBot.run()) - asyncio.run(discordBot.send_message( f"## {repoName}: {errorTitle}\n{errorMessage}")) + await client.execute_async(query=addToProject, variables=variables, headers=headers) else: print('\nOur team is already aware of this issue.\n') - def getProjectId(self, repoName: str, projectName: str) -> str: - """Retrieves the GitHub project ID for a specified repository and project name.""" + async def getProjectId_async(self, repoName: str, projectName: str) -> str: client = GraphqlClient(endpoint="https://api.github.com/graphql") headers = {"Authorization": f"Bearer {self.handlers[repoName].githubKey}"} @@ -243,7 +250,7 @@ def getProjectId(self, repoName: str, projectName: str) -> str: } # Execute the query - response = asyncio.run(client.execute_async(query=query, variables=variables, headers=headers)) + response = await client.execute_async(query=query, variables=variables, headers=headers) projects = response["data"]["repository"]["projectsV2"]["nodes"] # Find the project with the matching name and return its ID @@ -253,7 +260,7 @@ def getProjectId(self, repoName: str, projectName: str) -> str: raise ValueError(f"Project '{projectName}' not found in repository '{repoName}'.") - def _checkIfIssueExists(self, handler: BugHandler, errorTitle: str) -> bool: + async def _checkIfIssueExists_async(self, handler: BugHandler, errorTitle: str) -> bool: """Checks if an issue already exists in the repository. Args: @@ -291,7 +298,7 @@ def _checkIfIssueExists(self, handler: BugHandler, errorTitle: str) -> bool: "labels": autoLabel, } - result = asyncio.run(client.execute_async(query=findIssue, variables=variables, headers=headers)) + result = await client.execute_async(query=findIssue, variables=variables, headers=headers) nodes = result['data']['organization']['repository']['issues']['nodes'] index = 0 @@ -307,7 +314,7 @@ def _checkIfIssueExists(self, handler: BugHandler, errorTitle: str) -> bool: return issueExists - def _getRepoId(self, handler: BugHandler) -> str: + async def _getRepoId_async(self, handler: BugHandler) -> str: """Gets the repository ID. Args: @@ -333,7 +340,7 @@ def _getRepoId(self, handler: BugHandler) -> str: "name": handler.repoName } - repoID = asyncio.run(client.execute_async(query=getID, variables=variables, headers=headers)) + repoID = await client.execute_async(query=getID, variables=variables, headers=headers) return repoID['data']['repository']['id'] @classmethod diff --git a/PyBugReporter/src/DiscordBot.py b/PyBugReporter/src/DiscordBot.py index ac86083..3fb5fd5 100644 --- a/PyBugReporter/src/DiscordBot.py +++ b/PyBugReporter/src/DiscordBot.py @@ -3,19 +3,24 @@ class DiscordBot(discord.Client): def __init__(self, token, channel_id): self.token = token - self.channel_id = channel_id - intents = discord.Intents(send_messages = True, - change_nickname = True, - emojis = True, + self.channel_id = int(channel_id) + self._message = None + + intents = discord.Intents(emojis = True, + guild_reactions = True, + message_content = True, guild_messages = True,) - super(intents=intents) + super().__init__(intents=intents) async def send_message(self, message): + self._message = message + await self.start(self.token) + + async def on_ready(self): channel = self.get_channel(self.channel_id) if channel: - await channel.send(message) + await channel.send(self._message) + print(f"Sent message to channel {self.channel_id}") else: print(f"Channel with ID {self.channel_id} not found.") - - def run(self): - self.run(self.token) \ No newline at end of file + await self.close() \ No newline at end of file diff --git a/test.py b/test.py index e9c9a98..2ba4436 100644 --- a/test.py +++ b/test.py @@ -1,4 +1,6 @@ from PyBugReporter.src.BugReporter import BugReporter +import os +import dotenv import boto3 @@ -7,7 +9,12 @@ client = awsSession.client(service_name="ssm") response = client.get_parameter(Name='/growth-spurt/github/access-token', WithDecryption=True) token = response['Parameter']['Value'] - BugReporter.setVars(token, 'PyBugReporter', 'byuawsfhtl', False) + dotenv.load_dotenv("./.env") + token = os.getenv("GITHUB_TOKEN") + discordToken = os.getenv("DISCORD_TOKEN") + channelId = os.getenv("CHANNEL_ID") + + BugReporter.setVars(token, 'PyBugReporter', 'byuawsfhtl', False, True, discordToken, channelId) @BugReporter('PyBugReporter', extraInfo=True, env='test') def test(item, item2=None): From fa408ce58d38dcfbe0c1df588f58dd0eca678472 Mon Sep 17 00:00:00 2001 From: Elijah Date: Thu, 15 May 2025 18:18:42 -0600 Subject: [PATCH 05/16] final fixes! --- PyBugReporter/src/DiscordBot.py | 5 ++++- test.py | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/PyBugReporter/src/DiscordBot.py b/PyBugReporter/src/DiscordBot.py index 3fb5fd5..9309b5b 100644 --- a/PyBugReporter/src/DiscordBot.py +++ b/PyBugReporter/src/DiscordBot.py @@ -9,11 +9,13 @@ def __init__(self, token, channel_id): intents = discord.Intents(emojis = True, guild_reactions = True, message_content = True, - guild_messages = True,) + guild_messages = True, + guilds = True) super().__init__(intents=intents) async def send_message(self, message): self._message = message + print("Starting bot...") await self.start(self.token) async def on_ready(self): @@ -23,4 +25,5 @@ async def on_ready(self): print(f"Sent message to channel {self.channel_id}") else: print(f"Channel with ID {self.channel_id} not found.") + print("Shutting down bot...") await self.close() \ No newline at end of file diff --git a/test.py b/test.py index 2ba4436..14e4148 100644 --- a/test.py +++ b/test.py @@ -5,10 +5,10 @@ import boto3 if __name__ == "__main__": - awsSession = boto3.Session(region_name="us-west-2") - client = awsSession.client(service_name="ssm") - response = client.get_parameter(Name='/growth-spurt/github/access-token', WithDecryption=True) - token = response['Parameter']['Value'] + # awsSession = boto3.Session(region_name="us-west-2") + # client = awsSession.client(service_name="ssm") + # response = client.get_parameter(Name='/growth-spurt/github/access-token', WithDecryption=True) + # token = response['Parameter']['Value'] dotenv.load_dotenv("./.env") token = os.getenv("GITHUB_TOKEN") discordToken = os.getenv("DISCORD_TOKEN") From 271895ce99c3bdf766ce2253c7cfa76425cbeede Mon Sep 17 00:00:00 2001 From: Elijah Date: Thu, 15 May 2025 19:00:29 -0600 Subject: [PATCH 06/16] adding reactions --- PyBugReporter/src/BugReporter.py | 6 +++--- PyBugReporter/src/DiscordBot.py | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/PyBugReporter/src/BugReporter.py b/PyBugReporter/src/BugReporter.py index 62f8c78..78f471b 100644 --- a/PyBugReporter/src/BugReporter.py +++ b/PyBugReporter/src/BugReporter.py @@ -189,12 +189,12 @@ async def _sendBugReport_async(self, repoName: str, errorTitle: str, errorMessag } } + issueExists = await self._checkIfIssueExists_async(self.handlers[repoName], errorTitle) + # Send to Discord if applicable if self.handlers[repoName].useDiscord: discordBot = DiscordBot(self.handlers[repoName].botToken, self.handlers[repoName].channelId) - await discordBot.send_message(f"## {repoName}: {errorTitle}\n{errorMessage}") - - issueExists = await self._checkIfIssueExists_async(self.handlers[repoName], errorTitle) + await discordBot.send_message(f"## {repoName}: {errorTitle}\n{errorMessage}", issueExists) if (not issueExists): result = await client.execute_async(query=createIssue, variables=variables, headers=headers) diff --git a/PyBugReporter/src/DiscordBot.py b/PyBugReporter/src/DiscordBot.py index 9309b5b..ca37146 100644 --- a/PyBugReporter/src/DiscordBot.py +++ b/PyBugReporter/src/DiscordBot.py @@ -1,10 +1,14 @@ import discord +HISTORY_LIMIT = 20 +EMOJI = "‼" + class DiscordBot(discord.Client): def __init__(self, token, channel_id): self.token = token self.channel_id = int(channel_id) self._message = None + self._alreadySent = False intents = discord.Intents(emojis = True, guild_reactions = True, @@ -13,16 +17,23 @@ def __init__(self, token, channel_id): guilds = True) super().__init__(intents=intents) - async def send_message(self, message): + async def send_message(self, message, alreadySent = False): self._message = message + self._alreadySent = alreadySent print("Starting bot...") await self.start(self.token) async def on_ready(self): - channel = self.get_channel(self.channel_id) - if channel: + channel = await self.fetch_channel(self.channel_id) + if channel and not self._alreadySent: await channel.send(self._message) print(f"Sent message to channel {self.channel_id}") + elif channel and self._alreadySent: + historyIter = await channel.history(limit=HISTORY_LIMIT) + for message in historyIter: + if message.content == self._message: + await message.add_reaction(EMOJI) + break else: print(f"Channel with ID {self.channel_id} not found.") print("Shutting down bot...") From fa29c64725b3476db313ac240f093f994b3bbb69 Mon Sep 17 00:00:00 2001 From: Elijah Date: Thu, 15 May 2025 19:08:35 -0600 Subject: [PATCH 07/16] bot makes a future (promise) and adds it to the loop, then sets it to done when it's done --- PyBugReporter/src/DiscordBot.py | 42 +++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/PyBugReporter/src/DiscordBot.py b/PyBugReporter/src/DiscordBot.py index ca37146..a5203ad 100644 --- a/PyBugReporter/src/DiscordBot.py +++ b/PyBugReporter/src/DiscordBot.py @@ -1,3 +1,4 @@ +import asyncio import discord HISTORY_LIMIT = 20 @@ -9,6 +10,7 @@ def __init__(self, token, channel_id): self.channel_id = int(channel_id) self._message = None self._alreadySent = False + self._done_future = None intents = discord.Intents(emojis = True, guild_reactions = True, @@ -20,21 +22,31 @@ def __init__(self, token, channel_id): async def send_message(self, message, alreadySent = False): self._message = message self._alreadySent = alreadySent + self._done_future = asyncio.get_running_loop().create_future() print("Starting bot...") - await self.start(self.token) + # Start the bot as a background task + asyncio.create_task(self.start(self.token)) + # Wait until the message is sent and the bot is closed + await self._done_future async def on_ready(self): - channel = await self.fetch_channel(self.channel_id) - if channel and not self._alreadySent: - await channel.send(self._message) - print(f"Sent message to channel {self.channel_id}") - elif channel and self._alreadySent: - historyIter = await channel.history(limit=HISTORY_LIMIT) - for message in historyIter: - if message.content == self._message: - await message.add_reaction(EMOJI) - break - else: - print(f"Channel with ID {self.channel_id} not found.") - print("Shutting down bot...") - await self.close() \ No newline at end of file + try: + channel = await self.fetch_channel(self.channel_id) + if channel and not self._alreadySent: + await channel.send(self._message) + print(f"Sent message to channel {self.channel_id}") + elif channel and self._alreadySent: + async for message in channel.history(limit=HISTORY_LIMIT): + if message.content == self._message: + await message.add_reaction(EMOJI) + break + else: + print(f"Channel with ID {self.channel_id} not found.") + except Exception as e: + print(f"Error sending message: {e}") + finally: + print("Shutting down bot...") + await self.close() + # Mark the future as done so send_message can return + if self._done_future and not self._done_future.done(): + self._done_future.set_result(True) \ No newline at end of file From ecab60c6249ed1cad438e860a59261edba8390a4 Mon Sep 17 00:00:00 2001 From: Elijah Date: Thu, 15 May 2025 19:17:17 -0600 Subject: [PATCH 08/16] docs --- PyBugReporter/src/DiscordBot.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/PyBugReporter/src/DiscordBot.py b/PyBugReporter/src/DiscordBot.py index a5203ad..1c7ce82 100644 --- a/PyBugReporter/src/DiscordBot.py +++ b/PyBugReporter/src/DiscordBot.py @@ -5,6 +5,16 @@ EMOJI = "‼" class DiscordBot(discord.Client): + """ + A simple Discord bot that forwards the bug reports to a given Discord channel. + + Attributes: + token (str): The bot token. + channel_id (int): The ID of the channel to send messages to. + _message (str): The message to send. + _alreadySent (bool): Whether the message has already been sent. + _done_future (asyncio.Future): A future that is set when the bot is done. + """ def __init__(self, token, channel_id): self.token = token self.channel_id = int(channel_id) @@ -20,6 +30,13 @@ def __init__(self, token, channel_id): super().__init__(intents=intents) async def send_message(self, message, alreadySent = False): + """ + Sends a message to the specified channel by setting the variables and starting the bot, then turning it off when finished. + + Args: + message (str): The message to send. + alreadySent (bool): Whether the message has already been sent. + """ self._message = message self._alreadySent = alreadySent self._done_future = asyncio.get_running_loop().create_future() @@ -30,6 +47,9 @@ async def send_message(self, message, alreadySent = False): await self._done_future async def on_ready(self): + """ + Called when the bot is ready. Also sends the message to the specified channel, or reacts if it's been sent. + """ try: channel = await self.fetch_channel(self.channel_id) if channel and not self._alreadySent: From 27c9a3e5b2753a1c8ddadbdf20147b0a8b1586d3 Mon Sep 17 00:00:00 2001 From: Elijah Date: Thu, 15 May 2025 19:25:07 -0600 Subject: [PATCH 09/16] std check stuff (docs) --- PyBugReporter/src/BugReporter.py | 7 +++++-- PyBugReporter/src/DiscordBot.py | 27 +++++++++++++++++---------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/PyBugReporter/src/BugReporter.py b/PyBugReporter/src/BugReporter.py index 78f471b..abf3ffc 100644 --- a/PyBugReporter/src/BugReporter.py +++ b/PyBugReporter/src/BugReporter.py @@ -28,9 +28,9 @@ class BugHandler: test: bool = False useDiscord: bool = False botToken: str = '' - channelId: str = '' + channelId: str | int = '' - def __init__(self, githubKey: str, repoName: str, orgName: str, test: bool, useDiscord: bool = False, botToken = "", channelId: str = "") -> None: + def __init__(self, githubKey: str, repoName: str, orgName: str, test: bool, useDiscord: bool = False, botToken: str = "", channelId: str | int = "") -> None: """Saves the given information in the BugHandler object. Args: @@ -38,6 +38,9 @@ def __init__(self, githubKey: str, repoName: str, orgName: str, test: bool, useD repoName (str): the name of the repo to report to orgName (str): the organization of the repo test (bool): whether or not bugs in this code should actually be reported + useDiscord (bool): whether to send the bug report to Discord + botToken (str): the token for the Discord bot + channelId (str | int): the ID of the Discord channel to send messages to """ self.githubKey = githubKey self.repoName = repoName diff --git a/PyBugReporter/src/DiscordBot.py b/PyBugReporter/src/DiscordBot.py index 1c7ce82..9c2aed0 100644 --- a/PyBugReporter/src/DiscordBot.py +++ b/PyBugReporter/src/DiscordBot.py @@ -15,12 +15,19 @@ class DiscordBot(discord.Client): _alreadySent (bool): Whether the message has already been sent. _done_future (asyncio.Future): A future that is set when the bot is done. """ - def __init__(self, token, channel_id): + def __init__(self, token: str, channelId: str | int): + """ + Initializes the Discord bot with the given token and channel ID. + + Args: + token (str): The bot token. + channel_id (int): The ID of the channel to send messages to. + """ self.token = token - self.channel_id = int(channel_id) + self.channelId = int(channelId) self._message = None self._alreadySent = False - self._done_future = None + self._doneFuture = None intents = discord.Intents(emojis = True, guild_reactions = True, @@ -39,34 +46,34 @@ async def send_message(self, message, alreadySent = False): """ self._message = message self._alreadySent = alreadySent - self._done_future = asyncio.get_running_loop().create_future() + self._doneFuture = asyncio.get_running_loop().create_future() print("Starting bot...") # Start the bot as a background task asyncio.create_task(self.start(self.token)) # Wait until the message is sent and the bot is closed - await self._done_future + await self._doneFuture async def on_ready(self): """ Called when the bot is ready. Also sends the message to the specified channel, or reacts if it's been sent. """ try: - channel = await self.fetch_channel(self.channel_id) + channel = await self.fetch_channel(self.channelId) if channel and not self._alreadySent: await channel.send(self._message) - print(f"Sent message to channel {self.channel_id}") + print(f"Sent message to channel {self.channelId}") elif channel and self._alreadySent: async for message in channel.history(limit=HISTORY_LIMIT): if message.content == self._message: await message.add_reaction(EMOJI) break else: - print(f"Channel with ID {self.channel_id} not found.") + print(f"Channel with ID {self.channelId} not found.") except Exception as e: print(f"Error sending message: {e}") finally: print("Shutting down bot...") await self.close() # Mark the future as done so send_message can return - if self._done_future and not self._done_future.done(): - self._done_future.set_result(True) \ No newline at end of file + if self._doneFuture and not self._doneFuture.done(): + self._doneFuture.set_result(True) \ No newline at end of file From e5eb30300f995c9f068f919296734744828bd505 Mon Sep 17 00:00:00 2001 From: Elijah Date: Thu, 15 May 2025 19:27:39 -0600 Subject: [PATCH 10/16] more std check --- PyBugReporter/src/DiscordBot.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/PyBugReporter/src/DiscordBot.py b/PyBugReporter/src/DiscordBot.py index 9c2aed0..f424f28 100644 --- a/PyBugReporter/src/DiscordBot.py +++ b/PyBugReporter/src/DiscordBot.py @@ -9,19 +9,19 @@ class DiscordBot(discord.Client): A simple Discord bot that forwards the bug reports to a given Discord channel. Attributes: - token (str): The bot token. - channel_id (int): The ID of the channel to send messages to. - _message (str): The message to send. - _alreadySent (bool): Whether the message has already been sent. - _done_future (asyncio.Future): A future that is set when the bot is done. + token (str): bot token + channel_id (int): the ID of the channel to send messages to + _message (str): message to send + _alreadySent (bool): whether the message has already been sent + _done_future (asyncio.Future): a future that is set when the bot is done """ - def __init__(self, token: str, channelId: str | int): + def __init__(self, token: str, channelId: str | int) -> None: """ Initializes the Discord bot with the given token and channel ID. Args: - token (str): The bot token. - channel_id (int): The ID of the channel to send messages to. + token (str): bot token + channel_id (int): the ID of the channel to send messages to """ self.token = token self.channelId = int(channelId) From 2931b6ad7fa69137ec3bf3752eb8ed49e2b24d11 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 16 May 2025 20:44:53 +0000 Subject: [PATCH 11/16] Auto-updated version from 1.0.9b0.dev0 to 1.0.9b0.dev1 --- PyBugReporter/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PyBugReporter/_version.py b/PyBugReporter/_version.py index fda245a..47abd4a 100644 --- a/PyBugReporter/_version.py +++ b/PyBugReporter/_version.py @@ -1 +1 @@ -__version__ = '1.0.9b0.dev0' \ No newline at end of file +__version__ = '1.0.9b0.dev1' \ No newline at end of file From 5f6cb63e3b0a708bf343f94d074d13ec6598737d Mon Sep 17 00:00:00 2001 From: Elijah Date: Wed, 21 May 2025 11:34:30 -0600 Subject: [PATCH 12/16] added to the requirements.txt file --- PyBugReporter/requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PyBugReporter/requirements.txt b/PyBugReporter/requirements.txt index 38db440..a9ca88a 100644 --- a/PyBugReporter/requirements.txt +++ b/PyBugReporter/requirements.txt @@ -1 +1,2 @@ -python-graphql-client~=0.4.3 \ No newline at end of file +python-graphql-client~=0.4.3 +discord.py~=2.0.1 \ No newline at end of file From fe3f88923a691b30c4bcfcc9bf5f7fdd840c340c Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 21 May 2025 17:43:56 +0000 Subject: [PATCH 13/16] Auto-updated version from 1.0.9b0.dev1 to 1.0.9b0.dev2 --- PyBugReporter/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PyBugReporter/_version.py b/PyBugReporter/_version.py index 47abd4a..d228a15 100644 --- a/PyBugReporter/_version.py +++ b/PyBugReporter/_version.py @@ -1 +1 @@ -__version__ = '1.0.9b0.dev1' \ No newline at end of file +__version__ = '1.0.9b0.dev2' \ No newline at end of file From 72310edd11445178df33406dedabed97a398d8a6 Mon Sep 17 00:00:00 2001 From: Elijah Date: Wed, 21 May 2025 13:22:48 -0600 Subject: [PATCH 14/16] added compressable middle part of the error message so that we can have a short description for discord --- PyBugReporter/src/BugReporter.py | 26 +++++++++++++++++++----- test.py | 35 +++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/PyBugReporter/src/BugReporter.py b/PyBugReporter/src/BugReporter.py index abf3ffc..e1ac717 100644 --- a/PyBugReporter/src/BugReporter.py +++ b/PyBugReporter/src/BugReporter.py @@ -130,24 +130,40 @@ def _handleError(self, e: Exception, repoName: str, *args, **kwargs) -> None: if self.extraInfo: description += f"\nExtra Info: {self.kwargs}" + # shortened description for discord if too long (shortens the error text) + start = f"# {title}\n\nType: {excType}\nError text: " + compress = f"{e}\nTraceback: {traceback.format_exc()}" + end = f"\n\nFunction Name: {functionName}\nArguments: {args}\nKeyword Arguments: {kwargs}" + if self.extraInfo: + end += f"\nExtra Info: {self.kwargs}" + + staticLength = len(start) + len(end) + if staticLength > 2000: + shortDescription = f"# {title}\n\n" + description[:2000 - len(f"# {title}\n\n") - 3] + "..." + else: + shortDescription = f"{start}{compress[:2000 - staticLength]}{end}" + + print(f"SHORT DESCRIPTION with length {len(shortDescription)}:\n{shortDescription}") + + # Check if we need to send a bug report if not self.handlers[repoName].test: - self._sendBugReport(repoName, title, description) + self._sendBugReport(repoName, title, description, shortDescription) print(title) print(description) raise e - def _sendBugReport(self, repoName: str, errorTitle: str, errorMessage: str) -> None: + def _sendBugReport(self, repoName: str, errorTitle: str, errorMessage: str, shortErrorMessage: str) -> None: """Sends a bug report to the Github repository. Args: errorTitle (str): the title of the error errorMessage (str): the error message """ - asyncio.run(self._sendBugReport_async(repoName, errorTitle, errorMessage)) + asyncio.run(self._sendBugReport_async(repoName, errorTitle, errorMessage, shortErrorMessage)) - async def _sendBugReport_async(self, repoName: str, errorTitle: str, errorMessage: str) -> None: + async def _sendBugReport_async(self, repoName: str, errorTitle: str, errorMessage: str, shortErrorMessage: str) -> None: """Sends a bug report to the Github repository asynchronously. Args: @@ -197,7 +213,7 @@ async def _sendBugReport_async(self, repoName: str, errorTitle: str, errorMessag # Send to Discord if applicable if self.handlers[repoName].useDiscord: discordBot = DiscordBot(self.handlers[repoName].botToken, self.handlers[repoName].channelId) - await discordBot.send_message(f"## {repoName}: {errorTitle}\n{errorMessage}", issueExists) + await discordBot.send_message(shortErrorMessage, issueExists) if (not issueExists): result = await client.execute_async(query=createIssue, variables=variables, headers=headers) diff --git a/test.py b/test.py index 14e4148..52932a9 100644 --- a/test.py +++ b/test.py @@ -18,6 +18,39 @@ @BugReporter('PyBugReporter', extraInfo=True, env='test') def test(item, item2=None): - raise Exception("This is a test exception") + raise Exception(""" + This is a really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really + really really really really really really really really long test exception + """) test(None, item2='item2') \ No newline at end of file From 4c171102031380c85a4fbbc84e1042cd7ed66035 Mon Sep 17 00:00:00 2001 From: Elijah Date: Wed, 21 May 2025 13:36:06 -0600 Subject: [PATCH 15/16] traceback test --- test.py | 107 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 73 insertions(+), 34 deletions(-) diff --git a/test.py b/test.py index 52932a9..009d8a2 100644 --- a/test.py +++ b/test.py @@ -18,39 +18,78 @@ @BugReporter('PyBugReporter', extraInfo=True, env='test') def test(item, item2=None): - raise Exception(""" - This is a really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really - really really really really really really really really long test exception - """) + # raise Exception(""" + # This is a really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really + # really really really really really really really really long test exception + # """) + + def this(): + def exception(): + def has(): + def an(): + def insane(): + def traceback(): + def length(): + def that(): + def just(): + def keeps(): + def going(): + def on(): + def yep(): + def still(): + def more(): + def never(): + def do(): + def this(): + raise Exception("This is a test exception") + this() + do() + never() + more() + still() + yep() + on() + going() + keeps() + just() + that() + length() + traceback() + insane() + an() + has() + exception() + this() + test(None, item2='item2') \ No newline at end of file From eafd91f687be54de2f92da546a004593840e0ee1 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 22 May 2025 00:20:47 +0000 Subject: [PATCH 16/16] Auto-updated version from 1.0.9b0.dev2 to 1.0.9b0.dev3 --- PyBugReporter/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PyBugReporter/_version.py b/PyBugReporter/_version.py index d228a15..2f900c9 100644 --- a/PyBugReporter/_version.py +++ b/PyBugReporter/_version.py @@ -1 +1 @@ -__version__ = '1.0.9b0.dev2' \ No newline at end of file +__version__ = '1.0.9b0.dev3' \ No newline at end of file