##// END OF EJS Templates
check-commit: support REVs as commandline arguments...
timeless -
r27781:2af351bd default
parent child Browse files
Show More
@@ -1,66 +1,74 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # Copyright 2014 Matt Mackall <mpm@selenic.com>
3 # Copyright 2014 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # A tool/hook to run basic sanity checks on commits/patches for
5 # A tool/hook to run basic sanity checks on commits/patches for
6 # submission to Mercurial. Install by adding the following to your
6 # submission to Mercurial. Install by adding the following to your
7 # .hg/hgrc:
7 # .hg/hgrc:
8 #
8 #
9 # [hooks]
9 # [hooks]
10 # pretxncommit = contrib/check-commit
10 # pretxncommit = contrib/check-commit
11 #
11 #
12 # The hook can be temporarily bypassed with:
12 # The hook can be temporarily bypassed with:
13 #
13 #
14 # $ BYPASS= hg commit
14 # $ BYPASS= hg commit
15 #
15 #
16 # See also: https://mercurial-scm.org/wiki/ContributingChanges
16 # See also: https://mercurial-scm.org/wiki/ContributingChanges
17
17
18 import re, sys, os
18 import re, sys, os
19
19
20 errors = [
20 errors = [
21 (r"[(]bc[)]", "(BC) needs to be uppercase"),
21 (r"[(]bc[)]", "(BC) needs to be uppercase"),
22 (r"[(]issue \d\d\d", "no space allowed between issue and number"),
22 (r"[(]issue \d\d\d", "no space allowed between issue and number"),
23 (r"[(]bug(\d|\s)", "use (issueDDDD) instead of bug"),
23 (r"[(]bug(\d|\s)", "use (issueDDDD) instead of bug"),
24 (r"^# User [^@\n]+$", "username is not an email address"),
24 (r"^# User [^@\n]+$", "username is not an email address"),
25 (r"^# .*\n(?!merge with )[^#]\S+[^:] ",
25 (r"^# .*\n(?!merge with )[^#]\S+[^:] ",
26 "summary line doesn't start with 'topic: '"),
26 "summary line doesn't start with 'topic: '"),
27 (r"^# .*\n[A-Z][a-z]\S+", "don't capitalize summary lines"),
27 (r"^# .*\n[A-Z][a-z]\S+", "don't capitalize summary lines"),
28 (r"^# .*\n[^\n]*: *[A-Z][a-z]\S+", "don't capitalize summary lines"),
28 (r"^# .*\n[^\n]*: *[A-Z][a-z]\S+", "don't capitalize summary lines"),
29 (r"^# [^\n]*\n\S*[^A-Za-z0-9-]\S*: ",
29 (r"^# [^\n]*\n\S*[^A-Za-z0-9-]\S*: ",
30 "summary keyword should be most user-relevant one-word command or topic"),
30 "summary keyword should be most user-relevant one-word command or topic"),
31 (r"^# .*\n.*\.\s+$", "don't add trailing period on summary line"),
31 (r"^# .*\n.*\.\s+$", "don't add trailing period on summary line"),
32 (r"^# .*\n[^#].{78,}", "summary line too long (limit is 78)"),
32 (r"^# .*\n[^#].{78,}", "summary line too long (limit is 78)"),
33 (r"^\+\n \n", "adds double empty line"),
33 (r"^\+\n \n", "adds double empty line"),
34 (r"^ \n\+\n", "adds double empty line"),
34 (r"^ \n\+\n", "adds double empty line"),
35 (r"^\+[ \t]+def [a-z]+_[a-z]", "adds a function with foo_bar naming"),
35 (r"^\+[ \t]+def [a-z]+_[a-z]", "adds a function with foo_bar naming"),
36 ]
36 ]
37
37
38 def checkcommit(commit):
38 def checkcommit(commit, node = None):
39 exitcode = 0
39 exitcode = 0
40 printed = node is None
40 for exp, msg in errors:
41 for exp, msg in errors:
41 m = re.search(exp, commit, re.MULTILINE)
42 m = re.search(exp, commit, re.MULTILINE)
42 if m:
43 if m:
43 pos = 0
44 pos = 0
44 for n, l in enumerate(commit.splitlines(True)):
45 for n, l in enumerate(commit.splitlines(True)):
45 pos += len(l)
46 pos += len(l)
46 if pos >= m.end():
47 if pos >= m.end():
48 if not printed:
49 printed = True
50 print "node: %s" % node
47 print "%d: %s" % (n, msg)
51 print "%d: %s" % (n, msg)
48 print " %s" % l[:-1]
52 print " %s" % l[:-1]
49 if "BYPASS" not in os.environ:
53 if "BYPASS" not in os.environ:
50 exitcode = 1
54 exitcode = 1
51 break
55 break
52 return exitcode
56 return exitcode
53
57
54 def readcommit(node):
58 def readcommit(node):
55 return os.popen("hg export %s" % node).read()
59 return os.popen("hg export %s" % node).read()
56
60
57 if __name__ == "__main__":
61 if __name__ == "__main__":
62 exitcode = 0
58 node = os.environ.get("HG_NODE")
63 node = os.environ.get("HG_NODE")
59
64
60 if node:
65 if node:
61 commit = readcommit(node)
66 commit = readcommit(node)
67 exitcode = checkcommit(commit)
68 elif sys.argv[1:]:
69 for node in sys.argv[1:]:
70 exitcode |= checkcommit(readcommit(node), node)
62 else:
71 else:
63 commit = sys.stdin.read()
72 commit = sys.stdin.read()
64
73 exitcode = checkcommit(commit)
65 exitcode = checkcommit(commit)
66 sys.exit(exitcode)
74 sys.exit(exitcode)
General Comments 0
You need to be logged in to leave comments. Login now