Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions app_dart/lib/src/datastore/cocoon_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,7 @@ class Config {

// Gets supported luci builders based on github http request.
Future<List<Map<String, dynamic>>> _getLuciBuilders(String bucket) async {
final String builderContent =
await getBuilders(Providers.freshHttpClient, loggingService, twoSecondLinearBackoff, bucket);
final Map<String, dynamic> builderMap = json.decode(builderContent) as Map<String, dynamic>;
final List<dynamic> builderList = builderMap['builders'] as List<dynamic>;
return builderList.map((dynamic builder) => builder as Map<String, dynamic>).toList();
return await getBuilders(Providers.freshHttpClient, loggingService, twoSecondLinearBackoff, bucket);
}

Future<String> _getSingleValue(String id) async {
Expand Down
15 changes: 12 additions & 3 deletions app_dart/lib/src/foundation/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,18 @@ Future<RepositorySlug> repoNameForBuilder(List<Map<String, dynamic>> builders, S
}

/// Gets supported luci builders based on [bucket] via GitHub http request.
Future<String> getBuilders(HttpClientProvider branchHttpClientProvider, Logging log,
Future<List<Map<String, dynamic>>> getBuilders(HttpClientProvider branchHttpClientProvider, Logging log,
GitHubBackoffCalculator gitHubBackoffCalculator, String bucket) async {
final String filename = bucket == 'try' ? 'luci_try_builders.json' : 'luci_prod_builders.json';
final String content = await remoteFileContent(branchHttpClientProvider, log, gitHubBackoffCalculator, filename);
return content ?? '{"builders":[]}';
String builderContent = await remoteFileContent(branchHttpClientProvider, log, gitHubBackoffCalculator, filename);
builderContent ??= '{"builders":[]}';
Map<String, dynamic> builderMap;
try {
builderMap = json.decode(builderContent) as Map<String, dynamic>;
} on FormatException catch (e) {
log.error('error: $e');
builderMap = <String, dynamic>{'builders': <dynamic>[]};
}
final List<dynamic> builderList = builderMap['builders'] as List<dynamic>;
return builderList.map((dynamic builder) => builder as Map<String, dynamic>).toList();
}
50 changes: 25 additions & 25 deletions app_dart/test/foundation/utils_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,17 @@ const String branchRegExp = '''
flutter-1.1-candidate.1
''';
const String luciBuilders = '''
builders: [
{
test1:value1,
test2:value2,
},{
test1:value3,
test2:value4,
test3:value5,
}
]
{
"builders":[
{
"name":"Cocoon",
"repo":"cocoon"
}, {
"name":"Cocoon2",
"repo":"cocoon"
}
]
}
''';

void main() {
Expand Down Expand Up @@ -116,30 +117,29 @@ void main() {
});
test('returns luci builders', () async {
lucBuilderHttpClient.request.response.body = luciBuilders;
final String builders =
final List<Map<String, dynamic>> builders =
await getBuilders(() => lucBuilderHttpClient, log, (int attempt) => Duration.zero, 'try');
expect(builders, '''
builders: [
{
test1:value1,
test2:value2,
},{
test1:value3,
test2:value4,
test3:value5,
}
]
''');
expect(builders.length, 2);
expect(builders[0]['name'], 'Cocoon');
expect(builders[0]['repo'], 'cocoon');
});

test('logs error and returns empty list when json file is invalid', () async {
lucBuilderHttpClient.request.response.body = '{"builders":[';
final List<Map<String, dynamic>> builders =
await getBuilders(() => lucBuilderHttpClient, log, (int attempt) => Duration.zero, 'try');
expect(log.records.where(hasLevel(LogLevel.ERROR)), isNotEmpty);
expect(builders.length, 0);
});

test('returns empty list when http request fails', () async {
int retry = 0;
lucBuilderHttpClient.onIssueRequest = (FakeHttpClientRequest request) => retry++;
lucBuilderHttpClient.request.response.statusCode = HttpStatus.serviceUnavailable;
lucBuilderHttpClient.request.response.body = luciBuilders;
final String builders =
final List<Map<String, dynamic>> builders =
await getBuilders(() => lucBuilderHttpClient, log, (int attempt) => Duration.zero, 'try');
expect(builders, '{"builders":[]}');
expect(builders.length, 0);
});
});

Expand Down
22 changes: 22 additions & 0 deletions dev/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
This directory contains resources that the Flutter team uses during
the development of cocoon.

## Luci builder file
`cocoon_try_builders.json` contains the supported luci try builders
for cocoon. It follows format:
```json
{
"builders":[
{
"name":"xxx",
"repo":"cocoon"
}
]
}
```
This file will be mainly used in [`flutter/cocoon`](https://github.com/flutter/cocoon)
to trigger LUCI presubmit tasks.

If any new changes, please validate json contents by running
`dart validat_json.dart cocoon_try_builders.json`.

8 changes: 8 additions & 0 deletions dev/cocoon_try_builders.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the test I was thinking something like a dart script that receives a the path of the json file as a flag and validates it has the correct content and the file is parseable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a separate dart file to validate the json contents: validate_json.dart, and included it in the README.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a separate dart file to validate the json contents: validate_json.dart, and included it in the README.

Great, maybe not in this PR but can we run the validation in presubmit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will try adding that in a separate PR.

"builders":[
{
"name":"Cocoon",
"repo":"cocoon"
}
]
}
38 changes: 38 additions & 0 deletions dev/validate_json.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2020 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:convert';
import 'dart:io' show File;

/// Validates if the input builders JSON file has valid contents.
///
/// Examples:
/// dart validate_json.dart /path/to/json/file
Future<bool> main(List<String> args) async {
final String jsonString = await File(args[0]).readAsString();
Map<String, dynamic> decodedJson;
bool decodedStatus = true;
try {
decodedJson = json.decode(jsonString) as Map<String, dynamic>;
final List<dynamic> builders = decodedJson['builders'] as List<dynamic>;
if (builders == null) {
print('Json format is violated: no "builders" exists. Please follow');
print('''
{
"builders":[
{
"name":"xxx",
"repo":"cocoon"
}
]
}''');
return decodedStatus = false;
}
} on FormatException catch (e) {
print('error: $e');
return decodedStatus = false;
}
print('Success.');
return decodedStatus;
}