|
4 | 4 | # This module is part of GitPython and is released under
|
5 | 5 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php
|
6 | 6 | import datetime
|
| 7 | +import re |
7 | 8 | from subprocess import Popen
|
8 | 9 | from gitdb import IStream
|
9 | 10 | from git.util import (
|
|
39 | 40 |
|
40 | 41 | # typing ------------------------------------------------------------------
|
41 | 42 |
|
42 |
| -from typing import Any, IO, Iterator, List, Sequence, Tuple, Union, TYPE_CHECKING, cast |
| 43 | +from typing import Any, IO, Iterator, List, Sequence, Tuple, Union, TYPE_CHECKING, cast, Dict |
43 | 44 |
|
44 | 45 | from git.types import PathLike, Literal
|
45 | 46 |
|
@@ -315,6 +316,44 @@ def stats(self) -> Stats:
|
315 | 316 | text = self.repo.git.diff(self.parents[0].hexsha, self.hexsha, '--', numstat=True)
|
316 | 317 | return Stats._list_from_string(self.repo, text)
|
317 | 318 |
|
| 319 | + @property |
| 320 | + def trailers(self) -> Dict: |
| 321 | + """Get the trailers of the message as dictionary |
| 322 | +
|
| 323 | + Git messages can contain trailer information that are similar to RFC 822 |
| 324 | + e-mail headers (see: https://git-scm.com/docs/git-interpret-trailers). |
| 325 | + |
| 326 | + The trailer is thereby the last paragraph (seperated by a empty line |
| 327 | + from the subject/body). This trailer paragraph must contain a ``:`` as |
| 328 | + seperator for key and value in every line. |
| 329 | +
|
| 330 | + Valid message with trailer: |
| 331 | +
|
| 332 | + .. code-block:: |
| 333 | +
|
| 334 | + Subject line |
| 335 | +
|
| 336 | + some body information |
| 337 | +
|
| 338 | + another information |
| 339 | +
|
| 340 | + key1: value1 |
| 341 | + key2: value2 |
| 342 | +
|
| 343 | + :return: Dictionary containing whitespace stripped trailer information |
| 344 | + """ |
| 345 | + d: Dict[str, str] = {} |
| 346 | + match = re.search(r".+^\s*$\n([\w\n\s:]+?)\s*\Z", str(self.message), re.MULTILINE | re.DOTALL) |
| 347 | + if match is None: |
| 348 | + return d |
| 349 | + last_paragraph = match.group(1) |
| 350 | + if not all(':' in line for line in last_paragraph.split('\n')): |
| 351 | + return d |
| 352 | + for line in last_paragraph.split('\n'): |
| 353 | + key, value = line.split(':', 1) |
| 354 | + d[key.strip()] = value.strip() |
| 355 | + return d |
| 356 | + |
318 | 357 | @ classmethod
|
319 | 358 | def _iter_from_process_or_stream(cls, repo: 'Repo', proc_or_stream: Union[Popen, IO]) -> Iterator['Commit']:
|
320 | 359 | """Parse out commit information into a list of Commit objects
|
|
0 commit comments