Skip to content

Commit b1b5f82

Browse files
committed
[infra] Use buildbucket.v2 API in find_base_commit
* Migrate find_base_commit to null-safety. * Replace incorrect use of the term "bot" with "builder". See also https://crbug.com/1112975. Change-Id: Iee07e46a19a6304184e66f36560fba88d9b18971 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/171730 Reviewed-by: Jonas Termansen <[email protected]>
1 parent 5cbb25f commit b1b5f82

File tree

1 file changed

+67
-49
lines changed

1 file changed

+67
-49
lines changed

tools/bots/find_base_commit.dart

Lines changed: 67 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
// for details. All rights reserved. Use of this source code is governed by a
44
// BSD-style license that can be found in the LICENSE file.
55

6-
// Find the newest commit that has a full set of results on the bots.
7-
8-
// @dart = 2.9
6+
// Find the newest commit that has a full set of results on the builders.
97

108
import 'dart:async';
119
import 'dart:convert';
@@ -17,13 +15,13 @@ import 'package:glob/glob.dart';
1715

1816
void main(List<String> args) async {
1917
final parser = new ArgParser();
20-
parser.addMultiOption("bot",
18+
parser.addMultiOption("builder",
2119
abbr: "b",
22-
help: "Select the bots matching the glob pattern [option is repeatable]",
20+
help: "Select the builders matching the glob [option is repeatable]",
2321
splitCommas: false);
2422
parser.addOption("branch",
2523
abbr: "B",
26-
help: "Select the bots building this branch",
24+
help: "Select the builders building this branch",
2725
defaultsTo: "master");
2826
parser.addOption("count",
2927
abbr: "c", help: "List this many commits", defaultsTo: "1");
@@ -33,7 +31,7 @@ void main(List<String> args) async {
3331
if (options["help"]) {
3432
print("""
3533
Usage: find_base_commit.dart [OPTION]...
36-
Find the newest commit that has a full set of results on the bots.
34+
Find the newest commit that has a full set of results on the builders.
3735
3836
The options are as follows:
3937
@@ -43,34 +41,50 @@ ${parser.usage}""");
4341

4442
int count = int.parse(options["count"]);
4543
final globs = new List<Glob>.from(
46-
options["bot"].map((String pattern) => new Glob(pattern)));
44+
options["builder"].map((String pattern) => new Glob(pattern)));
4745

4846
// Download the most recent builds from buildbucket.
49-
int maxBuilds = 1000;
50-
final url = Uri.parse(
51-
"https://cr-buildbucket.appspot.com/_ah/api/buildbucket/v1/search"
52-
"?bucket=luci.dart.ci.sandbox"
53-
"&max_builds=$maxBuilds"
54-
"&status=COMPLETED"
55-
"&fields=builds(url%2Cparameters_json)");
47+
const maxBuilds = 1000;
48+
final url = Uri.parse("https://cr-buildbucket.appspot.com"
49+
"/prpc/buildbucket.v2.Builds/SearchBuilds");
5650
const maxRetries = 3;
5751
const timeout = const Duration(seconds: 30);
58-
Map<String, dynamic> object;
52+
final query = jsonEncode({
53+
"predicate": {
54+
"builder": {"project": "dart", "bucket": "ci.sandbox"},
55+
"status": "ENDED_MASK"
56+
},
57+
"pageSize": maxBuilds,
58+
"fields": "builds.*.builder.builder,builds.*.input"
59+
});
60+
late Map<String, dynamic> searchResult;
5961
for (int i = 1; i <= maxRetries; i++) {
6062
try {
6163
final client = new HttpClient();
62-
final request = await client.getUrl(url).timeout(timeout);
64+
final request = await client.postUrl(url).timeout(timeout)
65+
..headers.contentType = ContentType.json
66+
..headers.add(HttpHeaders.acceptHeader, ContentType.json)
67+
..write(query);
6368
final response = await request.close().timeout(timeout);
64-
object = await response
69+
if (response.statusCode != 200) {
70+
print("Failed to search for builds: "
71+
"${response.statusCode}:${response.reasonPhrase}");
72+
exit(1);
73+
}
74+
const prefix = ")]}'";
75+
searchResult = await (response
6576
.cast<List<int>>()
6677
.transform(new Utf8Decoder())
78+
.map((event) =>
79+
event.startsWith(prefix) ? event.substring(prefix.length) : event)
6780
.transform(new JsonDecoder())
81+
.cast<Map<String, dynamic>>()
6882
.first
69-
.timeout(timeout);
83+
.timeout(timeout));
7084
client.close();
7185
break;
7286
} on TimeoutException catch (e) {
73-
final inSeconds = e.duration.inSeconds;
87+
final inSeconds = e.duration?.inSeconds;
7488
stderr.writeln(
7589
"Attempt $i of $maxRetries timed out after $inSeconds seconds");
7690
if (i == maxRetries) {
@@ -81,57 +95,61 @@ ${parser.usage}""");
8195
}
8296

8397
// Locate the builds we're interested in and map them to each commit. The
84-
// builds returned by the API are sorted with the newest first. Since bots
98+
// builds returned by the API are sorted with the newest first. Since builders
8599
// don't build back in time and always build the latest commit whenever they
86100
// can, the first time we see a commit, we know it's newer than all commits
87-
// we haven't seen yet. The insertion order into the botsForCommits map will
88-
// then sorted with the newest commit first.
89-
final builds = object["builds"];
90-
final botsForCommits = <String, Set<String>>{};
101+
// we haven't seen yet. The insertion order into the buildersForCommits map
102+
// will then sorted with the newest commit first.
103+
final builds = searchResult["builds"];
104+
if (builds == null) {
105+
print("No builds found");
106+
exit(1);
107+
}
108+
final buildersForCommits = <String, Set<String>>{};
91109
for (final build in builds) {
92-
final parameters = jsonDecode(build["parameters_json"]);
93-
final bot = parameters["builder_name"];
94-
if (bot.endsWith("-beta") ||
95-
bot.endsWith("-dev") ||
96-
bot.endsWith("-stable")) {
110+
final builder = build["builder"]?["builder"];
111+
if (builder is! String ||
112+
builder.endsWith("-beta") ||
113+
builder.endsWith("-dev") ||
114+
builder.endsWith("-stable")) {
97115
// Ignore the release builders. The -try builders aren't in the
98116
// bucket we're reading.
99117
continue;
100118
}
101-
if (globs.isNotEmpty && !globs.any((glob) => glob.matches(bot))) {
102-
// Filter way bots we're not interested in.
119+
if (globs.isNotEmpty && !globs.any((glob) => glob.matches(builder))) {
120+
// Filter way builders we're not interested in.
103121
continue;
104122
}
105-
final properties = parameters["properties"];
106-
final branch = properties["branch"];
107-
if (branch != null && branch != "refs/heads/${options['branch']}") {
108-
// Ignore bots that are building the wrong branch.
123+
final input = build["input"]?["gitilesCommit"];
124+
if (input == null) {
125+
// Ignore builds not triggered by a commit, e.g. fuzz-linux.
109126
continue;
110127
}
111-
final commit = properties["revision"];
112-
if (commit == null) {
113-
// Ignore bots that aren't commit based, e.g. fuzz-linux.
128+
final ref = input["ref"];
129+
if (ref != "refs/heads/${options['branch']}") {
130+
// Ignore builds on the wrong branch.
114131
continue;
115132
}
116-
final botsForCommit =
117-
botsForCommits.putIfAbsent(commit, () => new Set<String>());
118-
botsForCommit.add(bot);
133+
final commit = input["id"] as String;
134+
final buildersForCommit =
135+
buildersForCommits.putIfAbsent(commit, () => new Set<String>());
136+
buildersForCommit.add(builder);
119137
}
120138

121-
if (botsForCommits.isEmpty) {
122-
print("Failed to locate any commits having run on the bots");
139+
if (buildersForCommits.isEmpty) {
140+
print("Failed to locate any commits having run on the builders");
123141
exitCode = 1;
124142
return;
125143
}
126144

127145
int maxBots = 0;
128-
for (final commit in botsForCommits.keys) {
129-
maxBots = max(maxBots, botsForCommits[commit].length);
146+
for (final builders in buildersForCommits.values) {
147+
maxBots = max(maxBots, builders.length);
130148
}
131149

132-
// List commits run on the most bots.
133-
for (final commit in botsForCommits.keys
134-
.where((commit) => botsForCommits[commit].length == maxBots)
150+
// List commits run on the most builders.
151+
for (final commit in buildersForCommits.keys
152+
.where((commit) => buildersForCommits[commit]!.length == maxBots)
135153
.take(count)) {
136154
print(commit);
137155
}

0 commit comments

Comments
 (0)