Skip to content

Commit

Permalink
Merge branch 'flutter:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
ricardoamador authored Mar 5, 2024
2 parents f45df08 + fb9d34c commit f4710dd
Show file tree
Hide file tree
Showing 20 changed files with 712 additions and 35 deletions.
10 changes: 10 additions & 0 deletions .ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,16 @@ targets:
- cipd_packages/ruby/**
- .ci.yaml

- name: Linux ktlint
recipe: cocoon/cipd
timeout: 60
properties:
script: cipd_packages/ktlint/tools/build.sh
cipd_name: flutter/ktlint/linux-amd64
runIf:
- cipd_packages/ktlint/**
- .ci.yaml

- name: Linux ci_yaml roller
recipe: infra/ci_yaml
properties:
Expand Down
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ triage_bot @Hix
cipd_packages/codesign/** @XilaiZhang
cipd_packages/device_doctor/** @yusuf-goog
cipd_packages/doxygen/** @gspencergoog
cipd_packages/ktlint/** @gmackall
cipd_packages/ruby/** @godofredoc

## gh_actions
Expand Down
2 changes: 1 addition & 1 deletion app_dart/integration_test/data/cocoon_config.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"targets":[{"name":"Linux Cocoon","properties":{"add_recipes_cq":"true"},"runIf":[".ci.yaml","analyze/**","app_dart/**","auto_submit/**","cipd_packages/**","cloud_build/**","dashboard/**","dev/**","licenses/**","packages/**","test_utilities/**","tooling/**","CI_YAML.md"],"recipe":"cocoon/cocoon"},{"name":"Linux device_doctor","properties":{"script":"cipd_packages/device_doctor/tool/build.sh","cipd_name":"flutter/device_doctor/linux-amd64"},"runIf":["cipd_packages/device_doctor/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Mac device_doctor","properties":{"script":"cipd_packages/device_doctor/tool/build.sh","cipd_name":"flutter/device_doctor/mac-amd64","device_type":"none"},"runIf":["cipd_packages/device_doctor/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Mac_arm64 device_doctor","properties":{"script":"cipd_packages/device_doctor/tool/build.sh","cipd_name":"flutter/device_doctor/mac-arm64","device_type":"none"},"runIf":["cipd_packages/device_doctor/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Windows device_doctor","properties":{"script":"cipd_packages\\device_doctor\\tool\\build.bat","cipd_name":"flutter/device_doctor/windows-amd64"},"runIf":["cipd_packages/device_doctor/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Linux doxygen","properties":{"script":"cipd_packages/doxygen/tool/build.sh","cipd_name":"flutter/doxygen/linux-amd64","dependencies":"[\n {\"dependency\": \"cmake\", \"version\": \"build_id:8787856497187628321\"}\n]"},"runIf":["cipd_packages/doxygen/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Mac codesign","properties":{"script":"cipd_packages/codesign/tool/build.sh","cipd_name":"flutter/codesign/mac-amd64","device_type":"none"},"runIf":["cipd_packages/codesign/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Mac_arm64 codesign","properties":{"script":"cipd_packages/codesign/tool/build.sh","cipd_name":"flutter/codesign/mac-arm64","device_type":"none"},"runIf":["cipd_packages/codesign/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Mac ruby","timeout":60,"properties":{"script":"cipd_packages/ruby/tools/build.sh","cipd_name":"flutter/ruby/mac-amd64","device_os":"iOS","contexts":"[\n \"osx_sdk_devicelab\"\n]","$flutter/osx_sdk":"{\n \"sdk_version\": \"14e300c\"\n}"},"runIf":["cipd_packages/ruby/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Mac_arm64 ruby","timeout":60,"properties":{"script":"cipd_packages/ruby/tools/build.sh","cipd_name":"flutter/ruby/mac-arm64","device_os":"iOS","contexts":"[\n \"osx_sdk_devicelab\"\n]","$flutter/osx_sdk":"{\n \"sdk_version\": \"14e300c\"\n}"},"runIf":["cipd_packages/ruby/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Linux ci_yaml roller","properties":{"backfill":"false"},"runIf":[".ci.yaml"],"recipe":"infra/ci_yaml"}],"enabledBranches":["main"],"platformProperties":{"linux":{"properties":{"os":"Linux","device_type":"none"}},"mac":{"properties":{"os":"Mac-12|Mac-13","cpu":"x86"}},"mac_arm64":{"properties":{"os":"Mac-12|Mac-13","cpu":"arm64"}},"windows":{"properties":{"os":"Windows","device_type":"none"}}}}
{"targets":[{"name":"Linux Cocoon","properties":{"add_recipes_cq":"true"},"runIf":[".ci.yaml","analyze/**","app_dart/**","auto_submit/**","cipd_packages/**","cloud_build/**","dashboard/**","dev/**","licenses/**","packages/**","test_utilities/**","tooling/**","CI_YAML.md"],"recipe":"cocoon/cocoon"},{"name":"Linux device_doctor","properties":{"script":"cipd_packages/device_doctor/tool/build.sh","cipd_name":"flutter/device_doctor/linux-amd64"},"runIf":["cipd_packages/device_doctor/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Mac device_doctor","properties":{"script":"cipd_packages/device_doctor/tool/build.sh","cipd_name":"flutter/device_doctor/mac-amd64","device_type":"none"},"runIf":["cipd_packages/device_doctor/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Mac_arm64 device_doctor","properties":{"script":"cipd_packages/device_doctor/tool/build.sh","cipd_name":"flutter/device_doctor/mac-arm64","device_type":"none"},"runIf":["cipd_packages/device_doctor/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Windows device_doctor","properties":{"script":"cipd_packages\\device_doctor\\tool\\build.bat","cipd_name":"flutter/device_doctor/windows-amd64"},"runIf":["cipd_packages/device_doctor/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Linux doxygen","properties":{"script":"cipd_packages/doxygen/tool/build.sh","cipd_name":"flutter/doxygen/linux-amd64","dependencies":"[\n {\"dependency\": \"cmake\", \"version\": \"build_id:8787856497187628321\"}\n]"},"runIf":["cipd_packages/doxygen/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Mac codesign","properties":{"script":"cipd_packages/codesign/tool/build.sh","cipd_name":"flutter/codesign/mac-amd64","device_type":"none"},"runIf":["cipd_packages/codesign/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Mac_arm64 codesign","properties":{"script":"cipd_packages/codesign/tool/build.sh","cipd_name":"flutter/codesign/mac-arm64","device_type":"none"},"runIf":["cipd_packages/codesign/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Mac ruby","timeout":60,"properties":{"script":"cipd_packages/ruby/tools/build.sh","cipd_name":"flutter/ruby/mac-amd64","device_os":"iOS","contexts":"[\n \"osx_sdk_devicelab\"\n]","$flutter/osx_sdk":"{\n \"sdk_version\": \"14e300c\"\n}"},"runIf":["cipd_packages/ruby/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Mac_arm64 ruby","timeout":60,"properties":{"script":"cipd_packages/ruby/tools/build.sh","cipd_name":"flutter/ruby/mac-arm64","device_os":"iOS","contexts":"[\n \"osx_sdk_devicelab\"\n]","$flutter/osx_sdk":"{\n \"sdk_version\": \"14e300c\"\n}"},"runIf":["cipd_packages/ruby/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Linux ktlint","timeout":60,"properties":{"script":"cipd_packages/ktlint/tools/build.sh","cipd_name":"flutter/ktlint/linux-amd64"},"runIf":["cipd_packages/ktlint/**",".ci.yaml"],"recipe":"cocoon/cipd"},{"name":"Linux ci_yaml roller","properties":{"backfill":"false"},"runIf":[".ci.yaml"],"recipe":"infra/ci_yaml"}],"enabledBranches":["main"],"platformProperties":{"linux":{"properties":{"os":"Linux","device_type":"none"}},"mac":{"properties":{"os":"Mac-12|Mac-13","cpu":"x86"}},"mac_arm64":{"properties":{"os":"Mac-12|Mac-13","cpu":"arm64"}},"windows":{"properties":{"os":"Windows","device_type":"none"}}}}
96 changes: 96 additions & 0 deletions app_dart/lib/src/model/firestore/github_build_status.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// 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.

import 'package:cocoon_service/cocoon_service.dart';
import 'package:github/github.dart';
import 'package:googleapis/firestore/v1.dart' hide Status;

import '../../service/firestore.dart';
import '../appengine/github_build_status_update.dart';

const String kGithubBuildStatusCollectionId = 'githubBuildStatuses';
const String kGithubBuildStatusPrNumberField = 'prNumber';
const String kGithubBuildStatusRepositoryField = 'repository';
const String kGithubBuildStatusHeadField = 'head';
const String kGithubBuildStatusStatusField = 'status';
const String kGithubBuildStatusUpdateTimeMillisField = 'updateTimeMillis';
const String kGithubBuildStatusUpdatesField = 'updates';

/// Class that represents an update having been posted to a GitHub PR on the
/// status of the Flutter build.
class GithubBuildStatus extends Document {
/// Lookup [GithubBuildStatus] from Firestore.
///
/// `documentName` follows `/projects/{project}/databases/{database}/documents/{document_path}`
static Future<GithubBuildStatus> fromFirestore({
required FirestoreService firestoreService,
required String documentName,
}) async {
final Document document = await firestoreService.getDocument(documentName);
return GithubBuildStatus.fromDocument(githubBuildStatus: document);
}

/// Create [GithubBuildStatus] from a GithubBuildStatus Document.
static GithubBuildStatus fromDocument({
required Document githubBuildStatus,
}) {
return GithubBuildStatus()
..fields = githubBuildStatus.fields!
..name = githubBuildStatus.name!;
}

static const String statusSuccess = 'success';

static const String statusFailure = 'failure';

int? get prNumber => int.parse(fields![kGithubBuildStatusPrNumberField]!.integerValue!);

/// A serializable form of [slug].
///
/// This will be of the form `<org>/<repo>`. e.g. `flutter/flutter`.
String? get repository => fields![kGithubBuildStatusRepositoryField]!.stringValue!;

/// [RepositorySlug] of where this commit exists.
RepositorySlug get slug => RepositorySlug.full(repository!);

String? get head => fields![kGithubBuildStatusHeadField]!.stringValue!;

String? get status => fields![kGithubBuildStatusStatusField]!.stringValue!;

/// The last time when the status is updated for the PR.
int? get updateTimeMillis => int.parse(fields![kGithubBuildStatusUpdateTimeMillisField]!.integerValue!);

int? get updates => int.parse(fields![kGithubBuildStatusUpdatesField]!.integerValue!);

@override
String toString() {
final StringBuffer buf = StringBuffer()
..write('$runtimeType(')
..write(', $kGithubBuildStatusRepositoryField: $repository')
..write(', $kGithubBuildStatusPrNumberField: $prNumber')
..write(', $kGithubBuildStatusHeadField: $head')
..write(', $kGithubBuildStatusStatusField: $status')
..write(', $kGithubBuildStatusUpdatesField: $updates')
..write(', $kGithubBuildStatusUpdateTimeMillisField: $updateTimeMillis')
..write(')');
return buf.toString();
}
}

/// Generates GithubGoldStatus document based on datastore GithubGoldStatusUpdate data model.
GithubBuildStatus githubBuildStatusToDocument(GithubBuildStatusUpdate githubBuildStatus) {
return GithubBuildStatus.fromDocument(
githubBuildStatus: Document(
name: '$kDatabase/documents/$kGithubBuildStatusCollectionId/${githubBuildStatus.head}_${githubBuildStatus.pr}',
fields: <String, Value>{
kGithubBuildStatusUpdateTimeMillisField: Value(stringValue: githubBuildStatus.updateTimeMillis.toString()),
kGithubBuildStatusHeadField: Value(stringValue: githubBuildStatus.head),
kGithubBuildStatusPrNumberField: Value(integerValue: githubBuildStatus.pr.toString()),
kGithubBuildStatusRepositoryField: Value(stringValue: githubBuildStatus.repository),
kGithubBuildStatusStatusField: Value(stringValue: githubBuildStatus.status),
kGithubBuildStatusUpdatesField: Value(integerValue: githubBuildStatus.updates.toString()),
},
),
);
}
2 changes: 1 addition & 1 deletion app_dart/lib/src/model/firestore/github_gold_status.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class GithubGoldStatus extends Document {
return GithubGoldStatus.fromDocument(githubGoldStatus: document);
}

/// Create [Commit] from a Commit Document.
/// Create [GithubGoldStatus] from a GithubGoldStatus Document.
static GithubGoldStatus fromDocument({
required Document githubGoldStatus,
}) {
Expand Down
20 changes: 20 additions & 0 deletions app_dart/lib/src/request_handlers/push_build_status_to_github.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
import 'dart:async';

import 'package:github/github.dart';
import 'package:googleapis/firestore/v1.dart';
import 'package:meta/meta.dart';

import '../../cocoon_service.dart';
import '../model/appengine/github_build_status_update.dart';
import '../model/firestore/github_build_status.dart';
import '../request_handling/api_request_handler.dart';
import '../service/build_status_provider.dart';
import '../service/datastore.dart';
Expand Down Expand Up @@ -79,6 +81,24 @@ class PushBuildStatusToGithub extends ApiRequestHandler<Body> {
}
}
await datastore.insert(updates);
// TODO(keyonghan): remove try block after fully migrated to firestore
// https://github.com/flutter/flutter/issues/142951
try {
await updateGithubBuildStatusDocuments(updates);
} catch (error) {
log.warning('Failed to update github build status in Firestore: $error');
}
}

Future<void> updateGithubBuildStatusDocuments(List<GithubBuildStatusUpdate> updates) async {
if (updates.isEmpty) {
return;
}
final List<GithubBuildStatus> githubBuildStatusDocuments =
updates.map((e) => githubBuildStatusToDocument(e)).toList();
final List<Write> writes = documentsToWrites(githubBuildStatusDocuments);
final FirestoreService firestoreService = await config.createFirestoreService();
await firestoreService.batchWriteDocuments(BatchWriteRequest(writes: writes), kDatabase);
}

Future<void> _insertBigquery(RepositorySlug slug, String status, String branch, Config config) async {
Expand Down
2 changes: 1 addition & 1 deletion app_dart/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ dependencies:
gcloud: 0.8.12
github: 9.23.0
googleapis: 12.0.0
googleapis_auth: 1.4.2
googleapis_auth: 1.5.0
gql: 1.0.1-alpha+1696717343881
graphql: 5.2.0-beta.7
grpc: 3.2.4
Expand Down
72 changes: 72 additions & 0 deletions app_dart/test/model/firestore/github_build_status_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// 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.

import 'package:cocoon_service/src/model/appengine/github_build_status_update.dart';
import 'package:cocoon_service/src/model/firestore/github_build_status.dart';
import 'package:cocoon_service/src/service/firestore.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';

import '../../src/utilities/entity_generators.dart';
import '../../src/utilities/mocks.dart';

void main() {
group('GithubBuildStatus.fromFirestore', () {
late MockFirestoreService mockFirestoreService;

setUp(() {
mockFirestoreService = MockFirestoreService();
});

test('generates githubBuildStatus correctly', () async {
final GithubBuildStatus githubBuildStatus = generateFirestoreGithubBuildStatus(1);
when(
mockFirestoreService.getDocument(
captureAny,
),
).thenAnswer((Invocation invocation) {
return Future<GithubBuildStatus>.value(
githubBuildStatus,
);
});
final GithubBuildStatus resultedGithubBuildStatus = await GithubBuildStatus.fromFirestore(
firestoreService: mockFirestoreService,
documentName: 'test',
);
expect(resultedGithubBuildStatus.name, githubBuildStatus.name);
expect(resultedGithubBuildStatus.fields, githubBuildStatus.fields);
});
});

group('Creates github gold status document', () {
test('from data model', () async {
final GithubBuildStatusUpdate githubBuildStatusUpdate = GithubBuildStatusUpdate(
head: 'sha',
pr: 1,
status: GithubBuildStatusUpdate.statusSuccess,
updates: 2,
repository: '',
);
final GithubBuildStatus githubBuildStatusDocument = githubBuildStatusToDocument(githubBuildStatusUpdate);
expect(
githubBuildStatusDocument.name,
'$kDatabase/documents/$kGithubBuildStatusCollectionId/${githubBuildStatusUpdate.head}_${githubBuildStatusUpdate.pr}',
);
expect(githubBuildStatusDocument.fields![kGithubBuildStatusHeadField]!.stringValue, githubBuildStatusUpdate.head);
expect(
githubBuildStatusDocument.fields![kGithubBuildStatusPrNumberField]!.integerValue,
githubBuildStatusUpdate.pr.toString(),
);
expect(
githubBuildStatusDocument.fields![kGithubBuildStatusStatusField]!.stringValue,
githubBuildStatusUpdate.status,
);
expect(
githubBuildStatusDocument.fields![kGithubBuildStatusUpdatesField]!.integerValue,
githubBuildStatusUpdate.updates.toString(),
);
expect(githubBuildStatusDocument.fields![kGithubBuildStatusRepositoryField]!.stringValue, '');
});
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

import 'package:cocoon_service/src/model/appengine/github_build_status_update.dart';
import 'package:cocoon_service/src/model/firestore/github_build_status.dart';
import 'package:cocoon_service/src/request_handlers/push_build_status_to_github.dart';
import 'package:cocoon_service/src/request_handling/body.dart';
import 'package:cocoon_service/src/service/build_status_provider.dart';
Expand All @@ -11,6 +12,7 @@ import 'package:cocoon_service/src/service/datastore.dart';
import 'package:gcloud/db.dart';
import 'package:github/github.dart';
import 'package:googleapis/bigquery/v2.dart' hide Model;
import 'package:googleapis/firestore/v1.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';

Expand All @@ -27,6 +29,7 @@ import '../src/utilities/mocks.dart';
void main() {
group('PushStatusToGithub', () {
late FakeBuildStatusService buildStatusService;
late MockFirestoreService mockFirestoreService;
late FakeClientContext clientContext;
late FakeConfig config;
late FakeDatastoreDB db;
Expand All @@ -52,6 +55,7 @@ void main() {
}

setUp(() async {
mockFirestoreService = MockFirestoreService();
clientContext = FakeClientContext();
authContext = FakeAuthenticatedContext(clientContext: clientContext);
clientContext.isDevelopmentEnvironment = false;
Expand All @@ -67,6 +71,7 @@ void main() {
tabledataResource: tabledataResourceApi,
githubService: githubService,
dbValue: db,
firestoreService: mockFirestoreService,
githubClient: github,
);
tester = ApiRequestHandlerTester(context: authContext);
Expand Down Expand Up @@ -154,6 +159,14 @@ void main() {
});

test('updates github and datastore if status has changed since last update', () async {
when(
mockFirestoreService.batchWriteDocuments(
captureAny,
captureAny,
),
).thenAnswer((Invocation invocation) {
return Future<BatchWriteResponse>.value(BatchWriteResponse());
});
final PullRequest pr = generatePullRequest(id: 1, sha: '1');
when(pullRequestsService.list(any, base: anyNamed('base'))).thenAnswer((_) => Stream<PullRequest>.value(pr));
buildStatusService.cumulativeStatus = BuildStatus.success();
Expand All @@ -164,6 +177,14 @@ void main() {
expect(status.updates, 1);
expect(status.updateTimeMillis, isNotNull);
expect(status.status, BuildStatus.success().githubStatus);

final List<dynamic> captured = verify(mockFirestoreService.batchWriteDocuments(captureAny, captureAny)).captured;
expect(captured.length, 2);
final BatchWriteRequest batchWriteRequest = captured[0] as BatchWriteRequest;
expect(batchWriteRequest.writes!.length, 1);
final GithubBuildStatus updatedDocument =
GithubBuildStatus.fromDocument(githubBuildStatus: batchWriteRequest.writes![0].update!);
expect(updatedDocument.updates, status.updates);
});
});
}
Loading

0 comments on commit f4710dd

Please sign in to comment.