diff --git a/plugins/labhub.py b/plugins/labhub.py index 7a284918..d4590685 100644 --- a/plugins/labhub.py +++ b/plugins/labhub.py @@ -7,7 +7,7 @@ import github3 from IGitt.GitHub.GitHub import GitHub, GitHubToken from IGitt.GitLab.GitLab import GitLab, GitLabPrivateToken -from errbot import BotPlugin, re_botcmd +from errbot import BotPlugin, arg_botcmd, re_botcmd from plugins import constants @@ -141,7 +141,7 @@ def callback_message(self, msg): @re_botcmd(pattern=r'(?:new|file) issue ([\w-]+?)(?: |\n)(.+?)(?:$|\n((?:.|\n)*))', # Ignore LineLengthBear, PyCodeStyleBear re_cmd_name_help='new issue repo-name title\n[description]', flags=re.IGNORECASE) - def create_issut_cmd(self, msg, match): + def create_issue_cmd(self, msg, match): """Create issues on GitHub and GitLab repositories.""" # Ignore QuotesBear, LineLengthBear, PyCodeStyleBear repo_name = match.group(1) iss_title = match.group(2) @@ -242,14 +242,65 @@ def mark_cmd(self, msg, match): bot_prefix=self.bot_config.BOT_PREFIX) ) - @re_botcmd(pattern=r'^assign\s+https://(github|gitlab)\.com/([^/]+)/([^/]+/)+issues/(\d+)', # Ignore LineLengthBear, PyCodeStyleBear - re_cmd_name_help='assign ', - flags=re.IGNORECASE) - def assign_cmd(self, msg, match): + @arg_botcmd('issue_reference', type=str) + def assign(self, msg, issue_reference): """Assign to GitLab and GitHub issues.""" # Ignore QuotesBear - org = match.group(2) - repo_name = match.group(3)[:-1] - iss_number = match.group(4) + + # Complete URL to issue + def process_full_url(issue_reference): + rgx = r'https://(github|gitlab)\.com/([^/]+)/([^/]+/)+issues/(\d+)' + m = re.fullmatch(rgx, issue_reference, re.IGNORECASE) + + if m is None: + return None + + return m.group(2), m.group(3)[:-1], m.group(4) + + # Short issue reference (e.g. `coala/corobo#12`) + def process_short_ref(issue_reference): + rgx = r'(.+?)/(.+?)#(\d+)' + m = re.fullmatch(rgx, issue_reference, re.IGNORECASE) + + if m is None: + return None + + return m.group(1), m.group(2), m.group(3) + + # Super short issue reference (e.g. `#1234`) + def process_super_short_ref(issue_reference): + issue_rgx = r'#(\d+)' + issue_reference_match = re.fullmatch(issue_rgx, issue_reference) + + if issue_reference_match is None: + return None + + roomname_rgx = r'(.+?)/(.+)' + roomname_match = re.fullmatch( + roomname_rgx, msg.to.name, re.IGNORECASE) + + if roomname_match is None: + return None + + return (roomname_match.group(1), + roomname_match.group(2), + issue_reference_match.group(1)) + + issue_processors = [ + process_full_url, + process_short_ref, + process_super_short_ref + ] + + for issue_processor in issue_processors: + issue_data = issue_processor(issue_reference) + + if issue_data is not None: + break + else: + yield 'Invalid issue.' + return + + org, repo_name, iss_number = issue_data user = msg.frm.nick diff --git a/tests/labhub_test.py b/tests/labhub_test.py index 272939ca..c50d31dd 100644 --- a/tests/labhub_test.py +++ b/tests/labhub_test.py @@ -1,9 +1,7 @@ import logging -import os import queue -import time import unittest -from unittest.mock import Mock, MagicMock, create_autospec, PropertyMock, patch +from unittest.mock import MagicMock, create_autospec, PropertyMock, patch import github3 import IGitt @@ -13,10 +11,10 @@ from errbot.backends.test import TestBot import plugins.labhub -from plugins.labhub import LabHub from tests.helper import plugin_testbot + class TestLabHub(unittest.TestCase): def setUp(self): @@ -148,6 +146,22 @@ def test_assign_cmd(self): 'coala developers': mock_dev_team, 'coala maintainers': mock_maint_team} + # invalid issue format + testbot.assertCommand('!assign this-is-an-invalid-issue-xyz', + 'Invalid issue.') + + # test short issue reference + mock_issue.assignees = tuple() + self.mock_team.is_member.return_value = False + testbot.assertCommand('!assign coala/a#23', + "You've been assigned to the issue") + + # test super-short issue reference + mock_issue.assignees = tuple() + self.mock_team.is_member.return_value = False + testbot.assertCommand('!assign #23', + "You've been assigned to the issue") + cmd = '!assign https://github.com/{}/{}/issues/{}' # no assignee, not newcomer mock_issue.assignees = tuple()