Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Side by Side Diff: third_party/WebKit/Tools/Scripts/webkitpy/common/net/rietveld.py

Issue 2439693003: rebaseline-cl: Don't trigger new try jobs for builders that already have jobs started. (Closed)
Patch Set: Revert latest_try_job_results to only return a list of Builds again (simpler) Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | third_party/WebKit/Tools/Scripts/webkitpy/common/net/rietveld_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
22 22
23 def latest_try_job_results(self, issue_number, builder_names=None, patchset_ number=None): 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. 24 """Returns a list of Build objects for builds on the latest patchset.
25 25
26 Args: 26 Args:
27 issue_number: A Rietveld issue number. 27 issue_number: A Rietveld issue number.
28 builder_names: A collection of builder names. If specified, only res ults 28 builder_names: A collection of builder names. If specified, only res ults
29 from the given list of builders will be kept. 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. 30 patchset_number: If given, a specific patchset will be used instead of the latest one.
31 31
32 Returns: 32 Returns:
33 A dict mapping Build objects to result dicts for the latest build 33 A list of Build objects, where Build objects for completed jobs have a build number,
34 for each builder on the latest patchset. 34 and Build objects for pending jobs have no build number.
35 """ 35 """
36 try: 36 try:
37 if patchset_number: 37 if patchset_number:
38 url = self._patchset_url(issue_number, patchset_number) 38 url = self._patchset_url(issue_number, patchset_number)
39 else: 39 else:
40 url = self._latest_patchset_url(issue_number) 40 url = self._latest_patchset_url(issue_number)
41 patchset_data = self._get_json(url) 41 patchset_data = self._get_json(url)
42 except (urllib2.URLError, ValueError): 42 except (urllib2.URLError, ValueError):
43 return {} 43 return []
44 44
45 def build(job): 45 builds = []
46 return Build(builder_name=job['builder'], build_number=job['buildnum ber']) 46 for result_dict in patchset_data['try_job_results']:
47 47 build = Build(result_dict['builder'], result_dict['buildnumber'])
48 results = {build(job): job for job in patchset_data['try_job_results']} 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)
49 54
50 if builder_names is not None: 55 if builder_names is not None:
51 results = {b: result for b, result in results.iteritems() if b.build er_name in builder_names} 56 builds = [b for b in builds if b.builder_name in builder_names]
52 57
53 latest_builds = self._filter_latest_builds(list(results)) 58 return self._filter_latest_builds(builds)
54 return {b: result for b, result in results.iteritems() if b in latest_bu ilds}
55 59
56 def _filter_latest_builds(self, builds): 60 def _filter_latest_builds(self, builds):
57 """Filters out a collection of Build objects to include only the latest for each builder. 61 """Filters out a collection of Build objects to include only the latest for each builder.
58 62
59 Args: 63 Args:
60 jobs: A list of Build objects. 64 jobs: A list of Build objects.
61 65
62 Returns: 66 Returns:
63 A list of Build objects that contains only the latest build for each builder. 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.
64 """ 70 """
65 builder_to_highest_number = {} 71 builder_to_latest_build = {}
66 for build in builds: 72 for build in builds:
67 if build.build_number > builder_to_highest_number.get(build.builder_ name, 0): 73 if build.builder_name not in builder_to_latest_build:
68 builder_to_highest_number[build.builder_name] = build.build_numb er 74 builder_to_latest_build[build.builder_name] = build
69 75 elif build.build_number > builder_to_latest_build[build.builder_name ].build_number:
70 def is_latest_build(build): 76 builder_to_latest_build[build.builder_name] = build
71 if build.builder_name not in builder_to_highest_number: 77 return sorted(builder_to_latest_build.values())
72 return False
73 return builder_to_highest_number[build.builder_name] == build.build_ number
74
75 return [b for b in builds if is_latest_build(b)]
76 78
77 def changed_files(self, issue_number): 79 def changed_files(self, issue_number):
78 """Lists the files included in a CL, or None if this can't be determined . 80 """Lists the files included in a CL, or None if this can't be determined .
79 81
80 File paths are sorted and relative to the repository root. 82 File paths are sorted and relative to the repository root.
81 """ 83 """
82 try: 84 try:
83 url = self._latest_patchset_url(issue_number) 85 url = self._latest_patchset_url(issue_number)
84 issue_data = self._get_json(url) 86 issue_data = self._get_json(url)
85 return sorted(issue_data['files']) 87 return sorted(issue_data['files'])
(...skipping 22 matching lines...) Expand all
108 return json.loads(contents) 110 return json.loads(contents)
109 except ValueError: 111 except ValueError:
110 _log.error('Invalid JSON: %s', contents) 112 _log.error('Invalid JSON: %s', contents)
111 raise 113 raise
112 114
113 def _issue_url(self, issue_number): 115 def _issue_url(self, issue_number):
114 return '%s/%s' % (BASE_CODEREVIEW_URL, issue_number) 116 return '%s/%s' % (BASE_CODEREVIEW_URL, issue_number)
115 117
116 def _patchset_url(self, issue_number, patchset_number): 118 def _patchset_url(self, issue_number, patchset_number):
117 return '%s/%s' % (self._issue_url(issue_number), patchset_number) 119 return '%s/%s' % (self._issue_url(issue_number), patchset_number)
OLDNEW
« no previous file with comments | « no previous file | third_party/WebKit/Tools/Scripts/webkitpy/common/net/rietveld_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698