annotate contrib/check-commit @ 30706:2e4862646f02

repair: speed up stripping of many roots repair.strip() expects a set of root revisions to strip. It then builds the full set of descedants by walking the descandants of each. It is rare that more than a few roots get passed in, but if that happens, it will wastefully walk the changelog for each root. So let's just walk it once. I noticed this because the narrowhg extension was passing not only roots, but all the commits to strip. When there were tens of thousands of commits to strip, this resulted in quadratic behavior with that extension.
author Martin von Zweigbergk <martinvonz@google.com>
date Wed, 04 Jan 2017 10:07:12 -0800
parents 8e805cf27caa
children 2fb3ae89e4e1
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"),
28042
08e0c4082903 check-commit: wrap too long line
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28013
diff changeset
30 (beforepatch + r".*[(]issue \d\d\d",
08e0c4082903 check-commit: wrap too long line
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28013
diff changeset
31 "no space allowed between issue and number"),
27782
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
32 (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
33 (commitheader + r"# User [^@\n]+\n", "username is not an email address"),
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
34 (commitheader + r"(?!merge with )[^#]\S+[^:] ",
22043
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
35 "summary line doesn't start with 'topic: '"),
27782
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
36 (afterheader + r"[A-Z][a-z]\S+", "don't capitalize summary lines"),
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
37 (afterheader + r"[^\n]*: *[A-Z][a-z]\S+", "don't capitalize summary lines"),
30061
8e805cf27caa check-commit: allow underscore as commit topic
Mathias De Maré <mathias.de_mare@nokia.com>
parents: 29716
diff changeset
38 (afterheader + r"\S*[^A-Za-z0-9-_]\S*: ",
27692
e0465035def9 check-commit: try to curb bad commit summary keywords
Matt Mackall <mpm@selenic.com>
parents: 27199
diff changeset
39 "summary keyword should be most user-relevant one-word command or topic"),
27782
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
40 (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
41 (afterheader + r".{79,}", "summary line too long (limit is 78)"),
28013
e529b5f1b9e3 check-commit: check for double-addition of blank lines
Matt Mackall <mpm@selenic.com>
parents: 28012
diff changeset
42 (r"\n\+\n( |\+)\n", "adds double empty line"),
27782
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
43 (r"\n \n\+\n", "adds double empty line"),
29716
37b6f0ec6241 check-commit: allow underbars in cffi_-prefix function names
Augie Fackler <augie@google.com>
parents: 29164
diff changeset
44 # Forbid "_" in function name.
37b6f0ec6241 check-commit: allow underbars in cffi_-prefix function names
Augie Fackler <augie@google.com>
parents: 29164
diff changeset
45 #
37b6f0ec6241 check-commit: allow underbars in cffi_-prefix function names
Augie Fackler <augie@google.com>
parents: 29164
diff changeset
46 # We skip the check for cffi related functions. They use names mapping the
37b6f0ec6241 check-commit: allow underbars in cffi_-prefix function names
Augie Fackler <augie@google.com>
parents: 29164
diff changeset
47 # name of the C function. C function names may contain "_".
37b6f0ec6241 check-commit: allow underbars in cffi_-prefix function names
Augie Fackler <augie@google.com>
parents: 29164
diff changeset
48 (r"\n\+[ \t]+def (?!cffi)[a-z]+_[a-z]",
37b6f0ec6241 check-commit: allow underbars in cffi_-prefix function names
Augie Fackler <augie@google.com>
parents: 29164
diff changeset
49 "adds a function with foo_bar naming"),
22043
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
50 ]
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
51
27782
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
52 word = re.compile('\S')
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
28043
ac4684c21f73 check-commit: omit whitespace
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28042
diff changeset
58 def checkcommit(commit, node=None):
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
59 exitcode = 0
27781
2af351bd289c check-commit: support REVs as commandline arguments
timeless <timeless@mozdev.org>
parents: 27780
diff changeset
60 printed = node is None
27783
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
61 hits = []
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
62 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
63 for m in re.finditer(exp, commit):
27782
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
64 end = m.end()
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
65 trailing = re.search(r'(\\n)+$', exp)
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
66 if trailing:
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
67 end -= len(trailing.group()) / 2
27783
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
68 hits.append((end, exp, msg))
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
69 if hits:
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
70 hits.sort()
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
71 pos = 0
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
72 last = ''
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
73 for n, l in enumerate(commit.splitlines(True)):
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
74 pos += len(l)
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
75 while len(hits):
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
76 end, exp, msg = hits[0]
27782
7291c8165e33 check-commit: try to fix multiline handling
timeless <timeless@mozdev.org>
parents: 27781
diff changeset
77 if pos < end:
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
78 break
27783
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
79 if not printed:
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
80 printed = True
29164
91f35b1a34cf py3: make contrib/check-commit use print_function
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29163
diff changeset
81 print("node: %s" % node)
91f35b1a34cf py3: make contrib/check-commit use print_function
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29163
diff changeset
82 print("%d: %s" % (n, msg))
91f35b1a34cf py3: make contrib/check-commit use print_function
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29163
diff changeset
83 print(" %s" % nonempty(l, last)[:-1])
27783
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
84 if "BYPASS" not in os.environ:
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
85 exitcode = 1
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
86 del hits[0]
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
87 last = nonempty(l, last)
1d095371de47 check-commit: sort errors by line number
timeless <timeless@mozdev.org>
parents: 27782
diff changeset
88
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
89 return exitcode
22043
1274ff3f20a8 contrib: add check-commit hook script to sanity-check commits
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
90
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
91 def readcommit(node):
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
92 return os.popen("hg export %s" % node).read()
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
93
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
94 if __name__ == "__main__":
27781
2af351bd289c check-commit: support REVs as commandline arguments
timeless <timeless@mozdev.org>
parents: 27780
diff changeset
95 exitcode = 0
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
96 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
97
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
98 if node:
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
99 commit = readcommit(node)
27781
2af351bd289c check-commit: support REVs as commandline arguments
timeless <timeless@mozdev.org>
parents: 27780
diff changeset
100 exitcode = checkcommit(commit)
2af351bd289c check-commit: support REVs as commandline arguments
timeless <timeless@mozdev.org>
parents: 27780
diff changeset
101 elif sys.argv[1:]:
2af351bd289c check-commit: support REVs as commandline arguments
timeless <timeless@mozdev.org>
parents: 27780
diff changeset
102 for node in sys.argv[1:]:
2af351bd289c check-commit: support REVs as commandline arguments
timeless <timeless@mozdev.org>
parents: 27780
diff changeset
103 exitcode |= checkcommit(readcommit(node), node)
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
104 else:
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
105 commit = sys.stdin.read()
27781
2af351bd289c check-commit: support REVs as commandline arguments
timeless <timeless@mozdev.org>
parents: 27780
diff changeset
106 exitcode = checkcommit(commit)
27780
f47185f09533 check-commit: modularize
timeless <timeless@mozdev.org>
parents: 27779
diff changeset
107 sys.exit(exitcode)