| OLD | NEW |
| (Empty) |
| 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 | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 """Utility functions to communicate with Rietveld.""" | |
| 6 | |
| 7 import json | |
| 8 import logging | |
| 9 import urllib2 | |
| 10 | |
| 11 from webkitpy.common.net.buildbot import Build, filter_latest_builds | |
| 12 | |
| 13 _log = logging.getLogger(__name__) | |
| 14 | |
| 15 BASE_CODEREVIEW_URL = 'https://codereview.chromium.org/api' | |
| 16 | |
| 17 | |
| 18 class Rietveld(object): | |
| 19 | |
| 20 def __init__(self, web): | |
| 21 self.web = web | |
| 22 | |
| 23 def latest_try_jobs(self, issue_number, builder_names=None, patchset_number=
None): | |
| 24 """Returns a list of Build objects for builds on the latest patchset. | |
| 25 | |
| 26 Args: | |
| 27 issue_number: A Rietveld issue number. | |
| 28 builder_names: A collection of builder names. If specified, only res
ults | |
| 29 from the given list of builders will be kept. | |
| 30 patchset_number: If given, a specific patchset will be used instead
of the latest one. | |
| 31 | |
| 32 Returns: | |
| 33 A list of Build objects, where Build objects for completed jobs have
a build number, | |
| 34 and Build objects for pending jobs have no build number. | |
| 35 """ | |
| 36 try: | |
| 37 if patchset_number: | |
| 38 url = self._patchset_url(issue_number, patchset_number) | |
| 39 else: | |
| 40 url = self._latest_patchset_url(issue_number) | |
| 41 patchset_data = self._get_json(url) | |
| 42 except (urllib2.URLError, ValueError): | |
| 43 return [] | |
| 44 | |
| 45 builds = [] | |
| 46 for result_dict in patchset_data['try_job_results']: | |
| 47 build = Build(result_dict['builder'], result_dict['buildnumber']) | |
| 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. | |
| 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']) | |
| 52 build.build_number = None | |
| 53 builds.append(build) | |
| 54 | |
| 55 if builder_names is not None: | |
| 56 builds = [b for b in builds if b.builder_name in builder_names] | |
| 57 | |
| 58 return filter_latest_builds(builds) | |
| 59 | |
| 60 def changed_files(self, issue_number): | |
| 61 """Lists the files included in a CL that are changed but not deleted. | |
| 62 | |
| 63 File paths are sorted and relative to the repository root. | |
| 64 """ | |
| 65 try: | |
| 66 url = self._latest_patchset_url(issue_number) | |
| 67 issue_data = self._get_json(url) | |
| 68 return sorted(path for path, file_change in issue_data['files'].iter
items() if file_change['status'] != 'D') | |
| 69 except (urllib2.URLError, ValueError, KeyError): | |
| 70 _log.warning('Failed to list changed files for issue %s.', issue_num
ber) | |
| 71 return None | |
| 72 | |
| 73 def _latest_patchset_url(self, issue_number): | |
| 74 issue_data = self._get_json(self._issue_url(issue_number)) | |
| 75 latest_patchset_number = issue_data["patchsets"][-1] | |
| 76 return self._patchset_url(issue_number, latest_patchset_number) | |
| 77 | |
| 78 def _get_json(self, url): | |
| 79 """Fetches JSON from a URL, and logs errors if the request was unsuccess
ful. | |
| 80 | |
| 81 Raises: | |
| 82 urllib2.URLError: Something went wrong with the request. | |
| 83 ValueError: The response wasn't valid JSON. | |
| 84 """ | |
| 85 try: | |
| 86 contents = self.web.get_binary(url) | |
| 87 except urllib2.URLError: | |
| 88 _log.error('Request failed to URL: %s', url) | |
| 89 raise | |
| 90 try: | |
| 91 return json.loads(contents) | |
| 92 except ValueError: | |
| 93 _log.error('Invalid JSON: %s', contents) | |
| 94 raise | |
| 95 | |
| 96 def _issue_url(self, issue_number): | |
| 97 return '%s/%s' % (BASE_CODEREVIEW_URL, issue_number) | |
| 98 | |
| 99 def _patchset_url(self, issue_number, patchset_number): | |
| 100 return '%s/%s' % (self._issue_url(issue_number), patchset_number) | |
| OLD | NEW |