Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(300)

Side by Side Diff: git_cl.py

Issue 9264065: Add minimal Gerrit support to 'git cl config' and 'git cl upload' (Closed) Base URL: svn://chrome-svn/chrome/trunk/tools/depot_tools/
Patch Set: '' Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/git_cl_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 = None
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
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 self.is_gerrit is None:
271 self.is_gerrit = self._GetConfig('gerrit.host', error_ok=True)
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
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
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
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.
M-A Ruel 2012/02/01 15:50:35 What about CL pipelining? Why not just get the bra
ukai 2012/02/02 04:21:59 I'm new to gerrit and don't know how to do it yet.
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)
M-A Ruel 2012/02/01 15:50:35 Why can't you reuse the parsing code? It'd be nice
ukai 2012/02/02 04:21:59 Done.
904 reviewers = filter(None, ','.join(
905 i.group(2).strip()
906 for i in reviewer_regexp.finditer(description)).split(','))
907 if options.reviewers:
908 reviewers += filter(None, options.reviewers.split(','))
909 if reviewers:
910 receive_options += ['--reviewer=' + email for email in reviewers]
911
912 git_command = ['push']
913 if receive_options:
914 git_command.append('--receive-pack=git receive-pack ' +
915 ' '.join(receive_options))
916 git_command += [remote, 'HEAD:refs/for/' + branch]
917 RunGit(git_command)
918 return 0
919
920
866 @usage('[args to "git diff"]') 921 @usage('[args to "git diff"]')
867 def CMDupload(parser, args): 922 def CMDupload(parser, args):
868 """upload the current changelist to codereview""" 923 """upload the current changelist to codereview"""
869 parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks', 924 parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks',
870 help='bypass upload presubmit hook') 925 help='bypass upload presubmit hook')
871 parser.add_option('-f', action='store_true', dest='force', 926 parser.add_option('-f', action='store_true', dest='force',
872 help="force yes to questions (don't prompt)") 927 help="force yes to questions (don't prompt)")
873 parser.add_option('-m', dest='message', help='message for patch') 928 parser.add_option('-m', dest='message', help='message for patch')
874 parser.add_option('-r', '--reviewers', 929 parser.add_option('-r', '--reviewers',
875 help='reviewer email addresses') 930 help='reviewer email addresses')
(...skipping 13 matching lines...) Expand all
889 (options, args) = parser.parse_args(args) 944 (options, args) = parser.parse_args(args)
890 945
891 # Make sure index is up-to-date before running diff-index. 946 # Make sure index is up-to-date before running diff-index.
892 RunGit(['update-index', '--refresh', '-q'], error_ok=True) 947 RunGit(['update-index', '--refresh', '-q'], error_ok=True)
893 if RunGit(['diff-index', 'HEAD']): 948 if RunGit(['diff-index', 'HEAD']):
894 print 'Cannot upload with a dirty tree. You must commit locally first.' 949 print 'Cannot upload with a dirty tree. You must commit locally first.'
895 return 1 950 return 1
896 951
897 cl = Changelist() 952 cl = Changelist()
898 if args: 953 if args:
954 # TODO(ukai): is it ok for gerrit case?
899 base_branch = args[0] 955 base_branch = args[0]
900 else: 956 else:
901 # Default to diffing against the "upstream" branch. 957 # Default to diffing against the "upstream" branch.
902 base_branch = cl.GetUpstreamBranch() 958 base_branch = cl.GetUpstreamBranch()
903 args = [base_branch + "..."] 959 if settings.GetIsGerrit():
960 args = ['master']
M-A Ruel 2012/02/01 15:50:35 Why?
ukai 2012/02/02 04:21:59 I initially thought args[0] to be used for target
961 else:
962 args = [base_branch + "..."]
904 963
905 if not options.bypass_hooks: 964 if not options.bypass_hooks:
906 hook_results = cl.RunHook(committing=False, upstream_branch=base_branch, 965 hook_results = cl.RunHook(committing=False, upstream_branch=base_branch,
907 may_prompt=not options.force, 966 may_prompt=not options.force,
908 verbose=options.verbose, 967 verbose=options.verbose,
909 author=None) 968 author=None)
910 if not hook_results.should_continue(): 969 if not hook_results.should_continue():
911 return 1 970 return 1
912 if not options.reviewers and hook_results.reviewers: 971 if not options.reviewers and hook_results.reviewers:
913 options.reviewers = hook_results.reviewers 972 options.reviewers = hook_results.reviewers
914 973
915 # --no-ext-diff is broken in some versions of Git, so try to work around 974 # --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 975 # this by overriding the environment (but there is still a problem if the
917 # git config key "diff.external" is used). 976 # git config key "diff.external" is used).
918 env = os.environ.copy() 977 env = os.environ.copy()
919 if 'GIT_EXTERNAL_DIFF' in env: 978 if 'GIT_EXTERNAL_DIFF' in env:
920 del env['GIT_EXTERNAL_DIFF'] 979 del env['GIT_EXTERNAL_DIFF']
921 subprocess2.call( 980 subprocess2.call(
922 ['git', 'diff', '--no-ext-diff', '--stat', '-M'] + args, env=env) 981 ['git', 'diff', '--no-ext-diff', '--stat', '-M'] + args, env=env)
923 982
983 if settings.GetIsGerrit():
984 GerritUpload(options, args, cl)
985 # TODO(ukai): parse Change-Id: and set issue number?
986 return 0
987
924 upload_args = ['--assume_yes'] # Don't ask about untracked files. 988 upload_args = ['--assume_yes'] # Don't ask about untracked files.
M-A Ruel 2012/02/01 15:50:35 I'd rather move the rest into RietveldUpload to ma
ukai 2012/02/02 04:21:59 Done.
925 upload_args.extend(['--server', cl.GetRietveldServer()]) 989 upload_args.extend(['--server', cl.GetRietveldServer()])
926 if options.emulate_svn_auto_props: 990 if options.emulate_svn_auto_props:
927 upload_args.append('--emulate_svn_auto_props') 991 upload_args.append('--emulate_svn_auto_props')
928 if options.from_logs and not options.message: 992 if options.from_logs and not options.message:
929 print 'Must set message for subject line if using desc_from_logs' 993 print 'Must set message for subject line if using desc_from_logs'
930 return 1 994 return 1
931 995
932 change_desc = None 996 change_desc = None
933 997
934 if cl.GetIssue(): 998 if cl.GetIssue():
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after
1222 help='allow failed patches and spew .rej files') 1286 help='allow failed patches and spew .rej files')
1223 parser.add_option('-n', '--no-commit', action='store_true', dest='nocommit', 1287 parser.add_option('-n', '--no-commit', action='store_true', dest='nocommit',
1224 help="don't commit after patch applies") 1288 help="don't commit after patch applies")
1225 (options, args) = parser.parse_args(args) 1289 (options, args) = parser.parse_args(args)
1226 if len(args) != 1: 1290 if len(args) != 1:
1227 parser.print_help() 1291 parser.print_help()
1228 return 1 1292 return 1
1229 issue_arg = args[0] 1293 issue_arg = args[0]
1230 1294
1231 # TODO(maruel): Use apply_issue.py 1295 # TODO(maruel): Use apply_issue.py
1296 # TODO(ukai): use gerrit-cherry-pick for gerrit repository?
1232 1297
1233 if re.match(r'\d+', issue_arg): 1298 if re.match(r'\d+', issue_arg):
1234 # Input is an issue id. Figure out the URL. 1299 # Input is an issue id. Figure out the URL.
1235 issue = issue_arg 1300 issue = issue_arg
1236 patch_data = Changelist().GetPatchSetDiff(issue) 1301 patch_data = Changelist().GetPatchSetDiff(issue)
1237 else: 1302 else:
1238 # Assume it's a URL to the patch. Default to https. 1303 # Assume it's a URL to the patch. Default to https.
1239 issue_url = gclient_utils.UpgradeToHttps(issue_arg) 1304 issue_url = gclient_utils.UpgradeToHttps(issue_arg)
1240 match = re.match(r'.*?/issue(\d+)_\d+.diff', issue_url) 1305 match = re.match(r'.*?/issue(\d+)_\d+.diff', issue_url)
1241 if not match: 1306 if not match:
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
1428 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) 1493 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e)))
1429 1494
1430 # Not a known command. Default to help. 1495 # Not a known command. Default to help.
1431 GenUsage(parser, 'help') 1496 GenUsage(parser, 'help')
1432 return CMDhelp(parser, argv) 1497 return CMDhelp(parser, argv)
1433 1498
1434 1499
1435 if __name__ == '__main__': 1500 if __name__ == '__main__':
1436 fix_encoding.fix_encoding() 1501 fix_encoding.fix_encoding()
1437 sys.exit(main(sys.argv[1:])) 1502 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « no previous file | tests/git_cl_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698