pw_presubmit: Check style of the first line of the commit message

Check that the first line of the commit message style matches the style:

  module_or_target: Description

This style is required by the Pigweed style guide:
https://pigweed.dev/docs/style_guide.html#commit-message

Change-Id: I37427a5be41d343c700fa85b4e2ceb8b48a2934e
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/111533
Commit-Queue: Wyatt Hepler <hepler@google.com>
Reviewed-by: Rob Mohr <mohrr@google.com>
Pigweed-Auto-Submit: Wyatt Hepler <hepler@google.com>
diff --git a/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py b/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
index fe86fa4..10c9208 100755
--- a/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
+++ b/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
@@ -728,6 +728,14 @@
     call('pyoxidizer', 'build', cwd=ctx.output_dir)
 
 
+def _valid_capitalization(word: str) -> bool:
+    """Checks that the word has a capital letter or is not a regular word."""
+    return bool(
+        any(c.isupper() for c in word)  # Any capitalizatian (iTelephone)
+        or not word.isalpha()  # Non-alphabetical (cool_stuff.exe)
+        or shutil.which(word))  # Matches an executable (clangd)
+
+
 def commit_message_format(_: PresubmitContext):
     """Checks that the top commit's message is correctly formatted."""
     lines = git_repo.commit_message().splitlines()
@@ -763,6 +771,21 @@
             lines[0])
         errors += 1
 
+    # Check that the first line matches the expected pattern.
+    match = re.match(r'^[\w/]+(?:{[\w ,]+})?: (?P<desc>.+)$', lines[0])
+    if not match:
+        _LOG.warning('The first line does not match the expected format')
+        _LOG.warning(
+            'Expected:\n\n  module_or_target: The description\n\n'
+            'Found:\n\n  %s\n', lines[0])
+        errors += 1
+    elif not _valid_capitalization(match.group('desc').split()[0]):
+        _LOG.warning(
+            'The first word after the ":" in the first line ("%s") must be '
+            'capitalized:\n  %s',
+            match.group('desc').split()[0], lines[0])
+        errors += 1
+
     if len(lines) > 1 and lines[1]:
         _LOG.warning("The commit message's second line must be blank.")
         _LOG.warning('The second line has %d characters:\n  %s', len(lines[1]),