Skip to content

Commit 45be26a

Browse files
Unlock Flutter Presubmits and Merge Queue Guard when emergency label is added. (#5033)
This addresses flutter/flutter#185628
1 parent e642968 commit 45be26a

2 files changed

Lines changed: 160 additions & 71 deletions

File tree

app_dart/lib/src/request_handlers/github/webhook_subscription.dart

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,50 +1105,21 @@ The "Merge" button is also unlocked. To bypass presubmits as well as the tree st
11051105
) ??
11061106
false;
11071107
if (hasEmergencyLabel) {
1108-
// The merge guard can be unlocked without approval checks because:
1108+
// The merge guard and Flutter Presubmits check can be unlocked without approval checks because:
11091109
//
11101110
// * For manual merges the GitHub repo settings already require minimum
11111111
// approvals before the PR can be submitted.
11121112
// * For `autosubmit` label Cocoon has the [Approval] validation that
1113-
// checks approvasl before attempting to merge the PR.
1114-
await _unlockMergeQueueGuardForEmergency();
1113+
// checks approvals before attempting to merge the PR.
1114+
await _unlockCheckrunsForEmergency();
11151115
} else {
11161116
logInfo('no emergency label; moving on.');
11171117
}
11181118
}
11191119

1120-
Future<void> _unlockMergeQueueGuardForEmergency() async {
1121-
logInfo(
1122-
'attempting to unlock the ${Config.kMergeQueueLockName} for emergency',
1123-
);
1124-
1125-
final guard = (await githubService.getCheckRunsFiltered(
1126-
slug: slug,
1127-
ref: pullRequest.head!.sha!,
1128-
checkName: Config.kMergeQueueLockName,
1129-
)).singleOrNull;
1130-
1131-
if (guard == null) {
1132-
logSevere(
1133-
'failed to process the emergency label. "${Config.kMergeQueueLockName}" check run is missing.',
1134-
);
1135-
return;
1136-
}
1137-
1138-
await githubService.updateCheckRun(
1139-
slug: slug,
1140-
checkRun: guard,
1141-
status: CheckRunStatus.completed,
1142-
conclusion: CheckRunConclusion.success,
1143-
output: const CheckRunOutput(
1144-
title: Config.kMergeQueueLockName,
1145-
summary: 'Emergency label applied.',
1146-
),
1147-
);
1148-
1149-
logInfo(
1150-
'unlocked "${Config.kMergeQueueLockName}", allowing it to land as an emergency.',
1151-
);
1120+
Future<void> _unlockCheckrunsForEmergency() async {
1121+
await _unlockCheckrun(Config.kMergeQueueLockName);
1122+
await _unlockCheckrun(Config.kFlutterPresubmitsName);
11521123

11531124
// Let the developer know what is happening with the MQ when this label is found the first time.
11541125
try {
@@ -1171,4 +1142,34 @@ The "Merge" button is also unlocked. To bypass presubmits as well as the tree st
11711142
);
11721143
}
11731144
}
1145+
1146+
Future<void> _unlockCheckrun(String checkName) async {
1147+
logInfo('attempting to unlock the $checkName for emergency');
1148+
1149+
final guard = (await githubService.getCheckRunsFiltered(
1150+
slug: slug,
1151+
ref: pullRequest.head!.sha!,
1152+
checkName: checkName,
1153+
)).singleOrNull;
1154+
1155+
if (guard == null) {
1156+
logSevere(
1157+
'failed to process the emergency label. "$checkName" check run is missing.',
1158+
);
1159+
return;
1160+
}
1161+
1162+
await githubService.updateCheckRun(
1163+
slug: slug,
1164+
checkRun: guard,
1165+
status: CheckRunStatus.completed,
1166+
conclusion: CheckRunConclusion.success,
1167+
output: CheckRunOutput(
1168+
title: checkName,
1169+
summary: 'Emergency label applied.',
1170+
),
1171+
);
1172+
1173+
logInfo('unlocked "$checkName", allowing it to land as an emergency.');
1174+
}
11741175
}

app_dart/test/request_handlers/github/webhook_subscription_test.dart

Lines changed: 124 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3010,15 +3010,17 @@ void foo() {
30103010
});
30113011

30123012
group('PullRequestLabelProcessor.processLabels', () {
3013-
test('applies emergency label on approved PRs', () async {
3014-
final pullRequest = generatePullRequest(
3015-
number: 123,
3016-
headSha: '6dcb09b5b57875f334f61aebed695e2e4193db5e',
3017-
labels: [IssueLabel(name: 'emergency')],
3018-
);
3013+
test(
3014+
'applies emergency label on approved PRs (Merge Queue Guard only)',
3015+
() async {
3016+
final pullRequest = generatePullRequest(
3017+
number: 123,
3018+
headSha: '6dcb09b5b57875f334f61aebed695e2e4193db5e',
3019+
labels: [IssueLabel(name: 'emergency')],
3020+
);
30193021

3020-
githubService.checkRunsMock = '''{
3021-
"total_count": 2,
3022+
githubService.checkRunsMock = '''{
3023+
"total_count": 1,
30223024
"check_runs": [
30233025
{
30243026
"id": 2,
@@ -3035,35 +3037,46 @@ void foo() {
30353037
]
30363038
}''';
30373039

3038-
final pullRequestLabelProcessor = PullRequestLabelProcessor(
3039-
config: config,
3040-
githubService: githubService,
3041-
pullRequest: pullRequest,
3042-
);
3040+
final pullRequestLabelProcessor = PullRequestLabelProcessor(
3041+
config: config,
3042+
githubService: githubService,
3043+
pullRequest: pullRequest,
3044+
);
30433045

3044-
await pullRequestLabelProcessor.processLabels();
3046+
await pullRequestLabelProcessor.processLabels();
30453047

3046-
expect(
3047-
log,
3048-
bufferedLoggerOf(
3049-
containsAll([
3050-
logThat(
3051-
message: equals(
3052-
'PullRequestLabelProcessor(flutter/flutter/pull/123): attempting to unlock the Merge Queue Guard for emergency',
3048+
expect(
3049+
log,
3050+
bufferedLoggerOf(
3051+
containsAll([
3052+
logThat(
3053+
message: equals(
3054+
'PullRequestLabelProcessor(flutter/flutter/pull/123): attempting to unlock the Merge Queue Guard for emergency',
3055+
),
30533056
),
3054-
),
3055-
logThat(
3056-
message: equals(
3057-
'PullRequestLabelProcessor(flutter/flutter/pull/123): unlocked "Merge Queue Guard", allowing it to land as an emergency.',
3057+
logThat(
3058+
message: equals(
3059+
'PullRequestLabelProcessor(flutter/flutter/pull/123): unlocked "Merge Queue Guard", allowing it to land as an emergency.',
3060+
),
30583061
),
3059-
),
3060-
]),
3061-
),
3062-
);
3063-
});
3062+
logThat(
3063+
message: equals(
3064+
'PullRequestLabelProcessor(flutter/flutter/pull/123): attempting to unlock the Flutter Presubmits for emergency',
3065+
),
3066+
),
3067+
logThat(
3068+
message: equals(
3069+
'PullRequestLabelProcessor(flutter/flutter/pull/123): failed to process the emergency label. "Flutter Presubmits" check run is missing.',
3070+
),
3071+
),
3072+
]),
3073+
),
3074+
);
3075+
},
3076+
);
30643077

30653078
test(
3066-
'logs and gracefully skips emergency label on missing Merge Queue Guard',
3079+
'applies emergency label on approved PRs (Flutter Presubmits only)',
30673080
() async {
30683081
final pullRequest = generatePullRequest(
30693082
number: 123,
@@ -3072,16 +3085,16 @@ void foo() {
30723085
);
30733086

30743087
githubService.checkRunsMock = '''{
3075-
"total_count": 2,
3088+
"total_count": 1,
30763089
"check_runs": [
30773090
{
3078-
"id": 2,
3091+
"id": 3,
30793092
"head_sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
30803093
"external_id": "",
30813094
"details_url": "https://example.com",
30823095
"status": "in_progress",
30833096
"started_at": "2018-05-04T01:14:52Z",
3084-
"name": "Not A Guard For Sure",
3097+
"name": "Flutter Presubmits",
30853098
"check_suite": {
30863099
"id": 5
30873100
}
@@ -3111,6 +3124,81 @@ void foo() {
31113124
'PullRequestLabelProcessor(flutter/flutter/pull/123): failed to process the emergency label. "Merge Queue Guard" check run is missing.',
31123125
),
31133126
),
3127+
logThat(
3128+
message: equals(
3129+
'PullRequestLabelProcessor(flutter/flutter/pull/123): attempting to unlock the Flutter Presubmits for emergency',
3130+
),
3131+
),
3132+
logThat(
3133+
message: equals(
3134+
'PullRequestLabelProcessor(flutter/flutter/pull/123): unlocked "Flutter Presubmits", allowing it to land as an emergency.',
3135+
),
3136+
),
3137+
]),
3138+
),
3139+
);
3140+
},
3141+
);
3142+
3143+
test(
3144+
'logs and gracefully skips emergency label on missing checkruns',
3145+
() async {
3146+
final pullRequest = generatePullRequest(
3147+
number: 123,
3148+
headSha: '6dcb09b5b57875f334f61aebed695e2e4193db5e',
3149+
labels: [IssueLabel(name: 'emergency')],
3150+
);
3151+
3152+
githubService.checkRunsMock = '''{
3153+
"total_count": 1,
3154+
"check_runs": [
3155+
{
3156+
"id": 2,
3157+
"head_sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
3158+
"external_id": "",
3159+
"details_url": "https://example.com",
3160+
"status": "in_progress",
3161+
"started_at": "2018-05-04T01:14:52Z",
3162+
"name": "Not A Guard For Sure",
3163+
"check_suite": {
3164+
"id": 5
3165+
}
3166+
}
3167+
]
3168+
}''';
3169+
3170+
final pullRequestLabelProcessor = PullRequestLabelProcessor(
3171+
config: config,
3172+
githubService: githubService,
3173+
pullRequest: pullRequest,
3174+
);
3175+
3176+
await pullRequestLabelProcessor.processLabels();
3177+
3178+
expect(
3179+
log,
3180+
bufferedLoggerOf(
3181+
containsAll([
3182+
logThat(
3183+
message: contains(
3184+
'attempting to unlock the Merge Queue Guard for emergency',
3185+
),
3186+
),
3187+
logThat(
3188+
message: contains(
3189+
'failed to process the emergency label. "Merge Queue Guard" check run is missing.',
3190+
),
3191+
),
3192+
logThat(
3193+
message: contains(
3194+
'attempting to unlock the Flutter Presubmits for emergency',
3195+
),
3196+
),
3197+
logThat(
3198+
message: contains(
3199+
'failed to process the emergency label. "Flutter Presubmits" check run is missing.',
3200+
),
3201+
),
31143202
]),
31153203
),
31163204
);
@@ -3153,7 +3241,7 @@ void foo() {
31533241
);
31543242
githubService.createdComments.clear();
31553243
githubService.checkRunsMock = '''{
3156-
"total_count": 2,
3244+
"total_count": 1,
31573245
"check_runs": [
31583246
{
31593247
"id": 2,
@@ -3197,7 +3285,7 @@ void foo() {
31973285
);
31983286
githubService.createdComments.clear();
31993287
githubService.checkRunsMock = '''{
3200-
"total_count": 2,
3288+
"total_count": 1,
32013289
"check_runs": [
32023290
{
32033291
"id": 2,

0 commit comments

Comments
 (0)