diff --git a/app_dart/lib/src/request_handlers/github/webhook_subscription.dart b/app_dart/lib/src/request_handlers/github/webhook_subscription.dart index d7ddb8df5..b3a8f1bd9 100644 --- a/app_dart/lib/src/request_handlers/github/webhook_subscription.dart +++ b/app_dart/lib/src/request_handlers/github/webhook_subscription.dart @@ -199,11 +199,14 @@ final class GithubWebhookSubscription extends SubscriptionHandler { final result = await _processPullRequestClosed(pullRequestEvent); return result.toResponse(); case 'edited': - await _addCICDForRollers(pullRequestEvent); + if (pullRequestEvent.changes != null && + pullRequestEvent.changes!.base != null) { + await _addCICDForRollersAndMembers(pullRequestEvent); + } await _checkForTests(pullRequestEvent); break; case 'opened': - await _addCICDForRollers(pullRequestEvent); + await _addCICDForRollersAndMembers(pullRequestEvent); await _checkForTests(pullRequestEvent); await _tryReleaseApproval(pullRequestEvent); break; @@ -232,8 +235,10 @@ final class GithubWebhookSubscription extends SubscriptionHandler { case 'dequeued': await _respondToPullRequestDequeued(pullRequestEvent); break; - // Ignore the rest of the events. case 'synchronize': + await _addCICDForRollersAndMembers(pullRequestEvent); + break; + // Ignore the rest of the events. case 'ready_for_review': case 'unlabeled': case 'assigned': @@ -569,12 +574,22 @@ final class GithubWebhookSubscription extends SubscriptionHandler { ); } - Future _addCICDForRollers(PullRequestEvent pullRequestEvent) async { + Future _addCICDForRollersAndMembers( + PullRequestEvent pullRequestEvent, + ) async { final pr = pullRequestEvent.pullRequest!; final slug = pr.base!.repo!.slug(); + final author = pr.user!.login!; + final githubService = await config.createGithubService(slug); + + final isRoller = config.rollerAccounts.contains(pr.user!.login); + final isFlutterHacker = await githubService.isTeamMember( + 'flutter-hackers', + author, + slug.owner, + ); - if (config.rollerAccounts.contains(pr.user!.login) && - config.supportedRepos.contains(slug)) { + if (config.supportedRepos.contains(slug) && (isRoller || isFlutterHacker)) { final gitHubClient = await config.createGitHubClient(pullRequest: pr); await gitHubClient.issues.addLabelsToIssue(slug, pr.number!, ['CICD']); } diff --git a/app_dart/lib/src/service/github_service.dart b/app_dart/lib/src/service/github_service.dart index 53de70af6..14adf0fda 100644 --- a/app_dart/lib/src/service/github_service.dart +++ b/app_dart/lib/src/service/github_service.dart @@ -113,6 +113,20 @@ class GithubService { .toList(); } + /// Check to see if user is a member of team in org. + /// + /// Note that we catch here as the api returns a 404 if the user has no + /// membership in general or is not a member of the team. + Future isTeamMember(String team, String user, String org) async { + try { + final teamMembershipState = await github.organizations + .getTeamMembershipByName(org, team, user); + return teamMembershipState.isActive; + } on GitHubError { + return false; + } + } + /// Creates a pull request against the `baseRef` in the `slug` repository. /// /// The `entries` contains the file changes in the created pull request. This diff --git a/app_dart/test/request_handlers/github/webhook_subscription_test.dart b/app_dart/test/request_handlers/github/webhook_subscription_test.dart index 8c6cf0591..1b8dff8d1 100644 --- a/app_dart/test/request_handlers/github/webhook_subscription_test.dart +++ b/app_dart/test/request_handlers/github/webhook_subscription_test.dart @@ -3715,6 +3715,34 @@ void foo() { expect(scheduler.triggerPresubmitTargetsCnt, 0); }); + test( + 'opened PR with adds CICD label if author is member of flutter-hackers', + () async { + tester.message = generateGithubWebhookMessage( + action: 'opened', + login: 'test-flutter-hacker', + ); + + await tester.post(webhook); + + verify( + issuesService.addLabelsToIssue(Config.flutterSlug, 123, ['CICD']), + ); + }, + ); + test( + 'opened PR does not add CICD label if author is not member of flutter-hackers', + () async { + tester.message = generateGithubWebhookMessage(action: 'opened'); + + await tester.post(webhook); + + verifyNever( + issuesService.addLabelsToIssue(Config.flutterSlug, 123, any), + ); + }, + ); + test( 'labeled event with CICD label schedules tests on flutter/flutter', () async { @@ -3805,5 +3833,31 @@ void foo() { expect(scheduler.triggerPresubmitTargetsCnt, 0); }, ); + + test( + 'synchronize event adds CICD label if author is member of flutter-hackers', + () async { + tester.message = generateGithubWebhookMessage( + action: 'synchronize', + login: 'test-flutter-hacker', + ); + + await tester.post(webhook); + verify( + issuesService.addLabelsToIssue(Config.flutterSlug, 123, ['CICD']), + ); + }, + ); + test( + 'synchronize event does not add CICD label if author is not member of flutter-hackers', + () async { + tester.message = generateGithubWebhookMessage(action: 'synchronize'); + + await tester.post(webhook); + verifyNever( + issuesService.addLabelsToIssue(Config.flutterSlug, 123, any), + ); + }, + ); }); } diff --git a/packages/cocoon_integration_test/lib/src/fakes/fake_github_service.dart b/packages/cocoon_integration_test/lib/src/fakes/fake_github_service.dart index 8bf789f0f..d899c3d50 100644 --- a/packages/cocoon_integration_test/lib/src/fakes/fake_github_service.dart +++ b/packages/cocoon_integration_test/lib/src/fakes/fake_github_service.dart @@ -64,6 +64,14 @@ class FakeGithubService implements GithubService { return true; } + @override + Future isTeamMember(String team, String user, String org) async { + if (user == 'test-flutter-hacker') { + return true; + } + return false; + } + @override Future assignReviewer( RepositorySlug slug, {