diff --git a/plugins/explain.py b/plugins/explain.py index 1c37b838..883759b2 100644 --- a/plugins/explain.py +++ b/plugins/explain.py @@ -23,20 +23,23 @@ class Explain(BotPlugin): '\n- '.join(KNOWN_KEYS) ) - @re_botcmd(pattern=r'^explain\s+(\w+)(?:\s+to\s+@?([\w-]+))?$', + @re_botcmd(pattern=r'^explain(\s+(\w+)(?:\s+to\s+@?([\w-]+))?)?$', re_cmd_name_help='explain ', flags=re.IGNORECASE) def explain(self, msg, match): """Explain various terms.""" # Ignore QuotesBear + if match.group(1) is None: + return('Invalid command args. Usage: `{} ' + 'explain `.'.format(self.bot_config.BOT_PREFIX)) user = msg.frm.nick response = '' filename = 'explain/{}.jinja2.md'.format(match.group(1).lower()) - if match.group(1).lower() in self.KNOWN_KEYS: - if match.group(2): + if match.group(2).lower() in self.KNOWN_KEYS: + if match.group(3): response += '@{}: \n'.format(match.group(2)) response += tenv().get_template(filename).render( username=user, - target=match.group(2), + target=match.group(3), bot_prefix=self.bot_config.BOT_PREFIX, ) else: diff --git a/plugins/ghetto.py b/plugins/ghetto.py index 91ab5669..9a39afa6 100755 --- a/plugins/ghetto.py +++ b/plugins/ghetto.py @@ -10,15 +10,18 @@ class Ghetto(BotPlugin): Real talk yo """ - @re_botcmd(pattern=r'ghetto\s+(.+)', + @re_botcmd(pattern=r'ghetto(\s+(.+))?', re_cmd_name_help='ghetto ', flags=re.IGNORECASE) def ghetto(self, msg, match): """ Real talk yo """ + if match.group(1) is None: + return('Invalid command args. Usage: `{} ' + 'ghetto `'.format(self.bot_config.BOT_PREFIX)) rq = requests.post('http://www.gizoogle.net/textilizer.php', - data={'translatetext': match.group(1)}) + data={'translatetext': match.group(2)}) translated_text = re.search( r'', rq.text) diff --git a/plugins/git_stats.py b/plugins/git_stats.py index 5c39b5f7..c2080cba 100644 --- a/plugins/git_stats.py +++ b/plugins/git_stats.py @@ -18,13 +18,15 @@ class GitStats(LabHub): def __init__(self, bot, name=None): super().__init__(bot, name) - @re_botcmd(pattern=r'mergable\s+([^/]+)', # Ignore PyCodeStyleBear + @re_botcmd(pattern=r'mergable(\s+([^/]+))?', # Ignore PyCodeStyleBear re_cmd_name_help='pr list ', flags=re.IGNORECASE) def pr_list(self, msg, match): """List PRs ready to be merged.""" # Ignore QuotesBear - repo_name = match.groups(1)[0] - + if match.group(1) is None: + return('Invalid command args. Usage: `pr list ' + '`'.format(self.bot_config.BOT_PREFIX)) + repo_name = match.group(2) try: merge_requests = self.REPOS[repo_name].merge_requests except KeyError: diff --git a/plugins/labhub.py b/plugins/labhub.py index d1ca42e2..3577dc96 100644 --- a/plugins/labhub.py +++ b/plugins/labhub.py @@ -72,14 +72,18 @@ def TEAMS(self, new): self._teams = new # Ignore LineLengthBear, PycodestyleBear - @re_botcmd(pattern=r'^(?:(?:welcome)|(?:inv)|(?:invite))\s+(?:(?:@?([\w-]+)(?:\s*(?:to)\s+(\w+))?)|(me))$', + @re_botcmd(pattern=r'^(?:(?:welcome)|(?:inv)|(?:invite))(\s+(?:(?:@?([\w-]+)(?:\s*(?:to)\s+(\w+))?)|(me)))?$', re_cmd_name_help='invite [to team]') def invite_cmd(self, msg, match): """ Invite given user to given team. By default it invites to "newcomers" team. """ - invitee = match.group(1) + if match.group(1) is None: + return('Invalid command args. Usage: `{} (invite|inv) ' + '((member|member to [team])|me)`'.format( + self.bot_config.BOT_PREFIX)) + invitee = match.group(2) inviter = msg.frm.nick if invitee == 'me': @@ -94,7 +98,7 @@ def invite_cmd(self, msg, match): self.invited_users.add(user) return - team = 'newcomers' if match.group(2) is None else match.group(2) + team = 'newcomers' if match.group(3) is None else match.group(3) self.log.info('{} invited {} to {}'.format(inviter, invitee, team)) @@ -139,15 +143,18 @@ def callback_message(self, msg): self.TEAMS[self.GH_ORG_NAME + ' newcomers'].invite(user) self.invited_users.add(user) - @re_botcmd(pattern=r'(?:new|file) issue ([\w\-\.]+?)(?: |\n)(.+?)(?:$|\n((?:.|\n)*))', # Ignore LineLengthBear, PyCodeStyleBear + @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_issue_cmd(self, msg, match): """Create issues on GitHub and GitLab repositories.""" # Ignore QuotesBear, LineLengthBear, PyCodeStyleBear + if match.group(1) is None: + return('Invalid command args. Usage: `{} (new|file) issue repo-name' + ' title\n[description]`'.format(self.bot_config.BOT_PREFIX)) user = msg.frm.nick - repo_name = match.group(1) - iss_title = match.group(2) - iss_description = match.group(3) if match.group(3) is not None else '' + repo_name = match.group(2) + iss_title = match.group(3) + iss_description = match.group(4) if match.group(4) is not None else '' extra_msg = '\nOpened by @{username} at [{backend}]({msg_link})'.format( username=user, backend=self.bot_config.BACKEND, @@ -165,14 +172,17 @@ def create_issue_cmd(self, msg, match): target=user, ) - @re_botcmd(pattern=r'^unassign\s+https://(github|gitlab)\.com/([^/]+)/([^/]+)/issues/(\d+)', # Ignore LineLengthBear, PyCodeStyleBear + @re_botcmd(pattern=r'^unassign(\s+https://(github|gitlab)\.com/([^/]+)/([^/]+)/issues/(\d+))?', # Ignore LineLengthBear, PyCodeStyleBear re_cmd_name_help='unassign ', flags=re.IGNORECASE) def unassign_cmd(self, msg, match): """Unassign from an issue.""" # Ignore QuotesBear - org = match.group(2) - repo_name = match.group(3) - issue_number = match.group(4) + if match.group(1) is None: + return('Invalid command args. Usage: `{} unassign ' + '`'.format(self.bot_config.BOT_PREFIX)) + org = match.group(3) + repo_name = match.group(4) + issue_number = match.group(5) user = msg.frm.nick @@ -192,13 +202,15 @@ def unassign_cmd(self, msg, match): else: return 'You are not an assignee on the issue.' - @re_botcmd(pattern=r'mark\s+(wip|pending(?:(?:-|\s+)review)?\b)\s+https://(github|gitlab)\.com/([^/]+)/([^/]+)/(pull|merge_requests)/(\d+)', # Ignore LineLengthBear, PyCodeStyleBear + @re_botcmd(pattern=r'mark(\s+(wip|pending(?:(?:-|\s+)review)?\b)\s+https://(github|gitlab)\.com/([^/]+)/([^/]+)/(pull|merge_requests)/(\d+))?', # Ignore LineLengthBear, PyCodeStyleBear re_cmd_name_help='mark (wip|pending) ', flags=re.IGNORECASE) def mark_cmd(self, msg, match): """Mark a given PR/MR with status labels.""" # Ignore QuotesBear - state, host, org, repo_name, xr, number = match.groups() - + arg, state, host, org, repo_name, xr, number = match.groups() + if arg is None: + return('Invalid command args. Usage: `{} mark (wip|pending) ' + '`'.format(self.bot_config.BOT_PREFIX)) if host.lower() == 'github': assert xr.lower() == 'pull' elif host.lower() == 'gitlab': @@ -247,14 +259,17 @@ 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_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): """Assign to GitLab and GitHub issues.""" # Ignore QuotesBear - org = match.group(2) - repo_name = match.group(3)[:-1] - iss_number = match.group(4) + if match.group(1) is None: + return('Invalid command args. Usage: `{} assign ' + '`'.format(self.bot_config.BOT_PREFIX)) + org = match.group(3) + repo_name = match.group(4)[:-1] + iss_number = match.group(5) user = msg.frm.nick @@ -346,9 +361,12 @@ def community_state(pr_count: dict): else: return 'dead' - @re_botcmd(pattern=r'pr\s+stats\s+(\d+)(?:hours|hrs)') + @re_botcmd(pattern=r'pr\s+stats(\s+(\d+)(?:hours|hrs))?') def pr_stats(self, msg, match): - hours = match.group(1) + if match.group(1) is None: + return('Invalid command args. Usage: `{} pr stats ' + '(hours|hrs)`'.format(self.bot_config.BOT_PREFIX)) + hours = match.group(2) pr_count = dict() start = time.time() for count, (name, repo) in enumerate(self.gh_repos.items(), 1): diff --git a/plugins/lmgtfy.py b/plugins/lmgtfy.py index 05dc7fe6..15556e91 100644 --- a/plugins/lmgtfy.py +++ b/plugins/lmgtfy.py @@ -7,9 +7,12 @@ class Lmgtfy(BotPlugin): question rather than search it for themselves. """ - @re_botcmd(pattern=r'lmgtfy\s+(.+)', + @re_botcmd(pattern=r'lmgtfy(\s+(.+))?', re_cmd_name_help='lmgtfy ', template='lmgtfy.jinja2') def lmgtfy(self, msg, match): """I'm lazy, please google for me.""" # Ignore QuotesBear - return {'query': match.group(1)} + if match.group(1) is None: + return('Invalid command args. Usage: `{} lmgtfy ' + '`'.format(self.bot_config.BOT_PREFIX)) + return {'query': match.group(2)} diff --git a/tests/explain_test.py b/tests/explain_test.py index 997142d1..8e94003c 100644 --- a/tests/explain_test.py +++ b/tests/explain_test.py @@ -17,3 +17,4 @@ def test_explain(testbot): '@meet') testbot.assertCommand("!please explain review", "Command \"please\" / \"please explain\" not found.") + testbot.assertCommand("!explain", "Invalid command args.") diff --git a/tests/ghetto_test.py b/tests/ghetto_test.py index 06da4af2..e36b4a9c 100644 --- a/tests/ghetto_test.py +++ b/tests/ghetto_test.py @@ -8,6 +8,7 @@ @vcr.use_cassette('tests/cassettes/ghetto.yaml') def test_ghetto(testbot): testbot.assertCommand("!ghetto hi, whats up?", "hi, wassup?") + testbot.assertCommand("!ghetto", "Invalid command args.") with requests_mock.Mocker() as m: m.register_uri('POST', 'http://www.gizoogle.net/textilizer.php', text='test text which will not match with the regex') diff --git a/tests/labhub_test.py b/tests/labhub_test.py index 8bbb7771..a7793a0c 100644 --- a/tests/labhub_test.py +++ b/tests/labhub_test.py @@ -58,6 +58,7 @@ def test_invite_cmd(self): testbot.assertCommand('!invite meet to developers', ':poop:') + testbot.assertCommand('!invite', 'Invalid command args.') def test_hello_world_callback(self): teams = { @@ -118,6 +119,7 @@ def test_create_issue_cmd(self): testbot_public.assertCommand('!new issue coala title', 'repository that does not exist') + testbot_public.assertCommand('!new issue', 'Invalid command args.') def test_unassign_cmd(self): plugins.labhub.GitHub = create_autospec(IGitt.GitHub.GitHub.GitHub) plugins.labhub.GitLab = create_autospec(IGitt.GitLab.GitLab.GitLab) @@ -147,6 +149,7 @@ def test_unassign_cmd(self): testbot.assertCommand('!unassign https://gitlab.com/ala/am/issues/532', 'Repository not owned by our org.') + testbot.assertCommand('!unassign', 'Invalid command args.') def test_assign_cmd(self): plugins.labhub.GitHub = create_autospec(IGitt.GitHub.GitHub.GitHub) @@ -228,6 +231,10 @@ def test_assign_cmd(self): # unknown org testbot.assertCommand(cmd.format('coa', 'a', '23'), 'Repository not owned by our org.') + # command without args + testbot.assertCommand('!assign', 'Invalid command args.') + with self.assertRaises(queue.Empty): + testbot.pop_message() def test_mark_cmd(self): labhub, testbot = plugin_testbot(plugins.labhub.LabHub, logging.ERROR) @@ -275,6 +282,8 @@ def test_mark_cmd(self): 'marked pending review') testbot.assertCommand(cmd_github.format('pending review', 'coala', 'a', '23'), 'marked pending review') + # command without args + testbot.assertCommand('!mark', 'Invalid command args.') def test_alive(self): labhub, testbot = plugin_testbot(plugins.labhub.LabHub, logging.ERROR) @@ -312,6 +321,9 @@ def test_alive(self): testbot.assertCommand('!pr stats 3hours', '10 PRs opened in last 3 hours\n' 'The community is on fire') + testbot.assertCommand('!pr stats', 'Invalid command args.') + with self.assertRaises(queue.Empty): + testbot.pop_message() def test_invite_me(self): teams = { diff --git a/tests/lmgtfy_test.py b/tests/lmgtfy_test.py index a1092569..7dd8c383 100644 --- a/tests/lmgtfy_test.py +++ b/tests/lmgtfy_test.py @@ -10,3 +10,4 @@ def test_lmgtfy(testbot): testbot.assertCommand("!lmgtfy py c", "https://www.lmgtfy.com/?q=py c") + testbot.assertCommand("!lmgtfy", "Invalid command args")