blob: fa2f98f5c907302c99d7fc63146150501cfa4810 [file] [log] [blame]
[email protected]377ab1da2011-03-17 15:36:281# Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
[email protected]50d7d721e2009-11-15 17:56:188for more details about the presubmit API built into gcl.
[email protected]ca8d19842009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
14 r"^net/tools/spdyshark/[\\\/].*",
15 r"^skia[\\\/].*",
16 r"^v8[\\\/].*",
17 r".*MakeFile$",
[email protected]4306417642009-06-11 00:33:4018)
[email protected]ca8d19842009-02-19 16:33:1219
[email protected]ca8d19842009-02-19 16:33:1220
[email protected]eea609a2011-11-18 13:10:1221_TEST_ONLY_WARNING = (
22 'You might be calling functions intended only for testing from\n'
23 'production code. It is OK to ignore this warning if you know what\n'
24 'you are doing, as the heuristics used to detect the situation are\n'
25 'not perfect. The commit queue will not block on this warning.\n'
26 'Email [email protected] if you have questions.')
27
28
29
[email protected]22c9bd72011-03-27 16:47:3930def _CheckNoInterfacesInBase(input_api, output_api):
[email protected]6a4c8e682010-12-19 03:31:3431 """Checks to make sure no files in libbase.a have |@interface|."""
[email protected]839c1392011-04-29 20:15:1932 pattern = input_api.re.compile(r'^\s*@interface', input_api.re.MULTILINE)
[email protected]6a4c8e682010-12-19 03:31:3433 files = []
[email protected]22c9bd72011-03-27 16:47:3934 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
[email protected]a766a1322011-09-08 20:46:0535 if (f.LocalPath().startswith('base/') and
[email protected]0b2f07b02011-05-02 17:29:0036 not f.LocalPath().endswith('_unittest.mm')):
[email protected]6a4c8e682010-12-19 03:31:3437 contents = input_api.ReadFile(f)
38 if pattern.search(contents):
39 files.append(f)
40
41 if len(files):
42 return [ output_api.PresubmitError(
43 'Objective-C interfaces or categories are forbidden in libbase. ' +
44 'See http://groups.google.com/a/chromium.org/group/chromium-dev/' +
45 'browse_thread/thread/efb28c10435987fd',
46 files) ]
47 return []
48
[email protected]650c9082010-12-14 14:33:4449
[email protected]55459852011-08-10 15:17:1950def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
51 """Attempts to prevent use of functions intended only for testing in
52 non-testing code. For now this is just a best-effort implementation
53 that ignores header files and may have some false positives. A
54 better implementation would probably need a proper C++ parser.
55 """
56 # We only scan .cc files and the like, as the declaration of
57 # for-testing functions in header files are hard to distinguish from
58 # calls to such functions without a proper C++ parser.
59 source_extensions = r'\.(cc|cpp|cxx|mm)$'
60 file_inclusion_pattern = r'.+%s' % source_extensions
[email protected]19e77fd2011-10-20 05:24:0561 file_exclusion_patterns = (
62 r'.*/(test_|mock_).+%s' % source_extensions,
63 r'.+_test_(support|base)%s' % source_extensions,
64 r'.+_(api|browser|perf|unit|ui)?test%s' % source_extensions,
65 r'.+profile_sync_service_harness%s' % source_extensions,
66 )
67 path_exclusion_patterns = (
68 r'.*[/\\](test|tool(s)?)[/\\].*',
69 # At request of folks maintaining this folder.
70 r'chrome[/\\]browser[/\\]automation[/\\].*',
71 )
[email protected]55459852011-08-10 15:17:1972
73 base_function_pattern = r'ForTest(ing)?|for_test(ing)?'
74 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
75 exclusion_pattern = input_api.re.compile(
76 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
77 base_function_pattern, base_function_pattern))
78
79 def FilterFile(affected_file):
[email protected]19e77fd2011-10-20 05:24:0580 black_list = (file_exclusion_patterns + path_exclusion_patterns +
[email protected]3afb12a42011-08-15 13:48:3381 _EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:1982 return input_api.FilterSourceFile(
83 affected_file,
84 white_list=(file_inclusion_pattern, ),
85 black_list=black_list)
86
87 problems = []
88 for f in input_api.AffectedSourceFiles(FilterFile):
89 local_path = f.LocalPath()
90 lines = input_api.ReadFile(f).splitlines()
91 line_number = 0
92 for line in lines:
93 if (inclusion_pattern.search(line) and
94 not exclusion_pattern.search(line)):
95 problems.append(
96 '%s:%d\n %s' % (local_path, line_number, line.strip()))
97 line_number += 1
98
99 if problems:
[email protected]eea609a2011-11-18 13:10:12100 if not input_api.is_committing:
101 return [output_api.PresubmitPromptWarning(_TEST_ONLY_WARNING, problems)]
102 else:
103 # We don't warn on commit, to avoid stopping commits going through CQ.
104 return [output_api.PresubmitNotifyResult(_TEST_ONLY_WARNING, problems)]
[email protected]55459852011-08-10 15:17:19105 else:
106 return []
107
108
[email protected]10689ca2011-09-02 02:31:54109def _CheckNoIOStreamInHeaders(input_api, output_api):
110 """Checks to make sure no .h files include <iostream>."""
111 files = []
112 pattern = input_api.re.compile(r'^#include\s*<iostream>',
113 input_api.re.MULTILINE)
114 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
115 if not f.LocalPath().endswith('.h'):
116 continue
117 contents = input_api.ReadFile(f)
118 if pattern.search(contents):
119 files.append(f)
120
121 if len(files):
122 return [ output_api.PresubmitError(
123 'Do not #include <iostream> in header files, since it inserts static ' +
124 'initialization into every file including the header. Instead, ' +
125 '#include <ostream>. See http://crbug.com/94794',
126 files) ]
127 return []
128
129
[email protected]8ea5d4b2011-09-13 21:49:22130def _CheckNoNewWStrings(input_api, output_api):
131 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27132 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22133 for f in input_api.AffectedFiles():
134 for line_num, line in f.ChangedContents():
[email protected]044ef4d2011-09-23 03:37:52135 if (not f.LocalPath().endswith(('.cc', '.h')) or
136 f.LocalPath().endswith('test.cc')):
[email protected]8ea5d4b2011-09-13 21:49:22137 continue
138
139 if 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27140 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]8ea5d4b2011-09-13 21:49:22141
[email protected]55463aa62011-10-12 00:48:27142 if not problems:
143 return []
144 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
145 ' If you are calling an API that accepts a wstring, fix the API.\n' +
146 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22147
148
[email protected]2a8ac9c2011-10-19 17:20:44149def _CheckNoDEPSGIT(input_api, output_api):
150 """Make sure .DEPS.git is never modified manually."""
151 if any(f.LocalPath().endswith('.DEPS.git') for f in
152 input_api.AffectedFiles()):
153 return [output_api.PresubmitError(
154 'Never commit changes to .DEPS.git. This file is maintained by an\n'
155 'automated system based on what\'s in DEPS and your changes will be\n'
156 'overwritten.\n'
157 'See http://code.google.com/p/chromium/wiki/UsingNewGit#Rolling_DEPS\n'
158 'for more information')]
159 return []
160
161
[email protected]22c9bd72011-03-27 16:47:39162def _CommonChecks(input_api, output_api):
163 """Checks common to both upload and commit."""
164 results = []
165 results.extend(input_api.canned_checks.PanProjectChecks(
166 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
167 results.extend(_CheckNoInterfacesInBase(input_api, output_api))
[email protected]66daa702011-05-28 14:41:46168 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:19169 results.extend(
170 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:54171 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:22172 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:44173 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]22c9bd72011-03-27 16:47:39174 return results
[email protected]1f7b4172010-01-28 01:17:34175
[email protected]b337cb5b2011-01-23 21:24:05176
177def _CheckSubversionConfig(input_api, output_api):
178 """Verifies the subversion config file is correctly setup.
179
180 Checks that autoprops are enabled, returns an error otherwise.
181 """
182 join = input_api.os_path.join
183 if input_api.platform == 'win32':
184 appdata = input_api.environ.get('APPDATA', '')
185 if not appdata:
186 return [output_api.PresubmitError('%APPDATA% is not configured.')]
187 path = join(appdata, 'Subversion', 'config')
188 else:
189 home = input_api.environ.get('HOME', '')
190 if not home:
191 return [output_api.PresubmitError('$HOME is not configured.')]
192 path = join(home, '.subversion', 'config')
193
194 error_msg = (
195 'Please look at http://dev.chromium.org/developers/coding-style to\n'
196 'configure your subversion configuration file. This enables automatic\n'
[email protected]c6a3c10b2011-01-24 16:14:20197 'properties to simplify the project maintenance.\n'
198 'Pro-tip: just download and install\n'
199 'http://src.chromium.org/viewvc/chrome/trunk/tools/build/slave/config\n')
[email protected]b337cb5b2011-01-23 21:24:05200
201 try:
202 lines = open(path, 'r').read().splitlines()
203 # Make sure auto-props is enabled and check for 2 Chromium standard
204 # auto-prop.
205 if (not '*.cc = svn:eol-style=LF' in lines or
206 not '*.pdf = svn:mime-type=application/pdf' in lines or
207 not 'enable-auto-props = yes' in lines):
208 return [
[email protected]79ed7e62011-02-21 21:08:53209 output_api.PresubmitNotifyResult(
[email protected]b337cb5b2011-01-23 21:24:05210 'It looks like you have not configured your subversion config '
[email protected]b5359c02011-02-01 20:29:56211 'file or it is not up-to-date.\n' + error_msg)
[email protected]b337cb5b2011-01-23 21:24:05212 ]
213 except (OSError, IOError):
214 return [
[email protected]79ed7e62011-02-21 21:08:53215 output_api.PresubmitNotifyResult(
[email protected]b337cb5b2011-01-23 21:24:05216 'Can\'t find your subversion config file.\n' + error_msg)
217 ]
218 return []
219
220
[email protected]66daa702011-05-28 14:41:46221def _CheckAuthorizedAuthor(input_api, output_api):
222 """For non-googler/chromites committers, verify the author's email address is
223 in AUTHORS.
224 """
[email protected]9bb9cb82011-06-13 20:43:01225 # TODO(maruel): Add it to input_api?
226 import fnmatch
227
[email protected]66daa702011-05-28 14:41:46228 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:01229 if not author:
230 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:46231 return []
[email protected]c99663292011-05-31 19:46:08232 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:46233 input_api.PresubmitLocalPath(), 'AUTHORS')
234 valid_authors = (
235 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
236 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:18237 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]9bb9cb82011-06-13 20:43:01238 if input_api.verbose:
239 print 'Valid authors are %s' % ', '.join(valid_authors)
[email protected]d8b50be2011-06-15 14:19:44240 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]66daa702011-05-28 14:41:46241 return [output_api.PresubmitPromptWarning(
242 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
243 '\n'
244 'http://www.chromium.org/developers/contributing-code and read the '
245 '"Legal" section\n'
246 'If you are a chromite, verify the contributor signed the CLA.') %
247 author)]
248 return []
249
250
[email protected]1f7b4172010-01-28 01:17:34251def CheckChangeOnUpload(input_api, output_api):
252 results = []
253 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:54254 return results
[email protected]ca8d19842009-02-19 16:33:12255
256
257def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:54258 results = []
[email protected]1f7b4172010-01-28 01:17:34259 results.extend(_CommonChecks(input_api, output_api))
[email protected]dd805fe2009-10-01 08:11:51260 # TODO(thestig) temporarily disabled, doesn't work in third_party/
261 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
262 # input_api, output_api, sources))
[email protected]fe5f57c52009-06-05 14:25:54263 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:27264 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:34265 input_api,
266 output_api,
[email protected]4efa42142010-08-26 01:29:26267 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:27268 results.extend(input_api.canned_checks.CheckRietveldTryJobExecution(input_api,
269 output_api, 'http://codereview.chromium.org', ('win', 'linux', 'mac'),
270 '[email protected]'))
271
[email protected]3e4eb112011-01-18 03:29:54272 results.extend(input_api.canned_checks.CheckChangeHasBugField(
273 input_api, output_api))
274 results.extend(input_api.canned_checks.CheckChangeHasTestField(
275 input_api, output_api))
[email protected]b337cb5b2011-01-23 21:24:05276 results.extend(_CheckSubversionConfig(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:54277 return results
[email protected]ca8d19842009-02-19 16:33:12278
279
[email protected]5efb2a822011-09-27 23:06:13280def GetPreferredTrySlaves(project, change):
281 only_objc_files = all(
282 f.LocalPath().endswith(('.mm', '.m')) for f in change.AffectedFiles())
283 if only_objc_files:
284 return ['mac']
[email protected]5fa06292009-09-29 01:55:00285 return ['win', 'linux', 'mac']