blob: 6b3a4eed2c9c0793e3cca47b544c72490f3b4db6 [file] [log] [blame]
[email protected]fb2b8eb2009-04-23 21:03:421#!/usr/bin/env python
2# Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Generic presubmit checks that can be reused by other presubmit checks."""
7
8
[email protected]3410d912009-06-09 20:56:169### Description checks
10
[email protected]00c41e42009-05-12 21:43:1311def CheckChangeHasTestField(input_api, output_api):
12 """Requires that the changelist have a TEST= field."""
[email protected]e1a524f2009-05-27 14:43:4613 if input_api.change.TEST:
[email protected]00c41e42009-05-12 21:43:1314 return []
15 else:
16 return [output_api.PresubmitNotifyResult(
17 "Changelist should have a TEST= field. TEST=none is allowed.")]
18
19
20def CheckChangeHasBugField(input_api, output_api):
21 """Requires that the changelist have a BUG= field."""
[email protected]e1a524f2009-05-27 14:43:4622 if input_api.change.BUG:
[email protected]00c41e42009-05-12 21:43:1323 return []
24 else:
25 return [output_api.PresubmitNotifyResult(
26 "Changelist should have a BUG= field. BUG=none is allowed.")]
27
28
[email protected]fb2b8eb2009-04-23 21:03:4229def CheckChangeHasTestedField(input_api, output_api):
30 """Requires that the changelist have a TESTED= field."""
[email protected]e1a524f2009-05-27 14:43:4631 if input_api.change.TESTED:
[email protected]fb2b8eb2009-04-23 21:03:4232 return []
33 else:
34 return [output_api.PresubmitError("Changelist must have a TESTED= field.")]
35
36
37def CheckChangeHasQaField(input_api, output_api):
38 """Requires that the changelist have a QA= field."""
39 if input_api.change.QA:
40 return []
41 else:
42 return [output_api.PresubmitError("Changelist must have a QA= field.")]
43
44
45def CheckDoNotSubmitInDescription(input_api, output_api):
46 """Checks that the user didn't add 'DO NOT ' + 'SUBMIT' to the CL description.
47 """
48 keyword = 'DO NOT ' + 'SUBMIT'
49 if keyword in input_api.change.DescriptionText():
50 return [output_api.PresubmitError(
51 keyword + " is present in the changelist description.")]
52 else:
53 return []
54
55
[email protected]3410d912009-06-09 20:56:1656### Content checks
57
[email protected]fb2b8eb2009-04-23 21:03:4258def CheckDoNotSubmitInFiles(input_api, output_api):
59 """Checks that the user didn't add 'DO NOT ' + 'SUBMIT' to any files."""
60 keyword = 'DO NOT ' + 'SUBMIT'
[email protected]3410d912009-06-09 20:56:1661 # We want to check every text files, not just source files.
62 for f, line_num, line in input_api.RightHandSideLines(lambda x: x):
[email protected]fb2b8eb2009-04-23 21:03:4263 if keyword in line:
64 text = 'Found ' + keyword + ' in %s, line %s' % (f.LocalPath(), line_num)
65 return [output_api.PresubmitError(text)]
66 return []
67
68
[email protected]3410d912009-06-09 20:56:1669def CheckChangeHasNoCR(input_api, output_api, source_file_filter=None):
[email protected]44a17ad2009-06-08 14:14:3570 """Checks that there are no \r, \r\n (CR or CRLF) characters in any of the
[email protected]3410d912009-06-09 20:56:1671 source files to be submitted.
[email protected]44a17ad2009-06-08 14:14:3572 """
73 outputs = []
[email protected]3410d912009-06-09 20:56:1674 for f in input_api.AffectedSourceFiles(source_file_filter):
[email protected]44a17ad2009-06-08 14:14:3575 if '\r' in input_api.ReadFile(f, 'rb'):
76 outputs.append(output_api.PresubmitPromptWarning(
77 "Found a CR character in %s" % f.LocalPath()))
78 return outputs
79
80
[email protected]3410d912009-06-09 20:56:1681def CheckChangeHasNoTabs(input_api, output_api, source_file_filter=None):
[email protected]fb2b8eb2009-04-23 21:03:4282 """Checks that there are no tab characters in any of the text files to be
83 submitted.
84 """
[email protected]3410d912009-06-09 20:56:1685 for f, line_num, line in input_api.RightHandSideLines(source_file_filter):
[email protected]fb2b8eb2009-04-23 21:03:4286 if '\t' in line:
[email protected]89491382009-06-06 18:58:3987 return [output_api.PresubmitPromptWarning(
[email protected]fb2b8eb2009-04-23 21:03:4288 "Found a tab character in %s, line %s" %
89 (f.LocalPath(), line_num))]
90 return []
91
92
[email protected]3410d912009-06-09 20:56:1693def CheckLongLines(input_api, output_api, maxlen=80, source_file_filter=None):
[email protected]fb2b8eb2009-04-23 21:03:4294 """Checks that there aren't any lines longer than maxlen characters in any of
95 the text files to be submitted.
96 """
[email protected]fb2b8eb2009-04-23 21:03:4297 bad = []
[email protected]3410d912009-06-09 20:56:1698 for f, line_num, line in input_api.RightHandSideLines(source_file_filter):
[email protected]5c2720e2009-06-09 14:04:0899 # Allow lines with http://, https:// and #define/#pragma/#include/#if/#endif
100 # to exceed the maxlen rule.
101 if (len(line) > maxlen and
102 not 'http://' in line and
103 not 'https://' in line and
104 not line.startswith('#define') and
105 not line.startswith('#include') and
106 not line.startswith('#pragma') and
107 not line.startswith('#if') and
108 not line.startswith('#endif')):
[email protected]fb2b8eb2009-04-23 21:03:42109 bad.append(
110 '%s, line %s, %s chars' %
[email protected]1487d532009-06-06 00:22:57111 (f.LocalPath(), line_num, len(line)))
[email protected]fb2b8eb2009-04-23 21:03:42112 if len(bad) == 5: # Just show the first 5 errors.
113 break
114
115 if bad:
116 msg = "Found lines longer than %s characters (first 5 shown)." % maxlen
117 return [output_api.PresubmitPromptWarning(msg, items=bad)]
118 else:
119 return []
120
121
[email protected]1a0e3cb2009-06-10 18:03:04122def CheckChangeSvnEolStyle(input_api, output_api, source_file_filter=None):
[email protected]b7d46902009-06-10 14:12:10123 """Checks that the source files have svn:eol-style=LF."""
124 bad = filter(lambda f: f.scm == 'svn' and f.Property('svn:eol-style') != 'LF',
125 input_api.AffectedSourceFiles(source_file_filter))
126 if bad:
127 return [output_api.PresubmitError(
128 "Fix these files with svn svn:eol-style=LF", items=bad)]
129 return []
130
131
[email protected]3410d912009-06-09 20:56:16132### Other checks
133
134def CheckDoNotSubmit(input_api, output_api):
135 return (
136 CheckDoNotSubmitInDescription(input_api, output_api) +
137 CheckDoNotSubmitInFiles(input_api, output_api)
138 )
139
140
[email protected]fb2b8eb2009-04-23 21:03:42141def CheckTreeIsOpen(input_api, output_api, url, closed):
142 """Checks that an url's content doesn't match a regexp that would mean that
143 the tree is closed."""
[email protected]89491382009-06-06 18:58:39144 assert(input_api.is_committing)
[email protected]fb2b8eb2009-04-23 21:03:42145 try:
146 connection = input_api.urllib2.urlopen(url)
147 status = connection.read()
148 connection.close()
149 if input_api.re.match(closed, status):
150 long_text = status + '\n' + url
[email protected]89491382009-06-06 18:58:39151 return [output_api.PresubmitPromptWarning("The tree is closed.",
152 long_text=long_text)]
[email protected]fb2b8eb2009-04-23 21:03:42153 except IOError:
154 pass
155 return []
[email protected]7b305e82009-05-19 18:24:20156
157
[email protected]1487d532009-06-06 00:22:57158def _RunPythonUnitTests_LoadTests(input_api, module_name):
159 """Meant to be stubbed out during unit testing."""
160 module = __import__(module_name)
161 for part in module_name.split('.')[1:]:
162 module = getattr(module, part)
163 return input_api.unittest.TestLoader().loadTestsFromModule(module)._tests
164
[email protected]3410d912009-06-09 20:56:16165
[email protected]7b305e82009-05-19 18:24:20166def RunPythonUnitTests(input_api, output_api, unit_tests):
167 """Imports the unit_tests modules and run them."""
[email protected]d7dccf52009-06-06 18:51:58168 # We don't want to hinder users from uploading incomplete patches.
169 if input_api.is_committing:
170 message_type = output_api.PresubmitError
171 else:
172 message_type = output_api.PresubmitNotifyResult
[email protected]7b305e82009-05-19 18:24:20173 tests_suite = []
[email protected]7b305e82009-05-19 18:24:20174 outputs = []
175 for unit_test in unit_tests:
176 try:
[email protected]de0ba292009-06-06 19:43:27177 tests_suite.extend(_RunPythonUnitTests_LoadTests(input_api, unit_test))
[email protected]7b305e82009-05-19 18:24:20178 except ImportError:
[email protected]d7dccf52009-06-06 18:51:58179 outputs.append(message_type("Failed to load %s" % unit_test,
180 long_text=input_api.traceback.format_exc()))
[email protected]7b305e82009-05-19 18:24:20181
[email protected]c809ec22009-06-10 14:25:42182 buffer = input_api.cStringIO.StringIO()
183 results = input_api.unittest.TextTestRunner(stream=buffer, verbosity=0).run(
[email protected]1487d532009-06-06 00:22:57184 input_api.unittest.TestSuite(tests_suite))
[email protected]7b305e82009-05-19 18:24:20185 if not results.wasSuccessful():
[email protected]de0ba292009-06-06 19:43:27186 outputs.append(message_type("%d unit tests failed." %
[email protected]c809ec22009-06-10 14:25:42187 (len(results.failures) + len(results.errors)),
188 long_text=buffer.getvalue()))
[email protected]7b305e82009-05-19 18:24:20189 return outputs