| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # git-cl -- a git-command for integrating reviews on Rietveld | 2 # git-cl -- a git-command for integrating reviews on Rietveld |
| 3 # Copyright (C) 2008 Evan Martin <martine@danga.com> | 3 # Copyright (C) 2008 Evan Martin <martine@danga.com> |
| 4 | 4 |
| 5 import errno | 5 import errno |
| 6 import logging | 6 import logging |
| 7 import optparse | 7 import optparse |
| 8 import os | 8 import os |
| 9 import re | 9 import re |
| 10 import subprocess | 10 import subprocess |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 except OSError, e: | 47 except OSError, e: |
| 48 if e.errno == errno.EAGAIN and sys.platform == 'cygwin': | 48 if e.errno == errno.EAGAIN and sys.platform == 'cygwin': |
| 49 DieWithError( | 49 DieWithError( |
| 50 'Visit ' | 50 'Visit ' |
| 51 'http://code.google.com/p/chromium/wiki/CygwinDllRemappingFailure to ' | 51 'http://code.google.com/p/chromium/wiki/CygwinDllRemappingFailure to ' |
| 52 'learn how to fix this error; you need to rebase your cygwin dlls') | 52 'learn how to fix this error; you need to rebase your cygwin dlls') |
| 53 raise | 53 raise |
| 54 | 54 |
| 55 | 55 |
| 56 def RunCommand(cmd, error_ok=False, error_message=None, | 56 def RunCommand(cmd, error_ok=False, error_message=None, |
| 57 redirect_stdout=True, swallow_stderr=False, **kwargs): | 57 redirect_stdout=True, swallow_stderr=False, |
| 58 tee_filter=None, **kwargs): |
| 58 if redirect_stdout: | 59 if redirect_stdout: |
| 59 stdout = subprocess.PIPE | 60 stdout = subprocess.PIPE |
| 60 else: | 61 else: |
| 61 stdout = None | 62 stdout = None |
| 62 if swallow_stderr: | 63 if swallow_stderr: |
| 63 stderr = subprocess.PIPE | 64 stderr = subprocess.PIPE |
| 64 else: | 65 else: |
| 65 stderr = None | 66 stderr = None |
| 66 proc = Popen(cmd, stdout=stdout, stderr=stderr, **kwargs) | 67 proc = Popen(cmd, stdout=stdout, stderr=stderr, **kwargs) |
| 67 output = proc.communicate()[0] | 68 if tee_filter: |
| 69 output = '' |
| 70 while True: |
| 71 line = proc.stdout.readline() |
| 72 if line == '' and proc.poll() != None: |
| 73 break |
| 74 if not tee_filter(line): |
| 75 print line |
| 76 output += line + '\n' |
| 77 else: |
| 78 output = proc.communicate()[0] |
| 79 |
| 68 if not error_ok and proc.returncode != 0: | 80 if not error_ok and proc.returncode != 0: |
| 69 DieWithError('Command "%s" failed.\n' % (' '.join(cmd)) + | 81 DieWithError('Command "%s" failed.\n' % (' '.join(cmd)) + |
| 70 (error_message or output or '')) | 82 (error_message or output or '')) |
| 71 return output | 83 return output |
| 72 | 84 |
| 73 | 85 |
| 74 def RunGit(args, **kwargs): | 86 def RunGit(args, **kwargs): |
| 75 cmd = ['git'] + args | 87 cmd = ['git'] + args |
| 76 return RunCommand(cmd, **kwargs) | 88 return RunCommand(cmd, **kwargs) |
| 77 | 89 |
| (...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 472 | 484 |
| 473 SetProperty(settings.GetCCList(), 'CC list', 'cc') | 485 SetProperty(settings.GetCCList(), 'CC list', 'cc') |
| 474 SetProperty(settings.GetTreeStatusUrl(error_ok=True), 'Tree status URL', | 486 SetProperty(settings.GetTreeStatusUrl(error_ok=True), 'Tree status URL', |
| 475 'tree-status-url') | 487 'tree-status-url') |
| 476 SetProperty(settings.GetViewVCUrl(), 'ViewVC URL', 'viewvc-url') | 488 SetProperty(settings.GetViewVCUrl(), 'ViewVC URL', 'viewvc-url') |
| 477 | 489 |
| 478 # TODO: configure a default branch to diff against, rather than this | 490 # TODO: configure a default branch to diff against, rather than this |
| 479 # svn-based hackery. | 491 # svn-based hackery. |
| 480 | 492 |
| 481 | 493 |
| 494 class HookResults(object): |
| 495 """Contains the parsed output of the presubmit hooks.""" |
| 496 def __init__(self, output_from_hooks=None): |
| 497 self.reviewers = [] |
| 498 self.output = None |
| 499 self._ParseOutputFromHooks(output_from_hooks) |
| 500 |
| 501 def _ParseOutputFromHooks(self, output_from_hooks): |
| 502 if not output_from_hooks: |
| 503 return |
| 504 lines = [] |
| 505 reviewers = [] |
| 506 reviewer_regexp = re.compile('ADD: R=(.+)') |
| 507 for l in output_from_hooks.splitlines(): |
| 508 m = reviewer_regexp.match(l) |
| 509 if m: |
| 510 reviewers.extend(m.group(1).split(',')) |
| 511 else: |
| 512 lines.append(l) |
| 513 self.output = '\n'.join(lines) |
| 514 self.reviewers = ','.join(reviewers) |
| 515 |
| 516 |
| 517 class ChangeDescription(object): |
| 518 """Contains a parsed form of the change description.""" |
| 519 def __init__(self, subject, log_desc, reviewers): |
| 520 self.subject = subject |
| 521 self.log_desc = log_desc |
| 522 self.reviewers = reviewers |
| 523 self.description = self.log_desc |
| 524 |
| 525 def Update(self): |
| 526 initial_text = """# Enter a description of the change. |
| 527 # This will displayed on the codereview site. |
| 528 # The first line will also be used as the subject of the review. |
| 529 """ |
| 530 initial_text += self.description |
| 531 if 'R=' not in self.description and self.reviewers: |
| 532 initial_text += '\nR=' + self.reviewers |
| 533 if 'BUG=' not in self.description: |
| 534 initial_text += '\nBUG=' |
| 535 if 'TEST=' not in self.description: |
| 536 initial_text += '\nTEST=' |
| 537 self._ParseDescription(UserEditedLog(initial_text)) |
| 538 |
| 539 def _ParseDescription(self, description): |
| 540 if not description: |
| 541 self.description = description |
| 542 return |
| 543 |
| 544 parsed_lines = [] |
| 545 reviewers_regexp = re.compile('\s*R=(.+)') |
| 546 reviewers = '' |
| 547 subject = '' |
| 548 for l in description.splitlines(): |
| 549 if not subject: |
| 550 subject = l |
| 551 matched_reviewers = reviewers_regexp.match(l) |
| 552 if matched_reviewers: |
| 553 reviewers = matched_reviewers.group(1) |
| 554 parsed_lines.append(l) |
| 555 |
| 556 self.description = '\n'.join(parsed_lines) + '\n' |
| 557 self.subject = subject |
| 558 self.reviewers = reviewers |
| 559 |
| 560 def IsEmpty(self): |
| 561 return not self.description |
| 562 |
| 563 |
| 482 def FindCodereviewSettingsFile(filename='codereview.settings'): | 564 def FindCodereviewSettingsFile(filename='codereview.settings'): |
| 483 """Finds the given file starting in the cwd and going up. | 565 """Finds the given file starting in the cwd and going up. |
| 484 | 566 |
| 485 Only looks up to the top of the repository unless an | 567 Only looks up to the top of the repository unless an |
| 486 'inherit-review-settings-ok' file exists in the root of the repository. | 568 'inherit-review-settings-ok' file exists in the root of the repository. |
| 487 """ | 569 """ |
| 488 inherit_ok_file = 'inherit-review-settings-ok' | 570 inherit_ok_file = 'inherit-review-settings-ok' |
| 489 cwd = os.getcwd() | 571 cwd = os.getcwd() |
| 490 root = os.path.abspath(RunGit(['rev-parse', '--show-cdup']).strip()) | 572 root = os.path.abspath(RunGit(['rev-parse', '--show-cdup']).strip()) |
| 491 if os.path.isfile(os.path.join(root, inherit_ok_file)): | 573 if os.path.isfile(os.path.join(root, inherit_ok_file)): |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 662 return | 744 return |
| 663 | 745 |
| 664 fileobj = open(filename) | 746 fileobj = open(filename) |
| 665 text = fileobj.read() | 747 text = fileobj.read() |
| 666 fileobj.close() | 748 fileobj.close() |
| 667 os.remove(filename) | 749 os.remove(filename) |
| 668 stripcomment_re = re.compile(r'^#.*$', re.MULTILINE) | 750 stripcomment_re = re.compile(r'^#.*$', re.MULTILINE) |
| 669 return stripcomment_re.sub('', text).strip() | 751 return stripcomment_re.sub('', text).strip() |
| 670 | 752 |
| 671 | 753 |
| 672 def RunHook(hook, upstream_branch, error_ok=False): | 754 def RunHook(hook, upstream_branch, rietveld_server, tbr=False, |
| 755 error_ok=False): |
| 673 """Run a given hook if it exists. By default, we fail on errors.""" | 756 """Run a given hook if it exists. By default, we fail on errors.""" |
| 674 hook = '%s/%s' % (settings.GetRoot(), hook) | 757 hook = '%s/%s' % (settings.GetRoot(), hook) |
| 675 if not os.path.exists(hook): | 758 if not os.path.exists(hook): |
| 676 return | 759 return HookResults() |
| 677 return RunCommand([hook, upstream_branch], error_ok=error_ok, | 760 cmd = [hook] |
| 678 redirect_stdout=False) | 761 if tbr: |
| 762 cmd.append('--tbr') |
| 763 cmd.extend(['--host-url=' + rietveld_server, upstream_branch]) |
| 764 output = RunCommand(cmd, error_ok=error_ok, redirect_stdout=True, |
| 765 tee_filter=lambda l: l.startswith('ADD:')) |
| 766 return HookResults(output) |
| 679 | 767 |
| 680 | 768 |
| 681 def CMDpresubmit(parser, args): | 769 def CMDpresubmit(parser, args): |
| 682 """run presubmit tests on the current changelist""" | 770 """run presubmit tests on the current changelist""" |
| 683 parser.add_option('--upload', action='store_true', | 771 parser.add_option('--upload', action='store_true', |
| 684 help='Run upload hook instead of the push/dcommit hook') | 772 help='Run upload hook instead of the push/dcommit hook') |
| 685 (options, args) = parser.parse_args(args) | 773 (options, args) = parser.parse_args(args) |
| 686 | 774 |
| 687 # Make sure index is up-to-date before running diff-index. | 775 # Make sure index is up-to-date before running diff-index. |
| 688 RunGit(['update-index', '--refresh', '-q'], error_ok=True) | 776 RunGit(['update-index', '--refresh', '-q'], error_ok=True) |
| 689 if RunGit(['diff-index', 'HEAD']): | 777 if RunGit(['diff-index', 'HEAD']): |
| 690 # TODO(maruel): Is this really necessary? | 778 # TODO(maruel): Is this really necessary? |
| 691 print 'Cannot presubmit with a dirty tree. You must commit locally first.' | 779 print 'Cannot presubmit with a dirty tree. You must commit locally first.' |
| 692 return 1 | 780 return 1 |
| 693 | 781 |
| 782 cl = Changelist() |
| 694 if args: | 783 if args: |
| 695 base_branch = args[0] | 784 base_branch = args[0] |
| 696 else: | 785 else: |
| 697 # Default to diffing against the "upstream" branch. | 786 # Default to diffing against the "upstream" branch. |
| 698 base_branch = Changelist().GetUpstreamBranch() | 787 base_branch = cl.GetUpstreamBranch() |
| 699 | 788 |
| 700 if options.upload: | 789 if options.upload: |
| 701 print '*** Presubmit checks for UPLOAD would report: ***' | 790 print '*** Presubmit checks for UPLOAD would report: ***' |
| 702 return not RunHook(PREUPLOAD_HOOK, upstream_branch=base_branch, | 791 return not RunHook(PREUPLOAD_HOOK, upstream_branch=base_branch, |
| 703 error_ok=True) | 792 rietveld_server=cl.GetRietveldServer(), tbr=False, |
| 793 error_ok=True).output |
| 704 else: | 794 else: |
| 705 print '*** Presubmit checks for DCOMMIT would report: ***' | 795 print '*** Presubmit checks for DCOMMIT would report: ***' |
| 706 return not RunHook(PREDCOMMIT_HOOK, upstream_branch=base_branch, | 796 return not RunHook(PREDCOMMIT_HOOK, upstream_branch=base_branch, |
| 707 error_ok=True) | 797 rietveld_server=cl.GetRietveldServer(), tbr=options.tbr, |
| 798 error_ok=True).output |
| 708 | 799 |
| 709 | 800 |
| 710 @usage('[args to "git diff"]') | 801 @usage('[args to "git diff"]') |
| 711 def CMDupload(parser, args): | 802 def CMDupload(parser, args): |
| 712 """upload the current changelist to codereview""" | 803 """upload the current changelist to codereview""" |
| 713 parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks', | 804 parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks', |
| 714 help='bypass upload presubmit hook') | 805 help='bypass upload presubmit hook') |
| 715 parser.add_option('-m', dest='message', help='message for patch') | 806 parser.add_option('-m', dest='message', help='message for patch') |
| 716 parser.add_option('-r', '--reviewers', | 807 parser.add_option('-r', '--reviewers', |
| 717 help='reviewer email addresses') | 808 help='reviewer email addresses') |
| (...skipping 18 matching lines...) Expand all Loading... |
| 736 | 827 |
| 737 cl = Changelist() | 828 cl = Changelist() |
| 738 if args: | 829 if args: |
| 739 base_branch = args[0] | 830 base_branch = args[0] |
| 740 else: | 831 else: |
| 741 # Default to diffing against the "upstream" branch. | 832 # Default to diffing against the "upstream" branch. |
| 742 base_branch = cl.GetUpstreamBranch() | 833 base_branch = cl.GetUpstreamBranch() |
| 743 args = [base_branch + "..."] | 834 args = [base_branch + "..."] |
| 744 | 835 |
| 745 if not options.bypass_hooks: | 836 if not options.bypass_hooks: |
| 746 RunHook(PREUPLOAD_HOOK, upstream_branch=base_branch, error_ok=False) | 837 hook_results = RunHook(PREUPLOAD_HOOK, upstream_branch=base_branch, |
| 838 rietveld_server=cl.GetRietveldServer(), tbr=False, |
| 839 error_ok=False) |
| 840 else: |
| 841 hook_results = HookResults() |
| 842 |
| 843 if not options.reviewers and hook_results.reviewers: |
| 844 options.reviewers = hook_results.reviewers |
| 747 | 845 |
| 748 # --no-ext-diff is broken in some versions of Git, so try to work around | 846 # --no-ext-diff is broken in some versions of Git, so try to work around |
| 749 # this by overriding the environment (but there is still a problem if the | 847 # this by overriding the environment (but there is still a problem if the |
| 750 # git config key "diff.external" is used). | 848 # git config key "diff.external" is used). |
| 751 env = os.environ.copy() | 849 env = os.environ.copy() |
| 752 if 'GIT_EXTERNAL_DIFF' in env: | 850 if 'GIT_EXTERNAL_DIFF' in env: |
| 753 del env['GIT_EXTERNAL_DIFF'] | 851 del env['GIT_EXTERNAL_DIFF'] |
| 754 subprocess.call(['git', 'diff', '--no-ext-diff', '--stat', '-M'] + args, | 852 subprocess.call(['git', 'diff', '--no-ext-diff', '--stat', '-M'] + args, |
| 755 env=env) | 853 env=env) |
| 756 | 854 |
| 757 upload_args = ['--assume_yes'] # Don't ask about untracked files. | 855 upload_args = ['--assume_yes'] # Don't ask about untracked files. |
| 758 upload_args.extend(['--server', cl.GetRietveldServer()]) | 856 upload_args.extend(['--server', cl.GetRietveldServer()]) |
| 759 if options.reviewers: | |
| 760 upload_args.extend(['--reviewers', options.reviewers]) | |
| 761 if options.emulate_svn_auto_props: | 857 if options.emulate_svn_auto_props: |
| 762 upload_args.append('--emulate_svn_auto_props') | 858 upload_args.append('--emulate_svn_auto_props') |
| 763 if options.send_mail: | 859 if options.send_mail: |
| 764 if not options.reviewers: | 860 if not options.reviewers: |
| 765 DieWithError("Must specify reviewers to send email.") | 861 DieWithError("Must specify reviewers to send email.") |
| 766 upload_args.append('--send_mail') | 862 upload_args.append('--send_mail') |
| 767 if options.from_logs and not options.message: | 863 if options.from_logs and not options.message: |
| 768 print 'Must set message for subject line if using desc_from_logs' | 864 print 'Must set message for subject line if using desc_from_logs' |
| 769 return 1 | 865 return 1 |
| 770 | 866 |
| 771 change_desc = None | 867 change_desc = None |
| 772 | 868 |
| 773 if cl.GetIssue(): | 869 if cl.GetIssue(): |
| 774 if options.message: | 870 if options.message: |
| 775 upload_args.extend(['--message', options.message]) | 871 upload_args.extend(['--message', options.message]) |
| 776 upload_args.extend(['--issue', cl.GetIssue()]) | 872 upload_args.extend(['--issue', cl.GetIssue()]) |
| 777 print ("This branch is associated with issue %s. " | 873 print ("This branch is associated with issue %s. " |
| 778 "Adding patch to that issue." % cl.GetIssue()) | 874 "Adding patch to that issue." % cl.GetIssue()) |
| 779 else: | 875 else: |
| 780 log_desc = CreateDescriptionFromLog(args) | 876 log_desc = CreateDescriptionFromLog(args) |
| 781 if options.from_logs: | 877 change_desc = ChangeDescription(options.message, log_desc, |
| 782 # Uses logs as description and message as subject. | 878 options.reviewers) |
| 783 subject = options.message | 879 if not options.from_logs: |
| 784 change_desc = subject + '\n\n' + log_desc | 880 change_desc.Update() |
| 785 else: | 881 |
| 786 initial_text = """# Enter a description of the change. | 882 if change_desc.IsEmpty(): |
| 787 # This will displayed on the codereview site. | |
| 788 # The first line will also be used as the subject of the review. | |
| 789 """ | |
| 790 if 'BUG=' not in log_desc: | |
| 791 log_desc += '\nBUG=' | |
| 792 if 'TEST=' not in log_desc: | |
| 793 log_desc += '\nTEST=' | |
| 794 change_desc = UserEditedLog(initial_text + log_desc) | |
| 795 subject = '' | |
| 796 if change_desc: | |
| 797 subject = change_desc.splitlines()[0] | |
| 798 if not change_desc: | |
| 799 print "Description is empty; aborting." | 883 print "Description is empty; aborting." |
| 800 return 1 | 884 return 1 |
| 801 upload_args.extend(['--message', subject]) | 885 |
| 802 upload_args.extend(['--description', change_desc]) | 886 upload_args.extend(['--message', change_desc.subject]) |
| 887 upload_args.extend(['--description', change_desc.description]) |
| 888 if change_desc.reviewers: |
| 889 upload_args.extend(['--reviewers', change_desc.reviewers]) |
| 803 cc = ','.join(filter(None, (settings.GetCCList(), options.cc))) | 890 cc = ','.join(filter(None, (settings.GetCCList(), options.cc))) |
| 804 if cc: | 891 if cc: |
| 805 upload_args.extend(['--cc', cc]) | 892 upload_args.extend(['--cc', cc]) |
| 806 | 893 |
| 807 # Include the upstream repo's URL in the change -- this is useful for | 894 # Include the upstream repo's URL in the change -- this is useful for |
| 808 # projects that have their source spread across multiple repos. | 895 # projects that have their source spread across multiple repos. |
| 809 remote_url = None | 896 remote_url = None |
| 810 if settings.GetIsGitSvn(): | 897 if settings.GetIsGitSvn(): |
| 811 # URL is dependent on the current directory. | 898 # URL is dependent on the current directory. |
| 812 data = RunGit(['svn', 'info'], cwd=settings.GetRoot()) | 899 data = RunGit(['svn', 'info'], cwd=settings.GetRoot()) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 824 try: | 911 try: |
| 825 issue, patchset = upload.RealMain(['upload'] + upload_args + args) | 912 issue, patchset = upload.RealMain(['upload'] + upload_args + args) |
| 826 except: | 913 except: |
| 827 # If we got an exception after the user typed a description for their | 914 # If we got an exception after the user typed a description for their |
| 828 # change, back up the description before re-raising. | 915 # change, back up the description before re-raising. |
| 829 if change_desc: | 916 if change_desc: |
| 830 backup_path = os.path.expanduser(DESCRIPTION_BACKUP_FILE) | 917 backup_path = os.path.expanduser(DESCRIPTION_BACKUP_FILE) |
| 831 print '\nGot exception while uploading -- saving description to %s\n' \ | 918 print '\nGot exception while uploading -- saving description to %s\n' \ |
| 832 % backup_path | 919 % backup_path |
| 833 backup_file = open(backup_path, 'w') | 920 backup_file = open(backup_path, 'w') |
| 834 backup_file.write(change_desc) | 921 backup_file.write(change_desc.description) |
| 835 backup_file.close() | 922 backup_file.close() |
| 836 raise | 923 raise |
| 837 | 924 |
| 838 if not cl.GetIssue(): | 925 if not cl.GetIssue(): |
| 839 cl.SetIssue(issue) | 926 cl.SetIssue(issue) |
| 840 cl.SetPatchset(patchset) | 927 cl.SetPatchset(patchset) |
| 841 return 0 | 928 return 0 |
| 842 | 929 |
| 843 | 930 |
| 844 def SendUpstream(parser, args, cmd): | 931 def SendUpstream(parser, args, cmd): |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 892 svn_head = RunGit(['log', '--grep=^git-svn-id:', '-1', | 979 svn_head = RunGit(['log', '--grep=^git-svn-id:', '-1', |
| 893 '--pretty=format:%H']) | 980 '--pretty=format:%H']) |
| 894 extra_commits = RunGit(['rev-list', '^' + svn_head, base_branch]) | 981 extra_commits = RunGit(['rev-list', '^' + svn_head, base_branch]) |
| 895 if extra_commits: | 982 if extra_commits: |
| 896 print ('This branch has %d additional commits not upstreamed yet.' | 983 print ('This branch has %d additional commits not upstreamed yet.' |
| 897 % len(extra_commits.splitlines())) | 984 % len(extra_commits.splitlines())) |
| 898 print ('Upstream "%s" or rebase this branch on top of the upstream trunk ' | 985 print ('Upstream "%s" or rebase this branch on top of the upstream trunk ' |
| 899 'before attempting to %s.' % (base_branch, cmd)) | 986 'before attempting to %s.' % (base_branch, cmd)) |
| 900 return 1 | 987 return 1 |
| 901 | 988 |
| 902 if not options.force and not options.bypass_hooks: | 989 if not options.bypass_hooks: |
| 903 RunHook(PREDCOMMIT_HOOK, upstream_branch=base_branch, error_ok=False) | 990 RunHook(PREDCOMMIT_HOOK, upstream_branch=base_branch, |
| 991 rietveld_server=cl.GetRietveldServer(), tbr=options.tbr, |
| 992 error_ok=False) |
| 904 | 993 |
| 905 if cmd == 'dcommit': | 994 if cmd == 'dcommit': |
| 906 # Check the tree status if the tree status URL is set. | 995 # Check the tree status if the tree status URL is set. |
| 907 status = GetTreeStatus() | 996 status = GetTreeStatus() |
| 908 if 'closed' == status: | 997 if 'closed' == status: |
| 909 print ('The tree is closed. Please wait for it to reopen. Use ' | 998 print ('The tree is closed. Please wait for it to reopen. Use ' |
| 910 '"git cl dcommit -f" to commit on a closed tree.') | 999 '"git cl dcommit -f" to commit on a closed tree.') |
| 911 return 1 | 1000 return 1 |
| 912 elif 'unknown' == status: | 1001 elif 'unknown' == status: |
| 913 print ('Unable to determine tree status. Please verify manually and ' | 1002 print ('Unable to determine tree status. Please verify manually and ' |
| (...skipping 19 matching lines...) Expand all Loading... |
| 933 | 1022 |
| 934 description += "\n\nReview URL: %s" % cl.GetIssueURL() | 1023 description += "\n\nReview URL: %s" % cl.GetIssueURL() |
| 935 else: | 1024 else: |
| 936 if not description: | 1025 if not description: |
| 937 # Submitting TBR. See if there's already a description in Rietveld, else | 1026 # Submitting TBR. See if there's already a description in Rietveld, else |
| 938 # create a template description. Eitherway, give the user a chance to edit | 1027 # create a template description. Eitherway, give the user a chance to edit |
| 939 # it to fill in the TBR= field. | 1028 # it to fill in the TBR= field. |
| 940 if cl.GetIssue(): | 1029 if cl.GetIssue(): |
| 941 description = cl.GetDescription() | 1030 description = cl.GetDescription() |
| 942 | 1031 |
| 1032 # TODO(dpranke): Update to use ChangeDescription object. |
| 943 if not description: | 1033 if not description: |
| 944 description = """# Enter a description of the change. | 1034 description = """# Enter a description of the change. |
| 945 # This will be used as the change log for the commit. | 1035 # This will be used as the change log for the commit. |
| 946 | 1036 |
| 947 """ | 1037 """ |
| 948 description += CreateDescriptionFromLog(args) | 1038 description += CreateDescriptionFromLog(args) |
| 949 | 1039 |
| 950 description = UserEditedLog(description + '\nTBR=') | 1040 description = UserEditedLog(description + '\nTBR=') |
| 951 | 1041 |
| 952 if not description: | 1042 if not description: |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1024 if viewvc_url and revision: | 1114 if viewvc_url and revision: |
| 1025 cl.description += ('\n\nCommitted: ' + viewvc_url + revision) | 1115 cl.description += ('\n\nCommitted: ' + viewvc_url + revision) |
| 1026 print ('Closing issue ' | 1116 print ('Closing issue ' |
| 1027 '(you may be prompted for your codereview password)...') | 1117 '(you may be prompted for your codereview password)...') |
| 1028 cl.CloseIssue() | 1118 cl.CloseIssue() |
| 1029 cl.SetIssue(0) | 1119 cl.SetIssue(0) |
| 1030 | 1120 |
| 1031 if retcode == 0: | 1121 if retcode == 0: |
| 1032 hook = POSTUPSTREAM_HOOK_PATTERN % cmd | 1122 hook = POSTUPSTREAM_HOOK_PATTERN % cmd |
| 1033 if os.path.isfile(hook): | 1123 if os.path.isfile(hook): |
| 1034 RunHook(hook, upstream_branch=base_branch, error_ok=True) | 1124 RunHook(hook, upstream_branch=base_branch, |
| 1035 | 1125 rietveld_server=cl.GetRietveldServer(), tbr=options.tbr, |
| 1126 error_ok=True) |
| 1036 return 0 | 1127 return 0 |
| 1037 | 1128 |
| 1038 | 1129 |
| 1039 @usage('[upstream branch to apply against]') | 1130 @usage('[upstream branch to apply against]') |
| 1040 def CMDdcommit(parser, args): | 1131 def CMDdcommit(parser, args): |
| 1041 """commit the current changelist via git-svn""" | 1132 """commit the current changelist via git-svn""" |
| 1042 if not settings.GetIsGitSvn(): | 1133 if not settings.GetIsGitSvn(): |
| 1043 message = """This doesn't appear to be an SVN repository. | 1134 message = """This doesn't appear to be an SVN repository. |
| 1044 If your project has a git mirror with an upstream SVN master, you probably need | 1135 If your project has a git mirror with an upstream SVN master, you probably need |
| 1045 to run 'git svn init', see your project's git mirror documentation. | 1136 to run 'git svn init', see your project's git mirror documentation. |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1279 ('AppEngine is misbehaving and returned HTTP %d, again. Keep faith ' | 1370 ('AppEngine is misbehaving and returned HTTP %d, again. Keep faith ' |
| 1280 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) | 1371 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) |
| 1281 | 1372 |
| 1282 # Not a known command. Default to help. | 1373 # Not a known command. Default to help. |
| 1283 GenUsage(parser, 'help') | 1374 GenUsage(parser, 'help') |
| 1284 return CMDhelp(parser, argv) | 1375 return CMDhelp(parser, argv) |
| 1285 | 1376 |
| 1286 | 1377 |
| 1287 if __name__ == '__main__': | 1378 if __name__ == '__main__': |
| 1288 sys.exit(main(sys.argv[1:])) | 1379 sys.exit(main(sys.argv[1:])) |
| OLD | NEW |