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 a Rietveld issue. | 5 """A command to fetch new baselines from try jobs for a Rietveld issue. |
6 | 6 |
7 This command interacts with the Rietveld API to get information about try jobs | 7 This command interacts with the Rietveld API to get information about try jobs |
8 with layout test results. | 8 with layout test results. |
9 """ | 9 """ |
10 | 10 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 self.results_directory_option, | 49 self.results_directory_option, |
50 ]) | 50 ]) |
51 self.rietveld = Rietveld(Web()) | 51 self.rietveld = Rietveld(Web()) |
52 | 52 |
53 def execute(self, options, args, tool): | 53 def execute(self, options, args, tool): |
54 self._tool = tool | 54 self._tool = tool |
55 issue_number = self._get_issue_number(options) | 55 issue_number = self._get_issue_number(options) |
56 if not issue_number: | 56 if not issue_number: |
57 return | 57 return |
58 | 58 |
59 builds = self.rietveld.latest_try_job_results(issue_number, self._try_bo
ts()) | 59 builds = self.rietveld.latest_try_jobs(issue_number, self._try_bots()) |
60 if options.trigger_jobs: | 60 if options.trigger_jobs: |
61 if self.trigger_jobs_for_missing_builds(builds): | 61 if self.trigger_jobs_for_missing_builds(builds): |
62 _log.info('Please re-run webkit-patch rebaseline-cl once all pen
ding try jobs have finished.') | 62 _log.info('Please re-run webkit-patch rebaseline-cl once all pen
ding try jobs have finished.') |
63 return | 63 return |
64 if not builds: | 64 if not builds: |
65 # TODO(qyearsley): Also check that there are *finished* builds. | |
66 # The current behavior would still proceed if there are queued | |
67 # or started builds. | |
68 _log.info('No builds to download baselines from.') | 65 _log.info('No builds to download baselines from.') |
69 | 66 |
70 if args: | 67 if args: |
71 test_prefix_list = {} | 68 test_prefix_list = {} |
72 for test in args: | 69 for test in args: |
73 test_prefix_list[test] = {b: BASELINE_SUFFIX_LIST for b in build
s} | 70 test_prefix_list[test] = {b: BASELINE_SUFFIX_LIST for b in build
s} |
74 else: | 71 else: |
75 test_prefix_list = self._test_prefix_list( | 72 test_prefix_list = self._test_prefix_list( |
76 issue_number, only_changed_tests=options.only_changed_tests) | 73 issue_number, only_changed_tests=options.only_changed_tests) |
77 | 74 |
(...skipping 30 matching lines...) Expand all Loading... |
108 'to operate on; please run `git cl upload` on this branch
first, or use the --issue\n' | 105 'to operate on; please run `git cl upload` on this branch
first, or use the --issue\n' |
109 'option to download baselines for another existing CL.') | 106 'option to download baselines for another existing CL.') |
110 return None | 107 return None |
111 return int(issue_number) | 108 return int(issue_number) |
112 | 109 |
113 def git_cl(self): | 110 def git_cl(self): |
114 """Returns a GitCL instance; can be overridden for tests.""" | 111 """Returns a GitCL instance; can be overridden for tests.""" |
115 return GitCL(self._tool) | 112 return GitCL(self._tool) |
116 | 113 |
117 def trigger_jobs_for_missing_builds(self, builds): | 114 def trigger_jobs_for_missing_builds(self, builds): |
118 """Returns True if jobs were triggered; False otherwise.""" | 115 """Triggers try jobs for any builders that have no builds started. |
| 116 |
| 117 Args: |
| 118 builds: A list of Build objects; if the build number of a Build is Non
e, |
| 119 then that indicates that the job is pending. |
| 120 |
| 121 Returns: |
| 122 True if there are pending jobs to wait for, including jobs just star
ted. |
| 123 """ |
119 builders_with_builds = {b.builder_name for b in builds} | 124 builders_with_builds = {b.builder_name for b in builds} |
120 builders_without_builds = set(self._try_bots()) - builders_with_builds | 125 builders_without_builds = set(self._try_bots()) - builders_with_builds |
121 if not builders_without_builds: | 126 builders_with_pending_builds = {b.builder_name for b in builds if b.buil
d_number is None} |
122 return False | |
123 | 127 |
124 _log.info('Triggering try jobs for:') | 128 if builders_with_pending_builds: |
125 for builder in sorted(builders_without_builds): | 129 _log.info('There are existing pending builds for:') |
126 _log.info(' %s', builder) | 130 for builder in sorted(builders_with_pending_builds): |
| 131 _log.info(' %s', builder) |
127 | 132 |
128 # If the builders may be under different masters, then they cannot | 133 if builders_without_builds: |
129 # all be started in one invocation of git cl try without providing | 134 _log.info('Triggering try jobs for:') |
130 # master names. Doing separate invocations is slower, but always works | 135 for builder in sorted(builders_without_builds): |
131 # even when there are builders under different master names. | 136 _log.info(' %s', builder) |
132 for builder in sorted(builders_without_builds): | 137 # If the builders may be under different masters, then they cannot |
133 self.git_cl().run(['try', '-b', builder]) | 138 # all be started in one invocation of git cl try without providing |
134 return True | 139 # master names. Doing separate invocations is slower, but always wor
ks |
| 140 # even when there are builders under different master names. |
| 141 for builder in sorted(builders_without_builds): |
| 142 self.git_cl().run(['try', '-b', builder]) |
| 143 |
| 144 return bool(builders_with_pending_builds or builders_without_builds) |
135 | 145 |
136 def _test_prefix_list(self, issue_number, only_changed_tests): | 146 def _test_prefix_list(self, issue_number, only_changed_tests): |
137 """Returns a collection of test, builder and file extensions to get new
baselines for. | 147 """Returns a collection of test, builder and file extensions to get new
baselines for. |
138 | 148 |
139 Args: | 149 Args: |
140 issue_number: The CL number of the change which needs new baselines. | 150 issue_number: The CL number of the change which needs new baselines. |
141 only_changed_tests: Whether to only include baselines for tests that | 151 only_changed_tests: Whether to only include baselines for tests that |
142 are changed in this CL. If False, all new baselines for failing | 152 are changed in this CL. If False, all new baselines for failing |
143 tests will be downloaded, even for tests that were not modified. | 153 tests will be downloaded, even for tests that were not modified. |
144 | 154 |
(...skipping 11 matching lines...) Expand all Loading... |
156 if only_changed_tests and test not in tests_in_cl: | 166 if only_changed_tests and test not in tests_in_cl: |
157 continue | 167 continue |
158 if test not in result: | 168 if test not in result: |
159 result[test] = {} | 169 result[test] = {} |
160 result[test][build] = BASELINE_SUFFIX_LIST | 170 result[test][build] = BASELINE_SUFFIX_LIST |
161 return result | 171 return result |
162 | 172 |
163 def _builds_to_tests(self, issue_number): | 173 def _builds_to_tests(self, issue_number): |
164 """Fetches a list of try bots, and for each, fetches tests with new base
lines.""" | 174 """Fetches a list of try bots, and for each, fetches tests with new base
lines.""" |
165 _log.debug('Getting results for Rietveld issue %d.', issue_number) | 175 _log.debug('Getting results for Rietveld issue %d.', issue_number) |
166 builds = self.rietveld.latest_try_job_results(issue_number, self._try_bo
ts()) | 176 builds = self.rietveld.latest_try_jobs(issue_number, self._try_bots()) |
167 if not builds: | 177 if not builds: |
168 _log.debug('No try job results for builders in: %r.', self._try_bots
()) | 178 _log.debug('No try job results for builders in: %r.', self._try_bots
()) |
169 return {build: self._tests_to_rebaseline(build) for build in builds} | 179 return {build: self._tests_to_rebaseline(build) for build in builds} |
170 | 180 |
171 def _try_bots(self): | 181 def _try_bots(self): |
172 """Returns a collection of try bot builders to fetch results for.""" | 182 """Returns a collection of try bot builders to fetch results for.""" |
173 return self._tool.builders.all_try_builder_names() | 183 return self._tool.builders.all_try_builder_names() |
174 | 184 |
175 def _tests_to_rebaseline(self, build): | 185 def _tests_to_rebaseline(self, build): |
176 """Fetches a list of LayoutTestResult objects for unexpected results wit
h new baselines.""" | 186 """Fetches a list of LayoutTestResult objects for unexpected results wit
h new baselines.""" |
(...skipping 10 matching lines...) Expand all Loading... |
187 @staticmethod | 197 @staticmethod |
188 def _log_test_prefix_list(test_prefix_list): | 198 def _log_test_prefix_list(test_prefix_list): |
189 """Logs the tests to download new baselines for.""" | 199 """Logs the tests to download new baselines for.""" |
190 if not test_prefix_list: | 200 if not test_prefix_list: |
191 _log.info('No tests to rebaseline; exiting.') | 201 _log.info('No tests to rebaseline; exiting.') |
192 return | 202 return |
193 _log.info('Tests to rebaseline:') | 203 _log.info('Tests to rebaseline:') |
194 for test, builds in test_prefix_list.iteritems(): | 204 for test, builds in test_prefix_list.iteritems(): |
195 builds_str = ', '.join(sorted('%s (%s)' % (b.builder_name, b.build_n
umber) for b in builds)) | 205 builds_str = ', '.join(sorted('%s (%s)' % (b.builder_name, b.build_n
umber) for b in builds)) |
196 _log.info(' %s: %s', test, builds_str) | 206 _log.info(' %s: %s', test, builds_str) |
OLD | NEW |