BCR PR reviewer: add support for a "do_not_notify" field (#2037)

A maintainer can request to not be notified by new PRs by setting
`"do_not_notify": true`. In this case, they can still approve the PR and
have it count, but they won't be pinged.

This helps in situations like protobuf's release rotation, which has a
lot of people but ideally only the releaser should be notified and be
able to approve the PR. It's rather hard to support a "rotating"
maintainer model, though. Thus we compromise by adding everyone from
that rotation as a "do-not-notify" maintainer, and asking the releaser
to watch out for the PR manually as a release step.

cc @zhangskz
diff --git a/actions/bcr-pr-reviewer/index.js b/actions/bcr-pr-reviewer/index.js
index 0fcb491..21369c2 100644
--- a/actions/bcr-pr-reviewer/index.js
+++ b/actions/bcr-pr-reviewer/index.js
@@ -29,7 +29,7 @@
   return accumulate;
 }
 
-async function generateMaintainersMap(octokit, owner, repo, modifiedModules) {
+async function generateMaintainersMap(octokit, owner, repo, modifiedModules, toNotifyOnly) {
   const maintainersMap = new Map(); // Map: maintainer GitHub username -> Set of module they maintain
   const modulesWithoutGithubMaintainers = new Set(); // Set of module names without module maintainers
   for (const moduleName of modifiedModules) {
@@ -45,7 +45,8 @@
       const metadata = JSON.parse(Buffer.from(metadataContent.content, 'base64').toString('utf-8'));
       let hasGithubMaintainer = false;
       metadata.maintainers.forEach(maintainer => {
-        if (maintainer.github) { // Check if the github field is specified
+        // Only add maintainers with a github handle set. When `toNotifyOnly`, also exclude those who have set "do_not_notify"
+        if (maintainer.github && !(toNotifyOnly && maintainer["do_not_notify"])) {
           hasGithubMaintainer = true;
           if (!maintainersMap.has(maintainer.github)) {
             maintainersMap.set(maintainer.github, new Set());
@@ -256,7 +257,7 @@
   }
 
   // Figure out maintainers for each modified module
-  const [ maintainersMap, modulesWithoutGithubMaintainers ] = await generateMaintainersMap(octokit, owner, repo, modifiedModules);
+  const [ maintainersMap, modulesWithoutGithubMaintainers ] = await generateMaintainersMap(octokit, owner, repo, modifiedModules, /* toNotifyOnly= */ false);
   console.log('Maintainers Map:');
   for (const [maintainer, maintainedModules] of maintainersMap.entries()) {
     console.log(`- Maintainer: ${maintainer}, Modules: ${Array.from(maintainedModules).join(', ')}`);
@@ -332,7 +333,7 @@
   console.log(`Modified modules: ${Array.from(modifiedModules).join(', ')}`);
 
   // Figure out maintainers for each modified module
-  const [ maintainersMap, modulesWithoutGithubMaintainers ] = await generateMaintainersMap(octokit, owner, repo, modifiedModules);
+  const [ maintainersMap, modulesWithoutGithubMaintainers ] = await generateMaintainersMap(octokit, owner, repo, modifiedModules, /* toNotifyOnly= */ true);
 
   // Notify maintainers for modules with module maintainers
   await notifyMaintainers(octokit, owner, repo, prNumber, maintainersMap);