Improve presubmit's Bug: tag check

Specifying the project name is now mandatory.  This helps avoid
accidentally referring to chromium bugs by forgetting the project name.
At the same time, it ensures the project name is not misspelled.

Bug: angleproject:4184
Change-Id: I6bbfe1751e2fd0baf424be38018374cce360df5d
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1969067
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Jonah Ryan-Davis <jonahr@google.com>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 0de387a..f71cd0c 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -8,6 +8,7 @@
 """
 
 import os
+import re
 import shutil
 import subprocess
 import sys
@@ -28,7 +29,7 @@
 
 
 def _CheckChangeHasBugField(input_api, output_api):
-    """Requires that the changelist have a Bug: field."""
+    """Requires that the changelist have a Bug: field from a known project."""
     bugs = input_api.change.BugsFromDescription()
     if not bugs:
         return [
@@ -36,14 +37,37 @@
                                       '"Bug: angleproject:[bug number]"\n'
                                       'directly above the Change-Id tag.')
         ]
-    elif not all([' ' not in bug for bug in bugs]):
-        return [
-            output_api.PresubmitError(
-                'Check bug tag formatting. Ensure there are no spaces after the colon.')
-        ]
-    else:
+
+    # The bug must be in the form of "project:number".  None is also accepted, which is used by
+    # rollers as well as in very minor changes.
+    if len(bugs) == 1 and bugs[0] == 'None':
         return []
 
+    projects = ['angleproject', 'chromium', 'dawn', 'fuchsia', 'skia', 'swiftshader']
+    bug_regex = re.compile(r"([a-z]+):(\d+)")
+    errors = []
+    extra_help = None
+
+    for bug in bugs:
+        if bug == 'None':
+            errors.append(
+                output_api.PresubmitError('Invalid bug tag "None" in presence of other bug tags.'))
+            continue
+
+        match = re.match(bug_regex, bug)
+        if match == None or bug != match.group(0) or match.group(1) not in projects:
+            errors.append(output_api.PresubmitError('Incorrect bug tag "' + bug + '".'))
+            if not extra_help:
+                extra_help = output_api.PresubmitError('Acceptable format is:\n\n'
+                                                       '    Bug: project:bugnumber\n\n'
+                                                       'Acceptable projects are:\n\n    ' +
+                                                       '\n    '.join(projects))
+
+    if extra_help:
+        errors.append(extra_help)
+
+    return errors
+
 
 def _CheckCodeGeneration(input_api, output_api):