diff --git a/bear-requirements.txt b/bear-requirements.txt index 7593f0c9d7..25f973d4d1 100644 --- a/bear-requirements.txt +++ b/bear-requirements.txt @@ -8,6 +8,7 @@ cmakelint~=1.3 cppclean~=0.12.0 cpplint~=1.3 dennis~=0.8 +dnspython~=1.15.0 docutils-ast-writer~=0.1.2 eradicate~=0.1.6 guess-language-spirit~=0.5.2 @@ -24,6 +25,7 @@ proselint~=0.7.0 pycodestyle~=2.2 pydocstyle~=2.0 pyflakes~=1.5.0 +pyisemail~=1.3.1 pylint~=1.6 pyroma~=2.2.0 pyyaml~=3.12 diff --git a/bears/vcs/git/GitCommitBear.py b/bears/vcs/git/GitCommitBear.py index b8b22be586..b1946ae806 100644 --- a/bears/vcs/git/GitCommitBear.py +++ b/bears/vcs/git/GitCommitBear.py @@ -3,6 +3,7 @@ import shutil import os from urllib.parse import urlparse +from pyisemail import is_email from coalib.bears.GlobalBear import GlobalBear from dependency_management.requirements.PipRequirement import PipRequirement @@ -15,7 +16,8 @@ class GitCommitBear(GlobalBear): LANGUAGES = {'Git'} - REQUIREMENTS = {PipRequirement('nltk', '3.2')} + REQUIREMENTS = {PipRequirement('nltk', '3.2'), + PipRequirement('pyisemail', '1.3.1')} AUTHORS = {'The coala developers'} AUTHORS_EMAILS = {'coala-devel@googlegroups.com'} LICENSE = 'AGPL-3.0' @@ -223,7 +225,9 @@ def check_body(self, body, body_line_length: int=72, force_body: bool=False, ignore_length_regex: typed_list(str)=(), - body_regex: str=None): + body_regex: str=None, + valid_email_check: bool=True, + email_dns_check: bool=False): """ Checks the given commit body. @@ -236,6 +240,10 @@ def check_body(self, body, expressions in this list will be ignored. :param body_regex: If provided, checks the presence of regex in the commit body. + :param valid_email_check: If True, it checks if emails are in valid + format or not + :param email_dns_check: If True, it checks if domains in the emails + are valid or not """ if len(body) == 0: if force_body: @@ -260,6 +268,25 @@ def check_body(self, body, 'Commit body lines should not exceed {} ' 'characters.'.format(body_line_length)) + if valid_email_check: + result_message = 'Body contains these invalid emails:\n' + invalid_emails = False + for line in body: + for email in re.findall(r'\S*@\S*', line): + email_check = re.match(r"(^[a-zA-Z0-9_.+-]" + +r"+@[a-zA-Z0-9-]+\." + +r"[a-zA-Z0-9-.]+$)", email) + # if eamil do not match regex there is no need to + # look up dns + if email_dns_check and email_check: + email_check = not is_email(email, diagnose=True, + check_dns=True).ERROR_CODES + if not email_check: + invalid_emails = True + result_message += ' ' + email + '\n' + if invalid_emails: + yield Result(self, result_message) + def check_issue_reference(self, body, body_close_issue: bool=False, body_close_issue_full_url: bool=False, diff --git a/tests/vcs/git/GitCommitBearTest.py b/tests/vcs/git/GitCommitBearTest.py index eefe509770..eac605228b 100644 --- a/tests/vcs/git/GitCommitBearTest.py +++ b/tests/vcs/git/GitCommitBearTest.py @@ -288,6 +288,24 @@ def test_body_checks(self): body_regex=r'TICKER\s*CLOSE\s+[1-9][0-9]*'), []) self.assert_no_msgs() + # Testing if check recognises invalid emails + self.git_commit('Shortlog\n\n' + 'invalid#!format!*!@email.com\n' + 'another.*invalid@format\n' + 'validformat@email.check\n' + 'validdomain@gmail.com\n' + 'Fix 2017') + message = 'Body contains these invalid emails:\n' + message += ' invalid#!format!*!@email.com\n' + message += ' another.*invalid@format\n' + # Test with email_dns_check set to False + self.assertEqual(self.run_uut(), [message]) + # Test with email_dns_check set to True + message += " validformat@email.check\n" + self.assertEqual(self.run_uut(email_dns_check=True), [message]) + # Test with valid_email_check set to False + self.assertEqual(self.run_uut(valid_email_check=False), []) + def test_check_issue_reference(self): # Commit with no remotes configured self.git_commit('Shortlog\n\n'