Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """A command to fetch new baselines from try jobs for the current CL.""" | 5 """A command to fetch new baselines from try jobs for the current CL.""" |
| 6 | 6 |
| 7 import json | 7 import json |
| 8 import logging | 8 import logging |
| 9 import optparse | 9 import optparse |
| 10 | 10 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 56 _log.error(' %s', path) | 56 _log.error(' %s', path) |
| 57 return 1 | 57 return 1 |
| 58 | 58 |
| 59 issue_number = self._get_issue_number() | 59 issue_number = self._get_issue_number() |
| 60 if issue_number is None: | 60 if issue_number is None: |
| 61 _log.error('No issue number for current branch.') | 61 _log.error('No issue number for current branch.') |
| 62 return 1 | 62 return 1 |
| 63 _log.debug('Issue number for current branch: %s', issue_number) | 63 _log.debug('Issue number for current branch: %s', issue_number) |
| 64 | 64 |
| 65 builds = self.git_cl().latest_try_jobs(self._try_bots()) | 65 builds = self.git_cl().latest_try_jobs(self._try_bots()) |
| 66 | 66 self._log_pending_builds(builds) |
| 67 builders_with_pending_builds = self.builders_with_pending_builds(builds) | |
| 68 if builders_with_pending_builds: | |
| 69 _log.info('There are existing pending builds for:') | |
| 70 for builder in sorted(builders_with_pending_builds): | |
| 71 _log.info(' %s', builder) | |
| 72 builders_with_no_results = self.builders_with_no_results(builds) | 67 builders_with_no_results = self.builders_with_no_results(builds) |
| 73 | 68 |
| 74 if options.trigger_jobs and builders_with_no_results: | 69 if options.trigger_jobs: |
| 75 self.trigger_builds(builders_with_no_results) | 70 triggered = self.trigger_builds(builders_with_no_results) |
| 76 _log.info('Please re-run webkit-patch rebaseline-cl once all pending try jobs have finished.') | 71 if triggered: |
|
jeffcarp
2017/05/19 20:21:45
Could these two lines be collapsed?
qyearsley
2017/05/19 20:39:03
Yep, and that would be a bit nicer I think; done.
| |
| 77 return 1 | 72 return 1 |
| 78 | 73 |
| 79 if builders_with_no_results and not options.fill_missing: | 74 if builders_with_no_results and not options.fill_missing: |
| 80 _log.error('The following builders have no results:') | 75 _log.error('The following builders have no results:') |
| 81 for builder in builders_with_no_results: | 76 for builder in builders_with_no_results: |
| 82 _log.error(' %s', builder) | 77 _log.error(' %s', builder) |
| 83 return 1 | 78 return 1 |
| 84 | 79 |
| 85 _log.debug('Getting results for issue %d.', issue_number) | 80 _log.debug('Getting results for issue %d.', issue_number) |
| 86 builds_to_results = self._fetch_results(builds) | 81 builds_to_results = self._fetch_results(builds) |
| 87 if not options.fill_missing and len(builds_to_results) < len(builds): | 82 if not options.fill_missing and len(builds_to_results) < len(builds): |
| 88 return 1 | 83 return 1 |
| 89 | 84 |
| 90 test_baseline_set = TestBaselineSet(tool) | |
| 91 if args: | 85 if args: |
| 92 for test in args: | 86 test_baseline_set = self._make_test_baseline_set_for_tests( |
| 93 for build in builds: | 87 args, builds_to_results) |
| 94 if not builds_to_results.get(build): | |
| 95 continue | |
| 96 test_baseline_set.add(test, build) | |
| 97 else: | 88 else: |
| 98 test_baseline_set = self._make_test_baseline_set( | 89 test_baseline_set = self._make_test_baseline_set( |
| 99 builds_to_results, | 90 builds_to_results, options.only_changed_tests) |
| 100 only_changed_tests=options.only_changed_tests) | |
| 101 | 91 |
| 102 if options.fill_missing: | 92 if options.fill_missing: |
| 103 self.fill_in_missing_results(test_baseline_set) | 93 self.fill_in_missing_results(test_baseline_set) |
| 104 | 94 |
| 105 _log.debug('Rebaselining: %s', test_baseline_set) | 95 _log.debug('Rebaselining: %s', test_baseline_set) |
| 106 | 96 |
| 107 if not options.dry_run: | 97 if not options.dry_run: |
| 108 self.rebaseline(options, test_baseline_set) | 98 self.rebaseline(options, test_baseline_set) |
| 109 return 0 | 99 return 0 |
| 110 | 100 |
| 111 def _get_issue_number(self): | 101 def _get_issue_number(self): |
| 112 """Returns the current CL issue number, or None.""" | 102 """Returns the current CL issue number, or None.""" |
| 113 issue = self.git_cl().get_issue_number() | 103 issue = self.git_cl().get_issue_number() |
| 114 if not issue.isdigit(): | 104 if not issue.isdigit(): |
| 115 return None | 105 return None |
| 116 return int(issue) | 106 return int(issue) |
| 117 | 107 |
| 118 def git_cl(self): | 108 def git_cl(self): |
| 119 """Returns a GitCL instance. Can be overridden for tests.""" | 109 """Returns a GitCL instance. Can be overridden for tests.""" |
| 120 return GitCL(self._tool) | 110 return GitCL(self._tool) |
| 121 | 111 |
| 122 def trigger_builds(self, builders): | 112 def trigger_builds(self, builders): |
| 113 """Triggers try jobs if necessary; returns whether builds were triggered .""" | |
| 114 if builders is None: | |
| 115 return False | |
| 123 _log.info('Triggering try jobs for:') | 116 _log.info('Triggering try jobs for:') |
| 124 for builder in sorted(builders): | 117 for builder in sorted(builders): |
| 125 _log.info(' %s', builder) | 118 _log.info(' %s', builder) |
| 126 self.git_cl().trigger_try_jobs(builders) | 119 self.git_cl().trigger_try_jobs(builders) |
| 120 _log.info('Once all pending try jobs have finished, please re-run\n' | |
| 121 'webkit-patch rebaseline-cl to fetch new baselines.') | |
| 122 return True | |
| 127 | 123 |
| 128 def builders_with_no_results(self, builds): | 124 def builders_with_no_results(self, builds): |
| 129 """Returns the set of builders that don't have finished results.""" | 125 """Returns the set of builders that don't have finished results.""" |
| 130 builders_with_no_builds = set(self._try_bots()) - {b.builder_name for b in builds} | 126 builders_with_no_builds = set(self._try_bots()) - {b.builder_name for b in builds} |
| 131 return builders_with_no_builds | self.builders_with_pending_builds(build s) | 127 return builders_with_no_builds | self.builders_with_pending_builds(build s) |
| 132 | 128 |
| 129 def _log_pending_builds(self, builds): | |
| 130 builders = self.builders_with_pending_builds(builds) | |
| 131 if not builders: | |
| 132 return | |
| 133 _log.info('There are existing pending builds for:') | |
| 134 for builder in sorted(builders): | |
| 135 _log.info(' %s', builder) | |
| 136 | |
| 133 def builders_with_pending_builds(self, builds): | 137 def builders_with_pending_builds(self, builds): |
| 134 """Returns the set of builders that have pending builds.""" | 138 """Returns the set of builders that have pending builds.""" |
| 135 return {b.builder_name for b in builds if b.build_number is None} | 139 return {b.builder_name for b in builds if b.build_number is None} |
| 136 | 140 |
| 137 def _try_bots(self): | 141 def _try_bots(self): |
| 138 """Returns a collection of try bot builders to fetch results for.""" | 142 """Returns a collection of try bot builders to fetch results for.""" |
| 139 return self._tool.builders.all_try_builder_names() | 143 return self._tool.builders.all_try_builder_names() |
| 140 | 144 |
| 141 def _fetch_results(self, builds): | 145 def _fetch_results(self, builds): |
| 142 """Fetches results for all of the given builds. | 146 """Fetches results for all of the given builds. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 160 results_url = buildbot.results_url(build.builder_name, build.build_n umber) | 164 results_url = buildbot.results_url(build.builder_name, build.build_n umber) |
| 161 layout_test_results = buildbot.fetch_results(build) | 165 layout_test_results = buildbot.fetch_results(build) |
| 162 if layout_test_results is None: | 166 if layout_test_results is None: |
| 163 _log.info('Failed to fetch results for %s', build) | 167 _log.info('Failed to fetch results for %s', build) |
| 164 _log.info('Results URL: %s/results.html', results_url) | 168 _log.info('Results URL: %s/results.html', results_url) |
| 165 _log.info('Retry job by running: git cl try -b %s', build.builde r_name) | 169 _log.info('Retry job by running: git cl try -b %s', build.builde r_name) |
| 166 continue | 170 continue |
| 167 results[build] = layout_test_results | 171 results[build] = layout_test_results |
| 168 return results | 172 return results |
| 169 | 173 |
| 174 def _make_test_baseline_set_for_tests(self, tests, builds_to_results): | |
| 175 test_baseline_set = TestBaselineSet(self._tool) | |
| 176 for test in tests: | |
| 177 for build in builds_to_results: | |
| 178 test_baseline_set.add(test, build) | |
| 179 return test_baseline_set | |
| 180 | |
| 170 def _make_test_baseline_set(self, builds_to_results, only_changed_tests): | 181 def _make_test_baseline_set(self, builds_to_results, only_changed_tests): |
| 171 """Returns a dict which lists the set of baselines to fetch. | 182 """Returns a dict which lists the set of baselines to fetch. |
| 172 | 183 |
| 173 The dict that is returned is a dict of tests to Build objects | 184 The dict that is returned is a dict of tests to Build objects |
| 174 to baseline file extensions. | 185 to baseline file extensions. |
| 175 | 186 |
| 176 Args: | 187 Args: |
| 177 builds_to_results: A dict mapping Builds to LayoutTestResults. | 188 builds_to_results: A dict mapping Builds to LayoutTestResults. |
| 178 only_changed_tests: Whether to only include baselines for tests that | 189 only_changed_tests: Whether to only include baselines for tests that |
| 179 are changed in this CL. If False, all new baselines for failing | 190 are changed in this CL. If False, all new baselines for failing |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 266 | 277 |
| 267 # If any Build exists with the same OS, use the first one. | 278 # If any Build exists with the same OS, use the first one. |
| 268 target_os = os_name(target_port) | 279 target_os = os_name(target_port) |
| 269 same_os_builds = sorted(b for b, p in build_port_pairs if os_name(p) == target_os) | 280 same_os_builds = sorted(b for b, p in build_port_pairs if os_name(p) == target_os) |
| 270 if same_os_builds: | 281 if same_os_builds: |
| 271 return same_os_builds[0] | 282 return same_os_builds[0] |
| 272 | 283 |
| 273 # Otherwise, perhaps any build will do, for example if the results are | 284 # Otherwise, perhaps any build will do, for example if the results are |
| 274 # the same on all platforms. In this case, just return the first build. | 285 # the same on all platforms. In this case, just return the first build. |
| 275 return sorted(build_port_pairs)[0][0] | 286 return sorted(build_port_pairs)[0][0] |
| OLD | NEW |