Skip to content

Commit

Permalink
[qa] Added Commit Check openwisp#20
Browse files Browse the repository at this point in the history
  • Loading branch information
ppabcd committed Nov 27, 2018
1 parent 951ce45 commit b87ed20
Show file tree
Hide file tree
Showing 3 changed files with 264 additions and 2 deletions.
144 changes: 144 additions & 0 deletions openwisp_utils/qa.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,147 @@ def check_migration_name():
raise Exception("Migration %s %s in directory %s must "
"be renamed to something more descriptive."
% (file_, ', '.join(migrations), args.migration_path))


def _commit_check_args():
"""
Parse and return CLI arguements
"""
parser = argparse.ArgumentParser(description="Ensures migration files "
"created have a descriptive name. If "
"default name pattern is found, "
"raise exception!")
parser.add_argument("--message",
help="Commit message")
return parser.parse_args()


def check_commit_message():
args = _commit_check_args()
if not args.message:
raise Exception("CLI arguement `message` is required "
"but not found")
else:
short_desc = args.message.split("\n")[0]
if len(args.message.split("\n")) > 1:
long_desc = args.message.split("\n")[1:]
errors = []
# Check dot in end of the first line
if short_desc[len(short_desc.strip()) - 1].strip() == '.':
errors.append("Do not add a final dot at the end of the first line.")
# Check prefix
prefix = re.match(r'\[(.*?)\]', short_desc)
if not prefix:
errors.append(
"Add prefix in beginning of the commit. "
"Example: [module/file/feature]"
)
else:
# Check capital after prefix
commit_message_first = short_desc.replace(prefix.group(), '').strip()
if not commit_message_first[0].isupper():
errors.append("No capital letter after prefix")
# Check blank line before first line and second line
if 'long_desc' in locals():
if len(args.message.split("\n")) > 1:
if args.message.split("\n")[1] != '':
errors.append("No blank line before first "
"line and second line")
# Mentions an issues without closing it
message = ' '.join(long_desc)
# Check issues in long desc
long_desc_location = re.search(r'\#(\d+)', message)
if long_desc_location:
# message_check will return array of number issues when success
message_check = _check_word(message)
# Checked is variable type is array
if(not _is_array(message_check)):
errors.append(message_check)
# Check hastag if mention issues
checked = 0
for check in message_check:
# Checked is one of issues in short messages
short_desc_hastag = re.search(
r'\#' +
check.replace("#", ""),
short_desc
)
if short_desc_hastag:
checked = checked + 1
# If not mentioned issues at least 1 issues
if checked == 0:
errors.append("No mention issues in the short description")
# Check issues in short desc
short_desc_location = re.search(r'\#(\d+)', short_desc)
if short_desc_location:
# Get all issues in long description
long_desc_issues = _check_word(message)
if(not _is_array(long_desc_issues)):
errors.append("No mention issues in the long description")
checked = 0
# Foreach all issues
for issues in long_desc_issues:
# Check is issues in short description
long_desc_hastag = re.search(
r'\#' +
issues.replace("#", ""),
short_desc)
if long_desc_hastag:
checked = checked + 1
if checked == 0:
errors.append("No mention issues in the long description")
# Check is error
if len(errors) == 0:
body = "All check done, no errors."
else:
body = "You have errors with commit message: \n"
for e in errors:
body += "- " + e + "\n"
if(len(errors) > 0):
raise Exception(body)
else:
print(body)


def _is_array(var):
return isinstance(var, (list, tuple))


def _check_word(message):
parts = message.split(' ')
return_data = []
loc = []
i = 0
# Search hastag from parts
for part in parts:
hastag = re.search(r'\#(\d+)', part)
if hastag:
loc.append(i)
i = i + 1
# Check for num hastag with allowed words
num = 0
for location in loc:
word = parts[location - 1]
return_data.append(parts[location])
if(location > 2):
word2 = str(parts[location - 2] + " " + parts[location - 1])
allowed_words2 = [
'related to',
'refers to',
]
if((word2.lower() in allowed_words2)):
num = num + 1
continue
allowed_words = [
'fix',
'fixes',
'close',
'closes',
'ref',
'rel'
]
if (word.lower() in allowed_words):
num = num + 1
if num != len(loc):
return "Mentions an issues without closing it"
return return_data
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
packages=find_packages(exclude=['tests', 'docs']),
entry_points={
'console_scripts': [
'checkmigrations = openwisp_utils.qa:check_migration_name'
'checkmigrations = openwisp_utils.qa:check_migration_name',
'checkcommit = openwisp_utils.qa:check_commit_message',
],
},
include_package_data=True,
Expand Down
119 changes: 118 additions & 1 deletion tests/test_project/tests/test_qa.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# Mock is a standard library from python3.3-pre onwards
# from unittest.mock import patch
from mock import patch
from openwisp_utils.qa import check_migration_name
from openwisp_utils.qa import check_commit_message, check_migration_name

MIGRATIONS_DIR = path.join(path.dirname(path.dirname(path.abspath(__file__))), 'migrations')

Expand Down Expand Up @@ -44,5 +44,122 @@ def test_qa_call_check_migration_name_failure(self):
else:
self.fail('SystemExit or Exception not raised')

def test_qa_call_check_commit_message_pass(self):
options = [
[
'commitcheck',
'--message',
"[qa] Minor clean up operations"
],
[
'commitcheck',
'--message',
"[qa] Updated more file and fix problem #20\n\n"
"Added more files Fixes #20"
],
[
'commitcheck',
'--message',
"[qa] Improved Y #2\n\n"
"Related to #2"
],
[
'commitcheck',
'--message',
"[qa] Finished task #2\n\n"
"Closes #2\nRelated to #1"
],
[
'commitcheck',
'--message',
"[qa] Finished task #2\n\n"
"Related to #2\nCloses #1"
],
[
'commitcheck',
'--message',
"[qa] Finished task #2\n\n"
"Related to #2\nRelated to #1"
]
]
for option in options:
with patch('argparse._sys.argv', option):
check_commit_message()

def test_qa_call_check_commit_message_failure(self):
options = [
['commitcheck'],
[
'commitcheck',
'--message',
'Hello World',
],
[
'commitcheck',
'--message',
'[qa] hello World',
],
[
'commitcheck',
'--message',
'[qa] Hello World.',
],
[
'commitcheck',
'--message',
'[qa] Hello World.\nFixes #20',
],
[
'commitcheck',
'--message',
"[qa] Updated more file and fix problem #20"
"\n\nAdded more files #20"
],
[
'commitcheck',
'--message',
"[qa] Finished task #2\n\n"
"Failure #2\nRelated to #1"
],
[
'commitcheck',
'--message',
"[qa] Finished task\n\n"
"Failure #2\nRelated to #1"
],
[
'commitcheck',
'--message',
"[qa] Updated more file and fix problem\n\n"
"Added more files Fixes #20"
],
[
'commitcheck',
'--message',
"[qa] Improved Y\n\n"
"Related to #2"
],
[
'commitcheck',
'--message',
"[qa] Improved Y #2\n\n"
"Updated files"
],
[
'commitcheck',
'--message',
"[qa] Improved Y #20\n\n"
"Related to #32 Fixes #30 Fix #40"
],
]
for option in options:
with patch('argparse._sys.argv', option):
try:
check_commit_message()
except (SystemExit, Exception):
pass
else:
self.fail('SystemExit or Exception not raised')

def tearDown(self):
os.unlink(self._test_migration_file)

0 comments on commit b87ed20

Please sign in to comment.