-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fixup! CI: Check commit message compliance
- Loading branch information
Showing
3 changed files
with
137 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
#! /bin/env python3 | ||
|
||
import git | ||
import re | ||
|
||
has_error = False | ||
|
||
LOG_ERROR = 100 | ||
LOG_WARNING = 200 | ||
LOG_INFO = 300 | ||
current_commit = None | ||
|
||
def blog(level, txt): | ||
if level == LOG_ERROR: | ||
global has_error | ||
has_error = True | ||
s_level = "Error: " | ||
elif level == LOG_WARNING: | ||
s_level = "Warning: " | ||
elif level == LOG_INFO: | ||
s_level = "Info: " | ||
print('{level}commit {hexsha}: {txt}'.format(level = s_level, hexsha = current_commit.hexsha[:9], txt = txt)) | ||
|
||
def find_directory_name(name, tree, max_depth): | ||
for t in tree.trees: | ||
if name == t.name: | ||
return True | ||
if max_depth > 1: | ||
for t in tree.trees: | ||
if find_directory_name(name, t, max_depth - 1): | ||
return True | ||
for b in tree.blobs: | ||
if name == b.name: | ||
return True | ||
return False | ||
|
||
def check_path(path, tree): | ||
paths = path.split('/', 1) | ||
name = paths[0] | ||
if len(paths) == 1: | ||
return find_directory_name(name, tree, 1) | ||
else: | ||
for t in tree.trees: | ||
if name == t.name: | ||
return check_path(paths[1], t) | ||
return False | ||
|
||
def find_submodule_name(name, submodules): | ||
for s in submodules: | ||
sname = s.name.split('/')[-1] | ||
if name == sname: | ||
return True | ||
|
||
def check_module_names(names): | ||
for name in names: | ||
if name.find('/') >= 0: | ||
if check_path(name, current_commit.tree): | ||
return True | ||
else: | ||
if find_directory_name(name, current_commit.tree, 3): | ||
return True | ||
# TODO: Cannot handle removed submodules. Implement to parse .gitmodules file. | ||
if find_submodule_name(name, current_commit.repo.submodules): | ||
return True | ||
blog(LOG_ERROR, "unknown module name '%s'" % name) | ||
|
||
def check_message_title(title): | ||
global has_error | ||
title_split = title.split(': ', 1) | ||
if len(title_split) == 2: | ||
check_module_names(re.split(r', *', title_split[0])) | ||
title_text = title_split[1] | ||
else: | ||
title_text = title_split[0] | ||
|
||
if len(title) > 72: | ||
blog(LOG_ERROR, 'Too long title: %s' % title) | ||
|
||
if len(title_text) > 50: | ||
blog(LOG_WARNING, 'Too long title excluding module name: %s' % title_text) | ||
|
||
if not re.match(r"([A-Z][a-z]*(-[a-z]+)*|Don't) ", title_text): | ||
blog(LOG_ERROR, 'Invalid first word: %s' % title_text.split(' ', 1)[0]) | ||
has_error = True | ||
|
||
def check_message_body(body): | ||
for line in body.split('\n'): | ||
if len(line) > 72 and line.find(' ') > 0: | ||
blog(LOG_ERROR, 'Too long description in a line: %s' % line) | ||
pass | ||
|
||
def check_message(c): | ||
msg = c.message.split('\n', 2) | ||
if len(msg) == 0: | ||
blog(LOG_ERROR, 'Commit message is empty.') | ||
return True | ||
|
||
if re.match(r'Revert ', msg[0]): | ||
return False | ||
if re.match(r'Merge [0-9a-f]{40} into [0-9a-f]{40}$', msg[0]): | ||
return False | ||
if re.match(r'Merge pull request', msg[0]): | ||
return False | ||
|
||
if len(msg) > 0: | ||
check_message_title(msg[0]) | ||
if len(msg) > 1: | ||
if len(msg[1]): | ||
blog(LOG_ERROR, '2nd line is not empty.') | ||
if len(msg) > 2: | ||
check_message_body(msg[2]) | ||
return has_error | ||
|
||
def main(): | ||
import sys | ||
import argparse | ||
parser = argparse.ArgumentParser(prog='check-log-msg.py', description='Log message compliance checker') | ||
parser.add_argument('commits') | ||
args = parser.parse_args() | ||
|
||
repo = git.Repo('.') | ||
global has_error | ||
for c in repo.iter_commits(args.commits): # '27.1.0-rc2..27.1.0'): | ||
global current_commit | ||
current_commit = c | ||
check_message(c) | ||
if has_error: | ||
sys.exit(1) | ||
|
||
if __name__ == '__main__': | ||
ret = main() |