OLD | NEW |
---|---|
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:io'; | 5 import 'dart:io'; |
6 import 'dart:async'; | 6 import 'dart:async'; |
7 import 'dart:convert'; | 7 import 'dart:convert'; |
8 import 'package:http/http.dart' as http; | 8 import 'package:http/http.dart' as http; |
9 import 'package:html/parser.dart' show parse; | 9 import 'package:archive/archive.dart'; |
10 import 'try.dart'; | 10 import 'try.dart'; |
11 import 'cache_new.dart'; | 11 import 'cache_new.dart'; |
12 | 12 |
13 const String LUCI_HOST = "luci-milo.appspot.com"; | 13 const String LUCI_HOST = "luci-milo.appspot.com"; |
14 const String CBE_HOST = "chrome-build-extract.appspot.com"; | |
14 | 15 |
15 typedef void ModifyRequestFunction(HttpClientRequest request); | 16 typedef void ModifyRequestFunction(HttpClientRequest request); |
16 | 17 |
17 /// Base class for communicating with [Luci] | 18 /// Base class for communicating with [Luci] |
18 /// Some information is found through the api | 19 /// Some information is found through the api |
19 /// <https://docs.google.com/document/d/1HbPp7Sy7ofC | 20 /// <https://luci-milo.appspot.com/rpcexplorer/services/milo.Buildbot/>, |
20 /// U7C9USqcE91VubGg_IIET2GUj9iknev4/edit#> | 21 /// some information is found via CBE (Chrome Built Extract) |
Johnni Winther
2017/08/29 07:23:04
-> `Chrome Build Extract` ?
mkroghj
2017/08/30 07:27:44
Done.
| |
21 /// and some information is found via screen-scraping. | 22 /// <https://chrome-build-extract.appspot.com/get_master/<client>>. |
22 class LuciApi { | 23 class LuciApi { |
23 final HttpClient _client = new HttpClient(); | 24 final HttpClient _client = new HttpClient(); |
24 | 25 |
25 LuciApi(); | 26 LuciApi(); |
26 | 27 |
27 /// [getBuildBots] fetches all build bots from luci (we cannot | 28 /// [getBuilderGroups] fetches all builder groups not in -dev, -stable and |
Johnni Winther
2017/08/29 07:23:04
Documentation doesn't seem to match the implementa
mkroghj
2017/08/30 07:27:43
Done.
| |
28 /// get this from the api). The format is: | 29 /// -integration. |
29 /// <li> | 30 Future<Try<dynamic>> getCBEJson( |
Johnni Winther
2017/08/29 07:23:04
Rename to [getJsonFromChromeBuildExtract]
mkroghj
2017/08/30 07:27:44
Done.
| |
30 /// <a href="/buildbot/client.crashpad/crashpad_win_x86_wow64_rel"> | |
31 /// crashpad_win_x86_wow64_rel</a> | |
32 /// </li> | |
33 /// <h3> client.dart </h3> | |
34 /// <li> | |
35 /// <a href="/buildbot/client.dart/analyze-linux-be">analyze-linux-be</a> | |
36 /// </li> | |
37 /// <li> | |
38 /// <a href="/buildbot/client.dart/analyze-linux-stable"> | |
39 /// analyze-linux-stable</a> | |
40 /// </li> | |
41 /// <li> | |
42 /// <a href="/buildbot/client.dart/analyzer-linux-release-be"> | |
43 /// analyzer-linux-release-be</a> | |
44 /// </li> | |
45 /// | |
46 /// We look for the section header matching clients, then | |
47 /// if we are in the right section, we take the <li> element | |
48 /// and transform to a build bot | |
49 /// | |
50 Future<Try<List<LuciBuildBot>>> getAllBuildBots( | |
51 String client, WithCacheFunction withCache) async { | 31 String client, WithCacheFunction withCache) async { |
52 return await tryStartAsync(() => withCache( | 32 var result = await tryStartAsync(() => withCache( |
53 () => _makeGetRequest( | 33 () => _makeGetRequest(new Uri( |
54 new Uri(scheme: 'https', host: LUCI_HOST, path: "/")), | 34 scheme: 'https', host: CBE_HOST, path: "/get_master/${client}")), |
55 "all_buildbots")) | 35 "cbe")); |
56 .then((Try<String> tryRes) => tryRes.bind(parse).bind((htmlDoc) { | 36 return result.bind(JSON.decode); |
57 // This is really dirty, but the structure of | |
58 // the document is not really suited for anything else. | |
59 var takeSection = false; | |
60 return htmlDoc.body.children.where((node) { | |
61 if (node.localName == "li") return takeSection; | |
62 if (node.localName != "h3") { | |
63 takeSection = false; | |
64 return false; | |
65 } | |
66 // Current node is <h3>. | |
67 takeSection = client == node.text.trim(); | |
68 return false; | |
69 }); | |
70 }).bind((elements) { | |
71 // Here we hold an iterable of buildbot elements | |
72 // <li> | |
73 // <a href="/buildbot/client.dart/analyzer-linux-release-be"> | |
74 // analyzer-linux-release-be</a> | |
75 // </li> | |
76 return elements.map((element) { | |
77 var name = element.children[0].text; | |
78 var url = element.children[0].attributes['href']; | |
79 return new LuciBuildBot(client, name, url); | |
80 }).toList(); | |
81 })); | |
82 } | 37 } |
83 | 38 |
84 /// [getPrimaryBuilders] fetches all primary builders | 39 /// Gets master information out for all bots, which is not that |
Johnni Winther
2017/08/29 07:23:04
Remove ', which is not that useful atm'. Maybe add
mkroghj
2017/08/30 07:27:43
Done.
| |
85 /// (the ones usually used by gardeners) by not including buildbots with | 40 /// useful atm. |
86 /// the name -dev, -stable or -integration. | 41 Future<Try<Object>> getMaster( |
87 Future<Try<List<LuciBuildBot>>> getPrimaryBuilders( | |
88 String client, WithCacheFunction withCache) async { | 42 String client, WithCacheFunction withCache) async { |
89 return await getAllBuildBots(client, withCache) | 43 var uri = new Uri( |
90 .then((Try<List<LuciBuildBot>> tryRes) { | 44 scheme: "https", |
91 return tryRes | 45 host: LUCI_HOST, |
92 .bind((buildBots) => buildBots.where((LuciBuildBot buildBot) { | 46 path: "prpc/milo.Buildbot/GetCompressedMasterJSON"); |
93 return !(buildBot.name.contains("-dev") || | 47 var body = {"name": client}; |
94 buildBot.name.contains("-stable") || | 48 var result = await tryStartAsync(() => withCache( |
95 buildBot.name.contains("-integration")); | 49 () => _makePostRequest(uri, JSON.encode(body), { |
96 })); | 50 HttpHeaders.CONTENT_TYPE: "application/json", |
51 HttpHeaders.ACCEPT: "application/json" | |
52 }), | |
53 '${uri.path}')); | |
54 return result.bind(JSON.decode).bind((json) { | |
55 var data = JSON.decode(UTF8 | |
56 .decode(new GZipDecoder().decodeBytes(BASE64.decode(json["data"])))); | |
57 return data; | |
97 }); | 58 }); |
98 } | 59 } |
99 | 60 |
100 /// Calling the Milo Api to get latest builds for this bot, | 61 /// Calling the Milo Api to get latest builds for this bot, |
101 /// where the field [amount] is the number of recent builds to fetch. | 62 /// where the field [amount] is the number of recent builds to fetch. |
102 Future<Try<List<BuildDetail>>> getBuildBotDetails( | 63 Future<Try<List<BuildDetail>>> getBuildBotDetails( |
103 String client, String botName, WithCacheFunction withCache, | 64 String client, String botName, WithCacheFunction withCache, |
104 [int amount = 20]) async { | 65 [int amount = 20]) async { |
105 var uri = new Uri( | 66 var uri = new Uri( |
106 scheme: "https", | 67 scheme: "https", |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
226 build["number"], | 187 build["number"], |
227 build["text"].join(' '), | 188 build["text"].join(' '), |
228 build["finished"], | 189 build["finished"], |
229 steps, | 190 steps, |
230 properties, | 191 properties, |
231 build["blame"], | 192 build["blame"], |
232 timing, | 193 timing, |
233 changes); | 194 changes); |
234 } | 195 } |
235 | 196 |
236 // Structured classes to relay information from api and web pages | |
237 | |
238 /// [LuciBuildBot] holds information about a build bot | |
239 class LuciBuildBot { | |
240 final String client; | |
241 final String name; | |
242 final String url; | |
243 | |
244 LuciBuildBot(this.client, this.name, this.url); | |
245 | |
246 @override | |
247 String toString() { | |
248 return "LuciBuildBot { client: $client, name: $name, url: $url }"; | |
249 } | |
250 } | |
251 | |
252 /// [BuildDetail] holds data detailing a specific build | 197 /// [BuildDetail] holds data detailing a specific build |
253 class BuildDetail { | 198 class BuildDetail { |
254 final String client; | 199 final String client; |
255 final String botName; | 200 final String botName; |
256 final int buildNumber; | 201 final int buildNumber; |
257 final String results; | 202 final String results; |
258 final bool finished; | 203 final bool finished; |
259 final List<BuildStep> steps; | 204 final List<BuildStep> steps; |
260 final List<BuildProperty> buildProperties; | 205 final List<BuildProperty> buildProperties; |
261 final List<String> blameList; | 206 final List<String> blameList; |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
376 buffer.writeln("revision: $revision"); | 321 buffer.writeln("revision: $revision"); |
377 buffer.writeln("commitUrl: $commitUrl"); | 322 buffer.writeln("commitUrl: $commitUrl"); |
378 buffer.writeln("changedBy: $changedBy"); | 323 buffer.writeln("changedBy: $changedBy"); |
379 buffer.write("\n"); | 324 buffer.write("\n"); |
380 buffer.writeln(comments); | 325 buffer.writeln(comments); |
381 buffer.write("\nfiles:\n"); | 326 buffer.write("\nfiles:\n"); |
382 changedFiles.forEach(buffer.writeln); | 327 changedFiles.forEach(buffer.writeln); |
383 return buffer.toString(); | 328 return buffer.toString(); |
384 } | 329 } |
385 } | 330 } |
OLD | NEW |