xref: /aosp_15_r20/external/skia/PRESUBMIT.py (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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