blob: a832761c89dbd05a4205729a132260d5df334b22 [file] [log] [blame]
andrew@webrtc.org2442de12012-01-23 17:45:41 +00001# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
2#
3# Use of this source code is governed by a BSD-style license
4# that can be found in the LICENSE file in the root of the source
5# tree. An additional intellectual property rights grant can be found
6# in the file PATENTS. All contributing project authors may
7# be found in the AUTHORS file in the root of the source tree.
niklase@google.comda159d62011-05-30 11:51:34 +00008
kjellander986ee082015-06-16 04:32:13 -07009import json
kjellander@webrtc.orgaefe61a2014-12-08 13:00:30 +000010import os
kjellander986ee082015-06-16 04:32:13 -070011import platform
kjellander@webrtc.org85759802013-10-22 16:47:40 +000012import re
kjellander986ee082015-06-16 04:32:13 -070013import subprocess
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +000014import sys
kjellander@webrtc.org85759802013-10-22 16:47:40 +000015
16
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000017def _CheckNoIOStreamInHeaders(input_api, output_api):
18 """Checks to make sure no .h files include <iostream>."""
19 files = []
20 pattern = input_api.re.compile(r'^#include\s*<iostream>',
21 input_api.re.MULTILINE)
22 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
23 if not f.LocalPath().endswith('.h'):
24 continue
25 contents = input_api.ReadFile(f)
26 if pattern.search(contents):
27 files.append(f)
28
29 if len(files):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +020030 return [output_api.PresubmitError(
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000031 'Do not #include <iostream> in header files, since it inserts static ' +
32 'initialization into every file including the header. Instead, ' +
33 '#include <ostream>. See http://crbug.com/94794',
Henrik Kjellander57e5fd22015-05-25 12:55:39 +020034 files)]
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000035 return []
36
kjellander@webrtc.orge4158642014-08-06 09:11:18 +000037
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000038def _CheckNoFRIEND_TEST(input_api, output_api):
39 """Make sure that gtest's FRIEND_TEST() macro is not used, the
40 FRIEND_TEST_ALL_PREFIXES() macro from testsupport/gtest_prod_util.h should be
41 used instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes."""
42 problems = []
43
44 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.h'))
45 for f in input_api.AffectedFiles(file_filter=file_filter):
46 for line_num, line in f.ChangedContents():
47 if 'FRIEND_TEST(' in line:
48 problems.append(' %s:%d' % (f.LocalPath(), line_num))
49
50 if not problems:
51 return []
52 return [output_api.PresubmitPromptWarning('WebRTC\'s code should not use '
53 'gtest\'s FRIEND_TEST() macro. Include testsupport/gtest_prod_util.h and '
54 'use FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems))]
55
kjellander@webrtc.orge4158642014-08-06 09:11:18 +000056
mflodman@webrtc.org2a452092012-07-01 05:55:23 +000057def _CheckApprovedFilesLintClean(input_api, output_api,
58 source_file_filter=None):
59 """Checks that all new or whitelisted .cc and .h files pass cpplint.py.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000060 This check is based on _CheckChangeLintsClean in
61 depot_tools/presubmit_canned_checks.py but has less filters and only checks
62 added files."""
63 result = []
64
65 # Initialize cpplint.
66 import cpplint
67 # Access to a protected member _XX of a client class
68 # pylint: disable=W0212
69 cpplint._cpplint_state.ResetErrorCounts()
70
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000071 # Use the strictest verbosity level for cpplint.py (level 1) which is the
72 # default when running cpplint.py from command line.
73 # To make it possible to work with not-yet-converted code, we're only applying
mflodman@webrtc.org2a452092012-07-01 05:55:23 +000074 # it to new (or moved/renamed) files and files listed in LINT_FOLDERS.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000075 verbosity_level = 1
76 files = []
77 for f in input_api.AffectedSourceFiles(source_file_filter):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +020078 # Note that moved/renamed files also count as added.
79 if f.Action() == 'A':
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000080 files.append(f.AbsoluteLocalPath())
mflodman@webrtc.org2a452092012-07-01 05:55:23 +000081
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000082 for file_name in files:
83 cpplint.ProcessFile(file_name, verbosity_level)
84
85 if cpplint._cpplint_state.error_count > 0:
86 if input_api.is_committing:
87 # TODO(kjellander): Change back to PresubmitError below when we're
88 # confident with the lint settings.
89 res_type = output_api.PresubmitPromptWarning
90 else:
91 res_type = output_api.PresubmitPromptWarning
92 result = [res_type('Changelist failed cpplint.py check.')]
93
94 return result
95
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +000096def _CheckNoRtcBaseDeps(input_api, gyp_files, output_api):
97 pattern = input_api.re.compile(r"base.gyp:rtc_base\s*'")
98 violating_files = []
99 for f in gyp_files:
henrike@webrtc.org36b0c1a2014-10-01 14:40:58 +0000100 gyp_exceptions = (
101 'base_tests.gyp',
102 'desktop_capture.gypi',
103 'libjingle.gyp',
henrike@webrtc.org28af6412014-11-04 15:11:46 +0000104 'libjingle_tests.gyp',
kjellander@webrtc.orge7237282015-02-26 11:12:17 +0000105 'p2p.gyp',
henrike@webrtc.org36b0c1a2014-10-01 14:40:58 +0000106 'sound.gyp',
107 'webrtc_test_common.gyp',
108 'webrtc_tests.gypi',
109 )
110 if f.LocalPath().endswith(gyp_exceptions):
111 continue
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +0000112 contents = input_api.ReadFile(f)
113 if pattern.search(contents):
114 violating_files.append(f)
115 if violating_files:
116 return [output_api.PresubmitError(
117 'Depending on rtc_base is not allowed. Change your dependency to '
118 'rtc_base_approved and possibly sanitize and move the desired source '
119 'file(s) to rtc_base_approved.\nChanged GYP files:',
120 items=violating_files)]
121 return []
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000122
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000123def _CheckNoSourcesAboveGyp(input_api, gyp_files, output_api):
124 # Disallow referencing source files with paths above the GYP file location.
125 source_pattern = input_api.re.compile(r'sources.*?\[(.*?)\]',
126 re.MULTILINE | re.DOTALL)
kjellander@webrtc.orga33f05e2015-01-29 14:29:45 +0000127 file_pattern = input_api.re.compile(r"'((\.\./.*?)|(<\(webrtc_root\).*?))'")
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000128 violating_gyp_files = set()
129 violating_source_entries = []
130 for gyp_file in gyp_files:
131 contents = input_api.ReadFile(gyp_file)
132 for source_block_match in source_pattern.finditer(contents):
kjellander@webrtc.orgc98f6f32015-03-04 07:08:11 +0000133 # Find all source list entries starting with ../ in the source block
134 # (exclude overrides entries).
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000135 for file_list_match in file_pattern.finditer(source_block_match.group(0)):
kjellander@webrtc.orgc98f6f32015-03-04 07:08:11 +0000136 source_file = file_list_match.group(0)
137 if 'overrides/' not in source_file:
138 violating_source_entries.append(source_file)
139 violating_gyp_files.add(gyp_file)
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000140 if violating_gyp_files:
141 return [output_api.PresubmitError(
142 'Referencing source files above the directory of the GYP file is not '
143 'allowed. Please introduce new GYP targets and/or GYP files in the '
144 'proper location instead.\n'
145 'Invalid source entries:\n'
146 '%s\n'
147 'Violating GYP files:' % '\n'.join(violating_source_entries),
148 items=violating_gyp_files)]
149 return []
150
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000151def _CheckGypChanges(input_api, output_api):
152 source_file_filter = lambda x: input_api.FilterSourceFile(
153 x, white_list=(r'.+\.(gyp|gypi)$',))
154
155 gyp_files = []
156 for f in input_api.AffectedSourceFiles(source_file_filter):
kjellander@webrtc.org3398a4a2014-11-24 10:05:37 +0000157 if f.LocalPath().startswith('webrtc'):
158 gyp_files.append(f)
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000159
160 result = []
161 if gyp_files:
162 result.append(output_api.PresubmitNotifyResult(
163 'As you\'re changing GYP files: please make sure corresponding '
164 'BUILD.gn files are also updated.\nChanged GYP files:',
165 items=gyp_files))
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +0000166 result.extend(_CheckNoRtcBaseDeps(input_api, gyp_files, output_api))
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000167 result.extend(_CheckNoSourcesAboveGyp(input_api, gyp_files, output_api))
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000168 return result
169
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000170def _CheckUnwantedDependencies(input_api, output_api):
171 """Runs checkdeps on #include statements added in this
172 change. Breaking - rules is an error, breaking ! rules is a
173 warning.
174 """
175 # Copied from Chromium's src/PRESUBMIT.py.
176
177 # We need to wait until we have an input_api object and use this
178 # roundabout construct to import checkdeps because this file is
179 # eval-ed and thus doesn't have __file__.
180 original_sys_path = sys.path
181 try:
kjellander@webrtc.orgaefe61a2014-12-08 13:00:30 +0000182 checkdeps_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
183 'buildtools', 'checkdeps')
184 if not os.path.exists(checkdeps_path):
185 return [output_api.PresubmitError(
186 'Cannot find checkdeps at %s\nHave you run "gclient sync" to '
187 'download Chromium and setup the symlinks?' % checkdeps_path)]
188 sys.path.append(checkdeps_path)
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000189 import checkdeps
190 from cpp_checker import CppChecker
191 from rules import Rule
192 finally:
193 # Restore sys.path to what it was before.
194 sys.path = original_sys_path
195
196 added_includes = []
197 for f in input_api.AffectedFiles():
198 if not CppChecker.IsCppFile(f.LocalPath()):
199 continue
200
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200201 changed_lines = [line for _, line in f.ChangedContents()]
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000202 added_includes.append([f.LocalPath(), changed_lines])
203
204 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
205
206 error_descriptions = []
207 warning_descriptions = []
208 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
209 added_includes):
210 description_with_path = '%s\n %s' % (path, rule_description)
211 if rule_type == Rule.DISALLOW:
212 error_descriptions.append(description_with_path)
213 else:
214 warning_descriptions.append(description_with_path)
215
216 results = []
217 if error_descriptions:
218 results.append(output_api.PresubmitError(
219 'You added one or more #includes that violate checkdeps rules.',
220 error_descriptions))
221 if warning_descriptions:
222 results.append(output_api.PresubmitPromptOrNotify(
223 'You added one or more #includes of files that are temporarily\n'
224 'allowed but being removed. Can you avoid introducing the\n'
225 '#include? See relevant DEPS file(s) for details and contacts.',
226 warning_descriptions))
227 return results
228
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000229
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200230def _RunPythonTests(input_api, output_api):
231 def join(*args):
232 return input_api.os_path.join(input_api.PresubmitLocalPath(), *args)
233
234 test_directories = [
235 join('tools', 'autoroller', 'unittests'),
236 ]
237
238 tests = []
239 for directory in test_directories:
240 tests.extend(
241 input_api.canned_checks.GetUnitTestsInDirectory(
242 input_api,
243 output_api,
244 directory,
245 whitelist=[r'.+_test\.py$']))
246 return input_api.RunTests(tests, parallel=True)
247
248
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000249def _CommonChecks(input_api, output_api):
250 """Checks common to both upload and commit."""
niklase@google.comda159d62011-05-30 11:51:34 +0000251 results = []
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000252 results.extend(input_api.canned_checks.RunPylint(input_api, output_api,
253 black_list=(r'^.*gviz_api\.py$',
254 r'^.*gaeunit\.py$',
fischman@webrtc.org33584f92013-07-25 16:43:30 +0000255 # Embedded shell-script fakes out pylint.
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200256 r'^build[\\\/].*\.py$',
257 r'^buildtools[\\\/].*\.py$',
258 r'^chromium[\\\/].*\.py$',
259 r'^google_apis[\\\/].*\.py$',
260 r'^net.*[\\\/].*\.py$',
261 r'^out.*[\\\/].*\.py$',
262 r'^testing[\\\/].*\.py$',
263 r'^third_party[\\\/].*\.py$',
264 r'^tools[\\\/]find_depot_tools.py$',
265 r'^tools[\\\/]clang[\\\/].*\.py$',
266 r'^tools[\\\/]generate_library_loader[\\\/].*\.py$',
267 r'^tools[\\\/]gn[\\\/].*\.py$',
268 r'^tools[\\\/]gyp[\\\/].*\.py$',
Henrik Kjellanderd6d27e72015-09-25 22:19:11 +0200269 r'^tools[\\\/]isolate_driver.py$',
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200270 r'^tools[\\\/]protoc_wrapper[\\\/].*\.py$',
271 r'^tools[\\\/]python[\\\/].*\.py$',
272 r'^tools[\\\/]python_charts[\\\/]data[\\\/].*\.py$',
273 r'^tools[\\\/]refactoring[\\\/].*\.py$',
274 r'^tools[\\\/]swarming_client[\\\/].*\.py$',
275 r'^tools[\\\/]vim[\\\/].*\.py$',
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000276 # TODO(phoglund): should arguably be checked.
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200277 r'^tools[\\\/]valgrind-webrtc[\\\/].*\.py$',
278 r'^tools[\\\/]valgrind[\\\/].*\.py$',
279 r'^tools[\\\/]win[\\\/].*\.py$',
280 r'^xcodebuild.*[\\\/].*\.py$',),
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000281 disabled_warnings=['F0401', # Failed to import x
282 'E0611', # No package y in x
283 'W0232', # Class has no __init__ method
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200284 ],
285 pylintrc='pylintrc'))
286 # WebRTC can't use the presubmit_canned_checks.PanProjectChecks function since
287 # we need to have different license checks in talk/ and webrtc/ directories.
288 # Instead, hand-picked checks are included below.
Henrik Kjellander63224672015-09-08 08:03:56 +0200289
290 # Skip long-lines check for DEPS, GN and GYP files.
291 long_lines_sources = lambda x: input_api.FilterSourceFile(x,
292 black_list=(r'.+\.gyp$', r'.+\.gypi$', r'.+\.gn$', r'.+\.gni$', 'DEPS'))
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000293 results.extend(input_api.canned_checks.CheckLongLines(
Henrik Kjellander63224672015-09-08 08:03:56 +0200294 input_api, output_api, maxlen=80, source_file_filter=long_lines_sources))
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000295 results.extend(input_api.canned_checks.CheckChangeHasNoTabs(
296 input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000297 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
298 input_api, output_api))
299 results.extend(input_api.canned_checks.CheckChangeTodoHasOwner(
300 input_api, output_api))
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000301 results.extend(_CheckApprovedFilesLintClean(input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000302 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
303 results.extend(_CheckNoFRIEND_TEST(input_api, output_api))
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000304 results.extend(_CheckGypChanges(input_api, output_api))
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000305 results.extend(_CheckUnwantedDependencies(input_api, output_api))
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200306 results.extend(_RunPythonTests(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000307 return results
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000308
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000309
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000310def CheckChangeOnUpload(input_api, output_api):
311 results = []
312 results.extend(_CommonChecks(input_api, output_api))
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200313 results.extend(
314 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
niklase@google.comda159d62011-05-30 11:51:34 +0000315 return results
316
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000317
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000318def CheckChangeOnCommit(input_api, output_api):
niklase@google.com1198db92011-06-09 07:07:24 +0000319 results = []
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000320 results.extend(_CommonChecks(input_api, output_api))
niklase@google.com1198db92011-06-09 07:07:24 +0000321 results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000322 results.extend(input_api.canned_checks.CheckChangeWasUploaded(
323 input_api, output_api))
324 results.extend(input_api.canned_checks.CheckChangeHasDescription(
325 input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000326 results.extend(input_api.canned_checks.CheckChangeHasBugField(
327 input_api, output_api))
328 results.extend(input_api.canned_checks.CheckChangeHasTestField(
329 input_api, output_api))
kjellander@webrtc.org12cb88c2014-02-13 11:53:43 +0000330 results.extend(input_api.canned_checks.CheckTreeIsOpen(
331 input_api, output_api,
332 json_url='http://webrtc-status.appspot.com/current?format=json'))
niklase@google.com1198db92011-06-09 07:07:24 +0000333 return results
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000334
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000335
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000336# pylint: disable=W0613
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000337def GetPreferredTryMasters(project, change):
kjellander986ee082015-06-16 04:32:13 -0700338 cq_config_path = os.path.join(
tandrii04465d22015-06-20 04:00:49 -0700339 change.RepositoryRoot(), 'infra', 'config', 'cq.cfg')
kjellander986ee082015-06-16 04:32:13 -0700340 # commit_queue.py below is a script in depot_tools directory, which has a
341 # 'builders' command to retrieve a list of CQ builders from the CQ config.
342 is_win = platform.system() == 'Windows'
343 masters = json.loads(subprocess.check_output(
344 ['commit_queue', 'builders', cq_config_path], shell=is_win))
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000345
kjellander986ee082015-06-16 04:32:13 -0700346 try_config = {}
347 for master in masters:
348 try_config.setdefault(master, {})
349 for builder in masters[master]:
350 if 'presubmit' in builder:
351 # Do not trigger presubmit builders, since they're likely to fail
352 # (e.g. OWNERS checks before finished code review), and we're running
353 # local presubmit anyway.
354 pass
355 else:
356 try_config[master][builder] = ['defaulttests']
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000357
kjellander986ee082015-06-16 04:32:13 -0700358 return try_config