blob: 0bb8ac8b69e43ab0407404e3851f651142808ccb [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-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]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]9d16ad12011-12-14 20:49:4712import re
13
14
[email protected]379e7dd2010-01-28 17:39:2115_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5416 r"^breakpad[\\\/].*",
[email protected]a18130a2012-01-03 17:52:0817 r"^native_client_sdk[\\\/].*",
18 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5419 r"^skia[\\\/].*",
20 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]4306417642009-06-11 00:33:4023)
[email protected]ca8d1982009-02-19 16:33:1224
[email protected]ca8d1982009-02-19 16:33:1225
[email protected]eea609a2011-11-18 13:10:1226_TEST_ONLY_WARNING = (
27 'You might be calling functions intended only for testing from\n'
28 'production code. It is OK to ignore this warning if you know what\n'
29 'you are doing, as the heuristics used to detect the situation are\n'
30 'not perfect. The commit queue will not block on this warning.\n'
31 'Email [email protected] if you have questions.')
32
33
34
[email protected]22c9bd72011-03-27 16:47:3935def _CheckNoInterfacesInBase(input_api, output_api):
[email protected]6a4c8e682010-12-19 03:31:3436 """Checks to make sure no files in libbase.a have |@interface|."""
[email protected]839c1392011-04-29 20:15:1937 pattern = input_api.re.compile(r'^\s*@interface', input_api.re.MULTILINE)
[email protected]6a4c8e682010-12-19 03:31:3438 files = []
[email protected]22c9bd72011-03-27 16:47:3939 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
[email protected]a766a1322011-09-08 20:46:0540 if (f.LocalPath().startswith('base/') and
[email protected]0b2f07b02011-05-02 17:29:0041 not f.LocalPath().endswith('_unittest.mm')):
[email protected]6a4c8e682010-12-19 03:31:3442 contents = input_api.ReadFile(f)
43 if pattern.search(contents):
44 files.append(f)
45
46 if len(files):
47 return [ output_api.PresubmitError(
48 'Objective-C interfaces or categories are forbidden in libbase. ' +
49 'See http://groups.google.com/a/chromium.org/group/chromium-dev/' +
50 'browse_thread/thread/efb28c10435987fd',
51 files) ]
52 return []
53
[email protected]650c9082010-12-14 14:33:4454
[email protected]55459852011-08-10 15:17:1955def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
56 """Attempts to prevent use of functions intended only for testing in
57 non-testing code. For now this is just a best-effort implementation
58 that ignores header files and may have some false positives. A
59 better implementation would probably need a proper C++ parser.
60 """
61 # We only scan .cc files and the like, as the declaration of
62 # for-testing functions in header files are hard to distinguish from
63 # calls to such functions without a proper C++ parser.
64 source_extensions = r'\.(cc|cpp|cxx|mm)$'
65 file_inclusion_pattern = r'.+%s' % source_extensions
[email protected]19e77fd2011-10-20 05:24:0566 file_exclusion_patterns = (
[email protected]e21ce382012-01-04 18:48:2567 r'.*[/\\](test_|mock_).+%s' % source_extensions,
[email protected]c762d252012-02-28 02:07:2468 r'.+_test_(base|support|util)%s' % source_extensions,
[email protected]19e77fd2011-10-20 05:24:0569 r'.+_(api|browser|perf|unit|ui)?test%s' % source_extensions,
70 r'.+profile_sync_service_harness%s' % source_extensions,
71 )
72 path_exclusion_patterns = (
73 r'.*[/\\](test|tool(s)?)[/\\].*',
74 # At request of folks maintaining this folder.
75 r'chrome[/\\]browser[/\\]automation[/\\].*',
76 )
[email protected]55459852011-08-10 15:17:1977
78 base_function_pattern = r'ForTest(ing)?|for_test(ing)?'
79 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
80 exclusion_pattern = input_api.re.compile(
81 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
82 base_function_pattern, base_function_pattern))
83
84 def FilterFile(affected_file):
[email protected]19e77fd2011-10-20 05:24:0585 black_list = (file_exclusion_patterns + path_exclusion_patterns +
[email protected]3afb12a42011-08-15 13:48:3386 _EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:1987 return input_api.FilterSourceFile(
88 affected_file,
89 white_list=(file_inclusion_pattern, ),
90 black_list=black_list)
91
92 problems = []
93 for f in input_api.AffectedSourceFiles(FilterFile):
94 local_path = f.LocalPath()
95 lines = input_api.ReadFile(f).splitlines()
96 line_number = 0
97 for line in lines:
98 if (inclusion_pattern.search(line) and
99 not exclusion_pattern.search(line)):
100 problems.append(
101 '%s:%d\n %s' % (local_path, line_number, line.strip()))
102 line_number += 1
103
104 if problems:
[email protected]eea609a2011-11-18 13:10:12105 if not input_api.is_committing:
106 return [output_api.PresubmitPromptWarning(_TEST_ONLY_WARNING, problems)]
107 else:
108 # We don't warn on commit, to avoid stopping commits going through CQ.
109 return [output_api.PresubmitNotifyResult(_TEST_ONLY_WARNING, problems)]
[email protected]55459852011-08-10 15:17:19110 else:
111 return []
112
113
[email protected]10689ca2011-09-02 02:31:54114def _CheckNoIOStreamInHeaders(input_api, output_api):
115 """Checks to make sure no .h files include <iostream>."""
116 files = []
117 pattern = input_api.re.compile(r'^#include\s*<iostream>',
118 input_api.re.MULTILINE)
119 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
120 if not f.LocalPath().endswith('.h'):
121 continue
122 contents = input_api.ReadFile(f)
123 if pattern.search(contents):
124 files.append(f)
125
126 if len(files):
127 return [ output_api.PresubmitError(
128 'Do not #include <iostream> in header files, since it inserts static ' +
129 'initialization into every file including the header. Instead, ' +
130 '#include <ostream>. See http://crbug.com/94794',
131 files) ]
132 return []
133
134
[email protected]8ea5d4b2011-09-13 21:49:22135def _CheckNoNewWStrings(input_api, output_api):
136 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27137 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22138 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20139 if (not f.LocalPath().endswith(('.cc', '.h')) or
140 f.LocalPath().endswith('test.cc')):
141 continue
[email protected]8ea5d4b2011-09-13 21:49:22142
[email protected]b5c24292011-11-28 14:38:20143 for line_num, line in f.ChangedContents():
[email protected]8ea5d4b2011-09-13 21:49:22144 if 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27145 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]8ea5d4b2011-09-13 21:49:22146
[email protected]55463aa62011-10-12 00:48:27147 if not problems:
148 return []
149 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
150 ' If you are calling an API that accepts a wstring, fix the API.\n' +
151 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22152
153
[email protected]2a8ac9c2011-10-19 17:20:44154def _CheckNoDEPSGIT(input_api, output_api):
155 """Make sure .DEPS.git is never modified manually."""
156 if any(f.LocalPath().endswith('.DEPS.git') for f in
157 input_api.AffectedFiles()):
158 return [output_api.PresubmitError(
159 'Never commit changes to .DEPS.git. This file is maintained by an\n'
160 'automated system based on what\'s in DEPS and your changes will be\n'
161 'overwritten.\n'
162 'See http://code.google.com/p/chromium/wiki/UsingNewGit#Rolling_DEPS\n'
163 'for more information')]
164 return []
165
166
[email protected]b5c24292011-11-28 14:38:20167def _CheckNoFRIEND_TEST(input_api, output_api):
168 """Make sure that gtest's FRIEND_TEST() macro is not used, the
169 FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be used
170 instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes."""
171 problems = []
172
173 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.h'))
174 for f in input_api.AffectedFiles(file_filter=file_filter):
175 for line_num, line in f.ChangedContents():
176 if 'FRIEND_TEST(' in line:
177 problems.append(' %s:%d' % (f.LocalPath(), line_num))
178
179 if not problems:
180 return []
181 return [output_api.PresubmitPromptWarning('Chromium code should not use '
[email protected]24a4ac62011-11-29 15:30:33182 'gtest\'s FRIEND_TEST() macro. Include base/gtest_prod_util.h and use '
[email protected]b5c24292011-11-28 14:38:20183 'FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems))]
184
185
[email protected]7bbc7d12012-03-22 21:44:41186def _CheckNoScopedAllowIO(input_api, output_api):
187 """Make sure that ScopedAllowIO is not used."""
188 problems = []
189
190 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.h'))
191 for f in input_api.AffectedFiles(file_filter=file_filter):
192 for line_num, line in f.ChangedContents():
193 if 'ScopedAllowIO' in line:
194 problems.append(' %s:%d' % (f.LocalPath(), line_num))
195
196 if not problems:
197 return []
198 return [output_api.PresubmitPromptWarning('New code should not use '
199 'ScopedAllowIO. Post a task to the blocking pool or the FILE thread '
200 'instead.\n' + '\n'.join(problems))]
201
202
[email protected]22c9bd72011-03-27 16:47:39203def _CommonChecks(input_api, output_api):
204 """Checks common to both upload and commit."""
205 results = []
206 results.extend(input_api.canned_checks.PanProjectChecks(
207 input_api, output_api, excluded_paths=_EXCLUDED_PATHS))
208 results.extend(_CheckNoInterfacesInBase(input_api, output_api))
[email protected]66daa702011-05-28 14:41:46209 results.extend(_CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:19210 results.extend(
211 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:54212 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:22213 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:44214 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]b5c24292011-11-28 14:38:20215 results.extend(_CheckNoFRIEND_TEST(input_api, output_api))
[email protected]7bbc7d12012-03-22 21:44:41216 results.extend(_CheckNoScopedAllowIO(input_api, output_api))
[email protected]22c9bd72011-03-27 16:47:39217 return results
[email protected]1f7b4172010-01-28 01:17:34218
[email protected]b337cb5b2011-01-23 21:24:05219
220def _CheckSubversionConfig(input_api, output_api):
221 """Verifies the subversion config file is correctly setup.
222
223 Checks that autoprops are enabled, returns an error otherwise.
224 """
225 join = input_api.os_path.join
226 if input_api.platform == 'win32':
227 appdata = input_api.environ.get('APPDATA', '')
228 if not appdata:
229 return [output_api.PresubmitError('%APPDATA% is not configured.')]
230 path = join(appdata, 'Subversion', 'config')
231 else:
232 home = input_api.environ.get('HOME', '')
233 if not home:
234 return [output_api.PresubmitError('$HOME is not configured.')]
235 path = join(home, '.subversion', 'config')
236
237 error_msg = (
238 'Please look at http://dev.chromium.org/developers/coding-style to\n'
239 'configure your subversion configuration file. This enables automatic\n'
[email protected]c6a3c10b2011-01-24 16:14:20240 'properties to simplify the project maintenance.\n'
241 'Pro-tip: just download and install\n'
242 'http://src.chromium.org/viewvc/chrome/trunk/tools/build/slave/config\n')
[email protected]b337cb5b2011-01-23 21:24:05243
244 try:
245 lines = open(path, 'r').read().splitlines()
246 # Make sure auto-props is enabled and check for 2 Chromium standard
247 # auto-prop.
248 if (not '*.cc = svn:eol-style=LF' in lines or
249 not '*.pdf = svn:mime-type=application/pdf' in lines or
250 not 'enable-auto-props = yes' in lines):
251 return [
[email protected]79ed7e62011-02-21 21:08:53252 output_api.PresubmitNotifyResult(
[email protected]b337cb5b2011-01-23 21:24:05253 'It looks like you have not configured your subversion config '
[email protected]b5359c02011-02-01 20:29:56254 'file or it is not up-to-date.\n' + error_msg)
[email protected]b337cb5b2011-01-23 21:24:05255 ]
256 except (OSError, IOError):
257 return [
[email protected]79ed7e62011-02-21 21:08:53258 output_api.PresubmitNotifyResult(
[email protected]b337cb5b2011-01-23 21:24:05259 'Can\'t find your subversion config file.\n' + error_msg)
260 ]
261 return []
262
263
[email protected]66daa702011-05-28 14:41:46264def _CheckAuthorizedAuthor(input_api, output_api):
265 """For non-googler/chromites committers, verify the author's email address is
266 in AUTHORS.
267 """
[email protected]9bb9cb82011-06-13 20:43:01268 # TODO(maruel): Add it to input_api?
269 import fnmatch
270
[email protected]66daa702011-05-28 14:41:46271 author = input_api.change.author_email
[email protected]9bb9cb82011-06-13 20:43:01272 if not author:
273 input_api.logging.info('No author, skipping AUTHOR check')
[email protected]66daa702011-05-28 14:41:46274 return []
[email protected]c99663292011-05-31 19:46:08275 authors_path = input_api.os_path.join(
[email protected]66daa702011-05-28 14:41:46276 input_api.PresubmitLocalPath(), 'AUTHORS')
277 valid_authors = (
278 input_api.re.match(r'[^#]+\s+\<(.+?)\>\s*$', line)
279 for line in open(authors_path))
[email protected]ac54b132011-06-06 18:11:18280 valid_authors = [item.group(1).lower() for item in valid_authors if item]
[email protected]9bb9cb82011-06-13 20:43:01281 if input_api.verbose:
282 print 'Valid authors are %s' % ', '.join(valid_authors)
[email protected]d8b50be2011-06-15 14:19:44283 if not any(fnmatch.fnmatch(author.lower(), valid) for valid in valid_authors):
[email protected]66daa702011-05-28 14:41:46284 return [output_api.PresubmitPromptWarning(
285 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
286 '\n'
287 'http://www.chromium.org/developers/contributing-code and read the '
288 '"Legal" section\n'
289 'If you are a chromite, verify the contributor signed the CLA.') %
290 author)]
291 return []
292
293
[email protected]1f7b4172010-01-28 01:17:34294def CheckChangeOnUpload(input_api, output_api):
295 results = []
296 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:54297 return results
[email protected]ca8d1982009-02-19 16:33:12298
299
300def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:54301 results = []
[email protected]1f7b4172010-01-28 01:17:34302 results.extend(_CommonChecks(input_api, output_api))
[email protected]dd805fe2009-10-01 08:11:51303 # TODO(thestig) temporarily disabled, doesn't work in third_party/
304 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
305 # input_api, output_api, sources))
[email protected]fe5f57c52009-06-05 14:25:54306 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:27307 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:34308 input_api,
309 output_api,
[email protected]4efa42142010-08-26 01:29:26310 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:27311 results.extend(input_api.canned_checks.CheckRietveldTryJobExecution(input_api,
[email protected]4ddc5df2011-12-12 03:05:04312 output_api, 'http://codereview.chromium.org',
[email protected]c1ba4c52012-03-09 14:23:28313 ('win_rel', 'linux_rel', 'mac_rel, win:compile'),
314 '[email protected]'))
[email protected]806e98e2010-03-19 17:49:27315
[email protected]3e4eb112011-01-18 03:29:54316 results.extend(input_api.canned_checks.CheckChangeHasBugField(
317 input_api, output_api))
318 results.extend(input_api.canned_checks.CheckChangeHasTestField(
319 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:41320 results.extend(input_api.canned_checks.CheckChangeHasDescription(
321 input_api, output_api))
[email protected]b337cb5b2011-01-23 21:24:05322 results.extend(_CheckSubversionConfig(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:54323 return results
[email protected]ca8d1982009-02-19 16:33:12324
325
[email protected]5efb2a822011-09-27 23:06:13326def GetPreferredTrySlaves(project, change):
[email protected]50c30092012-02-15 04:21:36327 affected_files = change.LocalPaths()
328 only_objc_files = all(f.endswith(('.mm', '.m')) for f in affected_files)
[email protected]5efb2a822011-09-27 23:06:13329 if only_objc_files:
[email protected]4ddc5df2011-12-12 03:05:04330 return ['mac_rel']
[email protected]1f2629892012-05-07 19:23:12331 preferred = ['win_rel', 'linux_rel', 'mac_rel', 'linux_clang:compile']
[email protected]9d16ad12011-12-14 20:49:47332 aura_re = '_aura[^/]*[.][^/]*'
[email protected]50c30092012-02-15 04:21:36333 if any(re.search(aura_re, f) for f in affected_files):
[email protected]e9b23882012-02-03 01:05:49334 preferred.append('linux_chromeos')
[email protected]d3b7e7cca2012-03-01 21:25:06335 # Nothing in chrome/
336 android_re_list = ('^base/',
337 '^build/common.gypi$',
338 '^content/',
339 '^ipc/',
340 '^jingle/',
341 '^media/',
342 '^net/',
343 '^sql/')
344 # Nothing that looks like win-only or aura-only
345 win_re = '_win\.(cc|h)$'
346 possibly_android = True
347 for non_android_re in (aura_re, win_re):
348 if all(re.search(non_android_re, f) for f in affected_files):
349 possibly_android = False
350 break
351 if possibly_android:
352 for f in change.AffectedFiles():
353 if any(re.search(r, f.LocalPath()) for r in android_re_list):
354 preferred.append('android')
355 break
[email protected]9d16ad12011-12-14 20:49:47356 return preferred