blob: c42900919928917f470fc3cd917afe8963c95f13 [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
71 # Justifications for each filter:
72 #
73 # - build/header_guard : WebRTC coding style says they should be prefixed
74 # with WEBRTC_, which is not possible to configure in
75 # cpplint.py.
76 cpplint._SetFilters('-build/header_guard')
77
78 # Use the strictest verbosity level for cpplint.py (level 1) which is the
79 # default when running cpplint.py from command line.
80 # To make it possible to work with not-yet-converted code, we're only applying
mflodman@webrtc.org2a452092012-07-01 05:55:23 +000081 # it to new (or moved/renamed) files and files listed in LINT_FOLDERS.
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000082 verbosity_level = 1
83 files = []
84 for f in input_api.AffectedSourceFiles(source_file_filter):
Henrik Kjellander57e5fd22015-05-25 12:55:39 +020085 # Note that moved/renamed files also count as added.
86 if f.Action() == 'A':
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000087 files.append(f.AbsoluteLocalPath())
mflodman@webrtc.org2a452092012-07-01 05:55:23 +000088
kjellander@webrtc.org51198f12012-02-21 17:53:46 +000089 for file_name in files:
90 cpplint.ProcessFile(file_name, verbosity_level)
91
92 if cpplint._cpplint_state.error_count > 0:
93 if input_api.is_committing:
94 # TODO(kjellander): Change back to PresubmitError below when we're
95 # confident with the lint settings.
96 res_type = output_api.PresubmitPromptWarning
97 else:
98 res_type = output_api.PresubmitPromptWarning
99 result = [res_type('Changelist failed cpplint.py check.')]
100
101 return result
102
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +0000103def _CheckNoRtcBaseDeps(input_api, gyp_files, output_api):
104 pattern = input_api.re.compile(r"base.gyp:rtc_base\s*'")
105 violating_files = []
106 for f in gyp_files:
henrike@webrtc.org36b0c1a2014-10-01 14:40:58 +0000107 gyp_exceptions = (
108 'base_tests.gyp',
109 'desktop_capture.gypi',
110 'libjingle.gyp',
henrike@webrtc.org28af6412014-11-04 15:11:46 +0000111 'libjingle_tests.gyp',
kjellander@webrtc.orge7237282015-02-26 11:12:17 +0000112 'p2p.gyp',
henrike@webrtc.org36b0c1a2014-10-01 14:40:58 +0000113 'sound.gyp',
114 'webrtc_test_common.gyp',
115 'webrtc_tests.gypi',
116 )
117 if f.LocalPath().endswith(gyp_exceptions):
118 continue
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +0000119 contents = input_api.ReadFile(f)
120 if pattern.search(contents):
121 violating_files.append(f)
122 if violating_files:
123 return [output_api.PresubmitError(
124 'Depending on rtc_base is not allowed. Change your dependency to '
125 'rtc_base_approved and possibly sanitize and move the desired source '
126 'file(s) to rtc_base_approved.\nChanged GYP files:',
127 items=violating_files)]
128 return []
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000129
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000130def _CheckNoSourcesAboveGyp(input_api, gyp_files, output_api):
131 # Disallow referencing source files with paths above the GYP file location.
132 source_pattern = input_api.re.compile(r'sources.*?\[(.*?)\]',
133 re.MULTILINE | re.DOTALL)
kjellander@webrtc.orga33f05e2015-01-29 14:29:45 +0000134 file_pattern = input_api.re.compile(r"'((\.\./.*?)|(<\(webrtc_root\).*?))'")
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000135 violating_gyp_files = set()
136 violating_source_entries = []
137 for gyp_file in gyp_files:
138 contents = input_api.ReadFile(gyp_file)
139 for source_block_match in source_pattern.finditer(contents):
kjellander@webrtc.orgc98f6f32015-03-04 07:08:11 +0000140 # Find all source list entries starting with ../ in the source block
141 # (exclude overrides entries).
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000142 for file_list_match in file_pattern.finditer(source_block_match.group(0)):
kjellander@webrtc.orgc98f6f32015-03-04 07:08:11 +0000143 source_file = file_list_match.group(0)
144 if 'overrides/' not in source_file:
145 violating_source_entries.append(source_file)
146 violating_gyp_files.add(gyp_file)
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000147 if violating_gyp_files:
148 return [output_api.PresubmitError(
149 'Referencing source files above the directory of the GYP file is not '
150 'allowed. Please introduce new GYP targets and/or GYP files in the '
151 'proper location instead.\n'
152 'Invalid source entries:\n'
153 '%s\n'
154 'Violating GYP files:' % '\n'.join(violating_source_entries),
155 items=violating_gyp_files)]
156 return []
157
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000158def _CheckGypChanges(input_api, output_api):
159 source_file_filter = lambda x: input_api.FilterSourceFile(
160 x, white_list=(r'.+\.(gyp|gypi)$',))
161
162 gyp_files = []
163 for f in input_api.AffectedSourceFiles(source_file_filter):
kjellander@webrtc.org3398a4a2014-11-24 10:05:37 +0000164 if f.LocalPath().startswith('webrtc'):
165 gyp_files.append(f)
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000166
167 result = []
168 if gyp_files:
169 result.append(output_api.PresubmitNotifyResult(
170 'As you\'re changing GYP files: please make sure corresponding '
171 'BUILD.gn files are also updated.\nChanged GYP files:',
172 items=gyp_files))
henrike@webrtc.org83fe69d2014-09-30 21:54:26 +0000173 result.extend(_CheckNoRtcBaseDeps(input_api, gyp_files, output_api))
kjellander@webrtc.orgf68ffca2015-01-27 13:13:24 +0000174 result.extend(_CheckNoSourcesAboveGyp(input_api, gyp_files, output_api))
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000175 return result
176
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000177def _CheckUnwantedDependencies(input_api, output_api):
178 """Runs checkdeps on #include statements added in this
179 change. Breaking - rules is an error, breaking ! rules is a
180 warning.
181 """
182 # Copied from Chromium's src/PRESUBMIT.py.
183
184 # We need to wait until we have an input_api object and use this
185 # roundabout construct to import checkdeps because this file is
186 # eval-ed and thus doesn't have __file__.
187 original_sys_path = sys.path
188 try:
kjellander@webrtc.orgaefe61a2014-12-08 13:00:30 +0000189 checkdeps_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
190 'buildtools', 'checkdeps')
191 if not os.path.exists(checkdeps_path):
192 return [output_api.PresubmitError(
193 'Cannot find checkdeps at %s\nHave you run "gclient sync" to '
194 'download Chromium and setup the symlinks?' % checkdeps_path)]
195 sys.path.append(checkdeps_path)
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000196 import checkdeps
197 from cpp_checker import CppChecker
198 from rules import Rule
199 finally:
200 # Restore sys.path to what it was before.
201 sys.path = original_sys_path
202
203 added_includes = []
204 for f in input_api.AffectedFiles():
205 if not CppChecker.IsCppFile(f.LocalPath()):
206 continue
207
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200208 changed_lines = [line for _, line in f.ChangedContents()]
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000209 added_includes.append([f.LocalPath(), changed_lines])
210
211 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
212
213 error_descriptions = []
214 warning_descriptions = []
215 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
216 added_includes):
217 description_with_path = '%s\n %s' % (path, rule_description)
218 if rule_type == Rule.DISALLOW:
219 error_descriptions.append(description_with_path)
220 else:
221 warning_descriptions.append(description_with_path)
222
223 results = []
224 if error_descriptions:
225 results.append(output_api.PresubmitError(
226 'You added one or more #includes that violate checkdeps rules.',
227 error_descriptions))
228 if warning_descriptions:
229 results.append(output_api.PresubmitPromptOrNotify(
230 'You added one or more #includes of files that are temporarily\n'
231 'allowed but being removed. Can you avoid introducing the\n'
232 '#include? See relevant DEPS file(s) for details and contacts.',
233 warning_descriptions))
234 return results
235
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000236
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200237def _RunPythonTests(input_api, output_api):
238 def join(*args):
239 return input_api.os_path.join(input_api.PresubmitLocalPath(), *args)
240
241 test_directories = [
242 join('tools', 'autoroller', 'unittests'),
243 ]
244
245 tests = []
246 for directory in test_directories:
247 tests.extend(
248 input_api.canned_checks.GetUnitTestsInDirectory(
249 input_api,
250 output_api,
251 directory,
252 whitelist=[r'.+_test\.py$']))
253 return input_api.RunTests(tests, parallel=True)
254
255
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000256def _CommonChecks(input_api, output_api):
257 """Checks common to both upload and commit."""
niklase@google.comda159d62011-05-30 11:51:34 +0000258 results = []
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000259 results.extend(input_api.canned_checks.RunPylint(input_api, output_api,
260 black_list=(r'^.*gviz_api\.py$',
261 r'^.*gaeunit\.py$',
fischman@webrtc.org33584f92013-07-25 16:43:30 +0000262 # Embedded shell-script fakes out pylint.
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200263 r'^build[\\\/].*\.py$',
264 r'^buildtools[\\\/].*\.py$',
265 r'^chromium[\\\/].*\.py$',
266 r'^google_apis[\\\/].*\.py$',
267 r'^net.*[\\\/].*\.py$',
268 r'^out.*[\\\/].*\.py$',
269 r'^testing[\\\/].*\.py$',
270 r'^third_party[\\\/].*\.py$',
271 r'^tools[\\\/]find_depot_tools.py$',
272 r'^tools[\\\/]clang[\\\/].*\.py$',
273 r'^tools[\\\/]generate_library_loader[\\\/].*\.py$',
274 r'^tools[\\\/]gn[\\\/].*\.py$',
275 r'^tools[\\\/]gyp[\\\/].*\.py$',
276 r'^tools[\\\/]protoc_wrapper[\\\/].*\.py$',
277 r'^tools[\\\/]python[\\\/].*\.py$',
278 r'^tools[\\\/]python_charts[\\\/]data[\\\/].*\.py$',
279 r'^tools[\\\/]refactoring[\\\/].*\.py$',
280 r'^tools[\\\/]swarming_client[\\\/].*\.py$',
281 r'^tools[\\\/]vim[\\\/].*\.py$',
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000282 # TODO(phoglund): should arguably be checked.
Henrik Kjellander14771ac2015-06-02 13:10:04 +0200283 r'^tools[\\\/]valgrind-webrtc[\\\/].*\.py$',
284 r'^tools[\\\/]valgrind[\\\/].*\.py$',
285 r'^tools[\\\/]win[\\\/].*\.py$',
286 r'^xcodebuild.*[\\\/].*\.py$',),
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000287 disabled_warnings=['F0401', # Failed to import x
288 'E0611', # No package y in x
289 'W0232', # Class has no __init__ method
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200290 ],
291 pylintrc='pylintrc'))
292 # WebRTC can't use the presubmit_canned_checks.PanProjectChecks function since
293 # we need to have different license checks in talk/ and webrtc/ directories.
294 # Instead, hand-picked checks are included below.
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000295 results.extend(input_api.canned_checks.CheckLongLines(
pbos@webrtc.orgf2e7bc62013-04-08 15:46:07 +0000296 input_api, output_api, maxlen=80))
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000297 results.extend(input_api.canned_checks.CheckChangeHasNoTabs(
298 input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000299 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
300 input_api, output_api))
301 results.extend(input_api.canned_checks.CheckChangeTodoHasOwner(
302 input_api, output_api))
mflodman@webrtc.org2a452092012-07-01 05:55:23 +0000303 results.extend(_CheckApprovedFilesLintClean(input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000304 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
305 results.extend(_CheckNoFRIEND_TEST(input_api, output_api))
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000306 results.extend(_CheckGypChanges(input_api, output_api))
kjellander@webrtc.org3bd41562014-09-01 11:06:37 +0000307 results.extend(_CheckUnwantedDependencies(input_api, output_api))
Henrik Kjellander8d3ad822015-05-26 19:52:05 +0200308 results.extend(_RunPythonTests(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000309 return results
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000310
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000311
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000312def CheckChangeOnUpload(input_api, output_api):
313 results = []
314 results.extend(_CommonChecks(input_api, output_api))
Henrik Kjellander57e5fd22015-05-25 12:55:39 +0200315 results.extend(
316 input_api.canned_checks.CheckGNFormatted(input_api, output_api))
niklase@google.comda159d62011-05-30 11:51:34 +0000317 return results
318
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000319
andrew@webrtc.org2442de12012-01-23 17:45:41 +0000320def CheckChangeOnCommit(input_api, output_api):
niklase@google.com1198db92011-06-09 07:07:24 +0000321 results = []
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000322 results.extend(_CommonChecks(input_api, output_api))
niklase@google.com1198db92011-06-09 07:07:24 +0000323 results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
andrew@webrtc.org53df1362012-01-26 21:24:23 +0000324 results.extend(input_api.canned_checks.CheckChangeWasUploaded(
325 input_api, output_api))
326 results.extend(input_api.canned_checks.CheckChangeHasDescription(
327 input_api, output_api))
kjellander@webrtc.org51198f12012-02-21 17:53:46 +0000328 results.extend(input_api.canned_checks.CheckChangeHasBugField(
329 input_api, output_api))
330 results.extend(input_api.canned_checks.CheckChangeHasTestField(
331 input_api, output_api))
kjellander@webrtc.org12cb88c2014-02-13 11:53:43 +0000332 results.extend(input_api.canned_checks.CheckTreeIsOpen(
333 input_api, output_api,
334 json_url='http://webrtc-status.appspot.com/current?format=json'))
niklase@google.com1198db92011-06-09 07:07:24 +0000335 return results
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000336
kjellander@webrtc.orge4158642014-08-06 09:11:18 +0000337
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000338# pylint: disable=W0613
kjellander@webrtc.orgc7b8b2f2014-04-03 20:19:36 +0000339def GetPreferredTryMasters(project, change):
kjellander986ee082015-06-16 04:32:13 -0700340 cq_config_path = os.path.join(
tandrii04465d22015-06-20 04:00:49 -0700341 change.RepositoryRoot(), 'infra', 'config', 'cq.cfg')
kjellander986ee082015-06-16 04:32:13 -0700342 # commit_queue.py below is a script in depot_tools directory, which has a
343 # 'builders' command to retrieve a list of CQ builders from the CQ config.
344 is_win = platform.system() == 'Windows'
345 masters = json.loads(subprocess.check_output(
346 ['commit_queue', 'builders', cq_config_path], shell=is_win))
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000347
kjellander986ee082015-06-16 04:32:13 -0700348 try_config = {}
349 for master in masters:
350 try_config.setdefault(master, {})
351 for builder in masters[master]:
352 if 'presubmit' in builder:
353 # Do not trigger presubmit builders, since they're likely to fail
354 # (e.g. OWNERS checks before finished code review), and we're running
355 # local presubmit anyway.
356 pass
357 else:
358 try_config[master][builder] = ['defaulttests']
kjellander@webrtc.org85759802013-10-22 16:47:40 +0000359
kjellander986ee082015-06-16 04:32:13 -0700360 return try_config