blob: b94cd004a8f99b4b03c3f486976ea11ef97606d6 [file] [log] [blame]
// 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.
// Feed of recent approvals.
import 'dart:async';
import 'dart:collection';
import 'dart:convert';
import 'dart:io';
import 'package:dart_ci/src/get_log.dart';
// TODO: Hack.
const builders = [
"analyzer-analysis-server-linux",
"analyzer-linux-release",
"analyzer-mac-release",
"analyzer-win-release",
"app-kernel-linux-debug-x64",
"app-kernel-linux-product-x64",
"app-kernel-linux-release-x64",
"cross-vm-linux-release-arm64",
"dart2js-csp-minified-linux-x64-chrome",
"dart2js-minified-strong-linux-x64-d8",
"dart2js-strong-hostasserts-linux-ia32-d8",
"dart2js-strong-linux-x64-chrome",
"dart2js-strong-linux-x64-firefox",
"dart2js-strong-mac-x64-chrome",
"dart2js-strong-mac-x64-safari",
"dart2js-strong-win-x64-chrome",
"dart2js-strong-win-x64-ie11",
"dart2js-unit-linux-x64-release",
"ddc-linux-release-chrome",
"ddc-mac-release-chrome",
"ddc-win-release-chrome",
"front-end-linux-release-x64",
"front-end-mac-release-x64",
"front-end-win-release-x64",
"pkg-linux-debug",
"pkg-linux-release",
"pkg-mac-release",
"pkg-win-release",
"vm-canary-linux-debug",
"vm-dartkb-linux-debug-simarm64",
"vm-dartkb-linux-debug-x64",
"vm-dartkb-linux-product-simarm64",
"vm-dartkb-linux-product-x64",
"vm-dartkb-linux-release-simarm64",
"vm-dartkb-linux-release-x64",
"vm-ffi-android-debug-arm",
"vm-ffi-android-debug-arm64",
"vm-ffi-android-product-arm",
"vm-ffi-android-product-arm64",
"vm-ffi-android-release-arm",
"vm-ffi-android-release-arm64",
"vm-kernel-asan-linux-release-x64",
"vm-kernel-checked-linux-release-x64",
"vm-kernel-linux-debug-ia32",
"vm-kernel-linux-debug-simdbc64",
"vm-kernel-linux-debug-x64",
"vm-kernel-linux-product-x64",
"vm-kernel-linux-release-ia32",
"vm-kernel-linux-release-simarm",
"vm-kernel-linux-release-simarm64",
"vm-kernel-linux-release-simdbc64",
"vm-kernel-linux-release-x64",
"vm-kernel-mac-debug-simdbc64",
"vm-kernel-mac-debug-x64",
"vm-kernel-mac-product-x64",
"vm-kernel-mac-release-simdbc64",
"vm-kernel-mac-release-x64",
"vm-kernel-optcounter-threshold-linux-release-ia32",
"vm-kernel-optcounter-threshold-linux-release-x64",
"vm-kernel-precomp-android-release-arm",
"vm-kernel-precomp-bare-linux-release-simarm",
"vm-kernel-precomp-bare-linux-release-simarm64",
"vm-kernel-precomp-bare-linux-release-x64",
"vm-kernel-precomp-linux-debug-x64",
"vm-kernel-precomp-linux-product-x64",
"vm-kernel-precomp-linux-release-simarm",
"vm-kernel-precomp-linux-release-simarm64",
"vm-kernel-precomp-linux-release-x64",
"vm-kernel-precomp-mac-release-simarm64",
"vm-kernel-precomp-obfuscate-linux-release-x64",
"vm-kernel-precomp-win-release-simarm64",
"vm-kernel-precomp-win-release-x64",
"vm-kernel-reload-linux-debug-x64",
"vm-kernel-reload-linux-release-x64",
"vm-kernel-reload-mac-debug-simdbc64",
"vm-kernel-reload-mac-release-simdbc64",
"vm-kernel-reload-rollback-linux-debug-x64",
"vm-kernel-reload-rollback-linux-release-x64",
"vm-kernel-win-debug-ia32",
"vm-kernel-win-debug-x64",
"vm-kernel-win-product-x64",
"vm-kernel-win-release-ia32",
"vm-kernel-win-release-x64",
];
class Approval implements Comparable {
final String builder;
final String configuration;
final String name;
final String suite;
final String testName;
final String result;
final bool matches;
Approval(this.builder, this.configuration, this.name, this.suite,
this.testName, this.result, this.matches);
String get sortKey => "$name:$configuration";
bool operator ==(Object other) =>
other is Approval && other.sortKey == sortKey;
int compareTo(Object other) {
if (other is Approval) {
return sortKey.compareTo(other.sortKey);
}
return -1;
}
}
class ApprovalEvent {
final approver;
final approvedAt;
final changeId;
ApprovalEvent(this.approver, this.approvedAt, this.changeId);
final approvals = new SplayTreeSet<Approval>();
}
final approvalEvents = new SplayTreeMap<String, ApprovalEvent>();
Future getApprovals() async {
for (final builder in builders) {
try {
print("Downloading approvals for $builder");
final data = await getApproval(builder);
if (data == null) continue;
for (final line in LineSplitter.split(data)) {
final record = jsonDecode(line);
final approver = record["approver"];
final approvedAt = record["approved_at"];
if (approver == null || approvedAt == null) {
continue;
}
final String name = record["name"];
final String configuration = record["configuration"];
final String suite = record["suite"];
final String testName = record["test_name"];
final String result = record["result"];
final bool matches = record["matches"];
if (matches) continue;
final approvalEvent = approvalEvents.putIfAbsent(
approvedAt, () => new ApprovalEvent(approver, approvedAt, null));
final approval = new Approval(
builder, configuration, name, suite, testName, result, matches);
approvalEvent.approvals.add(approval);
final preapprovals = record["preapprovals"] ?? <String, dynamic>{};
for (final changeId in preapprovals.keys) {
final preapprovalRecord = preapprovals[changeId];
final preapprover = preapprovalRecord["preapprover"];
final preapprovedAt = preapprovalRecord["preapproved_at"];
final String preapprovedResult = preapprovalRecord["result"];
final bool preapprovedMatches = preapprovalRecord["matches"];
if (preapprovedMatches) continue;
final preapprovalEvent = approvalEvents.putIfAbsent(
"preapprovedAt $changeId",
() => new ApprovalEvent(preapprover, preapprovedAt, changeId));
final preapproval = new Approval(builder, configuration, name, suite,
testName, preapprovedResult, preapprovedMatches);
preapprovalEvent.approvals.add(preapproval);
}
}
} catch (e, st) {
print("Failed to download approvals for $builder: $e\n$st");
}
}
}
void serveApprovals(HttpRequest request) async {
request.response.headers.contentType = ContentType.html;
request.response.write("""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Approvals Feed</title>
</head>
<body>
<h1>Approvals Feed</h1>
""");
for (final event in approvalEvents.values.toList().reversed.take(100)) {
final time = event.approvedAt.replaceAll("T", " ").substring(0, 19);
final approver = event.approver;
final action = event.changeId != null
? "<a href='https://dart-review.googlesource.com/q/${event.changeId}'>"
"pre-approved ${event.changeId}"
"</a>"
: "approved";
request.response.write("<h2>$time $approver $action</h2>\n");
request.response.write("<table>\n");
for (final approval in event.approvals) {
final what = approval.matches ? "succeeding" : approval.result;
final color = approval.matches ? "green" : "red";
request.response.write("<tr>");
request.response.write("<td>${approval.name}</td>");
request.response.write("<td><b style='color: $color;'>$what</b></td>");
request.response.write("<td>${approval.builder}</td>");
request.response.write("<td>${approval.configuration}</td>");
request.response.write("</tr>\n");
}
request.response.write("</table>\n");
}
request.response.write(""" </body>
</html>
""");
request.response.close();
}