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

Side by Side Diff: presubmit_support.py

Issue 6674014: Make git-cl work with OWNERS files in a non .git/hooks/pre-cl-* world (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: rebase to HEAD, minor linting, cleanup, testing, fix post-commit hook 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
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 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 tbr, host_url, remove 223 # TODO(dpranke): Update callers to pass in tbr, host_url, remove
231 # default arguments. 224 # default arguments.
232 def __init__(self, change, presubmit_path, is_committing, tbr=False, 225 def __init__(self, change, presubmit_path, is_committing, tbr, host_url=None):
233 host_url='http://codereview.chromium.org'):
234 """Builds an InputApi object. 226 """Builds an InputApi object.
235 227
236 Args: 228 Args:
237 change: A presubmit.Change object. 229 change: A presubmit.Change object.
238 presubmit_path: The path to the presubmit script being processed. 230 presubmit_path: The path to the presubmit script being processed.
239 is_committing: True if the change is about to be committed. 231 is_committing: True if the change is about to be committed.
232 tbr: True if '--tbr' was passed to skip any reviewer/owner checks
233 host_url: scheme, host, and path of rietveld instance
240 """ 234 """
241 # Version number of the presubmit_support script. 235 # Version number of the presubmit_support script.
242 self.version = [int(x) for x in __version__.split('.')] 236 self.version = [int(x) for x in __version__.split('.')]
243 self.change = change 237 self.change = change
244 self.host_url = host_url 238 self.host_url = host_url
245 self.is_committing = is_committing 239 self.is_committing = is_committing
246 self.tbr = tbr 240 self.tbr = tbr
241 self.host_url = host_url or 'http://codereview.chromium.org'
247 242
248 # We expose various modules and functions as attributes of the input_api 243 # We expose various modules and functions as attributes of the input_api
249 # so that presubmit scripts don't have to import them. 244 # so that presubmit scripts don't have to import them.
250 self.basename = os.path.basename 245 self.basename = os.path.basename
251 self.cPickle = cPickle 246 self.cPickle = cPickle
252 self.cStringIO = cStringIO 247 self.cStringIO = cStringIO
253 self.json = json 248 self.json = json
254 self.os_path = os.path 249 self.os_path = os.path
255 self.pickle = pickle 250 self.pickle = pickle
256 self.marshal = marshal 251 self.marshal = marshal
(...skipping 671 matching lines...) Expand 10 before | Expand all | Expand 10 after
928 results += executer.ExecPresubmitScript(presubmit_script) 923 results += executer.ExecPresubmitScript(presubmit_script)
929 924
930 slaves = list(set(results)) 925 slaves = list(set(results))
931 if slaves and verbose: 926 if slaves and verbose:
932 output_stream.write(', '.join(slaves)) 927 output_stream.write(', '.join(slaves))
933 output_stream.write('\n') 928 output_stream.write('\n')
934 return slaves 929 return slaves
935 930
936 931
937 class PresubmitExecuter(object): 932 class PresubmitExecuter(object):
938 def __init__(self, change, committing): 933 def __init__(self, change, committing, tbr, host_url):
939 """ 934 """
940 Args: 935 Args:
941 change: The Change object. 936 change: The Change object.
942 committing: True if 'gcl commit' is running, False if 'gcl upload' is. 937 committing: True if 'gcl commit' is running, False if 'gcl upload' is.
938 tbr: True if '--tbr' was passed to skip any reviewer/owner checks
939 host_url: scheme, host, and path of rietveld instance
940 (or None for default)
943 """ 941 """
944 self.change = change 942 self.change = change
945 self.committing = committing 943 self.committing = committing
944 self.tbr = tbr
945 self.host_url = host_url
946 946
947 def ExecPresubmitScript(self, script_text, presubmit_path): 947 def ExecPresubmitScript(self, script_text, presubmit_path):
948 """Executes a single presubmit script. 948 """Executes a single presubmit script.
949 949
950 Args: 950 Args:
951 script_text: The text of the presubmit script. 951 script_text: The text of the presubmit script.
952 presubmit_path: The path to the presubmit file (this will be reported via 952 presubmit_path: The path to the presubmit file (this will be reported via
953 input_api.PresubmitLocalPath()). 953 input_api.PresubmitLocalPath()).
954 954
955 Return: 955 Return:
956 A list of result objects, empty if no problems. 956 A list of result objects, empty if no problems.
957 """ 957 """
958 958
959 # Change to the presubmit file's directory to support local imports. 959 # Change to the presubmit file's directory to support local imports.
960 main_path = os.getcwd() 960 main_path = os.getcwd()
961 os.chdir(os.path.dirname(presubmit_path)) 961 os.chdir(os.path.dirname(presubmit_path))
962 962
963 # Load the presubmit script into context. 963 # Load the presubmit script into context.
964 input_api = InputApi(self.change, presubmit_path, self.committing) 964 input_api = InputApi(self.change, presubmit_path, self.committing,
965 self.tbr, self.host_url)
965 context = {} 966 context = {}
966 exec script_text in context 967 exec script_text in context
967 968
968 # These function names must change if we make substantial changes to 969 # These function names must change if we make substantial changes to
969 # the presubmit API that are not backwards compatible. 970 # the presubmit API that are not backwards compatible.
970 if self.committing: 971 if self.committing:
971 function_name = 'CheckChangeOnCommit' 972 function_name = 'CheckChangeOnCommit'
972 else: 973 else:
973 function_name = 'CheckChangeOnUpload' 974 function_name = 'CheckChangeOnUpload'
974 if function_name in context: 975 if function_name in context:
(...skipping 10 matching lines...) Expand all
985 raise exceptions.RuntimeError( 986 raise exceptions.RuntimeError(
986 'All presubmit results must be of types derived from ' 987 'All presubmit results must be of types derived from '
987 'output_api.PresubmitResult') 988 'output_api.PresubmitResult')
988 else: 989 else:
989 result = () # no error since the script doesn't care about current event. 990 result = () # no error since the script doesn't care about current event.
990 991
991 # Return the process to the original working directory. 992 # Return the process to the original working directory.
992 os.chdir(main_path) 993 os.chdir(main_path)
993 return result 994 return result
994 995
995 996 # TODO(dpranke): make all callers pass in tbr, host_url?
996 def DoPresubmitChecks(change, 997 def DoPresubmitChecks(change,
997 committing, 998 committing,
998 verbose, 999 verbose,
999 output_stream, 1000 output_stream,
1000 input_stream, 1001 input_stream,
1001 default_presubmit, 1002 default_presubmit,
1002 may_prompt): 1003 may_prompt,
1004 tbr=False,
1005 host_url=None):
1003 """Runs all presubmit checks that apply to the files in the change. 1006 """Runs all presubmit checks that apply to the files in the change.
1004 1007
1005 This finds all PRESUBMIT.py files in directories enclosing the files in the 1008 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 1009 change (up to the repository root) and calls the relevant entrypoint function
1007 depending on whether the change is being committed or uploaded. 1010 depending on whether the change is being committed or uploaded.
1008 1011
1009 Prints errors, warnings and notifications. Prompts the user for warnings 1012 Prints errors, warnings and notifications. Prompts the user for warnings
1010 when needed. 1013 when needed.
1011 1014
1012 Args: 1015 Args:
1013 change: The Change object. 1016 change: The Change object.
1014 committing: True if 'gcl commit' is running, False if 'gcl upload' is. 1017 committing: True if 'gcl commit' is running, False if 'gcl upload' is.
1015 verbose: Prints debug info. 1018 verbose: Prints debug info.
1016 output_stream: A stream to write output from presubmit tests to. 1019 output_stream: A stream to write output from presubmit tests to.
1017 input_stream: A stream to read input from the user. 1020 input_stream: A stream to read input from the user.
1018 default_presubmit: A default presubmit script to execute in any case. 1021 default_presubmit: A default presubmit script to execute in any case.
1019 may_prompt: Enable (y/n) questions on warning or error. 1022 may_prompt: Enable (y/n) questions on warning or error.
1023 tbr: was --tbr specified to skip any reviewer/owner checks?
1024 host_url: scheme, host, and port of host to use for rietveld-related
1025 checks
1020 1026
1021 Warning: 1027 Warning:
1022 If may_prompt is true, output_stream SHOULD be sys.stdout and input_stream 1028 If may_prompt is true, output_stream SHOULD be sys.stdout and input_stream
1023 SHOULD be sys.stdin. 1029 SHOULD be sys.stdin.
1024 1030
1025 Return: 1031 Return:
1026 True if execution can continue, False if not. 1032 True if execution can continue, False if not.
1027 """ 1033 """
1028 print "Running presubmit hooks..." 1034 print "Running presubmit hooks..."
1029 start_time = time.time() 1035 start_time = time.time()
1030 presubmit_files = ListRelevantPresubmitFiles(change.AbsoluteLocalPaths(True), 1036 presubmit_files = ListRelevantPresubmitFiles(change.AbsoluteLocalPaths(True),
1031 change.RepositoryRoot()) 1037 change.RepositoryRoot())
1032 if not presubmit_files and verbose: 1038 if not presubmit_files and verbose:
1033 output_stream.write("Warning, no presubmit.py found.\n") 1039 output_stream.write("Warning, no presubmit.py found.\n")
1034 results = [] 1040 results = []
1035 executer = PresubmitExecuter(change, committing) 1041 executer = PresubmitExecuter(change, committing, tbr, host_url)
1036 if default_presubmit: 1042 if default_presubmit:
1037 if verbose: 1043 if verbose:
1038 output_stream.write("Running default presubmit script.\n") 1044 output_stream.write("Running default presubmit script.\n")
1039 fake_path = os.path.join(change.RepositoryRoot(), 'PRESUBMIT.py') 1045 fake_path = os.path.join(change.RepositoryRoot(), 'PRESUBMIT.py')
1040 results += executer.ExecPresubmitScript(default_presubmit, fake_path) 1046 results += executer.ExecPresubmitScript(default_presubmit, fake_path)
1041 for filename in presubmit_files: 1047 for filename in presubmit_files:
1042 filename = os.path.abspath(filename) 1048 filename = os.path.abspath(filename)
1043 if verbose: 1049 if verbose:
1044 output_stream.write("Running %s\n" % filename) 1050 output_stream.write("Running %s\n" % filename)
1045 # Accept CRLF presubmit script. 1051 # Accept CRLF presubmit script.
(...skipping 11 matching lines...) Expand all
1057 else: 1063 else:
1058 errors.append(result) 1064 errors.append(result)
1059 1065
1060 error_count = 0 1066 error_count = 0
1061 for name, items in (('Messages', notifications), 1067 for name, items in (('Messages', notifications),
1062 ('Warnings', warnings), 1068 ('Warnings', warnings),
1063 ('ERRORS', errors)): 1069 ('ERRORS', errors)):
1064 if items: 1070 if items:
1065 output_stream.write('** Presubmit %s **\n' % name) 1071 output_stream.write('** Presubmit %s **\n' % name)
1066 for item in items: 1072 for item in items:
1067 if not item.IsMessage():
1068 continue
1069
1070 # Access to a protected member XXX of a client class 1073 # Access to a protected member XXX of a client class
1071 # pylint: disable=W0212 1074 # pylint: disable=W0212
1072 if not item._Handle(output_stream, input_stream, 1075 if not item._Handle(output_stream, input_stream,
1073 may_prompt=False): 1076 may_prompt=False):
1074 error_count += 1 1077 error_count += 1
1075 output_stream.write('\n') 1078 output_stream.write('\n')
1076 1079
1077 total_time = time.time() - start_time 1080 total_time = time.time() - start_time
1078 if total_time > 1.0: 1081 if total_time > 1.0:
1079 print "Presubmit checks took %.1fs to calculate." % total_time 1082 print "Presubmit checks took %.1fs to calculate." % total_time
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
1185 options.commit, 1188 options.commit,
1186 options.verbose, 1189 options.verbose,
1187 sys.stdout, 1190 sys.stdout,
1188 sys.stdin, 1191 sys.stdin,
1189 options.default_presubmit, 1192 options.default_presubmit,
1190 options.may_prompt) 1193 options.may_prompt)
1191 1194
1192 1195
1193 if __name__ == '__main__': 1196 if __name__ == '__main__':
1194 sys.exit(Main(sys.argv)) 1197 sys.exit(Main(sys.argv))
OLDNEW
« git_cl/git_cl.py ('K') | « presubmit_canned_checks.py ('k') | tests/presubmit_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698