Skip to content

Commit

Permalink
tools/verifygitlog.py: Add script for verifying commit message format.
Browse files Browse the repository at this point in the history
The main rules enforced are:
- At most 72 characters in the subject line, with a ": " in it.
- At most 75 characters per line in the body.
- No "noreply" email addresses.
  • Loading branch information
stinos authored and dpgeorge committed Jan 30, 2021
1 parent fca2730 commit d48860c
Showing 1 changed file with 122 additions and 0 deletions.
122 changes: 122 additions & 0 deletions tools/verifygitlog.py
@@ -0,0 +1,122 @@
#!/usr/bin/env python3

import re
import subprocess
import sys

verbosity = 0 # Show what's going on, 0 1 or 2.
suggestions = 1 # Set to 0 to not include lengthy suggestions in error messages.


def verbose(*args):
if verbosity:
print(*args)


def very_verbose(*args):
if verbosity > 1:
print(*args)


def git_log(pretty_format, *args):
# Delete pretty argument from user args so it doesn't interfere with what we do.
args = ["git", "log"] + [arg for arg in args if "--pretty" not in args]
args.append("--pretty=format:" + pretty_format)
very_verbose("git_log", *args)
# Generator yielding each output line.
for line in subprocess.Popen(args, stdout=subprocess.PIPE).stdout:
yield line.decode().rstrip("\r\n")


def verify(sha):
verbose("verify", sha)
errors = []
warnings = []

def error_text(err):
return "commit " + sha + ": " + err

def error(err):
errors.append(error_text(err))

def warning(err):
warnings.append(error_text(err))

# Author and committer email.
for line in git_log("%ae%n%ce", sha, "-n1"):
very_verbose("email", line)
if "noreply" in line:
error("Unwanted email address: " + line)

# Message body.
raw_body = list(git_log("%B", sha, "-n1"))
if not raw_body:
error("Message is empty")
return errors, warnings

# Subject line.
subject_line = raw_body[0]
very_verbose("subject_line", subject_line)
if not re.match(r"^[^!]+: [A-Z]+.+ .+\.$", subject_line):
error("Subject line should contain ': ' and end in '.': " + subject_line)
if len(subject_line) >= 73:
error("Subject line should be 72 or less characters: " + subject_line)

# Second one divides subject and body.
if len(raw_body) > 1 and raw_body[1]:
error("Second message line should be empty: " + raw_body[1])

# Message body lines.
for line in raw_body[2:]:
if len(line) >= 76:
error("Message lines should be 75 or less characters: " + line)

if not raw_body[-1].startswith("Signed-off-by: ") or "@" not in raw_body[-1]:
warning("Message should be signed-off")

return errors, warnings


def run(args):
verbose("run", *args)
has_errors = False
has_warnings = False
for sha in git_log("%h", *args):
errors, warnings = verify(sha)
has_errors |= any(errors)
has_warnings |= any(warnings)
for err in errors:
print("error:", err)
for err in warnings:
print("warning:", err)
if has_errors or has_warnings:
if suggestions:
print("See https://github.com/micropython/micropython/blob/master/CODECONVENTIONS.md")
else:
print("ok")
if has_errors:
sys.exit(1)


def show_help():
print("usage: verifygitlog.py [-v -n -h] ...")
print("-v : increase verbosity, can be speficied multiple times")
print("-n : do not print multi-line suggestions")
print("-h : print this help message and exit")
print("... : arguments passed to git log to retrieve commits to verify")
print(" see https://www.git-scm.com/docs/git-log")
print(" passing no arguments at all will verify all commits")
print("examples:")
print("verifygitlog.py -n10 # Check last 10 commits")
print("verifygitlog.py -v master..HEAD # Check commits since master")


if __name__ == "__main__":
args = sys.argv[1:]
verbosity = args.count("-v")
suggestions = args.count("-n") == 0
if "-h" in args:
show_help()
else:
args = [arg for arg in args if arg not in ["-v", "-n", "-h"]]
run(args)

0 comments on commit d48860c

Please sign in to comment.