Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite3bc5d1

Browse files
authored
Merge pull request#1576 from itsluketwist/fix-trailers
Fix up the commit trailers functionality
2 parents61ed7ec +9ef07a7 commite3bc5d1

File tree

2 files changed

+121
-58
lines changed

2 files changed

+121
-58
lines changed

‎git/objects/commit.py

Lines changed: 80 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
importos
2727
fromioimportBytesIO
2828
importlogging
29+
fromcollectionsimportdefaultdict
2930

3031

3132
# typing ------------------------------------------------------------------
@@ -335,8 +336,72 @@ def stats(self) -> Stats:
335336
returnStats._list_from_string(self.repo,text)
336337

337338
@property
338-
deftrailers(self)->Dict:
339-
"""Get the trailers of the message as dictionary
339+
deftrailers(self)->Dict[str,str]:
340+
"""Get the trailers of the message as a dictionary
341+
342+
:note: This property is deprecated, please use either ``Commit.trailers_list`` or ``Commit.trailers_dict``.
343+
344+
:return:
345+
Dictionary containing whitespace stripped trailer information.
346+
Only contains the latest instance of each trailer key.
347+
"""
348+
return {
349+
k:v[0]fork,vinself.trailers_dict.items()
350+
}
351+
352+
@property
353+
deftrailers_list(self)->List[Tuple[str,str]]:
354+
"""Get the trailers of the message as a list
355+
356+
Git messages can contain trailer information that are similar to RFC 822
357+
e-mail headers (see: https://git-scm.com/docs/git-interpret-trailers).
358+
359+
This functions calls ``git interpret-trailers --parse`` onto the message
360+
to extract the trailer information, returns the raw trailer data as a list.
361+
362+
Valid message with trailer::
363+
364+
Subject line
365+
366+
some body information
367+
368+
another information
369+
370+
key1: value1.1
371+
key1: value1.2
372+
key2 : value 2 with inner spaces
373+
374+
375+
Returned list will look like this::
376+
377+
[
378+
("key1", "value1.1"),
379+
("key1", "value1.2"),
380+
("key2", "value 2 with inner spaces"),
381+
]
382+
383+
384+
:return:
385+
List containing key-value tuples of whitespace stripped trailer information.
386+
"""
387+
cmd= ["git","interpret-trailers","--parse"]
388+
proc:Git.AutoInterrupt=self.repo.git.execute(cmd,as_process=True,istream=PIPE)# type: ignore
389+
trailer:str=proc.communicate(str(self.message).encode())[0].decode("utf8")
390+
trailer=trailer.strip()
391+
392+
ifnottrailer:
393+
return []
394+
395+
trailer_list= []
396+
fortintrailer.split("\n"):
397+
key,val=t.split(":",1)
398+
trailer_list.append((key.strip(),val.strip()))
399+
400+
returntrailer_list
401+
402+
@property
403+
deftrailers_dict(self)->Dict[str,List[str]]:
404+
"""Get the trailers of the message as a dictionary
340405
341406
Git messages can contain trailer information that are similar to RFC 822
342407
e-mail headers (see: https://git-scm.com/docs/git-interpret-trailers).
@@ -345,42 +410,35 @@ def trailers(self) -> Dict:
345410
to extract the trailer information. The key value pairs are stripped of
346411
leading and trailing whitespaces before they get saved into a dictionary.
347412
348-
Valid message with trailer:
349-
350-
.. code-block::
413+
Valid message with trailer::
351414
352415
Subject line
353416
354417
some body information
355418
356419
another information
357420
358-
key1: value1
421+
key1: value1.1
422+
key1: value1.2
359423
key2 : value 2 with inner spaces
360424
361-
dictionary will look like this:
362425
363-
.. code-block::
426+
Returned dictionary will look like this::
364427
365428
{
366-
"key1": "value1",
367-
"key2": "value 2 with inner spaces"
429+
"key1":["value1.1", "value1.2"],
430+
"key2":["value 2 with inner spaces"],
368431
}
369432
370-
:return: Dictionary containing whitespace stripped trailer information
371433
434+
:return:
435+
Dictionary containing whitespace stripped trailer information.
436+
Mapping trailer keys to a list of their corresponding values.
372437
"""
373-
d= {}
374-
cmd= ["git","interpret-trailers","--parse"]
375-
proc:Git.AutoInterrupt=self.repo.git.execute(cmd,as_process=True,istream=PIPE)# type: ignore
376-
trailer:str=proc.communicate(str(self.message).encode())[0].decode()
377-
iftrailer.endswith("\n"):
378-
trailer=trailer[0:-1]
379-
iftrailer!="":
380-
forlineintrailer.split("\n"):
381-
key,value=line.split(":",1)
382-
d[key.strip()]=value.strip()
383-
returnd
438+
d=defaultdict(list)
439+
forkey,valinself.trailers_list:
440+
d[key].append(val)
441+
returndict(d)
384442

385443
@classmethod
386444
def_iter_from_process_or_stream(cls,repo:"Repo",proc_or_stream:Union[Popen,IO])->Iterator["Commit"]:

‎test/test_commit.py

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -494,52 +494,57 @@ def test_datetimes(self):
494494

495495
deftest_trailers(self):
496496
KEY_1="Hello"
497-
VALUE_1="World"
497+
VALUE_1_1="World"
498+
VALUE_1_2="Another-World"
498499
KEY_2="Key"
499500
VALUE_2="Value with inner spaces"
500501

501-
# Check if KEY 1 & 2 with Value 1 & 2 is extracted from multiple msg variations
502-
msgs= []
503-
msgs.append(f"Subject\n\n{KEY_1}:{VALUE_1}\n{KEY_2}:{VALUE_2}\n")
504-
msgs.append(f"Subject\n\nSome body of a function\n\n{KEY_1}:{VALUE_1}\n{KEY_2}:{VALUE_2}\n")
505-
msgs.append(
506-
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"
507-
)
508-
msgs.append(
509-
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"
510-
)
511-
502+
# Check the following trailer example is extracted from multiple msg variations
503+
TRAILER=f"{KEY_1}:{VALUE_1_1}\n{KEY_2}:{VALUE_2}\n{KEY_1}:{VALUE_1_2}"
504+
msgs= [
505+
f"Subject\n\n{TRAILER}\n",
506+
f"Subject\n\nSome body of a function\n\n{TRAILER}\n",
507+
f"Subject\n\nSome body of a function\n\nnon-key: non-value\n\n{TRAILER}\n",
508+
(
509+
# check when trailer has inconsistent whitespace
510+
f"Subject\n\nSome multiline\n body of a function\n\nnon-key: non-value\n\n"
511+
f"{KEY_1}:{VALUE_1_1}\n{KEY_2} :{VALUE_2}\n{KEY_1}:{VALUE_1_2}\n"
512+
),
513+
]
512514
formsginmsgs:
513-
commit=self.rorepo.commit("master")
514-
commit=copy.copy(commit)
515+
commit=copy.copy(self.rorepo.commit("master"))
515516
commit.message=msg
516-
assertKEY_1incommit.trailers.keys()
517-
assertKEY_2incommit.trailers.keys()
518-
assertcommit.trailers[KEY_1]==VALUE_1
519-
assertcommit.trailers[KEY_2]==VALUE_2
520-
521-
# Check that trailer stays empty for multiple msg combinations
522-
msgs= []
523-
msgs.append(f"Subject\n")
524-
msgs.append(f"Subject\n\nBody with some\nText\n")
525-
msgs.append(f"Subject\n\nBody with\nText\n\nContinuation but\n doesn't contain colon\n")
526-
msgs.append(f"Subject\n\nBody with\nText\n\nContinuation but\n only contains one :\n")
527-
msgs.append(f"Subject\n\nBody with\nText\n\nKey: Value\nLine without colon\n")
528-
msgs.append(f"Subject\n\nBody with\nText\n\nLine without colon\nKey: Value\n")
517+
assertcommit.trailers_list== [
518+
(KEY_1,VALUE_1_1),
519+
(KEY_2,VALUE_2),
520+
(KEY_1,VALUE_1_2),
521+
]
522+
assertcommit.trailers_dict== {
523+
KEY_1: [VALUE_1_1,VALUE_1_2],
524+
KEY_2: [VALUE_2],
525+
}
526+
527+
# check that trailer stays empty for multiple msg combinations
528+
msgs= [
529+
f"Subject\n",
530+
f"Subject\n\nBody with some\nText\n",
531+
f"Subject\n\nBody with\nText\n\nContinuation but\n doesn't contain colon\n",
532+
f"Subject\n\nBody with\nText\n\nContinuation but\n only contains one :\n",
533+
f"Subject\n\nBody with\nText\n\nKey: Value\nLine without colon\n",
534+
f"Subject\n\nBody with\nText\n\nLine without colon\nKey: Value\n",
535+
]
529536

530537
formsginmsgs:
531-
commit=self.rorepo.commit("master")
532-
commit=copy.copy(commit)
538+
commit=copy.copy(self.rorepo.commit("master"))
533539
commit.message=msg
534-
assertlen(commit.trailers.keys())==0
540+
assertcommit.trailers_list== []
541+
assertcommit.trailers_dict== {}
535542

536543
# check that only the last key value paragraph is evaluated
537-
commit=self.rorepo.commit("master")
538-
commit=copy.copy(commit)
539-
commit.message=f"Subject\n\nMultiline\nBody\n\n{KEY_1}:{VALUE_1}\n\n{KEY_2}:{VALUE_2}\n"
540-
assertKEY_1notincommit.trailers.keys()
541-
assertKEY_2incommit.trailers.keys()
542-
assertcommit.trailers[KEY_2]==VALUE_2
544+
commit=copy.copy(self.rorepo.commit("master"))
545+
commit.message=f"Subject\n\nMultiline\nBody\n\n{KEY_1}:{VALUE_1_1}\n\n{KEY_2}:{VALUE_2}\n"
546+
assertcommit.trailers_list== [(KEY_2,VALUE_2)]
547+
assertcommit.trailers_dict== {KEY_2: [VALUE_2]}
543548

544549
deftest_commit_co_authors(self):
545550
commit=copy.copy(self.rorepo.commit("4251bd5"))

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp