Using protobuf instead of ciyaml directly. (#2206)
diff --git a/app_dart/lib/src/foundation/utils.dart b/app_dart/lib/src/foundation/utils.dart
index 4183e09..40dcfd6 100644
--- a/app_dart/lib/src/foundation/utils.dart
+++ b/app_dart/lib/src/foundation/utils.dart
@@ -165,14 +165,21 @@
final List<String> noOwnerBuilders = <String>[];
final YamlMap? ciYaml = loadYaml(ciYamlContent) as YamlMap?;
final pb.SchedulerConfig unCheckedSchedulerConfig = pb.SchedulerConfig()..mergeFromProto3Json(ciYaml);
- final pb.SchedulerConfig schedulerConfig = CiYaml(
+ final CiYaml ciYamlFromProto = CiYaml(
slug: Config.flutterSlug,
branch: Config.defaultBranch(Config.flutterSlug),
config: unCheckedSchedulerConfig,
- ).config;
+ );
+
+ final pb.SchedulerConfig schedulerConfig = ciYamlFromProto.config;
+
for (pb.Target target in schedulerConfig.targets) {
final String builder = target.name;
- final String? owner = getTestOwnership(builder, getTypeForBuilder(builder, ciYaml!), testOwnersContent).owner;
+ final String? owner = getTestOwnership(
+ builder,
+ getTypeForBuilder(builder, ciYamlFromProto),
+ testOwnersContent,
+ ).owner;
print('$builder: $owner');
if (owner == null) {
noOwnerBuilders.add(builder);
diff --git a/app_dart/lib/src/model/ci_yaml/target.dart b/app_dart/lib/src/model/ci_yaml/target.dart
index 3a70770..316e898 100644
--- a/app_dart/lib/src/model/ci_yaml/target.dart
+++ b/app_dart/lib/src/model/ci_yaml/target.dart
@@ -89,6 +89,14 @@
return BatchPolicy();
}
+ /// Get the tags from the defined properties in the ci.
+ ///
+ /// Return an empty list if no tags are found.
+ List<String> get getTags {
+ Map<String, Object> properties = getProperties();
+ return (properties.containsKey('tags')) ? (properties['tags'] as List).map((e) => e as String).toList() : [];
+ }
+
/// Gets the assembled properties for this [pb.Target].
///
/// Target properties are prioritized in:
diff --git a/app_dart/lib/src/request_handlers/check_flaky_builders.dart b/app_dart/lib/src/request_handlers/check_flaky_builders.dart
index 5b40997..82e7a10 100644
--- a/app_dart/lib/src/request_handlers/check_flaky_builders.dart
+++ b/app_dart/lib/src/request_handlers/check_flaky_builders.dart
@@ -74,8 +74,9 @@
slug,
kTestOwnerPath,
);
+
for (final _BuilderInfo info in eligibleBuilders) {
- final BuilderType type = getTypeForBuilder(info.name, loadYaml(ciContent) as YamlMap);
+ final BuilderType type = getTypeForBuilder(info.name, ciYaml);
final TestOwnership testOwnership = getTestOwnership(info.name!, type, testOwnerContent);
final List<BuilderRecord> builderRecords =
await bigquery.listRecentBuildRecordsForBuilder(kBigQueryProjectId, builder: info.name, limit: kRecordNumber);
@@ -154,6 +155,8 @@
if (nameToExistingPRs.containsKey(builder)) {
continue;
}
+
+ //TODO (ricardoamador): Refactor this so we don't need to parse the entire yaml looking for commented issues, https://github.com/flutter/flutter/issues/113232
int builderLineNumber = lines.indexWhere((String line) => line.contains('name: $builder')) + 1;
while (builderLineNumber < lines.length && !lines[builderLineNumber].contains('name:')) {
if (lines[builderLineNumber].contains('$kCiYamlTargetIsFlakyKey:')) {
diff --git a/app_dart/lib/src/request_handlers/file_flaky_issue_and_pr.dart b/app_dart/lib/src/request_handlers/file_flaky_issue_and_pr.dart
index 65e727b..1decf11 100644
--- a/app_dart/lib/src/request_handlers/file_flaky_issue_and_pr.dart
+++ b/app_dart/lib/src/request_handlers/file_flaky_issue_and_pr.dart
@@ -57,7 +57,7 @@
if (statistic.flakyRate < _threshold) {
continue;
}
- final BuilderType type = getTypeForBuilder(statistic.name, ci!);
+ final BuilderType type = getTypeForBuilder(statistic.name, ciYaml);
await _fileIssueAndPR(
gitHub,
slug,
@@ -65,7 +65,7 @@
statistic: statistic,
existingIssue: nameToExistingIssue[statistic.name],
existingPullRequest: nameToExistingPR[statistic.name],
- isMarkedFlaky: _getIsMarkedFlaky(statistic.name, ci),
+ isMarkedFlaky: _getIsMarkedFlaky(statistic.name, ci!),
type: type,
ownership: getTestOwnership(statistic.name, type, testOwnerContent)),
);
diff --git a/app_dart/lib/src/request_handlers/flaky_handler_utils.dart b/app_dart/lib/src/request_handlers/flaky_handler_utils.dart
index 61ee372..0863779 100644
--- a/app_dart/lib/src/request_handlers/flaky_handler_utils.dart
+++ b/app_dart/lib/src/request_handlers/flaky_handler_utils.dart
@@ -5,8 +5,9 @@
import 'dart:convert';
import 'dart:core';
+import 'package:cocoon_service/ci_yaml.dart';
+import 'package:collection/collection.dart';
import 'package:github/github.dart';
-import 'package:yaml/yaml.dart';
import '../service/bigquery.dart';
import '../service/github_service.dart';
@@ -295,8 +296,8 @@
}
/// Looks up the owner of a builder in TESTOWNERS file.
-TestOwnership getTestOwnership(String builderName, BuilderType type, String testOwnersContent) {
- final String testName = _getTestNameFromBuilderName(builderName);
+TestOwnership getTestOwnership(String targetName, BuilderType type, String testOwnersContent) {
+ final String testName = _getTestNameFromTargetName(targetName);
String? owner;
Team? team;
switch (type) {
@@ -418,11 +419,12 @@
/// Gets the [BuilderType] of the builder by looking up the information in the
/// ci.yaml.
-BuilderType getTypeForBuilder(String? builderName, YamlMap ci) {
- final List<dynamic>? tags = _getTags(builderName, ci);
- if (tags == null) {
+BuilderType getTypeForBuilder(String? targetName, CiYaml ciYaml) {
+ final List<String>? tags = _getTags(targetName, ciYaml);
+ if (tags == null || tags.isEmpty) {
return BuilderType.unknown;
}
+
bool hasFrameworkTag = false;
bool hasHostOnlyTag = false;
// If tags contain 'shard', it must be a shard test.
@@ -430,7 +432,7 @@
// If tags contain 'firebaselab`, it must be a firebase tests.
// Otherwise, it is framework host only test if its tags contain both
// 'framework' and 'hostonly'.
- for (dynamic tag in tags) {
+ for (String tag in tags) {
if (tag == kCiYamlTargetTagsFirebaselab) {
return BuilderType.firebaselab;
} else if (tag == kCiYamlTargetTagsShard) {
@@ -446,21 +448,19 @@
return hasFrameworkTag && hasHostOnlyTag ? BuilderType.frameworkHostOnly : BuilderType.unknown;
}
-List<dynamic>? _getTags(String? builderName, YamlMap ci) {
- final YamlList targets = ci[kCiYamlTargetsKey] as YamlList;
- final YamlMap? target = targets.firstWhere(
- (dynamic element) => element[kCiYamlTargetNameKey] == builderName,
- orElse: () => null,
- ) as YamlMap?;
+List<String>? _getTags(String? targetName, CiYaml ciYaml) {
+ List<Target> allTargets = ciYaml.presubmitTargets;
+ allTargets.addAll(ciYaml.postsubmitTargets);
+ Target? target = allTargets.firstWhereOrNull((element) => element.value.name == targetName);
if (target == null) {
return null;
}
- return jsonDecode(target[kCiYamlPropertiesKey][kCiYamlTargetTagsKey] as String) as List<dynamic>?;
+ return target.getTags;
}
-String _getTestNameFromBuilderName(String builderName) {
+String _getTestNameFromTargetName(String targetName) {
// The builder names is in the format '<platform> <test name>'.
- final List<String> words = builderName.split(' ');
+ final List<String> words = targetName.split(' ');
return words.length < 2 ? words[0] : words[1];
}
diff --git a/app_dart/lib/src/request_handlers/update_existing_flaky_issues.dart b/app_dart/lib/src/request_handlers/update_existing_flaky_issues.dart
index 2c1fe42..a25caf0 100644
--- a/app_dart/lib/src/request_handlers/update_existing_flaky_issues.dart
+++ b/app_dart/lib/src/request_handlers/update_existing_flaky_issues.dart
@@ -28,26 +28,34 @@
const UpdateExistingFlakyIssue({
required super.config,
required super.authenticationProvider,
+ @visibleForTesting this.ciYaml,
});
static const String kThresholdKey = 'threshold';
static const int kFreshPeriodForOpenFlake = 7; // days
+ final CiYaml? ciYaml;
+
@override
Future<Body> get() async {
final RepositorySlug slug = Config.flutterSlug;
final GithubService gitHub = config.createGithubServiceWithToken(await config.githubOAuthToken);
final BigqueryService bigquery = await config.createBigQueryService();
- final YamlMap? ci = loadYaml(await gitHub.getFileContent(
- slug,
- kCiYamlPath,
- )) as YamlMap?;
- final pb.SchedulerConfig unCheckedSchedulerConfig = pb.SchedulerConfig()..mergeFromProto3Json(ci);
- final CiYaml ciYaml = CiYaml(
- slug: slug,
- branch: Config.defaultBranch(slug),
- config: unCheckedSchedulerConfig,
- );
+
+ CiYaml? localCiYaml = ciYaml;
+ if (localCiYaml == null) {
+ final YamlMap? ci = loadYaml(await gitHub.getFileContent(
+ slug,
+ kCiYamlPath,
+ )) as YamlMap?;
+ final pb.SchedulerConfig unCheckedSchedulerConfig = pb.SchedulerConfig()..mergeFromProto3Json(ci);
+ localCiYaml = CiYaml(
+ slug: slug,
+ branch: Config.defaultBranch(slug),
+ config: unCheckedSchedulerConfig,
+ );
+ }
+
final List<BuilderStatistic> prodBuilderStatisticList =
await bigquery.listBuilderStatistic(kBigQueryProjectId, bucket: 'prod');
final List<BuilderStatistic> stagingBuilderStatisticList =
@@ -56,7 +64,7 @@
await _updateExistingFlakyIssue(
gitHub,
slug,
- ciYaml,
+ localCiYaml,
prodBuilderStatisticList: prodBuilderStatisticList,
stagingBuilderStatisticList: stagingBuilderStatisticList,
nameToExistingIssue: nameToExistingIssue,
@@ -79,6 +87,7 @@
required Bucket bucket,
required BuilderStatistic statistic,
required Issue existingIssue,
+ required CiYaml ciYaml,
}) async {
if (DateTime.now().difference(existingIssue.createdAt!) < const Duration(days: kFreshPeriodForOpenFlake)) {
return;
@@ -88,17 +97,12 @@
await gitHub.createComment(slug, issueNumber: existingIssue.number, body: updateBuilder.issueUpdateComment);
await gitHub.replaceLabelsForIssue(slug, issueNumber: existingIssue.number, labels: updateBuilder.issueLabels);
if (existingIssue.assignee == null && !updateBuilder.isBelow) {
- final String ciContent = await gitHub.getFileContent(
- slug,
- kCiYamlPath,
- );
final String testOwnerContent = await gitHub.getFileContent(
slug,
kTestOwnerPath,
);
- final String? testOwner = getTestOwnership(
- statistic.name, getTypeForBuilder(statistic.name, loadYaml(ciContent) as YamlMap), testOwnerContent)
- .owner;
+ final String? testOwner =
+ getTestOwnership(statistic.name, getTypeForBuilder(statistic.name, ciYaml), testOwnerContent).owner;
if (testOwner != null) {
await gitHub.assignIssue(slug, issueNumber: existingIssue.number, assignee: testOwner);
}
@@ -133,8 +137,14 @@
builderFlakyMap.containsKey(statistic.name) &&
// ignore: iterable_contains_unrelated_type
!ignoreFlakyMap.containsKey(statistic.name)) {
- await _addCommentToExistingIssue(gitHub, slug,
- bucket: Bucket.prod, statistic: statistic, existingIssue: nameToExistingIssue[statistic.name]!);
+ await _addCommentToExistingIssue(
+ gitHub,
+ slug,
+ bucket: Bucket.prod,
+ statistic: statistic,
+ existingIssue: nameToExistingIssue[statistic.name]!,
+ ciYaml: ciYaml,
+ );
}
}
// For all staging builder stats, updates any existing flaky bug.
@@ -143,8 +153,14 @@
builderFlakyMap[statistic.name] == true &&
// ignore: iterable_contains_unrelated_type
!ignoreFlakyMap.containsKey(statistic.name)) {
- await _addCommentToExistingIssue(gitHub, slug,
- bucket: Bucket.staging, statistic: statistic, existingIssue: nameToExistingIssue[statistic.name]!);
+ await _addCommentToExistingIssue(
+ gitHub,
+ slug,
+ bucket: Bucket.staging,
+ statistic: statistic,
+ existingIssue: nameToExistingIssue[statistic.name]!,
+ ciYaml: ciYaml,
+ );
}
}
}
diff --git a/app_dart/test/model/ci_yaml/target_test.dart b/app_dart/test/model/ci_yaml/target_test.dart
index cd2b4ca..189385b 100644
--- a/app_dart/test/model/ci_yaml/target_test.dart
+++ b/app_dart/test/model/ci_yaml/target_test.dart
@@ -105,6 +105,34 @@
});
});
+ test('tags are parsed from within properties', () {
+ final Target target = generateTarget(
+ 1,
+ platform: 'Linux_build_test',
+ platformProperties: <String, String>{
+ // This should be overrided by the target specific property
+ 'android_sdk': 'abc',
+ },
+ properties: <String, String>{'xcode': '12abc', 'tags': '["devicelab", "android", "linux"]'},
+ );
+ expect(target.getTags, ['devicelab', 'android', 'linux']);
+ });
+
+ test('we do not blow up if tags are not present', () {
+ final Target target = generateTarget(
+ 1,
+ platform: 'Linux_build_test',
+ platformProperties: <String, String>{
+ // This should be overrided by the target specific property
+ 'android_sdk': 'abc',
+ },
+ properties: <String, String>{
+ 'xcode': '12abc',
+ },
+ );
+ expect(target.getTags, []);
+ });
+
test('platform properties with xcode', () {
final Target target = generateTarget(
1,
diff --git a/app_dart/test/request_handlers/update_existing_flaky_issues_test.dart b/app_dart/test/request_handlers/update_existing_flaky_issues_test.dart
index b2b27c7..d8267e7 100644
--- a/app_dart/test/request_handlers/update_existing_flaky_issues_test.dart
+++ b/app_dart/test/request_handlers/update_existing_flaky_issues_test.dart
@@ -56,14 +56,6 @@
return const Stream<Issue>.empty();
});
- // when gets the content of .ci.yaml
- when(mockRepositoriesService.getContents(
- captureAny,
- kCiYamlPath,
- )).thenAnswer((Invocation invocation) {
- return Future<RepositoryContents>.value(
- RepositoryContents(file: GitHubFile(content: gitHubEncode(ciYamlContent))));
- });
// when gets the content of TESTOWNERS
when(mockRepositoriesService.getContents(
captureAny,
@@ -87,6 +79,7 @@
handler = UpdateExistingFlakyIssue(
config: config,
authenticationProvider: auth,
+ ciYaml: testCiYaml,
);
});
@@ -326,6 +319,7 @@
)).thenAnswer((Invocation invocation) {
return Future<Response>.value(Response('[]', 200));
});
+
final Map<String, dynamic> result = await utf8.decoder
.bind((await tester.get<Body>(handler)).serialize() as Stream<List<int>>)
.transform(json.decoder)
diff --git a/app_dart/test/request_handlers/update_existing_flaky_issues_test_data.dart b/app_dart/test/request_handlers/update_existing_flaky_issues_test_data.dart
index f05638b..5b3c821 100644
--- a/app_dart/test/request_handlers/update_existing_flaky_issues_test_data.dart
+++ b/app_dart/test/request_handlers/update_existing_flaky_issues_test_data.dart
@@ -4,7 +4,11 @@
import 'dart:convert';
+import 'package:cocoon_service/src/model/ci_yaml/ci_yaml.dart';
import 'package:cocoon_service/src/service/bigquery.dart';
+import 'package:cocoon_service/src/service/config.dart';
+
+import 'package:cocoon_service/src/model/proto/protos.dart' as pb;
const String expectedSemanticsIntegrationTestIssueComment = '''
[prod pool] current flaky ratio for the past (up to) 100 commits is 50.00%. Flaky number: 3; total number: 10.
@@ -203,66 +207,82 @@
Please follow https://github.com/flutter/flutter/wiki/Reducing-Test-Flakiness#fixing-flaky-tests to fix the flakiness and enable the test back after validating the fix (internal dashboard to validate: go/flutter_test_flakiness).
''';
-const String ciYamlContent = '''
-# Describes the targets run in continuous integration environment.
-#
-# Flutter infra uses this file to generate a checklist of tasks to be performed
-# for every commit.
-#
-# More information at:
-# * https://github.com/flutter/cocoon/blob/master/scheduler/README.md
-enabled_branches:
- - master
-
-targets:
- - name: Mac_android android_semantics_integration_test
- builder: Mac_android android_semantics_integration_test
- presubmit: false
- scheduler: luci
- properties:
- tags: >
- ["devicelab"]
-
- - name: Mac_android ignore_myflakiness
- builder: Mac_android android_semantics_integration_test
- presubmit: false
- scheduler: luci
- properties:
- ignore_flakiness: "true"
- tags: >
- ["devicelab"]
-
- - name: Linux ci_yaml flutter roller
- recipe: infra/ci_yaml
- bringup: true # TODO(chillers): https://github.com/flutter/flutter/issues/93225
- timeout: 30
- properties:
- tags: >
- ["framework","hostonly","shard"]
- scheduler: luci
- runIf:
- - .ci.yaml
-
- - name: Mac build_tests_1_4
- recipe: flutter/flutter_drone
- timeout: 60
- properties:
- add_recipes_cq: "true"
- dependencies: >-
- [
- {"dependency": "android_sdk", "version": "version:29.0"},
- {"dependency": "chrome_and_driver", "version": "version:84"},
- {"dependency": "open_jdk", "version": "11"},
- {"dependency": "xcode", "version": "13a233"},
- {"dependency": "gems", "version": "v3.3.14"},
- {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}
- ]
- shard: build_tests
- subshard: "1_4"
- tags: >
- ["framework","hostonly","shard"]
- scheduler: luci
-''';
+final CiYaml testCiYaml = CiYaml(
+ slug: Config.flutterSlug,
+ branch: Config.defaultBranch(Config.flutterSlug),
+ config: pb.SchedulerConfig(
+ enabledBranches: <String>[
+ Config.defaultBranch(Config.flutterSlug),
+ ],
+ targets: <pb.Target>[
+ pb.Target(
+ name: 'Mac_android android_semantics_integration_test',
+ scheduler: pb.SchedulerSystem.luci,
+ presubmit: false,
+ properties: <String, String>{
+ 'tags': jsonEncode(['devicelab'])
+ },
+ ),
+ pb.Target(
+ name: 'Mac_android ignore_myflakiness',
+ scheduler: pb.SchedulerSystem.luci,
+ presubmit: false,
+ properties: <String, String>{
+ 'ignore_flakiness': 'true',
+ 'tags': jsonEncode(['devicelab']),
+ }),
+ pb.Target(
+ name: 'Linux ci_yaml flutter roller',
+ scheduler: pb.SchedulerSystem.luci,
+ bringup: true,
+ timeout: 30,
+ runIf: ['.ci.yaml'],
+ recipe: 'infra/ci_yaml',
+ properties: <String, String>{
+ 'tags': jsonEncode(["framework", "hostonly", "shard"]),
+ },
+ ),
+ pb.Target(
+ name: 'Mac build_tests_1_4',
+ scheduler: pb.SchedulerSystem.luci,
+ recipe: 'flutter/flutter_drone',
+ timeout: 60,
+ properties: <String, String>{
+ 'add_recipes_cq': 'true',
+ 'shard': 'build_tests',
+ 'subshard': '1_4',
+ 'tags': jsonEncode(["framework", "hostonly", "shard"]),
+ 'dependencies': jsonEncode([
+ {
+ 'dependency': 'android_sdk',
+ 'version': 'version:29.0',
+ },
+ {
+ 'dependency': 'chrome_and_driver',
+ 'version': 'version:84',
+ },
+ {
+ 'dependency': 'xcode',
+ 'version': '13a233',
+ },
+ {
+ 'dependency': 'open_jdk',
+ 'version': '11',
+ },
+ {
+ 'dependency': 'gems',
+ 'version': 'v3.3.14',
+ },
+ {
+ 'dependency': 'goldctl',
+ 'version': 'git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603',
+ },
+ ]),
+ },
+ ),
+ ],
+ ),
+);
const String testOwnersContent = '''
diff --git a/app_dart/test/src/utilities/entity_generators.dart b/app_dart/test/src/utilities/entity_generators.dart
index 786a1c7..197b210 100644
--- a/app_dart/test/src/utilities/entity_generators.dart
+++ b/app_dart/test/src/utilities/entity_generators.dart
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'package:cocoon_service/ci_yaml.dart';
import 'package:cocoon_service/src/model/appengine/commit.dart';
import 'package:cocoon_service/src/model/appengine/task.dart';
import 'package:cocoon_service/src/model/ci_yaml/target.dart';
diff --git a/dashboard/pubspec.lock b/dashboard/pubspec.lock
index e23aa55..9dc64c6 100644
--- a/dashboard/pubspec.lock
+++ b/dashboard/pubspec.lock
@@ -323,7 +323,7 @@
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
- version: "0.1.5"
+ version: "0.2.0"
meta:
dependency: transitive
description:
@@ -447,7 +447,7 @@
name: source_span
url: "https://pub.dartlang.org"
source: hosted
- version: "1.9.0"
+ version: "1.9.1"
stack_trace:
dependency: transitive
description:
@@ -461,7 +461,7 @@
name: stream_channel
url: "https://pub.dartlang.org"
source: hosted
- version: "2.1.0"
+ version: "2.1.1"
stream_transform:
dependency: transitive
description:
@@ -489,7 +489,7 @@
name: test_api
url: "https://pub.dartlang.org"
source: hosted
- version: "0.4.12"
+ version: "0.4.14"
timing:
dependency: transitive
description:
@@ -573,7 +573,7 @@
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
- version: "2.1.2"
+ version: "2.1.4"
watcher:
dependency: transitive
description:
@@ -596,5 +596,5 @@
source: hosted
version: "3.1.1"
sdks:
- dart: ">=2.17.0 <3.0.0"
+ dart: ">=2.18.0 <3.0.0"
flutter: ">=2.10.0"