Skip to content

Commit

Permalink
Pass through specific github label to presumit builds
Browse files Browse the repository at this point in the history
  • Loading branch information
yusuf-goog committed Aug 29, 2023
1 parent 6eacd06 commit b255d51
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 0 deletions.
15 changes: 15 additions & 0 deletions app_dart/lib/src/service/luci_build_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ class LuciBuildService {
static const int kDefaultPriority = 30;
static const int kRerunPriority = 29;

/// Github labels have a max length of 100, so conserve chars here.
/// This is currently used by packages repo only.
/// See: https://github.com/flutter/flutter/issues/130076
static const String githubBuildLabelPrefix = 'gh_override:';
static const String propertiesGithubBuildLabelName = 'gh_overrides';

/// Name of the subcache to store luci build related values in redis.
static const String subCacheName = 'luci';

Expand Down Expand Up @@ -197,6 +203,15 @@ class LuciBuildService {
final Map<String, Object> properties = target.getProperties();
properties.putIfAbsent('git_branch', () => pullRequest.base!.ref!.replaceAll('refs/heads/', ''));

final List<String>? labels = pullRequest.labels
?.where((label) => label.name.startsWith(githubBuildLabelPrefix))
.map((obj) => obj.name)
.toList();

if (labels != null && labels.isNotEmpty) {
properties[propertiesGithubBuildLabelName] = labels;
}

requests.add(
Request(
scheduleBuild: _createPresubmitScheduleBuild(
Expand Down
62 changes: 62 additions & 0 deletions app_dart/test/service/luci_build_service_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,68 @@ void main() {
expect(dimensions[0].value, 'abc');
});

test('schedule try builds with github build labels successfully', () async {
final issueLabels = [
IssueLabel(name: '${LuciBuildService.githubBuildLabelPrefix}hello'),
IssueLabel(name: '${LuciBuildService.githubBuildLabelPrefix}world'),
];
final PullRequest pullRequest = generatePullRequest(labels: issueLabels);
when(mockBuildBucketClient.batch(any)).thenAnswer((_) async {
return BatchResponse(
responses: <Response>[
Response(
scheduleBuild: generateBuild(1),
),
],
);
});
when(mockGithubChecksUtil.createCheckRun(any, any, any, any))
.thenAnswer((_) async => generateCheckRun(1, name: 'Linux 1'));
final List<Target> scheduledTargets = await service.scheduleTryBuilds(
pullRequest: pullRequest,
targets: targets,
);
final Iterable<String> scheduledTargetNames = scheduledTargets.map((Target target) => target.value.name);
expect(scheduledTargetNames, <String>['Linux 1']);
final BatchRequest batchRequest = pubsub.messages.single as BatchRequest;
expect(batchRequest.requests!.single.scheduleBuild, isNotNull);

final ScheduleBuildRequest scheduleBuild = batchRequest.requests!.single.scheduleBuild!;
expect(scheduleBuild.builderId.bucket, 'try');
expect(scheduleBuild.builderId.builder, 'Linux 1');
expect(scheduleBuild.notify?.pubsubTopic, 'projects/flutter-dashboard/topics/luci-builds');
final Map<String, dynamic> userData =
jsonDecode(String.fromCharCodes(base64Decode(scheduleBuild.notify!.userData!))) as Map<String, dynamic>;
expect(userData, <String, dynamic>{
'repo_owner': 'flutter',
'repo_name': 'flutter',
'user_agent': 'flutter-cocoon',
'check_run_id': 1,
'commit_sha': 'abc',
'commit_branch': 'master',
'builder_name': 'Linux 1',
});

final Map<String, dynamic> properties = scheduleBuild.properties!;
final List<RequestedDimension> dimensions = scheduleBuild.dimensions!;
expect(properties, <String, dynamic>{
'os': 'abc',
'dependencies': <dynamic>[],
'bringup': false,
'git_branch': 'master',
'git_url': 'https://github.com/flutter/flutter',
'git_ref': 'refs/pull/123/head',
'exe_cipd_version': 'refs/heads/main',
LuciBuildService.propertiesGithubBuildLabelName: [
'${LuciBuildService.githubBuildLabelPrefix}hello',
'${LuciBuildService.githubBuildLabelPrefix}world',
],
});
expect(dimensions.length, 1);
expect(dimensions[0].key, 'os');
expect(dimensions[0].value, 'abc');
});

test('Schedule builds no-ops when targets list is empty', () async {
await service.scheduleTryBuilds(
pullRequest: pullRequest,
Expand Down
69 changes: 69 additions & 0 deletions app_dart/test/service/scheduler_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,75 @@ targets:
expect(scheduleBuildRequest.properties!['custom'], 'abc');
});

test('pass github_build_label to properties', () async {
final MockBuildBucketClient mockBuildbucket = MockBuildBucketClient();
buildStatusService =
FakeBuildStatusService(commitStatuses: <CommitStatus>[CommitStatus(generateCommit(1), const <Stage>[])]);
final FakePubSub pubsub = FakePubSub();
scheduler = Scheduler(
cache: cache,
config: config,
datastoreProvider: (DatastoreDB db) => DatastoreService(db, 2),
githubChecksService: GithubChecksService(config, githubChecksUtil: mockGithubChecksUtil),
buildStatusProvider: (_) => buildStatusService,
httpClientProvider: () => httpClient,
luciBuildService: FakeLuciBuildService(
config: config,
githubChecksUtil: mockGithubChecksUtil,
buildbucket: mockBuildbucket,
gerritService: FakeGerritService(branchesValue: <String>['master']),
pubsub: pubsub,
),
);
when(mockBuildbucket.batch(any)).thenAnswer(
(_) async => BatchResponse(
responses: <Response>[
Response(
searchBuilds: SearchBuildsResponse(
builds: <Build>[
generateBuild(1000, name: 'Linux', bucket: 'try'),
generateBuild(2000, name: 'Linux Coverage', bucket: 'try'),
generateBuild(3000, name: 'Mac', bucket: 'try', status: Status.scheduled),
generateBuild(4000, name: 'Windows', bucket: 'try', status: Status.started),
generateBuild(5000, name: 'Linux A', bucket: 'try', status: Status.failure),
],
),
),
],
),
);
when(mockBuildbucket.scheduleBuild(any))
.thenAnswer((_) async => generateBuild(5001, name: 'Linux A', bucket: 'try', status: Status.scheduled));
// Only Linux A should be retried
final Map<String, CheckRun> checkRuns = <String, CheckRun>{
'Linux': createCheckRun(name: 'Linux', id: 100),
'Linux Coverage': createCheckRun(name: 'Linux Coverage', id: 200),
'Mac': createCheckRun(name: 'Mac', id: 300, status: CheckRunStatus.queued),
'Windows': createCheckRun(name: 'Windows', id: 400, status: CheckRunStatus.inProgress),
'Linux A': createCheckRun(name: 'Linux A', id: 500),
};
when(mockGithubChecksUtil.allCheckRuns(any, any)).thenAnswer((_) async {
return checkRuns;
});

final CheckSuiteEvent checkSuiteEvent =
CheckSuiteEvent.fromJson(jsonDecode(checkSuiteTemplate('rerequested')) as Map<String, dynamic>);
await scheduler.retryPresubmitTargets(
pullRequest: pullRequest,
checkSuiteEvent: checkSuiteEvent,
);

expect(pubsub.messages.length, 1);
final BatchRequest batchRequest = pubsub.messages.single as BatchRequest;
expect(batchRequest.requests!.length, 1);
// Schedule build should have been sent
expect(batchRequest.requests!.single.scheduleBuild, isNotNull);
final ScheduleBuildRequest scheduleBuildRequest = batchRequest.requests!.single.scheduleBuild!;
// Verify expected parameters to schedule build
expect(scheduleBuildRequest.builderId.builder, 'Linux A');
expect(scheduleBuildRequest.properties!['custom'], 'abc');
});

test('triggers only specificed targets', () async {
final List<Target> presubmitTargets = <Target>[generateTarget(1), generateTarget(2)];
final List<Target> presubmitTriggerTargets = scheduler.getTriggerList(presubmitTargets, <String>['Linux 1']);
Expand Down
2 changes: 2 additions & 0 deletions app_dart/test/src/utilities/entity_generators.dart
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ github.PullRequest generatePullRequest({
DateTime? mergedAt,
String sha = 'abc',
bool merged = true,
List<github.IssueLabel> labels = const [],
}) {
mergedAt ??= DateTime.fromMillisecondsSinceEpoch(1);
return github.PullRequest(
Expand All @@ -249,6 +250,7 @@ github.PullRequest generatePullRequest({
),
mergeCommitSha: sha,
merged: merged,
labels: labels,
);
}

Expand Down

0 comments on commit b255d51

Please sign in to comment.