tor/scripts/maint/lintChanges.py
2016-02-01 16:46:29 -05:00

82 lines
2.2 KiB
Python
Executable File

#!/usr/bin/python
from __future__ import print_function
from __future__ import with_statement
import sys
import re
import os
KNOWN_GROUPS=set([
"Minor bugfix",
"Minor bugfixes",
"Major bugfix",
"Major bugfixes",
"Minor feature",
"Minor features",
"Major feature",
"Major features",
"Testing",
"Documentation",
"Code simplification and refactoring",
"Removed features"])
def lintfile(fname):
have_warned = []
def warn(s):
if not have_warned:
have_warned.append(1)
print("{}:".format(fname))
print("\t{}".format(s))
m = re.search(r'(\d{3,})', os.path.basename(fname))
if m:
bugnum = m.group(1)
else:
bugnum = None
with open(fname) as f:
contents = f.read()
if bugnum and bugnum not in contents:
warn("bug number {} does not appear".format(bugnum))
lines = contents.split("\n")
isBug = ("bug" in lines[0] or "fix" in lines[0])
m = re.match(r'^[ ]{2}o ([^\(:]*)([^:]*):', contents)
if not m:
warn("header not in format expected")
elif m.group(1).strip() not in KNOWN_GROUPS:
warn("Weird header: %r"%m.group(1))
elif ( ("bugfix" in m.group(1) or "feature" in m.group(1)) and
("Removed" not in m.group(1)) and
'(' not in m.group(2)):
warn("Missing subcategory on %s"%m.group(1))
contents = " ".join(contents.split())
if re.search(r'\#\d{2,}', contents):
warn("don't use a # before ticket numbers")
if isBug and not re.search(r'(\d+)', contents):
warn("bugfix does not mention a number")
elif isBug and not re.search(r'Fixes ([a-z ]*)bug (\d+)', contents):
warn("bugfix does not say 'Fixes bug XXX'")
if re.search(r'[bB]ug (\d+)', contents):
if not re.search(r'[Bb]ugfix on ', contents):
warn("bugfix does not say 'bugfix on X.Y.Z'")
elif not re.search('[fF]ixes ([a-z ]*)bug (\d+); bugfix on ',
contents):
warn("bugfix incant is not semicoloned")
if __name__ == '__main__':
for fname in sys.argv[1:]:
if fname.endswith("~"):
continue
lintfile(fname)