xref: /aosp_15_r20/external/angle/PRESUBMIT.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker# Copyright 2019 The ANGLE Project Authors. All rights reserved.
2*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
3*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file.
4*8975f5c5SAndroid Build Coastguard Worker"""Top-level presubmit script for code generation.
5*8975f5c5SAndroid Build Coastguard Worker
6*8975f5c5SAndroid Build Coastguard WorkerSee http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
7*8975f5c5SAndroid Build Coastguard Workerfor more details on the presubmit API built into depot_tools.
8*8975f5c5SAndroid Build Coastguard Worker"""
9*8975f5c5SAndroid Build Coastguard Worker
10*8975f5c5SAndroid Build Coastguard Workerimport itertools
11*8975f5c5SAndroid Build Coastguard Workerimport os
12*8975f5c5SAndroid Build Coastguard Workerimport re
13*8975f5c5SAndroid Build Coastguard Workerimport shutil
14*8975f5c5SAndroid Build Coastguard Workerimport subprocess
15*8975f5c5SAndroid Build Coastguard Workerimport sys
16*8975f5c5SAndroid Build Coastguard Workerimport tempfile
17*8975f5c5SAndroid Build Coastguard Workerimport textwrap
18*8975f5c5SAndroid Build Coastguard Workerimport pathlib
19*8975f5c5SAndroid Build Coastguard Worker
20*8975f5c5SAndroid Build Coastguard Worker# This line is 'magic' in that git-cl looks for it to decide whether to
21*8975f5c5SAndroid Build Coastguard Worker# use Python3 instead of Python2 when running the code in this file.
22*8975f5c5SAndroid Build Coastguard WorkerUSE_PYTHON3 = True
23*8975f5c5SAndroid Build Coastguard Worker
24*8975f5c5SAndroid Build Coastguard Worker# Fragment of a regular expression that matches C/C++ and Objective-C++ implementation files and headers.
25*8975f5c5SAndroid Build Coastguard Worker_IMPLEMENTATION_AND_HEADER_EXTENSIONS = r'\.(c|cc|cpp|cxx|mm|h|hpp|hxx)$'
26*8975f5c5SAndroid Build Coastguard Worker
27*8975f5c5SAndroid Build Coastguard Worker# Fragment of a regular expression that matches C++ and Objective-C++ header files.
28*8975f5c5SAndroid Build Coastguard Worker_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
29*8975f5c5SAndroid Build Coastguard Worker
30*8975f5c5SAndroid Build Coastguard Worker_PRIMARY_EXPORT_TARGETS = [
31*8975f5c5SAndroid Build Coastguard Worker    '//:libEGL',
32*8975f5c5SAndroid Build Coastguard Worker    '//:libGLESv1_CM',
33*8975f5c5SAndroid Build Coastguard Worker    '//:libGLESv2',
34*8975f5c5SAndroid Build Coastguard Worker    '//:translator',
35*8975f5c5SAndroid Build Coastguard Worker]
36*8975f5c5SAndroid Build Coastguard Worker
37*8975f5c5SAndroid Build Coastguard Worker
38*8975f5c5SAndroid Build Coastguard Workerdef _SplitIntoMultipleCommits(description_text):
39*8975f5c5SAndroid Build Coastguard Worker    paragraph_split_pattern = r"(?m)(^\s*$\n)"
40*8975f5c5SAndroid Build Coastguard Worker    multiple_paragraphs = re.split(paragraph_split_pattern, description_text)
41*8975f5c5SAndroid Build Coastguard Worker    multiple_commits = [""]
42*8975f5c5SAndroid Build Coastguard Worker    change_id_pattern = re.compile(r"(?m)^Change-Id: [a-zA-Z0-9]*$")
43*8975f5c5SAndroid Build Coastguard Worker    for paragraph in multiple_paragraphs:
44*8975f5c5SAndroid Build Coastguard Worker        multiple_commits[-1] += paragraph
45*8975f5c5SAndroid Build Coastguard Worker        if change_id_pattern.search(paragraph):
46*8975f5c5SAndroid Build Coastguard Worker            multiple_commits.append("")
47*8975f5c5SAndroid Build Coastguard Worker    if multiple_commits[-1] == "":
48*8975f5c5SAndroid Build Coastguard Worker        multiple_commits.pop()
49*8975f5c5SAndroid Build Coastguard Worker    return multiple_commits
50*8975f5c5SAndroid Build Coastguard Worker
51*8975f5c5SAndroid Build Coastguard Worker
52*8975f5c5SAndroid Build Coastguard Workerdef _CheckCommitMessageFormatting(input_api, output_api):
53*8975f5c5SAndroid Build Coastguard Worker
54*8975f5c5SAndroid Build Coastguard Worker    def _IsLineBlank(line):
55*8975f5c5SAndroid Build Coastguard Worker        return line.isspace() or line == ""
56*8975f5c5SAndroid Build Coastguard Worker
57*8975f5c5SAndroid Build Coastguard Worker    def _PopBlankLines(lines, reverse=False):
58*8975f5c5SAndroid Build Coastguard Worker        if reverse:
59*8975f5c5SAndroid Build Coastguard Worker            while len(lines) > 0 and _IsLineBlank(lines[-1]):
60*8975f5c5SAndroid Build Coastguard Worker                lines.pop()
61*8975f5c5SAndroid Build Coastguard Worker        else:
62*8975f5c5SAndroid Build Coastguard Worker            while len(lines) > 0 and _IsLineBlank(lines[0]):
63*8975f5c5SAndroid Build Coastguard Worker                lines.pop(0)
64*8975f5c5SAndroid Build Coastguard Worker
65*8975f5c5SAndroid Build Coastguard Worker    def _IsTagLine(line):
66*8975f5c5SAndroid Build Coastguard Worker        return ":" in line
67*8975f5c5SAndroid Build Coastguard Worker
68*8975f5c5SAndroid Build Coastguard Worker    def _CheckTabInCommit(lines):
69*8975f5c5SAndroid Build Coastguard Worker        return all([line.find("\t") == -1 for line in lines])
70*8975f5c5SAndroid Build Coastguard Worker
71*8975f5c5SAndroid Build Coastguard Worker    allowlist_strings = ['Revert', 'Roll', 'Manual roll', 'Reland', 'Re-land']
72*8975f5c5SAndroid Build Coastguard Worker    summary_linelength_warning_lower_limit = 65
73*8975f5c5SAndroid Build Coastguard Worker    summary_linelength_warning_upper_limit = 70
74*8975f5c5SAndroid Build Coastguard Worker    description_linelength_limit = 72
75*8975f5c5SAndroid Build Coastguard Worker
76*8975f5c5SAndroid Build Coastguard Worker    git_output = input_api.change.DescriptionText()
77*8975f5c5SAndroid Build Coastguard Worker
78*8975f5c5SAndroid Build Coastguard Worker    multiple_commits = _SplitIntoMultipleCommits(git_output)
79*8975f5c5SAndroid Build Coastguard Worker    errors = []
80*8975f5c5SAndroid Build Coastguard Worker
81*8975f5c5SAndroid Build Coastguard Worker    for k in range(len(multiple_commits)):
82*8975f5c5SAndroid Build Coastguard Worker        commit_msg_lines = multiple_commits[k].splitlines()
83*8975f5c5SAndroid Build Coastguard Worker        commit_number = len(multiple_commits) - k
84*8975f5c5SAndroid Build Coastguard Worker        commit_tag = "Commit " + str(commit_number) + ":"
85*8975f5c5SAndroid Build Coastguard Worker        commit_msg_line_numbers = {}
86*8975f5c5SAndroid Build Coastguard Worker        for i in range(len(commit_msg_lines)):
87*8975f5c5SAndroid Build Coastguard Worker            commit_msg_line_numbers[commit_msg_lines[i]] = i + 1
88*8975f5c5SAndroid Build Coastguard Worker        _PopBlankLines(commit_msg_lines, True)
89*8975f5c5SAndroid Build Coastguard Worker        _PopBlankLines(commit_msg_lines, False)
90*8975f5c5SAndroid Build Coastguard Worker        allowlisted = False
91*8975f5c5SAndroid Build Coastguard Worker        if len(commit_msg_lines) > 0:
92*8975f5c5SAndroid Build Coastguard Worker            for allowlist_string in allowlist_strings:
93*8975f5c5SAndroid Build Coastguard Worker                if commit_msg_lines[0].startswith(allowlist_string):
94*8975f5c5SAndroid Build Coastguard Worker                    allowlisted = True
95*8975f5c5SAndroid Build Coastguard Worker                    break
96*8975f5c5SAndroid Build Coastguard Worker        if allowlisted:
97*8975f5c5SAndroid Build Coastguard Worker            continue
98*8975f5c5SAndroid Build Coastguard Worker
99*8975f5c5SAndroid Build Coastguard Worker        if not _CheckTabInCommit(commit_msg_lines):
100*8975f5c5SAndroid Build Coastguard Worker            errors.append(
101*8975f5c5SAndroid Build Coastguard Worker                output_api.PresubmitError(commit_tag + "Tabs are not allowed in commit message."))
102*8975f5c5SAndroid Build Coastguard Worker
103*8975f5c5SAndroid Build Coastguard Worker        # the tags paragraph is at the end of the message
104*8975f5c5SAndroid Build Coastguard Worker        # the break between the tags paragraph is the first line without ":"
105*8975f5c5SAndroid Build Coastguard Worker        # this is sufficient because if a line is blank, it will not have ":"
106*8975f5c5SAndroid Build Coastguard Worker        last_paragraph_line_count = 0
107*8975f5c5SAndroid Build Coastguard Worker        while len(commit_msg_lines) > 0 and _IsTagLine(commit_msg_lines[-1]):
108*8975f5c5SAndroid Build Coastguard Worker            last_paragraph_line_count += 1
109*8975f5c5SAndroid Build Coastguard Worker            commit_msg_lines.pop()
110*8975f5c5SAndroid Build Coastguard Worker        if last_paragraph_line_count == 0:
111*8975f5c5SAndroid Build Coastguard Worker            errors.append(
112*8975f5c5SAndroid Build Coastguard Worker                output_api.PresubmitError(
113*8975f5c5SAndroid Build Coastguard Worker                    commit_tag +
114*8975f5c5SAndroid Build Coastguard Worker                    "Please ensure that there are tags (e.g., Bug:, Test:) in your description."))
115*8975f5c5SAndroid Build Coastguard Worker        if len(commit_msg_lines) > 0:
116*8975f5c5SAndroid Build Coastguard Worker            if not _IsLineBlank(commit_msg_lines[-1]):
117*8975f5c5SAndroid Build Coastguard Worker                output_api.PresubmitError(commit_tag +
118*8975f5c5SAndroid Build Coastguard Worker                                          "Please ensure that there exists 1 blank line " +
119*8975f5c5SAndroid Build Coastguard Worker                                          "between tags and description body.")
120*8975f5c5SAndroid Build Coastguard Worker            else:
121*8975f5c5SAndroid Build Coastguard Worker                # pop the blank line between tag paragraph and description body
122*8975f5c5SAndroid Build Coastguard Worker                commit_msg_lines.pop()
123*8975f5c5SAndroid Build Coastguard Worker                if len(commit_msg_lines) > 0 and _IsLineBlank(commit_msg_lines[-1]):
124*8975f5c5SAndroid Build Coastguard Worker                    errors.append(
125*8975f5c5SAndroid Build Coastguard Worker                        output_api.PresubmitError(
126*8975f5c5SAndroid Build Coastguard Worker                            commit_tag + 'Please ensure that there exists only 1 blank line '
127*8975f5c5SAndroid Build Coastguard Worker                            'between tags and description body.'))
128*8975f5c5SAndroid Build Coastguard Worker                    # pop all the remaining blank lines between tag and description body
129*8975f5c5SAndroid Build Coastguard Worker                    _PopBlankLines(commit_msg_lines, True)
130*8975f5c5SAndroid Build Coastguard Worker        if len(commit_msg_lines) == 0:
131*8975f5c5SAndroid Build Coastguard Worker            errors.append(
132*8975f5c5SAndroid Build Coastguard Worker                output_api.PresubmitError(commit_tag +
133*8975f5c5SAndroid Build Coastguard Worker                                          'Please ensure that your description summary'
134*8975f5c5SAndroid Build Coastguard Worker                                          ' and description body are not blank.'))
135*8975f5c5SAndroid Build Coastguard Worker            continue
136*8975f5c5SAndroid Build Coastguard Worker
137*8975f5c5SAndroid Build Coastguard Worker        if summary_linelength_warning_lower_limit <= len(commit_msg_lines[0]) \
138*8975f5c5SAndroid Build Coastguard Worker        <= summary_linelength_warning_upper_limit:
139*8975f5c5SAndroid Build Coastguard Worker            errors.append(
140*8975f5c5SAndroid Build Coastguard Worker                output_api.PresubmitPromptWarning(
141*8975f5c5SAndroid Build Coastguard Worker                    commit_tag + "Your description summary should be on one line of " +
142*8975f5c5SAndroid Build Coastguard Worker                    str(summary_linelength_warning_lower_limit - 1) + " or less characters."))
143*8975f5c5SAndroid Build Coastguard Worker        elif len(commit_msg_lines[0]) > summary_linelength_warning_upper_limit:
144*8975f5c5SAndroid Build Coastguard Worker            errors.append(
145*8975f5c5SAndroid Build Coastguard Worker                output_api.PresubmitError(
146*8975f5c5SAndroid Build Coastguard Worker                    commit_tag + "Please ensure that your description summary is on one line of " +
147*8975f5c5SAndroid Build Coastguard Worker                    str(summary_linelength_warning_lower_limit - 1) + " or less characters."))
148*8975f5c5SAndroid Build Coastguard Worker        commit_msg_lines.pop(0)  # get rid of description summary
149*8975f5c5SAndroid Build Coastguard Worker        if len(commit_msg_lines) == 0:
150*8975f5c5SAndroid Build Coastguard Worker            continue
151*8975f5c5SAndroid Build Coastguard Worker        if not _IsLineBlank(commit_msg_lines[0]):
152*8975f5c5SAndroid Build Coastguard Worker            errors.append(
153*8975f5c5SAndroid Build Coastguard Worker                output_api.PresubmitError(commit_tag +
154*8975f5c5SAndroid Build Coastguard Worker                                          'Please ensure the summary is only 1 line and '
155*8975f5c5SAndroid Build Coastguard Worker                                          'there is 1 blank line between the summary '
156*8975f5c5SAndroid Build Coastguard Worker                                          'and description body.'))
157*8975f5c5SAndroid Build Coastguard Worker        else:
158*8975f5c5SAndroid Build Coastguard Worker            commit_msg_lines.pop(0)  # pop first blank line
159*8975f5c5SAndroid Build Coastguard Worker            if len(commit_msg_lines) == 0:
160*8975f5c5SAndroid Build Coastguard Worker                continue
161*8975f5c5SAndroid Build Coastguard Worker            if _IsLineBlank(commit_msg_lines[0]):
162*8975f5c5SAndroid Build Coastguard Worker                errors.append(
163*8975f5c5SAndroid Build Coastguard Worker                    output_api.PresubmitError(commit_tag +
164*8975f5c5SAndroid Build Coastguard Worker                                              'Please ensure that there exists only 1 blank line '
165*8975f5c5SAndroid Build Coastguard Worker                                              'between description summary and description body.'))
166*8975f5c5SAndroid Build Coastguard Worker                # pop all the remaining blank lines between
167*8975f5c5SAndroid Build Coastguard Worker                # description summary and description body
168*8975f5c5SAndroid Build Coastguard Worker                _PopBlankLines(commit_msg_lines)
169*8975f5c5SAndroid Build Coastguard Worker
170*8975f5c5SAndroid Build Coastguard Worker        # loop through description body
171*8975f5c5SAndroid Build Coastguard Worker        while len(commit_msg_lines) > 0:
172*8975f5c5SAndroid Build Coastguard Worker            line = commit_msg_lines.pop(0)
173*8975f5c5SAndroid Build Coastguard Worker            # lines starting with 4 spaces, quotes or lines without space(urls)
174*8975f5c5SAndroid Build Coastguard Worker            # are exempt from length check
175*8975f5c5SAndroid Build Coastguard Worker            if line.startswith("    ") or line.startswith("> ") or " " not in line:
176*8975f5c5SAndroid Build Coastguard Worker                continue
177*8975f5c5SAndroid Build Coastguard Worker            if len(line) > description_linelength_limit:
178*8975f5c5SAndroid Build Coastguard Worker                errors.append(
179*8975f5c5SAndroid Build Coastguard Worker                    output_api.PresubmitError(
180*8975f5c5SAndroid Build Coastguard Worker                        commit_tag + 'Line ' + str(commit_msg_line_numbers[line]) +
181*8975f5c5SAndroid Build Coastguard Worker                        ' is too long.\n' + '"' + line + '"\n' + 'Please wrap it to ' +
182*8975f5c5SAndroid Build Coastguard Worker                        str(description_linelength_limit) + ' characters. ' +
183*8975f5c5SAndroid Build Coastguard Worker                        "Lines without spaces or lines starting with 4 spaces are exempt."))
184*8975f5c5SAndroid Build Coastguard Worker                break
185*8975f5c5SAndroid Build Coastguard Worker    return errors
186*8975f5c5SAndroid Build Coastguard Worker
187*8975f5c5SAndroid Build Coastguard Worker
188*8975f5c5SAndroid Build Coastguard Workerdef _CheckChangeHasBugField(input_api, output_api):
189*8975f5c5SAndroid Build Coastguard Worker    """Requires that the changelist have a Bug: field from a known project."""
190*8975f5c5SAndroid Build Coastguard Worker    bugs = input_api.change.BugsFromDescription()
191*8975f5c5SAndroid Build Coastguard Worker
192*8975f5c5SAndroid Build Coastguard Worker    # The bug must be in the form of "project:number".  None is also accepted, which is used by
193*8975f5c5SAndroid Build Coastguard Worker    # rollers as well as in very minor changes.
194*8975f5c5SAndroid Build Coastguard Worker    if len(bugs) == 1 and bugs[0] == 'None':
195*8975f5c5SAndroid Build Coastguard Worker        return []
196*8975f5c5SAndroid Build Coastguard Worker
197*8975f5c5SAndroid Build Coastguard Worker    projects = [
198*8975f5c5SAndroid Build Coastguard Worker        'angleproject:', 'chromium:', 'dawn:', 'fuchsia:', 'skia:', 'swiftshader:', 'tint:', 'b/'
199*8975f5c5SAndroid Build Coastguard Worker    ]
200*8975f5c5SAndroid Build Coastguard Worker    bug_regex = re.compile(r"([a-z]+[:/])(\d+)")
201*8975f5c5SAndroid Build Coastguard Worker    errors = []
202*8975f5c5SAndroid Build Coastguard Worker    extra_help = False
203*8975f5c5SAndroid Build Coastguard Worker
204*8975f5c5SAndroid Build Coastguard Worker    if not bugs:
205*8975f5c5SAndroid Build Coastguard Worker        errors.append('Please ensure that your description contains\n'
206*8975f5c5SAndroid Build Coastguard Worker                      'Bug: bugtag\n'
207*8975f5c5SAndroid Build Coastguard Worker                      'directly above the Change-Id tag (no empty line in-between)')
208*8975f5c5SAndroid Build Coastguard Worker        extra_help = True
209*8975f5c5SAndroid Build Coastguard Worker
210*8975f5c5SAndroid Build Coastguard Worker    for bug in bugs:
211*8975f5c5SAndroid Build Coastguard Worker        if bug == 'None':
212*8975f5c5SAndroid Build Coastguard Worker            errors.append('Invalid bug tag "None" in presence of other bug tags.')
213*8975f5c5SAndroid Build Coastguard Worker            continue
214*8975f5c5SAndroid Build Coastguard Worker
215*8975f5c5SAndroid Build Coastguard Worker        match = re.match(bug_regex, bug)
216*8975f5c5SAndroid Build Coastguard Worker        if match == None or bug != match.group(0) or match.group(1) not in projects:
217*8975f5c5SAndroid Build Coastguard Worker            errors.append('Incorrect bug tag "' + bug + '".')
218*8975f5c5SAndroid Build Coastguard Worker            extra_help = True
219*8975f5c5SAndroid Build Coastguard Worker
220*8975f5c5SAndroid Build Coastguard Worker    if extra_help:
221*8975f5c5SAndroid Build Coastguard Worker        change_ids = re.findall('^Change-Id:', input_api.change.FullDescriptionText(), re.M)
222*8975f5c5SAndroid Build Coastguard Worker        if len(change_ids) > 1:
223*8975f5c5SAndroid Build Coastguard Worker            errors.append('Note: multiple Change-Id tags found in description')
224*8975f5c5SAndroid Build Coastguard Worker
225*8975f5c5SAndroid Build Coastguard Worker        errors.append('''Acceptable bugtags:
226*8975f5c5SAndroid Build Coastguard Worker    project:bugnumber - where project is one of ({projects})
227*8975f5c5SAndroid Build Coastguard Worker    b/bugnumber - for Buganizer/IssueTracker bugs
228*8975f5c5SAndroid Build Coastguard Worker'''.format(projects=', '.join(p[:-1] for p in projects if p != 'b/')))
229*8975f5c5SAndroid Build Coastguard Worker
230*8975f5c5SAndroid Build Coastguard Worker    return [output_api.PresubmitError('\n\n'.join(errors))] if errors else []
231*8975f5c5SAndroid Build Coastguard Worker
232*8975f5c5SAndroid Build Coastguard Worker
233*8975f5c5SAndroid Build Coastguard Workerdef _CheckCodeGeneration(input_api, output_api):
234*8975f5c5SAndroid Build Coastguard Worker
235*8975f5c5SAndroid Build Coastguard Worker    class Msg(output_api.PresubmitError):
236*8975f5c5SAndroid Build Coastguard Worker        """Specialized error message"""
237*8975f5c5SAndroid Build Coastguard Worker
238*8975f5c5SAndroid Build Coastguard Worker        def __init__(self, message, **kwargs):
239*8975f5c5SAndroid Build Coastguard Worker            super(output_api.PresubmitError, self).__init__(
240*8975f5c5SAndroid Build Coastguard Worker                message,
241*8975f5c5SAndroid Build Coastguard Worker                long_text='Please ensure your ANGLE repositiory is synced to tip-of-tree\n'
242*8975f5c5SAndroid Build Coastguard Worker                'and all ANGLE DEPS are fully up-to-date by running gclient sync.\n'
243*8975f5c5SAndroid Build Coastguard Worker                '\n'
244*8975f5c5SAndroid Build Coastguard Worker                'If that fails, run scripts/run_code_generation.py to refresh generated hashes.\n'
245*8975f5c5SAndroid Build Coastguard Worker                '\n'
246*8975f5c5SAndroid Build Coastguard Worker                'If you are building ANGLE inside Chromium you must bootstrap ANGLE\n'
247*8975f5c5SAndroid Build Coastguard Worker                'before gclient sync. See the DevSetup documentation for more details.\n',
248*8975f5c5SAndroid Build Coastguard Worker                **kwargs)
249*8975f5c5SAndroid Build Coastguard Worker
250*8975f5c5SAndroid Build Coastguard Worker    code_gen_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
251*8975f5c5SAndroid Build Coastguard Worker                                           'scripts/run_code_generation.py')
252*8975f5c5SAndroid Build Coastguard Worker    cmd_name = 'run_code_generation'
253*8975f5c5SAndroid Build Coastguard Worker    cmd = [input_api.python3_executable, code_gen_path, '--verify-no-dirty']
254*8975f5c5SAndroid Build Coastguard Worker    test_cmd = input_api.Command(name=cmd_name, cmd=cmd, kwargs={}, message=Msg)
255*8975f5c5SAndroid Build Coastguard Worker    if input_api.verbose:
256*8975f5c5SAndroid Build Coastguard Worker        print('Running ' + cmd_name)
257*8975f5c5SAndroid Build Coastguard Worker    return input_api.RunTests([test_cmd])
258*8975f5c5SAndroid Build Coastguard Worker
259*8975f5c5SAndroid Build Coastguard Worker
260*8975f5c5SAndroid Build Coastguard Worker# Taken directly from Chromium's PRESUBMIT.py
261*8975f5c5SAndroid Build Coastguard Workerdef _CheckNewHeaderWithoutGnChange(input_api, output_api):
262*8975f5c5SAndroid Build Coastguard Worker    """Checks that newly added header files have corresponding GN changes.
263*8975f5c5SAndroid Build Coastguard Worker  Note that this is only a heuristic. To be precise, run script:
264*8975f5c5SAndroid Build Coastguard Worker  build/check_gn_headers.py.
265*8975f5c5SAndroid Build Coastguard Worker  """
266*8975f5c5SAndroid Build Coastguard Worker
267*8975f5c5SAndroid Build Coastguard Worker    def headers(f):
268*8975f5c5SAndroid Build Coastguard Worker        return input_api.FilterSourceFile(f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,))
269*8975f5c5SAndroid Build Coastguard Worker
270*8975f5c5SAndroid Build Coastguard Worker    new_headers = []
271*8975f5c5SAndroid Build Coastguard Worker    for f in input_api.AffectedSourceFiles(headers):
272*8975f5c5SAndroid Build Coastguard Worker        if f.Action() != 'A':
273*8975f5c5SAndroid Build Coastguard Worker            continue
274*8975f5c5SAndroid Build Coastguard Worker        new_headers.append(f.LocalPath())
275*8975f5c5SAndroid Build Coastguard Worker
276*8975f5c5SAndroid Build Coastguard Worker    def gn_files(f):
277*8975f5c5SAndroid Build Coastguard Worker        return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn',))
278*8975f5c5SAndroid Build Coastguard Worker
279*8975f5c5SAndroid Build Coastguard Worker    all_gn_changed_contents = ''
280*8975f5c5SAndroid Build Coastguard Worker    for f in input_api.AffectedSourceFiles(gn_files):
281*8975f5c5SAndroid Build Coastguard Worker        for _, line in f.ChangedContents():
282*8975f5c5SAndroid Build Coastguard Worker            all_gn_changed_contents += line
283*8975f5c5SAndroid Build Coastguard Worker
284*8975f5c5SAndroid Build Coastguard Worker    problems = []
285*8975f5c5SAndroid Build Coastguard Worker    for header in new_headers:
286*8975f5c5SAndroid Build Coastguard Worker        basename = input_api.os_path.basename(header)
287*8975f5c5SAndroid Build Coastguard Worker        if basename not in all_gn_changed_contents:
288*8975f5c5SAndroid Build Coastguard Worker            problems.append(header)
289*8975f5c5SAndroid Build Coastguard Worker
290*8975f5c5SAndroid Build Coastguard Worker    if problems:
291*8975f5c5SAndroid Build Coastguard Worker        return [
292*8975f5c5SAndroid Build Coastguard Worker            output_api.PresubmitPromptWarning(
293*8975f5c5SAndroid Build Coastguard Worker                'Missing GN changes for new header files',
294*8975f5c5SAndroid Build Coastguard Worker                items=sorted(problems),
295*8975f5c5SAndroid Build Coastguard Worker                long_text='Please double check whether newly added header files need '
296*8975f5c5SAndroid Build Coastguard Worker                'corresponding changes in gn or gni files.\nThis checking is only a '
297*8975f5c5SAndroid Build Coastguard Worker                'heuristic. Run build/check_gn_headers.py to be precise.\n'
298*8975f5c5SAndroid Build Coastguard Worker                'Read https://crbug.com/661774 for more info.')
299*8975f5c5SAndroid Build Coastguard Worker        ]
300*8975f5c5SAndroid Build Coastguard Worker    return []
301*8975f5c5SAndroid Build Coastguard Worker
302*8975f5c5SAndroid Build Coastguard Worker
303*8975f5c5SAndroid Build Coastguard Workerdef _CheckExportValidity(input_api, output_api):
304*8975f5c5SAndroid Build Coastguard Worker    outdir = tempfile.mkdtemp()
305*8975f5c5SAndroid Build Coastguard Worker    # shell=True is necessary on Windows, as otherwise subprocess fails to find
306*8975f5c5SAndroid Build Coastguard Worker    # either 'gn' or 'vpython3' even if they are findable via PATH.
307*8975f5c5SAndroid Build Coastguard Worker    use_shell = input_api.is_windows
308*8975f5c5SAndroid Build Coastguard Worker    try:
309*8975f5c5SAndroid Build Coastguard Worker        try:
310*8975f5c5SAndroid Build Coastguard Worker            subprocess.check_output(['gn', 'gen', outdir], shell=use_shell)
311*8975f5c5SAndroid Build Coastguard Worker        except subprocess.CalledProcessError as e:
312*8975f5c5SAndroid Build Coastguard Worker            return [
313*8975f5c5SAndroid Build Coastguard Worker                output_api.PresubmitError('Unable to run gn gen for export_targets.py: %s' %
314*8975f5c5SAndroid Build Coastguard Worker                                          e.output.decode())
315*8975f5c5SAndroid Build Coastguard Worker            ]
316*8975f5c5SAndroid Build Coastguard Worker        export_target_script = os.path.join(input_api.PresubmitLocalPath(), 'scripts',
317*8975f5c5SAndroid Build Coastguard Worker                                            'export_targets.py')
318*8975f5c5SAndroid Build Coastguard Worker        try:
319*8975f5c5SAndroid Build Coastguard Worker            subprocess.check_output(
320*8975f5c5SAndroid Build Coastguard Worker                ['vpython3', export_target_script, outdir] + _PRIMARY_EXPORT_TARGETS,
321*8975f5c5SAndroid Build Coastguard Worker                stderr=subprocess.STDOUT,
322*8975f5c5SAndroid Build Coastguard Worker                shell=use_shell)
323*8975f5c5SAndroid Build Coastguard Worker        except subprocess.CalledProcessError as e:
324*8975f5c5SAndroid Build Coastguard Worker            if input_api.is_committing:
325*8975f5c5SAndroid Build Coastguard Worker                return [
326*8975f5c5SAndroid Build Coastguard Worker                    output_api.PresubmitError('export_targets.py failed: %s' % e.output.decode())
327*8975f5c5SAndroid Build Coastguard Worker                ]
328*8975f5c5SAndroid Build Coastguard Worker            return [
329*8975f5c5SAndroid Build Coastguard Worker                output_api.PresubmitPromptWarning(
330*8975f5c5SAndroid Build Coastguard Worker                    'export_targets.py failed, this may just be due to your local checkout: %s' %
331*8975f5c5SAndroid Build Coastguard Worker                    e.output.decode())
332*8975f5c5SAndroid Build Coastguard Worker            ]
333*8975f5c5SAndroid Build Coastguard Worker        return []
334*8975f5c5SAndroid Build Coastguard Worker    finally:
335*8975f5c5SAndroid Build Coastguard Worker        shutil.rmtree(outdir)
336*8975f5c5SAndroid Build Coastguard Worker
337*8975f5c5SAndroid Build Coastguard Worker
338*8975f5c5SAndroid Build Coastguard Workerdef _CheckTabsInSourceFiles(input_api, output_api):
339*8975f5c5SAndroid Build Coastguard Worker    """Forbids tab characters in source files due to a WebKit repo requirement."""
340*8975f5c5SAndroid Build Coastguard Worker
341*8975f5c5SAndroid Build Coastguard Worker    def implementation_and_headers_including_third_party(f):
342*8975f5c5SAndroid Build Coastguard Worker        # Check third_party files too, because WebKit's checks don't make exceptions.
343*8975f5c5SAndroid Build Coastguard Worker        return input_api.FilterSourceFile(
344*8975f5c5SAndroid Build Coastguard Worker            f,
345*8975f5c5SAndroid Build Coastguard Worker            files_to_check=(r'.+%s' % _IMPLEMENTATION_AND_HEADER_EXTENSIONS,),
346*8975f5c5SAndroid Build Coastguard Worker            files_to_skip=[f for f in input_api.DEFAULT_FILES_TO_SKIP if not "third_party" in f])
347*8975f5c5SAndroid Build Coastguard Worker
348*8975f5c5SAndroid Build Coastguard Worker    files_with_tabs = []
349*8975f5c5SAndroid Build Coastguard Worker    for f in input_api.AffectedSourceFiles(implementation_and_headers_including_third_party):
350*8975f5c5SAndroid Build Coastguard Worker        for (num, line) in f.ChangedContents():
351*8975f5c5SAndroid Build Coastguard Worker            if '\t' in line:
352*8975f5c5SAndroid Build Coastguard Worker                files_with_tabs.append(f)
353*8975f5c5SAndroid Build Coastguard Worker                break
354*8975f5c5SAndroid Build Coastguard Worker
355*8975f5c5SAndroid Build Coastguard Worker    if files_with_tabs:
356*8975f5c5SAndroid Build Coastguard Worker        return [
357*8975f5c5SAndroid Build Coastguard Worker            output_api.PresubmitError(
358*8975f5c5SAndroid Build Coastguard Worker                'Tab characters in source files.',
359*8975f5c5SAndroid Build Coastguard Worker                items=sorted(files_with_tabs),
360*8975f5c5SAndroid Build Coastguard Worker                long_text=
361*8975f5c5SAndroid Build Coastguard Worker                'Tab characters are forbidden in ANGLE source files because WebKit\'s Subversion\n'
362*8975f5c5SAndroid Build Coastguard Worker                'repository does not allow tab characters in source files.\n'
363*8975f5c5SAndroid Build Coastguard Worker                'Please remove tab characters from these files.')
364*8975f5c5SAndroid Build Coastguard Worker        ]
365*8975f5c5SAndroid Build Coastguard Worker    return []
366*8975f5c5SAndroid Build Coastguard Worker
367*8975f5c5SAndroid Build Coastguard Worker
368*8975f5c5SAndroid Build Coastguard Worker# https://stackoverflow.com/a/196392
369*8975f5c5SAndroid Build Coastguard Workerdef is_ascii(s):
370*8975f5c5SAndroid Build Coastguard Worker    return all(ord(c) < 128 for c in s)
371*8975f5c5SAndroid Build Coastguard Worker
372*8975f5c5SAndroid Build Coastguard Worker
373*8975f5c5SAndroid Build Coastguard Workerdef _CheckNonAsciiInSourceFiles(input_api, output_api):
374*8975f5c5SAndroid Build Coastguard Worker    """Forbids non-ascii characters in source files."""
375*8975f5c5SAndroid Build Coastguard Worker
376*8975f5c5SAndroid Build Coastguard Worker    def implementation_and_headers(f):
377*8975f5c5SAndroid Build Coastguard Worker        return input_api.FilterSourceFile(
378*8975f5c5SAndroid Build Coastguard Worker            f, files_to_check=(r'.+%s' % _IMPLEMENTATION_AND_HEADER_EXTENSIONS,))
379*8975f5c5SAndroid Build Coastguard Worker
380*8975f5c5SAndroid Build Coastguard Worker    files_with_non_ascii = []
381*8975f5c5SAndroid Build Coastguard Worker    for f in input_api.AffectedSourceFiles(implementation_and_headers):
382*8975f5c5SAndroid Build Coastguard Worker        for (num, line) in f.ChangedContents():
383*8975f5c5SAndroid Build Coastguard Worker            if not is_ascii(line):
384*8975f5c5SAndroid Build Coastguard Worker                files_with_non_ascii.append("%s: %s" % (f, line))
385*8975f5c5SAndroid Build Coastguard Worker                break
386*8975f5c5SAndroid Build Coastguard Worker
387*8975f5c5SAndroid Build Coastguard Worker    if files_with_non_ascii:
388*8975f5c5SAndroid Build Coastguard Worker        return [
389*8975f5c5SAndroid Build Coastguard Worker            output_api.PresubmitError(
390*8975f5c5SAndroid Build Coastguard Worker                'Non-ASCII characters in source files.',
391*8975f5c5SAndroid Build Coastguard Worker                items=sorted(files_with_non_ascii),
392*8975f5c5SAndroid Build Coastguard Worker                long_text='Non-ASCII characters are forbidden in ANGLE source files.\n'
393*8975f5c5SAndroid Build Coastguard Worker                'Please remove non-ASCII characters from these files.')
394*8975f5c5SAndroid Build Coastguard Worker        ]
395*8975f5c5SAndroid Build Coastguard Worker    return []
396*8975f5c5SAndroid Build Coastguard Worker
397*8975f5c5SAndroid Build Coastguard Worker
398*8975f5c5SAndroid Build Coastguard Workerdef _CheckCommentBeforeTestInTestFiles(input_api, output_api):
399*8975f5c5SAndroid Build Coastguard Worker    """Require a comment before TEST_P() and other tests."""
400*8975f5c5SAndroid Build Coastguard Worker
401*8975f5c5SAndroid Build Coastguard Worker    def test_files(f):
402*8975f5c5SAndroid Build Coastguard Worker        return input_api.FilterSourceFile(
403*8975f5c5SAndroid Build Coastguard Worker            f, files_to_check=(r'^src/tests/.+\.cpp$', r'^src/.+_unittest\.cpp$'))
404*8975f5c5SAndroid Build Coastguard Worker
405*8975f5c5SAndroid Build Coastguard Worker    tests_with_no_comment = []
406*8975f5c5SAndroid Build Coastguard Worker    for f in input_api.AffectedSourceFiles(test_files):
407*8975f5c5SAndroid Build Coastguard Worker        diff = f.GenerateScmDiff()
408*8975f5c5SAndroid Build Coastguard Worker        last_line_was_comment = False
409*8975f5c5SAndroid Build Coastguard Worker        for line in diff.splitlines():
410*8975f5c5SAndroid Build Coastguard Worker            # Skip removed lines
411*8975f5c5SAndroid Build Coastguard Worker            if line.startswith('-'):
412*8975f5c5SAndroid Build Coastguard Worker                continue
413*8975f5c5SAndroid Build Coastguard Worker
414*8975f5c5SAndroid Build Coastguard Worker            new_line_is_comment = line.startswith(' //') or line.startswith('+//')
415*8975f5c5SAndroid Build Coastguard Worker            new_line_is_test_declaration = (
416*8975f5c5SAndroid Build Coastguard Worker                line.startswith('+TEST_P(') or line.startswith('+TEST(') or
417*8975f5c5SAndroid Build Coastguard Worker                line.startswith('+TYPED_TEST('))
418*8975f5c5SAndroid Build Coastguard Worker
419*8975f5c5SAndroid Build Coastguard Worker            if new_line_is_test_declaration and not last_line_was_comment:
420*8975f5c5SAndroid Build Coastguard Worker                tests_with_no_comment.append(line[1:])
421*8975f5c5SAndroid Build Coastguard Worker
422*8975f5c5SAndroid Build Coastguard Worker            last_line_was_comment = new_line_is_comment
423*8975f5c5SAndroid Build Coastguard Worker
424*8975f5c5SAndroid Build Coastguard Worker    if tests_with_no_comment:
425*8975f5c5SAndroid Build Coastguard Worker        return [
426*8975f5c5SAndroid Build Coastguard Worker            output_api.PresubmitError(
427*8975f5c5SAndroid Build Coastguard Worker                'Tests without comment.',
428*8975f5c5SAndroid Build Coastguard Worker                items=sorted(tests_with_no_comment),
429*8975f5c5SAndroid Build Coastguard Worker                long_text='ANGLE requires a comment describing what a test does.')
430*8975f5c5SAndroid Build Coastguard Worker        ]
431*8975f5c5SAndroid Build Coastguard Worker    return []
432*8975f5c5SAndroid Build Coastguard Worker
433*8975f5c5SAndroid Build Coastguard Worker
434*8975f5c5SAndroid Build Coastguard Workerdef _CheckWildcardInTestExpectationFiles(input_api, output_api):
435*8975f5c5SAndroid Build Coastguard Worker    """Require wildcard as API tag (i.e. in foo.bar/*) in expectations when no additional feature is
436*8975f5c5SAndroid Build Coastguard Worker    enabled."""
437*8975f5c5SAndroid Build Coastguard Worker
438*8975f5c5SAndroid Build Coastguard Worker    def expectation_files(f):
439*8975f5c5SAndroid Build Coastguard Worker        return input_api.FilterSourceFile(
440*8975f5c5SAndroid Build Coastguard Worker            f, files_to_check=[r'^src/tests/angle_end2end_tests_expectations.txt$'])
441*8975f5c5SAndroid Build Coastguard Worker
442*8975f5c5SAndroid Build Coastguard Worker    expectation_pattern = re.compile(r'^.*:\s*[a-zA-Z0-9._*]+\/([^ ]*)\s*=.*$')
443*8975f5c5SAndroid Build Coastguard Worker
444*8975f5c5SAndroid Build Coastguard Worker    expectations_without_wildcard = []
445*8975f5c5SAndroid Build Coastguard Worker    for f in input_api.AffectedSourceFiles(expectation_files):
446*8975f5c5SAndroid Build Coastguard Worker        diff = f.GenerateScmDiff()
447*8975f5c5SAndroid Build Coastguard Worker        for line in diff.splitlines():
448*8975f5c5SAndroid Build Coastguard Worker            # Only look at new lines
449*8975f5c5SAndroid Build Coastguard Worker            if not line.startswith('+'):
450*8975f5c5SAndroid Build Coastguard Worker                continue
451*8975f5c5SAndroid Build Coastguard Worker
452*8975f5c5SAndroid Build Coastguard Worker            match = re.match(expectation_pattern, line[1:].strip())
453*8975f5c5SAndroid Build Coastguard Worker            if match is None:
454*8975f5c5SAndroid Build Coastguard Worker                continue
455*8975f5c5SAndroid Build Coastguard Worker
456*8975f5c5SAndroid Build Coastguard Worker            tag = match.group(1)
457*8975f5c5SAndroid Build Coastguard Worker
458*8975f5c5SAndroid Build Coastguard Worker            # The tag is in the following general form:
459*8975f5c5SAndroid Build Coastguard Worker            #
460*8975f5c5SAndroid Build Coastguard Worker            #     FRONTENDAPI_BACKENDAPI[_FEATURE]*
461*8975f5c5SAndroid Build Coastguard Worker            #
462*8975f5c5SAndroid Build Coastguard Worker            # Any part of the above may be a wildcard.  Warn about usage of FRONTEND_BACKENDAPI as
463*8975f5c5SAndroid Build Coastguard Worker            # the tag.  Instead, the backend should be specified before the : and `*` used as the
464*8975f5c5SAndroid Build Coastguard Worker            # tag.  If any additional tags are present, it's a specific expectation that should
465*8975f5c5SAndroid Build Coastguard Worker            # remain specific (and not wildcarded).  NoFixture is an exception as X_Y_NoFixture is
466*8975f5c5SAndroid Build Coastguard Worker            # the generic form of the tags of tests that don't use the fixture.
467*8975f5c5SAndroid Build Coastguard Worker
468*8975f5c5SAndroid Build Coastguard Worker            sections = [section for section in tag.split('_') if section != 'NoFixture']
469*8975f5c5SAndroid Build Coastguard Worker
470*8975f5c5SAndroid Build Coastguard Worker            # Allow '*_...', or 'FRONTENDAPI_*_...'.
471*8975f5c5SAndroid Build Coastguard Worker            if '*' in sections[0] or (len(sections) > 1 and '*' in sections[1]):
472*8975f5c5SAndroid Build Coastguard Worker                continue
473*8975f5c5SAndroid Build Coastguard Worker
474*8975f5c5SAndroid Build Coastguard Worker            # Warn if no additional tags are present
475*8975f5c5SAndroid Build Coastguard Worker            if len(sections) == 2:
476*8975f5c5SAndroid Build Coastguard Worker                expectations_without_wildcard.append(line[1:])
477*8975f5c5SAndroid Build Coastguard Worker
478*8975f5c5SAndroid Build Coastguard Worker    if expectations_without_wildcard:
479*8975f5c5SAndroid Build Coastguard Worker        return [
480*8975f5c5SAndroid Build Coastguard Worker            output_api.PresubmitError(
481*8975f5c5SAndroid Build Coastguard Worker                'Use wildcard in API tags (after /) in angle_end2end_tests_expectations.txt.',
482*8975f5c5SAndroid Build Coastguard Worker                items=expectations_without_wildcard,
483*8975f5c5SAndroid Build Coastguard Worker                long_text="""ANGLE prefers end2end expections to use the following form:
484*8975f5c5SAndroid Build Coastguard Worker
485*8975f5c5SAndroid Build Coastguard Worker1234 MAC OPENGL : Foo.Bar/* = SKIP
486*8975f5c5SAndroid Build Coastguard Worker
487*8975f5c5SAndroid Build Coastguard Workerinstead of:
488*8975f5c5SAndroid Build Coastguard Worker
489*8975f5c5SAndroid Build Coastguard Worker1234 MAC OPENGL : Foo.Bar/ES2_OpenGL = SKIP
490*8975f5c5SAndroid Build Coastguard Worker1234 MAC OPENGL : Foo.Bar/ES3_OpenGL = SKIP
491*8975f5c5SAndroid Build Coastguard Worker
492*8975f5c5SAndroid Build Coastguard WorkerExpectatations that are specific (such as Foo.Bar/ES2_OpenGL_SomeFeature) are allowed.""")
493*8975f5c5SAndroid Build Coastguard Worker        ]
494*8975f5c5SAndroid Build Coastguard Worker    return []
495*8975f5c5SAndroid Build Coastguard Worker
496*8975f5c5SAndroid Build Coastguard Worker
497*8975f5c5SAndroid Build Coastguard Workerdef _CheckShaderVersionInShaderLangHeader(input_api, output_api):
498*8975f5c5SAndroid Build Coastguard Worker    """Requires an update to ANGLE_SH_VERSION when ShaderLang.h or ShaderVars.h change."""
499*8975f5c5SAndroid Build Coastguard Worker
500*8975f5c5SAndroid Build Coastguard Worker    def headers(f):
501*8975f5c5SAndroid Build Coastguard Worker        return input_api.FilterSourceFile(
502*8975f5c5SAndroid Build Coastguard Worker            f,
503*8975f5c5SAndroid Build Coastguard Worker            files_to_check=(r'^include/GLSLANG/ShaderLang.h$', r'^include/GLSLANG/ShaderVars.h$'))
504*8975f5c5SAndroid Build Coastguard Worker
505*8975f5c5SAndroid Build Coastguard Worker    headers_changed = input_api.AffectedSourceFiles(headers)
506*8975f5c5SAndroid Build Coastguard Worker    if len(headers_changed) == 0:
507*8975f5c5SAndroid Build Coastguard Worker        return []
508*8975f5c5SAndroid Build Coastguard Worker
509*8975f5c5SAndroid Build Coastguard Worker    # Skip this check for reverts and rolls.  Unlike
510*8975f5c5SAndroid Build Coastguard Worker    # _CheckCommitMessageFormatting, relands are still checked because the
511*8975f5c5SAndroid Build Coastguard Worker    # original change might have incremented the version correctly, but the
512*8975f5c5SAndroid Build Coastguard Worker    # rebase over a new version could accidentally remove that (because another
513*8975f5c5SAndroid Build Coastguard Worker    # change in the meantime identically incremented it).
514*8975f5c5SAndroid Build Coastguard Worker    git_output = input_api.change.DescriptionText()
515*8975f5c5SAndroid Build Coastguard Worker    multiple_commits = _SplitIntoMultipleCommits(git_output)
516*8975f5c5SAndroid Build Coastguard Worker    for commit in multiple_commits:
517*8975f5c5SAndroid Build Coastguard Worker        if commit.startswith('Revert') or commit.startswith('Roll'):
518*8975f5c5SAndroid Build Coastguard Worker            return []
519*8975f5c5SAndroid Build Coastguard Worker
520*8975f5c5SAndroid Build Coastguard Worker    diffs = '\n'.join(f.GenerateScmDiff() for f in headers_changed)
521*8975f5c5SAndroid Build Coastguard Worker    versions = dict(re.findall(r'^([-+])#define ANGLE_SH_VERSION\s+(\d+)', diffs, re.M))
522*8975f5c5SAndroid Build Coastguard Worker
523*8975f5c5SAndroid Build Coastguard Worker    if len(versions) != 2 or int(versions['+']) <= int(versions['-']):
524*8975f5c5SAndroid Build Coastguard Worker        return [
525*8975f5c5SAndroid Build Coastguard Worker            output_api.PresubmitError(
526*8975f5c5SAndroid Build Coastguard Worker                'ANGLE_SH_VERSION should be incremented when ShaderLang.h or ShaderVars.h change.',
527*8975f5c5SAndroid Build Coastguard Worker            )
528*8975f5c5SAndroid Build Coastguard Worker        ]
529*8975f5c5SAndroid Build Coastguard Worker    return []
530*8975f5c5SAndroid Build Coastguard Worker
531*8975f5c5SAndroid Build Coastguard Worker
532*8975f5c5SAndroid Build Coastguard Workerdef _CheckGClientExists(input_api, output_api, search_limit=None):
533*8975f5c5SAndroid Build Coastguard Worker    presubmit_path = pathlib.Path(input_api.PresubmitLocalPath())
534*8975f5c5SAndroid Build Coastguard Worker
535*8975f5c5SAndroid Build Coastguard Worker    for current_path in itertools.chain([presubmit_path], presubmit_path.parents):
536*8975f5c5SAndroid Build Coastguard Worker        gclient_path = current_path.joinpath('.gclient')
537*8975f5c5SAndroid Build Coastguard Worker        if gclient_path.exists() and gclient_path.is_file():
538*8975f5c5SAndroid Build Coastguard Worker            return []
539*8975f5c5SAndroid Build Coastguard Worker        # search_limit parameter is used in unit tests to prevent searching all the way to root
540*8975f5c5SAndroid Build Coastguard Worker        # directory for reproducibility.
541*8975f5c5SAndroid Build Coastguard Worker        elif search_limit != None and current_path == search_limit:
542*8975f5c5SAndroid Build Coastguard Worker            break
543*8975f5c5SAndroid Build Coastguard Worker
544*8975f5c5SAndroid Build Coastguard Worker    return [
545*8975f5c5SAndroid Build Coastguard Worker        output_api.PresubmitError(
546*8975f5c5SAndroid Build Coastguard Worker            'Missing .gclient file.',
547*8975f5c5SAndroid Build Coastguard Worker            long_text=textwrap.fill(
548*8975f5c5SAndroid Build Coastguard Worker                width=100,
549*8975f5c5SAndroid Build Coastguard Worker                text='The top level directory of the repository must contain a .gclient file.'
550*8975f5c5SAndroid Build Coastguard Worker                ' You can follow the steps outlined in the link below to get set up for ANGLE'
551*8975f5c5SAndroid Build Coastguard Worker                ' development:') +
552*8975f5c5SAndroid Build Coastguard Worker            '\n\nhttps://chromium.googlesource.com/angle/angle/+/refs/heads/main/doc/DevSetup.md')
553*8975f5c5SAndroid Build Coastguard Worker    ]
554*8975f5c5SAndroid Build Coastguard Worker
555*8975f5c5SAndroid Build Coastguard Workerdef CheckChangeOnUpload(input_api, output_api):
556*8975f5c5SAndroid Build Coastguard Worker    results = []
557*8975f5c5SAndroid Build Coastguard Worker    results.extend(input_api.canned_checks.CheckForCommitObjects(input_api, output_api))
558*8975f5c5SAndroid Build Coastguard Worker    results.extend(_CheckTabsInSourceFiles(input_api, output_api))
559*8975f5c5SAndroid Build Coastguard Worker    results.extend(_CheckNonAsciiInSourceFiles(input_api, output_api))
560*8975f5c5SAndroid Build Coastguard Worker    results.extend(_CheckCommentBeforeTestInTestFiles(input_api, output_api))
561*8975f5c5SAndroid Build Coastguard Worker    results.extend(_CheckWildcardInTestExpectationFiles(input_api, output_api))
562*8975f5c5SAndroid Build Coastguard Worker    results.extend(_CheckShaderVersionInShaderLangHeader(input_api, output_api))
563*8975f5c5SAndroid Build Coastguard Worker    results.extend(_CheckCodeGeneration(input_api, output_api))
564*8975f5c5SAndroid Build Coastguard Worker    results.extend(_CheckChangeHasBugField(input_api, output_api))
565*8975f5c5SAndroid Build Coastguard Worker    results.extend(input_api.canned_checks.CheckChangeHasDescription(input_api, output_api))
566*8975f5c5SAndroid Build Coastguard Worker    results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
567*8975f5c5SAndroid Build Coastguard Worker    results.extend(_CheckExportValidity(input_api, output_api))
568*8975f5c5SAndroid Build Coastguard Worker    results.extend(
569*8975f5c5SAndroid Build Coastguard Worker        input_api.canned_checks.CheckPatchFormatted(
570*8975f5c5SAndroid Build Coastguard Worker            input_api, output_api, result_factory=output_api.PresubmitError))
571*8975f5c5SAndroid Build Coastguard Worker    results.extend(_CheckCommitMessageFormatting(input_api, output_api))
572*8975f5c5SAndroid Build Coastguard Worker    results.extend(_CheckGClientExists(input_api, output_api))
573*8975f5c5SAndroid Build Coastguard Worker
574*8975f5c5SAndroid Build Coastguard Worker    return results
575*8975f5c5SAndroid Build Coastguard Worker
576*8975f5c5SAndroid Build Coastguard Worker
577*8975f5c5SAndroid Build Coastguard Workerdef CheckChangeOnCommit(input_api, output_api):
578*8975f5c5SAndroid Build Coastguard Worker    return CheckChangeOnUpload(input_api, output_api)
579