From b88a4343deac96b7fe40e4f2b0fe542de102a3bf Mon Sep 17 00:00:00 2001 From: Joanna Wang Date: Tue, 24 Jan 2023 01:28:22 +0000 Subject: [PATCH] [stacked-changes] Prepare squashed commit Bug: b/265929888 Change-Id: Ia492666a5707996d94a4b6f7668ceaeb0eda8c39 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/4182841 Reviewed-by: Josip Sokcevic Commit-Queue: Joanna Wang Reviewed-by: Gavin Mak --- git_cl.py | 32 +++++++++++++++++++++++ tests/git_cl_test.py | 60 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/git_cl.py b/git_cl.py index 6ea849841..c070e5907 100755 --- a/git_cl.py +++ b/git_cl.py @@ -1576,6 +1576,38 @@ class Changelist(object): return title return user_title or title + def PrepareSquashedCommit(self, options, parent=None, end_commit=None): + # type: (optparse.Values, Optional[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() + + reviewers, ccs, change_desc = self._PrepareChange(options, parent, + end_commit) + latest_tree = RunGit(['rev-parse', end_commit + ':']).strip() + with gclient_utils.temporary_file() as desc_tempfile: + gclient_utils.FileWrite(desc_tempfile, change_desc.description) + commit_to_push = RunGit( + ['commit-tree', latest_tree, '-p', parent, '-F', + desc_tempfile]).strip() + + return _NewUpload(reviewers, ccs, commit_to_push, end_commit, change_desc) + def PrepareCherryPickSquashedCommit(self, options): # type: (optparse.Values) -> _NewUpload() """Create a commit cherry-picked on parent to push.""" diff --git a/tests/git_cl_test.py b/tests/git_cl_test.py index 16ef2407a..e44ec0bb7 100755 --- a/tests/git_cl_test.py +++ b/tests/git_cl_test.py @@ -3559,6 +3559,66 @@ 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): + + change_desc = git_cl.ChangeDescription('BOO!') + reviewers = [] + ccs = [] + mockPrepareChange.return_value = (reviewers, ccs, change_desc) + + parent_hash = 'upstream-gerrit-hash' + parent_hash_root = 'root-commit' + hash_to_push = 'new-squash-hash' + hash_to_push_root = 'new-squash-hash-root' + branchref = 'refs/heads/current-branch' + end_hash = 'end-hash' + tree_hash = 'tree-hash' + + def mock_run_git(commands): + if {'commit-tree', tree_hash, '-p', parent_hash, + '-F'}.issubset(set(commands)): + return hash_to_push + if {'commit-tree', tree_hash, '-p', parent_hash_root, + '-F'}.issubset(set(commands)): + return hash_to_push_root + if commands == ['rev-parse', branchref]: + return end_hash + if commands == ['rev-parse', end_hash + ':']: + return tree_hash + + mockRunGit.side_effect = mock_run_git + 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) + 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, end_hash) + 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')