| 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 """An interface to git-cl. | 5 """An interface to git-cl. |
| 6 | 6 |
| 7 The git-cl tool is responsible for communicating with Rietveld, Gerrit, | 7 The git-cl tool is responsible for communicating with Rietveld, Gerrit, |
| 8 and Buildbucket to manage changelists and try jobs associated with them. | 8 and Buildbucket to manage changelists and try jobs associated with them. |
| 9 """ | 9 """ |
| 10 | 10 |
| 11 import json | 11 import json |
| 12 import logging | 12 import logging |
| 13 import re |
| 14 |
| 15 from webkitpy.common.net.buildbot import Build, filter_latest_builds |
| 13 | 16 |
| 14 _log = logging.getLogger(__name__) | 17 _log = logging.getLogger(__name__) |
| 15 | 18 |
| 16 _COMMANDS_THAT_REQUIRE_AUTH = ( | 19 _COMMANDS_THAT_REQUIRE_AUTH = ( |
| 17 'archive', 'comments', 'commit', 'description', 'diff', 'land', 'lint', 'own
ers', 'patch', | 20 'archive', 'comments', 'commit', 'description', 'diff', 'land', 'lint', 'own
ers', 'patch', |
| 18 'presubmit', 'set-close', 'set-commit', 'status', 'try-results', 'try', 'upl
oad', | 21 'presubmit', 'set-close', 'set-commit', 'status', 'try-results', 'try', 'upl
oad', |
| 19 ) | 22 ) |
| 20 | 23 |
| 24 |
| 21 class GitCL(object): | 25 class GitCL(object): |
| 22 | 26 |
| 23 def __init__(self, host, auth_refresh_token_json=None, cwd=None): | 27 def __init__(self, host, auth_refresh_token_json=None, cwd=None): |
| 24 self._host = host | 28 self._host = host |
| 25 self._auth_refresh_token_json = auth_refresh_token_json | 29 self._auth_refresh_token_json = auth_refresh_token_json |
| 26 self._cwd = cwd | 30 self._cwd = cwd |
| 27 | 31 |
| 28 def run(self, args): | 32 def run(self, args): |
| 29 """Runs git-cl with the given arguments and returns the output.""" | 33 """Runs git-cl with the given arguments and returns the output.""" |
| 30 command = ['git', 'cl'] + args | 34 command = ['git', 'cl'] + args |
| (...skipping 21 matching lines...) Expand all Loading... |
| 52 try_results = self.fetch_try_results() | 56 try_results = self.fetch_try_results() |
| 53 _log.debug('Fetched try results: %s', try_results) | 57 _log.debug('Fetched try results: %s', try_results) |
| 54 if self.all_jobs_finished(try_results): | 58 if self.all_jobs_finished(try_results): |
| 55 self._host.print_('All jobs finished.') | 59 self._host.print_('All jobs finished.') |
| 56 return try_results | 60 return try_results |
| 57 self._host.print_('Waiting. %d seconds passed.' % (self._host.time()
- start)) | 61 self._host.print_('Waiting. %d seconds passed.' % (self._host.time()
- start)) |
| 58 self._host.sleep(poll_delay_seconds) | 62 self._host.sleep(poll_delay_seconds) |
| 59 self._host.print_('Timed out waiting for try results.') | 63 self._host.print_('Timed out waiting for try results.') |
| 60 return None | 64 return None |
| 61 | 65 |
| 66 def latest_try_jobs(self, builder_names=None): |
| 67 """Returns a list of Builds for the latest jobs for the given builders."
"" |
| 68 try_results = self.fetch_try_results() |
| 69 if builder_names: |
| 70 try_results = [r for r in try_results if r['builder_name'] in builde
r_names] |
| 71 return filter_latest_builds(self._try_result_to_build(r) for r in try_re
sults) |
| 72 |
| 62 def fetch_try_results(self): | 73 def fetch_try_results(self): |
| 63 """Requests results of try jobs for the current CL.""" | 74 """Requests results f try jobs for the current CL.""" |
| 64 with self._host.filesystem.mkdtemp() as temp_directory: | 75 with self._host.filesystem.mkdtemp() as temp_directory: |
| 65 results_path = self._host.filesystem.join(temp_directory, 'try-resul
ts.json') | 76 results_path = self._host.filesystem.join(temp_directory, 'try-resul
ts.json') |
| 66 self.run(['try-results', '--json', results_path]) | 77 self.run(['try-results', '--json', results_path]) |
| 67 contents = self._host.filesystem.read_text_file(results_path) | 78 contents = self._host.filesystem.read_text_file(results_path) |
| 68 _log.debug('Fetched try results to file "%s".', results_path) | 79 _log.debug('Fetched try results to file "%s".', results_path) |
| 69 self._host.filesystem.remove(results_path) | 80 self._host.filesystem.remove(results_path) |
| 70 return json.loads(contents) | 81 return json.loads(contents) |
| 71 | 82 |
| 83 @staticmethod |
| 84 def _try_result_to_build(try_result): |
| 85 """Converts a parsed try result dict to a Build object.""" |
| 86 builder_name = try_result['builder_name'] |
| 87 url = try_result['url'] |
| 88 if url is None: |
| 89 return Build(builder_name, None) |
| 90 match = re.match(r'.*/builds/(\d+)?$', url) |
| 91 build_number = match.group(1) |
| 92 assert build_number and build_number.isdigit() |
| 93 return Build(builder_name, int(build_number)) |
| 94 |
| 72 def is_closed(self): | 95 def is_closed(self): |
| 73 out = self.run(['status' '--field', 'status']) | 96 out = self.run(['status' '--field', 'status']) |
| 74 return out.strip() == 'closed' | 97 return out.strip() == 'closed' |
| 75 | 98 |
| 76 @staticmethod | 99 @staticmethod |
| 77 def all_jobs_finished(try_results): | 100 def all_jobs_finished(try_results): |
| 78 return all(r.get('status') == 'COMPLETED' for r in try_results) | 101 return all(r.get('status') == 'COMPLETED' for r in try_results) |
| 79 | 102 |
| 80 @staticmethod | 103 @staticmethod |
| 81 def has_failing_try_results(try_results): | 104 def has_failing_try_results(try_results): |
| 82 return any(r.get('result') == 'FAILURE' for r in try_results) | 105 return any(r.get('result') == 'FAILURE' for r in try_results) |
| OLD | NEW |