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 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
140 def __init__(self): | 140 def __init__(self): |
141 self.default_server = None | 141 self.default_server = None |
142 self.cc = None | 142 self.cc = None |
143 self.root = None | 143 self.root = None |
144 self.is_git_svn = None | 144 self.is_git_svn = None |
145 self.svn_branch = None | 145 self.svn_branch = None |
146 self.tree_status_url = None | 146 self.tree_status_url = None |
147 self.viewvc_url = None | 147 self.viewvc_url = None |
148 self.updated = False | 148 self.updated = False |
149 self.did_migrate_check = False | 149 self.did_migrate_check = False |
150 self.is_gerrit = False | |
Evan Martin
2012/01/31 19:07:56
Set this to None here...
ukai
2012/02/01 05:57:15
Done.
| |
150 | 151 |
151 def LazyUpdateIfNeeded(self): | 152 def LazyUpdateIfNeeded(self): |
152 """Updates the settings from a codereview.settings file, if available.""" | 153 """Updates the settings from a codereview.settings file, if available.""" |
153 if not self.updated: | 154 if not self.updated: |
154 cr_settings_file = FindCodereviewSettingsFile() | 155 cr_settings_file = FindCodereviewSettingsFile() |
155 if cr_settings_file: | 156 if cr_settings_file: |
156 LoadCodereviewSettingsFromFile(cr_settings_file) | 157 LoadCodereviewSettingsFromFile(cr_settings_file) |
157 self.updated = True | 158 self.updated = True |
158 | 159 |
159 def GetDefaultServerUrl(self, error_ok=False): | 160 def GetDefaultServerUrl(self, error_ok=False): |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
257 | 258 |
258 def GetViewVCUrl(self): | 259 def GetViewVCUrl(self): |
259 if not self.viewvc_url: | 260 if not self.viewvc_url: |
260 self.viewvc_url = gclient_utils.UpgradeToHttps( | 261 self.viewvc_url = gclient_utils.UpgradeToHttps( |
261 self._GetConfig('rietveld.viewvc-url', error_ok=True)) | 262 self._GetConfig('rietveld.viewvc-url', error_ok=True)) |
262 return self.viewvc_url | 263 return self.viewvc_url |
263 | 264 |
264 def GetDefaultCCList(self): | 265 def GetDefaultCCList(self): |
265 return self._GetConfig('rietveld.cc', error_ok=True) | 266 return self._GetConfig('rietveld.cc', error_ok=True) |
266 | 267 |
268 def GetIsGerrit(self): | |
269 """Return true if this repo is assosiated with gerrit code review system.""" | |
270 if not self.is_gerrit: | |
271 self.is_gerrit = self._GetConfig('gerrit.host', error_ok=True) | |
Evan Martin
2012/01/31 19:07:56
...so that here we can change this test to
if se
ukai
2012/02/01 05:57:15
Done.
| |
272 return self.is_gerrit | |
273 | |
267 def _GetConfig(self, param, **kwargs): | 274 def _GetConfig(self, param, **kwargs): |
268 self.LazyUpdateIfNeeded() | 275 self.LazyUpdateIfNeeded() |
269 return RunGit(['config', param], **kwargs).strip() | 276 return RunGit(['config', param], **kwargs).strip() |
270 | 277 |
271 | 278 |
272 def CheckForMigration(): | 279 def CheckForMigration(): |
273 """Migrate from the old issue format, if found. | 280 """Migrate from the old issue format, if found. |
274 | 281 |
275 We used to store the branch<->issue mapping in a file in .git, but it's | 282 We used to store the branch<->issue mapping in a file in .git, but it's |
276 better to store it in the .git/config, since deleting a branch deletes that | 283 better to store it in the .git/config, since deleting a branch deletes that |
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
597 """Return the git setting that stores this change's most recent patchset.""" | 604 """Return the git setting that stores this change's most recent patchset.""" |
598 return 'branch.%s.rietveldpatchset' % self.GetBranch() | 605 return 'branch.%s.rietveldpatchset' % self.GetBranch() |
599 | 606 |
600 def _RietveldServer(self): | 607 def _RietveldServer(self): |
601 """Returns the git setting that stores this change's rietveld server.""" | 608 """Returns the git setting that stores this change's rietveld server.""" |
602 return 'branch.%s.rietveldserver' % self.GetBranch() | 609 return 'branch.%s.rietveldserver' % self.GetBranch() |
603 | 610 |
604 | 611 |
605 def GetCodereviewSettingsInteractively(): | 612 def GetCodereviewSettingsInteractively(): |
606 """Prompt the user for settings.""" | 613 """Prompt the user for settings.""" |
614 # TODO(ukai): ask code review system is rietveld or gerrit? | |
607 server = settings.GetDefaultServerUrl(error_ok=True) | 615 server = settings.GetDefaultServerUrl(error_ok=True) |
608 prompt = 'Rietveld server (host[:port])' | 616 prompt = 'Rietveld server (host[:port])' |
609 prompt += ' [%s]' % (server or DEFAULT_SERVER) | 617 prompt += ' [%s]' % (server or DEFAULT_SERVER) |
610 newserver = ask_for_data(prompt + ':') | 618 newserver = ask_for_data(prompt + ':') |
611 if not server and not newserver: | 619 if not server and not newserver: |
612 newserver = DEFAULT_SERVER | 620 newserver = DEFAULT_SERVER |
613 if newserver: | 621 if newserver: |
614 newserver = gclient_utils.UpgradeToHttps(newserver) | 622 newserver = gclient_utils.UpgradeToHttps(newserver) |
615 if newserver != server: | 623 if newserver != server: |
616 RunGit(['config', 'rietveld.server', newserver]) | 624 RunGit(['config', 'rietveld.server', newserver]) |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
716 else: | 724 else: |
717 RunGit(['config', '--unset-all', fullname], error_ok=unset_error_ok) | 725 RunGit(['config', '--unset-all', fullname], error_ok=unset_error_ok) |
718 | 726 |
719 SetProperty('server', 'CODE_REVIEW_SERVER') | 727 SetProperty('server', 'CODE_REVIEW_SERVER') |
720 # Only server setting is required. Other settings can be absent. | 728 # Only server setting is required. Other settings can be absent. |
721 # In that case, we ignore errors raised during option deletion attempt. | 729 # In that case, we ignore errors raised during option deletion attempt. |
722 SetProperty('cc', 'CC_LIST', unset_error_ok=True) | 730 SetProperty('cc', 'CC_LIST', unset_error_ok=True) |
723 SetProperty('tree-status-url', 'STATUS', unset_error_ok=True) | 731 SetProperty('tree-status-url', 'STATUS', unset_error_ok=True) |
724 SetProperty('viewvc-url', 'VIEW_VC', unset_error_ok=True) | 732 SetProperty('viewvc-url', 'VIEW_VC', unset_error_ok=True) |
725 | 733 |
734 if 'GERRIT_HOST' in keyvals and 'GERRIT_PORT' in keyvals: | |
735 RunGit(['config', 'gerrit.host', keyvals['GERRIT_HOST']]) | |
736 RunGit(['config', 'gerrit.port', keyvals['GERRIT_PORT']]) | |
737 # Install the standard commit-msg hook. | |
738 RunCommand(['scp', '-p', '-P', keyvals['GERRIT_PORT'], | |
739 '%s:hooks/commit-msg' % keyvals['GERRIT_HOST'], | |
740 os.path.join(settings.GetRoot(), | |
741 '.git', 'hooks', 'commit-msg')]) | |
742 | |
726 if 'PUSH_URL_CONFIG' in keyvals and 'ORIGIN_URL_CONFIG' in keyvals: | 743 if 'PUSH_URL_CONFIG' in keyvals and 'ORIGIN_URL_CONFIG' in keyvals: |
727 #should be of the form | 744 #should be of the form |
728 #PUSH_URL_CONFIG: url.ssh://gitrw.chromium.org.pushinsteadof | 745 #PUSH_URL_CONFIG: url.ssh://gitrw.chromium.org.pushinsteadof |
729 #ORIGIN_URL_CONFIG: http://src.chromium.org/git | 746 #ORIGIN_URL_CONFIG: http://src.chromium.org/git |
730 RunGit(['config', keyvals['PUSH_URL_CONFIG'], | 747 RunGit(['config', keyvals['PUSH_URL_CONFIG'], |
731 keyvals['ORIGIN_URL_CONFIG']]) | 748 keyvals['ORIGIN_URL_CONFIG']]) |
732 | 749 |
733 | 750 |
734 @usage('[repo root containing codereview.settings]') | 751 @usage('[repo root containing codereview.settings]') |
735 def CMDconfig(parser, args): | 752 def CMDconfig(parser, args): |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
856 else: | 873 else: |
857 # Default to diffing against the "upstream" branch. | 874 # Default to diffing against the "upstream" branch. |
858 base_branch = cl.GetUpstreamBranch() | 875 base_branch = cl.GetUpstreamBranch() |
859 | 876 |
860 cl.RunHook(committing=not options.upload, upstream_branch=base_branch, | 877 cl.RunHook(committing=not options.upload, upstream_branch=base_branch, |
861 may_prompt=False, verbose=options.verbose, | 878 may_prompt=False, verbose=options.verbose, |
862 author=None) | 879 author=None) |
863 return 0 | 880 return 0 |
864 | 881 |
865 | 882 |
883 def GerritUpload(options, args, cl): | |
884 """upload the current branch to gerrit.""" | |
885 # We assume the remote called "origin" is the one we want. | |
886 # It is probably not worthwhile to support different workflows. | |
887 remote = 'origin' | |
888 branch = 'master' | |
889 if args: | |
890 branch = args[0] | |
891 | |
892 description = RunCommand(['git', 'log', '--pretty=format:%s%n%n%b', | |
893 '%s...' % (branch)]).strip() | |
894 | |
895 receive_options = [] | |
896 cc = [] | |
897 if options.cc: | |
898 cc = options.cc.split(',') | |
899 cc = filter(None, (cl.GetCCList(), cc)) | |
900 if cc: | |
901 receive_options += ['--cc=' + email for email in cc] | |
902 # Retrieves all reviewer lines | |
903 reviewer_regexp = re.compile(r'^\s*(TBR|R)=(.+)$', re.MULTILINE) | |
904 reviewers = ','.join( | |
905 i.group(2).strip() | |
906 for i in reviewer_regexp.finditer(description)).split(',') | |
907 print reviewers | |
Evan Martin
2012/01/31 19:07:56
Probably don't mean to print here.
ukai
2012/02/01 05:57:15
Done.
| |
908 if options.reviewers: | |
909 reviewers = options.reviewers.split(',') | |
910 if reviewers: | |
911 receive_options += ['--reviewer=' + email for email in reviewers] | |
912 | |
913 git_command = ['push'] | |
914 if receive_options: | |
915 git_command.append('--receive-pack=git receive-pack ' + | |
Evan Martin
2012/01/31 19:07:56
This has a space in the argument. I don't think it
Roland McGrath
2012/01/31 19:24:21
No, it has to be this way.
ukai
2012/02/01 05:57:15
we pass "git receive-pack --reviewer=.." as value
| |
916 ' '.join(receive_options)) | |
917 git_command += [remote, 'HEAD:refs/for/' + branch] | |
918 RunGit(git_command) | |
919 return 0 | |
920 | |
921 | |
866 @usage('[args to "git diff"]') | 922 @usage('[args to "git diff"]') |
867 def CMDupload(parser, args): | 923 def CMDupload(parser, args): |
868 """upload the current changelist to codereview""" | 924 """upload the current changelist to codereview""" |
869 parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks', | 925 parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks', |
870 help='bypass upload presubmit hook') | 926 help='bypass upload presubmit hook') |
871 parser.add_option('-f', action='store_true', dest='force', | 927 parser.add_option('-f', action='store_true', dest='force', |
872 help="force yes to questions (don't prompt)") | 928 help="force yes to questions (don't prompt)") |
873 parser.add_option('-m', dest='message', help='message for patch') | 929 parser.add_option('-m', dest='message', help='message for patch') |
874 parser.add_option('-r', '--reviewers', | 930 parser.add_option('-r', '--reviewers', |
875 help='reviewer email addresses') | 931 help='reviewer email addresses') |
(...skipping 13 matching lines...) Expand all Loading... | |
889 (options, args) = parser.parse_args(args) | 945 (options, args) = parser.parse_args(args) |
890 | 946 |
891 # Make sure index is up-to-date before running diff-index. | 947 # Make sure index is up-to-date before running diff-index. |
892 RunGit(['update-index', '--refresh', '-q'], error_ok=True) | 948 RunGit(['update-index', '--refresh', '-q'], error_ok=True) |
893 if RunGit(['diff-index', 'HEAD']): | 949 if RunGit(['diff-index', 'HEAD']): |
894 print 'Cannot upload with a dirty tree. You must commit locally first.' | 950 print 'Cannot upload with a dirty tree. You must commit locally first.' |
895 return 1 | 951 return 1 |
896 | 952 |
897 cl = Changelist() | 953 cl = Changelist() |
898 if args: | 954 if args: |
955 # TODO(ukai): is it ok for gerrit case? | |
899 base_branch = args[0] | 956 base_branch = args[0] |
900 else: | 957 else: |
901 # Default to diffing against the "upstream" branch. | 958 # Default to diffing against the "upstream" branch. |
902 base_branch = cl.GetUpstreamBranch() | 959 base_branch = cl.GetUpstreamBranch() |
903 args = [base_branch + "..."] | 960 if settings.GetIsGerrit(): |
961 args = ['master'] | |
962 else: | |
963 args = [base_branch + "..."] | |
904 | 964 |
905 if not options.bypass_hooks: | 965 if not options.bypass_hooks: |
906 hook_results = cl.RunHook(committing=False, upstream_branch=base_branch, | 966 hook_results = cl.RunHook(committing=False, upstream_branch=base_branch, |
907 may_prompt=not options.force, | 967 may_prompt=not options.force, |
908 verbose=options.verbose, | 968 verbose=options.verbose, |
909 author=None) | 969 author=None) |
910 if not hook_results.should_continue(): | 970 if not hook_results.should_continue(): |
911 return 1 | 971 return 1 |
912 if not options.reviewers and hook_results.reviewers: | 972 if not options.reviewers and hook_results.reviewers: |
913 options.reviewers = hook_results.reviewers | 973 options.reviewers = hook_results.reviewers |
914 | 974 |
915 # --no-ext-diff is broken in some versions of Git, so try to work around | 975 # --no-ext-diff is broken in some versions of Git, so try to work around |
916 # this by overriding the environment (but there is still a problem if the | 976 # this by overriding the environment (but there is still a problem if the |
917 # git config key "diff.external" is used). | 977 # git config key "diff.external" is used). |
918 env = os.environ.copy() | 978 env = os.environ.copy() |
919 if 'GIT_EXTERNAL_DIFF' in env: | 979 if 'GIT_EXTERNAL_DIFF' in env: |
920 del env['GIT_EXTERNAL_DIFF'] | 980 del env['GIT_EXTERNAL_DIFF'] |
921 subprocess2.call( | 981 subprocess2.call( |
922 ['git', 'diff', '--no-ext-diff', '--stat', '-M'] + args, env=env) | 982 ['git', 'diff', '--no-ext-diff', '--stat', '-M'] + args, env=env) |
923 | 983 |
984 if settings.GetIsGerrit(): | |
985 GerritUpload(options, args, cl) | |
986 # TODO(ukai): parse Change-Id: and set issue number? | |
987 return 0 | |
988 | |
924 upload_args = ['--assume_yes'] # Don't ask about untracked files. | 989 upload_args = ['--assume_yes'] # Don't ask about untracked files. |
925 upload_args.extend(['--server', cl.GetRietveldServer()]) | 990 upload_args.extend(['--server', cl.GetRietveldServer()]) |
926 if options.emulate_svn_auto_props: | 991 if options.emulate_svn_auto_props: |
927 upload_args.append('--emulate_svn_auto_props') | 992 upload_args.append('--emulate_svn_auto_props') |
928 if options.from_logs and not options.message: | 993 if options.from_logs and not options.message: |
929 print 'Must set message for subject line if using desc_from_logs' | 994 print 'Must set message for subject line if using desc_from_logs' |
930 return 1 | 995 return 1 |
931 | 996 |
932 change_desc = None | 997 change_desc = None |
933 | 998 |
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1222 help='allow failed patches and spew .rej files') | 1287 help='allow failed patches and spew .rej files') |
1223 parser.add_option('-n', '--no-commit', action='store_true', dest='nocommit', | 1288 parser.add_option('-n', '--no-commit', action='store_true', dest='nocommit', |
1224 help="don't commit after patch applies") | 1289 help="don't commit after patch applies") |
1225 (options, args) = parser.parse_args(args) | 1290 (options, args) = parser.parse_args(args) |
1226 if len(args) != 1: | 1291 if len(args) != 1: |
1227 parser.print_help() | 1292 parser.print_help() |
1228 return 1 | 1293 return 1 |
1229 issue_arg = args[0] | 1294 issue_arg = args[0] |
1230 | 1295 |
1231 # TODO(maruel): Use apply_issue.py | 1296 # TODO(maruel): Use apply_issue.py |
1297 # TODO(ukai): use gerrit-cherry-pick for gerrit repository? | |
1232 | 1298 |
1233 if re.match(r'\d+', issue_arg): | 1299 if re.match(r'\d+', issue_arg): |
1234 # Input is an issue id. Figure out the URL. | 1300 # Input is an issue id. Figure out the URL. |
1235 issue = issue_arg | 1301 issue = issue_arg |
1236 patch_data = Changelist().GetPatchSetDiff(issue) | 1302 patch_data = Changelist().GetPatchSetDiff(issue) |
1237 else: | 1303 else: |
1238 # Assume it's a URL to the patch. Default to https. | 1304 # Assume it's a URL to the patch. Default to https. |
1239 issue_url = gclient_utils.UpgradeToHttps(issue_arg) | 1305 issue_url = gclient_utils.UpgradeToHttps(issue_arg) |
1240 match = re.match(r'.*?/issue(\d+)_\d+.diff', issue_url) | 1306 match = re.match(r'.*?/issue(\d+)_\d+.diff', issue_url) |
1241 if not match: | 1307 if not match: |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1428 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) | 1494 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) |
1429 | 1495 |
1430 # Not a known command. Default to help. | 1496 # Not a known command. Default to help. |
1431 GenUsage(parser, 'help') | 1497 GenUsage(parser, 'help') |
1432 return CMDhelp(parser, argv) | 1498 return CMDhelp(parser, argv) |
1433 | 1499 |
1434 | 1500 |
1435 if __name__ == '__main__': | 1501 if __name__ == '__main__': |
1436 fix_encoding.fix_encoding() | 1502 fix_encoding.fix_encoding() |
1437 sys.exit(main(sys.argv[1:])) | 1503 sys.exit(main(sys.argv[1:])) |
OLD | NEW |