fix revert enqueue cycle; ack pubsub (#4055)
Fixes https://github.com/flutter/flutter/issues/159518
diff --git a/auto_submit/lib/service/pull_request_validation_service.dart b/auto_submit/lib/service/pull_request_validation_service.dart
index 7a3f0dd..322c352 100644
--- a/auto_submit/lib/service/pull_request_validation_service.dart
+++ b/auto_submit/lib/service/pull_request_validation_service.dart
@@ -59,11 +59,14 @@
final github.RepositorySlug slug = messagePullRequest.base!.repo!.slug();
final int prNumber = messagePullRequest.number!;
+ // If a pull request is currently in the merge queue do not touch it. Let
+ // the merge queue merge it, or kick it out of the merge queue.
if (messagePullRequest.isMergeQueueEnabled) {
if (result.repository!.pullRequest!.isInMergeQueue) {
log.info(
'${slug.fullName}/$prNumber is already in the merge queue. Skipping.',
);
+ await pubsub.acknowledge(config.pubsubRevertRequestSubscription, ackId);
return;
}
}
@@ -140,7 +143,7 @@
await githubService.createComment(slug, prNumber, message);
log.info(message);
} else {
- log.info('Pull Request ${slug.fullName}/$prNumber was merged successfully!');
+ log.info('Pull Request ${slug.fullName}/$prNumber was ${processed.method.pastTenseLabel} successfully!');
log.info('Attempting to insert a pull request record into the database for $prNumber');
await insertPullRequestRecord(
config: config,
diff --git a/auto_submit/lib/service/revert_request_validation_service.dart b/auto_submit/lib/service/revert_request_validation_service.dart
index 125d69e..83d17a4 100644
--- a/auto_submit/lib/service/revert_request_validation_service.dart
+++ b/auto_submit/lib/service/revert_request_validation_service.dart
@@ -218,6 +218,18 @@
final GithubService githubService = await config.createGithubService(slug);
final int prNumber = messagePullRequest.number!;
+ // If a pull request is currently in the merge queue do not touch it. Let
+ // the merge queue merge it, or kick it out of the merge queue.
+ if (messagePullRequest.isMergeQueueEnabled) {
+ if (result.repository!.pullRequest!.isInMergeQueue) {
+ log.info(
+ '${slug.fullName}/$prNumber is already in the merge queue. Skipping.',
+ );
+ await pubsub.acknowledge(config.pubsubRevertRequestSubscription, ackId);
+ return;
+ }
+ }
+
// Check to make sure the repository allows review-less revert pull requests
// so that we can reassign if needed otherwise autoapprove the pull request.
final RepositoryConfiguration repositoryConfiguration = await config.getRepositoryConfiguration(slug);
@@ -304,7 +316,7 @@
final Message discordMessage = craftDiscordRevertMessage(messagePullRequest);
discordNotification.notifyDiscordChannelWebhook(jsonEncode(discordMessage.toJson()));
- log.info('Pull Request ${slug.fullName}/$prNumber was merged successfully!');
+ log.info('Pull Request ${slug.fullName}/$prNumber was ${processed.method.pastTenseLabel} successfully!');
log.info('Attempting to insert a pull request record into the database for $prNumber');
await insertPullRequestRecord(
config: config,
diff --git a/auto_submit/lib/service/validation_service.dart b/auto_submit/lib/service/validation_service.dart
index 9f1adfd..9e29565 100644
--- a/auto_submit/lib/service/validation_service.dart
+++ b/auto_submit/lib/service/validation_service.dart
@@ -101,10 +101,10 @@
} catch (e) {
final message = 'Failed to enqueue ${slug.fullName}/${restPullRequest.number} with $e';
log.severe(message);
- return (result: false, message: message);
+ return (result: false, message: message, method: SubmitMethod.enqueue);
}
- return (result: true, message: restPullRequest.title!);
+ return (result: true, message: restPullRequest.title!, method: SubmitMethod.enqueue);
}
Future<MergeResult> _mergePullRequest(int number, String commitMessage, github.RepositorySlug slug) async {
@@ -129,16 +129,16 @@
if (result != null && !merged) {
final String message = 'Failed to merge ${slug.fullName}/$number with ${result?.message}';
log.severe(message);
- return (result: false, message: message);
+ return (result: false, message: message, method: SubmitMethod.merge);
}
} catch (e) {
// Catch graphql client init exceptions.
final String message = 'Failed to merge ${slug.fullName}/$number with $e';
log.severe(message);
- return (result: false, message: message);
+ return (result: false, message: message, method: SubmitMethod.merge);
}
- return (result: true, message: commitMessage);
+ return (result: true, message: commitMessage, method: SubmitMethod.merge);
}
/// Insert a merged pull request record into the database.
@@ -183,9 +183,28 @@
}
}
+/// Method used to submit the PR for merging.
+enum SubmitMethod {
+ /// The PR is enqueued into the merge queue, and the merge queue is responsible
+ /// for merging the PR.
+ enqueue('enqueued'),
+
+ /// The PR is immediately merged into the target branch.
+ ///
+ /// This is the old method for merging PRs, used by repos where merge queues
+ /// are not (yet?) enabled.
+ merge('merged');
+
+ const SubmitMethod(this.pastTenseLabel);
+
+ /// The verb in past tense used to describe what happened to a PR when this
+ /// submit method was used, e.g. "merged".
+ final String pastTenseLabel;
+}
+
/// Small wrapper class to allow us to capture and create a comment in the PR with
/// the issue that caused the merge failure.
-typedef MergeResult = ({bool result, String message});
+typedef MergeResult = ({bool result, String message, SubmitMethod method});
/// Function signature that will be executed with retries.
typedef RetryHandler = Function();
diff --git a/auto_submit/test/service/pull_request_validation_service_test.dart b/auto_submit/test/service/pull_request_validation_service_test.dart
index 7e740bc..4124c67 100644
--- a/auto_submit/test/service/pull_request_validation_service_test.dart
+++ b/auto_submit/test/service/pull_request_validation_service_test.dart
@@ -645,6 +645,7 @@
mergeable: true,
);
+ unawaited(pubsub.publish(config.pubsubRevertRequestSubscription, pullRequest));
await validationService.processPullRequest(
config: config,
result: createQueryResult(flutterRequest),
@@ -658,6 +659,7 @@
logs,
contains('[INFO] auto_submit: flutter/flaux/0 is already in the merge queue. Skipping.'),
);
+ assert(pubsub.messagesQueue.isEmpty);
});
});
}
diff --git a/auto_submit/test/service/revert_request_validation_service_test.dart b/auto_submit/test/service/revert_request_validation_service_test.dart
index 87a3fe7..622cd16 100644
--- a/auto_submit/test/service/revert_request_validation_service_test.dart
+++ b/auto_submit/test/service/revert_request_validation_service_test.dart
@@ -9,6 +9,7 @@
import 'package:auto_submit/model/auto_submit_query_result.dart' as auto hide PullRequest;
import 'package:auto_submit/requests/github_pull_request_event.dart';
import 'package:auto_submit/model/discord_message.dart';
+import 'package:auto_submit/service/log.dart';
import 'package:auto_submit/service/revert_request_validation_service.dart';
import 'package:auto_submit/service/validation_service.dart';
import 'package:auto_submit/validations/validation.dart';
@@ -1233,6 +1234,59 @@
expect(githubService.labelRemoved, true);
assert(pubsub.messagesQueue.isEmpty);
});
+
+ test('Do not re-enqueue already enqueued pull requests', () async {
+ // Use a test slug that has MQ enabled
+ slug = RepositorySlug('flutter', 'flaux');
+
+ final logs = <String>[];
+ final logSub = log.onRecord.listen((record) {
+ logs.add(record.toString());
+ });
+
+ final FakePubSub pubsub = FakePubSub();
+
+ final PullRequestHelper flutterRequest = PullRequestHelper(
+ prNumber: 0,
+ lastCommitHash: oid,
+ reviews: <PullRequestReviewHelper>[],
+ isInMergeQueue: true,
+ );
+
+ final auto.QueryResult queryResult = createQueryResult(flutterRequest);
+
+ final PullRequest pullRequest = generatePullRequest(
+ prNumber: 0,
+ repoName: slug.name,
+ labelName: 'revert of',
+ body: sampleRevertBody.replaceAll('\n', ''),
+ );
+
+ final GithubPullRequestEvent githubPullRequestEvent = GithubPullRequestEvent(
+ pullRequest: pullRequest,
+ action: 'labeled',
+ sender: User(login: 'auto-submit[bot]'),
+ );
+
+ // Process the pull request
+ unawaited(pubsub.publish(config.pubsubRevertRequestSubscription, pullRequest));
+ await validationService.processRevertOfRequest(
+ result: queryResult,
+ githubPullRequestEvent: githubPullRequestEvent,
+ ackId: 'test',
+ pubsub: pubsub,
+ );
+ await logSub.cancel();
+
+ // Expectations
+ expect(
+ logs,
+ contains('[INFO] auto_submit: flutter/flaux/0 is already in the merge queue. Skipping.'),
+ );
+ expect(githubService.issueComment, isNull);
+ expect(githubService.labelRemoved, false);
+ assert(pubsub.messagesQueue.isEmpty);
+ });
});
group('Craft discord message', () {