1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Top-level presubmit script for Chromium.
7 See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
8 for more details about the presubmit API built into gcl.
19 r
"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
20 r
"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
21 r
"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
27 r
"^webkit[\\\/]compositor_bindings[\\\/].*",
28 r
".+[\\\/]pnacl_shim\.c$",
31 # Fragment of a regular expression that matches file name suffixes
32 # used to indicate different platforms.
33 _PLATFORM_SPECIFIERS
= r
'(_(android|chromeos|gtk|mac|posix|win))?'
35 # Fragment of a regular expression that matches C++ and Objective-C++
36 # implementation files.
37 _IMPLEMENTATION_EXTENSIONS
= r
'\.(cc|cpp|cxx|mm)$'
39 # Regular expression that matches code only used for test binaries
41 _TEST_CODE_EXCLUDED_PATHS
= (
42 r
'.*[/\\](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS
,
43 r
'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS
,
44 r
'.+_(api|browser|perf|unit|ui)?test%s%s' % (_PLATFORM_SPECIFIERS
,
45 _IMPLEMENTATION_EXTENSIONS
),
46 r
'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS
,
47 r
'.*[/\\](test|tool(s)?)[/\\].*',
48 # At request of folks maintaining this folder.
49 r
'chrome[/\\]browser[/\\]automation[/\\].*',
52 _TEST_ONLY_WARNING
= (
53 'You might be calling functions intended only for testing from\n'
54 'production code. It is OK to ignore this warning if you know what\n'
55 'you are doing, as the heuristics used to detect the situation are\n'
56 'not perfect. The commit queue will not block on this warning.\n'
57 'Email joi@chromium.org if you have questions.')
60 _INCLUDE_ORDER_WARNING
= (
61 'Your #include order seems to be broken. Send mail to\n'
62 'marja@chromium.org if this is not the case.')
65 _BANNED_OBJC_FUNCTIONS
= (
69 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
70 'prohibited. Please use CrTrackingArea instead.',
71 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
78 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
80 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
85 'convertPointFromBase:',
87 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
88 'Please use |convertPoint:(point) fromView:nil| instead.',
89 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
94 'convertPointToBase:',
96 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
97 'Please use |convertPoint:(point) toView:nil| instead.',
98 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
103 'convertRectFromBase:',
105 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
106 'Please use |convertRect:(point) fromView:nil| instead.',
107 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
112 'convertRectToBase:',
114 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
115 'Please use |convertRect:(point) toView:nil| instead.',
116 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
121 'convertSizeFromBase:',
123 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
124 'Please use |convertSize:(point) fromView:nil| instead.',
125 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
130 'convertSizeToBase:',
132 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
133 'Please use |convertSize:(point) toView:nil| instead.',
134 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
141 _BANNED_CPP_FUNCTIONS
= (
142 # Make sure that gtest's FRIEND_TEST() macro is not used; the
143 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
144 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
148 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
149 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
157 'New code should not use ScopedAllowIO. Post a task to the blocking',
158 'pool or the FILE thread instead.',
162 r
"^content[\\\/]shell[\\\/]shell_browser_main\.cc$",
166 'FilePathWatcher::Delegate',
168 'New code should not use FilePathWatcher::Delegate. Use the callback',
169 'interface instead.',
177 def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api
, output_api
):
178 """Attempts to prevent use of functions intended only for testing in
179 non-testing code. For now this is just a best-effort implementation
180 that ignores header files and may have some false positives. A
181 better implementation would probably need a proper C++ parser.
183 # We only scan .cc files and the like, as the declaration of
184 # for-testing functions in header files are hard to distinguish from
185 # calls to such functions without a proper C++ parser.
186 file_inclusion_pattern
= r
'.+%s' % _IMPLEMENTATION_EXTENSIONS
188 base_function_pattern
= r
'ForTest(ing)?|for_test(ing)?'
189 inclusion_pattern
= input_api
.re
.compile(r
'(%s)\s*\(' % base_function_pattern
)
190 exclusion_pattern
= input_api
.re
.compile(
191 r
'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
192 base_function_pattern
, base_function_pattern
))
194 def FilterFile(affected_file
):
195 black_list
= (_EXCLUDED_PATHS
+
196 _TEST_CODE_EXCLUDED_PATHS
+
197 input_api
.DEFAULT_BLACK_LIST
)
198 return input_api
.FilterSourceFile(
200 white_list
=(file_inclusion_pattern
, ),
201 black_list
=black_list
)
204 for f
in input_api
.AffectedSourceFiles(FilterFile
):
205 local_path
= f
.LocalPath()
206 lines
= input_api
.ReadFile(f
).splitlines()
209 if (inclusion_pattern
.search(line
) and
210 not exclusion_pattern
.search(line
)):
212 '%s:%d\n %s' % (local_path
, line_number
, line
.strip()))
216 if not input_api
.is_committing
:
217 return [output_api
.PresubmitPromptWarning(_TEST_ONLY_WARNING
, problems
)]
219 # We don't warn on commit, to avoid stopping commits going through CQ.
220 return [output_api
.PresubmitNotifyResult(_TEST_ONLY_WARNING
, problems
)]
225 def _CheckNoIOStreamInHeaders(input_api
, output_api
):
226 """Checks to make sure no .h files include <iostream>."""
228 pattern
= input_api
.re
.compile(r
'^#include\s*<iostream>',
229 input_api
.re
.MULTILINE
)
230 for f
in input_api
.AffectedSourceFiles(input_api
.FilterSourceFile
):
231 if not f
.LocalPath().endswith('.h'):
233 contents
= input_api
.ReadFile(f
)
234 if pattern
.search(contents
):
238 return [ output_api
.PresubmitError(
239 'Do not #include <iostream> in header files, since it inserts static '
240 'initialization into every file including the header. Instead, '
241 '#include <ostream>. See http://crbug.com/94794',
246 def _CheckNoUNIT_TESTInSourceFiles(input_api
, output_api
):
247 """Checks to make sure no source files use UNIT_TEST"""
249 for f
in input_api
.AffectedFiles():
250 if (not f
.LocalPath().endswith(('.cc', '.mm'))):
253 for line_num
, line
in f
.ChangedContents():
254 if 'UNIT_TEST' in line
:
255 problems
.append(' %s:%d' % (f
.LocalPath(), line_num
))
259 return [output_api
.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
260 '\n'.join(problems
))]
263 def _CheckNoNewWStrings(input_api
, output_api
):
264 """Checks to make sure we don't introduce use of wstrings."""
266 for f
in input_api
.AffectedFiles():
267 if (not f
.LocalPath().endswith(('.cc', '.h')) or
268 f
.LocalPath().endswith('test.cc')):
272 for line_num
, line
in f
.ChangedContents():
273 if 'presubmit: allow wstring' in line
:
275 elif not allowWString
and 'wstring' in line
:
276 problems
.append(' %s:%d' % (f
.LocalPath(), line_num
))
283 return [output_api
.PresubmitPromptWarning('New code should not use wstrings.'
284 ' If you are calling a cross-platform API that accepts a wstring, '
286 '\n'.join(problems
))]
289 def _CheckNoDEPSGIT(input_api
, output_api
):
290 """Make sure .DEPS.git is never modified manually."""
291 if any(f
.LocalPath().endswith('.DEPS.git') for f
in
292 input_api
.AffectedFiles()):
293 return [output_api
.PresubmitError(
294 'Never commit changes to .DEPS.git. This file is maintained by an\n'
295 'automated system based on what\'s in DEPS and your changes will be\n'
297 'See http://code.google.com/p/chromium/wiki/UsingNewGit#Rolling_DEPS\n'
298 'for more information')]
302 def _CheckNoBannedFunctions(input_api
, output_api
):
303 """Make sure that banned functions are not used."""
307 file_filter
= lambda f
: f
.LocalPath().endswith(('.mm', '.m', '.h'))
308 for f
in input_api
.AffectedFiles(file_filter
=file_filter
):
309 for line_num
, line
in f
.ChangedContents():
310 for func_name
, message
, error
in _BANNED_OBJC_FUNCTIONS
:
311 if func_name
in line
:
315 problems
.append(' %s:%d:' % (f
.LocalPath(), line_num
))
316 for message_line
in message
:
317 problems
.append(' %s' % message_line
)
319 file_filter
= lambda f
: f
.LocalPath().endswith(('.cc', '.mm', '.h'))
320 for f
in input_api
.AffectedFiles(file_filter
=file_filter
):
321 for line_num
, line
in f
.ChangedContents():
322 for func_name
, message
, error
, excluded_paths
in _BANNED_CPP_FUNCTIONS
:
323 def IsBlacklisted(affected_file
, blacklist
):
324 local_path
= affected_file
.LocalPath()
325 for item
in blacklist
:
326 if input_api
.re
.match(item
, local_path
):
329 if IsBlacklisted(f
, excluded_paths
):
331 if func_name
in line
:
335 problems
.append(' %s:%d:' % (f
.LocalPath(), line_num
))
336 for message_line
in message
:
337 problems
.append(' %s' % message_line
)
341 result
.append(output_api
.PresubmitPromptWarning(
342 'Banned functions were used.\n' + '\n'.join(warnings
)))
344 result
.append(output_api
.PresubmitError(
345 'Banned functions were used.\n' + '\n'.join(errors
)))
349 def _CheckNoPragmaOnce(input_api
, output_api
):
350 """Make sure that banned functions are not used."""
352 pattern
= input_api
.re
.compile(r
'^#pragma\s+once',
353 input_api
.re
.MULTILINE
)
354 for f
in input_api
.AffectedSourceFiles(input_api
.FilterSourceFile
):
355 if not f
.LocalPath().endswith('.h'):
357 contents
= input_api
.ReadFile(f
)
358 if pattern
.search(contents
):
362 return [output_api
.PresubmitError(
363 'Do not use #pragma once in header files.\n'
364 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
369 def _CheckNoTrinaryTrueFalse(input_api
, output_api
):
370 """Checks to make sure we don't introduce use of foo ? true : false."""
372 pattern
= input_api
.re
.compile(r
'\?\s*(true|false)\s*:\s*(true|false)')
373 for f
in input_api
.AffectedFiles():
374 if not f
.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
377 for line_num
, line
in f
.ChangedContents():
378 if pattern
.match(line
):
379 problems
.append(' %s:%d' % (f
.LocalPath(), line_num
))
383 return [output_api
.PresubmitPromptWarning(
384 'Please consider avoiding the "? true : false" pattern if possible.\n' +
385 '\n'.join(problems
))]
388 def _CheckUnwantedDependencies(input_api
, output_api
):
389 """Runs checkdeps on #include statements added in this
390 change. Breaking - rules is an error, breaking ! rules is a
393 # We need to wait until we have an input_api object and use this
394 # roundabout construct to import checkdeps because this file is
395 # eval-ed and thus doesn't have __file__.
396 original_sys_path
= sys
.path
398 sys
.path
= sys
.path
+ [input_api
.os_path
.join(
399 input_api
.PresubmitLocalPath(), 'tools', 'checkdeps')]
401 from cpp_checker
import CppChecker
402 from rules
import Rule
404 # Restore sys.path to what it was before.
405 sys
.path
= original_sys_path
408 for f
in input_api
.AffectedFiles():
409 if not CppChecker
.IsCppFile(f
.LocalPath()):
412 changed_lines
= [line
for line_num
, line
in f
.ChangedContents()]
413 added_includes
.append([f
.LocalPath(), changed_lines
])
415 deps_checker
= checkdeps
.DepsChecker()
417 error_descriptions
= []
418 warning_descriptions
= []
419 for path
, rule_type
, rule_description
in deps_checker
.CheckAddedCppIncludes(
421 description_with_path
= '%s\n %s' % (path
, rule_description
)
422 if rule_type
== Rule
.DISALLOW
:
423 error_descriptions
.append(description_with_path
)
425 warning_descriptions
.append(description_with_path
)
428 if error_descriptions
:
429 results
.append(output_api
.PresubmitError(
430 'You added one or more #includes that violate checkdeps rules.',
432 if warning_descriptions
:
433 if not input_api
.is_committing
:
434 warning_factory
= output_api
.PresubmitPromptWarning
436 # We don't want to block use of the CQ when there is a warning
437 # of this kind, so we only show a message when committing.
438 warning_factory
= output_api
.PresubmitNotifyResult
439 results
.append(warning_factory(
440 'You added one or more #includes of files that are temporarily\n'
441 'allowed but being removed. Can you avoid introducing the\n'
442 '#include? See relevant DEPS file(s) for details and contacts.',
443 warning_descriptions
))
447 def _CheckFilePermissions(input_api
, output_api
):
448 """Check that all files have their permissions properly set."""
449 args
= [sys
.executable
, 'tools/checkperms/checkperms.py', '--root',
450 input_api
.change
.RepositoryRoot()]
451 for f
in input_api
.AffectedFiles():
452 args
+= ['--file', f
.LocalPath()]
454 (errors
, stderrdata
) = subprocess
.Popen(args
).communicate()
458 results
.append(output_api
.PresubmitError('checkperms.py failed.',
463 def _CheckNoAuraWindowPropertyHInHeaders(input_api
, output_api
):
464 """Makes sure we don't include ui/aura/window_property.h
467 pattern
= input_api
.re
.compile(r
'^#include\s*"ui/aura/window_property.h"')
469 for f
in input_api
.AffectedFiles():
470 if not f
.LocalPath().endswith('.h'):
472 for line_num
, line
in f
.ChangedContents():
473 if pattern
.match(line
):
474 errors
.append(' %s:%d' % (f
.LocalPath(), line_num
))
478 results
.append(output_api
.PresubmitError(
479 'Header files should not include ui/aura/window_property.h', errors
))
483 def _CheckIncludeOrderForScope(scope
, input_api
, file_path
, changed_linenums
):
484 """Checks that the lines in scope occur in the right order.
486 1. C system files in alphabetical order
487 2. C++ system files in alphabetical order
488 3. Project's .h files
491 c_system_include_pattern
= input_api
.re
.compile(r
'\s*#include <.*\.h>')
492 cpp_system_include_pattern
= input_api
.re
.compile(r
'\s*#include <.*>')
493 custom_include_pattern
= input_api
.re
.compile(r
'\s*#include ".*')
495 C_SYSTEM_INCLUDES
, CPP_SYSTEM_INCLUDES
, CUSTOM_INCLUDES
= range(3)
497 state
= C_SYSTEM_INCLUDES
500 previous_line_num
= 0
501 problem_linenums
= []
502 for line_num
, line
in scope
:
503 if c_system_include_pattern
.match(line
):
504 if state
!= C_SYSTEM_INCLUDES
:
505 problem_linenums
.append((line_num
, previous_line_num
))
506 elif previous_line
and previous_line
> line
:
507 problem_linenums
.append((line_num
, previous_line_num
))
508 elif cpp_system_include_pattern
.match(line
):
509 if state
== C_SYSTEM_INCLUDES
:
510 state
= CPP_SYSTEM_INCLUDES
511 elif state
== CUSTOM_INCLUDES
:
512 problem_linenums
.append((line_num
, previous_line_num
))
513 elif previous_line
and previous_line
> line
:
514 problem_linenums
.append((line_num
, previous_line_num
))
515 elif custom_include_pattern
.match(line
):
516 if state
!= CUSTOM_INCLUDES
:
517 state
= CUSTOM_INCLUDES
518 elif previous_line
and previous_line
> line
:
519 problem_linenums
.append((line_num
, previous_line_num
))
521 problem_linenums
.append(line_num
)
523 previous_line_num
= line_num
526 for (line_num
, previous_line_num
) in problem_linenums
:
527 if line_num
in changed_linenums
or previous_line_num
in changed_linenums
:
528 warnings
.append(' %s:%d' % (file_path
, line_num
))
532 def _CheckIncludeOrderInFile(input_api
, f
, changed_linenums
):
533 """Checks the #include order for the given file f."""
535 system_include_pattern
= input_api
.re
.compile(r
'\s*#include \<.*')
536 # Exclude #include <.../...> includes from the check; e.g., <sys/...> includes
537 # often need to appear in a specific order.
538 excluded_include_pattern
= input_api
.re
.compile(r
'\s*#include \<.*/.*')
539 custom_include_pattern
= input_api
.re
.compile(r
'\s*#include "(?P<FILE>.*)"')
540 if_pattern
= input_api
.re
.compile(
541 r
'\s*#\s*(if|elif|else|endif|define|undef).*')
542 # Some files need specialized order of includes; exclude such files from this
544 uncheckable_includes_pattern
= input_api
.re
.compile(
546 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
548 contents
= f
.NewContents()
552 # Handle the special first include. If the first include file is
553 # some/path/file.h, the corresponding including file can be some/path/file.cc,
554 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
555 # etc. It's also possible that no special first include exists.
556 for line
in contents
:
558 if system_include_pattern
.match(line
):
559 # No special first include -> process the line again along with normal
563 match
= custom_include_pattern
.match(line
)
565 match_dict
= match
.groupdict()
566 header_basename
= input_api
.os_path
.basename(
567 match_dict
['FILE']).replace('.h', '')
568 if header_basename
not in input_api
.os_path
.basename(f
.LocalPath()):
569 # No special first include -> process the line again along with normal
574 # Split into scopes: Each region between #if and #endif is its own scope.
577 for line
in contents
[line_num
:]:
579 if uncheckable_includes_pattern
.match(line
):
581 if if_pattern
.match(line
):
582 scopes
.append(current_scope
)
584 elif ((system_include_pattern
.match(line
) or
585 custom_include_pattern
.match(line
)) and
586 not excluded_include_pattern
.match(line
)):
587 current_scope
.append((line_num
, line
))
588 scopes
.append(current_scope
)
591 warnings
.extend(_CheckIncludeOrderForScope(scope
, input_api
, f
.LocalPath(),
596 def _CheckIncludeOrder(input_api
, output_api
):
597 """Checks that the #include order is correct.
599 1. The corresponding header for source files.
600 2. C system files in alphabetical order
601 3. C++ system files in alphabetical order
602 4. Project's .h files in alphabetical order
604 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
605 these rules separately.
609 for f
in input_api
.AffectedFiles():
610 if f
.LocalPath().endswith(('.cc', '.h')):
611 changed_linenums
= set(line_num
for line_num
, _
in f
.ChangedContents())
612 warnings
.extend(_CheckIncludeOrderInFile(input_api
, f
, changed_linenums
))
616 if not input_api
.is_committing
:
617 results
.append(output_api
.PresubmitPromptWarning(_INCLUDE_ORDER_WARNING
,
620 # We don't warn on commit, to avoid stopping commits going through CQ.
621 results
.append(output_api
.PresubmitNotifyResult(_INCLUDE_ORDER_WARNING
,
626 def _CheckForVersionControlConflictsInFile(input_api
, f
):
627 pattern
= input_api
.re
.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
629 for line_num
, line
in f
.ChangedContents():
630 if pattern
.match(line
):
631 errors
.append(' %s:%d %s' % (f
.LocalPath(), line_num
, line
))
635 def _CheckForVersionControlConflicts(input_api
, output_api
):
636 """Usually this is not intentional and will cause a compile failure."""
638 for f
in input_api
.AffectedFiles():
639 errors
.extend(_CheckForVersionControlConflictsInFile(input_api
, f
))
643 results
.append(output_api
.PresubmitError(
644 'Version control conflict markers found, please resolve.', errors
))
648 def _CheckHardcodedGoogleHostsInLowerLayers(input_api
, output_api
):
649 def FilterFile(affected_file
):
650 """Filter function for use with input_api.AffectedSourceFiles,
651 below. This filters out everything except non-test files from
652 top-level directories that generally speaking should not hard-code
653 service URLs (e.g. src/android_webview/, src/content/ and others).
655 return input_api
.FilterSourceFile(
657 white_list
=(r
'^(android_webview|base|content|net)[\\\/].*', ),
658 black_list
=(_EXCLUDED_PATHS
+
659 _TEST_CODE_EXCLUDED_PATHS
+
660 input_api
.DEFAULT_BLACK_LIST
))
662 pattern
= input_api
.re
.compile('"[^"]*google\.com[^"]*"')
663 problems
= [] # items are (filename, line_number, line)
664 for f
in input_api
.AffectedSourceFiles(FilterFile
):
665 for line_num
, line
in f
.ChangedContents():
666 if pattern
.search(line
):
667 problems
.append((f
.LocalPath(), line_num
, line
))
670 if not input_api
.is_committing
:
671 warning_factory
= output_api
.PresubmitPromptWarning
673 # We don't want to block use of the CQ when there is a warning
674 # of this kind, so we only show a message when committing.
675 warning_factory
= output_api
.PresubmitNotifyResult
676 return [warning_factory(
677 'Most layers below src/chrome/ should not hardcode service URLs.\n'
678 'Are you sure this is correct? (Contact: joi@chromium.org)',
680 problem
[0], problem
[1], problem
[2]) for problem
in problems
])]
685 def _CommonChecks(input_api
, output_api
):
686 """Checks common to both upload and commit."""
688 results
.extend(input_api
.canned_checks
.PanProjectChecks(
689 input_api
, output_api
, excluded_paths
=_EXCLUDED_PATHS
))
690 results
.extend(_CheckAuthorizedAuthor(input_api
, output_api
))
692 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api
, output_api
))
693 results
.extend(_CheckNoIOStreamInHeaders(input_api
, output_api
))
694 results
.extend(_CheckNoUNIT_TESTInSourceFiles(input_api
, output_api
))
695 results
.extend(_CheckNoNewWStrings(input_api
, output_api
))
696 results
.extend(_CheckNoDEPSGIT(input_api
, output_api
))
697 results
.extend(_CheckNoBannedFunctions(input_api
, output_api
))
698 results
.extend(_CheckNoPragmaOnce(input_api
, output_api
))
699 results
.extend(_CheckNoTrinaryTrueFalse(input_api
, output_api
))
700 results
.extend(_CheckUnwantedDependencies(input_api
, output_api
))
701 results
.extend(_CheckFilePermissions(input_api
, output_api
))
702 results
.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api
, output_api
))
703 results
.extend(_CheckIncludeOrder(input_api
, output_api
))
704 results
.extend(_CheckForVersionControlConflicts(input_api
, output_api
))
705 results
.extend(_CheckPatchFiles(input_api
, output_api
))
706 results
.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api
, output_api
))
708 if any('PRESUBMIT.py' == f
.LocalPath() for f
in input_api
.AffectedFiles()):
709 results
.extend(input_api
.canned_checks
.RunUnitTestsInDirectory(
710 input_api
, output_api
,
711 input_api
.PresubmitLocalPath(),
712 whitelist
=[r
'.+_test\.py$']))
716 def _CheckSubversionConfig(input_api
, output_api
):
717 """Verifies the subversion config file is correctly setup.
719 Checks that autoprops are enabled, returns an error otherwise.
721 join
= input_api
.os_path
.join
722 if input_api
.platform
== 'win32':
723 appdata
= input_api
.environ
.get('APPDATA', '')
725 return [output_api
.PresubmitError('%APPDATA% is not configured.')]
726 path
= join(appdata
, 'Subversion', 'config')
728 home
= input_api
.environ
.get('HOME', '')
730 return [output_api
.PresubmitError('$HOME is not configured.')]
731 path
= join(home
, '.subversion', 'config')
734 'Please look at http://dev.chromium.org/developers/coding-style to\n'
735 'configure your subversion configuration file. This enables automatic\n'
736 'properties to simplify the project maintenance.\n'
737 'Pro-tip: just download and install\n'
738 'http://src.chromium.org/viewvc/chrome/trunk/tools/build/slave/config\n')
741 lines
= open(path
, 'r').read().splitlines()
742 # Make sure auto-props is enabled and check for 2 Chromium standard
744 if (not '*.cc = svn:eol-style=LF' in lines
or
745 not '*.pdf = svn:mime-type=application/pdf' in lines
or
746 not 'enable-auto-props = yes' in lines
):
748 output_api
.PresubmitNotifyResult(
749 'It looks like you have not configured your subversion config '
750 'file or it is not up-to-date.\n' + error_msg
)
752 except (OSError, IOError):
754 output_api
.PresubmitNotifyResult(
755 'Can\'t find your subversion config file.\n' + error_msg
)
760 def _CheckAuthorizedAuthor(input_api
, output_api
):
761 """For non-googler/chromites committers, verify the author's email address is
764 # TODO(maruel): Add it to input_api?
767 author
= input_api
.change
.author_email
769 input_api
.logging
.info('No author, skipping AUTHOR check')
771 authors_path
= input_api
.os_path
.join(
772 input_api
.PresubmitLocalPath(), 'AUTHORS')
774 input_api
.re
.match(r
'[^#]+\s+\<(.+?)\>\s*$', line
)
775 for line
in open(authors_path
))
776 valid_authors
= [item
.group(1).lower() for item
in valid_authors
if item
]
777 if not any(fnmatch
.fnmatch(author
.lower(), valid
) for valid
in valid_authors
):
778 input_api
.logging
.info('Valid authors are %s', ', '.join(valid_authors
))
779 return [output_api
.PresubmitPromptWarning(
780 ('%s is not in AUTHORS file. If you are a new contributor, please visit'
782 'http://www.chromium.org/developers/contributing-code and read the '
784 'If you are a chromite, verify the contributor signed the CLA.') %
789 def _CheckPatchFiles(input_api
, output_api
):
790 problems
= [f
.LocalPath() for f
in input_api
.AffectedFiles()
791 if f
.LocalPath().endswith(('.orig', '.rej'))]
793 return [output_api
.PresubmitError(
794 "Don't commit .rej and .orig files.", problems
)]
799 def CheckChangeOnUpload(input_api
, output_api
):
801 results
.extend(_CommonChecks(input_api
, output_api
))
805 def CheckChangeOnCommit(input_api
, output_api
):
807 results
.extend(_CommonChecks(input_api
, output_api
))
808 # TODO(thestig) temporarily disabled, doesn't work in third_party/
809 #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
810 # input_api, output_api, sources))
811 # Make sure the tree is 'open'.
812 results
.extend(input_api
.canned_checks
.CheckTreeIsOpen(
815 json_url
='http://chromium-status.appspot.com/current?format=json'))
816 results
.extend(input_api
.canned_checks
.CheckRietveldTryJobExecution(input_api
,
817 output_api
, 'http://codereview.chromium.org',
818 ('win_rel', 'linux_rel', 'mac_rel, win:compile'),
819 'tryserver@chromium.org'))
821 results
.extend(input_api
.canned_checks
.CheckChangeHasBugField(
822 input_api
, output_api
))
823 results
.extend(input_api
.canned_checks
.CheckChangeHasDescription(
824 input_api
, output_api
))
825 results
.extend(_CheckSubversionConfig(input_api
, output_api
))
829 def GetPreferredTrySlaves(project
, change
):
830 files
= change
.LocalPaths()
835 if all(re
.search('\.(m|mm)$|(^|[/_])mac[/_.]', f
) for f
in files
):
836 return ['mac_rel', 'mac_asan']
837 if all(re
.search('(^|[/_])win[/_.]', f
) for f
in files
):
839 if all(re
.search('(^|[/_])android[/_.]', f
) for f
in files
):
840 return ['android_dbg', 'android_clang_dbg']
841 if all(re
.search('^native_client_sdk', f
) for f
in files
):
842 return ['linux_nacl_sdk', 'win_nacl_sdk', 'mac_nacl_sdk']
843 if all(re
.search('[/_]ios[/_.]', f
) for f
in files
):
844 return ['ios_rel_device', 'ios_dbg_simulator']
854 'linux_clang:compile',
862 # Match things like path/aura/file.cc and path/file_aura.cc.
864 if any(re
.search('[/_](aura|chromeos)', f
) for f
in files
):
865 trybots
+= ['linux_chromeos_clang:compile', 'linux_chromeos_asan']