blob: 38cdcbc401cf44c7e9ec25cb80f1c06d579f988a [file] [log] [blame]
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# 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 the tools/build repo.
See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for
details on the presubmit API built into git cl.
"""
PRESUBMIT_VERSION = '2.0.0'
_IGNORE_FREEZE_FOOTER = 'Ignore-Freeze'
# The time module's handling of timezones is abysmal, so the boundaries are
# precomputed in UNIX time
_FREEZE_START = 1639641600 # 2021/12/16 00:00 -0800
_FREEZE_END = 1641196800 # 2022/01/03 00:00 -0800
def CheckFreeze(input_api, output_api):
if _FREEZE_START <= input_api.time.time() < _FREEZE_END:
footers = input_api.change.GitFootersFromDescription()
if _IGNORE_FREEZE_FOOTER not in footers:
def convert(t):
ts = input_api.time.localtime(t)
return input_api.time.strftime('%Y/%m/%d %H:%M %z', ts)
return [
output_api.PresubmitError(
'There is a prod freeze in effect from {} until {}'.format(
convert(_FREEZE_START), convert(_FREEZE_END)
)
)
]
return []
# A list of files that are _only_ compatible with python3. Tests for these are
# only run under vpython3, and lints are performed with pylint 2.7. The
# expectation is that these will become the defaults over time.
PYTHON3_ONLY_FILES = (
'PRESUBMIT_test.py',
'recipes/recipes/flakiness/generate_builder_test_data.resources/query.py',
(
'recipes/recipes/flakiness/generate_builder_test_data.resources/'
'query_test.py'
),
'recipes/recipe_modules/chromium_tests_builder_config/PRESUBMIT.py',
(
'recipes/recipe_modules/chromium_tests_builder_config/migration/'
'scripts/generate_groupings.py'
),
(
'recipes/recipe_modules/chromium_tests_builder_config/migration/'
'scripts/migrate.py'
),
(
'recipes/recipe_modules/chromium_tests_builder_config/migration/'
'scripts/tests/generate_groupings_integration_test.py'
),
(
'recipes/recipe_modules/chromium_tests_builder_config/migration/'
'scripts/tests/generate_groupings_unit_test.py'
),
(
'recipes/recipe_modules/chromium_tests_builder_config/migration/'
'scripts/tests/migrate_integration_test.py'
),
(
'recipes/recipe_modules/chromium_tests_builder_config/migration/'
'scripts/tests/migrate_unit_test.py'
),
'recipes/recipe_modules/cronet/resources/clear_landmines.py',
(
'recipes/recipe_modules/tricium_clang_tidy/resources/'
'tricium_clang_tidy_script.py'
),
(
'recipes/recipe_modules/tricium_clang_tidy/resources/'
'tricium_clang_tidy_test.py'
),
)
def GetFilesToSkip(input_api):
return list(input_api.DEFAULT_FILES_TO_SKIP) + [
r'.*recipes/.*/build.*/.',
r'.*recipes/.*/isolate.*/.',
r'.*depot_tools/.*',
r'.*goma/.*',
r'.*scripts/release/.*',
r'.*recipes/recipes.py$',
r'.*recipes/recipes/.*_autogen.py$',
# Exclude all "...recipe_deps" directories.
#
# These directories are created by recipe engine.
# Each is an independent recipe checkout. If Pylint is run on
# these, it will hang forever, so we must exclude them.
r'^(.*/)?\..*recipe_deps/.*',
]
def join(input_api, *args):
return input_api.os_path.normpath(
input_api.os_path.join(input_api.PresubmitLocalPath(), *args)
)
def CheckPylintOnCommit(input_api, output_api):
vpython = 'vpython.bat' if input_api.is_windows else 'vpython'
infra_path = input_api.subprocess.check_output([
vpython, 'scripts/common/env.py', 'print'
]).split()
disabled_warnings = [
'C0321', # More than one statement on a single line
'W0613', # Unused argument
'W0403', # Relative import. TODO(crbug.com/1095510): remove this
]
extra_paths_list = infra_path + [
# Initially, a separate run was done for unit tests but now that
# pylint is fetched in memory with setuptools, it seems it caches
# sys.path so modifications to sys.path aren't kept.
join(input_api, 'recipes', 'unittests'),
join(input_api, 'tests'),
]
lints = input_api.canned_checks.RunPylint(
input_api,
output_api,
files_to_skip=GetFilesToSkip(input_api) + list(PYTHON3_ONLY_FILES),
disabled_warnings=disabled_warnings,
extra_paths_list=extra_paths_list,
)
if PYTHON3_ONLY_FILES:
lints.extend(
input_api.canned_checks.RunPylint(
input_api,
output_api,
files_to_check=PYTHON3_ONLY_FILES,
disabled_warnings=disabled_warnings,
extra_paths_list=extra_paths_list,
version='2.7',
)
)
return lints
def _GetTests(input_api, output_api, test_files):
python3_only_files = set(join(input_api, f) for f in PYTHON3_ONLY_FILES)
non_python3_test_files = []
python3_test_files = []
for t in sorted(test_files):
if t in python3_only_files:
python3_test_files.append(t)
else:
non_python3_test_files.append(t)
tests = []
tests.extend(
input_api.canned_checks.GetUnitTests(
input_api,
output_api,
non_python3_test_files,
)
)
tests.extend(
input_api.canned_checks.GetUnitTests(
input_api,
output_api,
python3_test_files,
run_on_python2=False,
run_on_python3=True,
skip_shebang_check=True,
)
)
return tests
# The following tests invoke recipes.py which isn't safe in parallel, so they'll
# be run in a separate check function that runs them sequentially
RECIPES_PY_TESTS = [
'recipes/unittests/recipe_test.py',
(
'recipes/recipe_modules/chromium_tests_builder_config/migration/'
'scripts/tests/generate_groupings_integration_test.py'
),
(
'recipes/recipe_modules/chromium_tests_builder_config/migration/'
'scripts/tests/migrate_integration_test.py'
),
]
def _RecipesPyTestFiles(input_api):
return [join(input_api, f) for f in RECIPES_PY_TESTS]
def CheckRecipesPyTestsOnCommit(input_api, output_api):
tests = _GetTests(input_api, output_api, _RecipesPyTestFiles(input_api))
return input_api.RunTests(tests, parallel=False)
def CheckTestsOnCommit(input_api, output_api):
excluded_test_files = set(_RecipesPyTestFiles(input_api))
test_files = []
for dir_glob in (
('recipes', 'unittests'),
('scripts', 'common', 'unittests'),
('recipes', 'recipe_modules', '*', 'unittests'),
('recipes', 'recipe_modules', '*', 'resources'),
('recipes', 'recipe_modules', 'chromium_tests_builder_config',
'migration', 'scripts', 'tests'),
('recipes', 'recipes', '*.resources'),
('recipes', 'recipes', '*', '*.resources'),
):
glob = dir_glob + ('*_test.py',)
test_files.extend(
x for x in input_api.glob(join(input_api, *glob))
if x not in excluded_test_files
)
tests = _GetTests(input_api, output_api, test_files)
return input_api.RunTests(tests)
def CheckPanProjectChecksOnCommit(input_api, output_api):
return input_api.canned_checks.PanProjectChecks(
input_api,
output_api,
excluded_paths=GetFilesToSkip(input_api),
owners_check=False
)
def CheckConfigFilesParse(input_api, output_api):
file_filter = lambda x: x.LocalPath() == 'infra/config/recipes.cfg'
return input_api.canned_checks.CheckJsonParses(
input_api, output_api, file_filter=file_filter
)
def CheckPatchFormatted(input_api, output_api):
# TODO(https://crbug.com/979330) If clang-format is fixed for non-chromium
# repos, remove check_clang_format=False so that proto files can be formatted
return input_api.canned_checks.CheckPatchFormatted(
input_api, output_api, check_clang_format=False
)