blob: aa5a7b0ecaf1104d1bad8d05bd3cdc65b88de8de [file]
# Copyright 2012 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Top-level presubmit script for testing.
See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
for more details on the presubmit API built into depot_tools.
"""
PRESUBMIT_VERSION = '2.0.0'
PYLINT_PATHS_COMPONENTS = [
('build',),
('build', 'android'),
('build', 'util'),
('content', 'test', 'gpu'),
('testing',),
('testing', 'buildbot'),
('testing', 'scripts'),
('testing', 'variations', 'presubmit'),
('third_party',),
('third_party', 'blink', 'renderer', 'bindings', 'scripts'),
('third_party', 'blink', 'tools'),
('third_party', 'catapult', 'telemetry'),
('third_party', 'catapult', 'third_party', 'typ'),
('third_party', 'catapult', 'tracing'),
('third_party', 'domato', 'src'),
('third_party', 'js_code_coverage'),
('third_party', 'webdriver', 'pylib'),
('tools', 'perf'),
]
def _GetChromiumSrcPath(input_api):
"""Returns the path to the Chromium src directory."""
return input_api.os_path.realpath(
input_api.os_path.join(input_api.PresubmitLocalPath(), '..')
)
def _GetTestingEnv(input_api):
"""Gets the common environment for running testing/ tests."""
testing_env = dict(input_api.environ)
testing_path = input_api.PresubmitLocalPath()
# TODO(crbug.com/40237086): This is temporary till gpu code in
# flake_suppressor_commonis moved to gpu dir.
# Only common code will reside under /testing.
gpu_test_path = input_api.os_path.join(
input_api.PresubmitLocalPath(), '..', 'content', 'test', 'gpu'
)
typ_path = input_api.os_path.join(
input_api.PresubmitLocalPath(),
'..',
'third_party',
'catapult',
'third_party',
'typ',
)
testing_env.update(
{
'PYTHONPATH': input_api.os_path.pathsep.join(
[testing_path, gpu_test_path, typ_path]
),
'PYTHONDONTWRITEBYTECODE': '1',
}
)
return testing_env
def _ShouldRunCommonUnittests(input_api, directories):
"""Returns True if affected files match directories or this PRESUBMIT.py."""
if isinstance(directories, str):
directories = [directories]
this_presubmit = input_api.os_path.normcase(
input_api.os_path.join(input_api.PresubmitLocalPath(), 'PRESUBMIT.py')
)
# Ensure trailing separator to avoid prefix-matching unrelated directories.
prefixes = tuple(
input_api.os_path.normcase(
input_api.os_path.join(input_api.PresubmitLocalPath(), d, '')
)
for d in directories
)
affected_paths = (
input_api.os_path.normcase(f.AbsoluteLocalPath())
for f in input_api.AffectedFiles()
)
return any(
p.startswith(prefixes) or p == this_presubmit for p in affected_paths
)
def CheckFlakeSuppressorCommonUnittests(input_api, output_api):
"""Runs unittests in the testing/flake_suppressor_common/ directory."""
# Note: flake_suppressor_common depends on unexpected_passes_common.
if not _ShouldRunCommonUnittests(
input_api, ['flake_suppressor_common', 'unexpected_passes_common']
):
return []
return input_api.canned_checks.RunUnitTestsInDirectory(
input_api,
output_api,
input_api.os_path.join(
input_api.PresubmitLocalPath(), 'flake_suppressor_common'
),
[r'^.+_unittest\.py$'],
env=_GetTestingEnv(input_api),
)
def CheckUnexpectedPassesCommonUnittests(input_api, output_api):
"""Runs unittests in the testing/unexpected_passes_common/ directory."""
if not _ShouldRunCommonUnittests(input_api, ['unexpected_passes_common']):
return []
return input_api.canned_checks.RunUnitTestsInDirectory(
input_api,
output_api,
input_api.os_path.join(
input_api.PresubmitLocalPath(), 'unexpected_passes_common'
),
[r'^.+_unittest\.py$'],
env=_GetTestingEnv(input_api),
)
def CheckPresubmitUnittests(input_api, output_api):
"""Runs unittests for testing/PRESUBMIT.py."""
return input_api.canned_checks.RunUnitTestsInDirectory(
input_api,
output_api,
input_api.PresubmitLocalPath(),
[r'^PRESUBMIT_test\.py$'],
env=_GetTestingEnv(input_api),
)
def _GetPylintFilesToCheck(input_api):
"""Returns regex patterns identifying Python files to lint.
If testing/PRESUBMIT.py, any root Python file under testing/, or
input_api.no_diffs is set, returns None to lint all Python files under
testing/. Otherwise, scopes linting to the affected subdirectories under
testing/, or returns [] if no Python files are affected.
"""
if input_api.no_diffs:
return None
local_root = input_api.PresubmitLocalPath()
norm_root = input_api.os_path.normcase(input_api.os_path.abspath(local_root))
this_presubmit = input_api.os_path.normcase(
input_api.os_path.join(norm_root, 'PRESUBMIT.py')
)
affected_subdirs = set()
has_root_py = False
for f in input_api.AffectedFiles():
abs_path = f.AbsoluteLocalPath()
norm_path = input_api.os_path.normcase(input_api.os_path.abspath(abs_path))
if norm_path == this_presubmit:
return None
if not norm_path.endswith('.py'):
continue
try:
norm_rel = input_api.os_path.relpath(norm_path, norm_root)
except ValueError:
continue
if (
norm_rel != '.'
and not norm_rel.startswith('..' + input_api.os_path.sep)
and norm_rel != '..'
and not input_api.os_path.isabs(norm_rel)
):
# Extract from original case path to avoid case-sensitive regex failures.
original_rel_path = input_api.os_path.relpath(abs_path, local_root)
parts = original_rel_path.split(input_api.os_path.sep)
if len(parts) > 1:
affected_subdirs.add(parts[0])
else:
has_root_py = True
if not affected_subdirs and not has_root_py:
# No affected Python files in testing/; return empty list to skip.
return []
# If root Python files changed, check everything to ensure module consistency.
if has_root_py:
return None
patterns = []
for subdir in sorted(affected_subdirs):
# Match both POSIX and Windows separators across OS regex engines.
patterns.append(r'%s(?:/|\\).*\.py$' % input_api.re.escape(subdir))
return patterns
def CheckPylint(input_api, output_api):
"""Runs pylint on affected subdirectories or all directory content."""
files_to_check = _GetPylintFilesToCheck(input_api)
if files_to_check == []:
return []
files_to_skip = input_api.DEFAULT_FILES_TO_SKIP
chromium_src_path = _GetChromiumSrcPath(input_api)
pylint_extra_paths = [
input_api.os_path.join(chromium_src_path, *component)
for component in PYLINT_PATHS_COMPONENTS
]
if input_api.is_windows:
# These scripts don't run on Windows and should not be linted on Windows -
# trying to do so will lead to spurious errors.
files_to_skip += ('xvfb.py', '.*host_info.py')
pylint_checks = input_api.canned_checks.GetPylint(
input_api,
output_api,
files_to_check=files_to_check,
extra_paths_list=pylint_extra_paths,
files_to_skip=files_to_skip,
# TODO(crbug.com/355016915): Remove this directory-specific pylintrc
# file as the default one gets its disable list cleaned up.
pylintrc='pylintrc',
version='3.2',
)
return input_api.RunTests(pylint_checks)
def CheckPatchFormatted(input_api, output_api):
return input_api.canned_checks.CheckPatchFormatted(
input_api,
output_api,
result_factory=output_api.PresubmitError,
)