blob: b3a17c675c2a89a1d68df153e396a93128974cd6 [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371# Copyright (C) 2014 Google Inc. All rights reserved.
2#
3# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions are
5# met:
6#
7# * Redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer.
9# * Redistributions in binary form must reproduce the above
10# copyright notice, this list of conditions and the following disclaimer
11# in the documentation and/or other materials provided with the
12# distribution.
13# * Neither the name of Google Inc. nor the names of its
14# contributors may be used to endorse or promote products derived from
15# this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Yang Guo75beda92019-10-28 07:29:2528"""
29DevTools presubmit script
Blink Reformat4c46d092018-04-07 15:32:3730
Benedikt Meurerbc9da612024-08-19 10:44:4931See http://goo.gle/devtools-testing-guide#Presubmit-checks for more how to
32run presubmit checks in DevTools.
33
Blink Reformat4c46d092018-04-07 15:32:3734See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
35for more details about the presubmit API built into gcl.
36"""
37
38import sys
Tim van der Lippef515fdc2020-03-06 16:18:2539import six
Tim van der Lippefb023462020-08-21 13:10:0640import time
Blink Reformat4c46d092018-04-07 15:32:3741
Alex Rudenko4a7a3242024-04-18 10:36:5042from pathlib import Path
43
Liviu Rauf3028602023-11-10 10:52:0444# Depot tools imports
45import rdb_wrapper
46
Liviu Raufd2e3212019-12-18 15:38:2047AUTOROLL_ACCOUNT = "devtools-ci-autoroll-builder@chops-service-accounts.iam.gserviceaccount.com"
Tim van der Lippefb1dc172021-05-11 15:40:2648USE_PYTHON3 = True
Mathias Bynensa0a6e292019-12-17 12:24:0849
Alex Rudenko537c6312024-07-19 06:22:0550
Tim van der Lippe4d004ec2020-03-03 18:32:0151def _ExecuteSubProcess(input_api, output_api, script_path, args, results):
Tim van der Lippef515fdc2020-03-06 16:18:2552 if isinstance(script_path, six.string_types):
Philip Pfaffef4320aa2022-07-21 11:33:2453 script_path = [input_api.python3_executable, script_path]
Tim van der Lippef515fdc2020-03-06 16:18:2554
Tim van der Lippefb023462020-08-21 13:10:0655 start_time = time.time()
Sigurd Schneiderf3a1ecd2021-03-02 14:46:0356 process = input_api.subprocess.Popen(script_path + args,
57 stdout=input_api.subprocess.PIPE,
58 stderr=input_api.subprocess.STDOUT)
Tim van der Lippe4d004ec2020-03-03 18:32:0159 out, _ = process.communicate()
Tim van der Lippefb023462020-08-21 13:10:0660 end_time = time.time()
61
62 time_difference = end_time - start_time
63 time_info = "Script execution time was %.1fs seconds\n" % (time_difference)
Tim van der Lippe4d004ec2020-03-03 18:32:0164 if process.returncode != 0:
Tim van der Lippefb1dc172021-05-11 15:40:2665 results.append(
66 output_api.PresubmitError(time_info + out.decode('utf-8')))
Tim van der Lippe4d004ec2020-03-03 18:32:0167 else:
Tim van der Lippefb1dc172021-05-11 15:40:2668 results.append(
69 output_api.PresubmitNotifyResult(time_info + out.decode('utf-8')))
Tim van der Lippe4d004ec2020-03-03 18:32:0170 return results
71
72
Gavin Mak4a41e482024-07-31 17:16:4473def _IsEnvCog(input_api):
74 old_sys_path = sys.path[:]
75 devtools_root = input_api.PresubmitLocalPath()
76 depot_tools = input_api.os_path.join(devtools_root, 'third_party',
77 'depot_tools')
78 try:
79 sys.path.append(depot_tools)
80 from gclient_utils import IsEnvCog
81 if IsEnvCog():
82 return True
83 finally:
84 sys.path = old_sys_path
85 return False
86
87
Sigurd Schneider5c9b4f92021-01-22 10:09:5588def _CheckBugAssociation(input_api, output_api, is_committing):
89 results = [output_api.PresubmitNotifyResult('Bug Association Check:')]
90 bugs = input_api.change.BugsFromDescription()
91 message = (
92 "Each CL should be associated with a bug, use \'Bug:\' or \'Fixed:\' lines in\n"
93 "the footer of the commit description. If you explicitly don\'t want to\n"
94 "set a bug, use \'Bug: none\' in the footer of the commit description.\n\n"
95 "Note: The footer of the commit description is the last block of lines in\n"
96 "the commit description that doesn't contain empty lines. This means that\n"
97 "any \'Bug:\' or \'Fixed:\' lines that are eventually followed by an empty\n"
98 "line are not detected by this presubmit check.")
99
100 if not bugs:
101 if is_committing:
102 results.append(output_api.PresubmitError(message))
103 else:
104 results.append(output_api.PresubmitNotifyResult(message))
105
106 for bug in bugs:
107 results.append(output_api.PresubmitNotifyResult(('%s') % bug))
108
109 return results
110
111
Brandon Goddard33104372020-08-13 15:49:23112def _CheckExperimentTelemetry(input_api, output_api):
Brandon Goddard33104372020-08-13 15:49:23113 experiment_telemetry_files = [
114 input_api.os_path.join(input_api.PresubmitLocalPath(), 'front_end',
Christy Chenab9a44d2021-07-02 19:54:30115 'entrypoints', 'main', 'MainImpl.ts'),
Brandon Goddard33104372020-08-13 15:49:23116 input_api.os_path.join(input_api.PresubmitLocalPath(), 'front_end',
Tim van der Lippee0247312021-04-01 14:25:30117 'core', 'host', 'UserMetrics.ts')
Brandon Goddard33104372020-08-13 15:49:23118 ]
119 affected_main_files = _getAffectedFiles(input_api,
120 experiment_telemetry_files, [],
Christy Chenab9a44d2021-07-02 19:54:30121 ['.ts'])
Brandon Goddard33104372020-08-13 15:49:23122 if len(affected_main_files) == 0:
Tim van der Lippefb023462020-08-21 13:10:06123 return [
124 output_api.PresubmitNotifyResult(
125 'No affected files for telemetry check')
126 ]
Brandon Goddard33104372020-08-13 15:49:23127
Tim van der Lippefb023462020-08-21 13:10:06128 results = [
129 output_api.PresubmitNotifyResult('Running Experiment Telemetry check:')
130 ]
Brandon Goddard33104372020-08-13 15:49:23131 script_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
132 'scripts', 'check_experiments.js')
133 results.extend(_checkWithNodeScript(input_api, output_api, script_path))
134 return results
135
136
Jack Franklinb5a63092022-11-30 14:32:36137def _CheckESBuildVersion(input_api, output_api):
138 results = [
139 output_api.PresubmitNotifyResult('Running ESBuild version check:')
140 ]
141 script_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
142 'scripts',
143 'check_esbuild_versions.js')
144 results.extend(_checkWithNodeScript(input_api, output_api, script_path))
145 return results
146
147
Blink Reformat4c46d092018-04-07 15:32:37148def _CheckFormat(input_api, output_api):
Gavin Mak4a41e482024-07-31 17:16:44149 if _IsEnvCog(input_api):
150 return [
151 output_api.PresubmitPromptWarning(
152 'Non-git environment detected, skipping _CheckFormat.')
153 ]
154
Brandon Goddarde7028672020-01-30 17:31:04155 results = [output_api.PresubmitNotifyResult('Running Format Checks:')]
Blink Reformat4c46d092018-04-07 15:32:37156
Simon Zündcc994132024-02-15 07:34:44157 return _ExecuteSubProcess(input_api, output_api,
Alex Rudenko518bfae2024-12-02 13:04:52158 ['git', 'cl', 'format', '--js'], [], results)
Blink Reformat4c46d092018-04-07 15:32:37159
Jack Franklin1aa212d2021-09-10 14:20:08160
161def _CheckDevToolsRunESLintTests(input_api, output_api):
162 # Check for changes in the eslint_rules directory, and run the eslint rules
163 # tests if so.
164 # We don't do this on every CL as most do not touch the rules, but if we do
165 # change them we need to make sure all the tests are passing.
Jack Franklin03db63a2021-09-16 13:40:56166 original_sys_path = sys.path
167 try:
168 sys.path = sys.path + [
169 input_api.os_path.join(input_api.PresubmitLocalPath(), 'scripts')
170 ]
171 import devtools_paths
172 finally:
173 sys.path = original_sys_path
Jack Franklin1aa212d2021-09-10 14:20:08174 eslint_rules_dir_path = input_api.os_path.join(
175 input_api.PresubmitLocalPath(), 'scripts', 'eslint_rules')
Nikolay Vitkov77ba8df2025-03-27 15:06:08176 eslint_rules_checked_paths = [
177 # Check if EsLint is updated
178 input_api.os_path.join(input_api.PresubmitLocalPath(), 'node_modules',
179 'eslint'),
180 # Check for rules changes
181 eslint_rules_dir_path,
182 ]
183 eslint_rules_affected_files = _getAffectedFiles(
184 input_api, eslint_rules_checked_paths, [], [])
Jack Franklin1aa212d2021-09-10 14:20:08185
186 if (len(eslint_rules_affected_files) == 0):
187 return []
188
Jack Franklin03db63a2021-09-16 13:40:56189 mocha_path = devtools_paths.mocha_path()
Jack Franklin1aa212d2021-09-10 14:20:08190 eslint_tests_path = input_api.os_path.join(eslint_rules_dir_path, 'tests',
Benedikt Meurer586a9a52024-12-27 10:28:21191 '*.test.js')
Jack Franklin1aa212d2021-09-10 14:20:08192
193 results = [output_api.PresubmitNotifyResult('ESLint rules unit tests')]
194 results.extend(
195 # The dot reporter is more concise which is useful to not get LOADS of
196 # output when just one test fails.
197 _checkWithNodeScript(input_api, output_api, mocha_path,
198 ['--reporter', 'dot', eslint_tests_path]))
199 return results
200
201
Nikolay Vitkov77ba8df2025-03-27 15:06:08202def _CheckDevToolsRunStylelintTests(input_api, output_api):
203 # Check for changes in the stylelint_rules directory, and run the stylelint rules
204 # tests if so.
205 # We don't do this on every CL as most do not touch the rules, but if we do
206 # change them we need to make sure all the tests are passing.
207 original_sys_path = sys.path
208 try:
209 sys.path = sys.path + [
210 input_api.os_path.join(input_api.PresubmitLocalPath(), 'scripts')
211 ]
212 import devtools_paths
213 finally:
214 sys.path = original_sys_path
215
216 stylelint_tests_path = input_api.os_path.join(
217 input_api.PresubmitLocalPath(), 'scripts', 'stylelint_rules')
218 stylelint_rules_check_paths = [
219 input_api.os_path.join(input_api.PresubmitLocalPath(), 'node_modules',
220 'stylelint'),
221 # Rule is added/updated
222 stylelint_tests_path,
223 # Variable declaration used in test are changed
224 input_api.os_path.join(input_api.PresubmitLocalPath(), 'front_end',
225 'application_tokens.css'),
226 input_api.os_path.join(input_api.PresubmitLocalPath(), 'front_end',
227 'design_system_tokens.css'),
228 input_api.os_path.join(input_api.PresubmitLocalPath(), 'front_end',
229 'inspectorCommon.css'),
230 ]
231 stylelint_rules_affected_files = _getAffectedFiles(
232 input_api, stylelint_rules_check_paths, [], [])
233
234 if (len(stylelint_rules_affected_files) == 0):
235 return []
236
237 mocha_path = devtools_paths.mocha_path()
238 stylelint_tests_path = input_api.os_path.join(stylelint_tests_path,
239 'tests', '*.test.js')
240
241 results = [output_api.PresubmitNotifyResult('Stylelint rules unit tests')]
242 results.extend(
243 # The dot reporter is more concise which is useful to not get LOADS of
244 # output when just one test fails.
245 _checkWithNodeScript(input_api, output_api, mocha_path,
246 ['--reporter', 'dot', stylelint_tests_path]))
247 return results
248
249
Tim van der Lippe800d8752022-02-04 12:49:56250def _CheckDevToolsRunBuildTests(input_api, output_api):
251 # Check for changes in the build/tests directory, and run the tests if so.
252 # We don't do this on every CL as most do not touch the rules, but if we do
253 # change them we need to make sure all the tests are passing.
254 original_sys_path = sys.path
255 try:
256 sys.path = sys.path + [
257 input_api.os_path.join(input_api.PresubmitLocalPath(), 'scripts')
258 ]
259 import devtools_paths
260 finally:
261 sys.path = original_sys_path
262 scripts_build_dir_path = input_api.os_path.join(
263 input_api.PresubmitLocalPath(), 'scripts', 'build')
264 scripts_build_affected_files = _getAffectedFiles(input_api,
265 [scripts_build_dir_path],
266 [], [])
267
268 if len(scripts_build_affected_files) == 0:
269 return []
270
271 mocha_path = devtools_paths.mocha_path()
272 build_tests_path = input_api.os_path.join(scripts_build_dir_path, 'tests',
273 '*_test.js')
274
275 results = [output_api.PresubmitNotifyResult('Build plugins unit tests')]
276 results.extend(
277 # The dot reporter is more concise which is useful to not get LOADS of
278 # output when just one test fails.
279 _checkWithNodeScript(input_api, output_api, mocha_path,
280 ['--reporter', 'dot', build_tests_path]))
281 return results
282
283
Benedikt Meurer6dd23b62024-08-20 12:08:43284def _CheckDevToolsLint(input_api, output_api):
285 results = [output_api.PresubmitNotifyResult('Lint Check:')]
Mathias Bynens1b2c5e42020-06-18 06:29:21286 lint_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
Nikolay Vitkov2a1b3b32025-01-03 10:18:46287 'scripts', 'test', 'run_lint_check.mjs')
Tim van der Lippe4d004ec2020-03-03 18:32:01288
Mathias Bynens1b2c5e42020-06-18 06:29:21289 front_end_directory = input_api.os_path.join(
290 input_api.PresubmitLocalPath(), 'front_end')
Nikolay Vitkov77ba8df2025-03-27 15:06:08291
Alex Rudenko5556a902020-09-29 09:37:23292 inspector_overlay_directory = input_api.os_path.join(
293 input_api.PresubmitLocalPath(), 'inspector_overlay')
Mathias Bynens1b2c5e42020-06-18 06:29:21294 test_directory = input_api.os_path.join(input_api.PresubmitLocalPath(),
295 'test')
296 scripts_directory = input_api.os_path.join(input_api.PresubmitLocalPath(),
297 'scripts')
Tim van der Lippe2a4ae2b2020-03-11 17:28:06298
Mathias Bynens1b2c5e42020-06-18 06:29:21299 default_linted_directories = [
Benedikt Meurer6dd23b62024-08-20 12:08:43300 front_end_directory,
301 test_directory,
302 scripts_directory,
303 inspector_overlay_directory,
Mathias Bynens1b2c5e42020-06-18 06:29:21304 ]
Tim van der Lippe2a4ae2b2020-03-11 17:28:06305
Benedikt Meurer6dd23b62024-08-20 12:08:43306 lint_related_files = [
Mathias Bynens1b2c5e42020-06-18 06:29:21307 input_api.os_path.join(input_api.PresubmitLocalPath(),
Nikolay Vitkov55adf672025-01-02 12:07:33308 'eslint.config.mjs'),
Benedikt Meurer6dd23b62024-08-20 12:08:43309 input_api.os_path.join(input_api.PresubmitLocalPath(),
310 '.stylelintrc.json'),
311 input_api.os_path.join(input_api.PresubmitLocalPath(),
312 '.stylelintignore'),
Nikolay Vitkov5b2bcff2025-01-29 19:21:12313 # This file includes the LitAnalyzer rules
314 input_api.os_path.join(input_api.PresubmitLocalPath(),
315 'tsconfig.json'),
Nikolay Vitkov2a1b3b32025-01-03 10:18:46316 input_api.os_path.join(scripts_directory, 'test',
317 'run_lint_check.mjs'),
Tim van der Lippe2a4ae2b2020-03-11 17:28:06318 ]
319
Nikolay Vitkove2e44022025-04-01 17:29:41320 lint_related_directories = [
321 input_api.os_path.join(input_api.PresubmitLocalPath(), 'node_modules',
322 'eslint'),
323 input_api.os_path.join(input_api.PresubmitLocalPath(), 'node_modules',
324 'stylelint'),
325 input_api.os_path.join(input_api.PresubmitLocalPath(), 'node_modules',
326 '@typescript-eslint'),
327 input_api.os_path.join(scripts_directory, 'eslint_rules'),
328 ]
329
330 lint_config_files = _getAffectedFiles(
331 input_api, lint_related_directories,
332 [], [".js", ".mjs", ".ts"]) + _getAffectedFiles(
333 input_api, lint_related_files, [], [])
Tim van der Lippe2a4ae2b2020-03-11 17:28:06334
Mathias Bynens0ec56612020-06-19 07:14:03335 should_bail_out, files_to_lint = _getFilesToLint(
336 input_api, output_api, lint_config_files, default_linted_directories,
Nikolay Vitkov22050502025-01-21 10:09:31337 ['.css', '.mjs', '.js', '.ts'], results)
Mathias Bynens0ec56612020-06-19 07:14:03338 if should_bail_out:
Mathias Bynens1b2c5e42020-06-18 06:29:21339 return results
Tim van der Lippe2a4ae2b2020-03-11 17:28:06340
Brandon Goddarde34e94f2021-04-12 17:58:26341 # If there are more than 50 files to check, don't bother and check
342 # everything, so as to not run into command line length limits on Windows.
343 if len(files_to_lint) > 50:
344 files_to_lint = []
345
Mathias Bynens1b2c5e42020-06-18 06:29:21346 results.extend(
Nikolay Vitkovc9178752025-04-02 13:37:07347 _checkWithNodeScript(input_api,
348 output_api,
349 lint_path,
350 files_to_lint,
351 allow_typescript=True))
Tim van der Lippe98132242020-04-14 16:16:54352 return results
Blink Reformat4c46d092018-04-07 15:32:37353
Nikolay Vitkov55adf672025-01-02 12:07:33354
Tim van der Lippea53672d2021-07-08 14:52:35355def _CheckDevToolsNonJSFileLicenseHeaders(input_api, output_api):
Tim van der Lippe81752502021-05-26 14:38:12356 results = [
357 output_api.PresubmitNotifyResult(
358 'Python-like file license header check:')
359 ]
Tim van der Lippea53672d2021-07-08 14:52:35360 lint_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
361 'scripts', 'test',
362 'run_header_check_non_js_files.js')
Tim van der Lippe81752502021-05-26 14:38:12363
364 front_end_directory = input_api.os_path.join(
365 input_api.PresubmitLocalPath(), 'front_end')
366 inspector_overlay_directory = input_api.os_path.join(
367 input_api.PresubmitLocalPath(), 'inspector_overlay')
368 test_directory = input_api.os_path.join(input_api.PresubmitLocalPath(),
369 'test')
370 scripts_directory = input_api.os_path.join(input_api.PresubmitLocalPath(),
371 'scripts')
Tim van der Lippe8b929542021-05-26 14:54:20372 config_directory = input_api.os_path.join(input_api.PresubmitLocalPath(),
373 'config')
Tim van der Lippe81752502021-05-26 14:38:12374
375 default_linted_directories = [
376 front_end_directory, test_directory, scripts_directory,
Tim van der Lippe8b929542021-05-26 14:54:20377 inspector_overlay_directory, config_directory
Tim van der Lippe81752502021-05-26 14:38:12378 ]
379
380 check_related_files = [lint_path]
381
382 lint_config_files = _getAffectedFiles(input_api, check_related_files, [],
383 ['.js'])
384
385 should_bail_out, files_to_lint = _getFilesToLint(
386 input_api, output_api, lint_config_files, default_linted_directories,
Tim van der Lippea53672d2021-07-08 14:52:35387 ['BUILD.gn', '.gni', '.css'], results)
Tim van der Lippe81752502021-05-26 14:38:12388 if should_bail_out:
389 return results
390
391 # If there are more than 50 files to check, don't bother and check
392 # everything, so as to not run into command line length limits on Windows.
393 if len(files_to_lint) > 50:
394 files_to_lint = []
395
396 results.extend(
397 _checkWithNodeScript(input_api, output_api, lint_path, files_to_lint))
398 return results
399
400
Tim van der Lippe4d004ec2020-03-03 18:32:01401def _CheckGeneratedFiles(input_api, output_api):
Alex Rudenko537c6312024-07-19 06:22:05402 v8_directory_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
403 'v8')
404 blink_directory_path = input_api.os_path.join(
405 input_api.PresubmitLocalPath(), 'third_party', 'blink')
406 protocol_location = input_api.os_path.join(blink_directory_path, 'public',
407 'devtools_protocol')
408 scripts_build_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
409 'scripts', 'build')
410 scripts_generated_output_path = input_api.os_path.join(
411 input_api.PresubmitLocalPath(), 'front_end', 'generated')
Tim van der Lippeb3b90762020-03-04 15:21:52412
Alex Rudenko537c6312024-07-19 06:22:05413 generated_aria_path = input_api.os_path.join(scripts_build_path,
414 'generate_aria.py')
415 generated_supported_css_path = input_api.os_path.join(
416 scripts_build_path, 'generate_supported_css.py')
Simon Zünd2ce67542023-02-07 10:15:14417 generated_deprecation_path = input_api.os_path.join(
418 scripts_build_path, 'generate_deprecations.py')
Alex Rudenko537c6312024-07-19 06:22:05419 generated_protocol_path = input_api.os_path.join(
420 scripts_build_path, 'code_generator_frontend.py')
Tim van der Lippe2a1eac22021-05-13 15:19:29421 generated_protocol_typescript_path = input_api.os_path.join(
422 input_api.PresubmitLocalPath(), 'scripts', 'protocol_typescript')
Alex Rudenko537c6312024-07-19 06:22:05423 concatenate_protocols_path = input_api.os_path.join(
424 input_api.PresubmitLocalPath(), 'third_party', 'inspector_protocol',
425 'concatenate_protocols.py')
Tim van der Lippeb3b90762020-03-04 15:21:52426
427 affected_files = _getAffectedFiles(input_api, [
428 v8_directory_path,
429 blink_directory_path,
Tim van der Lippe2a1eac22021-05-13 15:19:29430 input_api.os_path.join(input_api.PresubmitLocalPath(), 'third_party',
431 'pyjson5'),
Tim van der Lippeb3b90762020-03-04 15:21:52432 generated_aria_path,
433 generated_supported_css_path,
Simon Zünd2ce67542023-02-07 10:15:14434 generated_deprecation_path,
Tim van der Lippeb3b90762020-03-04 15:21:52435 concatenate_protocols_path,
436 generated_protocol_path,
Tim van der Lippe5d2d79b2020-03-23 11:45:04437 scripts_generated_output_path,
Tim van der Lippe2a1eac22021-05-13 15:19:29438 generated_protocol_typescript_path,
439 ], [], ['.pdl', '.json5', '.py', '.js', '.ts'])
Tim van der Lippeb3b90762020-03-04 15:21:52440
441 if len(affected_files) == 0:
Tim van der Lippefb023462020-08-21 13:10:06442 return [
443 output_api.PresubmitNotifyResult(
444 'No affected files for generated files check')
445 ]
Tim van der Lippeb3b90762020-03-04 15:21:52446
Alex Rudenko537c6312024-07-19 06:22:05447 results = [
448 output_api.PresubmitNotifyResult('Running Generated Files Check:')
449 ]
450 generate_protocol_resources_path = input_api.os_path.join(
451 input_api.PresubmitLocalPath(), 'scripts', 'deps',
452 'generate_protocol_resources.py')
Tim van der Lippe4d004ec2020-03-03 18:32:01453
Alex Rudenko537c6312024-07-19 06:22:05454 return _ExecuteSubProcess(input_api, output_api,
455 generate_protocol_resources_path, [], results)
Tim van der Lippe4d004ec2020-03-03 18:32:01456
457
Simon Zünd9ff4da62022-11-22 09:25:59458def _CheckL10nStrings(input_api, output_api):
Christy Chen2d6d9a62020-09-22 16:04:09459 devtools_root = input_api.PresubmitLocalPath()
460 devtools_front_end = input_api.os_path.join(devtools_root, 'front_end')
Tim van der Lippe25f11082021-06-24 15:28:08461 script_path = input_api.os_path.join(devtools_root, 'third_party', 'i18n',
Simon Zünd9ff4da62022-11-22 09:25:59462 'check-strings.js')
Tim van der Lippe25f11082021-06-24 15:28:08463 affected_front_end_files = _getAffectedFiles(
464 input_api, [devtools_front_end, script_path], [], ['.js', '.ts'])
Christy Chen2d6d9a62020-09-22 16:04:09465 if len(affected_front_end_files) == 0:
466 return [
467 output_api.PresubmitNotifyResult(
Simon Zünd9ff4da62022-11-22 09:25:59468 'No affected files to run check-strings')
Christy Chen2d6d9a62020-09-22 16:04:09469 ]
470
471 results = [
Simon Zünd9ff4da62022-11-22 09:25:59472 output_api.PresubmitNotifyResult('Checking UI strings from front_end:')
Christy Chen2d6d9a62020-09-22 16:04:09473 ]
Tim van der Lippe25f11082021-06-24 15:28:08474 results.extend(
475 _checkWithNodeScript(input_api, output_api, script_path,
476 [devtools_front_end]))
Christy Chen2d6d9a62020-09-22 16:04:09477 return results
478
479
Tim van der Lippe5279f842020-01-14 16:26:38480def _CheckNoUncheckedFiles(input_api, output_api):
Gavin Mak4a41e482024-07-31 17:16:44481 if _IsEnvCog(input_api):
482 return [
483 output_api.PresubmitPromptWarning(
484 'Non-git environment detected, skipping '
485 '_CheckNoUncheckedFiles.')
486 ]
487
Tim van der Lippe5279f842020-01-14 16:26:38488 process = input_api.subprocess.Popen(['git', 'diff', '--exit-code'],
489 stdout=input_api.subprocess.PIPE,
490 stderr=input_api.subprocess.STDOUT)
491 out, _ = process.communicate()
492 if process.returncode != 0:
Jack Franklin324f3042020-09-03 10:28:29493 files_changed_process = input_api.subprocess.Popen(
Tim van der Lippe25f11082021-06-24 15:28:08494 ['git', 'diff'],
Jack Franklin324f3042020-09-03 10:28:29495 stdout=input_api.subprocess.PIPE,
496 stderr=input_api.subprocess.STDOUT)
Tim van der Lippe9bb1cf62020-03-06 16:17:02497 files_changed, _ = files_changed_process.communicate()
498
499 return [
Tim van der Lippefb1dc172021-05-11 15:40:26500 output_api.PresubmitError(
501 'You have changed files that need to be committed:'),
502 output_api.PresubmitError(files_changed.decode('utf-8'))
Tim van der Lippe9bb1cf62020-03-06 16:17:02503 ]
Tim van der Lippe5279f842020-01-14 16:26:38504 return []
505
Alex Rudenko537c6312024-07-19 06:22:05506
Tim van der Lippe8fdda112020-01-27 11:27:06507def _CheckForTooLargeFiles(input_api, output_api):
Christy Chen1ab87e02020-01-31 00:32:16508 """Avoid large files, especially binary files, in the repository since
Tim van der Lippe8fdda112020-01-27 11:27:06509 git doesn't scale well for those. They will be in everyone's repo
510 clones forever, forever making Chromium slower to clone and work
511 with."""
Christy Chen1ab87e02020-01-31 00:32:16512 # Uploading files to cloud storage is not trivial so we don't want
513 # to set the limit too low, but the upper limit for "normal" large
514 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
515 # anything over 20 MB is exceptional.
516 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
517 too_large_files = []
518 for f in input_api.AffectedFiles():
519 # Check both added and modified files (but not deleted files).
520 if f.Action() in ('A', 'M'):
521 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
522 if size > TOO_LARGE_FILE_SIZE_LIMIT:
523 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
524 if too_large_files:
525 message = (
Alex Rudenko537c6312024-07-19 06:22:05526 'Do not commit large files to git since git scales badly for those.\n'
527 +
528 'Instead put the large files in cloud storage and use DEPS to\n' +
529 'fetch them.\n' + '\n'.join(too_large_files))
530 return [
531 output_api.PresubmitError('Too large files found in commit',
532 long_text=message + '\n')
533 ]
Christy Chen1ab87e02020-01-31 00:32:16534 else:
535 return []
Tim van der Lippe8fdda112020-01-27 11:27:06536
Tim van der Lippe5279f842020-01-14 16:26:38537
Andrés Olivares205bf682023-02-01 10:47:13538def _CheckObsoleteScreenshotGoldens(input_api, output_api):
539 results = [
540 output_api.PresubmitNotifyResult('Obsolete screenshot images check')
541 ]
542 interaction_test_root_path = input_api.os_path.join(
543 input_api.PresubmitLocalPath(), 'test', 'interactions')
544 interaction_test_files = [interaction_test_root_path]
545
546 interaction_test_files_changed = _getAffectedFiles(input_api,
547 interaction_test_files,
548 [], [])
549
550 if len(interaction_test_files_changed) > 0:
551 script_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
552 'scripts', 'test',
553 'check_obsolete_goldens.js')
Andrés Olivares205bf682023-02-01 10:47:13554
Philip Pfaffece5afc02024-04-09 13:08:58555 script_args = []
Andrés Olivares205bf682023-02-01 10:47:13556 errors_from_script = _checkWithNodeScript(input_api, output_api,
557 script_path, script_args)
558 results.extend(errors_from_script)
559
560 return results
561
562
Liviu Rauf3028602023-11-10 10:52:04563def _WithArgs(checkType, **kwargs):
Alex Rudenko537c6312024-07-19 06:22:05564
Liviu Rauf3028602023-11-10 10:52:04565 def _WithArgsWrapper(input_api, output_api):
566 return checkType(input_api, output_api, **kwargs)
567
568 _WithArgsWrapper.__name__ = checkType.__name__
569 return _WithArgsWrapper
Tim van der Lippef8a87092020-09-14 12:01:18570
571
Liviu Rauf3028602023-11-10 10:52:04572def _CannedChecks(canned_checks):
573 return [
574 canned_checks.CheckForCommitObjects,
575 canned_checks.CheckOwnersFormat,
576 canned_checks.CheckOwners,
577 canned_checks.CheckChangeHasNoCrAndHasOnlyOneEol,
578 _WithArgs(canned_checks.CheckChangeHasNoStrayWhitespace,
579 source_file_filter=lambda file: not file.LocalPath().
580 startswith('node_modules')),
581 canned_checks.CheckGenderNeutral,
Jack Franklin6bc1cbd2024-07-09 10:44:09582 canned_checks.CheckDoNotSubmitInFiles,
Liviu Rauf3028602023-11-10 10:52:04583 ]
Jack Franklinb10193f2021-03-19 10:25:08584
Liviu Rauf3028602023-11-10 10:52:04585
586def _CommonChecks(canned_checks):
587 local_checks = [
588 _WithArgs(canned_checks.CheckAuthorizedAuthor,
Benedikt Meurer6dd23b62024-08-20 12:08:43589 bot_allowlist=[AUTOROLL_ACCOUNT]),
590 _CheckExperimentTelemetry,
591 _CheckGeneratedFiles,
592 _CheckDevToolsLint,
593 _CheckDevToolsRunESLintTests,
Nikolay Vitkov77ba8df2025-03-27 15:06:08594 _CheckDevToolsRunStylelintTests,
Benedikt Meurer6dd23b62024-08-20 12:08:43595 _CheckDevToolsRunBuildTests,
596 _CheckDevToolsNonJSFileLicenseHeaders,
597 _CheckFormat,
598 _CheckESBuildVersion,
Benedikt Meurer6dd23b62024-08-20 12:08:43599 _CheckObsoleteScreenshotGoldens,
600 _CheckNodeModules,
Liviu Rauf3028602023-11-10 10:52:04601 ]
Tim van der Lippef8a87092020-09-14 12:01:18602 # Run the canned checks from `depot_tools` after the custom DevTools checks.
603 # The canned checks for example check that lines have line endings. The
604 # DevTools presubmit checks automatically fix these issues. If we would run
605 # the canned checks before the DevTools checks, they would erroneously conclude
606 # that there are issues in the code. Since the canned checks are allowed to be
607 # ignored, a confusing message is shown that asks if the failed presubmit can
608 # be continued regardless. By fixing the issues before we reach the canned checks,
609 # we don't show the message to suppress these errors, which would otherwise be
610 # causing CQ to fail.
Liviu Rauf3028602023-11-10 10:52:04611 return local_checks + _CannedChecks(canned_checks)
Kalon Hindsd44fddf2020-12-10 13:43:25612
613
614def _SideEffectChecks(input_api, output_api):
615 """Check side effects caused by other checks"""
616 results = []
Tim van der Lippe5279f842020-01-14 16:26:38617 results.extend(_CheckNoUncheckedFiles(input_api, output_api))
Tim van der Lippe8fdda112020-01-27 11:27:06618 results.extend(_CheckForTooLargeFiles(input_api, output_api))
Blink Reformat4c46d092018-04-07 15:32:37619 return results
620
621
Liviu Rauf3028602023-11-10 10:52:04622def _RunAllChecks(checks, input_api, output_api):
623 with rdb_wrapper.client("presubmit:") as sink:
624 results = []
625 for check in checks:
626 start_time = time.time()
627
628 result = check(input_api, output_api)
629
630 elapsed_time = time.time() - start_time
631 results.extend(result)
632
633 if not sink:
634 continue
635 failure_reason = None
636 status = rdb_wrapper.STATUS_PASS
637 if any(r.fatal for r in result):
638 status = rdb_wrapper.STATUS_FAIL
639 failure_reasons = []
640 for r in result:
641 fields = r.json_format()
642 message = fields['message']
643 items = '\n'.join(' %s' % item
644 for item in fields['items'])
645 failure_reasons.append('\n'.join([message, items]))
646 if failure_reasons:
647 failure_reason = '\n'.join(failure_reasons)
648 sink.report(check.__name__, status, elapsed_time, failure_reason)
649
650 return results
651
652
Liviu Raud614e092020-01-08 09:56:33653def CheckChangeOnUpload(input_api, output_api):
Liviu Rauf3028602023-11-10 10:52:04654 checks = _CommonChecks(input_api.canned_checks) + [
655 _CheckL10nStrings,
656 # Run checks that rely on output from other DevTool checks
657 _SideEffectChecks,
658 _WithArgs(_CheckBugAssociation, is_committing=False),
659 ]
660 return _RunAllChecks(checks, input_api, output_api)
Liviu Raud614e092020-01-08 09:56:33661
662
Blink Reformat4c46d092018-04-07 15:32:37663def CheckChangeOnCommit(input_api, output_api):
Liviu Rauf3028602023-11-10 10:52:04664 checks = _CommonChecks(input_api.canned_checks) + [
665 _CheckL10nStrings,
666 # Run checks that rely on output from other DevTool checks
667 _SideEffectChecks,
668 input_api.canned_checks.CheckChangeHasDescription,
669 _WithArgs(_CheckBugAssociation, is_committing=True),
670 ]
671 return _RunAllChecks(checks, input_api, output_api)
Blink Reformat4c46d092018-04-07 15:32:37672
673
Alex Rudenko537c6312024-07-19 06:22:05674def _getAffectedFiles(input_api, parent_directories, excluded_actions,
675 accepted_endings): # pylint: disable=invalid-name
Yang Guo75beda92019-10-28 07:29:25676 """Return absolute file paths of affected files (not due to an excluded action)
Mandy Chena6be46a2019-07-09 17:06:27677 under a parent directory with an accepted file ending.
Yang Guo75beda92019-10-28 07:29:25678 """
Mandy Chena6be46a2019-07-09 17:06:27679 local_paths = [
Alex Rudenko537c6312024-07-19 06:22:05680 f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
681 if all(f.Action() != action for action in excluded_actions)
Mandy Chena6be46a2019-07-09 17:06:27682 ]
683 affected_files = [
Tim van der Lippefb1dc172021-05-11 15:40:26684 file_name for file_name in local_paths
685 if any(parent_directory in file_name
686 for parent_directory in parent_directories) and (
687 len(accepted_endings) == 0 or any(
688 file_name.endswith(accepted_ending)
689 for accepted_ending in accepted_endings))
Mandy Chena6be46a2019-07-09 17:06:27690 ]
691 return affected_files
692
693
Alex Rudenko537c6312024-07-19 06:22:05694def _checkWithNodeScript(input_api,
695 output_api,
696 script_path,
Nikolay Vitkovc9178752025-04-02 13:37:07697 script_arguments=[],
698 allow_typescript=False):
Blink Reformat4c46d092018-04-07 15:32:37699 original_sys_path = sys.path
700 try:
Alex Rudenko537c6312024-07-19 06:22:05701 sys.path = sys.path + [
702 input_api.os_path.join(input_api.PresubmitLocalPath(), 'scripts')
703 ]
Yang Guod8176982019-10-04 20:30:35704 import devtools_paths
Blink Reformat4c46d092018-04-07 15:32:37705 finally:
706 sys.path = original_sys_path
707
Nikolay Vitkovc9178752025-04-02 13:37:07708 process = [devtools_paths.node_path(), script_path]
709
710 if allow_typescript:
711 process.insert(1, '--no-warnings=ExperimentalWarning')
712 process.insert(1, '--experimental-strip-types')
713
714 return _ExecuteSubProcess(input_api, output_api, process, script_arguments,
715 [])
Mathias Bynens1b2c5e42020-06-18 06:29:21716
717
718def _getFilesToLint(input_api, output_api, lint_config_files,
719 default_linted_directories, accepted_endings, results):
Mathias Bynens0ec56612020-06-19 07:14:03720 run_full_check = False
Mathias Bynens1b2c5e42020-06-18 06:29:21721 files_to_lint = []
722
723 # We are changing the lint configuration; run the full check.
Tim van der Lippefb1dc172021-05-11 15:40:26724 if len(lint_config_files) != 0:
Mathias Bynens1b2c5e42020-06-18 06:29:21725 results.append(
726 output_api.PresubmitNotifyResult('Running full lint check'))
Mathias Bynens0ec56612020-06-19 07:14:03727 run_full_check = True
Mathias Bynens1b2c5e42020-06-18 06:29:21728 else:
729 # Only run the linter on files that are relevant, to save PRESUBMIT time.
730 files_to_lint = _getAffectedFiles(input_api,
731 default_linted_directories, ['D'],
732 accepted_endings)
733
Jack Franklin130d2ae2022-07-12 09:51:26734 # Exclude front_end/third_party and front_end/generated files.
Tim van der Lippefb1dc172021-05-11 15:40:26735 files_to_lint = [
Jack Franklin130d2ae2022-07-12 09:51:26736 file for file in files_to_lint
Philip Pfaffeb74da232025-01-20 08:19:09737 if "front_end/third_party" not in file
738 and "front_end/generated" not in file
Tim van der Lippefb1dc172021-05-11 15:40:26739 ]
Paul Lewis2b9224f2020-09-08 17:13:10740
Tim van der Lippefb1dc172021-05-11 15:40:26741 if len(files_to_lint) == 0:
Mathias Bynens1b2c5e42020-06-18 06:29:21742 results.append(
743 output_api.PresubmitNotifyResult(
744 'No affected files for lint check'))
745
Tim van der Lippefb1dc172021-05-11 15:40:26746 should_bail_out = len(files_to_lint) == 0 and not run_full_check
Mathias Bynens0ec56612020-06-19 07:14:03747 return should_bail_out, files_to_lint
Alex Rudenko4a7a3242024-04-18 10:36:50748
749
750def _CheckNodeModules(input_api, output_api):
751
752 files = ['.clang-format', 'OWNERS', 'README.chromium']
753
754 results = []
755 for file in files:
756 file_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
757 'node_modules', file)
758 if not Path(file_path).is_file():
Alex Rudenko537c6312024-07-19 06:22:05759 results.extend([
Alex Rudenko4a7a3242024-04-18 10:36:50760 output_api.PresubmitError(
761 "node_modules/%s is missing. Use npm run install-deps to re-create it."
Alex Rudenko537c6312024-07-19 06:22:05762 % file)
763 ])
Alex Rudenko4a7a3242024-04-18 10:36:50764
Alex Rudenko537c6312024-07-19 06:22:05765 return results