Prechádzať zdrojové kódy

[git_footers] add support for multiline footers

Gerrit allows multiline footers with indents.

e.g.,
Test: something
   looks great

This CL fixes the bug such that add_footer correctly inserts
a given message after multiline footers.

Bug: 379923433
Change-Id: I9b3f793095b63b0586123543a2f8d49f0503fca0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/6064963
Reviewed-by: Josip Sokcevic <sokcevic@chromium.org>
Commit-Queue: Scott Lee <ddoman@chromium.org>
Scott Lee 8 mesiacov pred
rodič
commit
562c59c76c
2 zmenil súbory, kde vykonal 117 pridanie a 15 odobranie
  1. 23 15
      git_footers.py
  2. 94 0
      tests/git_footers_test.py

+ 23 - 15
git_footers.py

@@ -42,15 +42,12 @@ def parse_footers(message):
     return footer_map
     return footer_map
 
 
 
 
-def matches_footer_key(line, key):
-    """Returns whether line is a valid footer whose key matches a given one.
-
-    Keys are compared in normalized form.
-    """
+def normalize_key(line):
+    """Returns the key of the footer line in normalized form."""
     r = parse_footer(line)
     r = parse_footer(line)
     if r is None:
     if r is None:
-        return False
-    return normalize_name(r[0]) == normalize_name(key)
+        return ''
+    return normalize_name(r[0])
 
 
 
 
 def split_footers(message):
 def split_footers(message):
@@ -140,16 +137,27 @@ def add_footer(message, key, value, after_keys=None):
             top_lines.append('')
             top_lines.append('')
         footer_lines = [new_footer]
         footer_lines = [new_footer]
     else:
     else:
+        # find the index of the last footer with any of the after_keys.
         after_keys = set(map(normalize_name, after_keys or []))
         after_keys = set(map(normalize_name, after_keys or []))
-        after_indices = [
-            footer_lines.index(x) for x in footer_lines for k in after_keys
-            if matches_footer_key(x, k)
-        ]
-        if after_indices:
-            # after_keys takes precedence, even if there's a conflict.
-            insert_idx = max(after_indices) + 1
-        else:
+        last_akey_idx = None
+        for idx in range(len(footer_lines)):
+            line = footer_lines[idx]
+
+            # if the current footer is indented, it may be a continuation of
+            # the previous line.
+            if line and line[0] == ' ':
+                if last_akey_idx is None:
+                    continue
+                if idx - last_akey_idx > 1:
+                    continue
+            elif normalize_key(line) not in after_keys:
+                continue
+            last_akey_idx = idx
+
+        if last_akey_idx is None:
             insert_idx = len(footer_lines)
             insert_idx = len(footer_lines)
+        else:
+            insert_idx = last_akey_idx + 1
         footer_lines.insert(insert_idx, new_footer)
         footer_lines.insert(insert_idx, new_footer)
     return '\n'.join(top_lines + footer_lines)
     return '\n'.join(top_lines + footer_lines)
 
 

+ 94 - 0
tests/git_footers_test.py

@@ -171,6 +171,100 @@ My commit message is my best friend. It is my life.
                                              'Ix'),
                                              'Ix'),
             'Header.\n\nBug: v8\nChange-Id: Ix\nN=t\nT=z')
             'Header.\n\nBug: v8\nChange-Id: Ix\nN=t\nT=z')
 
 
+    def testAddFooterChangeIdWithMultilineFooters(self):
+        add_change_id = lambda lines: git_footers.add_footer_change_id(
+            '\n'.join(lines), 'Ixxx')
+
+        self.assertEqual(
+            add_change_id([
+                'header',
+                '',
+                '',
+                'BUG: yy',
+                'Test: hello ',
+                '  world',
+            ]),
+            '\n'.join([
+                'header',
+                '',
+                '',
+                'BUG: yy',
+                'Test: hello ',
+                '  world',
+                'Change-Id: Ixxx',
+            ]),
+        )
+
+        self.assertEqual(
+            add_change_id([
+                'header',
+                '',
+                '',
+                'BUG: yy',
+                'Yeah: hello ',
+                '  world',
+            ]),
+            '\n'.join([
+                'header',
+                '',
+                '',
+                'BUG: yy',
+                'Change-Id: Ixxx',
+                'Yeah: hello ',
+                '  world',
+            ]),
+        )
+
+        self.assertEqual(
+            add_change_id([
+                'header',
+                '',
+                '',
+                'Something: ',
+                '   looks great',
+                'BUG: yy',
+                'Test: hello ',
+                '  world',
+            ]),
+            '\n'.join([
+                'header',
+                '',
+                '',
+                'Something: ',
+                '   looks great',
+                'BUG: yy',
+                'Test: hello ',
+                '  world',
+                'Change-Id: Ixxx',
+            ]),
+        )
+
+        self.assertEqual(
+            add_change_id([
+                'header',
+                '',
+                '',
+                'Something: ',
+                'BUG: yy',
+                'Something: ',
+                '   looks great',
+                'Test: hello ',
+                '  world',
+            ]),
+            '\n'.join([
+                'header',
+                '',
+                '',
+                'Something: ',
+                'BUG: yy',
+                'Something: ',
+                '   looks great',
+                'Test: hello ',
+                '  world',
+                'Change-Id: Ixxx',
+            ]),
+        )
+
     def testAddFooter(self):
     def testAddFooter(self):
         with self.assertRaises(ValueError):
         with self.assertRaises(ValueError):
             git_footers.add_footer('', 'Invalid Footer', 'Value')
             git_footers.add_footer('', 'Invalid Footer', 'Value')