##// END OF EJS Templates
py3: make contrib/check-commit use print_function
Pulkit Goyal -
r29164:91f35b1a default
parent child Browse files
Show More
@@ -1,102 +1,102 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 from __future__ import absolute_import
18 from __future__ import absolute_import, print_function
19
19
20 import os
20 import os
21 import re
21 import re
22 import sys
22 import sys
23
23
24 commitheader = r"^(?:# [^\n]*\n)*"
24 commitheader = r"^(?:# [^\n]*\n)*"
25 afterheader = commitheader + r"(?!#)"
25 afterheader = commitheader + r"(?!#)"
26 beforepatch = afterheader + r"(?!\n(?!@@))"
26 beforepatch = afterheader + r"(?!\n(?!@@))"
27
27
28 errors = [
28 errors = [
29 (beforepatch + r".*[(]bc[)]", "(BC) needs to be uppercase"),
29 (beforepatch + r".*[(]bc[)]", "(BC) needs to be uppercase"),
30 (beforepatch + r".*[(]issue \d\d\d",
30 (beforepatch + r".*[(]issue \d\d\d",
31 "no space allowed between issue and number"),
31 "no space allowed between issue and number"),
32 (beforepatch + r".*[(]bug(\d|\s)", "use (issueDDDD) instead of bug"),
32 (beforepatch + r".*[(]bug(\d|\s)", "use (issueDDDD) instead of bug"),
33 (commitheader + r"# User [^@\n]+\n", "username is not an email address"),
33 (commitheader + r"# User [^@\n]+\n", "username is not an email address"),
34 (commitheader + r"(?!merge with )[^#]\S+[^:] ",
34 (commitheader + r"(?!merge with )[^#]\S+[^:] ",
35 "summary line doesn't start with 'topic: '"),
35 "summary line doesn't start with 'topic: '"),
36 (afterheader + r"[A-Z][a-z]\S+", "don't capitalize summary lines"),
36 (afterheader + r"[A-Z][a-z]\S+", "don't capitalize summary lines"),
37 (afterheader + r"[^\n]*: *[A-Z][a-z]\S+", "don't capitalize summary lines"),
37 (afterheader + r"[^\n]*: *[A-Z][a-z]\S+", "don't capitalize summary lines"),
38 (afterheader + r"\S*[^A-Za-z0-9-]\S*: ",
38 (afterheader + r"\S*[^A-Za-z0-9-]\S*: ",
39 "summary keyword should be most user-relevant one-word command or topic"),
39 "summary keyword should be most user-relevant one-word command or topic"),
40 (afterheader + r".*\.\s*\n", "don't add trailing period on summary line"),
40 (afterheader + r".*\.\s*\n", "don't add trailing period on summary line"),
41 (afterheader + r".{79,}", "summary line too long (limit is 78)"),
41 (afterheader + r".{79,}", "summary line too long (limit is 78)"),
42 (r"\n\+\n( |\+)\n", "adds double empty line"),
42 (r"\n\+\n( |\+)\n", "adds double empty line"),
43 (r"\n \n\+\n", "adds double empty line"),
43 (r"\n \n\+\n", "adds double empty line"),
44 (r"\n\+[ \t]+def [a-z]+_[a-z]", "adds a function with foo_bar naming"),
44 (r"\n\+[ \t]+def [a-z]+_[a-z]", "adds a function with foo_bar naming"),
45 ]
45 ]
46
46
47 word = re.compile('\S')
47 word = re.compile('\S')
48 def nonempty(first, second):
48 def nonempty(first, second):
49 if word.search(first):
49 if word.search(first):
50 return first
50 return first
51 return second
51 return second
52
52
53 def checkcommit(commit, node=None):
53 def checkcommit(commit, node=None):
54 exitcode = 0
54 exitcode = 0
55 printed = node is None
55 printed = node is None
56 hits = []
56 hits = []
57 for exp, msg in errors:
57 for exp, msg in errors:
58 for m in re.finditer(exp, commit):
58 for m in re.finditer(exp, commit):
59 end = m.end()
59 end = m.end()
60 trailing = re.search(r'(\\n)+$', exp)
60 trailing = re.search(r'(\\n)+$', exp)
61 if trailing:
61 if trailing:
62 end -= len(trailing.group()) / 2
62 end -= len(trailing.group()) / 2
63 hits.append((end, exp, msg))
63 hits.append((end, exp, msg))
64 if hits:
64 if hits:
65 hits.sort()
65 hits.sort()
66 pos = 0
66 pos = 0
67 last = ''
67 last = ''
68 for n, l in enumerate(commit.splitlines(True)):
68 for n, l in enumerate(commit.splitlines(True)):
69 pos += len(l)
69 pos += len(l)
70 while len(hits):
70 while len(hits):
71 end, exp, msg = hits[0]
71 end, exp, msg = hits[0]
72 if pos < end:
72 if pos < end:
73 break
73 break
74 if not printed:
74 if not printed:
75 printed = True
75 printed = True
76 print "node: %s" % node
76 print("node: %s" % node)
77 print "%d: %s" % (n, msg)
77 print("%d: %s" % (n, msg))
78 print " %s" % nonempty(l, last)[:-1]
78 print(" %s" % nonempty(l, last)[:-1])
79 if "BYPASS" not in os.environ:
79 if "BYPASS" not in os.environ:
80 exitcode = 1
80 exitcode = 1
81 del hits[0]
81 del hits[0]
82 last = nonempty(l, last)
82 last = nonempty(l, last)
83
83
84 return exitcode
84 return exitcode
85
85
86 def readcommit(node):
86 def readcommit(node):
87 return os.popen("hg export %s" % node).read()
87 return os.popen("hg export %s" % node).read()
88
88
89 if __name__ == "__main__":
89 if __name__ == "__main__":
90 exitcode = 0
90 exitcode = 0
91 node = os.environ.get("HG_NODE")
91 node = os.environ.get("HG_NODE")
92
92
93 if node:
93 if node:
94 commit = readcommit(node)
94 commit = readcommit(node)
95 exitcode = checkcommit(commit)
95 exitcode = checkcommit(commit)
96 elif sys.argv[1:]:
96 elif sys.argv[1:]:
97 for node in sys.argv[1:]:
97 for node in sys.argv[1:]:
98 exitcode |= checkcommit(readcommit(node), node)
98 exitcode |= checkcommit(readcommit(node), node)
99 else:
99 else:
100 commit = sys.stdin.read()
100 commit = sys.stdin.read()
101 exitcode = checkcommit(commit)
101 exitcode = checkcommit(commit)
102 sys.exit(exitcode)
102 sys.exit(exitcode)
General Comments 0
You need to be logged in to leave comments. Login now