Skip to content

Commit 766f76c

Browse files
authored
Respect existing trailers (including co-author lines) when backporting (#46)
1 parent b1647e8 commit 766f76c

2 files changed

Lines changed: 128 additions & 4 deletions

File tree

cherry_picker/cherry_picker.py

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -317,14 +317,48 @@ def get_exit_message(self, branch):
317317
"""
318318

319319
def get_updated_commit_message(self, cherry_pick_branch):
320+
"""
321+
Get updated commit message for the cherry-picked commit.
322+
"""
323+
# Get the original commit message and prefix it with the branch name
324+
# if that's enabled.
320325
commit_prefix = ""
321326
if self.prefix_commit:
322327
commit_prefix = f"[{get_base_branch(cherry_pick_branch)}] "
323-
return f"""{commit_prefix}{self.get_commit_message(self.commit_sha1)}
324-
(cherry picked from commit {self.commit_sha1})
328+
updated_commit_message = f"{commit_prefix}{self.get_commit_message(self.commit_sha1)}"
329+
330+
# Add '(cherry picked from commit ...)' to the message
331+
# and add new Co-authored-by trailer if necessary.
332+
cherry_pick_information = f"(cherry picked from commit {self.commit_sha1})\n:"
333+
# Here, we're inserting new Co-authored-by trailer and we *somewhat*
334+
# abuse interpret-trailers by also adding cherry_pick_information which
335+
# is not an actual trailer.
336+
# `--where start` makes it so we insert new trailers *before* the existing
337+
# trailers so cherry-pick information gets added before any of the trailers
338+
# which prevents us from breaking the trailers.
339+
cmd = [
340+
"git",
341+
"interpret-trailers",
342+
"--where",
343+
"start",
344+
"--trailer",
345+
f"Co-authored-by: {get_author_info_from_short_sha(self.commit_sha1)}",
346+
"--trailer",
347+
cherry_pick_information,
348+
]
349+
output = subprocess.check_output(cmd, input=updated_commit_message.encode())
350+
# Replace the right most-occurence of the "cherry picked from commit" string.
351+
#
352+
# This needs to be done because `git interpret-trailers` required us to add `:`
353+
# to `cherry_pick_information` when we don't actually want it.
354+
before, after = output.strip().decode().rsplit(f"\n{cherry_pick_information}", 1)
355+
if not before.endswith("\n"):
356+
# ensure that we still have a newline between cherry pick information
357+
# and commit headline
358+
cherry_pick_information = f"\n{cherry_pick_information}"
359+
updated_commit_message = cherry_pick_information[:-1].join((before, after))
325360

326-
327-
Co-authored-by: {get_author_info_from_short_sha(self.commit_sha1)}"""
361+
return updated_commit_message
328362

329363
def amend_commit_message(self, cherry_pick_branch):
330364
""" prefix the commit message with (X.Y) """

cherry_picker/test_cherry_picker.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,96 @@ def test_normalize_short_commit_message():
538538
)
539539

540540

541+
@pytest.mark.parametrize(
542+
"commit_message,expected_commit_message",
543+
(
544+
# ensure existing co-author is retained
545+
(
546+
"""Fix broken `Show Source` links on documentation pages (GH-3113)
547+
548+
Co-authored-by: PR Co-Author <another@author.com>""",
549+
"""[3.6] Fix broken `Show Source` links on documentation pages (GH-3113)
550+
(cherry picked from commit b9ff498793611d1c6a9b99df464812931a1e2d69)
551+
552+
Co-authored-by: PR Author <author@name.email>
553+
Co-authored-by: PR Co-Author <another@author.com>""",
554+
),
555+
# ensure co-author trailer is not duplicated
556+
(
557+
"""Fix broken `Show Source` links on documentation pages (GH-3113)
558+
559+
Co-authored-by: PR Author <author@name.email>""",
560+
"""[3.6] Fix broken `Show Source` links on documentation pages (GH-3113)
561+
(cherry picked from commit b9ff498793611d1c6a9b99df464812931a1e2d69)
562+
563+
Co-authored-by: PR Author <author@name.email>""",
564+
),
565+
# ensure message is formatted properly when original commit is short
566+
(
567+
"Fix broken `Show Source` links on documentation pages (GH-3113)",
568+
"""[3.6] Fix broken `Show Source` links on documentation pages (GH-3113)
569+
(cherry picked from commit b9ff498793611d1c6a9b99df464812931a1e2d69)
570+
571+
Co-authored-by: PR Author <author@name.email>""",
572+
),
573+
# ensure message is formatted properly when original commit is long
574+
(
575+
"""Fix broken `Show Source` links on documentation pages (GH-3113)
576+
577+
The `Show Source` was broken because of a change made in sphinx 1.5.1
578+
In Sphinx 1.4.9, the sourcename was "index.txt".
579+
In Sphinx 1.5.1+, it is now "index.rst.txt".""",
580+
"""[3.6] Fix broken `Show Source` links on documentation pages (GH-3113)
581+
582+
The `Show Source` was broken because of a change made in sphinx 1.5.1
583+
In Sphinx 1.4.9, the sourcename was "index.txt".
584+
In Sphinx 1.5.1+, it is now "index.rst.txt".
585+
(cherry picked from commit b9ff498793611d1c6a9b99df464812931a1e2d69)
586+
587+
Co-authored-by: PR Author <author@name.email>""",
588+
),
589+
# ensure message is formatted properly when original commit is long
590+
# and it has a co-author
591+
(
592+
"""Fix broken `Show Source` links on documentation pages (GH-3113)
593+
594+
The `Show Source` was broken because of a change made in sphinx 1.5.1
595+
In Sphinx 1.4.9, the sourcename was "index.txt".
596+
In Sphinx 1.5.1+, it is now "index.rst.txt".
597+
598+
Co-authored-by: PR Co-Author <another@author.com>""",
599+
"""[3.6] Fix broken `Show Source` links on documentation pages (GH-3113)
600+
601+
The `Show Source` was broken because of a change made in sphinx 1.5.1
602+
In Sphinx 1.4.9, the sourcename was "index.txt".
603+
In Sphinx 1.5.1+, it is now "index.rst.txt".
604+
(cherry picked from commit b9ff498793611d1c6a9b99df464812931a1e2d69)
605+
606+
Co-authored-by: PR Author <author@name.email>
607+
Co-authored-by: PR Co-Author <another@author.com>""",
608+
),
609+
),
610+
)
611+
def test_get_updated_commit_message_with_trailers(commit_message, expected_commit_message):
612+
cherry_pick_branch = "backport-22a594a-3.6"
613+
commit = "b9ff498793611d1c6a9b99df464812931a1e2d69"
614+
615+
with mock.patch("cherry_picker.cherry_picker.validate_sha", return_value=True):
616+
cherry_picker = CherryPicker("origin", commit, [])
617+
618+
with mock.patch(
619+
"cherry_picker.cherry_picker.validate_sha", return_value=True
620+
), mock.patch.object(
621+
cherry_picker, "get_commit_message", return_value=commit_message
622+
), mock.patch(
623+
"cherry_picker.cherry_picker.get_author_info_from_short_sha",
624+
return_value="PR Author <author@name.email>",
625+
):
626+
updated_commit_message = cherry_picker.get_updated_commit_message(cherry_pick_branch)
627+
628+
assert updated_commit_message == expected_commit_message
629+
630+
541631
@pytest.mark.parametrize(
542632
"input_path", ("/some/path/without/revision", "HEAD:some/non-existent/path")
543633
)

0 commit comments

Comments
 (0)