stacked-changes: Skip empty branches.

Changes:
- _UploadAllPrecheck() returns a list of cls to upload that skips any empty commits in the stack.
- If the current branch is empty, we throw an error.
- UploadAllSquashed() now computes the parent to use for the squashed and cherry-pick flow.
  - for cherry-pick it uses the gerrit_squash_hash of the next cl in `cls`. This means it could be the gerrit_squash_hash of the direct ancestor OR the closest non-empty ancestor branch.
  - for multiple squashed commits, the first parent passed in is either:
     - the closest ancestor with a gerrit_squash_hash OR the common ancestor shared with the root of the tree.
- PrepareSquashedCommit() and PrepareCherryPick() now both require a parent passed in.

Bug:1411878, b/265929888
Change-Id: I7dba289defb40ed0464eabdb7e90810353ef155f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/4220412
Reviewed-by: Josip Sokcevic <sokcevic@chromium.org>
Commit-Queue: Joanna Wang <jojwang@chromium.org>
Reviewed-by: Gavin Mak <gavinmak@google.com>
changes/12/4220412/13
Joanna Wang 3 years ago committed by LUCI CQ
parent 2c90793139
commit 6215dd0365

@ -1001,6 +1001,7 @@ _CommentSummary = collections.namedtuple(
'approval', 'disapproval'])
# TODO(b/265929888): Change `parent` to `pushed_commit_base`.
_NewUpload = collections.namedtuple('NewUpload', [
'reviewers', 'ccs', 'commit_to_push', 'new_last_uploaded_commit', 'parent',
'change_desc'
@ -1673,23 +1674,9 @@ class Changelist(object):
# branch/change.
return refspec_opts
def PrepareSquashedCommit(self, options, parent=None, end_commit=None):
# type: (optparse.Values, Optional[str], Optional[str]) -> _NewUpload()
def PrepareSquashedCommit(self, options, parent, end_commit=None):
# type: (optparse.Values, str, Optional[str]) -> _NewUpload()
"""Create a squashed commit to upload."""
if parent is None:
origin, upstream_branch_ref = self.FetchUpstreamTuple(self.GetBranch())
upstream_branch = scm.GIT.ShortBranchName(upstream_branch_ref)
if origin == '.':
# upstream is another local branch.
# Assume we want to upload from upstream's last upload.
parent = scm.GIT.GetBranchConfig(settings.GetRoot(), upstream_branch,
GERRIT_SQUASH_HASH_CONFIG_KEY)
assert parent, ('upstream branch %s not configured correctly. '
'Could not fetch latest gerrit upload from git '
'config.')
else:
# upstream is the root of the tree.
parent = self.GetCommonAncestorWithUpstream()
if end_commit is None:
end_commit = RunGit(['rev-parse', self.branchref]).strip()
@ -1706,40 +1693,38 @@ class Changelist(object):
return _NewUpload(reviewers, ccs, commit_to_push, end_commit, parent,
change_desc)
def PrepareCherryPickSquashedCommit(self, options):
# type: (optparse.Values) -> _NewUpload()
def PrepareCherryPickSquashedCommit(self, options, parent):
# type: (optparse.Values, str) -> _NewUpload()
"""Create a commit cherry-picked on parent to push."""
parent = self.GetCommonAncestorWithUpstream()
reviewers, ccs, change_desc = self._PrepareChange(options, parent,
# The `parent` is what we will cherry-pick on top of.
# The `cherry_pick_base` is the beginning range of what
# we are cherry-picking.
cherry_pick_base = self.GetCommonAncestorWithUpstream()
reviewers, ccs, change_desc = self._PrepareChange(options, cherry_pick_base,
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()
commit_to_cp = RunGit([
'commit-tree', latest_tree, '-p', cherry_pick_base, '-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])
RunGit(['checkout', '-q', parent])
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'])
commit_to_push = RunGit(['rev-parse', 'HEAD']).strip()
RunGit(['checkout', '-q', self.branch])
return _NewUpload(reviewers, ccs, commit_to_push, new_upload_hash, parent,
change_desc)
return _NewUpload(reviewers, ccs, commit_to_push, new_upload_hash,
cherry_pick_base, change_desc)
def _PrepareChange(self, options, parent, end_commit):
# type: (optparse.Values, str, str) ->
@ -4836,9 +4821,28 @@ def UploadAllSquashed(options, orig_args):
new_upload = cls[0].PrepareCherryPickSquashedCommit(options, parent)
uploads_by_cl.append((cls[0], new_upload))
else:
parent = None
ordered_cls = list(reversed(cls))
parent = None
origin = '.'
cl = ordered_cls[0]
branch = cl.GetBranch()
while origin == '.':
# Search for cl's closest ancestor with a gerrit hash.
origin, upstream_branch_ref = Changelist.FetchUpstreamTuple(branch)
if origin == '.':
upstream_branch = scm.GIT.ShortBranchName(upstream_branch_ref)
parent = scm.GIT.GetBranchConfig(settings.GetRoot(), upstream_branch,
GERRIT_SQUASH_HASH_CONFIG_KEY)
if parent:
break
branch = upstream_branch
else:
# Either the root of the tree is the cl's direct parent and the while
# loop above only found empty branches between cl and the root of the
# tree.
parent = cl.GetCommonAncestorWithUpstream()
for i, cl in enumerate(ordered_cls):
# If we're in the middle of the stack, set end_commit to downstream's
# direct ancestor.
@ -4847,10 +4851,9 @@ def UploadAllSquashed(options, orig_args):
else:
child_base_commit = None
new_upload = cl.PrepareSquashedCommit(options,
parent=parent,
parent,
end_commit=child_base_commit)
uploads_by_cl.append((cl, new_upload))
parent = new_upload.commit_to_push
# Create refspec options
@ -4908,6 +4911,7 @@ def _UploadAllPrecheck(options, orig_args):
branch_ref = None
cls = []
must_upload_upstream = False
first_pass = True
Changelist._GerritCommitMsgHookCheck(offer_removal=not options.force)
@ -4920,28 +4924,42 @@ def _UploadAllPrecheck(options, orig_args):
(_MAX_STACKED_BRANCHES_UPLOAD))
cl = Changelist(branchref=branch_ref)
cls.append(cl)
# Only add CL if it has anything to commit.
base_commit = cl.GetCommonAncestorWithUpstream()
end_commit = RunGit(['rev-parse', cl.GetBranchRef()]).strip()
diff = RunGitSilent(['diff', '%s..%s' % (base_commit, end_commit)])
if diff:
cls.append(cl)
if (not first_pass and
cl._GitGetBranchConfigValue(GERRIT_SQUASH_HASH_CONFIG_KEY) is None):
# We are mid-stack and the user must upload their upstream branches.
must_upload_upstream = True
elif first_pass: # The current branch has nothing to commit. Exit.
DieWithError('Branch %s has nothing to commit' % cl.GetBranch())
# Else: A mid-stack branch has nothing to commit. We do not add it to cls.
first_pass = False
# Cases below determine if we should continue to traverse up the tree.
origin, upstream_branch_ref = Changelist.FetchUpstreamTuple(cl.GetBranch())
upstream_branch = scm.GIT.ShortBranchName(upstream_branch_ref)
branch_ref = upstream_branch_ref # set branch for next run.
# Case 1: We've reached the beginning of the tree.
if origin != '.':
break
upstream_branch = scm.GIT.ShortBranchName(upstream_branch_ref)
upstream_last_upload = scm.GIT.GetBranchConfig(settings.GetRoot(),
upstream_branch,
LAST_UPLOAD_HASH_CONFIG_KEY)
# Case 1: We've reached the beginning of the tree.
if origin != '.':
break
# Case 2: If any upstream branches have never been uploaded,
# the user MUST upload them.
# the user MUST upload them unless they are empty. Continue to
# next loop to add upstream if it is not empty.
if not upstream_last_upload:
must_upload_upstream = True
continue
base_commit = cl.GetCommonAncestorWithUpstream()
# Case 3: If upstream's last_upload == cl.base_commit we do
# not need to upload any more upstreams from this point on.
# (Even if there may be diverged branches higher up the tree)
@ -4973,17 +4991,18 @@ def _UploadAllPrecheck(options, orig_args):
cherry_pick = False
if len(cls) > 1:
message = ''
branches = ', '.join([cl.branch for cl in cls])
if len(orig_args):
message = ('options %s will be used for all uploads.\n' % orig_args)
if must_upload_upstream:
confirm_or_exit('\n' + message +
'There are upstream branches that must be uploaded.\n')
'Branches `%s` must be uploaded.\n' % branches)
else:
answer = gclient_utils.AskForData(
'\n' + message +
'Press enter to update branches %s.\nOr type `n` to upload only '
'`%s` cherry-picked on %s\'s last upload:' %
([cl.branch for cl in cls], cls[0].branch, cls[1].branch))
(branches, cls[0].branch, cls[1].branch))
if answer.lower() == 'n':
cherry_pick = True
return cls, cherry_pick

@ -1584,8 +1584,9 @@ class TestGitCl(unittest.TestCase):
return_value='chromium-review.googlesource.com')
@mock.patch('git_cl.Changelist.GetRemoteBranch',
return_value=('origin', 'refs/remotes/origin/main'))
@mock.patch('git_cl.Changelist.GetCommonAncestorWithUpstream',
return_value='current-upstream-ancestor')
@mock.patch(
'git_cl.Changelist.GetCommonAncestorWithUpstream',
side_effect=['current-upstream-ancestor', 'next-upstream-ancestor'])
@mock.patch('git_cl.Changelist.PostUploadUpdates')
@mock.patch('git_cl.Changelist._RunGitPushWithTraces')
@mock.patch('git_cl._UploadAllPrecheck')
@ -1608,7 +1609,7 @@ class TestGitCl(unittest.TestCase):
new_upload_current = git_cl._NewUpload(reviewers, ccs,
current_commit_to_push,
current_new_last_upload,
'current-upstream-ancestor',
'next-upstream-ancestor',
change_desc)
upstream_desc = git_cl.ChangeDescription('kwak')
@ -1647,8 +1648,10 @@ class TestGitCl(unittest.TestCase):
# Asserts
self.assertEqual(mockSquashedCommit.mock_calls, [
mock.call(options, parent=None, end_commit='current-upstream-ancestor'),
mock.call(options, parent=upstream_commit_to_push, end_commit=None)
mock.call(options,
'current-upstream-ancestor',
end_commit='next-upstream-ancestor'),
mock.call(options, upstream_commit_to_push, end_commit=None)
])
expected_refspec = ('commit-to-push:refs/for/refs/heads/main%notify=NONE,'
@ -1669,28 +1672,56 @@ class TestGitCl(unittest.TestCase):
@mock.patch(
'git_cl.Changelist._GerritCommitMsgHookCheck', lambda offer_removal: None)
@mock.patch('git_cl.RunGit')
@mock.patch('git_cl.RunGitSilent')
@mock.patch('git_cl.Changelist._GitGetBranchConfigValue')
@mock.patch('git_cl.Changelist.FetchUpstreamTuple')
@mock.patch('git_cl.Changelist.GetCommonAncestorWithUpstream')
@mock.patch('git_cl.Changelist.GetBranch')
@mock.patch('scm.GIT.GetBranchRef')
@mock.patch('git_cl.Changelist.GetRemoteBranch')
@mock.patch('scm.GIT.IsAncestor')
@mock.patch('gclient_utils.AskForData')
def test_upload_all_precheck_long_chain(self, mockAskForData, mockIsAncestor,
mockGetRemoteBranch, mockGetBranch,
mockGetCommonAncestorWithUpstream,
mockFetchUpstreamTuple, *_mocks):
def test_upload_all_precheck_long_chain(
self, mockAskForData, mockIsAncestor, mockGetRemoteBranch,
mockGetBranchRef, mockGetCommonAncestorWithUpstream,
mockFetchUpstreamTuple, mockGitGetBranchConfigValue, mockRunGitSilent,
mockRunGit, *_mocks):
mockGetRemoteBranch.return_value = ('origin', 'refs/remotes/origin/main')
mockGetBranch.side_effect = [
'current', 'upstream3', 'upstream2', 'upstream1', 'main'
branches = [
'current', 'upstream3', 'blank3', 'blank2', 'upstream2', 'blank1',
'upstream1', 'origin/main'
]
mockGetBranchRef.side_effect = ['refs/heads/%s' % b for b in branches]
mockGetCommonAncestorWithUpstream.side_effect = [
'commit3.5', 'commit2.5', 'commit1.5', 'commit0.5'
'commit3.5',
'commit3.5',
'commit3.5',
'commit2.5',
'commit1.5',
'commit1.5',
'commit0.5',
]
mockFetchUpstreamTuple.side_effect = [('.', 'refs/heads/upstream3'),
('.', 'refs/heads/blank3'),
('.', 'refs/heads/blank2'),
('.', 'refs/heads/upstream2'),
('.', 'refs/heads/blank1'),
('.', 'refs/heads/upstream1'),
('origin', 'refs/heads/main')]
('origin', 'refs/heads/origin/main')]
# end commits
mockRunGit.side_effect = [
'commit4', 'commit3.5', 'commit3.5', 'commit2', 'commit1.5', 'commit1',
'commit0.5'
]
mockRunGitSilent.side_effect = [
'diff', 'diff', None, None, 'diff', None, 'diff'
]
# Get gerrit squash hash. We only check this for branches that have a diff.
# Set to None to trigger `must_upload_upstream`.
mockGitGetBranchConfigValue.return_value = None
options = optparse.Values()
options.force = False
@ -1700,7 +1731,7 @@ class TestGitCl(unittest.TestCase):
# (so no LAST_UPLOAD_HASH_CONIFG_KEY)
# Case 4: upstream2's last_upload is behind upstream3's base_commit
self.mockGit.config['branch.upstream1.%s' %
self.mockGit.config['branch.upstream2.%s' %
git_cl.LAST_UPLOAD_HASH_CONFIG_KEY] = 'commit2.3'
mockIsAncestor.side_effect = [True]
@ -1712,64 +1743,73 @@ class TestGitCl(unittest.TestCase):
self.assertFalse(cherry_pick)
mockAskForData.assert_called_once_with(
"\noptions ['--preserve-tryjobs', '--chicken'] will be used for all "
"uploads.\nThere are upstream branches that must be uploaded.\n"
"uploads.\nBranches `current, upstream3, upstream2` must be uploaded.\n"
"Press Enter to confirm, or Ctrl+C to abort")
self.assertEqual(len(cls), 4)
self.assertEqual(len(cls), 3)
@mock.patch(
'git_cl.Changelist._GerritCommitMsgHookCheck', lambda offer_removal: None)
@mock.patch('git_cl.RunGit')
@mock.patch('git_cl.RunGitSilent')
@mock.patch('git_cl.Changelist._GitGetBranchConfigValue')
@mock.patch('git_cl.Changelist.FetchUpstreamTuple')
@mock.patch('git_cl.Changelist.GetCommonAncestorWithUpstream')
@mock.patch('git_cl.Changelist.GetBranch')
@mock.patch('git_cl.Changelist.GetRemoteBranch')
@mock.patch('scm.GIT.GetBranchRef')
@mock.patch('scm.GIT.IsAncestor')
@mock.patch('gclient_utils.AskForData')
def test_upload_all_precheck_must_rebase(self, mockAskForData, mockIsAncestor,
mockGetRemoteBranch, mockGetBranch,
mockGetCommonAncestorWithUpstream,
mockFetchUpstreamTuple, *_mocks):
def test_upload_all_precheck_must_rebase(
self, mockAskForData, mockIsAncestor, mockGetBranchRef,
mockGetCommonAncestorWithUpstream, mockFetchUpstreamTuple,
mockGitGetBranchConfigValue, mockRunGitSilent, mockRunGit, *_mocks):
branches = ['current', 'upstream3']
mockGetBranchRef.side_effect = ['refs/heads/%s' % b for b in branches]
mockGetCommonAncestorWithUpstream.return_value = 'commit3.5'
options = optparse.Values()
options.force = False
orig_args = ['--preserve-tryjobs', '--chicken']
mockFetchUpstreamTuple.return_value = ('.', 'refs/heads/upstream3')
# end commits
mockRunGit.return_value = 'commit4'
mockRunGitSilent.return_value = 'diff'
# Get gerrit squash hash. We only check this for branches that have a diff.
# Set to None to trigger `must_upload_upstream`.
mockGitGetBranchConfigValue.return_value = None
mockGetRemoteBranch.return_value = ('origin', 'refs/remotes/origin/main')
mockGetBranch.side_effect = [
'current', 'upstream3', 'upstream2', 'upstream1', 'main'
]
mockGetCommonAncestorWithUpstream.side_effect = [
'commit3.5', 'commit2.5', 'commit1.5', 'commit0.5'
]
mockFetchUpstreamTuple.side_effect = [('.', 'refs/heads/upstream3'),
('.', 'refs/heads/upstream2'),
('.', 'refs/heads/upstream1'),
('origin', 'refs/heads/main')]
# Case 5: current's base_commit is behind upstream3's last_upload.
self.mockGit.config['branch.upstream3.%s' %
git_cl.LAST_UPLOAD_HASH_CONFIG_KEY] = 'commit3.7'
mockIsAncestor.side_effect = [False, True]
with self.assertRaises(SystemExitMock):
git_cl._UploadAllPrecheck(options, orig_args)
options = optparse.Values()
options.force = False
git_cl._UploadAllPrecheck(options, [])
@mock.patch(
'git_cl.Changelist._GerritCommitMsgHookCheck', lambda offer_removal: None)
@mock.patch('git_cl.RunGit')
@mock.patch('git_cl.RunGitSilent')
@mock.patch('git_cl.Changelist._GitGetBranchConfigValue')
@mock.patch('git_cl.Changelist.FetchUpstreamTuple')
@mock.patch('git_cl.Changelist.GetCommonAncestorWithUpstream')
@mock.patch('git_cl.Changelist.GetBranch')
@mock.patch('scm.GIT.GetBranchRef')
@mock.patch('git_cl.Changelist.GetRemoteBranch')
@mock.patch('scm.GIT.IsAncestor')
@mock.patch('gclient_utils.AskForData')
def test_upload_all_precheck_hit_main(self, mockAskForData, mockIsAncestor,
mockGetRemoteBranch, mockGetBranch,
mockGetRemoteBranch, mockGetBranchRef,
mockGetCommonAncestorWithUpstream,
mockFetchUpstreamTuple, *_mocks):
mockFetchUpstreamTuple,
mockGitGetBranchConfigValue,
mockRunGitSilent, mockRunGit, *_mocks):
options = optparse.Values()
options.force = False
orig_args = ['--preserve-tryjobs', '--chicken']
mockGetRemoteBranch.return_value = ('origin', 'refs/remotes/origin/main')
mockGetBranch.return_value = ['current', 'upstream3', 'main']
branches = ['current', 'upstream3', 'main']
mockGetBranchRef.side_effect = ['refs/heads/%s' % b for b in branches]
mockGetCommonAncestorWithUpstream.side_effect = ['commit3.5', 'commit0.5']
mockFetchUpstreamTuple.side_effect = [('.', 'refs/heads/upstream3'),
('origin', 'refs/heads/main')]
@ -1782,6 +1822,14 @@ class TestGitCl(unittest.TestCase):
self.mockGit.config['branch.upstream3.%s' %
git_cl.LAST_UPLOAD_HASH_CONFIG_KEY] = 'commit3.4'
# end commits
mockRunGit.side_effect = ['commit4', 'commit3']
mockRunGitSilent.side_effect = ['diff', 'diff']
# Get gerrit squash hash. We only check this for branches that have a diff.
mockGitGetBranchConfigValue.return_value = 'just needs to exist'
# Case 1: We hit the main branch
cls, cherry_pick = git_cl._UploadAllPrecheck(options, orig_args)
self.assertTrue(cherry_pick)
@ -1790,33 +1838,45 @@ class TestGitCl(unittest.TestCase):
mockAskForData.assert_called_once_with(
"\noptions ['--preserve-tryjobs', '--chicken'] will be used for all "
"uploads.\n"
"Press enter to update branches [None, 'upstream3'].\n"
"Or type `n` to upload only `None` cherry-picked on upstream3's last "
"upload:")
"Press enter to update branches current, upstream3.\n"
"Or type `n` to upload only `current` cherry-picked on upstream3's "
"last upload:")
@mock.patch(
'git_cl.Changelist._GerritCommitMsgHookCheck', lambda offer_removal: None)
@mock.patch('git_cl.RunGit')
@mock.patch('git_cl.RunGitSilent')
@mock.patch('git_cl.Changelist._GitGetBranchConfigValue')
@mock.patch('git_cl.Changelist.FetchUpstreamTuple')
@mock.patch('git_cl.Changelist.GetCommonAncestorWithUpstream')
@mock.patch('git_cl.Changelist.GetBranch')
@mock.patch('scm.GIT.GetBranchRef')
@mock.patch('git_cl.Changelist.GetRemoteBranch')
@mock.patch('scm.GIT.IsAncestor')
@mock.patch('gclient_utils.AskForData')
def test_upload_all_precheck_one_change(self, mockAskForData, mockIsAncestor,
mockGetRemoteBranch, mockGetBranch,
mockGetCommonAncestorWithUpstream,
mockFetchUpstreamTuple, *_mocks):
def test_upload_all_precheck_one_change(
self, mockAskForData, mockIsAncestor, mockGetRemoteBranch,
mockGetBranchRef, mockGetCommonAncestorWithUpstream,
mockFetchUpstreamTuple, mockGitGetBranchConfigValue, mockRunGitSilent,
mockRunGit, *_mocks):
options = optparse.Values()
options.force = False
orig_args = ['--preserve-tryjobs', '--chicken']
mockGetRemoteBranch.return_value = ('origin', 'refs/remotes/origin/main')
mockGetBranch.return_value = ['current', 'main']
mockGetCommonAncestorWithUpstream.side_effect = ['commit3.5']
mockFetchUpstreamTuple.side_effect = [('', 'refs/heads/main')]
mockGetBranchRef.side_effect = ['refs/heads/current', 'refs/heads/main']
mockGetCommonAncestorWithUpstream.return_value = 'commit3.5'
mockFetchUpstreamTuple.return_value = ('', 'refs/heads/main')
mockIsAncestor.return_value = True
# end commits
mockRunGit.return_value = 'commit4'
mockRunGitSilent.return_value = 'diff'
# Get gerrit squash hash. We only check this for branches that have a diff.
# Set to None to trigger `must_upload_upstream`.
mockGitGetBranchConfigValue.return_value = 'does not matter'
# Case 1: We hit the main branch
cls, cherry_pick = git_cl._UploadAllPrecheck(options, orig_args)
self.assertFalse(cherry_pick)
@ -1824,6 +1884,11 @@ class TestGitCl(unittest.TestCase):
mockAskForData.assert_not_called()
# No diff for current change
mockRunGitSilent.return_value = ''
with self.assertRaises(SystemExitMock):
git_cl._UploadAllPrecheck(options, orig_args)
@mock.patch('git_cl.RunGit')
@mock.patch('git_cl.CMDupload')
@mock.patch('sys.stdin', StringIO('\n'))
@ -3713,14 +3778,9 @@ 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.RunGit')
@mock.patch('git_cl.Changelist._PrepareChange')
@mock.patch('git_cl.Changelist.GetCommonAncestorWithUpstream')
@mock.patch('git_cl.Changelist.FetchUpstreamTuple')
def testPrepareSquashedCommit(self, mockFetchUpstreamTuple,
mockGetCommonAncestorWithUpstream,
mockPrepareChange, mockRunGit, *_mocks):
def testPrepareSquashedCommit(self, mockPrepareChange, mockRunGit):
change_desc = git_cl.ChangeDescription('BOO!')
reviewers = []
@ -3751,12 +3811,7 @@ class ChangelistTest(unittest.TestCase):
cl = git_cl.Changelist(branchref=branchref)
options = optparse.Values()
# local origin
mockFetchUpstreamTuple.return_value = ('.', 'refs/heads/upstreamA')
self.mockGit.config['branch.upstreamA.%s' %
git_cl.GERRIT_SQUASH_HASH_CONFIG_KEY] = (parent_hash)
new_upload = cl.PrepareSquashedCommit(options)
new_upload = cl.PrepareSquashedCommit(options, parent_hash)
self.assertEqual(new_upload.reviewers, reviewers)
self.assertEqual(new_upload.ccs, ccs)
self.assertEqual(new_upload.commit_to_push, hash_to_push)
@ -3764,17 +3819,7 @@ class ChangelistTest(unittest.TestCase):
self.assertEqual(new_upload.change_desc, change_desc)
mockPrepareChange.assert_called_with(options, parent_hash, end_hash)
# remote origin
mockFetchUpstreamTuple.return_value = ('origin', 'refs/heads/release-1')
mockGetCommonAncestorWithUpstream.return_value = parent_hash_root
new_upload = cl.PrepareSquashedCommit(options)
self.assertEqual(new_upload.commit_to_push, hash_to_push_root)
self.assertEqual(new_upload.new_last_uploaded_commit, end_hash)
mockPrepareChange.assert_called_with(options, parent_hash_root, end_hash)
@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')
@ -3782,10 +3827,9 @@ class ChangelistTest(unittest.TestCase):
def testPrepareCherryPickSquashedCommit(self,
mockGetCommonAncestorWithUpstream,
mockPrepareChange, mockRunGit,
mockRunGitWithCode,
mockFetchUpstreamTuple, *_mocks):
parent_hash = '1a2bparentcommit'
mockGetCommonAncestorWithUpstream.return_value = parent_hash
mockRunGitWithCode, *_mocks):
cherry_pick_base_hash = '1a2bcherrypickbase'
mockGetCommonAncestorWithUpstream.return_value = cherry_pick_base_hash
change_desc = git_cl.ChangeDescription('BOO!')
ccs = ['cc@review.cl']
@ -3796,12 +3840,7 @@ class ChangelistTest(unittest.TestCase):
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'
@ -3813,7 +3852,7 @@ class ChangelistTest(unittest.TestCase):
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,
if {'commit-tree', latest_tree_hash, '-p', cherry_pick_base_hash,
'-F'}.issubset(set(commands)):
return hash_to_cp
if commands == ['rev-parse', 'HEAD']:
@ -3827,7 +3866,8 @@ class ChangelistTest(unittest.TestCase):
mockRunGitWithCode.side_effect = mock_run_git_with_code
new_upload = cl.PrepareCherryPickSquashedCommit(options)
new_upload = cl.PrepareCherryPickSquashedCommit(options,
upstream_gerrit_hash)
self.assertEqual(new_upload.reviewers, reviewers)
self.assertEqual(new_upload.ccs, ccs)
self.assertEqual(new_upload.commit_to_push, hash_to_push)
@ -3844,7 +3884,7 @@ class ChangelistTest(unittest.TestCase):
mockRunGitWithCode.side_effect = mock_run_git_with_code
with self.assertRaises(SystemExitMock):
cl.PrepareCherryPickSquashedCommit(options)
cl.PrepareCherryPickSquashedCommit(options, cherry_pick_base_hash)
@mock.patch('git_cl.Settings.GetDefaultCCList', return_value=[])
@mock.patch('git_cl.Changelist.GetAffectedFiles', return_value=[])

Loading…
Cancel
Save