Skip to content
Open
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
70 changes: 51 additions & 19 deletions app_dart/lib/src/service/luci_build_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -445,25 +445,57 @@ class LuciBuildService {
);
}

// Only set the dashboard check status to `CheckRunStatus.inProgress` for
// the initial run. For Re-run Failed Checks, we need to call GitHub's
// "rerequest check run" API, once it is supported by the `github` package.
final isInitialRun = targets.values.first == 1;
if (isUnifiedCheckRunFlow && dashboardChecks != null && isInitialRun) {
try {
await _githubChecksUtil.updateCheckRun(
_config,
slug,
dashboardChecks,
status: CheckRunStatus.inProgress,
);
} catch (e, s) {
// We are not going to block on this error.
log.warn(
'Failed to update dashboard checks for PR# ${pullRequest.number} to in progress',
e,
s,
);
// Set the dashboard check status to `CheckRunStatus.inProgress` for the
// initial run. For Re-run Failed Checks, if all failed jobs were reset, we
// need to re-request the check run before updating it to in progress.
final isRerun = targets.values.first > 1;
if (isUnifiedCheckRunFlow && dashboardChecks != null) {
var shouldUpdateCheckRun = !isRerun;
if (isRerun && stage != null) {
try {
final presubmitGuardDoc = await _firestore.getDocument(
PresubmitGuard.documentNameFor(
slug: slug,
prNum: pullRequest.number!,
checkRunId: dashboardChecks.id!,
stage: stage,
),
);
final guard = PresubmitGuard.fromDocument(presubmitGuardDoc);
if (guard.failedJobs == 0) {
final githubClient = await _config.createGitHubClient(slug: slug);
await githubClient.checks.checkRuns.reRequestCheckRun(
slug,
checkRunId: dashboardChecks.id!,
);
shouldUpdateCheckRun = true;
}
} catch (e, s) {
// We are not going to block on this error.
log.warn(
Comment thread
ievdokdm marked this conversation as resolved.
'Failed to re-request dashboard checks for PR# ${pullRequest.number}',
e,
s,
);
}
}

if (shouldUpdateCheckRun) {
try {
await _githubChecksUtil.updateCheckRun(
_config,
slug,
dashboardChecks,
status: CheckRunStatus.inProgress,
);
} catch (e, s) {
// We are not going to block on this error.
log.warn(
'Failed to update dashboard checks for PR# ${pullRequest.number} to in progress',
e,
s,
);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion app_dart/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ dependencies:
gcloud: 0.8.19
genkit: ^0.13.0
genkit_google_genai: ^0.2.5
github: 9.25.0
github: 9.26.0
googleapis: 14.0.0
googleapis_auth: 2.0.0
gql: ^1.0.1-alpha+1730759315362
Expand Down
235 changes: 163 additions & 72 deletions app_dart/test/service/luci_build_service/schedule_try_builds_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import 'package:buildbucket/buildbucket_pb.dart' as bbv2;
import 'package:cocoon_common_test/cocoon_common_test.dart';
import 'package:cocoon_integration_test/testing.dart';
import 'package:cocoon_server/logging.dart';
import 'package:cocoon_server_test/mocks.dart';
import 'package:cocoon_server_test/test_logging.dart';
import 'package:cocoon_service/src/model/commit_ref.dart';
import 'package:cocoon_service/src/model/firestore/base.dart';
import 'package:cocoon_service/src/model/firestore/pr_check_runs.dart';
import 'package:cocoon_service/src/model/firestore/presubmit_guard.dart';
import 'package:cocoon_service/src/service/cache_service.dart';
import 'package:cocoon_service/src/service/firestore.dart';
import 'package:cocoon_service/src/service/flags/dynamic_config.dart';
import 'package:cocoon_service/src/service/flags/ordered_presubmit_flags.dart';
import 'package:cocoon_service/src/service/flags/unified_check_run_flow_flags.dart';
Expand Down Expand Up @@ -631,89 +634,177 @@ void main() {
},
);

test('does not update dashboard checks for re-run failed checks', () async {
final pullRequest = generatePullRequest(
id: 1,
repo: 'flutter',
headSha: 'headsha123',
);
test(
'reRequests check run and updates dashboard checks for re-run failed checks when failedJobs is 0',
() async {
final pullRequest = generatePullRequest(
id: 1,
repo: 'flutter',
headSha: 'headsha123',
);

final buildTarget = generateTarget(
1,
properties: {'os': 'abc'},
slug: RepositorySlug.full('flutter/flutter'),
name: 'Linux foo',
);
final buildTarget = generateTarget(
1,
properties: {'os': 'abc'},
slug: RepositorySlug.full('flutter/flutter'),
name: 'Linux foo',
);

// Enable Unified Check Run Flow
luci = LuciBuildService(
config: FakeConfig(
dynamicConfig: DynamicConfig(
unifiedCheckRunFlow: UnifiedCheckRunFlow(useForAll: true),
),
),
cache: CacheService.inMemory(),
buildBucketClient: mockBuildBucketClient,
githubChecksUtil: mockGithubChecksUtil,
pubsub: pubSub,
gerritService: gerritService,
firestore: firestore,
);
final mockGithubClient = MockGitHub();
final mockChecksService = MockChecksService();
final mockCheckRunsService = MockCheckRunsService();

final checkRunGuard = generateCheckRun(1234, name: 'Guard');
when(mockGithubClient.checks).thenReturn(mockChecksService);
when(mockChecksService.checkRuns).thenReturn(mockCheckRunsService);

await expectLater(
luci.reScheduleTryBuilds(
pullRequest: pullRequest,
targets: {buildTarget: 2}, // Re-run failed (attempt 2)
engineArtifacts: EngineArtifacts.builtFromSource(
commitSha: pullRequest.head!.sha!,
luci = LuciBuildService(
config: FakeConfig(
githubClient: mockGithubClient,
dynamicConfig: DynamicConfig(
unifiedCheckRunFlow: UnifiedCheckRunFlow(useForAll: true),
),
),
dashboardChecks: checkRunGuard,
cache: CacheService.inMemory(),
buildBucketClient: mockBuildBucketClient,
githubChecksUtil: mockGithubChecksUtil,
pubsub: pubSub,
gerritService: gerritService,
firestore: firestore,
);

final checkRunGuard = generateCheckRun(1234, name: 'Guard');

final guard = PresubmitGuard(
checkRun: checkRunGuard,
headSha: 'headsha123',
slug: RepositorySlug.full('flutter/flutter'),
prNum: pullRequest.number!,
stage: CiStage.fusionTests,
),
completion([isTarget.hasName('Linux foo')]),
);
creationTime: 123456789,
author: 'dash',
remainingJobs: 1,
failedJobs: 0,
);
await firestore.writeViaTransaction(
documentsToWrites([guard], exists: false),
);

// Should NOT create individual check runs
verifyNever(mockGithubChecksUtil.createCheckRun(any, any, any, any));
await expectLater(
luci.reScheduleTryBuilds(
pullRequest: pullRequest,
targets: {buildTarget: 2},
engineArtifacts: EngineArtifacts.builtFromSource(
commitSha: pullRequest.head!.sha!,
),
dashboardChecks: checkRunGuard,
stage: CiStage.fusionTests,
),
completion([isTarget.hasName('Linux foo')]),
);

// Should NOT update dashboard checks status
verifyNever(
mockGithubChecksUtil.updateCheckRun(
any,
any,
any,
status: anyNamed('status'),
),
);
verify(
mockCheckRunsService.reRequestCheckRun(
RepositorySlug.full('flutter/flutter'),
checkRunId: 1234,
),
).called(1);

final bbv2.ScheduleBuildRequest scheduleBuild;
{
final batchRequest = bbv2.BatchRequest().createEmptyInstance();
batchRequest.mergeFromProto3Json(pubSub.messages.single);
scheduleBuild = batchRequest.requests.single.scheduleBuild;
}
verify(
mockGithubChecksUtil.updateCheckRun(
any,
any,
checkRunGuard,
status: CheckRunStatus.inProgress,
),
).called(1);
},
);

final userData = PresubmitUserData.fromBytes(
scheduleBuild.notify.userData,
);
expect(userData.guardCheckRunId, 1234);
expect(userData.stage, CiStage.fusionTests);
expect(userData.checkRunId, isNull);
test(
'does not reRequest or update dashboard checks for re-run failed checks when failedJobs > 0',
() async {
final pullRequest = generatePullRequest(
id: 1,
repo: 'flutter',
headSha: 'headsha123',
);

final tags = BuildTags.fromStringPairs(scheduleBuild.tags);
expect(
tags.buildTags.contains(GuardCheckRunIdBuildTag(guardCheckRunId: 1234)),
isTrue,
reason: 'Should have GuardCheckRunIdBuildTag',
);
expect(
tags.buildTags.contains(CurrentAttemptBuildTag(attemptNumber: 2)),
isTrue,
reason: 'Should have CurrentAttemptBuildTag',
);
});
final buildTarget = generateTarget(
1,
properties: {'os': 'abc'},
slug: RepositorySlug.full('flutter/flutter'),
name: 'Linux foo',
);

final mockGithubClient = MockGitHub();
final mockChecksService = MockChecksService();
final mockCheckRunsService = MockCheckRunsService();

when(mockGithubClient.checks).thenReturn(mockChecksService);
when(mockChecksService.checkRuns).thenReturn(mockCheckRunsService);

luci = LuciBuildService(
config: FakeConfig(
githubClient: mockGithubClient,
dynamicConfig: DynamicConfig(
unifiedCheckRunFlow: UnifiedCheckRunFlow(useForAll: true),
),
),
cache: CacheService.inMemory(),
buildBucketClient: mockBuildBucketClient,
githubChecksUtil: mockGithubChecksUtil,
pubsub: pubSub,
gerritService: gerritService,
firestore: firestore,
);

final checkRunGuard = generateCheckRun(1234, name: 'Guard');

final guard = PresubmitGuard(
checkRun: checkRunGuard,
headSha: 'headsha123',
slug: RepositorySlug.full('flutter/flutter'),
prNum: pullRequest.number!,
stage: CiStage.fusionTests,
creationTime: 123456789,
author: 'dash',
remainingJobs: 1,
failedJobs: 1,
);
await firestore.writeViaTransaction(
documentsToWrites([guard], exists: false),
);

await expectLater(
luci.reScheduleTryBuilds(
pullRequest: pullRequest,
targets: {buildTarget: 2},
engineArtifacts: EngineArtifacts.builtFromSource(
commitSha: pullRequest.head!.sha!,
),
dashboardChecks: checkRunGuard,
stage: CiStage.fusionTests,
),
completion([isTarget.hasName('Linux foo')]),
);

verifyNever(
mockCheckRunsService.reRequestCheckRun(
any,
checkRunId: anyNamed('checkRunId'),
),
);

verifyNever(
mockGithubChecksUtil.updateCheckRun(
any,
any,
any,
status: anyNamed('status'),
),
);
},
);
});

group('Ordered Presubmit', () {
Expand Down
2 changes: 1 addition & 1 deletion auto_submit/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ dependencies:
path: ../packages/cocoon_server
corsac_jwt: 2.0.2
crypto: 3.0.7
github: 9.25.0
github: 9.26.0
googleapis: 14.0.0
googleapis_auth: 2.0.0
gql: 1.0.1
Expand Down
2 changes: 1 addition & 1 deletion packages/cocoon_integration_test/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ dependencies:
path: ../../app_dart
collection: ^1.19.1
fixnum: 1.1.1
github: 9.25.0
github: 9.26.0
googleapis: 14.0.0
googleapis_auth: ^2.0.0
gql: ^1.0.1
Expand Down
2 changes: 2 additions & 0 deletions packages/cocoon_server_test/lib/mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
MockSpec<GitHubComparison>(),
MockSpec<PullRequestsService>(),
MockSpec<RepositoriesService>(),
MockSpec<ChecksService>(),
MockSpec<CheckRunsService>(),
])
import 'package:github/github.dart';

Expand Down
Loading
Loading