Add script for check patch header, including inclusion, commit, category, bugzilla sections.
Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- pr_checkformat.py | 166 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 pr_checkformat.py
diff --git a/pr_checkformat.py b/pr_checkformat.py new file mode 100644 index 000000000000..9a799fe290d9 --- /dev/null +++ b/pr_checkformat.py @@ -0,0 +1,166 @@ +#!/usr/bin/python3 + +import os +import re +import sys +import subprocess +import shlex + +def exec_shell(cmd, workdir = None): + p = subprocess.Popen(shlex.split(cmd), stdin = subprocess.PIPE, stdout = subprocess.PIPE, + stderr = subprocess.PIPE, cwd = workdir) + output, err = p.communicate(timeout = 180) + return p.returncode, str(output, 'utf-8'), str(err, 'utf-8') + +commit_format = { + "[Backport]": + [ + [ + [r'mainline inclusion\n' ,r''], + [r'from mainline(-v\d*.\d*-rc\d*)?\n' ,r'miss "from mainline"'], + [r'commit [a-f0-9]{40}\n' ,r'miss commit or commit-id not 40char'], + [r'(category: .*\n)?' ,r''], + [r'bugzilla: .*\n' ,r'miss bugzilla'], + [r'(CVE: CVE-\d{4}-\d+\n)?' ,r''], + [r'\n' ,r'miss \n'], + [r'(Reference: .*\n)+' ,r'miss Reference'], + [r'\n' ,r'miss \n'], + [r'-{16,80}\n' ,r'miss parting line 16~80 "-"'], + [r'\n' ,r'miss \n'], + ], + [ + [r'stable inclusion\n' ,r''], + [r'from stable-v\d*.\d*.\d*\n' ,r'miss "from stable"'], + [r'commit [a-f0-9]{40}\n' ,r'miss commit or commit-id not 40char'], + [r'(category: .*\n)?' ,r''], + [r'bugzilla: .*\n' ,r'miss bugzilla'], + [r'(CVE: CVE-\d{4}-\d+\n)?' ,r''], + [r'\n' ,r'miss \n'], + [r'(Reference: .*\n)+' ,r'miss Reference'], + [r'\n' ,r'miss \n'], + [r'-{16,80}\n' ,r'miss parting line 16~80 "-"'], + [r'\n' ,r'miss \n'], + ], + [ + [r'.* inclusion\n' ,r'miss inclusion'], + [r'(category: .*\n)?' ,r''], + [r'bugzilla: .*\n' ,r'miss bugzilla'], + [r'(CVE: CVE-\d{4}-\d+\n)?' ,r''], + [r'\n' ,r'miss \n'], + [r'(Reference: .*\n)+' ,r'miss Reference'], + [r'\n' ,r'miss \n'], + [r'-{16,80}\n' ,r'miss parting line 16~80 "-"'], + [r'\n' ,r'miss \n'], + ], + + ], + } + +def check_employee_id(body): + m = re.findall(r'Signed-off-by.*\n', body) + if len(m) == 0: + return False, "miss Signed-off-by\n" + else: + for sig in m: + __m = re.findall(r'Signed-off-by.*[a-zA-Z][0-9]{8}.*@huawei.com', sig) + if __m: + return False, "incorrect Signed-off-by: %s\n"%(__m); + + m = re.findall(r'Reviewed-by.*\n', body) + for rew in m: + __m = re.findall(r'Reviewed-by.*[a-zA-Z][0-9]{8}.*@huawei.com', rew) + if __m: + return False, "incorrect Reviewed-by: %s\n"%(__m); + + m = re.findall(r'Author:.*\n', body) + for author in m: + __m = re.findall(r'Author.*[a-zA-Z][0-9]{8}.*@huawei.com', author) + if __m: + return False, "incorrect author: %s\n"%(__m); + + return True, "" + +def format_print(__format, line): + description = "" + for i in range(0, len(__format)): + __line = __format[i][0].replace("\n","") + if i == line: + __line += "\t<------" + __format[i][1] + description += __line + "\n" + return description + +def match_format(__format, body): + regex = r'' + match = False + + for i in range(0, len(__format)): + regex = regex + __format[i][0] + m = re.match(regex, body) + if not m: + return match, format_print(__format, i) + match = True + + return True, "" + +def error_description(description): + return description + +def do_checkformat(patch, workdir = None): + commit = patch.split(" ")[0] + + description = "" + + #check subject begin with hw + subject = exec_shell('git log --pretty=%s -n 1 %s'%('%s', commit), workdir)[1] + subject_type = subject.split(" ")[0] + if not subject_type in commit_format: + description = "subject should be begin with " + for __subject_type in commit_format: + description = description + __subject_type + "," + return False, error_description(description) + + #check Sig/Review/Author has Job number + body = exec_shell('git log -n 1 %s'%(commit), workdir)[1] + ret, description = check_employee_id(body) + if ret == False: + return False, error_description(description) + + #check commit message header + body = exec_shell('git log --pretty=%s -n 1 %s'%('%b', commit), workdir)[1] + for __format in commit_format[subject_type]: + match, description = match_format(__format, body) + if match == True: + if description == "": + return True, "checkformat success" + else: + return False, error_description(description) + + #not match any template + description = "do not match any template!\n" + for __subject_type in commit_format: + description = description + __subject_type + for __format in commit_format[__subject_type]: + description += "^^^^^^^^^^\n" + description += format_print(__format, -1) + description = description + "^^^^^^^^^^\n" + return False, error_description(description) + +def main(): + ForT = True + tag=sys.argv[1] + patches = os.popen("git log --oneline " + tag + "..HEAD").readlines() + for patch in patches: + ret, description = do_checkformat(patch) + if ret == False: + print("check " + patch + " failed") + print(description) + ForT = False + if ForT == False: + return False + + print("check " + str(len(patches)) + " patch(es) success") + return True + +if __name__ == "__main__": + # execute only if run as a script + main()