| 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 |