annotate contrib/check-commit @ 45077:fa270dcbdb55

procutil: back out 8403cc54bc83 (make ....procutil.stderr unbuffered) Changeset 8403cc54bc83 introduced code that opens a second file object referring to the stderr file descriptor. This broke tests on Windows. The reason is that on Windows, sys.stderr is buffered and procutil.stderr closed the file descriptor when it got garbage collected before sys.stderr had the chance to flush buffered data. `procutil.stdout` had the same problem for a long time, but we didn’t realize, as in CI test runs, stdout is not a TTY and in this case no second file object is opened.
author Manuel Jacob <me@manueljacob.de>
date Sat, 11 Jul 2020 06:03:22 +0200
parents 99e231afc29c
children c102b704edb5
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
22043
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
1 #!/usr/bin/env python
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
2 #
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
3 # Copyright 2014 Matt Mackall <mpm@selenic.com>
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
4 #
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
5 # A tool/hook to run basic sanity checks on commits/patches for
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
6 # submission to Mercurial. Install by adding the following to your
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
7 # .hg/hgrc:
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
8 #
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
9 # [hooks]
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
10 # pretxncommit = contrib/check-commit
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
11 #
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
12 # The hook can be temporarily bypassed with:
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
13 #
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
14 # $ BYPASS= hg commit
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
15 #
26421
4b0fc75f9403 urls: bulk-change primary website URLs
Matt Mackall <mpm@selenic.com>
parents: 25643
diff changeset
16 # See also: https://mercurial-scm.org/wiki/ContributingChanges
22043
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
17
29164
91f35b1a34cf py3: make contrib/check-commit use print_function
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29163
diff changeset
18 from __future__ import absolute_import, print_function
29163
bf7fd815b083 py3: make contrib/check-commit use absolute_import
Pulkit Goyal <7895pulkit@gmail.com>
parents: 28043
diff changeset
19
bf7fd815b083 py3: make contrib/check-commit use absolute_import
Pulkit Goyal <7895pulkit@gmail.com>
parents: 28043
diff changeset
20 import os
bf7fd815b083 py3: make contrib/check-commit use absolute_import
Pulkit Goyal <7895pulkit@gmail.com>
parents: 28043
diff changeset
21 import re
bf7fd815b083 py3: make contrib/check-commit use absolute_import
Pulkit Goyal <7895pulkit@gmail.com>
parents: 28043
diff changeset
22 import sys
22043
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
23
27782
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
24 commitheader = r"^(?:# [^\n]*\n)*"
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
25 afterheader = commitheader + r"(?!#)"
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
26 beforepatch = afterheader + r"(?!\n(?!@@))"
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
27
22043
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
28 errors = [
27782
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
29 (beforepatch + r".*[(]bc[)]", "(BC) needs to be uppercase"),
43659
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
30 (
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
31 beforepatch + r".*[(]issue \d\d\d",
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
32 "no space allowed between issue and number",
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
33 ),
27782
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
34 (beforepatch + r".*[(]bug(\d|\s)", "use (issueDDDD) instead of bug"),
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
35 (commitheader + r"# User [^@\n]+\n", "username is not an email address"),
43659
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
36 (
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
37 commitheader + r"(?!merge with )[^#]\S+[^:] ",
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
38 "summary line doesn't start with 'topic: '",
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
39 ),
27782
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
40 (afterheader + r"[A-Z][a-z]\S+", "don't capitalize summary lines"),
40952
811f772b44aa check-commit: disallow capitalization only right after topic
Martin von Zweigbergk <martinvonz@google.com>
parents: 40308
diff changeset
41 (afterheader + r"^\S+: *[A-Z][a-z]\S+", "don't capitalize summary lines"),
43659
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
42 (
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
43 afterheader + r"\S*[^A-Za-z0-9-_]\S*: ",
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
44 "summary keyword should be most user-relevant one-word command or topic",
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
45 ),
27782
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
46 (afterheader + r".*\.\s*\n", "don't add trailing period on summary line"),
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
47 (afterheader + r".{79,}", "summary line too long (limit is 78)"),
22043
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
48 ]
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
49
41539
45a4789d3ff2 check-commit: use raw string for regular expression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 40952
diff changeset
50 word = re.compile(r'\S')
43659
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
51
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
52
27782
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
53 def nonempty(first, second):
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
54 if word.search(first):
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
55 return first
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
56 return second
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
57
43659
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
58
28043
ac4684c21f73 check-commit: omit whitespace
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28042
diff changeset
59 def checkcommit(commit, node=None):
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
60 exitcode = 0
27781
2af351bd289c check-commit: support REVs as commandline arguments
timeless <timeless@mozdev.org>
parents: 27780
diff changeset
61 printed = node is None
27783
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
62 hits = []
43659
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
63 signtag = (
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
64 afterheader + r'Added (tag [^ ]+|signature) for changeset [a-f0-9]{12}'
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
65 )
30843
2fb3ae89e4e1 contrib: fix check-commit to not reject commits from `hg sign` and `hg tag`
Augie Fackler <augie@google.com>
parents: 30061
diff changeset
66 if re.search(signtag, commit):
2fb3ae89e4e1 contrib: fix check-commit to not reject commits from `hg sign` and `hg tag`
Augie Fackler <augie@google.com>
parents: 30061
diff changeset
67 return 0
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
68 for exp, msg in errors:
28012
897b2fcf079f check-commit: scan for multiple instances of error patterns
Matt Mackall <mpm@selenic.com>
parents: 27783
diff changeset
69 for m in re.finditer(exp, commit):
27782
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
70 end = m.end()
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
71 trailing = re.search(r'(\\n)+$', exp)
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
72 if trailing:
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
73 end -= len(trailing.group()) / 2
27783
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
74 hits.append((end, exp, msg))
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
75 if hits:
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
76 hits.sort()
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
77 pos = 0
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
78 last = ''
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
79 for n, l in enumerate(commit.splitlines(True)):
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
80 pos += len(l)
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
81 while len(hits):
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
82 end, exp, msg = hits[0]
27782
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
83 if pos < end:
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
84 break
27783
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
85 if not printed:
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
86 printed = True
29164
91f35b1a34cf py3: make contrib/check-commit use print_function
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29163
diff changeset
87 print("node: %s" % node)
91f35b1a34cf py3: make contrib/check-commit use print_function
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29163
diff changeset
88 print("%d: %s" % (n, msg))
91f35b1a34cf py3: make contrib/check-commit use print_function
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29163
diff changeset
89 print(" %s" % nonempty(l, last)[:-1])
27783
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
90 if "BYPASS" not in os.environ:
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
91 exitcode = 1
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
92 del hits[0]
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
93 last = nonempty(l, last)
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
94
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
95 return exitcode
22043
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
96
43659
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
97
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
98 def readcommit(node):
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
99 return os.popen("hg export %s" % node).read()
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
100
43659
99e231afc29c black: blacken scripts
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43112
diff changeset
101
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
102 if __name__ == "__main__":
27781
2af351bd289c check-commit: support REVs as commandline arguments
timeless <timeless@mozdev.org>
parents: 27780
diff changeset
103 exitcode = 0
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
104 node = os.environ.get("HG_NODE")
22043
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
105
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
106 if node:
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
107 commit = readcommit(node)
27781
2af351bd289c check-commit: support REVs as commandline arguments
timeless <timeless@mozdev.org>
parents: 27780
diff changeset
108 exitcode = checkcommit(commit)
2af351bd289c check-commit: support REVs as commandline arguments
timeless <timeless@mozdev.org>
parents: 27780
diff changeset
109 elif sys.argv[1:]:
2af351bd289c check-commit: support REVs as commandline arguments
timeless <timeless@mozdev.org>
parents: 27780
diff changeset
110 for node in sys.argv[1:]:
2af351bd289c check-commit: support REVs as commandline arguments
timeless <timeless@mozdev.org>
parents: 27780
diff changeset
111 exitcode |= checkcommit(readcommit(node), node)
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
112 else:
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
113 commit = sys.stdin.read()
27781
2af351bd289c check-commit: support REVs as commandline arguments
timeless <timeless@mozdev.org>
parents: 27780
diff changeset
114 exitcode = checkcommit(commit)
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
115 sys.exit(exitcode)