| // Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 |  | 
 | // Add fields with data about the test run and the commit tested, and | 
 | // with the result on the last build tested, to the test results file. | 
 |  | 
 | import 'dart:convert'; | 
 | import 'dart:io'; | 
 |  | 
 | import 'package:test_runner/bot_results.dart'; | 
 |  | 
 | const skipped = 'skipped'; | 
 |  | 
 | void main(List<String> args) async { | 
 |   final resultsPath = args[0]; | 
 |   final priorResultsPath = args[1]; | 
 |   final flakyPath = args[2]; | 
 |   final priorFlakyPath = args[3]; | 
 |   final builderName = args[4]; | 
 |   final buildNumber = args[5]; | 
 |   final commitTime = int.parse(args[6]); | 
 |   final commitHash = args[7]; | 
 |   final newResultsPath = args[8]; | 
 |   // Load the input and the flakiness data if specified. | 
 |   final results = await loadResultsMap(resultsPath); | 
 |   final priorResults = await loadResultsMap(priorResultsPath); | 
 |   final flakes = await loadResultsMap(flakyPath); | 
 |   final priorFlakes = await loadResultsMap(priorFlakyPath); | 
 |   final firstPriorResult = | 
 |       priorResults.isEmpty ? null : priorResults.values.first; | 
 |  | 
 |   priorResults.forEach((key, priorResult) { | 
 |     if (priorResult['result'] != skipped) { | 
 |       results.putIfAbsent(key, () => constructNotRunResult(priorResult)); | 
 |     } | 
 |   }); | 
 |   for (final String key in results.keys) { | 
 |     final Map<String, dynamic> result = results[key]!; | 
 |     final Map<String, dynamic>? priorResult = priorResults[key]; | 
 |     final Map<String, dynamic>? flaky = flakes[key]; | 
 |     final Map<String, dynamic>? priorFlaky = priorFlakes[key]; | 
 |     result['commit_hash'] = commitHash; | 
 |     result['commit_time'] = commitTime; | 
 |     result['build_number'] = buildNumber; | 
 |     result['builder_name'] = builderName; | 
 |     result['flaky'] = flaky != null && (flaky['active'] ?? true) == true; | 
 |     result['previous_flaky'] = | 
 |         priorFlaky != null && (priorFlaky['active'] ?? true) == true; | 
 |     if (firstPriorResult != null) { | 
 |       result['previous_commit_hash'] = firstPriorResult['commit_hash']; | 
 |       result['previous_commit_time'] = firstPriorResult['commit_time']; | 
 |       result['previous_build_number'] = firstPriorResult['build_number']; | 
 |     } | 
 |     if (priorResult != null) { | 
 |       result['previous_result'] = priorResult['result']; | 
 |       result['changed'] = !(result['result'] == result['previous_result'] && | 
 |           result['flaky'] == result['previous_flaky'] && | 
 |           result['expected'] == priorResult['expected']); | 
 |     } else { | 
 |       result['changed'] = true; | 
 |     } | 
 |   } | 
 |   final sink = File(newResultsPath).openWrite(); | 
 |   final sorted = results.keys.toList()..sort(); | 
 |   for (final key in sorted) { | 
 |     sink.writeln(jsonEncode(results[key])); | 
 |   } | 
 |   sink.close(); | 
 | } | 
 |  | 
 | Map<String, dynamic> constructNotRunResult(Map<String, dynamic> previous) => { | 
 |       for (final key in [ | 
 |         'name', | 
 |         'configuration', | 
 |         'suite', | 
 |         'test_name', | 
 |         'expected' | 
 |       ]) | 
 |         key: previous[key], | 
 |       'time_ms': 0, | 
 |       'result': skipped, | 
 |       'matches': true, | 
 |       'bot_name': '', | 
 |     }; |