[stacked_changes] Create cherry-picked commit.

Bug:b/265929888
Change-Id: I4277474c1f09e4ac6ea6ebb5d9d340f22365f542
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/4178924
Reviewed-by: Gavin Mak <gavinmak@google.com>
Reviewed-by: Josip Sokcevic <sokcevic@chromium.org>
Commit-Queue: Joanna Wang <jojwang@chromium.org>
changes/24/4178924/11
Joanna Wang 2 years ago committed by LUCI CQ
parent b46232e729
commit e852391441

@ -999,6 +999,12 @@ _CommentSummary = collections.namedtuple(
'approval', 'disapproval'])
_NewUpload = collections.namedtuple('NewUpload', [
'reviewers', 'ccs', 'commit_to_push', 'new_last_uploaded_commit',
'change_desc'
])
class Changelist(object):
"""Changelist works with one changelist in local branch.
@ -1569,6 +1575,41 @@ class Changelist(object):
return title
return user_title or title
def PrepareCherryPickSquashedCommit(self, options):
# type: (optparse.Values) -> _NewUpload()
"""Create a commit cherry-picked on parent to push."""
parent = self.GetCommonAncestorWithUpstream()
reviewers, ccs, change_desc = self._PrepareChange(options, parent,
self.branchref)
new_upload_hash = RunGit(['rev-parse', self.branchref]).strip()
latest_tree = RunGit(['rev-parse', self.branchref + ':']).strip()
with gclient_utils.temporary_file() as desc_tempfile:
gclient_utils.FileWrite(desc_tempfile, change_desc.description)
commit_to_cp = RunGit(
['commit-tree', latest_tree, '-p', parent, '-F',
desc_tempfile]).strip()
_, upstream_branch_ref = self.FetchUpstreamTuple(self.GetBranch())
upstream_branch = scm.GIT.ShortBranchName(upstream_branch_ref)
upstream_squashed_upload = scm.GIT.GetBranchConfig(
settings.GetRoot(), upstream_branch, GERRIT_SQUASH_HASH_CONFIG_KEY)
RunGit(['checkout', '-q', upstream_squashed_upload])
ret, _out = RunGitWithCode(['cherry-pick', commit_to_cp])
if ret:
RunGit(['cherry-pick', '--abort'])
RunGit(['checkout', '-q', self.branch])
DieWithError('Could not cleanly cherry-pick')
commit_to_push = RunGit(['rev-parse', 'HEAD'])
RunGit(['checkout', '-q', self.branch])
return _NewUpload(reviewers, ccs, commit_to_push, new_upload_hash,
change_desc)
def _PrepareChange(self, options, parent, end_commit):
# type: (optparse.Values, str, str) ->
# Tuple[Sequence[str], Sequence[str], ChangeDescription]

@ -3210,8 +3210,12 @@ class ChangelistTest(unittest.TestCase):
mock.patch('subprocess2.Popen').start()
mock.patch(
'git_cl.Changelist.GetGerritProject', return_value='project').start()
mock.patch('sys.exit', side_effect=SystemExitMock).start()
self.addCleanup(mock.patch.stopall)
self.temp_count = 0
self.mockGit = GitMocks()
mock.patch('scm.GIT.GetConfig', self.mockGit.GetConfig).start()
def testRunHook(self):
expected_results = {
@ -3555,6 +3559,79 @@ class ChangelistTest(unittest.TestCase):
for user_title in ['not empty', 'yes', 'YES']:
self.assertEqual(cl._GetTitleForUpload(options), user_title)
@mock.patch('git_cl.Settings.GetRoot', return_value='')
@mock.patch('git_cl.Changelist.FetchUpstreamTuple')
@mock.patch('git_cl.RunGitWithCode')
@mock.patch('git_cl.RunGit')
@mock.patch('git_cl.Changelist._PrepareChange')
@mock.patch('git_cl.Changelist.GetCommonAncestorWithUpstream')
def testPrepareCherryPickSquashedCommit(self,
mockGetCommonAncestorWithUpstream,
mockPrepareChange, mockRunGit,
mockRunGitWithCode,
mockFetchUpstreamTuple, *_mocks):
parent_hash = '1a2bparentcommit'
mockGetCommonAncestorWithUpstream.return_value = parent_hash
change_desc = git_cl.ChangeDescription('BOO!')
ccs = ['cc@review.cl']
reviewers = ['reviewer@review.cl']
mockPrepareChange.return_value = (reviewers, ccs, change_desc)
branchref = 'refs/heads/current-branch'
cl = git_cl.Changelist(branchref=branchref)
options = optparse.Values()
mockFetchUpstreamTuple.return_value = ('', 'refs/heads/upstream')
upstream_gerrit_hash = 'upstream-gerrit-hash'
self.mockGit.config['branch.upstream.%s' %
git_cl.GERRIT_SQUASH_HASH_CONFIG_KEY] = (
upstream_gerrit_hash)
latest_tree_hash = 'tree-hash'
hash_to_cp = 'squashed-hash'
hash_to_push = 'hash-to-push'
hash_to_save_as_last_upload = 'last-upload'
def mock_run_git(commands):
if commands == ['rev-parse', branchref]:
return hash_to_save_as_last_upload
if commands == ['rev-parse', branchref + ':']:
return latest_tree_hash
if {'commit-tree', latest_tree_hash, '-p', parent_hash,
'-F'}.issubset(set(commands)):
return hash_to_cp
if commands == ['rev-parse', 'HEAD']:
return hash_to_push
mockRunGit.side_effect = mock_run_git
def mock_run_git_with_code(commands):
if commands == ['cherry-pick', hash_to_cp]:
return 0, ''
mockRunGitWithCode.side_effect = mock_run_git_with_code
new_upload = cl.PrepareCherryPickSquashedCommit(options)
self.assertEqual(new_upload.reviewers, reviewers)
self.assertEqual(new_upload.ccs, ccs)
self.assertEqual(new_upload.commit_to_push, hash_to_push)
self.assertEqual(new_upload.new_last_uploaded_commit,
hash_to_save_as_last_upload)
self.assertEqual(new_upload.change_desc, change_desc)
# Test failed cherry-pick
def mock_run_git_with_code(commands):
if commands == ['cherry-pick', hash_to_cp]:
return 1, ''
mockRunGitWithCode.side_effect = mock_run_git_with_code
with self.assertRaises(SystemExitMock):
cl.PrepareCherryPickSquashedCommit(options)
@mock.patch('git_cl.Changelist.GetAffectedFiles', return_value=[])
@mock.patch('git_cl.GenerateGerritChangeId', return_value='1a2b3c')
@mock.patch('git_cl.Changelist.GetIssue', return_value=None)

Loading…
Cancel
Save