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 from distutils.version import LooseVersion | 10 from distutils.version import LooseVersion |
(...skipping 1065 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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) |
OLD | NEW |