| 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 """Utility functions to communicate with Rietveld.""" | 5 """Utility functions to communicate with Rietveld.""" |
| 6 | 6 |
| 7 import json | 7 import json |
| 8 import logging | 8 import logging |
| 9 import urllib2 | 9 import urllib2 |
| 10 | 10 |
| 11 from webkitpy.common.net.buildbot import Build | 11 from webkitpy.common.net.buildbot import Build, filter_latest_builds |
| 12 | 12 |
| 13 _log = logging.getLogger(__name__) | 13 _log = logging.getLogger(__name__) |
| 14 | 14 |
| 15 BASE_CODEREVIEW_URL = 'https://codereview.chromium.org/api' | 15 BASE_CODEREVIEW_URL = 'https://codereview.chromium.org/api' |
| 16 | 16 |
| 17 | 17 |
| 18 class Rietveld(object): | 18 class Rietveld(object): |
| 19 | 19 |
| 20 def __init__(self, web): | 20 def __init__(self, web): |
| 21 self.web = web | 21 self.web = web |
| (...skipping 26 matching lines...) Expand all Loading... |
| 48 # Normally, a value of -1 or 6 in the "result" field indicates the j
ob is | 48 # Normally, a value of -1 or 6 in the "result" field indicates the j
ob is |
| 49 # started or pending, and the "buildnumber" field is null. | 49 # started or pending, and the "buildnumber" field is null. |
| 50 if build.build_number and result_dict['result'] in (-1, 6): | 50 if build.build_number and result_dict['result'] in (-1, 6): |
| 51 _log.warning('Build %s has result %d, but unexpectedly has a bui
ld number.', build, result_dict['result']) | 51 _log.warning('Build %s has result %d, but unexpectedly has a bui
ld number.', build, result_dict['result']) |
| 52 build.build_number = None | 52 build.build_number = None |
| 53 builds.append(build) | 53 builds.append(build) |
| 54 | 54 |
| 55 if builder_names is not None: | 55 if builder_names is not None: |
| 56 builds = [b for b in builds if b.builder_name in builder_names] | 56 builds = [b for b in builds if b.builder_name in builder_names] |
| 57 | 57 |
| 58 return self._filter_latest_builds(builds) | 58 return filter_latest_builds(builds) |
| 59 | |
| 60 def _filter_latest_builds(self, builds): | |
| 61 """Filters out a collection of Build objects to include only the latest
for each builder. | |
| 62 | |
| 63 Args: | |
| 64 jobs: A list of Build objects. | |
| 65 | |
| 66 Returns: | |
| 67 A list of Build objects; only one Build object per builder name. If
there are only | |
| 68 Builds with no build number, then one is kept; if there are Builds w
ith build numbers, | |
| 69 then the one with the highest build number is kept. | |
| 70 """ | |
| 71 builder_to_latest_build = {} | |
| 72 for build in builds: | |
| 73 if build.builder_name not in builder_to_latest_build: | |
| 74 builder_to_latest_build[build.builder_name] = build | |
| 75 elif build.build_number > builder_to_latest_build[build.builder_name
].build_number: | |
| 76 builder_to_latest_build[build.builder_name] = build | |
| 77 return sorted(builder_to_latest_build.values()) | |
| 78 | 59 |
| 79 def changed_files(self, issue_number): | 60 def changed_files(self, issue_number): |
| 80 """Lists the files included in a CL that are changed but not deleted. | 61 """Lists the files included in a CL that are changed but not deleted. |
| 81 | 62 |
| 82 File paths are sorted and relative to the repository root. | 63 File paths are sorted and relative to the repository root. |
| 83 """ | 64 """ |
| 84 try: | 65 try: |
| 85 url = self._latest_patchset_url(issue_number) | 66 url = self._latest_patchset_url(issue_number) |
| 86 issue_data = self._get_json(url) | 67 issue_data = self._get_json(url) |
| 87 return sorted(path for path, file_change in issue_data['files'].iter
items() if file_change['status'] != 'D') | 68 return sorted(path for path, file_change in issue_data['files'].iter
items() if file_change['status'] != 'D') |
| (...skipping 22 matching lines...) Expand all Loading... |
| 110 return json.loads(contents) | 91 return json.loads(contents) |
| 111 except ValueError: | 92 except ValueError: |
| 112 _log.error('Invalid JSON: %s', contents) | 93 _log.error('Invalid JSON: %s', contents) |
| 113 raise | 94 raise |
| 114 | 95 |
| 115 def _issue_url(self, issue_number): | 96 def _issue_url(self, issue_number): |
| 116 return '%s/%s' % (BASE_CODEREVIEW_URL, issue_number) | 97 return '%s/%s' % (BASE_CODEREVIEW_URL, issue_number) |
| 117 | 98 |
| 118 def _patchset_url(self, issue_number, patchset_number): | 99 def _patchset_url(self, issue_number, patchset_number): |
| 119 return '%s/%s' % (self._issue_url(issue_number), patchset_number) | 100 return '%s/%s' % (self._issue_url(issue_number), patchset_number) |
| OLD | NEW |