Chromium Code Reviews| 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 |