blob: 8984e045942017ed543d78b70c30074fc593c613 [file] [log] [blame]
Avi Drissmanea1be232022-09-14 23:29:061# Copyright 2017 The Chromium Authors
Sylvain Defresnefcda19f2017-06-27 10:14:012# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
Sylvain Defresnefcda19f2017-06-27 10:14:014"""Presubmit script for ios.
5
6See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
7for more details about the presubmit API built into depot_tools.
8"""
9
[email protected]0066f732017-12-28 10:33:0810import os
Gauthier Ambard3803d8f2025-01-07 19:36:0711import xml.etree.ElementTree as ElementTree
[email protected]0066f732017-12-28 10:33:0812
Nohemi Fernandeza3833372020-03-23 17:22:1913NULLABILITY_PATTERN = r'(nonnull|nullable|_Nullable|_Nonnull)'
Sylvain Defresnefcda19f2017-06-27 10:14:0114TODO_PATTERN = r'TO[D]O\(([^\)]*)\)'
Mark Cogancc4c1ea2024-03-07 09:31:2915BUG_PATTERN = r'^(crbug\.com|b)/\d+$'
16DEPRECATED_BUG_PATTERN = r'^b/\d+$'
Petro Akzhygitovdb9b351622022-07-01 08:21:5017INCLUDE_PATTERN = r'^#include'
Gauthier Ambardf85c5f12022-09-14 11:26:5418PIPE_IN_COMMENT_PATTERN = r'//.*[^|]\|(?!\|)'
Petro Akzhygitovdb9b351622022-07-01 08:21:5019IOS_PACKAGE_PATTERN = r'^ios'
Louis Romeroe33c2da2023-01-19 14:18:5320BOXED_BOOL_PATTERN = r'@\((YES|NO)\)'
Federica Germinario2ce51a82025-01-27 14:44:1021USER_DEFAULTS_PATTERN = r'\[NSUserDefaults standardUserDefaults]'
Gauthier Ambard7fc07bf2018-01-02 09:48:0922
Benjamin Williams715f0232025-02-20 12:44:0923# Color management constants
24COLOR_SHARED_DIR = 'ios/chrome/common/ui/colors/'
25COLOR_FILE_PATTERN = '.colorset/Contents.json'
26
27
28def FormatMessageWithFiles(message, errors):
29 """Helper to format warning/error messages with affected files."""
30 if not errors:
31 return message
32 return '\n'.join([message + '\n\nAffected file(s):'] + errors) + '\n'
33
Gauthier Ambard7fc07bf2018-01-02 09:48:0934def IsSubListOf(needle, hay):
Gauthier Ambard1981d622022-09-13 09:34:4935 """Returns whether there is a slice of |hay| equal to |needle|."""
36 for i, line in enumerate(hay):
37 if line == needle[0]:
38 if needle == hay[i:i + len(needle)]:
39 return True
40 return False
41
[email protected]0066f732017-12-28 10:33:0842
Nohemi Fernandeza3833372020-03-23 17:22:1943def _CheckNullabilityAnnotations(input_api, output_api):
Daniel Bratell5cb4c1e22024-04-17 07:49:0644 """ Checks whether there are nullability annotations in ios code.
45
46 They are accepted in ios/web_view/public since it tries to mimic
47 the platform library but not anywhere else.
48 """
Gauthier Ambard1981d622022-09-13 09:34:4949 nullability_regex = input_api.re.compile(NULLABILITY_PATTERN)
Sylvain Defresnefcda19f2017-06-27 10:14:0150
Gauthier Ambard1981d622022-09-13 09:34:4951 errors = []
52 for f in input_api.AffectedFiles():
Daniel Bratell5cb4c1e22024-04-17 07:49:0653 if f.LocalPath().startswith('ios/web_view/public/'):
54 # ios/web_view/public tries to mimic an existing API that
55 # might have nullability in it and that is acceptable.
56 continue
Gauthier Ambard1981d622022-09-13 09:34:4957 for line_num, line in f.ChangedContents():
58 if nullability_regex.search(line):
59 errors.append('%s:%s' % (f.LocalPath(), line_num))
60 if not errors:
61 return []
Nohemi Fernandeza3833372020-03-23 17:22:1962
Gauthier Ambard1981d622022-09-13 09:34:4963 plural_suffix = '' if len(errors) == 1 else 's'
Federica Germinario6aeebd42024-09-17 11:59:1564 warning_message = ('Found Nullability annotation%(plural)s. '
Gauthier Ambard1981d622022-09-13 09:34:4965 'Prefer DCHECKs in ios code to check for nullness:' % {
66 'plural': plural_suffix
67 })
Nohemi Fernandeza3833372020-03-23 17:22:1968
Federica Germinario6aeebd42024-09-17 11:59:1569 return [output_api.PresubmitPromptWarning(warning_message, items=errors)]
Nohemi Fernandeza3833372020-03-23 17:22:1970
71
72def _CheckBugInToDo(input_api, output_api):
Gauthier Ambard1981d622022-09-13 09:34:4973 """ Checks whether TODOs in ios code are identified by a bug number."""
74 errors = []
Mark Cogancc4c1ea2024-03-07 09:31:2975 warnings = []
Gauthier Ambard1981d622022-09-13 09:34:4976 for f in input_api.AffectedFiles():
77 for line_num, line in f.ChangedContents():
78 if _HasToDoWithNoBug(input_api, line):
79 errors.append('%s:%s' % (f.LocalPath(), line_num))
Mark Cogancc4c1ea2024-03-07 09:31:2980 if _HasToDoWithDeprecatedBug(input_api, line):
81 warnings.append('%s:%s' % (f.LocalPath(), line_num))
82 if not errors and not warnings:
Gauthier Ambard1981d622022-09-13 09:34:4983 return []
Sylvain Defresnefcda19f2017-06-27 10:14:0184
Mark Cogancc4c1ea2024-03-07 09:31:2985 output = []
86 if errors:
Gauthier Ambard304538e2025-01-07 14:07:0587 singular_article = 'a ' if len(errors) == 1 else ''
88 plural_suffix = '' if len(errors) == 1 else 's'
89 error_message = '\n'.join([
90 'Found TO'
91 'DO%(plural)s without %(a)sbug number%(plural)s (expected format '
92 'is \"TO'
93 'DO(crbug.com/######)\"):' % {
94 'plural': plural_suffix,
95 'a' : singular_article
96 }
97 ] + errors) + '\n'
98 output.append(output_api.PresubmitError(error_message))
Sylvain Defresnefcda19f2017-06-27 10:14:0199
Mark Cogancc4c1ea2024-03-07 09:31:29100 if warnings:
Gauthier Ambard304538e2025-01-07 14:07:05101 singular_article = 'a ' if len(warnings) == 1 else ''
102 plural_suffix = '' if len(warnings) == 1 else 's'
103 warning_message = '\n'.join([
104 'Found TO'
105 'DO%(plural)s with %(a)sdeprecated bug link%(plural)s (found '
106 '"b/#####\", expected format is \"crbug.com/######"):' % {
107 'plural': plural_suffix,
108 'a' : singular_article
109 }
110 ] + warnings) + '\n'
111 output.append(output_api.PresubmitPromptWarning(warning_message))
Mark Cogancc4c1ea2024-03-07 09:31:29112
113 return output
Sylvain Defresnefcda19f2017-06-27 10:14:01114
115
Petro Akzhygitovdb9b351622022-07-01 08:21:50116def _CheckHasNoIncludeDirectives(input_api, output_api):
Gauthier Ambard1981d622022-09-13 09:34:49117 """ Checks that #include preprocessor directives are not present."""
118 errors = []
119 for f in input_api.AffectedFiles():
120 if not _IsInIosPackage(input_api, f.LocalPath()):
121 continue
122 _, ext = os.path.splitext(f.LocalPath())
123 if ext != '.mm':
124 continue
125 for line_num, line in f.ChangedContents():
126 if _HasIncludeDirective(input_api, line):
127 errors.append('%s:%s' % (f.LocalPath(), line_num))
128 if not errors:
129 return []
Petro Akzhygitovdb9b351622022-07-01 08:21:50130
Gauthier Ambard1981d622022-09-13 09:34:49131 singular_plural = 'it' if len(errors) == 1 else 'them'
132 plural_suffix = '' if len(errors) == 1 else 's'
133 error_message = '\n'.join([
134 'Found usage of `#include` preprocessor directive%(plural)s! Please, '
135 'replace %(singular_plural)s with `#import` preprocessor '
136 'directive%(plural)s instead. '
137 'Consider replacing all existing `#include` with `#import` (if any) in '
138 'this file for the code clean up. See '
139 'https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main'
140 '/styleguide/objective-c/objective-c.md'
141 '#import-and-include-in-the-directory for more details. '
142 '\n\nAffected file%(plural)s:' % {
143 'plural': plural_suffix,
144 'singular_plural': singular_plural
145 }
146 ] + errors) + '\n'
Petro Akzhygitovdb9b351622022-07-01 08:21:50147
Gauthier Ambard1981d622022-09-13 09:34:49148 return [output_api.PresubmitError(error_message)]
149
Petro Akzhygitovdb9b351622022-07-01 08:21:50150
Gauthier Ambardf85c5f12022-09-14 11:26:54151def _CheckHasNoPipeInComment(input_api, output_api):
152 """ Checks that comments don't contain pipes."""
153 pipe_regex = input_api.re.compile(PIPE_IN_COMMENT_PATTERN)
154
155 errors = []
156 for f in input_api.AffectedFiles():
157 if not _IsInIosPackage(input_api, f.LocalPath()):
158 continue
159 for line_num, line in f.ChangedContents():
160 if pipe_regex.search(line):
161 errors.append('%s:%s' % (f.LocalPath(), line_num))
162 if not errors:
163 return []
Federica Germinario6aeebd42024-09-17 11:59:15164 warning_message = '\n'.join([
Gauthier Ambardf85c5f12022-09-14 11:26:54165 'Please use backticks "`" instead of pipes "|" if you need to quote'
166 ' variable names and symbols in comments.\n'
167 'Found potential uses of pipes in:'
168 ] + errors) + '\n'
169
Federica Germinario6aeebd42024-09-17 11:59:15170 return [output_api.PresubmitPromptWarning(warning_message)]
Gauthier Ambardf85c5f12022-09-14 11:26:54171
Federica Germinario6aeebd42024-09-17 11:59:15172def _CheckCanImproveTestUsingExpectNSEQ(input_api, output_api):
173 """ Checks that test files use EXPECT_NSEQ when possible."""
174 errors = []
175 # Substrings that should not be used together with EXPECT_TRUE or
176 # EXPECT_FALSE in tests.
177 wrong_patterns = ["isEqualToString:", "isEqualToData:", "isEqualToArray:"]
178 for f in input_api.AffectedFiles():
179 if not '_unittest.' in f.LocalPath():
Gauthier Ambard304538e2025-01-07 14:07:05180 continue
Federica Germinario6aeebd42024-09-17 11:59:15181 for line_num, line in f.ChangedContents():
182 if line.startswith(("EXPECT_TRUE", "EXPECT_FALSE")):
Gauthier Ambard304538e2025-01-07 14:07:05183 # Condition is in one line.
184 if any(x in line for x in wrong_patterns):
Federica Germinario6aeebd42024-09-17 11:59:15185 errors.append('%s:%s' % (f.LocalPath(), line_num))
Gauthier Ambard304538e2025-01-07 14:07:05186 # Condition is split on multiple lines.
187 elif not line.endswith(";"):
188 # Check this is not the last line.
189 if line_num < len(f.NewContents()):
190 next_line = f.NewContents()[line_num]
191 if any(x in next_line for x in wrong_patterns):
192 errors.append('%s:%s' % (f.LocalPath(), line_num))
Federica Germinario6aeebd42024-09-17 11:59:15193
194 if not errors:
195 return []
196
197 plural_suffix = '' if len(errors) == 1 else 's'
198 warning_message = '\n'.join([
199 'Found possible improvement in unittest. Prefer using'
200 ' EXPECT_NSEQ() or EXPECT_NSNE() when possible.'
201 '\n\nAffected file%(plural)s:' % {
202 'plural': plural_suffix,
203 }
204 ] + errors) + '\n'
205
206 return [output_api.PresubmitPromptWarning(warning_message)]
207
Petro Akzhygitovdb9b351622022-07-01 08:21:50208def _IsInIosPackage(input_api, path):
Gauthier Ambard1981d622022-09-13 09:34:49209 """ Returns True if path is within ios package"""
210 ios_package_regex = input_api.re.compile(IOS_PACKAGE_PATTERN)
Petro Akzhygitovdb9b351622022-07-01 08:21:50211
Gauthier Ambard1981d622022-09-13 09:34:49212 return ios_package_regex.search(path)
213
Petro Akzhygitovdb9b351622022-07-01 08:21:50214
215def _HasIncludeDirective(input_api, line):
Gauthier Ambard1981d622022-09-13 09:34:49216 """ Returns True if #include is found in the line"""
217 include_regex = input_api.re.compile(INCLUDE_PATTERN)
Petro Akzhygitovdb9b351622022-07-01 08:21:50218
Gauthier Ambard1981d622022-09-13 09:34:49219 return include_regex.search(line)
220
Petro Akzhygitovdb9b351622022-07-01 08:21:50221
Nohemi Fernandeza3833372020-03-23 17:22:19222def _HasToDoWithNoBug(input_api, line):
Gauthier Ambard1981d622022-09-13 09:34:49223 """ Returns True if TODO is not identified by a bug number."""
224 todo_regex = input_api.re.compile(TODO_PATTERN)
Tomasz Jurkiewicz55a0aa182023-03-01 18:53:46225 bug_regex = input_api.re.compile(BUG_PATTERN)
Nohemi Fernandeza3833372020-03-23 17:22:19226
Gauthier Ambard1981d622022-09-13 09:34:49227 todo_match = todo_regex.search(line)
228 if not todo_match:
229 return False
Mark Cogancc4c1ea2024-03-07 09:31:29230
Tomasz Jurkiewicz55a0aa182023-03-01 18:53:46231 return not bug_regex.match(todo_match.group(1))
Nohemi Fernandeza3833372020-03-23 17:22:19232
Mark Cogancc4c1ea2024-03-07 09:31:29233def _HasToDoWithDeprecatedBug(input_api, line):
234 """ Returns True if TODO is identified by a deprecated bug number format."""
235 todo_regex = input_api.re.compile(TODO_PATTERN)
236 deprecated_bug_regex = input_api.re.compile(DEPRECATED_BUG_PATTERN)
237
238 todo_match = todo_regex.search(line)
239 if not todo_match:
240 return False
241 return deprecated_bug_regex.match(todo_match.group(1))
242
Louis Romeroe33c2da2023-01-19 14:18:53243def _CheckHasNoBoxedBOOL(input_api, output_api):
244 """ Checks that there are no @(YES) or @(NO)."""
245 boxed_BOOL_regex = input_api.re.compile(BOXED_BOOL_PATTERN)
246
247 errors = []
248 for f in input_api.AffectedFiles():
249 for line_num, line in f.ChangedContents():
250 if boxed_BOOL_regex.search(line):
251 errors.append('%s:%s' % (f.LocalPath(), line_num))
252 if not errors:
253 return []
254
255 plural_suffix = '' if len(errors) == 1 else 's'
Federica Germinario6aeebd42024-09-17 11:59:15256 warning_message = ('Found boxed BOOL%(plural)s. '
Louis Romeroe33c2da2023-01-19 14:18:53257 'Prefer @YES or @NO in ios code:' % {
258 'plural': plural_suffix
259 })
260
Federica Germinario6aeebd42024-09-17 11:59:15261 return [output_api.PresubmitPromptWarning(warning_message, items=errors)]
Nohemi Fernandeza3833372020-03-23 17:22:19262
Justin Cohen5f8ac412024-10-15 15:09:19263def _CheckNoTearDownEGTest(input_api, output_api):
264 """ Checks that `- (void)tearDown {` is not present in an egtest.mm"""
265 errors = []
266 for f in input_api.AffectedFiles():
267 if not '_egtest.' in f.LocalPath():
Gauthier Ambard304538e2025-01-07 14:07:05268 continue
Justin Cohen5f8ac412024-10-15 15:09:19269 for line_num, line in f.ChangedContents():
270 if line.startswith("- (void)tearDown {"):
271 errors.append('%s:%s' % (f.LocalPath(), line_num))
272
273 if not errors:
274 return []
275 warning_message = '\n'.join([
276 'To support hermetic EarlGrey test cases, tearDown has been renamed '
277 'to tearDownHelper, and will soon be removed. If tearDown is really '
278 'necessary for this test, please use addTeardownBlock'
279 ] + errors) + '\n'
280
281 return [output_api.PresubmitError(warning_message)]
282
Gauthier Ambard3803d8f2025-01-07 19:36:07283
284def _IsAlphabeticallySortedXML(file):
285 """Check that the `file` is alphabetically sorted"""
286 parser = ElementTree.XMLParser(target=ElementTree.TreeBuilder(
287 insert_comments=True))
dpapadc885f142025-02-21 23:05:50288 with open(file, 'r', encoding='utf8') as xml_file:
Gauthier Ambard3803d8f2025-01-07 19:36:07289 tree = ElementTree.parse(xml_file, parser)
290 root = tree.getroot()
291
292 original_tree_string = ElementTree.tostring(root, encoding='utf8')
293
294 messages_element = tree.findall('.//messages')[0]
295 messages = messages_element.findall('message')
296 messages.sort(key=lambda message: message.attrib["name"])
297 for message in messages:
298 messages_element.remove(message)
299 for message in messages:
300 messages_element.append(message)
301 ordered_tree_string = ElementTree.tostring(root, encoding='utf8')
302 return ordered_tree_string == original_tree_string
303
304
305def _CheckOrderedStringFile(input_api, output_api):
306 """ Checks that the string files are alphabetically ordered"""
307 errors = []
Gauthier Ambard7a243cc2025-03-18 13:45:30308 for f in input_api.AffectedFiles(include_deletes=False):
Gauthier Ambard3803d8f2025-01-07 19:36:07309 if not f.LocalPath().endswith("_strings.grd"):
310 continue
311 if not _IsAlphabeticallySortedXML(f.AbsoluteLocalPath()):
312 errors.append(' python3 ios/tools/order_string_file.py ' +
313 f.LocalPath())
314
315 if not errors:
316 return []
317 warning_message = '\n'.join(
318 ['Files not alphabetically sorted, try running:'] + errors) + '\n'
319
320 return [output_api.PresubmitPromptWarning(warning_message)]
321
322
Federica Germinario2ce51a82025-01-27 14:44:10323def _CheckNotUsingNSUserDefaults(input_api, output_api):
324 """ Checks the added code to limit new usage of NSUserDefaults """
325 user_defaults_regex = input_api.re.compile(USER_DEFAULTS_PATTERN)
326
327 errors = []
328 for f in input_api.AffectedFiles():
329 if (not f.LocalPath().endswith('.mm')):
330 continue
331 for line_num, line in f.ChangedContents():
332 if user_defaults_regex.search(line):
333 errors.append('%s:%s' % (f.LocalPath(), line_num))
334
335 if not errors:
336 return []
337 warning_message = '\n'.join([
338 'A new use of NSUserDefaults was added. If this is a newly added key '
339 'consider storing it to PrefService instead.'
340 ] + errors) + '\n'
341
342 return [output_api.PresubmitPromptWarning(warning_message)]
343
344
Benjamin Williams715f0232025-02-20 12:44:09345def _CheckNewColorIntroduction(input_api, output_api):
346 """Checks for new or modified colorset files.
347
348 Ensures colors are properly added to the shared directory.
349 """
350 results = []
351
352 affected_files = [
353 f for f in input_api.AffectedFiles()
354 if f.LocalPath().endswith(COLOR_FILE_PATTERN)
355 ]
356
357 warnings = {
358 'shared_added': [],
359 'shared_modified': [],
360 'other_modified': []
361 }
362 errors = []
363
364 for affected_file in affected_files:
365 action = affected_file.Action()
366 local_path = affected_file.LocalPath()
367 file_path_error = '%s' % (affected_file.LocalPath())
368
369 if COLOR_SHARED_DIR in local_path:
370 if action == 'A':
371 warnings['shared_added'].append(file_path_error)
372 elif action == 'M':
373 warnings['shared_modified'].append(file_path_error)
374 else:
375 if action == 'A':
376 errors.append(file_path_error)
377 elif action == 'M':
378 warnings['other_modified'].append(file_path_error)
379
380 output = []
381
382 if errors:
383 error_message = ('New color(s) must be added to the %s directory.' %
384 COLOR_SHARED_DIR)
385 output.append(
386 output_api.PresubmitError(
387 FormatMessageWithFiles(error_message, errors)))
388
389 warning_message = ('Please ensure the color does not already exist in the '
390 'shared %s directory.' % COLOR_SHARED_DIR)
391
392 if warnings['shared_added']:
393 shared_added_message = ('New color(s) added in %s. %s' %
394 (COLOR_SHARED_DIR, warning_message))
395 output.append(
396 output_api.PresubmitPromptWarning(
397 FormatMessageWithFiles(shared_added_message,
398 warnings['shared_added'])))
399
400 if warnings['shared_modified']:
401 shared_modified_message = ('Color(s) modified in %s. %s' %
402 (COLOR_SHARED_DIR, warning_message))
403 output.append(
404 output_api.PresubmitPromptWarning(
405 FormatMessageWithFiles(shared_modified_message,
406 warnings['shared_modified'])))
407
408 if warnings['other_modified']:
409 modified_message = ('Color(s) modified. %s' % warning_message)
410 output.append(
411 output_api.PresubmitPromptWarning(
412 FormatMessageWithFiles(modified_message,
413 warnings['other_modified'])))
414
415 return output
416
dpapad5c828832025-02-25 19:47:12417def _CheckStyleESLint(input_api, output_api):
418 results = []
419
420 try:
421 import sys
422 old_sys_path = sys.path[:]
423 cwd = input_api.PresubmitLocalPath()
424 sys.path += [input_api.os_path.join(cwd, '..', 'tools')]
425 from web_dev_style import presubmit_support
426 results += presubmit_support.CheckStyleESLint(input_api, output_api)
427 finally:
428 sys.path = old_sys_path
429
430 return results
431
Federica Germinario94204012025-04-16 18:20:59432def _CheckUIGraphicsBeginImageContextWithOptions(input_api, output_api):
433 """ Checks that UIGraphicsBeginImageContextWithOptions is not used"""
434 deprecated_regex = input_api.re.compile(
435 r'UIGraphicsBeginImageContextWithOptions\(')
436
437 errors = []
438 for f in input_api.AffectedFiles():
439 if (not f.LocalPath().endswith('.mm')):
440 continue
441 for line_num, line in f.ChangedContents():
442 if deprecated_regex.search(line):
443 errors.append('%s:%s' % (f.LocalPath(), line_num))
444
445 if not errors:
446 return []
447 error_message = '\n'.join([
448 'UIGraphicsBeginImageContextWithOptions is deprecated, use '
449 'UIGraphicsImageRenderer instead.'
450 ] + errors) + '\n'
451
452 return [output_api.PresubmitError(error_message)]
453
dpapadc885f142025-02-21 23:05:50454def CheckChange(input_api, output_api):
Gauthier Ambard1981d622022-09-13 09:34:49455 results = []
456 results.extend(_CheckBugInToDo(input_api, output_api))
457 results.extend(_CheckNullabilityAnnotations(input_api, output_api))
Gauthier Ambard1981d622022-09-13 09:34:49458 results.extend(_CheckHasNoIncludeDirectives(input_api, output_api))
Gauthier Ambardf85c5f12022-09-14 11:26:54459 results.extend(_CheckHasNoPipeInComment(input_api, output_api))
Louis Romeroe33c2da2023-01-19 14:18:53460 results.extend(_CheckHasNoBoxedBOOL(input_api, output_api))
Justin Cohen5f8ac412024-10-15 15:09:19461 results.extend(_CheckNoTearDownEGTest(input_api, output_api))
Federica Germinario6aeebd42024-09-17 11:59:15462 results.extend(_CheckCanImproveTestUsingExpectNSEQ(input_api, output_api))
Gauthier Ambard3803d8f2025-01-07 19:36:07463 results.extend(_CheckOrderedStringFile(input_api, output_api))
Federica Germinario2ce51a82025-01-27 14:44:10464 results.extend(_CheckNotUsingNSUserDefaults(input_api, output_api))
Benjamin Williams715f0232025-02-20 12:44:09465 results.extend(_CheckNewColorIntroduction(input_api, output_api))
dpapad5c828832025-02-25 19:47:12466 results.extend(_CheckStyleESLint(input_api, output_api))
Federica Germinario94204012025-04-16 18:20:59467 results.extend(
468 _CheckUIGraphicsBeginImageContextWithOptions(input_api, output_api))
Gauthier Ambard1981d622022-09-13 09:34:49469 return results
dpapadc885f142025-02-21 23:05:50470
471def CheckChangeOnUpload(input_api, output_api):
472 return CheckChange(input_api, output_api)
473
474def CheckChangeOnCommit(input_api, output_api):
475 return CheckChange(input_api, output_api)