OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2013 The Chromium Authors. All rights reserved. | 2 # Copyright 2013 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 """Closes tree if configured masters have failed tree-closing steps. | 6 """Closes tree if configured masters have failed tree-closing steps. |
7 | 7 |
8 Given a list of masters, gatekeeper_ng will get a list of the latest builds from | 8 Given a list of masters, gatekeeper_ng will get a list of the latest builds from |
9 the specified masters. It then checks if any tree-closing steps have failed, and | 9 the specified masters. It then checks if any tree-closing steps have failed, and |
10 if so closes the tree and emails appropriate parties. Configuration for which | 10 if so closes the tree and emails appropriate parties. Configuration for which |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 tools/chromium-build/+/master/gatekeeper_mailer.py, but the list is | 258 tools/chromium-build/+/master/gatekeeper_mailer.py, but the list is |
259 reproduced here: | 259 reproduced here: |
260 | 260 |
261 %(result)s: 'warning' or 'failure' | 261 %(result)s: 'warning' or 'failure' |
262 %(projectName): 'Chromium', 'Chromium Perf', etc. | 262 %(projectName): 'Chromium', 'Chromium Perf', etc. |
263 %(builder): the builder name | 263 %(builder): the builder name |
264 %(reason): reason for launching the build | 264 %(reason): reason for launching the build |
265 %(revision): build revision | 265 %(revision): build revision |
266 %(buildnumber): buildnumber | 266 %(buildnumber): buildnumber |
267 | 267 |
| 268 'forgive_all' converts all closing_steps to be forgiving_steps. Since |
| 269 forgiving_steps only email sheriffs + watchlist (not the committer), this is a |
| 270 great way to set up experimental or informational builders without spamming |
| 271 people. It is enabled by providing the string 'true'. |
| 272 |
268 The 'comment' key can be put anywhere and is ignored by the parser. | 273 The 'comment' key can be put anywhere and is ignored by the parser. |
269 | 274 |
270 # Python, not JSON. | 275 # Python, not JSON. |
271 { | 276 { |
272 'masters': { | 277 'masters': { |
273 'http://build.chromium.org/p/chromium.win': [ | 278 'http://build.chromium.org/p/chromium.win': [ |
274 { | 279 { |
275 'sheriff_classes': ['sheriff_win'], | 280 'sheriff_classes': ['sheriff_win'], |
276 'tree_notify': ['a_watcher@chromium.org'], | 281 'tree_notify': ['a_watcher@chromium.org'], |
277 'categories': ['win_extra'], | 282 'categories': ['win_extra'], |
(...skipping 24 matching lines...) Expand all Loading... |
302 } | 307 } |
303 } | 308 } |
304 | 309 |
305 In this case, XP Tests (1) would be flattened down to: | 310 In this case, XP Tests (1) would be flattened down to: |
306 closing_steps: ['startup_test', 'win_tests'] | 311 closing_steps: ['startup_test', 'win_tests'] |
307 forgiving_steps: ['archive', 'boot_windows'] | 312 forgiving_steps: ['archive', 'boot_windows'] |
308 tree_notify: ['xp_watchers@chromium.org', 'win_watchers@chromium.org', | 313 tree_notify: ['xp_watchers@chromium.org', 'win_watchers@chromium.org', |
309 'a_watcher@chromium.org'] | 314 'a_watcher@chromium.org'] |
310 sheriff_classes: ['sheriff_win', 'sheriff_win_test', 'sheriff_xp'] | 315 sheriff_classes: ['sheriff_win', 'sheriff_win_test', 'sheriff_xp'] |
311 | 316 |
312 Again, fields are optional and treated as empty lists/sets if not present. | 317 Again, fields are optional and treated as empty lists/sets/strings if not |
| 318 present. |
313 """ | 319 """ |
314 | 320 |
315 # Keys which are allowed in a master or builder section. | 321 # Keys which are allowed in a master or builder section. |
316 master_keys = ['sheriff_classes', 'tree_notify', 'subject_template'] | 322 master_keys = ['forgive_all', 'tree_notify', 'sheriff_classes', |
317 builder_keys = ['forgiving_steps', 'closing_steps', 'tree_notify', | 323 'subject_template'] |
318 'sheriff_classes', 'subject_template'] | 324 builder_keys = ['closing_steps', 'forgiving_steps', 'forgive_all', |
| 325 'sheriff_classes', 'subject_template', 'tree_notify'] |
319 | 326 |
320 | 327 |
321 # These keys are strings instead of sets. Strings can't be merged, | 328 # These keys are strings instead of sets. Strings can't be merged, |
322 # so more specific (master -> category -> builder) strings clobber | 329 # so more specific (master -> category -> builder) strings clobber |
323 # more generic ones. | 330 # more generic ones. |
324 strings = ['subject_template'] | 331 strings = ['forgive_all', 'subject_template'] |
325 | 332 |
326 with open(filename) as f: | 333 with open(filename) as f: |
327 raw_gatekeeper_config = json.load(f) | 334 raw_gatekeeper_config = json.load(f) |
328 | 335 |
329 allowed_keys(raw_gatekeeper_config, 'categories', 'masters') | 336 allowed_keys(raw_gatekeeper_config, 'categories', 'masters') |
330 | 337 |
331 categories = raw_gatekeeper_config.get('categories', {}) | 338 categories = raw_gatekeeper_config.get('categories', {}) |
332 masters = raw_gatekeeper_config.get('masters', {}) | 339 masters = raw_gatekeeper_config.get('masters', {}) |
333 | 340 |
334 for category in categories.values(): | 341 for category in categories.values(): |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
388 gatekeeper_builder[k] |= set(categories[c].get(k, [])) | 395 gatekeeper_builder[k] |= set(categories[c].get(k, [])) |
389 | 396 |
390 # Add in any builder-specific values. | 397 # Add in any builder-specific values. |
391 for k in builder_keys: | 398 for k in builder_keys: |
392 if k in strings: | 399 if k in strings: |
393 if k in builder: | 400 if k in builder: |
394 gatekeeper_builder[k] = builder[k] | 401 gatekeeper_builder[k] = builder[k] |
395 else: | 402 else: |
396 gatekeeper_builder[k] |= set(builder.get(k, [])) | 403 gatekeeper_builder[k] |= set(builder.get(k, [])) |
397 | 404 |
| 405 # Builder postprocessing. |
| 406 if gatekeeper_builder['forgive_all'] == 'true': |
| 407 gatekeeper_builder['forgiving_steps'] |= gatekeeper_builder[ |
| 408 'closing_steps'] |
| 409 gatekeeper_builder['closing_steps'] = set([]) |
| 410 |
398 return gatekeeper_config | 411 return gatekeeper_config |
399 | 412 |
400 | 413 |
401 def parse_sheriff_file(url): | 414 def parse_sheriff_file(url): |
402 """Given a sheriff url, download and parse the appropirate sheriff list.""" | 415 """Given a sheriff url, download and parse the appropirate sheriff list.""" |
403 with closing(urllib2.urlopen(url)) as f: | 416 with closing(urllib2.urlopen(url)) as f: |
404 line = f.readline() | 417 line = f.readline() |
405 usernames_matcher_ = re.compile(r'document.write\(\'([\w, ]+)\'\)') | 418 usernames_matcher_ = re.compile(r'document.write\(\'([\w, ]+)\'\)') |
406 usernames_match = usernames_matcher_.match(line) | 419 usernames_match = usernames_matcher_.match(line) |
407 sheriffs = set() | 420 sheriffs = set() |
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
723 options.disable_domain_filter) | 736 options.disable_domain_filter) |
724 | 737 |
725 if not options.skip_build_db_update: | 738 if not options.skip_build_db_update: |
726 save_build_db(build_db, options.build_db) | 739 save_build_db(build_db, options.build_db) |
727 | 740 |
728 return 0 | 741 return 0 |
729 | 742 |
730 | 743 |
731 if __name__ == '__main__': | 744 if __name__ == '__main__': |
732 sys.exit(main()) | 745 sys.exit(main()) |
OLD | NEW |