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 |