check-commit
74 lines
| 2.4 KiB
| text/plain
|
TextLexer
/ contrib / check-commit
Matt Mackall
|
r22043 | #!/usr/bin/env python | ||
# | ||||
# Copyright 2014 Matt Mackall <mpm@selenic.com> | ||||
# | ||||
# A tool/hook to run basic sanity checks on commits/patches for | ||||
# submission to Mercurial. Install by adding the following to your | ||||
# .hg/hgrc: | ||||
# | ||||
# [hooks] | ||||
# pretxncommit = contrib/check-commit | ||||
# | ||||
# The hook can be temporarily bypassed with: | ||||
# | ||||
# $ BYPASS= hg commit | ||||
# | ||||
Matt Mackall
|
r26421 | # See also: https://mercurial-scm.org/wiki/ContributingChanges | ||
Matt Mackall
|
r22043 | |||
import re, sys, os | ||||
errors = [ | ||||
(r"[(]bc[)]", "(BC) needs to be uppercase"), | ||||
(r"[(]issue \d\d\d", "no space allowed between issue and number"), | ||||
Pierre-Yves David
|
r24703 | (r"[(]bug(\d|\s)", "use (issueDDDD) instead of bug"), | ||
Matt Mackall
|
r22043 | (r"^# User [^@\n]+$", "username is not an email address"), | ||
(r"^# .*\n(?!merge with )[^#]\S+[^:] ", | ||||
"summary line doesn't start with 'topic: '"), | ||||
(r"^# .*\n[A-Z][a-z]\S+", "don't capitalize summary lines"), | ||||
Eric Sumner
|
r24049 | (r"^# .*\n[^\n]*: *[A-Z][a-z]\S+", "don't capitalize summary lines"), | ||
Matt Mackall
|
r27692 | (r"^# [^\n]*\n\S*[^A-Za-z0-9-]\S*: ", | ||
"summary keyword should be most user-relevant one-word command or topic"), | ||||
Matt Mackall
|
r22043 | (r"^# .*\n.*\.\s+$", "don't add trailing period on summary line"), | ||
timeless
|
r27779 | (r"^# .*\n[^#].{78,}", "summary line too long (limit is 78)"), | ||
Matt Mackall
|
r22058 | (r"^\+\n \n", "adds double empty line"), | ||
Yuya Nishihara
|
r25643 | (r"^ \n\+\n", "adds double empty line"), | ||
Gregory Szorc
|
r25379 | (r"^\+[ \t]+def [a-z]+_[a-z]", "adds a function with foo_bar naming"), | ||
Matt Mackall
|
r22043 | ] | ||
timeless
|
r27781 | def checkcommit(commit, node = None): | ||
timeless
|
r27780 | exitcode = 0 | ||
timeless
|
r27781 | printed = node is None | ||
timeless
|
r27780 | for exp, msg in errors: | ||
m = re.search(exp, commit, re.MULTILINE) | ||||
if m: | ||||
pos = 0 | ||||
for n, l in enumerate(commit.splitlines(True)): | ||||
pos += len(l) | ||||
if pos >= m.end(): | ||||
timeless
|
r27781 | if not printed: | ||
printed = True | ||||
print "node: %s" % node | ||||
timeless
|
r27780 | print "%d: %s" % (n, msg) | ||
print " %s" % l[:-1] | ||||
if "BYPASS" not in os.environ: | ||||
exitcode = 1 | ||||
break | ||||
return exitcode | ||||
Matt Mackall
|
r22043 | |||
timeless
|
r27780 | def readcommit(node): | ||
return os.popen("hg export %s" % node).read() | ||||
if __name__ == "__main__": | ||||
timeless
|
r27781 | exitcode = 0 | ||
timeless
|
r27780 | node = os.environ.get("HG_NODE") | ||
Matt Mackall
|
r22043 | |||
timeless
|
r27780 | if node: | ||
commit = readcommit(node) | ||||
timeless
|
r27781 | exitcode = checkcommit(commit) | ||
elif sys.argv[1:]: | ||||
for node in sys.argv[1:]: | ||||
exitcode |= checkcommit(readcommit(node), node) | ||||
timeless
|
r27780 | else: | ||
commit = sys.stdin.read() | ||||
timeless
|
r27781 | exitcode = checkcommit(commit) | ||
timeless
|
r27780 | sys.exit(exitcode) | ||