1*c8dee2aaSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*c8dee2aaSAndroid Build Coastguard Worker# Copyright (c) 2013 The Chromium Authors. All rights reserved. 3*c8dee2aaSAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*c8dee2aaSAndroid Build Coastguard Worker# found in the LICENSE file. 5*c8dee2aaSAndroid Build Coastguard Worker 6*c8dee2aaSAndroid Build Coastguard Worker 7*c8dee2aaSAndroid Build Coastguard Worker"""Top-level presubmit script for Skia. 8*c8dee2aaSAndroid Build Coastguard Worker 9*c8dee2aaSAndroid Build Coastguard WorkerSee http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts 10*c8dee2aaSAndroid Build Coastguard Workerfor more details about the presubmit API built into gcl. 11*c8dee2aaSAndroid Build Coastguard Worker""" 12*c8dee2aaSAndroid Build Coastguard Worker 13*c8dee2aaSAndroid Build Coastguard Workerimport difflib 14*c8dee2aaSAndroid Build Coastguard Workerimport os 15*c8dee2aaSAndroid Build Coastguard Workerimport re 16*c8dee2aaSAndroid Build Coastguard Workerimport subprocess 17*c8dee2aaSAndroid Build Coastguard Workerimport sys 18*c8dee2aaSAndroid Build Coastguard Worker 19*c8dee2aaSAndroid Build Coastguard Worker 20*c8dee2aaSAndroid Build Coastguard WorkerRELEASE_NOTES_DIR = 'relnotes' 21*c8dee2aaSAndroid Build Coastguard WorkerRELEASE_NOTES_FILE_NAME = 'RELEASE_NOTES.md' 22*c8dee2aaSAndroid Build Coastguard WorkerRELEASE_NOTES_README = '//relnotes/README.md' 23*c8dee2aaSAndroid Build Coastguard Worker 24*c8dee2aaSAndroid Build Coastguard WorkerGOLD_TRYBOT_URL = 'https://gold.skia.org/search?issue=' 25*c8dee2aaSAndroid Build Coastguard Worker 26*c8dee2aaSAndroid Build Coastguard WorkerSERVICE_ACCOUNT_SUFFIX = [ 27*c8dee2aaSAndroid Build Coastguard Worker '@%s.iam.gserviceaccount.com' % project for project in [ 28*c8dee2aaSAndroid Build Coastguard Worker 'skia-buildbots.google.com', 'skia-swarming-bots', 'skia-public', 29*c8dee2aaSAndroid Build Coastguard Worker 'skia-corp.google.com', 'chops-service-accounts']] 30*c8dee2aaSAndroid Build Coastguard Worker 31*c8dee2aaSAndroid Build Coastguard WorkerUSE_PYTHON3 = True 32*c8dee2aaSAndroid Build Coastguard Worker 33*c8dee2aaSAndroid Build Coastguard Worker 34*c8dee2aaSAndroid Build Coastguard Workerdef _CheckChangeHasEol(input_api, output_api, source_file_filter=None): 35*c8dee2aaSAndroid Build Coastguard Worker """Checks that files end with at least one \n (LF).""" 36*c8dee2aaSAndroid Build Coastguard Worker eof_files = [] 37*c8dee2aaSAndroid Build Coastguard Worker for f in input_api.AffectedSourceFiles(source_file_filter): 38*c8dee2aaSAndroid Build Coastguard Worker contents = input_api.ReadFile(f, 'rb') 39*c8dee2aaSAndroid Build Coastguard Worker # Check that the file ends in at least one newline character. 40*c8dee2aaSAndroid Build Coastguard Worker if len(contents) > 1 and contents[-1:] != '\n': 41*c8dee2aaSAndroid Build Coastguard Worker eof_files.append(f.LocalPath()) 42*c8dee2aaSAndroid Build Coastguard Worker 43*c8dee2aaSAndroid Build Coastguard Worker if eof_files: 44*c8dee2aaSAndroid Build Coastguard Worker return [output_api.PresubmitPromptWarning( 45*c8dee2aaSAndroid Build Coastguard Worker 'These files should end in a newline character:', 46*c8dee2aaSAndroid Build Coastguard Worker items=eof_files)] 47*c8dee2aaSAndroid Build Coastguard Worker return [] 48*c8dee2aaSAndroid Build Coastguard Worker 49*c8dee2aaSAndroid Build Coastguard Worker 50*c8dee2aaSAndroid Build Coastguard Workerdef _JsonChecks(input_api, output_api): 51*c8dee2aaSAndroid Build Coastguard Worker """Run checks on any modified json files.""" 52*c8dee2aaSAndroid Build Coastguard Worker failing_files = [] 53*c8dee2aaSAndroid Build Coastguard Worker for affected_file in input_api.AffectedFiles(None): 54*c8dee2aaSAndroid Build Coastguard Worker affected_file_path = affected_file.LocalPath() 55*c8dee2aaSAndroid Build Coastguard Worker is_json = affected_file_path.endswith('.json') 56*c8dee2aaSAndroid Build Coastguard Worker is_metadata = (affected_file_path.startswith('site/') and 57*c8dee2aaSAndroid Build Coastguard Worker affected_file_path.endswith('/METADATA')) 58*c8dee2aaSAndroid Build Coastguard Worker if is_json or is_metadata: 59*c8dee2aaSAndroid Build Coastguard Worker try: 60*c8dee2aaSAndroid Build Coastguard Worker input_api.json.load(open(affected_file_path, 'r')) 61*c8dee2aaSAndroid Build Coastguard Worker except ValueError as ve: 62*c8dee2aaSAndroid Build Coastguard Worker failing_files.append(f'{affected_file_path}\t\t{ve}') 63*c8dee2aaSAndroid Build Coastguard Worker 64*c8dee2aaSAndroid Build Coastguard Worker results = [] 65*c8dee2aaSAndroid Build Coastguard Worker if failing_files: 66*c8dee2aaSAndroid Build Coastguard Worker results.append( 67*c8dee2aaSAndroid Build Coastguard Worker output_api.PresubmitError( 68*c8dee2aaSAndroid Build Coastguard Worker 'The following files contain invalid json:\n%s\n' % 69*c8dee2aaSAndroid Build Coastguard Worker '\n'.join(failing_files))) 70*c8dee2aaSAndroid Build Coastguard Worker return results 71*c8dee2aaSAndroid Build Coastguard Worker 72*c8dee2aaSAndroid Build Coastguard Worker 73*c8dee2aaSAndroid Build Coastguard Workerdef _IfDefChecks(input_api, output_api): 74*c8dee2aaSAndroid Build Coastguard Worker """Ensures if/ifdef are not before includes. See skbug/3362 for details.""" 75*c8dee2aaSAndroid Build Coastguard Worker comment_block_start_pattern = re.compile('^\s*\/\*.*$') 76*c8dee2aaSAndroid Build Coastguard Worker comment_block_middle_pattern = re.compile('^\s+\*.*') 77*c8dee2aaSAndroid Build Coastguard Worker comment_block_end_pattern = re.compile('^\s+\*\/.*$') 78*c8dee2aaSAndroid Build Coastguard Worker single_line_comment_pattern = re.compile('^\s*//.*$') 79*c8dee2aaSAndroid Build Coastguard Worker def is_comment(line): 80*c8dee2aaSAndroid Build Coastguard Worker return (comment_block_start_pattern.match(line) or 81*c8dee2aaSAndroid Build Coastguard Worker comment_block_middle_pattern.match(line) or 82*c8dee2aaSAndroid Build Coastguard Worker comment_block_end_pattern.match(line) or 83*c8dee2aaSAndroid Build Coastguard Worker single_line_comment_pattern.match(line)) 84*c8dee2aaSAndroid Build Coastguard Worker 85*c8dee2aaSAndroid Build Coastguard Worker empty_line_pattern = re.compile('^\s*$') 86*c8dee2aaSAndroid Build Coastguard Worker def is_empty_line(line): 87*c8dee2aaSAndroid Build Coastguard Worker return empty_line_pattern.match(line) 88*c8dee2aaSAndroid Build Coastguard Worker 89*c8dee2aaSAndroid Build Coastguard Worker failing_files = [] 90*c8dee2aaSAndroid Build Coastguard Worker for affected_file in input_api.AffectedSourceFiles(None): 91*c8dee2aaSAndroid Build Coastguard Worker affected_file_path = affected_file.LocalPath() 92*c8dee2aaSAndroid Build Coastguard Worker if affected_file_path.endswith('.cpp') or affected_file_path.endswith('.h'): 93*c8dee2aaSAndroid Build Coastguard Worker f = open(affected_file_path) 94*c8dee2aaSAndroid Build Coastguard Worker for line in f: 95*c8dee2aaSAndroid Build Coastguard Worker if is_comment(line) or is_empty_line(line): 96*c8dee2aaSAndroid Build Coastguard Worker continue 97*c8dee2aaSAndroid Build Coastguard Worker # The below will be the first real line after comments and newlines. 98*c8dee2aaSAndroid Build Coastguard Worker if line.startswith('#if 0 '): 99*c8dee2aaSAndroid Build Coastguard Worker pass 100*c8dee2aaSAndroid Build Coastguard Worker elif line.startswith('#if ') or line.startswith('#ifdef '): 101*c8dee2aaSAndroid Build Coastguard Worker failing_files.append(affected_file_path) 102*c8dee2aaSAndroid Build Coastguard Worker break 103*c8dee2aaSAndroid Build Coastguard Worker 104*c8dee2aaSAndroid Build Coastguard Worker results = [] 105*c8dee2aaSAndroid Build Coastguard Worker if failing_files: 106*c8dee2aaSAndroid Build Coastguard Worker results.append( 107*c8dee2aaSAndroid Build Coastguard Worker output_api.PresubmitError( 108*c8dee2aaSAndroid Build Coastguard Worker 'The following files have #if or #ifdef before includes:\n%s\n\n' 109*c8dee2aaSAndroid Build Coastguard Worker 'See https://bug.skia.org/3362 for why this should be fixed.' % 110*c8dee2aaSAndroid Build Coastguard Worker '\n'.join(failing_files))) 111*c8dee2aaSAndroid Build Coastguard Worker return results 112*c8dee2aaSAndroid Build Coastguard Worker 113*c8dee2aaSAndroid Build Coastguard Worker 114*c8dee2aaSAndroid Build Coastguard Workerdef _CopyrightChecks(input_api, output_api, source_file_filter=None): 115*c8dee2aaSAndroid Build Coastguard Worker results = [] 116*c8dee2aaSAndroid Build Coastguard Worker year_pattern = r'\d{4}' 117*c8dee2aaSAndroid Build Coastguard Worker year_range_pattern = r'%s(-%s)?' % (year_pattern, year_pattern) 118*c8dee2aaSAndroid Build Coastguard Worker years_pattern = r'%s(,%s)*,?' % (year_range_pattern, year_range_pattern) 119*c8dee2aaSAndroid Build Coastguard Worker copyright_pattern = ( 120*c8dee2aaSAndroid Build Coastguard Worker r'Copyright (\([cC]\) )?%s \w+' % years_pattern) 121*c8dee2aaSAndroid Build Coastguard Worker 122*c8dee2aaSAndroid Build Coastguard Worker for affected_file in input_api.AffectedSourceFiles(source_file_filter): 123*c8dee2aaSAndroid Build Coastguard Worker if ('third_party/' in affected_file.LocalPath() or 124*c8dee2aaSAndroid Build Coastguard Worker 'tests/sksl/' in affected_file.LocalPath() or 125*c8dee2aaSAndroid Build Coastguard Worker 'bazel/rbe/' in affected_file.LocalPath() or 126*c8dee2aaSAndroid Build Coastguard Worker 'bazel/external/' in affected_file.LocalPath() or 127*c8dee2aaSAndroid Build Coastguard Worker 'bazel/exporter/interfaces/mocks/' in affected_file.LocalPath() or 128*c8dee2aaSAndroid Build Coastguard Worker affected_file.LocalPath().endswith('gen.go')): 129*c8dee2aaSAndroid Build Coastguard Worker continue 130*c8dee2aaSAndroid Build Coastguard Worker contents = input_api.ReadFile(affected_file, 'rb') 131*c8dee2aaSAndroid Build Coastguard Worker if not re.search(copyright_pattern, contents): 132*c8dee2aaSAndroid Build Coastguard Worker results.append(output_api.PresubmitError( 133*c8dee2aaSAndroid Build Coastguard Worker '%s is missing a correct copyright header.' % affected_file)) 134*c8dee2aaSAndroid Build Coastguard Worker return results 135*c8dee2aaSAndroid Build Coastguard Worker 136*c8dee2aaSAndroid Build Coastguard Worker 137*c8dee2aaSAndroid Build Coastguard Workerdef _InfraTests(input_api, output_api): 138*c8dee2aaSAndroid Build Coastguard Worker """Run the infra tests.""" 139*c8dee2aaSAndroid Build Coastguard Worker results = [] 140*c8dee2aaSAndroid Build Coastguard Worker if not any(f.LocalPath().startswith('infra') 141*c8dee2aaSAndroid Build Coastguard Worker for f in input_api.AffectedFiles()): 142*c8dee2aaSAndroid Build Coastguard Worker return results 143*c8dee2aaSAndroid Build Coastguard Worker 144*c8dee2aaSAndroid Build Coastguard Worker cmd = ['python3', os.path.join('infra', 'bots', 'infra_tests.py')] 145*c8dee2aaSAndroid Build Coastguard Worker try: 146*c8dee2aaSAndroid Build Coastguard Worker subprocess.check_output(cmd) 147*c8dee2aaSAndroid Build Coastguard Worker except subprocess.CalledProcessError as e: 148*c8dee2aaSAndroid Build Coastguard Worker results.append(output_api.PresubmitError( 149*c8dee2aaSAndroid Build Coastguard Worker '`%s` failed:\n%s' % (' '.join(cmd), e.output))) 150*c8dee2aaSAndroid Build Coastguard Worker return results 151*c8dee2aaSAndroid Build Coastguard Worker 152*c8dee2aaSAndroid Build Coastguard Worker 153*c8dee2aaSAndroid Build Coastguard Workerdef _CheckGNFormatted(input_api, output_api): 154*c8dee2aaSAndroid Build Coastguard Worker """Make sure any .gn files we're changing have been formatted.""" 155*c8dee2aaSAndroid Build Coastguard Worker files = [] 156*c8dee2aaSAndroid Build Coastguard Worker for f in input_api.AffectedFiles(include_deletes=False): 157*c8dee2aaSAndroid Build Coastguard Worker if (f.LocalPath().endswith('.gn') or 158*c8dee2aaSAndroid Build Coastguard Worker f.LocalPath().endswith('.gni')): 159*c8dee2aaSAndroid Build Coastguard Worker files.append(f) 160*c8dee2aaSAndroid Build Coastguard Worker if not files: 161*c8dee2aaSAndroid Build Coastguard Worker return [] 162*c8dee2aaSAndroid Build Coastguard Worker 163*c8dee2aaSAndroid Build Coastguard Worker cmd = ['python3', os.path.join('bin', 'fetch-gn')] 164*c8dee2aaSAndroid Build Coastguard Worker try: 165*c8dee2aaSAndroid Build Coastguard Worker subprocess.check_output(cmd) 166*c8dee2aaSAndroid Build Coastguard Worker except subprocess.CalledProcessError as e: 167*c8dee2aaSAndroid Build Coastguard Worker return [output_api.PresubmitError( 168*c8dee2aaSAndroid Build Coastguard Worker '`%s` failed:\n%s' % (' '.join(cmd), e.output))] 169*c8dee2aaSAndroid Build Coastguard Worker 170*c8dee2aaSAndroid Build Coastguard Worker results = [] 171*c8dee2aaSAndroid Build Coastguard Worker for f in files: 172*c8dee2aaSAndroid Build Coastguard Worker gn = 'gn.exe' if 'win32' in sys.platform else 'gn' 173*c8dee2aaSAndroid Build Coastguard Worker gn = os.path.join(input_api.PresubmitLocalPath(), 'bin', gn) 174*c8dee2aaSAndroid Build Coastguard Worker cmd = [gn, 'format', '--dry-run', f.LocalPath()] 175*c8dee2aaSAndroid Build Coastguard Worker try: 176*c8dee2aaSAndroid Build Coastguard Worker subprocess.check_output(cmd) 177*c8dee2aaSAndroid Build Coastguard Worker except subprocess.CalledProcessError: 178*c8dee2aaSAndroid Build Coastguard Worker fix = 'bin/gn format ' + f.LocalPath() 179*c8dee2aaSAndroid Build Coastguard Worker results.append(output_api.PresubmitError( 180*c8dee2aaSAndroid Build Coastguard Worker '`%s` failed, try\n\t%s' % (' '.join(cmd), fix))) 181*c8dee2aaSAndroid Build Coastguard Worker return results 182*c8dee2aaSAndroid Build Coastguard Worker 183*c8dee2aaSAndroid Build Coastguard Worker 184*c8dee2aaSAndroid Build Coastguard Workerdef _CheckGitConflictMarkers(input_api, output_api): 185*c8dee2aaSAndroid Build Coastguard Worker pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$') 186*c8dee2aaSAndroid Build Coastguard Worker results = [] 187*c8dee2aaSAndroid Build Coastguard Worker for f in input_api.AffectedFiles(): 188*c8dee2aaSAndroid Build Coastguard Worker for line_num, line in f.ChangedContents(): 189*c8dee2aaSAndroid Build Coastguard Worker if f.LocalPath().endswith('.md'): 190*c8dee2aaSAndroid Build Coastguard Worker # First-level headers in markdown look a lot like version control 191*c8dee2aaSAndroid Build Coastguard Worker # conflict markers. http://daringfireball.net/projects/markdown/basics 192*c8dee2aaSAndroid Build Coastguard Worker continue 193*c8dee2aaSAndroid Build Coastguard Worker if pattern.match(line): 194*c8dee2aaSAndroid Build Coastguard Worker results.append( 195*c8dee2aaSAndroid Build Coastguard Worker output_api.PresubmitError( 196*c8dee2aaSAndroid Build Coastguard Worker 'Git conflict markers found in %s:%d %s' % ( 197*c8dee2aaSAndroid Build Coastguard Worker f.LocalPath(), line_num, line))) 198*c8dee2aaSAndroid Build Coastguard Worker return results 199*c8dee2aaSAndroid Build Coastguard Worker 200*c8dee2aaSAndroid Build Coastguard Worker 201*c8dee2aaSAndroid Build Coastguard Workerdef _CheckIncludesFormatted(input_api, output_api): 202*c8dee2aaSAndroid Build Coastguard Worker """Make sure #includes in files we're changing have been formatted.""" 203*c8dee2aaSAndroid Build Coastguard Worker files = [str(f) for f in input_api.AffectedFiles() if f.Action() != 'D'] 204*c8dee2aaSAndroid Build Coastguard Worker cmd = ['python3', 205*c8dee2aaSAndroid Build Coastguard Worker 'tools/rewrite_includes.py', 206*c8dee2aaSAndroid Build Coastguard Worker '--dry-run'] + files 207*c8dee2aaSAndroid Build Coastguard Worker if 0 != subprocess.call(cmd): 208*c8dee2aaSAndroid Build Coastguard Worker return [output_api.PresubmitError('`%s` failed' % ' '.join(cmd))] 209*c8dee2aaSAndroid Build Coastguard Worker return [] 210*c8dee2aaSAndroid Build Coastguard Worker 211*c8dee2aaSAndroid Build Coastguard Worker 212*c8dee2aaSAndroid Build Coastguard Workerclass _WarningsAsErrors(): 213*c8dee2aaSAndroid Build Coastguard Worker def __init__(self, output_api): 214*c8dee2aaSAndroid Build Coastguard Worker self.output_api = output_api 215*c8dee2aaSAndroid Build Coastguard Worker self.old_warning = None 216*c8dee2aaSAndroid Build Coastguard Worker def __enter__(self): 217*c8dee2aaSAndroid Build Coastguard Worker self.old_warning = self.output_api.PresubmitPromptWarning 218*c8dee2aaSAndroid Build Coastguard Worker self.output_api.PresubmitPromptWarning = self.output_api.PresubmitError 219*c8dee2aaSAndroid Build Coastguard Worker return self.output_api 220*c8dee2aaSAndroid Build Coastguard Worker def __exit__(self, ex_type, ex_value, ex_traceback): 221*c8dee2aaSAndroid Build Coastguard Worker self.output_api.PresubmitPromptWarning = self.old_warning 222*c8dee2aaSAndroid Build Coastguard Worker 223*c8dee2aaSAndroid Build Coastguard Worker 224*c8dee2aaSAndroid Build Coastguard Workerdef _RegenerateAllExamplesCPP(input_api, output_api): 225*c8dee2aaSAndroid Build Coastguard Worker """Regenerates all_examples.cpp if an example was added or deleted.""" 226*c8dee2aaSAndroid Build Coastguard Worker if not any(f.LocalPath().startswith('docs/examples/') 227*c8dee2aaSAndroid Build Coastguard Worker for f in input_api.AffectedFiles()): 228*c8dee2aaSAndroid Build Coastguard Worker return [] 229*c8dee2aaSAndroid Build Coastguard Worker command_str = 'tools/fiddle/make_all_examples_cpp.py' 230*c8dee2aaSAndroid Build Coastguard Worker cmd = ['python3', command_str, '--print-diff'] 231*c8dee2aaSAndroid Build Coastguard Worker proc = subprocess.run(cmd, capture_output=True) 232*c8dee2aaSAndroid Build Coastguard Worker if proc.returncode != 0: 233*c8dee2aaSAndroid Build Coastguard Worker return [output_api.PresubmitError('`%s` failed' % ' '.join(cmd))] 234*c8dee2aaSAndroid Build Coastguard Worker 235*c8dee2aaSAndroid Build Coastguard Worker results = [] 236*c8dee2aaSAndroid Build Coastguard Worker diff_output = proc.stdout.decode('utf-8').strip() 237*c8dee2aaSAndroid Build Coastguard Worker if diff_output: 238*c8dee2aaSAndroid Build Coastguard Worker results += [output_api.PresubmitError( 239*c8dee2aaSAndroid Build Coastguard Worker 'Diffs found after running "%s":\n\n%s\n' 240*c8dee2aaSAndroid Build Coastguard Worker 'Please commit or discard the above changes.' % ( 241*c8dee2aaSAndroid Build Coastguard Worker command_str, 242*c8dee2aaSAndroid Build Coastguard Worker diff_output, 243*c8dee2aaSAndroid Build Coastguard Worker ) 244*c8dee2aaSAndroid Build Coastguard Worker )] 245*c8dee2aaSAndroid Build Coastguard Worker return results 246*c8dee2aaSAndroid Build Coastguard Worker 247*c8dee2aaSAndroid Build Coastguard Worker 248*c8dee2aaSAndroid Build Coastguard Workerdef _CheckIncludeForOutsideDeps(input_api, output_api): 249*c8dee2aaSAndroid Build Coastguard Worker """The include directory should consist of only public APIs. 250*c8dee2aaSAndroid Build Coastguard Worker 251*c8dee2aaSAndroid Build Coastguard Worker This check makes sure we don't have anything in the include directory 252*c8dee2aaSAndroid Build Coastguard Worker depend on outside folders. If we had include/core/SkDonut.h depend on 253*c8dee2aaSAndroid Build Coastguard Worker src/core/SkPastry.h, then clients would have transitive access to the 254*c8dee2aaSAndroid Build Coastguard Worker private SkPastry class and any symbols in there, even if they don't 255*c8dee2aaSAndroid Build Coastguard Worker directly include src/core/SkPastry.h (which can be detected/blocked 256*c8dee2aaSAndroid Build Coastguard Worker with build systems like GN or Bazel). By keeping include/ self-contained, 257*c8dee2aaSAndroid Build Coastguard Worker we keep a tighter grip on our public API and make Skia easier to distribute 258*c8dee2aaSAndroid Build Coastguard Worker (one can ship a .a/.so and a single directory of .h files). 259*c8dee2aaSAndroid Build Coastguard Worker """ 260*c8dee2aaSAndroid Build Coastguard Worker banned_includes = [ 261*c8dee2aaSAndroid Build Coastguard Worker input_api.re.compile(r'#\s*include\s+("src/.*)'), 262*c8dee2aaSAndroid Build Coastguard Worker input_api.re.compile(r'#\s*include\s+("tools/.*)'), 263*c8dee2aaSAndroid Build Coastguard Worker ] 264*c8dee2aaSAndroid Build Coastguard Worker file_filter = lambda x: (x.LocalPath().startswith('include/')) 265*c8dee2aaSAndroid Build Coastguard Worker errors = [] 266*c8dee2aaSAndroid Build Coastguard Worker for affected_file in input_api.AffectedSourceFiles(file_filter): 267*c8dee2aaSAndroid Build Coastguard Worker affected_filepath = affected_file.LocalPath() 268*c8dee2aaSAndroid Build Coastguard Worker for (line_num, line) in affected_file.ChangedContents(): 269*c8dee2aaSAndroid Build Coastguard Worker for re in banned_includes: 270*c8dee2aaSAndroid Build Coastguard Worker match = re.search(line) 271*c8dee2aaSAndroid Build Coastguard Worker if match: 272*c8dee2aaSAndroid Build Coastguard Worker errors.append(('%s:%s: include/* should only depend on other things in include/*. ' + 273*c8dee2aaSAndroid Build Coastguard Worker 'Please remove #include of %s, perhaps making it a forward-declare.') % ( 274*c8dee2aaSAndroid Build Coastguard Worker affected_filepath, line_num, match.group(1))) 275*c8dee2aaSAndroid Build Coastguard Worker 276*c8dee2aaSAndroid Build Coastguard Worker if errors: 277*c8dee2aaSAndroid Build Coastguard Worker return [output_api.PresubmitError('\n'.join(errors))] 278*c8dee2aaSAndroid Build Coastguard Worker return [] 279*c8dee2aaSAndroid Build Coastguard Worker 280*c8dee2aaSAndroid Build Coastguard Worker 281*c8dee2aaSAndroid Build Coastguard Workerdef _CheckExamplesForPrivateAPIs(input_api, output_api): 282*c8dee2aaSAndroid Build Coastguard Worker """We only want our checked-in examples (aka fiddles) to show public API.""" 283*c8dee2aaSAndroid Build Coastguard Worker banned_includes = [ 284*c8dee2aaSAndroid Build Coastguard Worker input_api.re.compile(r'#\s*include\s+("src/.*)'), 285*c8dee2aaSAndroid Build Coastguard Worker input_api.re.compile(r'#\s*include\s+("include/private/.*)'), 286*c8dee2aaSAndroid Build Coastguard Worker ] 287*c8dee2aaSAndroid Build Coastguard Worker file_filter = lambda x: (x.LocalPath().startswith('docs/examples/')) 288*c8dee2aaSAndroid Build Coastguard Worker errors = [] 289*c8dee2aaSAndroid Build Coastguard Worker for affected_file in input_api.AffectedSourceFiles(file_filter): 290*c8dee2aaSAndroid Build Coastguard Worker affected_filepath = affected_file.LocalPath() 291*c8dee2aaSAndroid Build Coastguard Worker for (line_num, line) in affected_file.ChangedContents(): 292*c8dee2aaSAndroid Build Coastguard Worker for re in banned_includes: 293*c8dee2aaSAndroid Build Coastguard Worker match = re.search(line) 294*c8dee2aaSAndroid Build Coastguard Worker if match: 295*c8dee2aaSAndroid Build Coastguard Worker errors.append('%s:%s: Fiddles should not use private/internal API like %s.' % ( 296*c8dee2aaSAndroid Build Coastguard Worker affected_filepath, line_num, match.group(1))) 297*c8dee2aaSAndroid Build Coastguard Worker 298*c8dee2aaSAndroid Build Coastguard Worker if errors: 299*c8dee2aaSAndroid Build Coastguard Worker return [output_api.PresubmitError('\n'.join(errors))] 300*c8dee2aaSAndroid Build Coastguard Worker return [] 301*c8dee2aaSAndroid Build Coastguard Worker 302*c8dee2aaSAndroid Build Coastguard Worker 303*c8dee2aaSAndroid Build Coastguard Workerdef _CheckGeneratedBazelBUILDFiles(input_api, output_api): 304*c8dee2aaSAndroid Build Coastguard Worker if 'win32' in sys.platform: 305*c8dee2aaSAndroid Build Coastguard Worker # TODO(crbug.com/skia/12541): Remove when Bazel builds work on Windows. 306*c8dee2aaSAndroid Build Coastguard Worker # Note: `make` is not installed on Windows by default. 307*c8dee2aaSAndroid Build Coastguard Worker return [] 308*c8dee2aaSAndroid Build Coastguard Worker if 'darwin' in sys.platform: 309*c8dee2aaSAndroid Build Coastguard Worker # This takes too long on Mac with default settings. Probably due to sandboxing. 310*c8dee2aaSAndroid Build Coastguard Worker return [] 311*c8dee2aaSAndroid Build Coastguard Worker files = [] 312*c8dee2aaSAndroid Build Coastguard Worker for affected_file in input_api.AffectedFiles(include_deletes=True): 313*c8dee2aaSAndroid Build Coastguard Worker affected_file_path = affected_file.LocalPath() 314*c8dee2aaSAndroid Build Coastguard Worker if (affected_file_path.endswith('.go') or 315*c8dee2aaSAndroid Build Coastguard Worker affected_file_path.endswith('BUILD.bazel')): 316*c8dee2aaSAndroid Build Coastguard Worker files.append(affected_file) 317*c8dee2aaSAndroid Build Coastguard Worker if not files: 318*c8dee2aaSAndroid Build Coastguard Worker return [] 319*c8dee2aaSAndroid Build Coastguard Worker return _RunCommandAndCheckDiff( 320*c8dee2aaSAndroid Build Coastguard Worker output_api, ['make', '-C', 'bazel', 'generate_go'], files 321*c8dee2aaSAndroid Build Coastguard Worker ) 322*c8dee2aaSAndroid Build Coastguard Worker 323*c8dee2aaSAndroid Build Coastguard Worker 324*c8dee2aaSAndroid Build Coastguard Workerdef _CheckBazelBUILDFiles(input_api, output_api): 325*c8dee2aaSAndroid Build Coastguard Worker """Makes sure our BUILD.bazel files are compatible with G3.""" 326*c8dee2aaSAndroid Build Coastguard Worker results = [] 327*c8dee2aaSAndroid Build Coastguard Worker for affected_file in input_api.AffectedFiles(include_deletes=False): 328*c8dee2aaSAndroid Build Coastguard Worker affected_file_path = affected_file.LocalPath() 329*c8dee2aaSAndroid Build Coastguard Worker is_bazel = affected_file_path.endswith('BUILD.bazel') 330*c8dee2aaSAndroid Build Coastguard Worker # This list lines up with the one in autoroller_lib.py (see G3). 331*c8dee2aaSAndroid Build Coastguard Worker excluded_paths = ["infra/", "bazel/rbe/", "bazel/external/", "bazel/common_config_settings/", 332*c8dee2aaSAndroid Build Coastguard Worker "modules/canvaskit/go/", "experimental/", "bazel/platform", "third_party/", 333*c8dee2aaSAndroid Build Coastguard Worker "tests/", "resources/", "bazel/deps_parser/", "bazel/exporter_tool/", 334*c8dee2aaSAndroid Build Coastguard Worker "tools/gpu/gl/interface/", "bazel/utils/", "include/config/", 335*c8dee2aaSAndroid Build Coastguard Worker "bench/", "example/external_client/"] 336*c8dee2aaSAndroid Build Coastguard Worker is_excluded = any(affected_file_path.startswith(n) for n in excluded_paths) 337*c8dee2aaSAndroid Build Coastguard Worker if is_bazel and not is_excluded: 338*c8dee2aaSAndroid Build Coastguard Worker with open(affected_file_path, 'r') as file: 339*c8dee2aaSAndroid Build Coastguard Worker contents = file.read() 340*c8dee2aaSAndroid Build Coastguard Worker if 'licenses(["notice"])' not in contents: 341*c8dee2aaSAndroid Build Coastguard Worker results.append(output_api.PresubmitError( 342*c8dee2aaSAndroid Build Coastguard Worker ('%s needs to have\nlicenses(["notice"])\nimmediately after ' + 343*c8dee2aaSAndroid Build Coastguard Worker 'the load() calls to comply with G3 policies.') % affected_file_path 344*c8dee2aaSAndroid Build Coastguard Worker )) 345*c8dee2aaSAndroid Build Coastguard Worker if 'cc_library(' in contents and '"skia_cc_library"' not in contents: 346*c8dee2aaSAndroid Build Coastguard Worker results.append(output_api.PresubmitError( 347*c8dee2aaSAndroid Build Coastguard Worker ('%s needs to load skia_cc_library from macros.bzl instead of using the ' + 348*c8dee2aaSAndroid Build Coastguard Worker 'native one. This allows us to build differently for G3.\n' + 349*c8dee2aaSAndroid Build Coastguard Worker 'Add "skia_cc_library" to load("//bazel:macros.bzl", ...)') 350*c8dee2aaSAndroid Build Coastguard Worker % affected_file_path 351*c8dee2aaSAndroid Build Coastguard Worker )) 352*c8dee2aaSAndroid Build Coastguard Worker if 'default_applicable_licenses' not in contents: 353*c8dee2aaSAndroid Build Coastguard Worker # See https://opensource.google/documentation/reference/thirdparty/new_license_rules 354*c8dee2aaSAndroid Build Coastguard Worker results.append(output_api.PresubmitError( 355*c8dee2aaSAndroid Build Coastguard Worker ('%s needs to have\npackage(default_applicable_licenses = ["//:license"])\n'+ 356*c8dee2aaSAndroid Build Coastguard Worker 'to comply with G3 policies') % affected_file_path 357*c8dee2aaSAndroid Build Coastguard Worker )) 358*c8dee2aaSAndroid Build Coastguard Worker return results 359*c8dee2aaSAndroid Build Coastguard Worker 360*c8dee2aaSAndroid Build Coastguard Worker 361*c8dee2aaSAndroid Build Coastguard Workerdef _RunCommandAndCheckDiff(output_api, command, files_to_check): 362*c8dee2aaSAndroid Build Coastguard Worker """Run an arbitrary command. Fail if it produces any diffs on the given files.""" 363*c8dee2aaSAndroid Build Coastguard Worker prev_contents = {} 364*c8dee2aaSAndroid Build Coastguard Worker for file in files_to_check: 365*c8dee2aaSAndroid Build Coastguard Worker # NewContents just reads the file. 366*c8dee2aaSAndroid Build Coastguard Worker prev_contents[file] = file.NewContents() 367*c8dee2aaSAndroid Build Coastguard Worker 368*c8dee2aaSAndroid Build Coastguard Worker command_str = ' '.join(command) 369*c8dee2aaSAndroid Build Coastguard Worker results = [] 370*c8dee2aaSAndroid Build Coastguard Worker 371*c8dee2aaSAndroid Build Coastguard Worker try: 372*c8dee2aaSAndroid Build Coastguard Worker subprocess.check_output( 373*c8dee2aaSAndroid Build Coastguard Worker command, 374*c8dee2aaSAndroid Build Coastguard Worker stderr=subprocess.STDOUT, encoding='utf-8') 375*c8dee2aaSAndroid Build Coastguard Worker except subprocess.CalledProcessError as e: 376*c8dee2aaSAndroid Build Coastguard Worker results += [output_api.PresubmitError( 377*c8dee2aaSAndroid Build Coastguard Worker 'Command "%s" returned non-zero exit code %d. Output: \n\n%s' % ( 378*c8dee2aaSAndroid Build Coastguard Worker command_str, 379*c8dee2aaSAndroid Build Coastguard Worker e.returncode, 380*c8dee2aaSAndroid Build Coastguard Worker e.output, 381*c8dee2aaSAndroid Build Coastguard Worker ) 382*c8dee2aaSAndroid Build Coastguard Worker )] 383*c8dee2aaSAndroid Build Coastguard Worker 384*c8dee2aaSAndroid Build Coastguard Worker # Compare the new content to the previous content. 385*c8dee2aaSAndroid Build Coastguard Worker diffs = [] 386*c8dee2aaSAndroid Build Coastguard Worker for file, prev_content in prev_contents.items(): 387*c8dee2aaSAndroid Build Coastguard Worker new_content = file.NewContents(flush_cache=True) 388*c8dee2aaSAndroid Build Coastguard Worker if new_content != prev_content: 389*c8dee2aaSAndroid Build Coastguard Worker path = file.LocalPath() 390*c8dee2aaSAndroid Build Coastguard Worker diff = difflib.unified_diff(prev_content, new_content, path, path, lineterm='') 391*c8dee2aaSAndroid Build Coastguard Worker diffs.append('\n'.join(diff)) 392*c8dee2aaSAndroid Build Coastguard Worker 393*c8dee2aaSAndroid Build Coastguard Worker if diffs: 394*c8dee2aaSAndroid Build Coastguard Worker results += [output_api.PresubmitError( 395*c8dee2aaSAndroid Build Coastguard Worker 'Diffs found after running "%s":\n\n%s\n\n' 396*c8dee2aaSAndroid Build Coastguard Worker 'Please commit or discard the above changes.' % ( 397*c8dee2aaSAndroid Build Coastguard Worker command_str, 398*c8dee2aaSAndroid Build Coastguard Worker '\n'.join(diffs), 399*c8dee2aaSAndroid Build Coastguard Worker ) 400*c8dee2aaSAndroid Build Coastguard Worker )] 401*c8dee2aaSAndroid Build Coastguard Worker 402*c8dee2aaSAndroid Build Coastguard Worker return results 403*c8dee2aaSAndroid Build Coastguard Worker 404*c8dee2aaSAndroid Build Coastguard Worker 405*c8dee2aaSAndroid Build Coastguard Workerdef _CheckGNIGenerated(input_api, output_api): 406*c8dee2aaSAndroid Build Coastguard Worker """Ensures that the generated *.gni files are current. 407*c8dee2aaSAndroid Build Coastguard Worker 408*c8dee2aaSAndroid Build Coastguard Worker The Bazel project files are authoritative and some *.gni files are 409*c8dee2aaSAndroid Build Coastguard Worker generated from them using the exporter_tool. This check ensures they 410*c8dee2aaSAndroid Build Coastguard Worker are still current. 411*c8dee2aaSAndroid Build Coastguard Worker """ 412*c8dee2aaSAndroid Build Coastguard Worker if 'win32' in sys.platform: 413*c8dee2aaSAndroid Build Coastguard Worker # TODO(crbug.com/skia/12541): Remove when Bazel builds work on Windows. 414*c8dee2aaSAndroid Build Coastguard Worker # Note: `make` is not installed on Windows by default. 415*c8dee2aaSAndroid Build Coastguard Worker return [ 416*c8dee2aaSAndroid Build Coastguard Worker output_api.PresubmitNotifyResult( 417*c8dee2aaSAndroid Build Coastguard Worker 'Skipping Bazel=>GNI export check on Windows (unsupported platform).' 418*c8dee2aaSAndroid Build Coastguard Worker ) 419*c8dee2aaSAndroid Build Coastguard Worker ] 420*c8dee2aaSAndroid Build Coastguard Worker if 'darwin' in sys.platform: 421*c8dee2aaSAndroid Build Coastguard Worker # This takes too long on Mac with default settings. Probably due to sandboxing. 422*c8dee2aaSAndroid Build Coastguard Worker return [] 423*c8dee2aaSAndroid Build Coastguard Worker files = [] 424*c8dee2aaSAndroid Build Coastguard Worker for affected_file in input_api.AffectedFiles(include_deletes=True): 425*c8dee2aaSAndroid Build Coastguard Worker affected_file_path = affected_file.LocalPath() 426*c8dee2aaSAndroid Build Coastguard Worker if affected_file_path.endswith('BUILD.bazel') or affected_file_path.endswith('.gni'): 427*c8dee2aaSAndroid Build Coastguard Worker files.append(affected_file) 428*c8dee2aaSAndroid Build Coastguard Worker # Generate GNI files and verify no changes. 429*c8dee2aaSAndroid Build Coastguard Worker if not files: 430*c8dee2aaSAndroid Build Coastguard Worker # No Bazel build files changed. 431*c8dee2aaSAndroid Build Coastguard Worker return [] 432*c8dee2aaSAndroid Build Coastguard Worker return _RunCommandAndCheckDiff( 433*c8dee2aaSAndroid Build Coastguard Worker output_api, ['make', '-C', 'bazel', 'generate_gni'], files 434*c8dee2aaSAndroid Build Coastguard Worker ) 435*c8dee2aaSAndroid Build Coastguard Worker 436*c8dee2aaSAndroid Build Coastguard Worker 437*c8dee2aaSAndroid Build Coastguard Workerdef _CheckBuildifier(input_api, output_api): 438*c8dee2aaSAndroid Build Coastguard Worker """Runs Buildifier and fails on linting errors, or if it produces any diffs. 439*c8dee2aaSAndroid Build Coastguard Worker 440*c8dee2aaSAndroid Build Coastguard Worker This check only runs if the affected files include any WORKSPACE, BUILD, 441*c8dee2aaSAndroid Build Coastguard Worker BUILD.bazel or *.bzl files. 442*c8dee2aaSAndroid Build Coastguard Worker """ 443*c8dee2aaSAndroid Build Coastguard Worker files = [] 444*c8dee2aaSAndroid Build Coastguard Worker # Please keep the below exclude patterns in sync with those in the //:buildifier rule definition. 445*c8dee2aaSAndroid Build Coastguard Worker for affected_file in input_api.AffectedFiles(include_deletes=False): 446*c8dee2aaSAndroid Build Coastguard Worker affected_file_path = affected_file.LocalPath() 447*c8dee2aaSAndroid Build Coastguard Worker if affected_file_path.endswith('BUILD.bazel') or affected_file_path.endswith('.bzl'): 448*c8dee2aaSAndroid Build Coastguard Worker if not affected_file_path.endswith('public.bzl') and \ 449*c8dee2aaSAndroid Build Coastguard Worker not affected_file_path.endswith('go_repositories.bzl') and \ 450*c8dee2aaSAndroid Build Coastguard Worker not "bazel/rbe/gce_linux/" in affected_file_path and \ 451*c8dee2aaSAndroid Build Coastguard Worker not affected_file_path.startswith("third_party/externals/") and \ 452*c8dee2aaSAndroid Build Coastguard Worker not "node_modules/" in affected_file_path: # Skip generated files. 453*c8dee2aaSAndroid Build Coastguard Worker files.append(affected_file) 454*c8dee2aaSAndroid Build Coastguard Worker if not files: 455*c8dee2aaSAndroid Build Coastguard Worker return [] 456*c8dee2aaSAndroid Build Coastguard Worker try: 457*c8dee2aaSAndroid Build Coastguard Worker subprocess.check_output( 458*c8dee2aaSAndroid Build Coastguard Worker ['buildifier', '--version'], 459*c8dee2aaSAndroid Build Coastguard Worker stderr=subprocess.STDOUT) 460*c8dee2aaSAndroid Build Coastguard Worker except: 461*c8dee2aaSAndroid Build Coastguard Worker return [output_api.PresubmitNotifyResult( 462*c8dee2aaSAndroid Build Coastguard Worker 'Skipping buildifier check because it is not on PATH. \n' + 463*c8dee2aaSAndroid Build Coastguard Worker 'You can download it from https://github.com/bazelbuild/buildtools/releases')] 464*c8dee2aaSAndroid Build Coastguard Worker 465*c8dee2aaSAndroid Build Coastguard Worker return _RunCommandAndCheckDiff( 466*c8dee2aaSAndroid Build Coastguard Worker # Please keep the below arguments in sync with those in the //:buildifier rule definition. 467*c8dee2aaSAndroid Build Coastguard Worker output_api, [ 468*c8dee2aaSAndroid Build Coastguard Worker 'buildifier', 469*c8dee2aaSAndroid Build Coastguard Worker '--mode=fix', 470*c8dee2aaSAndroid Build Coastguard Worker '--lint=fix', 471*c8dee2aaSAndroid Build Coastguard Worker '--warnings', 472*c8dee2aaSAndroid Build Coastguard Worker ','.join([ 473*c8dee2aaSAndroid Build Coastguard Worker '-native-android', 474*c8dee2aaSAndroid Build Coastguard Worker '-native-cc', 475*c8dee2aaSAndroid Build Coastguard Worker '-native-py', 476*c8dee2aaSAndroid Build Coastguard Worker ]) 477*c8dee2aaSAndroid Build Coastguard Worker ] + [f.LocalPath() for f in files], files) 478*c8dee2aaSAndroid Build Coastguard Worker 479*c8dee2aaSAndroid Build Coastguard Worker 480*c8dee2aaSAndroid Build Coastguard Workerdef _CheckBannedAPIs(input_api, output_api): 481*c8dee2aaSAndroid Build Coastguard Worker """Check source code for functions, packages, and symbols that should not be used.""" 482*c8dee2aaSAndroid Build Coastguard Worker 483*c8dee2aaSAndroid Build Coastguard Worker # A list of tuples of a regex to match an API and a suggested replacement for 484*c8dee2aaSAndroid Build Coastguard Worker # that API. There is an optional third parameter for files which *can* use this 485*c8dee2aaSAndroid Build Coastguard Worker # API without warning. 486*c8dee2aaSAndroid Build Coastguard Worker banned_replacements = [ 487*c8dee2aaSAndroid Build Coastguard Worker (r'std::stof\(', 'std::strtof(), which does not throw'), 488*c8dee2aaSAndroid Build Coastguard Worker (r'std::stod\(', 'std::strtod(), which does not throw'), 489*c8dee2aaSAndroid Build Coastguard Worker (r'std::stold\(', 'std::strtold(), which does not throw'), 490*c8dee2aaSAndroid Build Coastguard Worker 491*c8dee2aaSAndroid Build Coastguard Worker # We used to have separate symbols for this, but coalesced them to make the 492*c8dee2aaSAndroid Build Coastguard Worker # Bazel build easier. 493*c8dee2aaSAndroid Build Coastguard Worker (r'GR_TEST_UTILS', 'GPU_TEST_UTILS'), 494*c8dee2aaSAndroid Build Coastguard Worker (r'GRAPHITE_TEST_UTILS', 'GPU_TEST_UTILS'), 495*c8dee2aaSAndroid Build Coastguard Worker ] 496*c8dee2aaSAndroid Build Coastguard Worker 497*c8dee2aaSAndroid Build Coastguard Worker # Our Bazel rules have special copies of our cc_library rules with GPU_TEST_UTILS 498*c8dee2aaSAndroid Build Coastguard Worker # set. If GPU_TEST_UTILS is used outside of those files in Skia proper, the build 499*c8dee2aaSAndroid Build Coastguard Worker # will break/crash in mysterious ways (because files may get compiled in multiple 500*c8dee2aaSAndroid Build Coastguard Worker # conflicting ways as a result of the define being inconsistently set). 501*c8dee2aaSAndroid Build Coastguard Worker allowed_test_util_paths = [ 502*c8dee2aaSAndroid Build Coastguard Worker 'include/core/SkTypes.h', 503*c8dee2aaSAndroid Build Coastguard Worker 'include/gpu/', 504*c8dee2aaSAndroid Build Coastguard Worker 'include/private/gpu/', 505*c8dee2aaSAndroid Build Coastguard Worker 'src/gpu/ganesh', 506*c8dee2aaSAndroid Build Coastguard Worker 'src/gpu/graphite', 507*c8dee2aaSAndroid Build Coastguard Worker 'tests/', 508*c8dee2aaSAndroid Build Coastguard Worker 'tools/', 509*c8dee2aaSAndroid Build Coastguard Worker ] 510*c8dee2aaSAndroid Build Coastguard Worker gpu_test_utils_re = input_api.re.compile('GPU_TEST_UTILS') 511*c8dee2aaSAndroid Build Coastguard Worker 512*c8dee2aaSAndroid Build Coastguard Worker # These defines are either there or not, and using them with just an #if is a 513*c8dee2aaSAndroid Build Coastguard Worker # subtle, frustrating bug. 514*c8dee2aaSAndroid Build Coastguard Worker existence_defines = ['SK_GANESH', 'SK_GRAPHITE', 'SK_GL', 'SK_VULKAN', 'SK_DAWN', 'SK_METAL', 515*c8dee2aaSAndroid Build Coastguard Worker 'SK_DIRECT3D', 'SK_DEBUG', 'GPU_TEST_UTILS'] 516*c8dee2aaSAndroid Build Coastguard Worker for d in existence_defines: 517*c8dee2aaSAndroid Build Coastguard Worker banned_replacements.append(('#if {}'.format(d), 518*c8dee2aaSAndroid Build Coastguard Worker '#if defined({})'.format(d))) 519*c8dee2aaSAndroid Build Coastguard Worker compiled_replacements = [] 520*c8dee2aaSAndroid Build Coastguard Worker for rep in banned_replacements: 521*c8dee2aaSAndroid Build Coastguard Worker exceptions = [] 522*c8dee2aaSAndroid Build Coastguard Worker if len(rep) == 3: 523*c8dee2aaSAndroid Build Coastguard Worker (re, replacement, exceptions) = rep 524*c8dee2aaSAndroid Build Coastguard Worker else: 525*c8dee2aaSAndroid Build Coastguard Worker (re, replacement) = rep 526*c8dee2aaSAndroid Build Coastguard Worker 527*c8dee2aaSAndroid Build Coastguard Worker compiled_re = input_api.re.compile(re) 528*c8dee2aaSAndroid Build Coastguard Worker compiled_exceptions = [input_api.re.compile(exc) for exc in exceptions] 529*c8dee2aaSAndroid Build Coastguard Worker compiled_replacements.append( 530*c8dee2aaSAndroid Build Coastguard Worker (compiled_re, replacement, compiled_exceptions)) 531*c8dee2aaSAndroid Build Coastguard Worker 532*c8dee2aaSAndroid Build Coastguard Worker errors = [] 533*c8dee2aaSAndroid Build Coastguard Worker file_filter = lambda x: (x.LocalPath().endswith('.h') or 534*c8dee2aaSAndroid Build Coastguard Worker x.LocalPath().endswith('.cpp') or 535*c8dee2aaSAndroid Build Coastguard Worker x.LocalPath().endswith('.cc') or 536*c8dee2aaSAndroid Build Coastguard Worker x.LocalPath().endswith('.m') or 537*c8dee2aaSAndroid Build Coastguard Worker x.LocalPath().endswith('.mm')) 538*c8dee2aaSAndroid Build Coastguard Worker for affected_file in input_api.AffectedSourceFiles(file_filter): 539*c8dee2aaSAndroid Build Coastguard Worker affected_filepath = affected_file.LocalPath() 540*c8dee2aaSAndroid Build Coastguard Worker for (line_num, line) in affected_file.ChangedContents(): 541*c8dee2aaSAndroid Build Coastguard Worker for (re, replacement, exceptions) in compiled_replacements: 542*c8dee2aaSAndroid Build Coastguard Worker match = re.search(line) 543*c8dee2aaSAndroid Build Coastguard Worker if match: 544*c8dee2aaSAndroid Build Coastguard Worker for exc in exceptions: 545*c8dee2aaSAndroid Build Coastguard Worker if exc.search(affected_filepath): 546*c8dee2aaSAndroid Build Coastguard Worker break 547*c8dee2aaSAndroid Build Coastguard Worker else: 548*c8dee2aaSAndroid Build Coastguard Worker errors.append('%s:%s: Instead of %s, please use %s.' % ( 549*c8dee2aaSAndroid Build Coastguard Worker affected_filepath, line_num, match.group(), replacement)) 550*c8dee2aaSAndroid Build Coastguard Worker # Now to an explicit search for use of GPU_TEST_UTILS outside of 551*c8dee2aaSAndroid Build Coastguard Worker # files that our Bazel rules that define to be set. 552*c8dee2aaSAndroid Build Coastguard Worker match = gpu_test_utils_re.search(line) 553*c8dee2aaSAndroid Build Coastguard Worker if match: 554*c8dee2aaSAndroid Build Coastguard Worker for exc in allowed_test_util_paths: 555*c8dee2aaSAndroid Build Coastguard Worker if affected_filepath.startswith(exc): 556*c8dee2aaSAndroid Build Coastguard Worker break 557*c8dee2aaSAndroid Build Coastguard Worker else: 558*c8dee2aaSAndroid Build Coastguard Worker errors.append('%s:%s: Only GPU code should use GPU_TEST_UTILS.' % ( 559*c8dee2aaSAndroid Build Coastguard Worker affected_filepath, line_num)) 560*c8dee2aaSAndroid Build Coastguard Worker 561*c8dee2aaSAndroid Build Coastguard Worker if errors: 562*c8dee2aaSAndroid Build Coastguard Worker return [output_api.PresubmitError('\n'.join(errors))] 563*c8dee2aaSAndroid Build Coastguard Worker 564*c8dee2aaSAndroid Build Coastguard Worker return [] 565*c8dee2aaSAndroid Build Coastguard Worker 566*c8dee2aaSAndroid Build Coastguard Worker 567*c8dee2aaSAndroid Build Coastguard Workerdef _CheckDEPS(input_api, output_api): 568*c8dee2aaSAndroid Build Coastguard Worker """If DEPS was modified, run the deps_parser to update bazel/deps.bzl""" 569*c8dee2aaSAndroid Build Coastguard Worker files = [] 570*c8dee2aaSAndroid Build Coastguard Worker for affected_file in input_api.AffectedFiles(include_deletes=False): 571*c8dee2aaSAndroid Build Coastguard Worker affected_file_path = affected_file.LocalPath() 572*c8dee2aaSAndroid Build Coastguard Worker if affected_file_path.endswith('DEPS') or affected_file_path.endswith('deps.bzl'): 573*c8dee2aaSAndroid Build Coastguard Worker files.append(affected_file) 574*c8dee2aaSAndroid Build Coastguard Worker if not files: 575*c8dee2aaSAndroid Build Coastguard Worker return [] 576*c8dee2aaSAndroid Build Coastguard Worker try: 577*c8dee2aaSAndroid Build Coastguard Worker subprocess.check_output( 578*c8dee2aaSAndroid Build Coastguard Worker ['bazelisk', '--version'], 579*c8dee2aaSAndroid Build Coastguard Worker stderr=subprocess.STDOUT) 580*c8dee2aaSAndroid Build Coastguard Worker except: 581*c8dee2aaSAndroid Build Coastguard Worker return [output_api.PresubmitNotifyResult( 582*c8dee2aaSAndroid Build Coastguard Worker 'Skipping DEPS check because bazelisk is not on PATH. \n' + 583*c8dee2aaSAndroid Build Coastguard Worker 'You can download it from https://github.com/bazelbuild/bazelisk/releases/tag/v1.14.0')] 584*c8dee2aaSAndroid Build Coastguard Worker 585*c8dee2aaSAndroid Build Coastguard Worker return _RunCommandAndCheckDiff( 586*c8dee2aaSAndroid Build Coastguard Worker output_api, ['bazelisk', 'run', '//bazel/deps_parser'], files 587*c8dee2aaSAndroid Build Coastguard Worker ) 588*c8dee2aaSAndroid Build Coastguard Worker 589*c8dee2aaSAndroid Build Coastguard Worker 590*c8dee2aaSAndroid Build Coastguard Workerdef _CommonChecks(input_api, output_api): 591*c8dee2aaSAndroid Build Coastguard Worker """Presubmit checks common to upload and commit.""" 592*c8dee2aaSAndroid Build Coastguard Worker results = [] 593*c8dee2aaSAndroid Build Coastguard Worker sources = lambda x: (x.LocalPath().endswith('.h') or 594*c8dee2aaSAndroid Build Coastguard Worker x.LocalPath().endswith('.py') or 595*c8dee2aaSAndroid Build Coastguard Worker x.LocalPath().endswith('.sh') or 596*c8dee2aaSAndroid Build Coastguard Worker x.LocalPath().endswith('.m') or 597*c8dee2aaSAndroid Build Coastguard Worker x.LocalPath().endswith('.mm') or 598*c8dee2aaSAndroid Build Coastguard Worker x.LocalPath().endswith('.go') or 599*c8dee2aaSAndroid Build Coastguard Worker x.LocalPath().endswith('.c') or 600*c8dee2aaSAndroid Build Coastguard Worker x.LocalPath().endswith('.cc') or 601*c8dee2aaSAndroid Build Coastguard Worker x.LocalPath().endswith('.cpp')) 602*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CheckChangeHasEol( 603*c8dee2aaSAndroid Build Coastguard Worker input_api, output_api, source_file_filter=sources)) 604*c8dee2aaSAndroid Build Coastguard Worker with _WarningsAsErrors(output_api): 605*c8dee2aaSAndroid Build Coastguard Worker results.extend(input_api.canned_checks.CheckChangeHasNoCR( 606*c8dee2aaSAndroid Build Coastguard Worker input_api, output_api, source_file_filter=sources)) 607*c8dee2aaSAndroid Build Coastguard Worker results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace( 608*c8dee2aaSAndroid Build Coastguard Worker input_api, output_api, source_file_filter=sources)) 609*c8dee2aaSAndroid Build Coastguard Worker results.extend(_JsonChecks(input_api, output_api)) 610*c8dee2aaSAndroid Build Coastguard Worker results.extend(_IfDefChecks(input_api, output_api)) 611*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CopyrightChecks(input_api, output_api, 612*c8dee2aaSAndroid Build Coastguard Worker source_file_filter=sources)) 613*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CheckIncludesFormatted(input_api, output_api)) 614*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CheckGNFormatted(input_api, output_api)) 615*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CheckGitConflictMarkers(input_api, output_api)) 616*c8dee2aaSAndroid Build Coastguard Worker results.extend(_RegenerateAllExamplesCPP(input_api, output_api)) 617*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CheckExamplesForPrivateAPIs(input_api, output_api)) 618*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CheckIncludeForOutsideDeps(input_api, output_api)) 619*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CheckBazelBUILDFiles(input_api, output_api)) 620*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CheckBannedAPIs(input_api, output_api)) 621*c8dee2aaSAndroid Build Coastguard Worker return results 622*c8dee2aaSAndroid Build Coastguard Worker 623*c8dee2aaSAndroid Build Coastguard Worker 624*c8dee2aaSAndroid Build Coastguard Workerdef CheckChangeOnUpload(input_api, output_api): 625*c8dee2aaSAndroid Build Coastguard Worker """Presubmit checks for the change on upload.""" 626*c8dee2aaSAndroid Build Coastguard Worker results = [] 627*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CommonChecks(input_api, output_api)) 628*c8dee2aaSAndroid Build Coastguard Worker # Run on upload, not commit, since the presubmit bot apparently doesn't have 629*c8dee2aaSAndroid Build Coastguard Worker # coverage or Go installed. 630*c8dee2aaSAndroid Build Coastguard Worker results.extend(_InfraTests(input_api, output_api)) 631*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CheckTopReleaseNotesChanged(input_api, output_api)) 632*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CheckReleaseNotesForPublicAPI(input_api, output_api)) 633*c8dee2aaSAndroid Build Coastguard Worker # Buildifier might not be on the CI machines. 634*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CheckBuildifier(input_api, output_api)) 635*c8dee2aaSAndroid Build Coastguard Worker # We don't want this to block the CQ (for now). 636*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CheckDEPS(input_api, output_api)) 637*c8dee2aaSAndroid Build Coastguard Worker # Bazelisk is not yet included in the Presubmit job. 638*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CheckGeneratedBazelBUILDFiles(input_api, output_api)) 639*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CheckGNIGenerated(input_api, output_api)) 640*c8dee2aaSAndroid Build Coastguard Worker return results 641*c8dee2aaSAndroid Build Coastguard Worker 642*c8dee2aaSAndroid Build Coastguard Worker 643*c8dee2aaSAndroid Build Coastguard Workerclass CodeReview(object): 644*c8dee2aaSAndroid Build Coastguard Worker """Abstracts which codereview tool is used for the specified issue.""" 645*c8dee2aaSAndroid Build Coastguard Worker 646*c8dee2aaSAndroid Build Coastguard Worker def __init__(self, input_api): 647*c8dee2aaSAndroid Build Coastguard Worker self._issue = input_api.change.issue 648*c8dee2aaSAndroid Build Coastguard Worker self._gerrit = input_api.gerrit 649*c8dee2aaSAndroid Build Coastguard Worker 650*c8dee2aaSAndroid Build Coastguard Worker def GetOwnerEmail(self): 651*c8dee2aaSAndroid Build Coastguard Worker return self._gerrit.GetChangeOwner(self._issue) 652*c8dee2aaSAndroid Build Coastguard Worker 653*c8dee2aaSAndroid Build Coastguard Worker def GetSubject(self): 654*c8dee2aaSAndroid Build Coastguard Worker return self._gerrit.GetChangeInfo(self._issue)['subject'] 655*c8dee2aaSAndroid Build Coastguard Worker 656*c8dee2aaSAndroid Build Coastguard Worker def GetDescription(self): 657*c8dee2aaSAndroid Build Coastguard Worker return self._gerrit.GetChangeDescription(self._issue) 658*c8dee2aaSAndroid Build Coastguard Worker 659*c8dee2aaSAndroid Build Coastguard Worker def GetReviewers(self): 660*c8dee2aaSAndroid Build Coastguard Worker code_review_label = ( 661*c8dee2aaSAndroid Build Coastguard Worker self._gerrit.GetChangeInfo(self._issue)['labels']['Code-Review']) 662*c8dee2aaSAndroid Build Coastguard Worker return [r['email'] for r in code_review_label.get('all', [])] 663*c8dee2aaSAndroid Build Coastguard Worker 664*c8dee2aaSAndroid Build Coastguard Worker def GetApprovers(self): 665*c8dee2aaSAndroid Build Coastguard Worker approvers = [] 666*c8dee2aaSAndroid Build Coastguard Worker code_review_label = ( 667*c8dee2aaSAndroid Build Coastguard Worker self._gerrit.GetChangeInfo(self._issue)['labels']['Code-Review']) 668*c8dee2aaSAndroid Build Coastguard Worker for m in code_review_label.get('all', []): 669*c8dee2aaSAndroid Build Coastguard Worker if m.get("value") == 1: 670*c8dee2aaSAndroid Build Coastguard Worker approvers.append(m["email"]) 671*c8dee2aaSAndroid Build Coastguard Worker return approvers 672*c8dee2aaSAndroid Build Coastguard Worker 673*c8dee2aaSAndroid Build Coastguard Worker 674*c8dee2aaSAndroid Build Coastguard Workerdef _CheckReleaseNotesForPublicAPI(input_api, output_api): 675*c8dee2aaSAndroid Build Coastguard Worker """Checks to see if a release notes file is added or edited with public API changes.""" 676*c8dee2aaSAndroid Build Coastguard Worker results = [] 677*c8dee2aaSAndroid Build Coastguard Worker public_api_changed = False 678*c8dee2aaSAndroid Build Coastguard Worker release_file_changed = False 679*c8dee2aaSAndroid Build Coastguard Worker for affected_file in input_api.AffectedFiles(): 680*c8dee2aaSAndroid Build Coastguard Worker affected_file_path = affected_file.LocalPath() 681*c8dee2aaSAndroid Build Coastguard Worker file_path, file_ext = os.path.splitext(affected_file_path) 682*c8dee2aaSAndroid Build Coastguard Worker # We only care about files that end in .h and are under the top-level 683*c8dee2aaSAndroid Build Coastguard Worker # include dir, but not include/private. 684*c8dee2aaSAndroid Build Coastguard Worker if (file_ext == '.h' and 685*c8dee2aaSAndroid Build Coastguard Worker file_path.split(os.path.sep)[0] == 'include' and 686*c8dee2aaSAndroid Build Coastguard Worker 'private' not in file_path): 687*c8dee2aaSAndroid Build Coastguard Worker public_api_changed = True 688*c8dee2aaSAndroid Build Coastguard Worker elif os.path.dirname(file_path) == RELEASE_NOTES_DIR: 689*c8dee2aaSAndroid Build Coastguard Worker release_file_changed = True 690*c8dee2aaSAndroid Build Coastguard Worker 691*c8dee2aaSAndroid Build Coastguard Worker if public_api_changed and not release_file_changed: 692*c8dee2aaSAndroid Build Coastguard Worker results.append(output_api.PresubmitPromptWarning( 693*c8dee2aaSAndroid Build Coastguard Worker 'If this change affects a client API, please add a new summary ' 694*c8dee2aaSAndroid Build Coastguard Worker 'file in the %s directory. More information can be found in ' 695*c8dee2aaSAndroid Build Coastguard Worker '%s.' % (RELEASE_NOTES_DIR, RELEASE_NOTES_README))) 696*c8dee2aaSAndroid Build Coastguard Worker return results 697*c8dee2aaSAndroid Build Coastguard Worker 698*c8dee2aaSAndroid Build Coastguard Worker 699*c8dee2aaSAndroid Build Coastguard Workerdef _CheckTopReleaseNotesChanged(input_api, output_api): 700*c8dee2aaSAndroid Build Coastguard Worker """Warns if the top level release notes file was changed. 701*c8dee2aaSAndroid Build Coastguard Worker 702*c8dee2aaSAndroid Build Coastguard Worker The top level file is now auto-edited, and new release notes should 703*c8dee2aaSAndroid Build Coastguard Worker be added to the RELEASE_NOTES_DIR directory""" 704*c8dee2aaSAndroid Build Coastguard Worker results = [] 705*c8dee2aaSAndroid Build Coastguard Worker top_relnotes_changed = False 706*c8dee2aaSAndroid Build Coastguard Worker release_file_changed = False 707*c8dee2aaSAndroid Build Coastguard Worker for affected_file in input_api.AffectedFiles(): 708*c8dee2aaSAndroid Build Coastguard Worker affected_file_path = affected_file.LocalPath() 709*c8dee2aaSAndroid Build Coastguard Worker file_path, file_ext = os.path.splitext(affected_file_path) 710*c8dee2aaSAndroid Build Coastguard Worker if affected_file_path == RELEASE_NOTES_FILE_NAME: 711*c8dee2aaSAndroid Build Coastguard Worker top_relnotes_changed = True 712*c8dee2aaSAndroid Build Coastguard Worker elif os.path.dirname(file_path) == RELEASE_NOTES_DIR: 713*c8dee2aaSAndroid Build Coastguard Worker release_file_changed = True 714*c8dee2aaSAndroid Build Coastguard Worker # When relnotes_util is run it will modify RELEASE_NOTES_FILE_NAME 715*c8dee2aaSAndroid Build Coastguard Worker # and delete the individual note files in RELEASE_NOTES_DIR. 716*c8dee2aaSAndroid Build Coastguard Worker # So, if both paths are modified do not emit a warning. 717*c8dee2aaSAndroid Build Coastguard Worker if top_relnotes_changed and not release_file_changed: 718*c8dee2aaSAndroid Build Coastguard Worker results.append(output_api.PresubmitPromptWarning( 719*c8dee2aaSAndroid Build Coastguard Worker 'Do not edit %s directly. %s is automatically edited during the ' 720*c8dee2aaSAndroid Build Coastguard Worker 'release process. Release notes should be added as new files in ' 721*c8dee2aaSAndroid Build Coastguard Worker 'the %s directory. More information can be found in %s.' % (RELEASE_NOTES_FILE_NAME, 722*c8dee2aaSAndroid Build Coastguard Worker RELEASE_NOTES_FILE_NAME, 723*c8dee2aaSAndroid Build Coastguard Worker RELEASE_NOTES_DIR, 724*c8dee2aaSAndroid Build Coastguard Worker RELEASE_NOTES_README))) 725*c8dee2aaSAndroid Build Coastguard Worker return results 726*c8dee2aaSAndroid Build Coastguard Worker 727*c8dee2aaSAndroid Build Coastguard Worker 728*c8dee2aaSAndroid Build Coastguard Workerdef PostUploadHook(gerrit, change, output_api): 729*c8dee2aaSAndroid Build Coastguard Worker """git cl upload will call this hook after the issue is created/modified. 730*c8dee2aaSAndroid Build Coastguard Worker 731*c8dee2aaSAndroid Build Coastguard Worker This hook does the following: 732*c8dee2aaSAndroid Build Coastguard Worker * Adds a link to preview docs changes if there are any docs changes in the CL. 733*c8dee2aaSAndroid Build Coastguard Worker * Adds 'No-Try: true' if the CL contains only docs changes. 734*c8dee2aaSAndroid Build Coastguard Worker """ 735*c8dee2aaSAndroid Build Coastguard Worker if not change.issue: 736*c8dee2aaSAndroid Build Coastguard Worker return [] 737*c8dee2aaSAndroid Build Coastguard Worker 738*c8dee2aaSAndroid Build Coastguard Worker # Skip PostUploadHooks for all auto-commit service account bots. New 739*c8dee2aaSAndroid Build Coastguard Worker # patchsets (caused due to PostUploadHooks) invalidates the CQ+2 vote from 740*c8dee2aaSAndroid Build Coastguard Worker # the "--use-commit-queue" flag to "git cl upload". 741*c8dee2aaSAndroid Build Coastguard Worker for suffix in SERVICE_ACCOUNT_SUFFIX: 742*c8dee2aaSAndroid Build Coastguard Worker if change.author_email.endswith(suffix): 743*c8dee2aaSAndroid Build Coastguard Worker return [] 744*c8dee2aaSAndroid Build Coastguard Worker 745*c8dee2aaSAndroid Build Coastguard Worker results = [] 746*c8dee2aaSAndroid Build Coastguard Worker at_least_one_docs_change = False 747*c8dee2aaSAndroid Build Coastguard Worker all_docs_changes = True 748*c8dee2aaSAndroid Build Coastguard Worker for affected_file in change.AffectedFiles(): 749*c8dee2aaSAndroid Build Coastguard Worker affected_file_path = affected_file.LocalPath() 750*c8dee2aaSAndroid Build Coastguard Worker file_path, _ = os.path.splitext(affected_file_path) 751*c8dee2aaSAndroid Build Coastguard Worker if 'site' == file_path.split(os.path.sep)[0]: 752*c8dee2aaSAndroid Build Coastguard Worker at_least_one_docs_change = True 753*c8dee2aaSAndroid Build Coastguard Worker else: 754*c8dee2aaSAndroid Build Coastguard Worker all_docs_changes = False 755*c8dee2aaSAndroid Build Coastguard Worker if at_least_one_docs_change and not all_docs_changes: 756*c8dee2aaSAndroid Build Coastguard Worker break 757*c8dee2aaSAndroid Build Coastguard Worker 758*c8dee2aaSAndroid Build Coastguard Worker footers = change.GitFootersFromDescription() 759*c8dee2aaSAndroid Build Coastguard Worker description_changed = False 760*c8dee2aaSAndroid Build Coastguard Worker 761*c8dee2aaSAndroid Build Coastguard Worker # If the change includes only doc changes then add No-Try: true in the 762*c8dee2aaSAndroid Build Coastguard Worker # CL's description if it does not exist yet. 763*c8dee2aaSAndroid Build Coastguard Worker if all_docs_changes and 'true' not in footers.get('No-Try', []): 764*c8dee2aaSAndroid Build Coastguard Worker description_changed = True 765*c8dee2aaSAndroid Build Coastguard Worker change.AddDescriptionFooter('No-Try', 'true') 766*c8dee2aaSAndroid Build Coastguard Worker results.append( 767*c8dee2aaSAndroid Build Coastguard Worker output_api.PresubmitNotifyResult( 768*c8dee2aaSAndroid Build Coastguard Worker 'This change has only doc changes. Automatically added ' 769*c8dee2aaSAndroid Build Coastguard Worker '\'No-Try: true\' to the CL\'s description')) 770*c8dee2aaSAndroid Build Coastguard Worker 771*c8dee2aaSAndroid Build Coastguard Worker # If the description has changed update it. 772*c8dee2aaSAndroid Build Coastguard Worker if description_changed: 773*c8dee2aaSAndroid Build Coastguard Worker gerrit.UpdateDescription( 774*c8dee2aaSAndroid Build Coastguard Worker change.FullDescriptionText(), change.issue) 775*c8dee2aaSAndroid Build Coastguard Worker 776*c8dee2aaSAndroid Build Coastguard Worker return results 777*c8dee2aaSAndroid Build Coastguard Worker 778*c8dee2aaSAndroid Build Coastguard Worker 779*c8dee2aaSAndroid Build Coastguard Workerdef CheckChangeOnCommit(input_api, output_api): 780*c8dee2aaSAndroid Build Coastguard Worker """Presubmit checks for the change on commit.""" 781*c8dee2aaSAndroid Build Coastguard Worker results = [] 782*c8dee2aaSAndroid Build Coastguard Worker results.extend(_CommonChecks(input_api, output_api)) 783*c8dee2aaSAndroid Build Coastguard Worker # Checks for the presence of 'DO NOT''SUBMIT' in CL description and in 784*c8dee2aaSAndroid Build Coastguard Worker # content of files. 785*c8dee2aaSAndroid Build Coastguard Worker results.extend( 786*c8dee2aaSAndroid Build Coastguard Worker input_api.canned_checks.CheckDoNotSubmit(input_api, output_api)) 787*c8dee2aaSAndroid Build Coastguard Worker return results 788