Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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.8.0' | 9 __version__ = '1.8.0' |
| 10 | 10 |
| (...skipping 989 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1000 results.append(p) | 1000 results.append(p) |
| 1001 | 1001 |
| 1002 logging.debug('Presubmit files: %s' % ','.join(results)) | 1002 logging.debug('Presubmit files: %s' % ','.join(results)) |
| 1003 return results | 1003 return results |
| 1004 | 1004 |
| 1005 | 1005 |
| 1006 class GetTrySlavesExecuter(object): | 1006 class GetTrySlavesExecuter(object): |
| 1007 @staticmethod | 1007 @staticmethod |
| 1008 def ExecPresubmitScript(script_text, presubmit_path, project, change): | 1008 def ExecPresubmitScript(script_text, presubmit_path, project, change): |
| 1009 """Executes GetPreferredTrySlaves() from a single presubmit script. | 1009 """Executes GetPreferredTrySlaves() from a single presubmit script. |
| 1010 | |
| 1011 This will soon be deprecated and replaced by GetPreferredTryMasters(). | |
| 1010 | 1012 |
| 1011 Args: | 1013 Args: |
| 1012 script_text: The text of the presubmit script. | 1014 script_text: The text of the presubmit script. |
| 1013 presubmit_path: Project script to run. | 1015 presubmit_path: Project script to run. |
| 1014 project: Project name to pass to presubmit script for bot selection. | 1016 project: Project name to pass to presubmit script for bot selection. |
| 1015 | 1017 |
| 1016 Return: | 1018 Return: |
| 1017 A list of try slaves. | 1019 A list of try slaves. |
| 1018 """ | 1020 """ |
| 1019 context = {} | 1021 context = {} |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1067 ) | 1069 ) |
| 1068 | 1070 |
| 1069 # Ensure it's either all old-style or all new-style. | 1071 # Ensure it's either all old-style or all new-style. |
| 1070 if not valid_oldstyle(result) and not valid_newstyle(result): | 1072 if not valid_oldstyle(result) and not valid_newstyle(result): |
| 1071 raise PresubmitFailure( | 1073 raise PresubmitFailure( |
| 1072 'PRESUBMIT.py returned invalid trybot specification!') | 1074 'PRESUBMIT.py returned invalid trybot specification!') |
| 1073 | 1075 |
| 1074 return result | 1076 return result |
| 1075 | 1077 |
| 1076 | 1078 |
| 1079 class GetTryMastersExecuter(object): | |
| 1080 @staticmethod | |
| 1081 def ExecPresubmitScript(script_text, presubmit_path, project, change): | |
| 1082 """Executes GetPreferredTryMasters() from a single presubmit script. | |
| 1083 | |
| 1084 Args: | |
| 1085 script_text: The text of the presubmit script. | |
| 1086 presubmit_path: Project script to run. | |
| 1087 project: Project name to pass to presubmit script for bot selection. | |
| 1088 | |
| 1089 Return: | |
| 1090 A map of try masters to (list of builders or map of builders to set of | |
| 1091 tests). | |
| 1092 """ | |
| 1093 context = {} | |
| 1094 try: | |
| 1095 exec script_text in context | |
| 1096 except Exception, e: | |
| 1097 raise PresubmitFailure('"%s" had an exception.\n%s' | |
| 1098 % (presubmit_path, e)) | |
| 1099 | |
| 1100 function_name = 'GetPreferredTryMasters' | |
| 1101 if function_name not in context: | |
| 1102 return {} | |
| 1103 get_preferred_try_masters = context[function_name] | |
| 1104 function_info = inspect.getargspec(get_preferred_try_masters) | |
|
Paweł Hajdan Jr.
2014/02/27 02:20:24
Since this is new, can we standardize on one signa
Michael Achenbach
2014/02/27 18:35:23
Done.
| |
| 1105 if len(function_info[0]) == 1: | |
| 1106 result = get_preferred_try_masters(project) | |
| 1107 elif len(function_info[0]) == 2: | |
| 1108 result = get_preferred_try_masters(project, change) | |
| 1109 else: | |
| 1110 result = get_preferred_try_masters() | |
| 1111 | |
| 1112 def CheckType(item, t): | |
|
Paweł Hajdan Jr.
2014/02/27 02:20:24
It's not obvious to me how much these type checks
Michael Achenbach
2014/02/27 18:35:23
If presubmit hooks return the wrong formats, it'd
| |
| 1113 if not isinstance(item, t): | |
| 1114 raise PresubmitFailure( | |
| 1115 'Expected a %s, got a %s instead: %s' % | |
| 1116 (str(t), type(item), str(item))) | |
| 1117 | |
| 1118 def CheckString(item): | |
| 1119 if not item: | |
| 1120 raise PresubmitFailure( | |
| 1121 'PRESUBMIT.py returned empty trymaster/builder string.') | |
| 1122 CheckType(item, basestring) | |
| 1123 if item != item.strip(): | |
| 1124 raise PresubmitFailure( | |
| 1125 'Try master/builder names cannot start/end with whitespace') | |
| 1126 if ',' in item: | |
| 1127 raise PresubmitFailure( | |
| 1128 'Do not use \',\' separated master, builder or test names: %s' | |
| 1129 % item) | |
| 1130 | |
| 1131 CheckType(result, dict) | |
| 1132 for (master, builders) in result.iteritems(): | |
| 1133 CheckString(master) | |
| 1134 if isinstance(builders, dict): | |
|
Paweł Hajdan Jr.
2014/02/27 02:20:24
Similarly, since this is new, can we standardize o
Michael Achenbach
2014/02/27 18:35:23
Done.
| |
| 1135 for (builder, tests) in builders.iteritems(): | |
| 1136 CheckString(builder) | |
| 1137 CheckType(tests, set) | |
| 1138 elif isinstance(builders, list): | |
| 1139 for builder in builders: | |
| 1140 CheckString(builder) | |
| 1141 else: | |
| 1142 raise PresubmitFailure( | |
| 1143 'Expected a list, got a %s instead: %s' % | |
| 1144 (type(builders), str(builders))) | |
| 1145 return result | |
| 1146 | |
| 1147 | |
| 1077 def DoGetTrySlaves(change, | 1148 def DoGetTrySlaves(change, |
| 1078 changed_files, | 1149 changed_files, |
| 1079 repository_root, | 1150 repository_root, |
| 1080 default_presubmit, | 1151 default_presubmit, |
| 1081 project, | 1152 project, |
| 1082 verbose, | 1153 verbose, |
| 1083 output_stream): | 1154 output_stream): |
| 1084 """Get the list of try servers from the presubmit scripts. | 1155 """Get the list of try servers from the presubmit scripts (deprecated). |
| 1085 | 1156 |
| 1086 Args: | 1157 Args: |
| 1087 changed_files: List of modified files. | 1158 changed_files: List of modified files. |
| 1088 repository_root: The repository root. | 1159 repository_root: The repository root. |
| 1089 default_presubmit: A default presubmit script to execute in any case. | 1160 default_presubmit: A default presubmit script to execute in any case. |
| 1090 project: Optional name of a project used in selecting trybots. | 1161 project: Optional name of a project used in selecting trybots. |
| 1091 verbose: Prints debug info. | 1162 verbose: Prints debug info. |
| 1092 output_stream: A stream to write debug output to. | 1163 output_stream: A stream to write debug output to. |
| 1093 | 1164 |
| 1094 Return: | 1165 Return: |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 1125 slaves = list(slave_dict.items()) | 1196 slaves = list(slave_dict.items()) |
| 1126 | 1197 |
| 1127 slaves.extend(set(old_style)) | 1198 slaves.extend(set(old_style)) |
| 1128 | 1199 |
| 1129 if slaves and verbose: | 1200 if slaves and verbose: |
| 1130 output_stream.write(', '.join((str(x) for x in slaves))) | 1201 output_stream.write(', '.join((str(x) for x in slaves))) |
| 1131 output_stream.write('\n') | 1202 output_stream.write('\n') |
| 1132 return slaves | 1203 return slaves |
| 1133 | 1204 |
| 1134 | 1205 |
| 1206 def _ExpandBuilders(builders): | |
| 1207 """Expands builders in list format to dict format.""" | |
| 1208 if isinstance(builders, list): | |
|
Paweł Hajdan Jr.
2014/02/27 02:20:24
Why do we need to make a decision based on type he
Michael Achenbach
2014/02/27 18:35:23
This is removed now, since now only dicts are allo
| |
| 1209 return dict((builder, set()) for builder in builders) | |
| 1210 else: | |
| 1211 return builders | |
| 1212 | |
| 1213 | |
| 1214 def _MergeMasters(results, masters): | |
| 1215 """Merges masters into results. | |
|
Paweł Hajdan Jr.
2014/02/27 02:20:24
It's not obvious to me what this does, could you c
Michael Achenbach
2014/02/27 18:35:23
I tried to simplify it and made it a function. The
| |
| 1216 | |
| 1217 Merges with side effects on the original results dict. | |
| 1218 """ | |
| 1219 for (master, builders) in masters.iteritems(): | |
| 1220 if master in results: | |
| 1221 result_builders = results[master] | |
| 1222 for (builder, tests) in _ExpandBuilders(builders).iteritems(): | |
| 1223 if builder in result_builders: | |
| 1224 for test in tests: | |
| 1225 result_builders.add(test) | |
| 1226 else: | |
| 1227 result_builders[builder] = tests | |
| 1228 else: | |
| 1229 results[master] = _ExpandBuilders(builders) | |
| 1230 return results | |
| 1231 | |
| 1232 | |
| 1233 def DoGetTryMasters(change, | |
| 1234 changed_files, | |
| 1235 repository_root, | |
| 1236 default_presubmit, | |
| 1237 project, | |
| 1238 verbose, | |
| 1239 output_stream): | |
| 1240 """Get the list of try masters from the presubmit scripts. | |
| 1241 | |
| 1242 Args: | |
| 1243 changed_files: List of modified files. | |
| 1244 repository_root: The repository root. | |
| 1245 default_presubmit: A default presubmit script to execute in any case. | |
| 1246 project: Optional name of a project used in selecting trybots. | |
| 1247 verbose: Prints debug info. | |
| 1248 output_stream: A stream to write debug output to. | |
| 1249 | |
| 1250 Return: | |
| 1251 Map of try masters to map of builders to set of tests. | |
| 1252 """ | |
| 1253 presubmit_files = ListRelevantPresubmitFiles(changed_files, repository_root) | |
| 1254 if not presubmit_files and verbose: | |
| 1255 output_stream.write("Warning, no presubmit.py found.\n") | |
| 1256 results = {} | |
| 1257 executer = GetTryMastersExecuter() | |
| 1258 | |
| 1259 if default_presubmit: | |
| 1260 if verbose: | |
| 1261 output_stream.write("Running default presubmit script.\n") | |
| 1262 fake_path = os.path.join(repository_root, 'PRESUBMIT.py') | |
| 1263 results = _MergeMasters(results, executer.ExecPresubmitScript( | |
| 1264 default_presubmit, fake_path, project, change)) | |
| 1265 for filename in presubmit_files: | |
| 1266 filename = os.path.abspath(filename) | |
| 1267 if verbose: | |
| 1268 output_stream.write("Running %s\n" % filename) | |
| 1269 # Accept CRLF presubmit script. | |
| 1270 presubmit_script = gclient_utils.FileRead(filename, 'rU') | |
| 1271 results = _MergeMasters(results, executer.ExecPresubmitScript( | |
| 1272 presubmit_script, filename, project, change)) | |
| 1273 | |
| 1274 # Make sets to lists again for later JSON serialization. Add | |
| 1275 # defaulttests where tests are missing. | |
| 1276 for (_, builders) in results.iteritems(): | |
| 1277 for builder in builders: | |
| 1278 builders[builder] = list(builders[builder]) | |
| 1279 if not builders[builder]: | |
| 1280 builders[builder].append('defaulttests') | |
| 1281 | |
| 1282 if results and verbose: | |
| 1283 output_stream.write('%s\n' % str(results)) | |
| 1284 return results | |
| 1285 | |
| 1286 | |
| 1135 class PresubmitExecuter(object): | 1287 class PresubmitExecuter(object): |
| 1136 def __init__(self, change, committing, rietveld_obj, verbose): | 1288 def __init__(self, change, committing, rietveld_obj, verbose): |
| 1137 """ | 1289 """ |
| 1138 Args: | 1290 Args: |
| 1139 change: The Change object. | 1291 change: The Change object. |
| 1140 committing: True if 'gcl commit' is running, False if 'gcl upload' is. | 1292 committing: True if 'gcl commit' is running, False if 'gcl upload' is. |
| 1141 rietveld_obj: rietveld.Rietveld client object. | 1293 rietveld_obj: rietveld.Rietveld client object. |
| 1142 """ | 1294 """ |
| 1143 self.change = change | 1295 self.change = change |
| 1144 self.committing = committing | 1296 self.committing = committing |
| (...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1508 except PresubmitFailure, e: | 1660 except PresubmitFailure, e: |
| 1509 print >> sys.stderr, e | 1661 print >> sys.stderr, e |
| 1510 print >> sys.stderr, 'Maybe your depot_tools is out of date?' | 1662 print >> sys.stderr, 'Maybe your depot_tools is out of date?' |
| 1511 print >> sys.stderr, 'If all fails, contact maruel@' | 1663 print >> sys.stderr, 'If all fails, contact maruel@' |
| 1512 return 2 | 1664 return 2 |
| 1513 | 1665 |
| 1514 | 1666 |
| 1515 if __name__ == '__main__': | 1667 if __name__ == '__main__': |
| 1516 fix_encoding.fix_encoding() | 1668 fix_encoding.fix_encoding() |
| 1517 sys.exit(Main(None)) | 1669 sys.exit(Main(None)) |
| OLD | NEW |