Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(337)

Side by Side Diff: presubmit_support.py

Issue 6646009: update git-cl for OWNERS file support via .git/hooks/pre-cl-* (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: clean up after running owners-related git-cl tests Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « presubmit_canned_checks.py ('k') | tests/presubmit_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Enables directory-specific presubmit checks to run at upload and/or commit. 6 """Enables directory-specific presubmit checks to run at upload and/or commit.
7 """ 7 """
8 8
9 __version__ = '1.3.5' 9 __version__ = '1.3.5'
10 10
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 def IsFatal(self): 147 def IsFatal(self):
148 """An error that is fatal stops g4 mail/submit immediately, i.e. before 148 """An error that is fatal stops g4 mail/submit immediately, i.e. before
149 other presubmit scripts are run. 149 other presubmit scripts are run.
150 """ 150 """
151 return False 151 return False
152 152
153 def ShouldPrompt(self): 153 def ShouldPrompt(self):
154 """Whether this presubmit result should result in a prompt warning.""" 154 """Whether this presubmit result should result in a prompt warning."""
155 return False 155 return False
156 156
157 def IsMessage(self):
158 """Whether this result contains anything needing to be displayed."""
159 return True
160
161 class PresubmitAddText(PresubmitResult): 157 class PresubmitAddText(PresubmitResult):
162 """Propagates a line of text back to the caller.""" 158 """Propagates a line of text back to the caller."""
163 def __init__(self, message, items=None, long_text=''): 159 def __init__(self, message, items=None, long_text=''):
164 super(OutputApi.PresubmitAddText, self).__init__("ADD: " + message, 160 super(OutputApi.PresubmitAddText, self).__init__("ADD: " + message,
165 items, long_text) 161 items, long_text)
166 162
167 def IsMessage(self):
168 return False
169
170 class PresubmitError(PresubmitResult): 163 class PresubmitError(PresubmitResult):
171 """A hard presubmit error.""" 164 """A hard presubmit error."""
172 def IsFatal(self): 165 def IsFatal(self):
173 return True 166 return True
174 167
175 class PresubmitPromptWarning(PresubmitResult): 168 class PresubmitPromptWarning(PresubmitResult):
176 """An warning that prompts the user if they want to continue.""" 169 """An warning that prompts the user if they want to continue."""
177 def ShouldPrompt(self): 170 def ShouldPrompt(self):
178 return True 171 return True
179 172
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 r".*\bRelease[\\\/].*", 213 r".*\bRelease[\\\/].*",
221 r".*\bxcodebuild[\\\/].*", 214 r".*\bxcodebuild[\\\/].*",
222 r".*\bsconsbuild[\\\/].*", 215 r".*\bsconsbuild[\\\/].*",
223 # All caps files like README and LICENCE. 216 # All caps files like README and LICENCE.
224 r".*\b[A-Z0-9_]{2,}$", 217 r".*\b[A-Z0-9_]{2,}$",
225 # SCM (can happen in dual SCM configuration). (Slightly over aggressive) 218 # SCM (can happen in dual SCM configuration). (Slightly over aggressive)
226 r"(|.*[\\\/])\.git[\\\/].*", 219 r"(|.*[\\\/])\.git[\\\/].*",
227 r"(|.*[\\\/])\.svn[\\\/].*", 220 r"(|.*[\\\/])\.svn[\\\/].*",
228 ) 221 )
229 222
230 # TODO(dpranke): Update callers to pass in is_tbr, host_url, remove 223 def __init__(self, change, presubmit_path, is_committing, tbr, host_url=None):
231 # default arguments.
232 def __init__(self, change, presubmit_path, is_committing, is_tbr=False,
233 host_url='http://codereview.chromium.org'):
234 """Builds an InputApi object. 224 """Builds an InputApi object.
235 225
236 Args: 226 Args:
237 change: A presubmit.Change object. 227 change: A presubmit.Change object.
238 presubmit_path: The path to the presubmit script being processed. 228 presubmit_path: The path to the presubmit script being processed.
239 is_committing: True if the change is about to be committed. 229 is_committing: True if the change is about to be committed.
230 tbr: True if '--tbr' was passed to skip any reviewer/owner checks
231 host_url: scheme, host, and path of rietveld instance
240 """ 232 """
241 # Version number of the presubmit_support script. 233 # Version number of the presubmit_support script.
242 self.version = [int(x) for x in __version__.split('.')] 234 self.version = [int(x) for x in __version__.split('.')]
243 self.change = change 235 self.change = change
244 self.host_url = host_url 236 self.host_url = host_url
245 self.is_committing = is_committing 237 self.is_committing = is_committing
246 self.is_tbr = is_tbr 238 self.tbr = tbr
239 self.host_url = host_url or 'http://codereview.chromium.org'
247 240
248 # We expose various modules and functions as attributes of the input_api 241 # We expose various modules and functions as attributes of the input_api
249 # so that presubmit scripts don't have to import them. 242 # so that presubmit scripts don't have to import them.
250 self.basename = os.path.basename 243 self.basename = os.path.basename
251 self.cPickle = cPickle 244 self.cPickle = cPickle
252 self.cStringIO = cStringIO 245 self.cStringIO = cStringIO
253 self.json = json 246 self.json = json
254 self.os_path = os.path 247 self.os_path = os.path
255 self.pickle = pickle 248 self.pickle = pickle
256 self.marshal = marshal 249 self.marshal = marshal
(...skipping 671 matching lines...) Expand 10 before | Expand all | Expand 10 after
928 results += executer.ExecPresubmitScript(presubmit_script) 921 results += executer.ExecPresubmitScript(presubmit_script)
929 922
930 slaves = list(set(results)) 923 slaves = list(set(results))
931 if slaves and verbose: 924 if slaves and verbose:
932 output_stream.write(', '.join(slaves)) 925 output_stream.write(', '.join(slaves))
933 output_stream.write('\n') 926 output_stream.write('\n')
934 return slaves 927 return slaves
935 928
936 929
937 class PresubmitExecuter(object): 930 class PresubmitExecuter(object):
938 def __init__(self, change, committing): 931 def __init__(self, change, committing, tbr, host_url):
939 """ 932 """
940 Args: 933 Args:
941 change: The Change object. 934 change: The Change object.
942 committing: True if 'gcl commit' is running, False if 'gcl upload' is. 935 committing: True if 'gcl commit' is running, False if 'gcl upload' is.
936 tbr: True if '--tbr' was passed to skip any reviewer/owner checks
937 host_url: scheme, host, and path of rietveld instance
938 (or None for default)
943 """ 939 """
944 self.change = change 940 self.change = change
945 self.committing = committing 941 self.committing = committing
942 self.tbr = tbr
943 self.host_url = host_url
946 944
947 def ExecPresubmitScript(self, script_text, presubmit_path): 945 def ExecPresubmitScript(self, script_text, presubmit_path):
948 """Executes a single presubmit script. 946 """Executes a single presubmit script.
949 947
950 Args: 948 Args:
951 script_text: The text of the presubmit script. 949 script_text: The text of the presubmit script.
952 presubmit_path: The path to the presubmit file (this will be reported via 950 presubmit_path: The path to the presubmit file (this will be reported via
953 input_api.PresubmitLocalPath()). 951 input_api.PresubmitLocalPath()).
954 952
955 Return: 953 Return:
956 A list of result objects, empty if no problems. 954 A list of result objects, empty if no problems.
957 """ 955 """
958 956
959 # Change to the presubmit file's directory to support local imports. 957 # Change to the presubmit file's directory to support local imports.
960 main_path = os.getcwd() 958 main_path = os.getcwd()
961 os.chdir(os.path.dirname(presubmit_path)) 959 os.chdir(os.path.dirname(presubmit_path))
962 960
963 # Load the presubmit script into context. 961 # Load the presubmit script into context.
964 input_api = InputApi(self.change, presubmit_path, self.committing) 962 input_api = InputApi(self.change, presubmit_path, self.committing,
963 self.tbr, self.host_url)
965 context = {} 964 context = {}
966 exec script_text in context 965 exec script_text in context
967 966
968 # These function names must change if we make substantial changes to 967 # These function names must change if we make substantial changes to
969 # the presubmit API that are not backwards compatible. 968 # the presubmit API that are not backwards compatible.
970 if self.committing: 969 if self.committing:
971 function_name = 'CheckChangeOnCommit' 970 function_name = 'CheckChangeOnCommit'
972 else: 971 else:
973 function_name = 'CheckChangeOnUpload' 972 function_name = 'CheckChangeOnUpload'
974 if function_name in context: 973 if function_name in context:
(...skipping 10 matching lines...) Expand all
985 raise exceptions.RuntimeError( 984 raise exceptions.RuntimeError(
986 'All presubmit results must be of types derived from ' 985 'All presubmit results must be of types derived from '
987 'output_api.PresubmitResult') 986 'output_api.PresubmitResult')
988 else: 987 else:
989 result = () # no error since the script doesn't care about current event. 988 result = () # no error since the script doesn't care about current event.
990 989
991 # Return the process to the original working directory. 990 # Return the process to the original working directory.
992 os.chdir(main_path) 991 os.chdir(main_path)
993 return result 992 return result
994 993
995 994 # TODO(dpranke): make all callers pass in tbr, host_url?
996 def DoPresubmitChecks(change, 995 def DoPresubmitChecks(change,
997 committing, 996 committing,
998 verbose, 997 verbose,
999 output_stream, 998 output_stream,
1000 input_stream, 999 input_stream,
1001 default_presubmit, 1000 default_presubmit,
1002 may_prompt): 1001 may_prompt,
1002 tbr=False,
1003 host_url=None):
1003 """Runs all presubmit checks that apply to the files in the change. 1004 """Runs all presubmit checks that apply to the files in the change.
1004 1005
1005 This finds all PRESUBMIT.py files in directories enclosing the files in the 1006 This finds all PRESUBMIT.py files in directories enclosing the files in the
1006 change (up to the repository root) and calls the relevant entrypoint function 1007 change (up to the repository root) and calls the relevant entrypoint function
1007 depending on whether the change is being committed or uploaded. 1008 depending on whether the change is being committed or uploaded.
1008 1009
1009 Prints errors, warnings and notifications. Prompts the user for warnings 1010 Prints errors, warnings and notifications. Prompts the user for warnings
1010 when needed. 1011 when needed.
1011 1012
1012 Args: 1013 Args:
1013 change: The Change object. 1014 change: The Change object.
1014 committing: True if 'gcl commit' is running, False if 'gcl upload' is. 1015 committing: True if 'gcl commit' is running, False if 'gcl upload' is.
1015 verbose: Prints debug info. 1016 verbose: Prints debug info.
1016 output_stream: A stream to write output from presubmit tests to. 1017 output_stream: A stream to write output from presubmit tests to.
1017 input_stream: A stream to read input from the user. 1018 input_stream: A stream to read input from the user.
1018 default_presubmit: A default presubmit script to execute in any case. 1019 default_presubmit: A default presubmit script to execute in any case.
1019 may_prompt: Enable (y/n) questions on warning or error. 1020 may_prompt: Enable (y/n) questions on warning or error.
1021 tbr: was --tbr specified to skip any reviewer/owner checks?
1022 host_url: scheme, host, and port of host to use for rietveld-related
1023 checks
1020 1024
1021 Warning: 1025 Warning:
1022 If may_prompt is true, output_stream SHOULD be sys.stdout and input_stream 1026 If may_prompt is true, output_stream SHOULD be sys.stdout and input_stream
1023 SHOULD be sys.stdin. 1027 SHOULD be sys.stdin.
1024 1028
1025 Return: 1029 Return:
1026 True if execution can continue, False if not. 1030 True if execution can continue, False if not.
1027 """ 1031 """
1028 print "Running presubmit hooks..." 1032 print "Running presubmit hooks..."
1029 start_time = time.time() 1033 start_time = time.time()
1030 presubmit_files = ListRelevantPresubmitFiles(change.AbsoluteLocalPaths(True), 1034 presubmit_files = ListRelevantPresubmitFiles(change.AbsoluteLocalPaths(True),
1031 change.RepositoryRoot()) 1035 change.RepositoryRoot())
1032 if not presubmit_files and verbose: 1036 if not presubmit_files and verbose:
1033 output_stream.write("Warning, no presubmit.py found.\n") 1037 output_stream.write("Warning, no presubmit.py found.\n")
1034 results = [] 1038 results = []
1035 executer = PresubmitExecuter(change, committing) 1039 executer = PresubmitExecuter(change, committing, tbr, host_url)
1036 if default_presubmit: 1040 if default_presubmit:
1037 if verbose: 1041 if verbose:
1038 output_stream.write("Running default presubmit script.\n") 1042 output_stream.write("Running default presubmit script.\n")
1039 fake_path = os.path.join(change.RepositoryRoot(), 'PRESUBMIT.py') 1043 fake_path = os.path.join(change.RepositoryRoot(), 'PRESUBMIT.py')
1040 results += executer.ExecPresubmitScript(default_presubmit, fake_path) 1044 results += executer.ExecPresubmitScript(default_presubmit, fake_path)
1041 for filename in presubmit_files: 1045 for filename in presubmit_files:
1042 filename = os.path.abspath(filename) 1046 filename = os.path.abspath(filename)
1043 if verbose: 1047 if verbose:
1044 output_stream.write("Running %s\n" % filename) 1048 output_stream.write("Running %s\n" % filename)
1045 # Accept CRLF presubmit script. 1049 # Accept CRLF presubmit script.
(...skipping 11 matching lines...) Expand all
1057 else: 1061 else:
1058 errors.append(result) 1062 errors.append(result)
1059 1063
1060 error_count = 0 1064 error_count = 0
1061 for name, items in (('Messages', notifications), 1065 for name, items in (('Messages', notifications),
1062 ('Warnings', warnings), 1066 ('Warnings', warnings),
1063 ('ERRORS', errors)): 1067 ('ERRORS', errors)):
1064 if items: 1068 if items:
1065 output_stream.write('** Presubmit %s **\n' % name) 1069 output_stream.write('** Presubmit %s **\n' % name)
1066 for item in items: 1070 for item in items:
1067 if not item.IsMessage():
1068 continue
1069
1070 # Access to a protected member XXX of a client class 1071 # Access to a protected member XXX of a client class
1071 # pylint: disable=W0212 1072 # pylint: disable=W0212
1072 if not item._Handle(output_stream, input_stream, 1073 if not item._Handle(output_stream, input_stream,
1073 may_prompt=False): 1074 may_prompt=False):
1074 error_count += 1 1075 error_count += 1
1075 output_stream.write('\n') 1076 output_stream.write('\n')
1076 1077
1077 total_time = time.time() - start_time 1078 total_time = time.time() - start_time
1078 if total_time > 1.0: 1079 if total_time > 1.0:
1079 print "Presubmit checks took %.1fs to calculate." % total_time 1080 print "Presubmit checks took %.1fs to calculate." % total_time
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
1185 options.commit, 1186 options.commit,
1186 options.verbose, 1187 options.verbose,
1187 sys.stdout, 1188 sys.stdout,
1188 sys.stdin, 1189 sys.stdin,
1189 options.default_presubmit, 1190 options.default_presubmit,
1190 options.may_prompt) 1191 options.may_prompt)
1191 1192
1192 1193
1193 if __name__ == '__main__': 1194 if __name__ == '__main__':
1194 sys.exit(Main(sys.argv)) 1195 sys.exit(Main(sys.argv))
OLDNEW
« no previous file with comments | « presubmit_canned_checks.py ('k') | tests/presubmit_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698