1# Copyright 2020 The ChromiumOS Authors 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5# Collection of helper functions that can be used to compose presubmit 6# checks. For cross repo usage import and compose into presubmit hooks 7# as follows: 8# 9# import sys 10# sys.path.insert(1, 'config/presubmit') 11# 12# import presubmits 13# 14# def CheckChangeOnUpload(input_api, output_api): 15# results = [] 16# results.extend(presubmits.CheckGenerated(input_api, output_api)) 17# # ... other checks 18# return results 19# 20# Note that this expects a config symlink to exist that points at this repo. 21# 22# For more details on the depot tools provided presubmit API see: 23# http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts 24 25def CheckScript(input_api, output_api, script, msg=None): 26 """Invokes a script with the result per unix error codes. 27 28 Invokes a shell script with the result following the unix error 29 code result of the script. 30 31 Args: 32 input_api: InputApi, provides information about the change. 33 output_api: OutputApi, provides the mechanism for returning a response. 34 script: str, script to invoke. 35 msg: str, message to use when failure. 36 37 Returns: 38 list of PresubmitError, or empty list if no errors. 39 """ 40 results = [] 41 if input_api.subprocess.call(script, shell=True): 42 if not msg: 43 msg = 'Error: {} failed. Please fix and try again.'.format(script) 44 results.append(output_api.PresubmitError(msg)) 45 return results 46 47 48def CheckChecker(input_api, output_api, 49 checker_cmd='./config/payload_utils/checker.py', 50 program='./program/generated/config.jsonproto', 51 project='./generated/config.jsonproto', 52 factory_dir='./factory'): 53 """Runs the checker.py script as a presubmit check. 54 55 Runs the checker script as a presubmit check checking for successful 56 exit. 57 58 Args: 59 input_api: InputApi, provides information about the change. 60 output_api: OutputApi, provides the mechanism for returning a response. 61 program: str, path to the program config json proto. 62 project: str, path to the project config json proto. 63 factory_dir: str, path to the project factory config dir. 64 65 Returns: 66 list of PresubmitError, or empty list if no errors. 67 """ 68 results = [] 69 70 cmd = [checker_cmd] 71 cmd.extend(['--program', program]) 72 cmd.extend(['--project', project]) 73 cmd.extend(['--factory_dir', factory_dir]) 74 if input_api.subprocess.call(cmd): 75 msg = 'Error: config checker checker.py failed. Please fix and try again.' 76 results.append(output_api.PresubmitError(msg)) 77 78 return results 79 80 81def CheckGenerated(input_api, output_api, cmd='./generate.sh'): 82 """Runs a script as a presubmit check. 83 84 Runs a script as a presubmit check checking for successful exit and no 85 diff generated. 86 87 Args: 88 input_api: InputApi, provides information about the change. 89 output_api: OutputApi, provides the mechanism for returning a response. 90 cmd: String, command to run as the "generate" script. 91 92 Returns: 93 list of PresubmitError, or empty list if no errors. 94 """ 95 results = [] 96 97 if input_api.subprocess.call( 98 cmd, 99 shell=True): 100 msg = 'Error: {} failed. Please fix and try again.'.format(cmd) 101 results.append(output_api.PresubmitError(msg)) 102 elif input_api.subprocess.call( 103 'git diff --exit-code', 104 shell=True, 105 stdout=input_api.subprocess.PIPE, 106 stderr=input_api.subprocess.PIPE): 107 msg = ('Error: Running {} produced a diff. Please run the script, amend ' 108 'your changes, and try again.'.format(cmd)) 109 results.append(output_api.PresubmitError(msg)) 110 111 return results 112 113 114_DEFAULT_FAILURE_MESSAGE=( 115 'Error: Running gen_config produced a diff. Please ' 116 'resync your chromiumos checkout, run the gen_config ' 117 'script, amend your changes, and try again. Repos ' 118 'needing resyncing could include: ' 119 'chromiumos/config, ' 120 'chromeos/program/<your program>, ' 121 'chromeos/project/<your program>/<your project>' 122) 123 124def CheckGenConfig(input_api, output_api, 125 config_file='config.star', 126 gen_config_cmd='./config/bin/gen_config', 127 failure_message=_DEFAULT_FAILURE_MESSAGE): 128 """Runs a gen_config as a presubmit check. 129 130 Runs the gen_config script as a presubmit check checking for successful 131 exit and no diff generated. 132 133 Args: 134 input_api: InputApi, provides information about the change. 135 output_api: OutputApi, provides the mechanism for returning a response. 136 config_file: str, file to generate from, defaults to config.star. 137 gen_config_cmd: str, location of gen_config script 138 failure_message: str, message to use when gen_config produces a diff. 139 140 Returns: 141 list of PresubmitError, or empty list if no errors. 142 """ 143 results = [] 144 145 # TODO: get on path for recipes, for now expect to find at 146 # config/bin/gen_config 147 if input_api.subprocess.call([gen_config_cmd, config_file]): 148 msg = 'Error: gen_config failed. Please fix and try again.' 149 results.append(output_api.PresubmitError(msg)) 150 elif input_api.subprocess.call(['git', 'diff', '--exit-code']): 151 results.append(output_api.PresubmitError(failure_message)) 152 153 return results 154 155 156def CheckUntracked(input_api, output_api): 157 """Looks for untracked files in the repo and fails if found. 158 159 Args: 160 input_api: InputApi, provides information about the change. 161 output_api: OutputApi, provides the mechanism for returning a response. 162 163 Returns: 164 list of PresubmitError, or empty list if no errors. 165 """ 166 results = [] 167 cmd = ['git', 'ls-files', '--others', '--exclude-standard'] 168 out = input_api.subprocess.capture(cmd) 169 if out: 170 msg = 'Found untracked files:\n{}'.format(out) 171 results.append(output_api.PresubmitPromptWarning(msg)) 172 173 return results 174