| 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 /// Compares the test log of a build step with previous builds. | 5 /// Compares the test log of a build step with previous builds. |
| 6 /// | 6 /// |
| 7 /// Use this to detect flakiness of failures, especially timeouts. | 7 /// Use this to detect flakiness of failures, especially timeouts. |
| 8 | 8 |
| 9 import 'dart:async'; | 9 import 'dart:async'; |
| 10 import 'dart:io'; |
| 10 | 11 |
| 11 import 'package:gardening/src/bot.dart'; | 12 import 'package:gardening/src/bot.dart'; |
| 12 import 'package:gardening/src/buildbot_structures.dart'; | 13 import 'package:gardening/src/buildbot_structures.dart'; |
| 13 import 'package:gardening/src/buildbot_data.dart'; | 14 import 'package:gardening/src/buildbot_data.dart'; |
| 14 import 'package:gardening/src/util.dart'; | 15 import 'package:gardening/src/util.dart'; |
| 15 | 16 |
| 16 Future mainInternal(Bot bot, List<String> args, {int runCount: 10}) async { | 17 Future mainInternal(Bot bot, List<String> args, {int runCount: 10}) async { |
| 17 printBuildResultsSummary( | 18 printBuildResultsSummary( |
| 18 await loadBuildResults(bot, args, runCount: runCount), args); | 19 await loadBuildResults(bot, args, runCount: runCount), args); |
| 19 } | 20 } |
| 20 | 21 |
| 22 RegExp logdogUrlRegexp = |
| 23 new RegExp(r'https://luci-logdog.appspot.com/.*client.dart'); |
| 24 |
| 21 /// Loads [BuildResult]s for the [runCount] last builds for the build(s) in | 25 /// Loads [BuildResult]s for the [runCount] last builds for the build(s) in |
| 22 /// [args]. [args] can be a list of [BuildGroup] names or a list of log uris. | 26 /// [args]. [args] can be a list of [BuildGroup] names or a list of log uris. |
| 23 Future<Map<BuildUri, List<BuildResult>>> loadBuildResults( | 27 Future<Map<BuildUri, List<BuildResult>>> loadBuildResults( |
| 24 Bot bot, List<String> args, | 28 Bot bot, List<String> args, |
| 25 {int runCount: 10}) async { | 29 {int runCount: 10}) async { |
| 26 List<BuildUri> buildUriList = <BuildUri>[]; | 30 List<BuildUri> buildUriList = <BuildUri>[]; |
| 31 for (String arg in args) { |
| 32 if (logdogUrlRegexp.hasMatch(arg)) { |
| 33 print('Encountered a logdog URI ("${arg.substring(0,40)}...").'); |
| 34 print('Please use the regular log URI, even with --logdog.'); |
| 35 exit(-1); |
| 36 } |
| 37 } |
| 27 for (BuildGroup buildGroup in buildGroups) { | 38 for (BuildGroup buildGroup in buildGroups) { |
| 28 if (args.contains(buildGroup.groupName)) { | 39 if (args.contains(buildGroup.groupName)) { |
| 29 buildUriList.addAll(buildGroup.createUris(bot.mostRecentBuildNumber)); | 40 buildUriList.addAll(buildGroup.createUris(bot.mostRecentBuildNumber)); |
| 30 } | 41 } |
| 31 } | 42 } |
| 32 if (buildUriList.isEmpty) { | 43 if (buildUriList.isEmpty) { |
| 33 for (String url in args) { | 44 for (String url in args) { |
| 34 buildUriList.add(new BuildUri.fromUrl(url)); | 45 buildUriList.add(new BuildUri.fromUrl(url)); |
| 35 } | 46 } |
| 36 } | 47 } |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 121 } | 132 } |
| 122 | 133 |
| 123 class Summary { | 134 class Summary { |
| 124 final BuildUri buildUri; | 135 final BuildUri buildUri; |
| 125 final List<BuildResult> results; | 136 final List<BuildResult> results; |
| 126 final Set<TestConfiguration> timeoutIds = new Set<TestConfiguration>(); | 137 final Set<TestConfiguration> timeoutIds = new Set<TestConfiguration>(); |
| 127 final Set<TestConfiguration> errorIds = new Set<TestConfiguration>(); | 138 final Set<TestConfiguration> errorIds = new Set<TestConfiguration>(); |
| 128 | 139 |
| 129 Summary(this.buildUri, this.results) { | 140 Summary(this.buildUri, this.results) { |
| 130 for (BuildResult result in results) { | 141 for (BuildResult result in results) { |
| 142 if (result == null) continue; |
| 131 timeoutIds | 143 timeoutIds |
| 132 .addAll(result.timeouts.map((TestFailure failure) => failure.id)); | 144 .addAll(result.timeouts.map((TestFailure failure) => failure.id)); |
| 133 errorIds.addAll(result.errors.map((TestFailure failure) => failure.id)); | 145 errorIds.addAll(result.errors.map((TestFailure failure) => failure.id)); |
| 134 } | 146 } |
| 135 } | 147 } |
| 136 | 148 |
| 137 bool get isEmpty => timeoutIds.isEmpty && errorIds.isEmpty; | 149 bool get isEmpty => timeoutIds.isEmpty && errorIds.isEmpty; |
| 138 | 150 |
| 139 /// Generate a summary of the timeouts and other failures in [results]. | 151 /// Generate a summary of the timeouts and other failures in [results]. |
| 140 void printOn(StringBuffer sb) { | 152 void printOn(StringBuffer sb) { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 sb.write('No errors found for ${name}'); | 223 sb.write('No errors found for ${name}'); |
| 212 } | 224 } |
| 213 } | 225 } |
| 214 | 226 |
| 215 String get name => results.isNotEmpty | 227 String get name => results.isNotEmpty |
| 216 // Use the first result as name since it most likely has an absolute build | 228 // Use the first result as name since it most likely has an absolute build |
| 217 // number. | 229 // number. |
| 218 ? results.first.buildUri.toString() | 230 ? results.first.buildUri.toString() |
| 219 : buildUri.toString(); | 231 : buildUri.toString(); |
| 220 } | 232 } |
| OLD | NEW |