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

Side by Side Diff: git_cl.py

Issue 1777603002: Gerrit git cl upload: record issue id for a branch. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@G050
Patch Set: Fix presubmit + improve error message. Created 4 years, 9 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
« 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 from distutils.version import LooseVersion 10 from distutils.version import LooseVersion
(...skipping 1065 matching lines...) Expand 10 before | Expand all | Expand 10 after
1076 # with that branch. 1076 # with that branch.
1077 if self.GetIssue(): 1077 if self.GetIssue():
1078 rietveld_server_config = self._RietveldServer() 1078 rietveld_server_config = self._RietveldServer()
1079 if rietveld_server_config: 1079 if rietveld_server_config:
1080 self.rietveld_server = gclient_utils.UpgradeToHttps(RunGit( 1080 self.rietveld_server = gclient_utils.UpgradeToHttps(RunGit(
1081 ['config', rietveld_server_config], error_ok=True).strip()) 1081 ['config', rietveld_server_config], error_ok=True).strip())
1082 if not self.rietveld_server: 1082 if not self.rietveld_server:
1083 self.rietveld_server = settings.GetDefaultServerUrl() 1083 self.rietveld_server = settings.GetDefaultServerUrl()
1084 return self.rietveld_server 1084 return self.rietveld_server
1085 1085
1086 def GetGerritServer(self):
1087 # We don't support multiple Gerrit servers, and assume it to be same as
1088 # origin, except with a '-review' suffix for first subdomain.
1089 parts = urlparse.urlparse(self.GetRemoteUrl()).netloc.split('.')
1090 parts[0] = parts[0] + '-review'
1091 return 'https://%s' % '.'.join(parts)
1092
1086 def GetIssueURL(self): 1093 def GetIssueURL(self):
1087 """Get the URL for a particular issue.""" 1094 """Get the URL for a particular issue."""
1088 if not self.GetIssue(): 1095 if not self.GetIssue():
1089 return None 1096 return None
1097 if settings.GetIsGerrit():
1098 return '%s/%s' % (self.GetGerritServer(), self.GetIssue())
1090 return '%s/%s' % (self.GetRietveldServer(), self.GetIssue()) 1099 return '%s/%s' % (self.GetRietveldServer(), self.GetIssue())
1091 1100
1092 def GetDescription(self, pretty=False): 1101 def GetDescription(self, pretty=False):
1093 if not self.has_description: 1102 if not self.has_description:
1094 if self.GetIssue(): 1103 if self.GetIssue():
1095 issue = self.GetIssue() 1104 issue = self.GetIssue()
1096 try: 1105 try:
1097 self.description = self.RpcServer().get_description(issue).strip() 1106 self.description = self.RpcServer().get_description(issue).strip()
1098 except urllib2.HTTPError as e: 1107 except urllib2.HTTPError as e:
1099 if e.code == 404: 1108 if e.code == 404:
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
1156 else: 1165 else:
1157 self._props = self.RpcServer().get_issue_properties(issue, True) 1166 self._props = self.RpcServer().get_issue_properties(issue, True)
1158 return self._props 1167 return self._props
1159 1168
1160 def GetApprovingReviewers(self): 1169 def GetApprovingReviewers(self):
1161 return get_approving_reviewers(self.GetIssueProperties()) 1170 return get_approving_reviewers(self.GetIssueProperties())
1162 1171
1163 def AddComment(self, message): 1172 def AddComment(self, message):
1164 return self.RpcServer().add_comment(self.GetIssue(), message) 1173 return self.RpcServer().add_comment(self.GetIssue(), message)
1165 1174
1166 def SetIssue(self, issue): 1175 def SetIssue(self, issue=None):
1167 """Set this branch's issue. If issue=0, clears the issue.""" 1176 """Set this branch's issue. If issue isn't given, clears the issue."""
1168 if issue: 1177 if issue:
1169 self.issue = issue 1178 self.issue = issue
1170 RunGit(['config', self._IssueSetting(), str(issue)]) 1179 RunGit(['config', self._IssueSetting(), str(issue)])
1171 if self.rietveld_server: 1180 if not settings.GetIsGerrit() and self.rietveld_server:
1172 RunGit(['config', self._RietveldServer(), self.rietveld_server]) 1181 RunGit(['config', self._RietveldServer(), self.rietveld_server])
1173 else: 1182 else:
1174 current_issue = self.GetIssue() 1183 current_issue = self.GetIssue()
1175 if current_issue: 1184 if current_issue:
1176 RunGit(['config', '--unset', self._IssueSetting()]) 1185 RunGit(['config', '--unset', self._IssueSetting()])
1177 self.issue = None 1186 self.issue = None
1178 self.SetPatchset(None) 1187 self.SetPatchset(None)
1179 1188
1180 def GetChange(self, upstream_branch, author): 1189 def GetChange(self, upstream_branch, author):
1181 if not self.GitSanityChecks(upstream_branch): 1190 if not self.GitSanityChecks(upstream_branch):
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
1312 """Returns an upload.RpcServer() to access this review's rietveld instance. 1321 """Returns an upload.RpcServer() to access this review's rietveld instance.
1313 """ 1322 """
1314 if not self._rpc_server: 1323 if not self._rpc_server:
1315 self._rpc_server = rietveld.CachingRietveld( 1324 self._rpc_server = rietveld.CachingRietveld(
1316 self.GetRietveldServer(), 1325 self.GetRietveldServer(),
1317 self._auth_config or auth.make_auth_config()) 1326 self._auth_config or auth.make_auth_config())
1318 return self._rpc_server 1327 return self._rpc_server
1319 1328
1320 def _IssueSetting(self): 1329 def _IssueSetting(self):
1321 """Return the git setting that stores this change's issue.""" 1330 """Return the git setting that stores this change's issue."""
1331 if settings.GetIsGerrit():
1332 return 'branch.%s.gerritissue' % self.GetBranch()
1322 return 'branch.%s.rietveldissue' % self.GetBranch() 1333 return 'branch.%s.rietveldissue' % self.GetBranch()
1323 1334
1324 def _PatchsetSetting(self): 1335 def _PatchsetSetting(self):
1325 """Return the git setting that stores this change's most recent patchset.""" 1336 """Return the git setting that stores this change's most recent patchset."""
1326 return 'branch.%s.rietveldpatchset' % self.GetBranch() 1337 return 'branch.%s.rietveldpatchset' % self.GetBranch()
1327 1338
1328 def _RietveldServer(self): 1339 def _RietveldServer(self):
1329 """Returns the git setting that stores this change's rietveld server.""" 1340 """Returns the git setting that stores this change's rietveld server."""
1330 branch = self.GetBranch() 1341 branch = self.GetBranch()
1331 if branch: 1342 if branch:
(...skipping 821 matching lines...) Expand 10 before | Expand all | Expand 10 after
2153 def AddChangeIdToCommitMessage(options, args): 2164 def AddChangeIdToCommitMessage(options, args):
2154 """Re-commits using the current message, assumes the commit hook is in 2165 """Re-commits using the current message, assumes the commit hook is in
2155 place. 2166 place.
2156 """ 2167 """
2157 log_desc = options.message or CreateDescriptionFromLog(args) 2168 log_desc = options.message or CreateDescriptionFromLog(args)
2158 git_command = ['commit', '--amend', '-m', log_desc] 2169 git_command = ['commit', '--amend', '-m', log_desc]
2159 RunGit(git_command) 2170 RunGit(git_command)
2160 new_log_desc = CreateDescriptionFromLog(args) 2171 new_log_desc = CreateDescriptionFromLog(args)
2161 if git_footers.get_footer_change_id(new_log_desc): 2172 if git_footers.get_footer_change_id(new_log_desc):
2162 print 'git-cl: Added Change-Id to commit message.' 2173 print 'git-cl: Added Change-Id to commit message.'
2174 return new_log_desc
Michael Achenbach 2016/03/16 09:44:28 Where is this used? It's a bit odd that the method
tandrii(chromium) 2016/03/16 10:09:24 it's not pythonic, but yes default is None. I'll f
2163 else: 2175 else:
2164 print >> sys.stderr, 'ERROR: Gerrit commit-msg hook not available.' 2176 print >> sys.stderr, 'ERROR: Gerrit commit-msg hook not available.'
2165 2177
2166 2178
2167 def GenerateGerritChangeId(message): 2179 def GenerateGerritChangeId(message):
2168 """Returns Ixxxxxx...xxx change id. 2180 """Returns Ixxxxxx...xxx change id.
2169 2181
2170 Works the same way as 2182 Works the same way as
2171 https://gerrit-review.googlesource.com/tools/hooks/commit-msg 2183 https://gerrit-review.googlesource.com/tools/hooks/commit-msg
2172 but can be called on demand on all platforms. 2184 but can be called on demand on all platforms.
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
2225 print "Description is empty; aborting." 2237 print "Description is empty; aborting."
2226 return 1 2238 return 1
2227 message = change_desc.description 2239 message = change_desc.description
2228 change_ids = git_footers.get_footer_change_id(message) 2240 change_ids = git_footers.get_footer_change_id(message)
2229 if len(change_ids) > 1: 2241 if len(change_ids) > 1:
2230 DieWithError('too many Change-Id footers in %s branch' % shadow_branch) 2242 DieWithError('too many Change-Id footers in %s branch' % shadow_branch)
2231 if not change_ids: 2243 if not change_ids:
2232 message = git_footers.add_footer_change_id( 2244 message = git_footers.add_footer_change_id(
2233 message, GenerateGerritChangeId(message)) 2245 message, GenerateGerritChangeId(message))
2234 change_desc.set_description(message) 2246 change_desc.set_description(message)
2247 change_ids = git_footers.get_footer_change_id(message)
2248 assert len(change_ids) == 1
2249
2250 change_id = change_ids[0]
2235 2251
2236 remote, upstream_branch = cl.FetchUpstreamTuple(cl.GetBranch()) 2252 remote, upstream_branch = cl.FetchUpstreamTuple(cl.GetBranch())
2237 if remote is '.': 2253 if remote is '.':
2238 # If our upstream branch is local, we base our squashed commit on its 2254 # If our upstream branch is local, we base our squashed commit on its
2239 # squashed version. 2255 # squashed version.
2240 parent = ('refs/heads/git_cl_uploads/' + 2256 parent = ('refs/heads/git_cl_uploads/' +
2241 scm.GIT.ShortBranchName(upstream_branch)) 2257 scm.GIT.ShortBranchName(upstream_branch))
2242 2258
2243 # Verify that the upstream branch has been uploaded too, otherwise Gerrit 2259 # Verify that the upstream branch has been uploaded too, otherwise Gerrit
2244 # will create additional CLs when uploading. 2260 # will create additional CLs when uploading.
2245 if (RunGitSilent(['rev-parse', upstream_branch + ':']) != 2261 if (RunGitSilent(['rev-parse', upstream_branch + ':']) !=
2246 RunGitSilent(['rev-parse', parent + ':'])): 2262 RunGitSilent(['rev-parse', parent + ':'])):
2247 print 'Upload upstream branch ' + upstream_branch + ' first.' 2263 print 'Upload upstream branch ' + upstream_branch + ' first.'
2248 return 1 2264 return 1
2249 else: 2265 else:
2250 parent = cl.GetCommonAncestorWithUpstream() 2266 parent = cl.GetCommonAncestorWithUpstream()
2251 2267
2252 tree = RunGit(['rev-parse', 'HEAD:']).strip() 2268 tree = RunGit(['rev-parse', 'HEAD:']).strip()
2253 ref_to_push = RunGit(['commit-tree', tree, '-p', parent, 2269 ref_to_push = RunGit(['commit-tree', tree, '-p', parent,
2254 '-m', message]).strip() 2270 '-m', message]).strip()
2255 else: 2271 else:
2256 if not git_footers.get_footer_change_id(change_desc.description): 2272 if not git_footers.get_footer_change_id(change_desc.description):
2257 DownloadGerritHook(False) 2273 DownloadGerritHook(False)
2258 AddChangeIdToCommitMessage(options, args) 2274 change_desc.set_description(AddChangeIdToCommitMessage(options, args))
2259 ref_to_push = 'HEAD' 2275 ref_to_push = 'HEAD'
2260 parent = '%s/%s' % (gerrit_remote, branch) 2276 parent = '%s/%s' % (gerrit_remote, branch)
2277 change_id = git_footers.get_footer_change_id(change_desc.description)[0]
2261 2278
2262 commits = RunGitSilent(['rev-list', '%s..%s' % (parent, 2279 commits = RunGitSilent(['rev-list', '%s..%s' % (parent,
2263 ref_to_push)]).splitlines() 2280 ref_to_push)]).splitlines()
2264 if len(commits) > 1: 2281 if len(commits) > 1:
2265 print('WARNING: This will upload %d commits. Run the following command ' 2282 print('WARNING: This will upload %d commits. Run the following command '
2266 'to see which commits will be uploaded: ' % len(commits)) 2283 'to see which commits will be uploaded: ' % len(commits))
2267 print('git log %s..%s' % (parent, ref_to_push)) 2284 print('git log %s..%s' % (parent, ref_to_push))
2268 print('You can also use `git squash-branch` to squash these into a single ' 2285 print('You can also use `git squash-branch` to squash these into a single '
2269 'commit.') 2286 'commit.')
2270 ask_for_data('About to upload; enter to confirm.') 2287 ask_for_data('About to upload; enter to confirm.')
(...skipping 10 matching lines...) Expand all
2281 receive_options += ['--cc=' + email for email in cc] 2298 receive_options += ['--cc=' + email for email in cc]
2282 if change_desc.get_reviewers(): 2299 if change_desc.get_reviewers():
2283 receive_options.extend( 2300 receive_options.extend(
2284 '--reviewer=' + email for email in change_desc.get_reviewers()) 2301 '--reviewer=' + email for email in change_desc.get_reviewers())
2285 2302
2286 git_command = ['push'] 2303 git_command = ['push']
2287 if receive_options: 2304 if receive_options:
2288 git_command.append('--receive-pack=git receive-pack %s' % 2305 git_command.append('--receive-pack=git receive-pack %s' %
2289 ' '.join(receive_options)) 2306 ' '.join(receive_options))
2290 git_command += [gerrit_remote, ref_to_push + ':refs/for/' + branch] 2307 git_command += [gerrit_remote, ref_to_push + ':refs/for/' + branch]
2291 RunGit(git_command) 2308 push_stdout = gclient_utils.CheckCallAndFilter(
2309 ['git'] + git_command,
2310 print_stdout=True,
2311 # Flush after every line: useful for seeing progress when running as
2312 # recipe.
2313 filter_fn=lambda _: sys.stdout.flush())
2292 2314
2293 if options.squash: 2315 if options.squash:
2316 regex = re.compile(r'remote:\s+https?://[\w\-\.\/]*/(\d+)\s.*')
2317 change_numbers = [m.group(1)
2318 for m in map(regex.match, push_stdout.splitlines())
2319 if m]
2320 if len(change_numbers) != 1:
2321 DieWithError(
2322 ('Created|Updated %d issues on Gerrit, but only 1 expected.\n'
2323 'Change-Id: %s') % (len(change_numbers), change_id))
2324 cl.SetIssue(change_numbers[0])
2294 head = RunGit(['rev-parse', 'HEAD']).strip() 2325 head = RunGit(['rev-parse', 'HEAD']).strip()
2295 RunGit(['update-ref', '-m', 'Uploaded ' + head, shadow_branch, ref_to_push]) 2326 RunGit(['update-ref', '-m', 'Uploaded ' + head, shadow_branch, ref_to_push])
2296
2297 # TODO(ukai): parse Change-Id: and set issue number?
2298 return 0 2327 return 0
2299 2328
2300 2329
2301 def GetTargetRef(remote, remote_branch, target_branch, pending_prefix): 2330 def GetTargetRef(remote, remote_branch, target_branch, pending_prefix):
2302 """Computes the remote branch ref to use for the CL. 2331 """Computes the remote branch ref to use for the CL.
2303 2332
2304 Args: 2333 Args:
2305 remote (str): The git remote for the CL. 2334 remote (str): The git remote for the CL.
2306 remote_branch (str): The git remote branch for the CL. 2335 remote_branch (str): The git remote branch for the CL.
2307 target_branch (str): The target branch specified by the user. 2336 target_branch (str): The target branch specified by the user.
(...skipping 1675 matching lines...) Expand 10 before | Expand all | Expand 10 after
3983 if __name__ == '__main__': 4012 if __name__ == '__main__':
3984 # These affect sys.stdout so do it outside of main() to simplify mocks in 4013 # These affect sys.stdout so do it outside of main() to simplify mocks in
3985 # unit testing. 4014 # unit testing.
3986 fix_encoding.fix_encoding() 4015 fix_encoding.fix_encoding()
3987 colorama.init() 4016 colorama.init()
3988 try: 4017 try:
3989 sys.exit(main(sys.argv[1:])) 4018 sys.exit(main(sys.argv[1:]))
3990 except KeyboardInterrupt: 4019 except KeyboardInterrupt:
3991 sys.stderr.write('interrupted\n') 4020 sys.stderr.write('interrupted\n')
3992 sys.exit(1) 4021 sys.exit(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