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 |