OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 # Copyright (C) 2008 Evan Martin <martine@danga.com> | 6 # Copyright (C) 2008 Evan Martin <martine@danga.com> |
7 | 7 |
8 """A git-command for integrating reviews on Rietveld and Gerrit.""" | 8 """A git-command for integrating reviews on Rietveld and Gerrit.""" |
9 | 9 |
10 from __future__ import print_function | 10 from __future__ import print_function |
(...skipping 4168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4179 if base_has_submodules: | 4179 if base_has_submodules: |
4180 cherry_pick_commit = RunGit(['rev-list', 'HEAD^!']).rstrip() | 4180 cherry_pick_commit = RunGit(['rev-list', 'HEAD^!']).rstrip() |
4181 RunGit(['branch', CHERRY_PICK_BRANCH, svn_head]) | 4181 RunGit(['branch', CHERRY_PICK_BRANCH, svn_head]) |
4182 RunGit(['checkout', CHERRY_PICK_BRANCH]) | 4182 RunGit(['checkout', CHERRY_PICK_BRANCH]) |
4183 RunGit(['cherry-pick', cherry_pick_commit]) | 4183 RunGit(['cherry-pick', cherry_pick_commit]) |
4184 if cmd == 'land': | 4184 if cmd == 'land': |
4185 remote, branch = cl.FetchUpstreamTuple(cl.GetBranch()) | 4185 remote, branch = cl.FetchUpstreamTuple(cl.GetBranch()) |
4186 mirror = settings.GetGitMirror(remote) | 4186 mirror = settings.GetGitMirror(remote) |
4187 pushurl = mirror.url if mirror else remote | 4187 pushurl = mirror.url if mirror else remote |
4188 pending_prefix = settings.GetPendingRefPrefix() | 4188 pending_prefix = settings.GetPendingRefPrefix() |
4189 if not pending_prefix or branch.startswith(pending_prefix): | 4189 git_number_footer = settings.GetHasGitNumberFooter() |
| 4190 # NOTE: that pending_prefix takes precendence over git_number_footer. |
| 4191 # If pending_prefix is set, it means gnumbd service is still working |
| 4192 # for this repo OR deve's checkout is stale, in which case push to |
| 4193 # refs/pending/ below fail anyway. |
| 4194 if not pending_prefix and git_number_footer: |
| 4195 # git_number_footer is used only if pending_prefix is not used. |
| 4196 retcode, output = PushToGitWithGitNumberFooter(pushurl, branch) |
| 4197 pushed_to_pending = False |
| 4198 elif not pending_prefix or branch.startswith(pending_prefix): |
4190 # If not using refs/pending/heads/* at all, or target ref is already set | 4199 # If not using refs/pending/heads/* at all, or target ref is already set |
4191 # to pending, then push to the target ref directly. | 4200 # to pending, then push to the target ref directly. |
4192 retcode, output = RunGitWithCode( | 4201 retcode, output = RunGitWithCode( |
4193 ['push', '--porcelain', pushurl, 'HEAD:%s' % branch]) | 4202 ['push', '--porcelain', pushurl, 'HEAD:%s' % branch]) |
4194 pushed_to_pending = pending_prefix and branch.startswith(pending_prefix) | 4203 pushed_to_pending = pending_prefix and branch.startswith(pending_prefix) |
4195 else: | 4204 else: |
4196 # Cherry-pick the change on top of pending ref and then push it. | 4205 # Cherry-pick the change on top of pending ref and then push it. |
4197 assert branch.startswith('refs/'), branch | 4206 assert branch.startswith('refs/'), branch |
4198 assert pending_prefix[-1] == '/', pending_prefix | 4207 assert pending_prefix[-1] == '/', pending_prefix |
4199 pending_ref = pending_prefix + branch[len('refs/'):] | 4208 pending_ref = pending_prefix + branch[len('refs/'):] |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4303 | 4312 |
4304 current_rev = to_rev | 4313 current_rev = to_rev |
4305 | 4314 |
4306 | 4315 |
4307 def PushToGitPending(remote, pending_ref): | 4316 def PushToGitPending(remote, pending_ref): |
4308 """Fetches pending_ref, cherry-picks current HEAD on top of it, pushes. | 4317 """Fetches pending_ref, cherry-picks current HEAD on top of it, pushes. |
4309 | 4318 |
4310 Returns: | 4319 Returns: |
4311 (retcode of last operation, output log of last operation). | 4320 (retcode of last operation, output log of last operation). |
4312 """ | 4321 """ |
| 4322 # TODO(tandrii): delete this with gnumbd service, see http://crbug.com/644915. |
4313 assert pending_ref.startswith('refs/'), pending_ref | 4323 assert pending_ref.startswith('refs/'), pending_ref |
4314 local_pending_ref = 'refs/git-cl/' + pending_ref[len('refs/'):] | 4324 local_pending_ref = 'refs/git-cl/' + pending_ref[len('refs/'):] |
4315 cherry = RunGit(['rev-parse', 'HEAD']).strip() | 4325 cherry = RunGit(['rev-parse', 'HEAD']).strip() |
4316 code = 0 | 4326 code = 0 |
4317 out = '' | 4327 out = '' |
4318 max_attempts = 3 | 4328 max_attempts = 3 |
4319 attempts_left = max_attempts | 4329 attempts_left = max_attempts |
4320 while attempts_left: | 4330 while attempts_left: |
4321 if attempts_left != max_attempts: | 4331 if attempts_left != max_attempts: |
4322 print('Retrying, %d attempts left...' % (attempts_left - 1,)) | 4332 print('Retrying, %d attempts left...' % (attempts_left - 1,)) |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4358 print(out.strip()) | 4368 print(out.strip()) |
4359 if IsFatalPushFailure(out): | 4369 if IsFatalPushFailure(out): |
4360 print('Fatal push error. Make sure your .netrc credentials and git ' | 4370 print('Fatal push error. Make sure your .netrc credentials and git ' |
4361 'user.email are correct and you have push access to the repo.') | 4371 'user.email are correct and you have push access to the repo.') |
4362 return code, out | 4372 return code, out |
4363 | 4373 |
4364 print('All attempts to push to pending ref failed.') | 4374 print('All attempts to push to pending ref failed.') |
4365 return code, out | 4375 return code, out |
4366 | 4376 |
4367 | 4377 |
| 4378 def PushToGitWithGitNumberFooter(remote, upstream_ref): |
| 4379 """Fetches remote ref, cherry-picks current HEAD on top of it, updates |
| 4380 position footers, pushes. |
| 4381 |
| 4382 Returns: |
| 4383 (retcode of last operation, output log of last operation). |
| 4384 """ |
| 4385 local_upstream_ref = 'refs/git-cl/' + upstream_ref[len('refs/'):] |
| 4386 cherry = RunGit(['rev-parse', 'HEAD']).strip() |
| 4387 code = 0 |
| 4388 out = '' |
| 4389 max_attempts = 3 |
| 4390 attempts_left = max_attempts |
| 4391 while attempts_left: |
| 4392 if attempts_left != max_attempts: |
| 4393 print('Retrying, %d attempts left...' % (attempts_left - 1,)) |
| 4394 attempts_left -= 1 |
| 4395 |
| 4396 # Fetch. Retry fetch errors. |
| 4397 print('Fetching pending ref %s...' % upstream_ref) |
| 4398 code, out = RunGitWithCode( |
| 4399 ['retry', 'fetch', remote, '+%s:%s' % (upstream_ref, local_upstream_ref)
]) |
| 4400 if code: |
| 4401 print('Fetch failed with exit code %d.' % code) |
| 4402 if out.strip(): |
| 4403 print(out.strip()) |
| 4404 continue |
| 4405 |
| 4406 # Try to cherry pick. Abort on merge conflicts. |
| 4407 print('Cherry-picking commit on top of pending ref...') |
| 4408 RunGitWithCode(['checkout', local_upstream_ref], suppress_stderr=True) |
| 4409 code, out = RunGitWithCode(['cherry-pick', cherry]) |
| 4410 if code: |
| 4411 print('Your patch doesn\'t apply cleanly to ref \'%s\', ' |
| 4412 'the following files have merge conflicts:' % upstream_ref) |
| 4413 print(RunGit(['diff', '--name-status', '--diff-filter=U']).strip()) |
| 4414 print('Please rebase your patch and try again.') |
| 4415 RunGitWithCode(['cherry-pick', '--abort']) |
| 4416 return code, out |
| 4417 |
| 4418 # Applied cleanly, amend commit message with position footers. |
| 4419 |
| 4420 # TODO(tandrii): amend footers. |
| 4421 |
| 4422 # Try to push now. Retry on error (flake or non-ff push). |
| 4423 print('Pushing commit to %s... It can take a while.' % upstream_ref) |
| 4424 code, out = RunGitWithCode( |
| 4425 ['retry', 'push', '--porcelain', remote, 'HEAD:%s' % upstream_ref]) |
| 4426 if code == 0: |
| 4427 # Success. |
| 4428 print('Commit pushed to pending ref successfully!') |
| 4429 return code, out |
| 4430 |
| 4431 print('Push failed with exit code %d.' % code) |
| 4432 if out.strip(): |
| 4433 print(out.strip()) |
| 4434 if IsFatalPushFailure(out): |
| 4435 print('Fatal push error. Make sure your .netrc credentials and git ' |
| 4436 'user.email are correct and you have push access to the repo.') |
| 4437 return code, out |
| 4438 |
| 4439 print('All attempts to push to pending ref failed.') |
| 4440 return code, out |
| 4441 |
| 4442 |
4368 def IsFatalPushFailure(push_stdout): | 4443 def IsFatalPushFailure(push_stdout): |
4369 """True if retrying push won't help.""" | 4444 """True if retrying push won't help.""" |
4370 return '(prohibited by Gerrit)' in push_stdout | 4445 return '(prohibited by Gerrit)' in push_stdout |
4371 | 4446 |
4372 | 4447 |
4373 @subcommand.usage('[upstream branch to apply against]') | 4448 @subcommand.usage('[upstream branch to apply against]') |
4374 def CMDdcommit(parser, args): | 4449 def CMDdcommit(parser, args): |
4375 """Commits the current changelist via git-svn.""" | 4450 """Commits the current changelist via git-svn.""" |
4376 if not settings.GetIsGitSvn(): | 4451 if not settings.GetIsGitSvn(): |
4377 if git_footers.get_footer_svn_id(): | 4452 if git_footers.get_footer_svn_id(): |
(...skipping 896 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5274 if __name__ == '__main__': | 5349 if __name__ == '__main__': |
5275 # These affect sys.stdout so do it outside of main() to simplify mocks in | 5350 # These affect sys.stdout so do it outside of main() to simplify mocks in |
5276 # unit testing. | 5351 # unit testing. |
5277 fix_encoding.fix_encoding() | 5352 fix_encoding.fix_encoding() |
5278 setup_color.init() | 5353 setup_color.init() |
5279 try: | 5354 try: |
5280 sys.exit(main(sys.argv[1:])) | 5355 sys.exit(main(sys.argv[1:])) |
5281 except KeyboardInterrupt: | 5356 except KeyboardInterrupt: |
5282 sys.stderr.write('interrupted\n') | 5357 sys.stderr.write('interrupted\n') |
5283 sys.exit(1) | 5358 sys.exit(1) |
OLD | NEW |