1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
# Copyright 2015 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 src/components/cronet.
See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
for more details about the presubmit API built into depot_tools.
"""
import os
PRESUBMIT_VERSION = '2.0.0'
def CheckPyLint(input_api, output_api):
pylint_checks = input_api.canned_checks.GetPylint(input_api, output_api)
return input_api.RunTests(pylint_checks)
def CheckPackage(input_api, output_api):
"""Verify API classes are in org.chromium.net package, and implementation
classes are not in org.chromium.net package."""
api_packages = ['org.chromium.net', 'org.chromium.net.apihelpers']
api_packages_regex = '(' + '|'.join(api_packages) + ')'
api_file_pattern = input_api.re.compile(
r'^components/cronet/android/api/.*\.(java|template)$')
impl_file_pattern = input_api.re.compile(
r'^components/cronet/android/java/.*\.(java|template)$')
invalid_api_package_pattern = input_api.re.compile(r'^package (?!' +
api_packages_regex +
';)')
invalid_impl_package_pattern = input_api.re.compile(r'^package ' +
api_packages_regex +
';')
source_filter = lambda path: input_api.FilterSourceFile(
path,
files_to_check=[r'^components/cronet/android/.*\.(java|template)$'])
problems = []
for f in input_api.AffectedSourceFiles(source_filter):
local_path = f.LocalPath()
for line_number, line in f.ChangedContents():
if (api_file_pattern.search(local_path)):
if (invalid_api_package_pattern.search(line)):
problems.append('%s:%d\n %s' %
(local_path, line_number, line.strip()))
elif (impl_file_pattern.search(local_path)):
if (invalid_impl_package_pattern.search(line)):
problems.append('%s:%d\n %s' %
(local_path, line_number, line.strip()))
if problems:
return [
output_api.PresubmitError(
'API classes must be in org.chromium.net package, '
'and implementation\n'
'classes must not be in org.chromium.net package.', problems)
]
return []
def CheckUnittestsOnCommit(input_api, output_api):
return input_api.RunTests(
input_api.canned_checks.GetUnitTestsRecursively(
input_api,
output_api,
os.path.join(input_api.change.RepositoryRoot(), 'components',
'cronet'),
files_to_check=['.*test\\.py$'],
files_to_skip=[]))
GOOD_CHANGE_ID_TXT = 'good_change_id'
BAD_CHANGE_ID_TXT = 'bad_change_id'
BUG_TXT = 'bugs'
COMMENT_TXT = 'comment'
def _GetBreakagesFilePathIfChanged(change):
""" Returns |true| if the change may affect the breakages file. """
for file in change.AffectedFiles(include_deletes=False):
if file.LocalPath().endswith('breakages.json'):
return file
return None
def _IsValidChangeId(input_api, change_id):
""" Returns |true| if the change_id is not valid.
Validity means starting with the letter I followed by 40 hex chars.
"""
if (input_api.re.fullmatch(r'^I[0-9a-fA-F]{40}$', change_id)
and not input_api.re.fullmatch(r'^I00*$', change_id)):
return True
return False
def _GetInvalidChangeIdText(input_api, breakage, key):
if key not in breakage:
return ''
if not _IsValidChangeId(input_api, breakage[key]):
return '\t - entry has invalid %s: %s\n' % (key, breakage[key])
return ''
def _GetMissingKeyText(breakage, key):
if key in breakage:
return ''
return '\t - entry is missing the "%s" key\n' % key
def _GetGoodWithoutBadChangeIdText(breakage):
if GOOD_CHANGE_ID_TXT in breakage and BAD_CHANGE_ID_TXT not in breakage:
return '\t - entry cannot have %s without %s\n' % \
(GOOD_CHANGE_ID_TXT, BAD_CHANGE_ID_TXT)
return ''
def _GetUnknownKeyText(breakage):
unknown_keys = []
for key in breakage:
if (key.startswith('_') or # ignore comments
key == BAD_CHANGE_ID_TXT or key == GOOD_CHANGE_ID_TXT or
key == BUG_TXT or key == COMMENT_TXT):
continue
unknown_keys.append(key)
if unknown_keys:
return (f'\t - entry contains unknown key(s): {unknown_keys}. '
f'Expected either {GOOD_CHANGE_ID_TXT}, {BUG_TXT} or '
f'{COMMENT_TXT}\n')
return ''
def CheckBreakagesFile(input_api, output_api):
"""Verify that the change_ids listed in the breakages file are valid."""
breakages_file = _GetBreakagesFilePathIfChanged(input_api.change)
if not breakages_file:
return []
breakages = input_api.json.loads(
input_api.ReadFile(breakages_file))["breakages"]
problems = []
for i, breakage in enumerate(breakages):
problem = ""
# ensures that the entries, where existing are valid and that there are
# no unknown keys.
problem += _GetInvalidChangeIdText(input_api, breakage,
BAD_CHANGE_ID_TXT)
problem += _GetInvalidChangeIdText(input_api, breakage,
GOOD_CHANGE_ID_TXT)
problem += _GetGoodWithoutBadChangeIdText(breakage)
problem += _GetMissingKeyText(breakage, BUG_TXT)
problem += _GetUnknownKeyText(breakage)
if problem:
problems.append('Breakage Entry %d: \n%s' % (i, problem))
if problems:
return [
output_api.PresubmitError(
'The breakages.json file contains invalid entries.\n'
'Please cross-check the entries.', problems)
]
return []
|