diff --git a/app_dart/lib/src/service/config.dart b/app_dart/lib/src/service/config.dart index a338cdeaf..fd0f7c23d 100644 --- a/app_dart/lib/src/service/config.dart +++ b/app_dart/lib/src/service/config.dart @@ -299,8 +299,6 @@ class Config { 'flutter-dashboard@appspot.gserviceaccount.com', }; - int get maxTaskRetries => 2; - /// Max retries for Luci builder with infra failure. int get maxLuciTaskRetries => 2; diff --git a/app_dart/test/src/datastore/fake_config.dart b/app_dart/test/src/datastore/fake_config.dart index 712210a8a..aa9c12d66 100644 --- a/app_dart/test/src/datastore/fake_config.dart +++ b/app_dart/test/src/datastore/fake_config.dart @@ -136,9 +136,6 @@ class FakeConfig implements Config { @override Duration get githubRequestDelay => githubRequestDelayValue ?? Duration.zero; - @override - int get maxTaskRetries => maxTaskRetriesValue!; - /// Size of the shards to send to buildBucket when scheduling builds. @override int get schedulingShardSize => 5; diff --git a/dashboard/lib/model/commit_firestore.pb.dart b/dashboard/lib/model/commit_firestore.pb.dart new file mode 100644 index 000000000..3f233ee2c --- /dev/null +++ b/dashboard/lib/model/commit_firestore.pb.dart @@ -0,0 +1,192 @@ +// +// Generated code. Do not modify. +// source: lib/model/commit_firestore.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +import 'dart:core' as $core; + +import 'package:fixnum/fixnum.dart' as $fixnum; +import 'package:protobuf/protobuf.dart' as $pb; + +class CommitDocument extends $pb.GeneratedMessage { + factory CommitDocument({ + $core.String? documentName, + $fixnum.Int64? createTimestamp, + $core.String? sha, + $core.String? author, + $core.String? avatar, + $core.String? repositoryPath, + $core.String? branch, + $core.String? message, + }) { + final $result = create(); + if (documentName != null) { + $result.documentName = documentName; + } + if (createTimestamp != null) { + $result.createTimestamp = createTimestamp; + } + if (sha != null) { + $result.sha = sha; + } + if (author != null) { + $result.author = author; + } + if (avatar != null) { + $result.avatar = avatar; + } + if (repositoryPath != null) { + $result.repositoryPath = repositoryPath; + } + if (branch != null) { + $result.branch = branch; + } + if (message != null) { + $result.message = message; + } + return $result; + } + CommitDocument._() : super(); + factory CommitDocument.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + factory CommitDocument.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CommitDocument', + package: const $pb.PackageName(_omitMessageNames ? '' : 'dashboard'), createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'documentName', protoName: 'documentName') + ..aInt64(2, _omitFieldNames ? '' : 'createTimestamp', protoName: 'createTimestamp') + ..aOS(3, _omitFieldNames ? '' : 'sha') + ..aOS(4, _omitFieldNames ? '' : 'author') + ..aOS(5, _omitFieldNames ? '' : 'avatar') + ..aOS(6, _omitFieldNames ? '' : 'repositoryPath', protoName: 'repositoryPath') + ..aOS(7, _omitFieldNames ? '' : 'branch') + ..aOS(8, _omitFieldNames ? '' : 'message') + ..hasRequiredFields = false; + + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + CommitDocument clone() => CommitDocument()..mergeFromMessage(this); + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + CommitDocument copyWith(void Function(CommitDocument) updates) => + super.copyWith((message) => updates(message as CommitDocument)) as CommitDocument; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static CommitDocument create() => CommitDocument._(); + CommitDocument createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static CommitDocument getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static CommitDocument? _defaultInstance; + + /// Next ID: 9 + @$pb.TagNumber(1) + $core.String get documentName => $_getSZ(0); + @$pb.TagNumber(1) + set documentName($core.String v) { + $_setString(0, v); + } + + @$pb.TagNumber(1) + $core.bool hasDocumentName() => $_has(0); + @$pb.TagNumber(1) + void clearDocumentName() => clearField(1); + + @$pb.TagNumber(2) + $fixnum.Int64 get createTimestamp => $_getI64(1); + @$pb.TagNumber(2) + set createTimestamp($fixnum.Int64 v) { + $_setInt64(1, v); + } + + @$pb.TagNumber(2) + $core.bool hasCreateTimestamp() => $_has(1); + @$pb.TagNumber(2) + void clearCreateTimestamp() => clearField(2); + + @$pb.TagNumber(3) + $core.String get sha => $_getSZ(2); + @$pb.TagNumber(3) + set sha($core.String v) { + $_setString(2, v); + } + + @$pb.TagNumber(3) + $core.bool hasSha() => $_has(2); + @$pb.TagNumber(3) + void clearSha() => clearField(3); + + @$pb.TagNumber(4) + $core.String get author => $_getSZ(3); + @$pb.TagNumber(4) + set author($core.String v) { + $_setString(3, v); + } + + @$pb.TagNumber(4) + $core.bool hasAuthor() => $_has(3); + @$pb.TagNumber(4) + void clearAuthor() => clearField(4); + + @$pb.TagNumber(5) + $core.String get avatar => $_getSZ(4); + @$pb.TagNumber(5) + set avatar($core.String v) { + $_setString(4, v); + } + + @$pb.TagNumber(5) + $core.bool hasAvatar() => $_has(4); + @$pb.TagNumber(5) + void clearAvatar() => clearField(5); + + @$pb.TagNumber(6) + $core.String get repositoryPath => $_getSZ(5); + @$pb.TagNumber(6) + set repositoryPath($core.String v) { + $_setString(5, v); + } + + @$pb.TagNumber(6) + $core.bool hasRepositoryPath() => $_has(5); + @$pb.TagNumber(6) + void clearRepositoryPath() => clearField(6); + + @$pb.TagNumber(7) + $core.String get branch => $_getSZ(6); + @$pb.TagNumber(7) + set branch($core.String v) { + $_setString(6, v); + } + + @$pb.TagNumber(7) + $core.bool hasBranch() => $_has(6); + @$pb.TagNumber(7) + void clearBranch() => clearField(7); + + @$pb.TagNumber(8) + $core.String get message => $_getSZ(7); + @$pb.TagNumber(8) + set message($core.String v) { + $_setString(7, v); + } + + @$pb.TagNumber(8) + $core.bool hasMessage() => $_has(7); + @$pb.TagNumber(8) + void clearMessage() => clearField(8); +} + +const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); +const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/dashboard/lib/model/commit_firestore.pbenum.dart b/dashboard/lib/model/commit_firestore.pbenum.dart new file mode 100644 index 000000000..f00e762fb --- /dev/null +++ b/dashboard/lib/model/commit_firestore.pbenum.dart @@ -0,0 +1,10 @@ +// +// Generated code. Do not modify. +// source: lib/model/commit_firestore.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import diff --git a/dashboard/lib/model/commit_firestore.pbjson.dart b/dashboard/lib/model/commit_firestore.pbjson.dart new file mode 100644 index 000000000..2a918697b --- /dev/null +++ b/dashboard/lib/model/commit_firestore.pbjson.dart @@ -0,0 +1,37 @@ +// +// Generated code. Do not modify. +// source: lib/model/commit_firestore.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +import 'dart:convert' as $convert; +import 'dart:core' as $core; +import 'dart:typed_data' as $typed_data; + +@$core.Deprecated('Use commitDocumentDescriptor instead') +const CommitDocument$json = { + '1': 'CommitDocument', + '2': [ + {'1': 'documentName', '3': 1, '4': 1, '5': 9, '10': 'documentName'}, + {'1': 'createTimestamp', '3': 2, '4': 1, '5': 3, '10': 'createTimestamp'}, + {'1': 'sha', '3': 3, '4': 1, '5': 9, '10': 'sha'}, + {'1': 'author', '3': 4, '4': 1, '5': 9, '10': 'author'}, + {'1': 'avatar', '3': 5, '4': 1, '5': 9, '10': 'avatar'}, + {'1': 'repositoryPath', '3': 6, '4': 1, '5': 9, '10': 'repositoryPath'}, + {'1': 'branch', '3': 7, '4': 1, '5': 9, '10': 'branch'}, + {'1': 'message', '3': 8, '4': 1, '5': 9, '10': 'message'}, + ], +}; + +/// Descriptor for `CommitDocument`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List commitDocumentDescriptor = + $convert.base64Decode('Cg5Db21taXREb2N1bWVudBIiCgxkb2N1bWVudE5hbWUYASABKAlSDGRvY3VtZW50TmFtZRIoCg' + '9jcmVhdGVUaW1lc3RhbXAYAiABKANSD2NyZWF0ZVRpbWVzdGFtcBIQCgNzaGEYAyABKAlSA3No' + 'YRIWCgZhdXRob3IYBCABKAlSBmF1dGhvchIWCgZhdmF0YXIYBSABKAlSBmF2YXRhchImCg5yZX' + 'Bvc2l0b3J5UGF0aBgGIAEoCVIOcmVwb3NpdG9yeVBhdGgSFgoGYnJhbmNoGAcgASgJUgZicmFu' + 'Y2gSGAoHbWVzc2FnZRgIIAEoCVIHbWVzc2FnZQ=='); diff --git a/dashboard/lib/model/commit_firestore.pbserver.dart b/dashboard/lib/model/commit_firestore.pbserver.dart new file mode 100644 index 000000000..166b6d6fe --- /dev/null +++ b/dashboard/lib/model/commit_firestore.pbserver.dart @@ -0,0 +1,13 @@ +// +// Generated code. Do not modify. +// source: lib/model/commit_firestore.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names +// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +export 'commit_firestore.pb.dart'; diff --git a/dashboard/lib/model/commit_firestore.proto b/dashboard/lib/model/commit_firestore.proto new file mode 100644 index 000000000..616b954de --- /dev/null +++ b/dashboard/lib/model/commit_firestore.proto @@ -0,0 +1,19 @@ +// Copyright 2019 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. + +syntax = "proto2"; + +package dashboard; + +message CommitDocument { + // Next ID: 9 + optional string documentName = 1; + optional int64 createTimestamp = 2; + optional string sha = 3; + optional string author = 4; + optional string avatar = 5; + optional string repositoryPath = 6; + optional string branch = 7; + optional string message = 8; +} diff --git a/dashboard/lib/model/commit_tasks_status.pb.dart b/dashboard/lib/model/commit_tasks_status.pb.dart new file mode 100644 index 000000000..0ab3b3b8a --- /dev/null +++ b/dashboard/lib/model/commit_tasks_status.pb.dart @@ -0,0 +1,103 @@ +// +// Generated code. Do not modify. +// source: lib/model/commit_tasks_status.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +import 'commit_firestore.pb.dart' as $0; +import 'task_firestore.pb.dart' as $1; + +class CommitTasksStatus extends $pb.GeneratedMessage { + factory CommitTasksStatus({ + $0.CommitDocument? commit, + $core.Iterable<$1.TaskDocument>? tasks, + $core.String? branch, + }) { + final $result = create(); + if (commit != null) { + $result.commit = commit; + } + if (tasks != null) { + $result.tasks.addAll(tasks); + } + if (branch != null) { + $result.branch = branch; + } + return $result; + } + CommitTasksStatus._() : super(); + factory CommitTasksStatus.fromBuffer($core.List<$core.int> i, + [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + factory CommitTasksStatus.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CommitTasksStatus', + package: const $pb.PackageName(_omitMessageNames ? '' : 'dashboard'), createEmptyInstance: create) + ..aOM<$0.CommitDocument>(1, _omitFieldNames ? '' : 'commit', subBuilder: $0.CommitDocument.create) + ..pc<$1.TaskDocument>(2, _omitFieldNames ? '' : 'tasks', $pb.PbFieldType.PM, subBuilder: $1.TaskDocument.create) + ..aOS(3, _omitFieldNames ? '' : 'branch') + ..hasRequiredFields = false; + + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + CommitTasksStatus clone() => CommitTasksStatus()..mergeFromMessage(this); + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + CommitTasksStatus copyWith(void Function(CommitTasksStatus) updates) => + super.copyWith((message) => updates(message as CommitTasksStatus)) as CommitTasksStatus; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static CommitTasksStatus create() => CommitTasksStatus._(); + CommitTasksStatus createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static CommitTasksStatus getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static CommitTasksStatus? _defaultInstance; + + @$pb.TagNumber(1) + $0.CommitDocument get commit => $_getN(0); + @$pb.TagNumber(1) + set commit($0.CommitDocument v) { + setField(1, v); + } + + @$pb.TagNumber(1) + $core.bool hasCommit() => $_has(0); + @$pb.TagNumber(1) + void clearCommit() => clearField(1); + @$pb.TagNumber(1) + $0.CommitDocument ensureCommit() => $_ensure(0); + + @$pb.TagNumber(2) + $core.List<$1.TaskDocument> get tasks => $_getList(1); + + @$pb.TagNumber(3) + $core.String get branch => $_getSZ(2); + @$pb.TagNumber(3) + set branch($core.String v) { + $_setString(2, v); + } + + @$pb.TagNumber(3) + $core.bool hasBranch() => $_has(2); + @$pb.TagNumber(3) + void clearBranch() => clearField(3); +} + +const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); +const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/dashboard/lib/model/commit_tasks_status.pbenum.dart b/dashboard/lib/model/commit_tasks_status.pbenum.dart new file mode 100644 index 000000000..50a7599dc --- /dev/null +++ b/dashboard/lib/model/commit_tasks_status.pbenum.dart @@ -0,0 +1,10 @@ +// +// Generated code. Do not modify. +// source: lib/model/commit_tasks_status.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import diff --git a/dashboard/lib/model/commit_tasks_status.pbjson.dart b/dashboard/lib/model/commit_tasks_status.pbjson.dart new file mode 100644 index 000000000..17747852c --- /dev/null +++ b/dashboard/lib/model/commit_tasks_status.pbjson.dart @@ -0,0 +1,30 @@ +// +// Generated code. Do not modify. +// source: lib/model/commit_tasks_status.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +import 'dart:convert' as $convert; +import 'dart:core' as $core; +import 'dart:typed_data' as $typed_data; + +@$core.Deprecated('Use commitTasksStatusDescriptor instead') +const CommitTasksStatus$json = { + '1': 'CommitTasksStatus', + '2': [ + {'1': 'commit', '3': 1, '4': 1, '5': 11, '6': '.dashboard.CommitDocument', '10': 'commit'}, + {'1': 'tasks', '3': 2, '4': 3, '5': 11, '6': '.dashboard.TaskDocument', '10': 'tasks'}, + {'1': 'branch', '3': 3, '4': 1, '5': 9, '10': 'branch'}, + ], +}; + +/// Descriptor for `CommitTasksStatus`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List commitTasksStatusDescriptor = + $convert.base64Decode('ChFDb21taXRUYXNrc1N0YXR1cxIxCgZjb21taXQYASABKAsyGS5kYXNoYm9hcmQuQ29tbWl0RG' + '9jdW1lbnRSBmNvbW1pdBItCgV0YXNrcxgCIAMoCzIXLmRhc2hib2FyZC5UYXNrRG9jdW1lbnRS' + 'BXRhc2tzEhYKBmJyYW5jaBgDIAEoCVIGYnJhbmNo'); diff --git a/dashboard/lib/model/commit_tasks_status.pbserver.dart b/dashboard/lib/model/commit_tasks_status.pbserver.dart new file mode 100644 index 000000000..3f880ccca --- /dev/null +++ b/dashboard/lib/model/commit_tasks_status.pbserver.dart @@ -0,0 +1,13 @@ +// +// Generated code. Do not modify. +// source: lib/model/commit_tasks_status.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names +// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +export 'commit_tasks_status.pb.dart'; diff --git a/dashboard/lib/model/commit_tasks_status.proto b/dashboard/lib/model/commit_tasks_status.proto new file mode 100644 index 000000000..44fa34a83 --- /dev/null +++ b/dashboard/lib/model/commit_tasks_status.proto @@ -0,0 +1,16 @@ +// Copyright 2019 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. + +syntax = "proto2"; + +package dashboard; + +import "lib/model/commit_firestore.proto"; +import "lib/model/task_firestore.proto"; + +message CommitTasksStatus { + optional CommitDocument commit = 1; + repeated TaskDocument tasks = 2; + optional string branch = 3; +} diff --git a/dashboard/lib/model/task_firestore.pb.dart b/dashboard/lib/model/task_firestore.pb.dart new file mode 100644 index 000000000..3e7f95757 --- /dev/null +++ b/dashboard/lib/model/task_firestore.pb.dart @@ -0,0 +1,226 @@ +// +// Generated code. Do not modify. +// source: lib/model/task_firestore.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +import 'dart:core' as $core; + +import 'package:fixnum/fixnum.dart' as $fixnum; +import 'package:protobuf/protobuf.dart' as $pb; + +class TaskDocument extends $pb.GeneratedMessage { + factory TaskDocument({ + $core.String? documentName, + $fixnum.Int64? createTimestamp, + $fixnum.Int64? startTimestamp, + $fixnum.Int64? endTimestamp, + $core.String? taskName, + $core.int? attempts, + $core.bool? bringup, + $core.bool? testFlaky, + $core.int? buildNumber, + $core.String? status, + }) { + final $result = create(); + if (documentName != null) { + $result.documentName = documentName; + } + if (createTimestamp != null) { + $result.createTimestamp = createTimestamp; + } + if (startTimestamp != null) { + $result.startTimestamp = startTimestamp; + } + if (endTimestamp != null) { + $result.endTimestamp = endTimestamp; + } + if (taskName != null) { + $result.taskName = taskName; + } + if (attempts != null) { + $result.attempts = attempts; + } + if (bringup != null) { + $result.bringup = bringup; + } + if (testFlaky != null) { + $result.testFlaky = testFlaky; + } + if (buildNumber != null) { + $result.buildNumber = buildNumber; + } + if (status != null) { + $result.status = status; + } + return $result; + } + TaskDocument._() : super(); + factory TaskDocument.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + factory TaskDocument.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'TaskDocument', + package: const $pb.PackageName(_omitMessageNames ? '' : 'dashboard'), createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'documentName') + ..aInt64(2, _omitFieldNames ? '' : 'createTimestamp') + ..aInt64(3, _omitFieldNames ? '' : 'startTimestamp') + ..aInt64(4, _omitFieldNames ? '' : 'endTimestamp') + ..aOS(5, _omitFieldNames ? '' : 'taskName') + ..a<$core.int>(6, _omitFieldNames ? '' : 'attempts', $pb.PbFieldType.O3) + ..aOB(7, _omitFieldNames ? '' : 'bringup') + ..aOB(8, _omitFieldNames ? '' : 'testFlaky') + ..a<$core.int>(9, _omitFieldNames ? '' : 'buildNumber', $pb.PbFieldType.O3) + ..aOS(10, _omitFieldNames ? '' : 'status') + ..hasRequiredFields = false; + + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + TaskDocument clone() => TaskDocument()..mergeFromMessage(this); + @$core.Deprecated('Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + TaskDocument copyWith(void Function(TaskDocument) updates) => + super.copyWith((message) => updates(message as TaskDocument)) as TaskDocument; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static TaskDocument create() => TaskDocument._(); + TaskDocument createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static TaskDocument getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static TaskDocument? _defaultInstance; + + /// Next ID: 11 + @$pb.TagNumber(1) + $core.String get documentName => $_getSZ(0); + @$pb.TagNumber(1) + set documentName($core.String v) { + $_setString(0, v); + } + + @$pb.TagNumber(1) + $core.bool hasDocumentName() => $_has(0); + @$pb.TagNumber(1) + void clearDocumentName() => clearField(1); + + @$pb.TagNumber(2) + $fixnum.Int64 get createTimestamp => $_getI64(1); + @$pb.TagNumber(2) + set createTimestamp($fixnum.Int64 v) { + $_setInt64(1, v); + } + + @$pb.TagNumber(2) + $core.bool hasCreateTimestamp() => $_has(1); + @$pb.TagNumber(2) + void clearCreateTimestamp() => clearField(2); + + @$pb.TagNumber(3) + $fixnum.Int64 get startTimestamp => $_getI64(2); + @$pb.TagNumber(3) + set startTimestamp($fixnum.Int64 v) { + $_setInt64(2, v); + } + + @$pb.TagNumber(3) + $core.bool hasStartTimestamp() => $_has(2); + @$pb.TagNumber(3) + void clearStartTimestamp() => clearField(3); + + @$pb.TagNumber(4) + $fixnum.Int64 get endTimestamp => $_getI64(3); + @$pb.TagNumber(4) + set endTimestamp($fixnum.Int64 v) { + $_setInt64(3, v); + } + + @$pb.TagNumber(4) + $core.bool hasEndTimestamp() => $_has(3); + @$pb.TagNumber(4) + void clearEndTimestamp() => clearField(4); + + @$pb.TagNumber(5) + $core.String get taskName => $_getSZ(4); + @$pb.TagNumber(5) + set taskName($core.String v) { + $_setString(4, v); + } + + @$pb.TagNumber(5) + $core.bool hasTaskName() => $_has(4); + @$pb.TagNumber(5) + void clearTaskName() => clearField(5); + + @$pb.TagNumber(6) + $core.int get attempts => $_getIZ(5); + @$pb.TagNumber(6) + set attempts($core.int v) { + $_setSignedInt32(5, v); + } + + @$pb.TagNumber(6) + $core.bool hasAttempts() => $_has(5); + @$pb.TagNumber(6) + void clearAttempts() => clearField(6); + + @$pb.TagNumber(7) + $core.bool get bringup => $_getBF(6); + @$pb.TagNumber(7) + set bringup($core.bool v) { + $_setBool(6, v); + } + + @$pb.TagNumber(7) + $core.bool hasBringup() => $_has(6); + @$pb.TagNumber(7) + void clearBringup() => clearField(7); + + @$pb.TagNumber(8) + $core.bool get testFlaky => $_getBF(7); + @$pb.TagNumber(8) + set testFlaky($core.bool v) { + $_setBool(7, v); + } + + @$pb.TagNumber(8) + $core.bool hasTestFlaky() => $_has(7); + @$pb.TagNumber(8) + void clearTestFlaky() => clearField(8); + + @$pb.TagNumber(9) + $core.int get buildNumber => $_getIZ(8); + @$pb.TagNumber(9) + set buildNumber($core.int v) { + $_setSignedInt32(8, v); + } + + @$pb.TagNumber(9) + $core.bool hasBuildNumber() => $_has(8); + @$pb.TagNumber(9) + void clearBuildNumber() => clearField(9); + + @$pb.TagNumber(10) + $core.String get status => $_getSZ(9); + @$pb.TagNumber(10) + set status($core.String v) { + $_setString(9, v); + } + + @$pb.TagNumber(10) + $core.bool hasStatus() => $_has(9); + @$pb.TagNumber(10) + void clearStatus() => clearField(10); +} + +const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); +const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/dashboard/lib/model/task_firestore.pbenum.dart b/dashboard/lib/model/task_firestore.pbenum.dart new file mode 100644 index 000000000..6427d4947 --- /dev/null +++ b/dashboard/lib/model/task_firestore.pbenum.dart @@ -0,0 +1,10 @@ +// +// Generated code. Do not modify. +// source: lib/model/task_firestore.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import diff --git a/dashboard/lib/model/task_firestore.pbjson.dart b/dashboard/lib/model/task_firestore.pbjson.dart new file mode 100644 index 000000000..53f312dc3 --- /dev/null +++ b/dashboard/lib/model/task_firestore.pbjson.dart @@ -0,0 +1,41 @@ +// +// Generated code. Do not modify. +// source: lib/model/task_firestore.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +import 'dart:convert' as $convert; +import 'dart:core' as $core; +import 'dart:typed_data' as $typed_data; + +@$core.Deprecated('Use taskDocumentDescriptor instead') +const TaskDocument$json = { + '1': 'TaskDocument', + '2': [ + {'1': 'document_name', '3': 1, '4': 1, '5': 9, '10': 'documentName'}, + {'1': 'create_timestamp', '3': 2, '4': 1, '5': 3, '10': 'createTimestamp'}, + {'1': 'start_timestamp', '3': 3, '4': 1, '5': 3, '10': 'startTimestamp'}, + {'1': 'end_timestamp', '3': 4, '4': 1, '5': 3, '10': 'endTimestamp'}, + {'1': 'task_name', '3': 5, '4': 1, '5': 9, '10': 'taskName'}, + {'1': 'attempts', '3': 6, '4': 1, '5': 5, '10': 'attempts'}, + {'1': 'bringup', '3': 7, '4': 1, '5': 8, '10': 'bringup'}, + {'1': 'test_flaky', '3': 8, '4': 1, '5': 8, '10': 'testFlaky'}, + {'1': 'build_number', '3': 9, '4': 1, '5': 5, '10': 'buildNumber'}, + {'1': 'status', '3': 10, '4': 1, '5': 9, '10': 'status'}, + ], +}; + +/// Descriptor for `TaskDocument`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List taskDocumentDescriptor = + $convert.base64Decode('CgxUYXNrRG9jdW1lbnQSIwoNZG9jdW1lbnRfbmFtZRgBIAEoCVIMZG9jdW1lbnROYW1lEikKEG' + 'NyZWF0ZV90aW1lc3RhbXAYAiABKANSD2NyZWF0ZVRpbWVzdGFtcBInCg9zdGFydF90aW1lc3Rh' + 'bXAYAyABKANSDnN0YXJ0VGltZXN0YW1wEiMKDWVuZF90aW1lc3RhbXAYBCABKANSDGVuZFRpbW' + 'VzdGFtcBIbCgl0YXNrX25hbWUYBSABKAlSCHRhc2tOYW1lEhoKCGF0dGVtcHRzGAYgASgFUghh' + 'dHRlbXB0cxIYCgdicmluZ3VwGAcgASgIUgdicmluZ3VwEh0KCnRlc3RfZmxha3kYCCABKAhSCX' + 'Rlc3RGbGFreRIhCgxidWlsZF9udW1iZXIYCSABKAVSC2J1aWxkTnVtYmVyEhYKBnN0YXR1cxgK' + 'IAEoCVIGc3RhdHVz'); diff --git a/dashboard/lib/model/task_firestore.pbserver.dart b/dashboard/lib/model/task_firestore.pbserver.dart new file mode 100644 index 000000000..628cf044a --- /dev/null +++ b/dashboard/lib/model/task_firestore.pbserver.dart @@ -0,0 +1,13 @@ +// +// Generated code. Do not modify. +// source: lib/model/task_firestore.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names +// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +export 'task_firestore.pb.dart'; diff --git a/dashboard/lib/model/task_firestore.proto b/dashboard/lib/model/task_firestore.proto new file mode 100644 index 000000000..66d806a0c --- /dev/null +++ b/dashboard/lib/model/task_firestore.proto @@ -0,0 +1,21 @@ +// Copyright 2019 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. + +syntax = "proto2"; + +package dashboard; + +message TaskDocument { + // Next ID: 11 + optional string document_name = 1; + optional int64 create_timestamp = 2; + optional int64 start_timestamp = 3; + optional int64 end_timestamp = 4; + optional string task_name = 5; + optional int32 attempts = 6; + optional bool bringup = 7; + optional bool test_flaky = 8; + optional int32 build_number = 9; + optional string status = 10; +} diff --git a/dashboard/lib/service/appengine_cocoon.dart b/dashboard/lib/service/appengine_cocoon.dart index 5c2dd51b5..2119846df 100644 --- a/dashboard/lib/service/appengine_cocoon.dart +++ b/dashboard/lib/service/appengine_cocoon.dart @@ -12,10 +12,13 @@ import 'package:http/http.dart' as http; import '../logic/qualified_task.dart'; import '../model/build_status_response.pb.dart'; +import '../model/commit_firestore.pb.dart'; import '../model/commit.pb.dart'; import '../model/commit_status.pb.dart'; +import '../model/commit_tasks_status.pb.dart'; import '../model/key.pb.dart'; import '../model/task.pb.dart'; +import '../model/task_firestore.pb.dart'; import 'cocoon.dart'; /// CocoonService for interacting with flutter/flutter production build data. @@ -35,6 +38,27 @@ class AppEngineCocoonService implements CocoonService { /// This is the base for all API requests to cocoon static const String _baseApiUrl = 'flutter-dashboard.appspot.com'; + /// Json keys from response data. + static const String kCommitAvatar = 'Avatar'; + static const String kCommitAuthor = 'Author'; + static const String kCommitBranch = 'Branch'; + static const String kCommitCreateTimestamp = 'CreateTimestamp'; + static const String kCommitDocumentName = 'DocumentName'; + static const String kCommitMessage = 'Message'; + static const String kCommitRepositoryPath = 'RepositoryPath'; + static const String kCommitSha = 'Sha'; + + static const String kTaskAttempts = 'Attempts'; + static const String kTaskBringup = 'Bringup'; + static const String kTaskBuildNumber = 'BuildNumber'; + static const String kTaskCreateTimestamp = 'CreateTimestamp'; + static const String kTaskDocumentName = 'DocumentName'; + static const String kTaskEndTimestamp = 'EndTimestamp'; + static const String kTaskStartTimestamp = 'StartTimestamp'; + static const String kTaskStatus = 'Status'; + static const String kTaskTaskNmae = 'TaskName'; + static const String kTaskTestFlaky = 'TestFlaky'; + final http.Client _client; @override @@ -67,6 +91,38 @@ class AppEngineCocoonService implements CocoonService { } } + @override + Future>> fetchCommitStatusesFirestore({ + CommitStatus? lastCommitStatus, + String? branch, + required String repo, + }) async { + final Map queryParameters = { + if (lastCommitStatus != null) 'lastCommitKey': lastCommitStatus.commit.key.child.name, + 'branch': branch ?? _defaultBranch, + 'repo': repo, + }; + final Uri getStatusUrl = apiEndpoint('/api/public/get-status-firestore', queryParameters: queryParameters); + + /// This endpoint returns JSON [List] + final http.Response response = await _client.get(getStatusUrl); + + if (response.statusCode != HttpStatus.ok) { + return CocoonResponse>.error( + '/api/public/get-status-firestore returned ${response.statusCode}', + ); + } + + try { + final Map jsonResponse = jsonDecode(response.body); + return CocoonResponse>.data( + _commitStatusesFromJsonFirestore(jsonResponse['Statuses']), + ); + } catch (error) { + return CocoonResponse>.error(error.toString()); + } + } + @override Future>> fetchRepos() async { final Uri getReposUrl = apiEndpoint('/api/public/repos'); @@ -207,7 +263,6 @@ class AppEngineCocoonService implements CocoonService { List _commitStatusesFromJson(List? jsonCommitStatuses) { assert(jsonCommitStatuses != null); - // TODO(chillers): Remove adapter code to just use proto fromJson method. https://github.com/flutter/cocoon/issues/441 final List statuses = []; @@ -224,11 +279,34 @@ class AppEngineCocoonService implements CocoonService { return statuses; } + List _commitStatusesFromJsonFirestore(List? jsonCommitStatuses) { + assert(jsonCommitStatuses != null); + // TODO(chillers): Remove adapter code to just use proto fromJson method. https://github.com/flutter/cocoon/issues/441 + + final List statuses = []; + for (final Map jsonCommitStatus in jsonCommitStatuses!) { + final Map jsonCommit = jsonCommitStatus['Commit']; + + statuses.add( + CommitTasksStatus() + ..commit = _commitFromJsonFirestore(jsonCommit) + ..branch = _branchFromJsonFirestore(jsonCommit)! + ..tasks.addAll(_tasksFromJsonFirestore(jsonCommitStatus['Tasks'])), + ); + } + + return statuses; + } + String? _branchFromJson(Map jsonChecklist) { final Map checklist = jsonChecklist['Checklist']; return checklist['Branch'] as String?; } + String? _branchFromJsonFirestore(Map jsonCommit) { + return jsonCommit['Branch'] as String?; + } + Commit _commitFromJson(Map jsonChecklist) { final Map checklist = jsonChecklist['Checklist']; @@ -249,6 +327,21 @@ class AppEngineCocoonService implements CocoonService { return result; } + CommitDocument _commitFromJsonFirestore(Map jsonCommit) { + final CommitDocument result = CommitDocument() + ..documentName = jsonCommit[kCommitDocumentName] + ..createTimestamp = Int64(jsonCommit[kCommitCreateTimestamp] as int) + ..sha = jsonCommit[kCommitSha] as String + ..author = jsonCommit[kCommitAuthor] as String + ..avatar = jsonCommit[kCommitAvatar] as String + ..repositoryPath = jsonCommit[kCommitRepositoryPath] as String + ..branch = jsonCommit[kCommitBranch] as String; + if (jsonCommit[kCommitMessage] != null) { + result.message = jsonCommit[kCommitMessage] as String; + } + return result; + } + List _tasksFromStagesJson(List json) { final List tasks = []; @@ -270,6 +363,17 @@ class AppEngineCocoonService implements CocoonService { return tasks; } + List _tasksFromJsonFirestore(List json) { + final List tasks = []; + + for (final Map jsonTask in json) { + //as Iterable> + tasks.add(_taskFromJsonFirestore(jsonTask)); + } + + return tasks; + } + Task _taskFromJson(Map json) { final Map taskData = json['Task']; final List? objectRequiredCapabilities = taskData['RequiredCapabilities'] as List?; @@ -296,4 +400,21 @@ class AppEngineCocoonService implements CocoonService { ..luciBucket = taskData['LuciBucket'] as String? ?? ''; return task; } + + TaskDocument _taskFromJsonFirestore(Map taskData) { + final TaskDocument task = TaskDocument() + ..createTimestamp = Int64(taskData[kTaskCreateTimestamp] as int) + ..startTimestamp = Int64(taskData[kTaskStartTimestamp] as int) + ..endTimestamp = Int64(taskData[kTaskEndTimestamp] as int) + ..documentName = taskData[kTaskDocumentName] as String + ..taskName = taskData[kTaskTaskNmae] as String + ..attempts = taskData[kTaskAttempts] as int + ..bringup = taskData[kTaskBringup] as bool + ..status = taskData[kTaskStatus] as String + ..testFlaky = taskData[kTaskTestFlaky] as bool? ?? false; + if (taskData[kTaskBuildNumber] != null) { + task.buildNumber = taskData[kTaskBuildNumber] as int; + } + return task; + } } diff --git a/dashboard/lib/service/cocoon.dart b/dashboard/lib/service/cocoon.dart index 0a40b7db6..e415e21fa 100644 --- a/dashboard/lib/service/cocoon.dart +++ b/dashboard/lib/service/cocoon.dart @@ -7,6 +7,7 @@ import 'package:flutter_dashboard/model/branch.pb.dart'; import '../model/build_status_response.pb.dart'; import '../model/commit_status.pb.dart'; +import '../model/commit_tasks_status.pb.dart'; import '../model/task.pb.dart'; import 'appengine_cocoon.dart'; import 'dev_cocoon.dart'; @@ -38,6 +39,16 @@ abstract class CocoonService { required String repo, }); + /// Gets build information on the most recent commits. + /// + /// If [lastCommitStatus] is given, it will return the next page of + /// [List] after [lastCommitStatus], not including it. + Future>> fetchCommitStatusesFirestore({ + CommitStatus? lastCommitStatus, + String? branch, + required String repo, + }); + /// Gets the current build status of flutter/flutter. Future> fetchTreeBuildStatus({ String? branch, diff --git a/dashboard/lib/service/dev_cocoon.dart b/dashboard/lib/service/dev_cocoon.dart index 3a9ad5a46..aa6fde098 100644 --- a/dashboard/lib/service/dev_cocoon.dart +++ b/dashboard/lib/service/dev_cocoon.dart @@ -12,6 +12,7 @@ import '../logic/qualified_task.dart'; import '../model/build_status_response.pb.dart'; import '../model/commit.pb.dart'; import '../model/commit_status.pb.dart'; +import '../model/commit_tasks_status.pb.dart'; import '../model/key.pb.dart'; import '../model/task.pb.dart'; import 'cocoon.dart'; @@ -68,6 +69,16 @@ class DevelopmentCocoonService implements CocoonService { _paused = pause; } + @override + Future>> fetchCommitStatusesFirestore({ + CommitStatus? lastCommitStatus, + String? branch, + required String repo, + }) async { + // TODO(keyonghan): to be impelemented when logics are switched to Firestore. + return const CocoonResponse>.error(''); + } + @override Future>> fetchCommitStatuses({ CommitStatus? lastCommitStatus, diff --git a/dashboard/test/service/appengine_cocoon_test.dart b/dashboard/test/service/appengine_cocoon_test.dart index e7a6ca745..39f547de6 100644 --- a/dashboard/test/service/appengine_cocoon_test.dart +++ b/dashboard/test/service/appengine_cocoon_test.dart @@ -8,9 +8,12 @@ import 'package:flutter_dashboard/logic/qualified_task.dart'; import 'package:flutter_dashboard/model/branch.pb.dart'; import 'package:flutter_dashboard/model/build_status_response.pb.dart'; import 'package:flutter_dashboard/model/commit.pb.dart'; +import 'package:flutter_dashboard/model/commit_firestore.pb.dart'; import 'package:flutter_dashboard/model/commit_status.pb.dart'; +import 'package:flutter_dashboard/model/commit_tasks_status.pb.dart'; import 'package:flutter_dashboard/model/key.pb.dart'; import 'package:flutter_dashboard/model/task.pb.dart'; +import 'package:flutter_dashboard/model/task_firestore.pb.dart'; import 'package:flutter_dashboard/service/appengine_cocoon.dart'; import 'package:flutter_dashboard/service/cocoon.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -92,6 +95,74 @@ void main() { }); }); + group('AppEngine CocoonService fetchCommitStatusFirestore', () { + late AppEngineCocoonService service; + + setUp(() async { + service = AppEngineCocoonService( + client: MockClient((Request request) async { + return Response(luciJsonGetStatsResponseFirestore, 200); + }), + ); + }); + + test('should return CocoonResponse>', () { + expect( + service.fetchCommitStatusesFirestore(repo: 'engine'), + const TypeMatcher>>>(), + ); + }); + + test('should return expected List', () async { + final CocoonResponse> statuses = + await service.fetchCommitStatusesFirestore(repo: 'engine'); + + final CommitTasksStatus expectedStatus = CommitTasksStatus() + ..branch = 'master' + ..commit = (CommitDocument() + ..documentName = 'commit/document/name' + ..createTimestamp = Int64(123456789) + ..sha = 'ShaShankHash' + ..author = 'ShaSha' + ..avatar = 'https://flutter.dev' + ..repositoryPath = 'flutter/cocoon' + ..branch = 'master' + ..message = 'message') + ..tasks.add( + TaskDocument() + ..documentName = 'task/document/name' + ..createTimestamp = Int64(1569353940885) + ..startTimestamp = Int64(1569354594672) + ..endTimestamp = Int64(1569354700642) + ..taskName = 'linux' + ..attempts = 1 + ..bringup = false + ..status = 'Succeeded' + ..testFlaky = false + ..buildNumber = 123, + ); + + expect(statuses.data!.length, 1); + expect(statuses.data!.first, expectedStatus); + }); + + test('should have error if given non-200 response', () async { + service = AppEngineCocoonService(client: MockClient((Request request) async => Response('', 404))); + + final CocoonResponse> response = + await service.fetchCommitStatusesFirestore(repo: 'engine'); + expect(response.error, isNotNull); + }); + + test('should have error if given bad response', () async { + service = AppEngineCocoonService(client: MockClient((Request request) async => Response('bad', 200))); + + final CocoonResponse> response = + await service.fetchCommitStatusesFirestore(repo: 'engine'); + expect(response.error, isNotNull); + }); + }); + group('AppEngine CocoonService fetchTreeBuildStatus', () { late AppEngineCocoonService service; diff --git a/dashboard/test/utils/appengine_cocoon_test_data.dart b/dashboard/test/utils/appengine_cocoon_test_data.dart index 22cd8adf9..663e79152 100644 --- a/dashboard/test/utils/appengine_cocoon_test_data.dart +++ b/dashboard/test/utils/appengine_cocoon_test_data.dart @@ -57,6 +57,39 @@ const String luciJsonGetStatsResponse = ''' } '''; +const String luciJsonGetStatsResponseFirestore = ''' + { + "Statuses": [ + { + "Commit": { + "DocumentName": "commit/document/name", + "Branch": "master", + "RepositoryPath": "flutter/cocoon", + "CreateTimestamp": 123456789, + "Sha": "ShaShankHash", + "Author": "ShaSha", + "Avatar": "https://flutter.dev", + "Message": "message" + }, + "Tasks": [ + { + "DocumentName": "task/document/name", + "Status": "Succeeded", + "Attempts": 1, + "CreateTimestamp": 1569353940885, + "EndTimestamp": 1569354700642, + "Bringup": false, + "TaskName": "linux", + "StartTimestamp": 1569354594672, + "BuildNumber": 123, + "TestFlaky": false + } + ] + } + ] + } +'''; + const String jsonGetBranchesResponse = '''[ { "branch":"flutter-3.13-candidate.0",