blob: 56d30184a82da6773446da5dff52b9aa91dad4b5 [file] [log] [blame]
# Copyright 2015 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 catapult.
See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts
for more details about the presubmit API built into depot_tools.
"""
import re
import sys
_EXCLUDED_PATHS = (
r'(.*[\\/])?\.git[\\/].*',
r'.+\.png$',
r'.+\.svg$',
r'.+\.skp$',
r'.+\.gypi$',
r'.+\.gyp$',
r'.+\.gn$',
r'.*\.gitignore$',
r'.*codereview.settings$',
r'.*AUTHOR$',
r'^CONTRIBUTORS\.md$',
r'.*LICENSE$',
r'.*OWNERS$',
r'.*README\.md$',
r'^dashboard[\\/]dashboard[\\/]templates[\\/].*',
r'^experimental[\\/]heatmap[\\/].*',
r'^perf_insights[\\/]test_data[\\/].*',
r'^perf_insights[\\/]third_party[\\/].*',
r'^third_party[\\/].*',
r'^tracing[\\/]\.allow-devtools-save$',
r'^tracing[\\/]bower\.json$',
r'^tracing[\\/]\.bowerrc$',
r'^tracing[\\/]tracing_examples[\\/]string_convert\.js$',
r'^tracing[\\/]test_data[\\/].*',
r'^tracing[\\/]third_party[\\/].*',
r'^telemetry[\\/]support[\\/]html_output[\\/]results-template.html',
)
_CATAPULT_BUG_ID_RE = re.compile(r'#[1-9]\d*')
_RIETVELD_BUG_ID_RE = re.compile(r'[1-9]\d*')
_RIETVELD_REPOSITORY_NAMES = frozenset({'chromium', 'v8', 'angleproject'})
def CheckChangeLogBug(input_api, output_api):
# Show a presubmit message if there is no BUG= line.
if input_api.change.BUG is None:
return [output_api.PresubmitNotifyResult(
'If this change has associated Catapult and/or Rietveld bug(s), add a '
'"BUG=<bug>(, <bug>)*" line to the patch description where <bug> can '
'be one of the following: catapult:#NNNN, ' +
', '.join('%s:NNNNNN' % n for n in _RIETVELD_REPOSITORY_NAMES) + '.')]
# Throw a presubmit error if the BUG= line is provided but empty.
if input_api.change.BUG.strip() == '':
return [output_api.PresubmitError(
'Empty BUG= line. Either remove it, or, preferably, change it to '
'"BUG=<bug>(, <bug>)*" where <bug> can be one of the following: ' +
'catapult:#NNNN, ' +
', '.join('%s:NNNNNN' % n for n in _RIETVELD_REPOSITORY_NAMES) + '.')]
# Check that each bug in the BUG= line has the correct format.
error_messages = []
catapult_bug_provided = False
append_repository_order_error = False
for index, bug in enumerate(input_api.change.BUG.split(',')):
if index > 0:
bug = bug.lstrip() # Allow spaces after commas.
# Check if the bug can be split into a repository name and a bug ID (e.g.
# 'catapult:#1234' -> 'catapult' and '#1234').
bug_parts = bug.split(':')
if len(bug_parts) != 2:
error_messages.append('Invalid bug "%s". Bugs should be provided in the '
'"<repository-name>:<bug-id>" format.' % bug)
continue
repository_name, bug_id = bug_parts
if repository_name == 'catapult':
if not _CATAPULT_BUG_ID_RE.match(bug_id):
error_messages.append('Invalid bug "%s". Bugs in the Catapult '
'repository should be provided in the '
'"catapult:#NNNN" format.' % bug)
catapult_bug_provided = True
elif repository_name in _RIETVELD_REPOSITORY_NAMES:
if not _RIETVELD_BUG_ID_RE.match(bug_id):
error_messages.append('Invalid bug "%s". Bugs in the Rietveld %s '
'repository should be provided in the '
'"%s:NNNNNN" format.' % (bug, repository_name,
repository_name))
if catapult_bug_provided:
append_repository_order_error = True
else:
error_messages.append('Invalid bug "%s". Unknown repository "%s".' % (
bug, repository_name))
if append_repository_order_error:
error_messages.append('Please list Rietveld bugs (' +
', '.join('%s:NNNNNN' % n
for n in _RIETVELD_REPOSITORY_NAMES) +
') before Catapult bugs (catapult:#NNNN) so '
'that Rietveld would display them as hyperlinks.')
return map(output_api.PresubmitError, error_messages)
def CheckChange(input_api, output_api):
results = []
try:
sys.path += [input_api.PresubmitLocalPath()]
from catapult_build import js_checks
from catapult_build import html_checks
from catapult_build import repo_checks
results += input_api.canned_checks.PanProjectChecks(
input_api, output_api, excluded_paths=_EXCLUDED_PATHS)
results += CheckChangeLogBug(input_api, output_api)
results += js_checks.RunChecks(
input_api, output_api, excluded_paths=_EXCLUDED_PATHS)
results += html_checks.RunChecks(
input_api, output_api, excluded_paths=_EXCLUDED_PATHS)
results += repo_checks.RunChecks(input_api, output_api)
finally:
sys.path.remove(input_api.PresubmitLocalPath())
return results
def CheckChangeOnUpload(input_api, output_api):
return CheckChange(input_api, output_api)
def CheckChangeOnCommit(input_api, output_api):
return CheckChange(input_api, output_api)