[AiS] Mac AiS on two lines
[chromium-blink-merge.git] / tools / auto_bisect / request_build.py
blob0035a955acf8785962e3bc7d6c2c3523c7592f84
1 # Copyright 2014 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.
5 """This module contains functionality for starting build try jobs via HTTP.
7 This includes both sending a request to start a job, and also related code
8 for querying the status of the job.
10 This module can be either run as a stand-alone script to send a request to a
11 builder, or imported and used by calling the public functions below.
12 """
14 import json
15 import urllib2
17 # URL template for fetching JSON data about builds.
18 BUILDER_JSON_URL = ('%(server_url)s/json/builders/%(bot_name)s/builds/'
19 '%(build_num)s?as_text=1&filter=0')
21 # URL template for displaying build steps.
22 BUILDER_HTML_URL = '%(server_url)s/builders/%(bot_name)s/builds/%(build_num)s'
24 # Status codes that can be returned by the GetBuildStatus method
25 # From buildbot.status.builder.
26 # See: http://docs.buildbot.net/current/developer/results.html
27 SUCCESS, WARNINGS, FAILURE, SKIPPED, EXCEPTION, RETRY, TRYPENDING = range(7)
28 OK = (SUCCESS, WARNINGS) # These indicate build is complete.
29 FAILED = (FAILURE, EXCEPTION, SKIPPED) # These indicate build failure.
30 PENDING = (RETRY, TRYPENDING) # These indicate in progress or in pending queue.
33 class ServerAccessError(Exception):
35 def __str__(self):
36 return '%s\nSorry, cannot connect to server.' % self.args[0]
39 def _IsBuildRunning(build_data):
40 """Checks whether the build is in progress on buildbot.
42 Presence of currentStep element in build JSON indicates build is in progress.
44 Args:
45 build_data: A dictionary with build data, loaded from buildbot JSON API.
47 Returns:
48 True if build is in progress, otherwise False.
49 """
50 current_step = build_data.get('currentStep')
51 if (current_step and current_step.get('isStarted') and
52 current_step.get('results') is None):
53 return True
54 return False
57 def _IsBuildFailed(build_data):
58 """Checks whether the build failed on buildbot.
60 Sometime build status is marked as failed even though compile and packaging
61 steps are successful. This may happen due to some intermediate steps of less
62 importance such as gclient revert, generate_telemetry_profile are failed.
63 Therefore we do an addition check to confirm if build was successful by
64 calling _IsBuildSuccessful.
66 Args:
67 build_data: A dictionary with build data, loaded from buildbot JSON API.
69 Returns:
70 True if revision is failed build, otherwise False.
71 """
72 if (build_data.get('results') in FAILED and
73 not _IsBuildSuccessful(build_data)):
74 return True
75 return False
78 def _IsBuildSuccessful(build_data):
79 """Checks whether the build succeeded on buildbot.
81 We treat build as successful if the package_build step is completed without
82 any error i.e., when results attribute of the this step has value 0 or 1
83 in its first element.
85 Args:
86 build_data: A dictionary with build data, loaded from buildbot JSON API.
88 Returns:
89 True if revision is successfully build, otherwise False.
90 """
91 if build_data.get('steps'):
92 for item in build_data.get('steps'):
93 # The 'results' attribute of each step consists of two elements,
94 # results[0]: This represents the status of build step.
95 # See: http://docs.buildbot.net/current/developer/results.html
96 # results[1]: List of items, contains text if step fails, otherwise empty.
97 if (item.get('name') == 'package_build' and
98 item.get('isFinished') and
99 item.get('results')[0] in OK):
100 return True
101 return False
104 def _FetchBuilderData(builder_url):
105 """Fetches JSON data for the all the builds from the try server.
107 Args:
108 builder_url: A try server URL to fetch builds information.
110 Returns:
111 A dictionary with information of all build on the try server.
113 data = None
114 try:
115 url = urllib2.urlopen(builder_url)
116 except urllib2.URLError as e:
117 print ('urllib2.urlopen error %s, waterfall status page down.[%s]' % (
118 builder_url, str(e)))
119 return None
120 if url is not None:
121 try:
122 data = url.read()
123 except IOError as e:
124 print 'urllib2 file object read error %s, [%s].' % (builder_url, str(e))
125 return data
128 def _GetBuildData(buildbot_url):
129 """Gets build information for the given build id from the try server.
131 Args:
132 buildbot_url: A try server URL to fetch build information.
134 Returns:
135 A dictionary with build information if build exists, otherwise None.
137 builds_json = _FetchBuilderData(buildbot_url)
138 if builds_json:
139 return json.loads(builds_json)
140 return None
143 def GetBuildStatus(build_num, bot_name, server_url):
144 """Gets build status from the buildbot status page for a given build number.
146 Args:
147 build_num: A build number on try server to determine its status.
148 bot_name: Name of the bot where the build information is scanned.
149 server_url: URL of the buildbot.
151 Returns:
152 A pair which consists of build status (SUCCESS, FAILED or PENDING) and a
153 link to build status page on the waterfall.
155 results_url = None
156 if build_num:
157 # Get the URL for requesting JSON data with status information.
158 buildbot_url = BUILDER_JSON_URL % {
159 'server_url': server_url,
160 'bot_name': bot_name,
161 'build_num': build_num,
163 build_data = _GetBuildData(buildbot_url)
164 if build_data:
165 # Link to build on the buildbot showing status of build steps.
166 results_url = BUILDER_HTML_URL % {
167 'server_url': server_url,
168 'bot_name': bot_name,
169 'build_num': build_num,
171 if _IsBuildFailed(build_data):
172 return (FAILED, results_url)
174 elif _IsBuildSuccessful(build_data):
175 return (OK, results_url)
176 return (PENDING, results_url)
179 def GetBuildNumFromBuilder(build_reason, bot_name, server_url):
180 """Gets build number on build status page for a given 'build reason'.
182 This function parses the JSON data from buildbot page and collects basic
183 information about the all the builds, and then uniquely identifies the build
184 based on the 'reason' attribute in the JSON data about the build.
186 The 'reason' attribute set is when a build request is posted, and it is used
187 to identify the build on status page.
189 Args:
190 build_reason: A unique build name set to build on try server.
191 bot_name: Name of the bot where the build information is scanned.
192 server_url: URL of the buildbot.
194 Returns:
195 A build number as a string if found, otherwise None.
197 buildbot_url = BUILDER_JSON_URL % {
198 'server_url': server_url,
199 'bot_name': bot_name,
200 'build_num': '_all',
202 builds_json = _FetchBuilderData(buildbot_url)
203 if builds_json:
204 builds_data = json.loads(builds_json)
205 for current_build in builds_data:
206 if builds_data[current_build].get('reason') == build_reason:
207 return builds_data[current_build].get('number')
208 return None