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

Side by Side Diff: depot_tools/gcl.py

Issue 13832005: Reapply r193525 "Make gcl use git_cl.py code for consistency in the CL description formatting." (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/
Patch Set: Created 7 years, 8 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 | depot_tools/tests/gcl_unittest.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 """\ 6 """\
7 Wrapper script around Rietveld's upload.py that simplifies working with groups 7 Wrapper script around Rietveld's upload.py that simplifies working with groups
8 of files. 8 of files.
9 """ 9 """
10 10
11 import json 11 import json
12 import optparse 12 import optparse
13 import os 13 import os
14 import random 14 import random
15 import re 15 import re
16 import string 16 import string
17 import sys 17 import sys
18 import tempfile 18 import tempfile
19 import time 19 import time
20 import urllib2 20 import urllib2
21 21
22 import breakpad # pylint: disable=W0611 22 import breakpad # pylint: disable=W0611
23 23
24 24
25 import fix_encoding 25 import fix_encoding
26 import gclient_utils 26 import gclient_utils
27 import git_cl
27 import presubmit_support 28 import presubmit_support
28 import rietveld 29 import rietveld
29 from scm import SVN 30 from scm import SVN
30 import subprocess2 31 import subprocess2
31 from third_party import upload 32 from third_party import upload
32 33
33 __version__ = '1.2.1' 34 __version__ = '1.2.1'
34 35
35 36
36 CODEREVIEW_SETTINGS = { 37 CODEREVIEW_SETTINGS = {
(...skipping 15 matching lines...) Expand all
52 # Warning message when the change appears to be missing tests. 53 # Warning message when the change appears to be missing tests.
53 MISSING_TEST_MSG = "Change contains new or modified methods, but no new tests!" 54 MISSING_TEST_MSG = "Change contains new or modified methods, but no new tests!"
54 55
55 # Global cache of files cached in GetCacheDir(). 56 # Global cache of files cached in GetCacheDir().
56 FILES_CACHE = {} 57 FILES_CACHE = {}
57 58
58 # Valid extensions for files we want to lint. 59 # Valid extensions for files we want to lint.
59 DEFAULT_LINT_REGEX = r"(.*\.cpp|.*\.cc|.*\.h)" 60 DEFAULT_LINT_REGEX = r"(.*\.cpp|.*\.cc|.*\.h)"
60 DEFAULT_LINT_IGNORE_REGEX = r"$^" 61 DEFAULT_LINT_IGNORE_REGEX = r"$^"
61 62
62 REVIEWERS_REGEX = r'\s*R=(.+)'
63
64 def CheckHomeForFile(filename): 63 def CheckHomeForFile(filename):
65 """Checks the users home dir for the existence of the given file. Returns 64 """Checks the users home dir for the existence of the given file. Returns
66 the path to the file if it's there, or None if it is not. 65 the path to the file if it's there, or None if it is not.
67 """ 66 """
68 home_vars = ['HOME'] 67 home_vars = ['HOME']
69 if sys.platform in ('cygwin', 'win32'): 68 if sys.platform in ('cygwin', 'win32'):
70 home_vars.append('USERPROFILE') 69 home_vars.append('USERPROFILE')
71 for home_var in home_vars: 70 for home_var in home_vars:
72 home = os.getenv(home_var) 71 home = os.getenv(home_var)
73 if home != None: 72 if home != None:
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 files: a list of 2 tuple containing (status, filename) of changed files, 265 files: a list of 2 tuple containing (status, filename) of changed files,
267 with paths being relative to the top repository directory. 266 with paths being relative to the top repository directory.
268 local_root: Local root directory 267 local_root: Local root directory
269 rietveld: rietveld server for this change 268 rietveld: rietveld server for this change
270 """ 269 """
271 # Kept for unit test support. This is for the old format, it's deprecated. 270 # Kept for unit test support. This is for the old format, it's deprecated.
272 SEPARATOR = "\n-----\n" 271 SEPARATOR = "\n-----\n"
273 272
274 def __init__(self, name, issue, patchset, description, files, local_root, 273 def __init__(self, name, issue, patchset, description, files, local_root,
275 rietveld_url, needs_upload): 274 rietveld_url, needs_upload):
275 # Defer the description processing to git_cl.ChangeDescription.
276 self._desc = git_cl.ChangeDescription(description)
276 self.name = name 277 self.name = name
277 self.issue = int(issue) 278 self.issue = int(issue)
278 self.patchset = int(patchset) 279 self.patchset = int(patchset)
279 self._description = None 280 self._files = files or []
280 self._reviewers = None
281 self._set_description(description)
282 if files is None:
283 files = []
284 self._files = files
285 self.patch = None 281 self.patch = None
286 self._local_root = local_root 282 self._local_root = local_root
287 self.needs_upload = needs_upload 283 self.needs_upload = needs_upload
288 self.rietveld = gclient_utils.UpgradeToHttps( 284 self.rietveld = gclient_utils.UpgradeToHttps(
289 rietveld_url or GetCodeReviewSetting('CODE_REVIEW_SERVER')) 285 rietveld_url or GetCodeReviewSetting('CODE_REVIEW_SERVER'))
290 self._rpc_server = None 286 self._rpc_server = None
291 287
292 def _get_description(self): 288 @property
293 return self._description 289 def description(self):
290 return self._desc.description
294 291
295 def _set_description(self, description): 292 def force_description(self, new_description):
296 # TODO(dpranke): Cloned from git_cl.py. These should be shared. 293 self._desc = git_cl.ChangeDescription(new_description)
297 if not description: 294 self.needs_upload = True
298 self._description = description
299 return
300 295
301 parsed_lines = [] 296 def append_footer(self, line):
302 reviewers_re = re.compile(REVIEWERS_REGEX) 297 self._desc.append_footer(line)
303 reviewers = ''
304 for l in description.splitlines():
305 matched_reviewers = reviewers_re.match(l)
306 if matched_reviewers:
307 reviewers = matched_reviewers.group(1).split(',')
308 parsed_lines.append(l)
309 self._reviewers = reviewers
310 self._description = '\n'.join(parsed_lines)
311 298
312 description = property(_get_description, _set_description) 299 def get_reviewers(self):
313 300 return self._desc.get_reviewers()
314 @property
315 def reviewers(self):
316 return self._reviewers
317 301
318 def NeedsUpload(self): 302 def NeedsUpload(self):
319 return self.needs_upload 303 return self.needs_upload
320 304
321 def GetFileNames(self): 305 def GetFileNames(self):
322 """Returns the list of file names included in this change.""" 306 """Returns the list of file names included in this change."""
323 return [f[1] for f in self._files] 307 return [f[1] for f in self._files]
324 308
325 def GetFiles(self): 309 def GetFiles(self):
326 """Returns the list of files included in this change with their status.""" 310 """Returns the list of files included in this change with their status."""
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 ctype, body = upload.EncodeMultipartFormData(data, []) 365 ctype, body = upload.EncodeMultipartFormData(data, [])
382 self.SendToRietveld('/%d/close' % self.issue, payload=body, 366 self.SendToRietveld('/%d/close' % self.issue, payload=body,
383 content_type=ctype) 367 content_type=ctype)
384 368
385 def UpdateRietveldDescription(self): 369 def UpdateRietveldDescription(self):
386 """Sets the description for an issue on Rietveld.""" 370 """Sets the description for an issue on Rietveld."""
387 data = [("description", self.description),] 371 data = [("description", self.description),]
388 ctype, body = upload.EncodeMultipartFormData(data, []) 372 ctype, body = upload.EncodeMultipartFormData(data, [])
389 self.SendToRietveld('/%d/description' % self.issue, payload=body, 373 self.SendToRietveld('/%d/description' % self.issue, payload=body,
390 content_type=ctype) 374 content_type=ctype)
375 self.needs_upload = False
391 376
392 def GetIssueDescription(self): 377 def GetIssueDescription(self):
393 """Returns the issue description from Rietveld.""" 378 """Returns the issue description from Rietveld."""
394 return self.SendToRietveld('/%d/description' % self.issue) 379 return self.SendToRietveld('/%d/description' % self.issue)
395 380
381 def UpdateDescriptionFromIssue(self):
382 """Updates self.description with the issue description from Rietveld."""
383 self._desc = git_cl.ChangeDescription(
384 self.SendToRietveld('/%d/description' % self.issue))
385
396 def AddComment(self, comment): 386 def AddComment(self, comment):
397 """Adds a comment for an issue on Rietveld. 387 """Adds a comment for an issue on Rietveld.
398 As a side effect, this will email everyone associated with the issue.""" 388 As a side effect, this will email everyone associated with the issue."""
399 return self.RpcServer().add_comment(self.issue, comment) 389 return self.RpcServer().add_comment(self.issue, comment)
400 390
401 def PrimeLint(self): 391 def PrimeLint(self):
402 """Do background work on Rietveld to lint the file so that the results are 392 """Do background work on Rietveld to lint the file so that the results are
403 ready when the issue is viewed.""" 393 ready when the issue is viewed."""
404 if self.issue and self.patchset: 394 if self.issue and self.patchset:
405 self.SendToRietveld('/lint/issue%s_%s' % (self.issue, self.patchset), 395 self.SendToRietveld('/lint/issue%s_%s' % (self.issue, self.patchset),
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after
844 args = map(replace_message, args) 834 args = map(replace_message, args)
845 if found_deprecated_arg[0]: 835 if found_deprecated_arg[0]:
846 print >> sys.stderr, ( 836 print >> sys.stderr, (
847 '\nWARNING: Use -t or --title to set the title of the patchset.\n' 837 '\nWARNING: Use -t or --title to set the title of the patchset.\n'
848 'In the near future, -m or --message will send a message instead.\n' 838 'In the near future, -m or --message will send a message instead.\n'
849 'See http://goo.gl/JGg0Z for details.\n') 839 'See http://goo.gl/JGg0Z for details.\n')
850 840
851 upload_arg = ["upload.py", "-y"] 841 upload_arg = ["upload.py", "-y"]
852 upload_arg.append("--server=%s" % change_info.rietveld) 842 upload_arg.append("--server=%s" % change_info.rietveld)
853 843
854 reviewers = change_info.reviewers or output.reviewers 844 reviewers = change_info.get_reviewers() or output.reviewers
855 if (reviewers and 845 if (reviewers and
856 not any(arg.startswith('-r') or arg.startswith('--reviewer') for 846 not any(arg.startswith('-r') or arg.startswith('--reviewer') for
857 arg in args)): 847 arg in args)):
858 upload_arg.append('--reviewers=%s' % ','.join(reviewers)) 848 upload_arg.append('--reviewers=%s' % ','.join(reviewers))
859 849
860 upload_arg.extend(args) 850 upload_arg.extend(args)
861 851
862 desc_file = None 852 desc_file = None
863 try: 853 try:
864 if change_info.issue: 854 if change_info.issue:
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
996 # We face a problem with svn here: Let's say change 'bleh' modifies 986 # We face a problem with svn here: Let's say change 'bleh' modifies
997 # svn:ignore on dir1\. but another unrelated change 'pouet' modifies 987 # svn:ignore on dir1\. but another unrelated change 'pouet' modifies
998 # dir1\foo.cc. When the user `gcl commit bleh`, foo.cc is *also committed*. 988 # dir1\foo.cc. When the user `gcl commit bleh`, foo.cc is *also committed*.
999 # The only fix is to use --non-recursive but that has its issues too: 989 # The only fix is to use --non-recursive but that has its issues too:
1000 # Let's say if dir1 is deleted, --non-recursive must *not* be used otherwise 990 # Let's say if dir1 is deleted, --non-recursive must *not* be used otherwise
1001 # you'll get "svn: Cannot non-recursively commit a directory deletion of a 991 # you'll get "svn: Cannot non-recursively commit a directory deletion of a
1002 # directory with child nodes". Yay... 992 # directory with child nodes". Yay...
1003 commit_cmd = ["svn", "commit"] 993 commit_cmd = ["svn", "commit"]
1004 if change_info.issue: 994 if change_info.issue:
1005 # Get the latest description from Rietveld. 995 # Get the latest description from Rietveld.
1006 change_info.description = change_info.GetIssueDescription() 996 change_info.UpdateDescriptionFromIssue()
1007 997
1008 commit_message = change_info.description.replace('\r\n', '\n') 998 commit_desc = git_cl.ChangeDescription(change_info.description)
1009 if change_info.issue: 999 if change_info.issue:
1010 server = change_info.rietveld 1000 server = change_info.rietveld
1011 if not server.startswith("http://") and not server.startswith("https://"): 1001 if not server.startswith("http://") and not server.startswith("https://"):
1012 server = "http://" + server 1002 server = "http://" + server
1013 commit_message += ('\nReview URL: %s/%d' % (server, change_info.issue)) 1003 commit_desc.append_footer('Review URL: %s/%d' % (server, change_info.issue))
1014 1004
1015 handle, commit_filename = tempfile.mkstemp(text=True) 1005 handle, commit_filename = tempfile.mkstemp(text=True)
1016 os.write(handle, commit_message) 1006 os.write(handle, commit_desc.description)
1017 os.close(handle) 1007 os.close(handle)
1018 try: 1008 try:
1019 handle, targets_filename = tempfile.mkstemp(text=True) 1009 handle, targets_filename = tempfile.mkstemp(text=True)
1020 os.write(handle, "\n".join(change_info.GetFileNames())) 1010 os.write(handle, "\n".join(change_info.GetFileNames()))
1021 os.close(handle) 1011 os.close(handle)
1022 try: 1012 try:
1023 commit_cmd += ['--file=' + commit_filename] 1013 commit_cmd += ['--file=' + commit_filename]
1024 commit_cmd += ['--targets=' + targets_filename] 1014 commit_cmd += ['--targets=' + targets_filename]
1025 # Change the current working directory before calling commit. 1015 # Change the current working directory before calling commit.
1026 output = '' 1016 output = ''
1027 try: 1017 try:
1028 output = RunShell(commit_cmd, True) 1018 output = RunShell(commit_cmd, True)
1029 except subprocess2.CalledProcessError, e: 1019 except subprocess2.CalledProcessError, e:
1030 ErrorExit('Commit failed.\n%s' % e) 1020 ErrorExit('Commit failed.\n%s' % e)
1031 finally: 1021 finally:
1032 os.remove(commit_filename) 1022 os.remove(commit_filename)
1033 finally: 1023 finally:
1034 os.remove(targets_filename) 1024 os.remove(targets_filename)
1035 if output.find("Committed revision") != -1: 1025 if output.find("Committed revision") != -1:
1036 change_info.Delete() 1026 change_info.Delete()
1037 1027
1038 if change_info.issue: 1028 if change_info.issue:
1039 revision = re.compile(".*?\nCommitted revision (\d+)", 1029 revision = re.compile(".*?\nCommitted revision (\d+)",
1040 re.DOTALL).match(output).group(1) 1030 re.DOTALL).match(output).group(1)
1041 viewvc_url = GetCodeReviewSetting('VIEW_VC') 1031 viewvc_url = GetCodeReviewSetting('VIEW_VC')
1042 change_info.description += '\n'
1043 if viewvc_url and revision: 1032 if viewvc_url and revision:
1044 change_info.description += "\nCommitted: " + viewvc_url + revision 1033 change_info.append_footer('Committed: ' + viewvc_url + revision)
1045 elif revision: 1034 elif revision:
1046 change_info.description += "\nCommitted: " + revision 1035 change_info.append_footer('Committed: ' + revision)
1047 change_info.CloseIssue() 1036 change_info.CloseIssue()
1048 props = change_info.RpcServer().get_issue_properties( 1037 props = change_info.RpcServer().get_issue_properties(
1049 change_info.issue, False) 1038 change_info.issue, False)
1050 patch_num = len(props['patchsets']) 1039 patch_num = len(props['patchsets'])
1051 comment = "Committed patchset #%d manually as r%s" % (patch_num, revision) 1040 comment = "Committed patchset #%d manually as r%s" % (patch_num, revision)
1052 comment += ' (presubmit successful).' if not bypassed else '.' 1041 comment += ' (presubmit successful).' if not bypassed else '.'
1053 change_info.AddComment(comment) 1042 change_info.AddComment(comment)
1054 return 0 1043 return 0
1055 1044
1056 1045
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
1131 ErrorExit('Running editor failed') 1120 ErrorExit('Running editor failed')
1132 1121
1133 split_result = result.split(separator1, 1) 1122 split_result = result.split(separator1, 1)
1134 if len(split_result) != 2: 1123 if len(split_result) != 2:
1135 ErrorExit("Don't modify the text starting with ---!\n\n%r" % result) 1124 ErrorExit("Don't modify the text starting with ---!\n\n%r" % result)
1136 1125
1137 # Update the CL description if it has changed. 1126 # Update the CL description if it has changed.
1138 new_description = split_result[0] 1127 new_description = split_result[0]
1139 cl_files_text = split_result[1] 1128 cl_files_text = split_result[1]
1140 if new_description != description or override_description: 1129 if new_description != description or override_description:
1141 change_info.description = new_description 1130 change_info.force_description(new_description)
1142 change_info.needs_upload = True
1143 1131
1144 new_cl_files = [] 1132 new_cl_files = []
1145 for line in cl_files_text.splitlines(): 1133 for line in cl_files_text.splitlines():
1146 if not len(line): 1134 if not len(line):
1147 continue 1135 continue
1148 if line.startswith("---"): 1136 if line.startswith("---"):
1149 break 1137 break
1150 status = line[:7] 1138 status = line[:7]
1151 filename = line[7:] 1139 filename = line[7:]
1152 new_cl_files.append((status, filename)) 1140 new_cl_files.append((status, filename))
1153 1141
1154 if (not len(change_info.GetFiles()) and not change_info.issue and 1142 if (not len(change_info.GetFiles()) and not change_info.issue and
1155 not len(new_description) and not new_cl_files): 1143 not len(new_description) and not new_cl_files):
1156 ErrorExit("Empty changelist not saved") 1144 ErrorExit("Empty changelist not saved")
1157 1145
1158 change_info._files = new_cl_files 1146 change_info._files = new_cl_files
1159 change_info.Save() 1147 change_info.Save()
1160 if svn_info.get('URL', '').startswith('http:'): 1148 if svn_info.get('URL', '').startswith('http:'):
1161 Warn("WARNING: Creating CL in a read-only checkout. You will need to " 1149 Warn("WARNING: Creating CL in a read-only checkout. You will need to "
1162 "commit using a commit queue!") 1150 "commit using a commit queue!")
1163 1151
1164 print change_info.name + " changelist saved." 1152 print change_info.name + " changelist saved."
1165 if change_info.MissingTests(): 1153 if change_info.MissingTests():
1166 Warn("WARNING: " + MISSING_TEST_MSG) 1154 Warn("WARNING: " + MISSING_TEST_MSG)
1167 1155
1168 # Update the Rietveld issue. 1156 # Update the Rietveld issue.
1169 if change_info.issue and change_info.NeedsUpload(): 1157 if change_info.issue and change_info.NeedsUpload():
1170 change_info.UpdateRietveldDescription() 1158 change_info.UpdateRietveldDescription()
1171 change_info.needs_upload = False
1172 change_info.Save() 1159 change_info.Save()
1173 return 0 1160 return 0
1174 1161
1175 1162
1176 @need_change_and_args 1163 @need_change_and_args
1177 def CMDlint(change_info, args): 1164 def CMDlint(change_info, args):
1178 """Runs cpplint.py on all the files in the change list. 1165 """Runs cpplint.py on all the files in the change list.
1179 1166
1180 Checks all the files in the changelist for possible style violations. 1167 Checks all the files in the changelist for possible style violations.
1181 """ 1168 """
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after
1470 raise 1457 raise
1471 print >> sys.stderr, ( 1458 print >> sys.stderr, (
1472 'AppEngine is misbehaving and returned HTTP %d, again. Keep faith ' 1459 'AppEngine is misbehaving and returned HTTP %d, again. Keep faith '
1473 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e)) 1460 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))
1474 return 1 1461 return 1
1475 1462
1476 1463
1477 if __name__ == "__main__": 1464 if __name__ == "__main__":
1478 fix_encoding.fix_encoding() 1465 fix_encoding.fix_encoding()
1479 sys.exit(main(sys.argv[1:])) 1466 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « no previous file | depot_tools/tests/gcl_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698