aboutsummaryrefslogtreecommitdiffstats
path: root/bot/exts/evergreen/issues.py
diff options
context:
space:
mode:
authorGravatar Matteo Bertucci <[email protected]>2021-04-12 17:00:55 +0200
committerGravatar Matteo Bertucci <[email protected]>2021-04-12 17:00:55 +0200
commite187a3c67bcc93e8a688bac1a49541914f8b4871 (patch)
tree7789b632729d6e9ebfaa9d5845ed0f8af0c46523 /bot/exts/evergreen/issues.py
parentMerge branch 'main' into akarys/630/automatic-linking-everywhere (diff)
Allow automatic linking of issues outside of the python-discord organisation
Actions python-discord/organisation#345
Diffstat (limited to 'bot/exts/evergreen/issues.py')
-rw-r--r--bot/exts/evergreen/issues.py75
1 files changed, 34 insertions, 41 deletions
diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py
index 42ab97c3..6797559c 100644
--- a/bot/exts/evergreen/issues.py
+++ b/bot/exts/evergreen/issues.py
@@ -5,7 +5,7 @@ import typing as t
from dataclasses import dataclass
import discord
-from discord.ext import commands, tasks
+from discord.ext import commands
from bot.constants import (
Categories,
@@ -50,6 +50,21 @@ CODE_BLOCK_RE = re.compile(
# Maximum number of issues in one message
MAXIMUM_ISSUES = 5
+# Regex used when looking for automatic linking in messages
+AUTOMATIC_REGEX = re.compile(r"((?P<org>.+?)\/)?(?P<repo>.+?)#(?P<number>.+?)")
+
+
+@dataclass
+class FoundIssue:
+ """Dataclass representing an issue found by the regex."""
+
+ organisation: t.Optional[str]
+ repository: str
+ number: str
+
+ def __hash__(self) -> int:
+ return hash(self.organisation) + hash(self.repository) + hash(self.number)
+
@dataclass
class FetchError:
@@ -76,38 +91,11 @@ class Issues(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
self.repos = []
- self.repo_regex = None
- self.get_pydis_repos.start()
-
- @tasks.loop(minutes=30)
- async def get_pydis_repos(self) -> None:
- """
- Get all python-discord repositories on github.
-
- This task will update a pipe-separated list of repositories in self.repo_regex.
- """
- async with self.bot.http_session.get(
- REPOSITORY_ENDPOINT.format(org="python-discord"),
- headers=REQUEST_HEADERS
- ) as resp:
- if resp.status == 200:
- data = await resp.json()
- for repo in data:
- self.repos.append(repo["full_name"].split("/")[1])
- self.repo_regex = "|".join(self.repos)
- else:
- log.warning(f"Failed to get latest Pydis repositories. Status code {resp.status}")
@staticmethod
- def check_in_block(message: discord.Message, repo_issue: str) -> bool:
- """Check whether the <repo>#<issue> is in codeblocks."""
- block = re.findall(CODE_BLOCK_RE, message.content)
-
- if not block:
- return False
- elif "#".join(repo_issue.split(" ")) in "".join([*block[0]]):
- return True
- return False
+ def remove_codeblocks(message: str) -> str:
+ """Remove any codeblock in a message."""
+ return re.sub(CODE_BLOCK_RE, "", message)
async def fetch_issues(
self,
@@ -219,17 +207,19 @@ class Issues(commands.Cog):
@commands.Cog.listener()
async def on_message(self, message: discord.Message) -> None:
- """Command to retrieve issue(s) from a GitHub repository using automatic linking if matching <repo>#<issue>."""
- if not self.repo_regex:
- log.warning("repo_regex isn't ready, cannot look for issues.")
- return
+ """
+ Automatic issue linking.
+ Listener to retrieve issue(s) from a GitHub repository using automatic linking if matching <org>/<repo>#<issue>.
+ """
# Ignore bots
if message.author.bot:
return
- # `issues` will hold a list of two element tuples `(repository, issue_number)`
- issues = re.findall(fr"\b({self.repo_regex})#(\d+)\b", message.content)
+ issues = [
+ FoundIssue(*match.group("org", "repo", "number"))
+ for match in AUTOMATIC_REGEX.finditer(self.remove_codeblocks(message.content))
+ ]
links = []
if issues:
@@ -261,10 +251,13 @@ class Issues(commands.Cog):
return
for repo_issue in issues:
- if not self.check_in_block(message, " ".join(repo_issue)):
- result = await self.fetch_issues(repo_issue[1], repo_issue[0], "python-discord")
- if isinstance(result, IssueState):
- links.append(result)
+ result = await self.fetch_issues(
+ int(repo_issue.number),
+ repo_issue.repository,
+ repo_issue.organisation or "python-discord"
+ )
+ if isinstance(result, IssueState):
+ links.append(result)
if not links:
return