Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions cherry_picker/cherry_picker.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,24 @@ def remember_previous_branch(self):
current_branch = get_current_branch()
save_cfg_vals_to_git_cfg(previous_branch=current_branch)

def set_remaining_backports(self, branches):
"""Save the remaining backport branches into Git config."""
save_cfg_vals_to_git_cfg(remaining_backport=" ".join(branches))

def get_remaining_backports(self):
"""Get the remaining backport branches from Git config."""
branches = load_val_from_git_cfg("remaining_backport")
if branches is None:
return []
return branches.split()

def pop_remaining_backports(self):
"""Get one of the remaining backport branch and remove it."""
branches = self.get_remaining_backports()
branch = branches.pop(0)
self.set_remaining_backports(branches)
return branch

@property
def upstream(self):
"""Get the remote name to use for upstream branches
Expand Down Expand Up @@ -535,9 +553,13 @@ def backport(self):
set_state(WORKFLOW_STATES.BACKPORT_STARTING)
self.fetch_upstream()
self.remember_previous_branch()
self.set_remaining_backports(self.sorted_branches)
self.process_remaining_backports()

def process_remaining_backports(self):
set_state(WORKFLOW_STATES.BACKPORT_LOOPING)
for maint_branch in self.sorted_branches:
while self.get_remaining_backports():
maint_branch = self.pop_remaining_backports()
set_state(WORKFLOW_STATES.BACKPORT_LOOP_START)
click.echo(f"Now backporting '{self.commit_sha1}' into '{maint_branch}'")

Expand Down Expand Up @@ -577,6 +599,7 @@ def backport(self):
return # to preserve the correct state
set_state(WORKFLOW_STATES.BACKPORT_LOOP_END)
reset_stored_previous_branch()
reset_stored_config_ref()
reset_state()

def abort_cherry_pick(self):
Expand Down Expand Up @@ -669,17 +692,15 @@ def continue_cherry_pick(self):
self.pause_after_committing(cherry_pick_branch)
return # to preserve the correct state

self.process_remaining_backports()

else:
click.echo(
f"Current branch ({cherry_pick_branch}) is not a backport branch. "
"Will not continue. \U0001f61b"
)
set_state(WORKFLOW_STATES.CONTINUATION_FAILED)

reset_stored_previous_branch()
reset_stored_config_ref()
reset_state()

def check_repo(self):
"""
Check that the repository is for the project we're configured to operate on.
Expand Down
54 changes: 53 additions & 1 deletion cherry_picker/test_cherry_picker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1165,6 +1165,58 @@ def test_backport_success(
assert get_state() == WORKFLOW_STATES.UNSET


def test_backport_pause_aud_continue_multiple(
tmp_git_repo_dir, git_branch, git_add, git_commit, git_checkout
):
cherry_pick_target_branches = ("3.8", "3.7", "3.6")
pr_remote = "origin"
upstream_remote = "upstream"
test_file = "some.file"
tmp_git_repo_dir.join(test_file).write("some contents")
for branch in cherry_pick_target_branches:
git_branch(branch)
git_branch(f"{upstream_remote}/{branch}", branch)
git_add(test_file)
git_commit("Add a test file")
scm_revision = get_sha1_from("HEAD")

with mock.patch("cherry_picker.cherry_picker.validate_sha", return_value=True):
cherry_picker = CherryPicker(
pr_remote, scm_revision, cherry_pick_target_branches, push=False
)

cherry_picker._upstream = upstream_remote
with (
mock.patch.object(cherry_picker, "push_to_remote"),
mock.patch.object(cherry_picker, "fetch_upstream"),
mock.patch.object(
cherry_picker, "amend_commit_message", return_value="commit message"
),
):
cherry_picker.backport()

assert get_state() == WORKFLOW_STATES.BACKPORT_PAUSED
assert cherry_picker.get_remaining_backports() == ["3.7", "3.6"]

with mock.patch("cherry_picker.cherry_picker.validate_sha", return_value=True):
cherry_picker = CherryPicker(
pr_remote, scm_revision, cherry_pick_target_branches
)

cherry_picker._upstream = upstream_remote
with (
mock.patch("cherry_picker.cherry_picker.wipe_cfg_vals_from_git_cfg"),
mock.patch.object(cherry_picker, "push_to_remote"),
mock.patch.object(cherry_picker, "fetch_upstream"),
mock.patch.object(
cherry_picker, "amend_commit_message", return_value="commit message"
),
):
cherry_picker.continue_cherry_pick()
assert get_state() == WORKFLOW_STATES.BACKPORT_LOOP_END
assert cherry_picker.get_remaining_backports() == []


@pytest.mark.parametrize("already_committed", (True, False))
@pytest.mark.parametrize("push", (True, False))
def test_backport_pause_and_continue(
Expand Down Expand Up @@ -1255,7 +1307,7 @@ def test_backport_pause_and_continue(
amend_commit_message.assert_not_called()

if push:
assert get_state() == WORKFLOW_STATES.BACKPORTING_CONTINUATION_SUCCEED
assert get_state() == WORKFLOW_STATES.BACKPORT_LOOPING
else:
assert get_state() == WORKFLOW_STATES.BACKPORT_PAUSED

Expand Down
Loading