| 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.""" | 8 """A git-command for integrating reviews on Rietveld.""" |
| 9 | 9 |
| 10 import logging | 10 import logging |
| (...skipping 604 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 615 SetProperty(settings.GetTreeStatusUrl(error_ok=True), 'Tree status URL', | 615 SetProperty(settings.GetTreeStatusUrl(error_ok=True), 'Tree status URL', |
| 616 'tree-status-url', False) | 616 'tree-status-url', False) |
| 617 SetProperty(settings.GetViewVCUrl(), 'ViewVC URL', 'viewvc-url', True) | 617 SetProperty(settings.GetViewVCUrl(), 'ViewVC URL', 'viewvc-url', True) |
| 618 | 618 |
| 619 # TODO: configure a default branch to diff against, rather than this | 619 # TODO: configure a default branch to diff against, rather than this |
| 620 # svn-based hackery. | 620 # svn-based hackery. |
| 621 | 621 |
| 622 | 622 |
| 623 class ChangeDescription(object): | 623 class ChangeDescription(object): |
| 624 """Contains a parsed form of the change description.""" | 624 """Contains a parsed form of the change description.""" |
| 625 def __init__(self, subject, log_desc, reviewers): | 625 def __init__(self, log_desc, reviewers): |
| 626 self.subject = subject | |
| 627 self.log_desc = log_desc | 626 self.log_desc = log_desc |
| 628 self.reviewers = reviewers | 627 self.reviewers = reviewers |
| 629 self.description = self.log_desc | 628 self.description = self.log_desc |
| 630 | 629 |
| 631 def Update(self): | 630 def Prompt(self): |
| 632 initial_text = """# Enter a description of the change. | 631 content = """# Enter a description of the change. |
| 633 # This will displayed on the codereview site. | 632 # This will displayed on the codereview site. |
| 634 # The first line will also be used as the subject of the review. | 633 # The first line will also be used as the subject of the review. |
| 635 """ | 634 """ |
| 636 initial_text += self.description | 635 content += self.description |
| 637 if ('\nR=' not in self.description and | 636 if ('\nR=' not in self.description and |
| 638 '\nTBR=' not in self.description and | 637 '\nTBR=' not in self.description and |
| 639 self.reviewers): | 638 self.reviewers): |
| 640 initial_text += '\nR=' + self.reviewers | 639 content += '\nR=' + self.reviewers |
| 641 if '\nBUG=' not in self.description: | 640 if '\nBUG=' not in self.description: |
| 642 initial_text += '\nBUG=' | 641 content += '\nBUG=' |
| 643 if '\nTEST=' not in self.description: | 642 if '\nTEST=' not in self.description: |
| 644 initial_text += '\nTEST=' | 643 content += '\nTEST=' |
| 645 initial_text = initial_text.rstrip('\n') + '\n' | 644 content = content.rstrip('\n') + '\n' |
| 646 content = gclient_utils.RunEditor(initial_text, True) | 645 content = gclient_utils.RunEditor(content, True) |
| 647 if not content: | 646 if not content: |
| 648 DieWithError('Running editor failed') | 647 DieWithError('Running editor failed') |
| 649 content = re.compile(r'^#.*$', re.MULTILINE).sub('', content).strip() | 648 content = re.compile(r'^#.*$', re.MULTILINE).sub('', content).strip() |
| 650 if not content: | 649 if not content.strip(): |
| 651 DieWithError('No CL description, aborting') | 650 DieWithError('No CL description, aborting') |
| 652 self.ParseDescription(content) | 651 self.description = content |
| 653 | 652 |
| 654 def ParseDescription(self, description): | 653 def ParseDescription(self): |
| 655 """Updates the list of reviewers and subject from the description.""" | 654 """Updates the list of reviewers and subject from the description.""" |
| 656 if not description: | 655 self.description = self.description.strip('\n') + '\n' |
| 657 self.description = description | |
| 658 return | |
| 659 | |
| 660 self.description = description.strip('\n') + '\n' | |
| 661 self.subject = description.split('\n', 1)[0] | |
| 662 # Retrieves all reviewer lines | 656 # Retrieves all reviewer lines |
| 663 regexp = re.compile(r'^\s*(TBR|R)=(.+)$', re.MULTILINE) | 657 regexp = re.compile(r'^\s*(TBR|R)=(.+)$', re.MULTILINE) |
| 664 self.reviewers = ','.join( | 658 reviewers = ','.join( |
| 665 i.group(2).strip() for i in regexp.finditer(self.description)) | 659 i.group(2).strip() for i in regexp.finditer(self.description)) |
| 660 if reviewers: |
| 661 self.reviewers = reviewers |
| 666 | 662 |
| 667 def IsEmpty(self): | 663 def IsEmpty(self): |
| 668 return not self.description | 664 return not self.description |
| 669 | 665 |
| 670 | 666 |
| 671 def FindCodereviewSettingsFile(filename='codereview.settings'): | 667 def FindCodereviewSettingsFile(filename='codereview.settings'): |
| 672 """Finds the given file starting in the cwd and going up. | 668 """Finds the given file starting in the cwd and going up. |
| 673 | 669 |
| 674 Only looks up to the top of the repository unless an | 670 Only looks up to the top of the repository unless an |
| 675 'inherit-review-settings-ok' file exists in the root of the repository. | 671 'inherit-review-settings-ok' file exists in the root of the repository. |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 857 | 853 |
| 858 def GerritUpload(options, args, cl): | 854 def GerritUpload(options, args, cl): |
| 859 """upload the current branch to gerrit.""" | 855 """upload the current branch to gerrit.""" |
| 860 # We assume the remote called "origin" is the one we want. | 856 # We assume the remote called "origin" is the one we want. |
| 861 # It is probably not worthwhile to support different workflows. | 857 # It is probably not worthwhile to support different workflows. |
| 862 remote = 'origin' | 858 remote = 'origin' |
| 863 branch = 'master' | 859 branch = 'master' |
| 864 if options.target_branch: | 860 if options.target_branch: |
| 865 branch = options.target_branch | 861 branch = options.target_branch |
| 866 | 862 |
| 867 log_desc = CreateDescriptionFromLog(args) | 863 log_desc = options.message or CreateDescriptionFromLog(args) |
| 868 if options.reviewers: | 864 if options.reviewers: |
| 869 log_desc += '\nR=' + options.reviewers | 865 log_desc += '\nR=' + options.reviewers |
| 870 change_desc = ChangeDescription(options.message, log_desc, | 866 change_desc = ChangeDescription(log_desc, options.reviewers) |
| 871 options.reviewers) | 867 change_desc.ParseDescription() |
| 872 change_desc.ParseDescription(log_desc) | |
| 873 if change_desc.IsEmpty(): | 868 if change_desc.IsEmpty(): |
| 874 print "Description is empty; aborting." | 869 print "Description is empty; aborting." |
| 875 return 1 | 870 return 1 |
| 876 | 871 |
| 877 receive_options = [] | 872 receive_options = [] |
| 878 cc = cl.GetCCList().split(',') | 873 cc = cl.GetCCList().split(',') |
| 879 if options.cc: | 874 if options.cc: |
| 880 cc += options.cc.split(',') | 875 cc += options.cc.split(',') |
| 881 cc = filter(None, cc) | 876 cc = filter(None, cc) |
| 882 if cc: | 877 if cc: |
| (...skipping 12 matching lines...) Expand all Loading... |
| 895 # TODO(ukai): parse Change-Id: and set issue number? | 890 # TODO(ukai): parse Change-Id: and set issue number? |
| 896 return 0 | 891 return 0 |
| 897 | 892 |
| 898 | 893 |
| 899 def RietveldUpload(options, args, cl): | 894 def RietveldUpload(options, args, cl): |
| 900 """upload the patch to rietveld.""" | 895 """upload the patch to rietveld.""" |
| 901 upload_args = ['--assume_yes'] # Don't ask about untracked files. | 896 upload_args = ['--assume_yes'] # Don't ask about untracked files. |
| 902 upload_args.extend(['--server', cl.GetRietveldServer()]) | 897 upload_args.extend(['--server', cl.GetRietveldServer()]) |
| 903 if options.emulate_svn_auto_props: | 898 if options.emulate_svn_auto_props: |
| 904 upload_args.append('--emulate_svn_auto_props') | 899 upload_args.append('--emulate_svn_auto_props') |
| 905 if options.from_logs and not options.message: | |
| 906 print 'Must set message for subject line if using desc_from_logs' | |
| 907 return 1 | |
| 908 | 900 |
| 909 change_desc = None | 901 change_desc = None |
| 910 | 902 |
| 911 if cl.GetIssue(): | 903 if cl.GetIssue(): |
| 912 if options.message: | 904 if options.message: |
| 913 upload_args.extend(['--message', options.message]) | 905 upload_args.extend(['--message', options.message]) |
| 914 upload_args.extend(['--issue', cl.GetIssue()]) | 906 upload_args.extend(['--issue', cl.GetIssue()]) |
| 915 print ("This branch is associated with issue %s. " | 907 print ("This branch is associated with issue %s. " |
| 916 "Adding patch to that issue." % cl.GetIssue()) | 908 "Adding patch to that issue." % cl.GetIssue()) |
| 917 else: | 909 else: |
| 918 log_desc = CreateDescriptionFromLog(args) | 910 message = options.message or CreateDescriptionFromLog(args) |
| 919 change_desc = ChangeDescription(options.message, log_desc, | 911 change_desc = ChangeDescription(message, options.reviewers) |
| 920 options.reviewers) | 912 if not options.force: |
| 921 if not options.from_logs: | 913 change_desc.Prompt() |
| 922 change_desc.Update() | 914 change_desc.ParseDescription() |
| 923 | 915 |
| 924 if change_desc.IsEmpty(): | 916 if change_desc.IsEmpty(): |
| 925 print "Description is empty; aborting." | 917 print "Description is empty; aborting." |
| 926 return 1 | 918 return 1 |
| 927 | 919 |
| 928 upload_args.extend(['--message', change_desc.subject]) | 920 upload_args.extend(['--message', change_desc.description]) |
| 929 upload_args.extend(['--description', change_desc.description]) | |
| 930 if change_desc.reviewers: | 921 if change_desc.reviewers: |
| 931 upload_args.extend(['--reviewers', change_desc.reviewers]) | 922 upload_args.extend(['--reviewers', change_desc.reviewers]) |
| 932 if options.send_mail: | 923 if options.send_mail: |
| 933 if not change_desc.reviewers: | 924 if not change_desc.reviewers: |
| 934 DieWithError("Must specify reviewers to send email.") | 925 DieWithError("Must specify reviewers to send email.") |
| 935 upload_args.append('--send_mail') | 926 upload_args.append('--send_mail') |
| 936 cc = ','.join(filter(None, (cl.GetCCList(), options.cc))) | 927 cc = ','.join(filter(None, (cl.GetCCList(), options.cc))) |
| 937 if cc: | 928 if cc: |
| 938 upload_args.extend(['--cc', cc]) | 929 upload_args.extend(['--cc', cc]) |
| 939 | 930 |
| (...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1473 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) | 1464 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) |
| 1474 | 1465 |
| 1475 # Not a known command. Default to help. | 1466 # Not a known command. Default to help. |
| 1476 GenUsage(parser, 'help') | 1467 GenUsage(parser, 'help') |
| 1477 return CMDhelp(parser, argv) | 1468 return CMDhelp(parser, argv) |
| 1478 | 1469 |
| 1479 | 1470 |
| 1480 if __name__ == '__main__': | 1471 if __name__ == '__main__': |
| 1481 fix_encoding.fix_encoding() | 1472 fix_encoding.fix_encoding() |
| 1482 sys.exit(main(sys.argv[1:])) | 1473 sys.exit(main(sys.argv[1:])) |
| OLD | NEW |