diff --git a/git_cl.py b/git_cl.py index 4f248fcfa..829f60fc8 100755 --- a/git_cl.py +++ b/git_cl.py @@ -2166,7 +2166,11 @@ class Changelist(object): gclient_utils.rmtree(git_info_dir) - def _RunGitPushWithTraces(self, refspec, refspec_opts, git_push_metadata): + def _RunGitPushWithTraces(self, + refspec, + refspec_opts, + git_push_metadata, + git_push_options=None): """Run git push and collect the traces resulting from the execution.""" # Create a temporary directory to store traces in. Traces will be compressed # and stored in a 'traces' dir inside depot_tools. @@ -2186,8 +2190,13 @@ class Changelist(object): push_returncode = 0 remote_url = self.GetRemoteUrl() before_push = time_time() + push_cmd = ['git', 'push', remote_url, refspec] + if git_push_options: + for opt in git_push_options: + push_cmd.extend(['-o', opt]) + push_stdout = gclient_utils.CheckCallAndFilter( - ['git', 'push', remote_url, refspec], + push_cmd, env=env, print_stdout=True, # Flush after every line: useful for seeing progress when running as @@ -2423,8 +2432,10 @@ class Changelist(object): 'change_id': change_id, 'description': change_desc.description, } + push_stdout = self._RunGitPushWithTraces(refspec, refspec_opts, - git_push_metadata) + git_push_metadata, + options.push_options) if options.squash: regex = re.compile(r'remote:\s+https?://[\w\-\.\+\/#]*/(\d+)\s.*') @@ -4192,6 +4203,13 @@ def CMDupload(parser, args): help='Run presubmit checks in the ResultSink environment ' 'and send results to the ResultDB database.') parser.add_option('--realm', help='LUCI realm if reporting to ResultDB') + parser.add_option('-o', + '--push-options', + action='append', + default=[], + help='Transmit the given string to the server when ' + 'performing git push (pass-through). See git-push ' + 'documentation for more details.') orig_args = args (options, args) = parser.parse_args(args) diff --git a/tests/git_cl_test.py b/tests/git_cl_test.py index 539e53860..74234cf9f 100755 --- a/tests/git_cl_test.py +++ b/tests/git_cl_test.py @@ -808,16 +808,27 @@ class TestGitCl(unittest.TestCase): return calls - def _gerrit_upload_calls(self, description, reviewers, squash, + def _gerrit_upload_calls(self, + description, + reviewers, + squash, squash_mode='default', - title=None, notify=False, - post_amend_description=None, issue=None, cc=None, - custom_cl_base=None, tbr=None, + title=None, + notify=False, + post_amend_description=None, + issue=None, + cc=None, + custom_cl_base=None, + tbr=None, short_hostname='chromium', - labels=None, change_id=None, - final_description=None, gitcookies_exists=True, - force=False, edit_description=None, - default_branch='master'): + labels=None, + change_id=None, + final_description=None, + gitcookies_exists=True, + force=False, + edit_description=None, + default_branch='master', + push_opts=None): if post_amend_description is None: post_amend_description = description cc = cc or [] @@ -952,35 +963,47 @@ class TestGitCl(unittest.TestCase): ] calls += [ - (('time.time',), 1000,), - ((['git', 'push', - 'https://%s.googlesource.com/my/repo' % short_hostname, - ref_to_push + ':refs/for/refs/heads/' + default_branch + ref_suffix],), - (('remote:\n' - 'remote: Processing changes: (\)\n' - 'remote: Processing changes: (|)\n' - 'remote: Processing changes: (/)\n' - 'remote: Processing changes: (-)\n' - 'remote: Processing changes: new: 1 (/)\n' - 'remote: Processing changes: new: 1, done\n' - 'remote:\n' - 'remote: New Changes:\n' - 'remote: https://%s-review.googlesource.com/#/c/my/repo/+/123456' - ' XXX\n' - 'remote:\n' - 'To https://%s.googlesource.com/my/repo\n' - ' * [new branch] hhhh -> refs/for/refs/heads/%s\n' - ) % (short_hostname, short_hostname, default_branch)),), - (('time.time',), 2000,), - (('add_repeated', - 'sub_commands', - { - 'execution_time': 1000, - 'command': 'git push', - 'exit_code': 0, - 'arguments': sorted(metrics_arguments), - }), - None,), + ( + ('time.time', ), + 1000, + ), + ( + ([ + 'git', 'push', + 'https://%s.googlesource.com/my/repo' % short_hostname, + ref_to_push + ':refs/for/refs/heads/' + default_branch + + ref_suffix + ] + (push_opts if push_opts else []), ), + (('remote:\n' + 'remote: Processing changes: (\)\n' + 'remote: Processing changes: (|)\n' + 'remote: Processing changes: (/)\n' + 'remote: Processing changes: (-)\n' + 'remote: Processing changes: new: 1 (/)\n' + 'remote: Processing changes: new: 1, done\n' + 'remote:\n' + 'remote: New Changes:\n' + 'remote: ' + 'https://%s-review.googlesource.com/#/c/my/repo/+/123456' + ' XXX\n' + 'remote:\n' + 'To https://%s.googlesource.com/my/repo\n' + ' * [new branch] hhhh -> refs/for/refs/heads/%s\n') % + (short_hostname, short_hostname, default_branch)), + ), + ( + ('time.time', ), + 2000, + ), + ( + ('add_repeated', 'sub_commands', { + 'execution_time': 1000, + 'command': 'git push', + 'exit_code': 0, + 'arguments': sorted(metrics_arguments), + }), + None, + ), ] final_description = final_description or post_amend_description.strip() @@ -1087,32 +1110,32 @@ class TestGitCl(unittest.TestCase): ] return calls - def _run_gerrit_upload_test( - self, - upload_args, - description, - reviewers=None, - squash=True, - squash_mode=None, - title=None, - notify=False, - post_amend_description=None, - issue=None, - cc=None, - fetched_status=None, - other_cl_owner=None, - custom_cl_base=None, - tbr=None, - short_hostname='chromium', - labels=None, - change_id=None, - final_description=None, - gitcookies_exists=True, - force=False, - log_description=None, - edit_description=None, - fetched_description=None, - default_branch='master'): + def _run_gerrit_upload_test(self, + upload_args, + description, + reviewers=None, + squash=True, + squash_mode=None, + title=None, + notify=False, + post_amend_description=None, + issue=None, + cc=None, + fetched_status=None, + other_cl_owner=None, + custom_cl_base=None, + tbr=None, + short_hostname='chromium', + labels=None, + change_id=None, + final_description=None, + gitcookies_exists=True, + force=False, + log_description=None, + edit_description=None, + fetched_description=None, + default_branch='master', + push_opts=None): """Generic gerrit upload test framework.""" if squash_mode is None: if '--no-squash' in upload_args: @@ -1192,12 +1215,17 @@ class TestGitCl(unittest.TestCase): 'gclient_utils.temporary_file', TemporaryFileMock()).start() mock.patch('os.remove', return_value=True).start() self.calls += self._gerrit_upload_calls( - description, reviewers, squash, + description, + reviewers, + squash, squash_mode=squash_mode, - title=title, notify=notify, + title=title, + notify=notify, post_amend_description=post_amend_description, - issue=issue, cc=cc, - custom_cl_base=custom_cl_base, tbr=tbr, + issue=issue, + cc=cc, + custom_cl_base=custom_cl_base, + tbr=tbr, short_hostname=short_hostname, labels=labels, change_id=change_id, @@ -1205,7 +1233,8 @@ class TestGitCl(unittest.TestCase): gitcookies_exists=gitcookies_exists, force=force, edit_description=edit_description, - default_branch=default_branch) + default_branch=default_branch, + push_opts=push_opts) # Uncomment when debugging. # print('\n'.join(map(lambda x: '%2i: %s' % x, enumerate(self.calls)))) git_cl.main(['upload'] + upload_args) @@ -1260,16 +1289,24 @@ class TestGitCl(unittest.TestCase): squash_mode='override_nosquash', change_id='I123456789') + def test_gerrit_push_opts(self): + self._run_gerrit_upload_test(['-o', 'wip'], + 'desc ✔\n\nBUG=\n\nChange-Id: I123456789\n', + [], + squash=False, + squash_mode='override_nosquash', + change_id='I123456789', + push_opts=['-o', 'wip']) + def test_gerrit_no_reviewer_non_chromium_host(self): # TODO(crbug/877717): remove this test case. - self._run_gerrit_upload_test( - [], - 'desc ✔\n\nBUG=\n\nChange-Id: I123456789\n', - [], - squash=False, - squash_mode='override_nosquash', - short_hostname='other', - change_id='I123456789') + self._run_gerrit_upload_test([], + 'desc ✔\n\nBUG=\n\nChange-Id: I123456789\n', + [], + squash=False, + squash_mode='override_nosquash', + short_hostname='other', + change_id='I123456789') def test_gerrit_patchset_title_special_chars_nosquash(self): self._run_gerrit_upload_test(