From cd8b9b2fd875b5040b1ca9f0c8f5acaffe70ab7f Mon Sep 17 00:00:00 2001 From: Ket3r Date: Thu, 30 Sep 2021 16:07:05 +0200 Subject: [PATCH] Use git interpret-trailers for trailers property The whitespace handling and trailer selection isn't very trivial or good documented. It therefore seemed easier and less error prone to just call git to parse the message for the trailers section and remove superfluos whitespaces. --- git/objects/commit.py | 43 ++++++++++++++++++++++++++----------------- test/test_commit.py | 4 ++-- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/git/objects/commit.py b/git/objects/commit.py index 780461a0c..bbd485da8 100644 --- a/git/objects/commit.py +++ b/git/objects/commit.py @@ -4,8 +4,7 @@ # This module is part of GitPython and is released under # the BSD License: http://www.opensource.org/licenses/bsd-license.php import datetime -import re -from subprocess import Popen +from subprocess import Popen, PIPE from gitdb import IStream from git.util import ( hex_to_bin, @@ -14,6 +13,7 @@ finalize_process ) from git.diff import Diffable +from git.cmd import Git from .tree import Tree from . import base @@ -322,10 +322,10 @@ def trailers(self) -> Dict: Git messages can contain trailer information that are similar to RFC 822 e-mail headers (see: https://git-scm.com/docs/git-interpret-trailers). - - The trailer is thereby the last paragraph (seperated by a empty line - from the subject/body). This trailer paragraph must contain a ``:`` as - seperator for key and value in every line. + + This funcions calls ``git interpret-trailers --parse`` onto the message + to extract the trailer information. The key value pairs are stripped of + leading and trailing whitespaces before they get saved into a dictionary. Valid message with trailer: @@ -338,20 +338,29 @@ def trailers(self) -> Dict: another information key1: value1 - key2: value2 + key2 : value 2 with inner spaces + + dictionary will look like this: + .. code-block:: + + { + "key1": "value1", + "key2": "value 2 with inner spaces" + } :return: Dictionary containing whitespace stripped trailer information + """ - d: Dict[str, str] = {} - match = re.search(r".+^\s*$\n([\w\n\s:]+?)\s*\Z", str(self.message), re.MULTILINE | re.DOTALL) - if match is None: - return d - last_paragraph = match.group(1) - if not all(':' in line for line in last_paragraph.split('\n')): - return d - for line in last_paragraph.split('\n'): - key, value = line.split(':', 1) - d[key.strip()] = value.strip() + d = {} + cmd = ['git', 'interpret-trailers', '--parse'] + proc: Git.AutoInterrupt = self.repo.git.execute(cmd, as_process=True, istream=PIPE) # type: ignore + trailer: str = proc.communicate(str(self.message).encode())[0].decode() + if trailer.endswith('\n'): + trailer = trailer[0:-1] + if trailer != '': + for line in trailer.split('\n'): + key, value = line.split(':', 1) + d[key.strip()] = value.strip() return d @ classmethod diff --git a/test/test_commit.py b/test/test_commit.py index 5aeef2e6c..40cf7dd26 100644 --- a/test/test_commit.py +++ b/test/test_commit.py @@ -435,14 +435,14 @@ def test_trailers(self): KEY_1 = "Hello" VALUE_1 = "World" KEY_2 = "Key" - VALUE_2 = "Value" + VALUE_2 = "Value with inner spaces" # Check if KEY 1 & 2 with Value 1 & 2 is extracted from multiple msg variations msgs = [] msgs.append(f"Subject\n\n{KEY_1}: {VALUE_1}\n{KEY_2}: {VALUE_2}\n") msgs.append(f"Subject\n \nSome body of a function\n \n{KEY_1}: {VALUE_1}\n{KEY_2}: {VALUE_2}\n") msgs.append(f"Subject\n \nSome body of a function\n\nnon-key: non-value\n\n{KEY_1}: {VALUE_1}\n{KEY_2}: {VALUE_2}\n") - msgs.append(f"Subject\n \nSome multiline\n body of a function\n\nnon-key: non-value\n\n{KEY_1}: {VALUE_1}\n{KEY_2}: {VALUE_2}\n") + msgs.append(f"Subject\n \nSome multiline\n body of a function\n\nnon-key: non-value\n\n{KEY_1}: {VALUE_1}\n{KEY_2} : {VALUE_2}\n") for msg in msgs: commit = self.rorepo.commit('master')