Add list of all plugin maintainers to plugins page

Issue: Issue 11645
Change-Id: I3b89644d139ca5d36bb2bc16674401d60f520839
diff --git a/tools/plugins.md.template b/tools/plugins.md.template
index 3774933..4215de1 100644
--- a/tools/plugins.md.template
+++ b/tools/plugins.md.template
@@ -23,7 +23,7 @@
 
 There is a [parent] component for plugin-specific components/issues in Monorail.
 
-Community members are welcome to propose themselves as plugin maintainers. This can be
+Community members are welcome to propose themselves as [plugin maintainers]. This can be
 done through the support [mailing] list:
 
 1. Volunteering can be done for either plugins with no maintainers or plugins with just
@@ -90,4 +90,5 @@
 [ownership]: https://gerrit-review.googlesource.com/Documentation/config-plugins.html#development
 [parent]: https://bugs.chromium.org/p/gerrit/issues/list?q=component%3Aplugins
 [plugins]: https://gerrit-review.googlesource.com/admin/repos/q/filter:plugins%252F
+[plugin maintainers]: #plugin-maintainers
 [supported]: https://www.gerritcodereview.com/support.html#supported-versions
diff --git a/tools/plugins.py b/tools/plugins.py
index 1b1fefe..f75d978 100644
--- a/tools/plugins.py
+++ b/tools/plugins.py
@@ -6,6 +6,7 @@
 import requests
 import sys
 import time
+from collections import defaultdict
 from dataclasses import dataclass
 from enum import Enum, IntEnum
 from operator import attrgetter
@@ -167,6 +168,7 @@
         auth = self._authenticate(self._parse_options())
         self.api = GerritRestAPI(url=GERRIT, auth=auth)
         self.plugins = list()
+        self.maintainers = defaultdict(list)
         self._fetch_plugin_data()
         self.plugins = sorted(self.plugins, key=attrgetter("state", "empty"))
 
@@ -199,13 +201,16 @@
             )
 
             parent, owner_group_ids = self._get_meta_data(name)
+            maintainers, maintainers_csv = self._get_owner_names(
+                parent, owner_group_ids
+            )
             self.plugins.append(
                 Plugin(
                     name=name,
                     parent=parent,
                     state=state,
                     owner_group_ids=owner_group_ids,
-                    owner_names=self._get_owner_names(parent, owner_group_ids),
+                    owner_names=maintainers_csv,
                     empty=self._is_project_empty(p),
                     description=description,
                     all_changes_count=self._get_all_changes_count(p),
@@ -213,6 +218,8 @@
                     branches=branches,
                 )
             )
+            for m in maintainers:
+                self.maintainers[m].append(name)
 
     def _authenticate(self, options):
         if options.netrc:
@@ -294,8 +301,8 @@
         names = sorted(list(names))
         if parent == "Public-Plugins":
             names.insert(0, "Core maintainers")
-        names = ", ".join(names)
-        return names
+        csv = ", ".join(names)
+        return names, csv
 
     def _is_project_empty(self, pluginName):
         gitiles_uri = f"{GITILES}/{pluginName}"
@@ -308,6 +315,21 @@
             print(f"Failed to browse {pluginName} in gitiles:\n{e}", file=sys.stderr)
         return False
 
+    @staticmethod
+    def _name_sorter(word):
+        pattern = re.compile(r"[\W]+")
+        return word != "Core maintainers", pattern.sub("", word)
+
+    def _render_maintainers(self, output):
+        header = "|Maintainer|Plugins|"
+        dashes = "|----------|-------|"
+        output.write("\n\n## Plugin Maintainers")
+        output.write(f"\n\n{header}|\n{dashes}|\n")
+        for m in sorted(self.maintainers, key=Plugins._name_sorter):
+            output.write(
+                f"|{m}|{', '.join(sorted(self.maintainers[m], key=Plugins._name_sorter))}|\n"
+            )
+
     def render_page(self, output):
         output.writelines(self._render_template())
         (header, dashes, spacer, links) = self._render_header()
@@ -334,6 +356,7 @@
             links += f"[{p.name}]: {GITILES}/plugins/{p.name}\n"
 
         output.write(links)
+        self._render_maintainers(output)
 
 
 def main():