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

Side by Side Diff: tools/push-to-trunk/push_to_trunk.py

Issue 112863002: Merge bleeding_edge 18021:18297 (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/parser
Patch Set: Created 7 years 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 | « tools/push-to-trunk/common_includes.py ('k') | tools/push-to-trunk/test_scripts.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 2013 the V8 project authors. All rights reserved. 2 # Copyright 2013 the V8 project authors. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without 3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are 4 # modification, are permitted provided that the following conditions are
5 # met: 5 # met:
6 # 6 #
7 # * Redistributions of source code must retain the above copyright 7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer. 8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above 9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following 10 # copyright notice, this list of conditions and the following
11 # disclaimer in the documentation and/or other materials provided 11 # disclaimer in the documentation and/or other materials provided
12 # with the distribution. 12 # with the distribution.
13 # * Neither the name of Google Inc. nor the names of its 13 # * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived 14 # contributors may be used to endorse or promote products derived
15 # from this software without specific prior written permission. 15 # from this software without specific prior written permission.
16 # 16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 28
29 import datetime
30 import optparse 29 import optparse
31 import sys 30 import sys
32 import tempfile 31 import tempfile
32 import urllib2
33 33
34 from common_includes import * 34 from common_includes import *
35 35
36 TRUNKBRANCH = "TRUNKBRANCH" 36 TRUNKBRANCH = "TRUNKBRANCH"
37 CHROMIUM = "CHROMIUM" 37 CHROMIUM = "CHROMIUM"
38 DEPS_FILE = "DEPS_FILE" 38 DEPS_FILE = "DEPS_FILE"
39 39
40 CONFIG = { 40 CONFIG = {
41 BRANCHNAME: "prepare-push", 41 BRANCHNAME: "prepare-push",
42 TRUNKBRANCH: "trunk-push", 42 TRUNKBRANCH: "trunk-push",
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 break 84 break
85 args = "log -1 --format=%H %s^ ChangeLog" % last_push 85 args = "log -1 --format=%H %s^ ChangeLog" % last_push
86 last_push = self.Git(args).strip() 86 last_push = self.Git(args).strip()
87 self.Persist("last_push", last_push) 87 self.Persist("last_push", last_push)
88 self._state["last_push"] = last_push 88 self._state["last_push"] = last_push
89 89
90 90
91 class PrepareChangeLog(Step): 91 class PrepareChangeLog(Step):
92 MESSAGE = "Prepare raw ChangeLog entry." 92 MESSAGE = "Prepare raw ChangeLog entry."
93 93
94 def Reload(self, body):
95 """Attempts to reload the commit message from rietveld in order to allow
96 late changes to the LOG flag. Note: This is brittle to future changes of
97 the web page name or structure.
98 """
99 match = re.search(r"^Review URL: https://codereview\.chromium\.org/(\d+)$",
100 body, flags=re.M)
101 if match:
102 cl_url = "https://codereview.chromium.org/%s/description" % match.group(1)
103 try:
104 # Fetch from Rietveld but only retry once with one second delay since
105 # there might be many revisions.
106 body = self.ReadURL(cl_url, wait_plan=[1])
107 except urllib2.URLError:
108 pass
109 return body
110
94 def RunStep(self): 111 def RunStep(self):
95 self.RestoreIfUnset("last_push") 112 self.RestoreIfUnset("last_push")
96 113
97 # These version numbers are used again later for the trunk commit. 114 # These version numbers are used again later for the trunk commit.
98 self.ReadAndPersistVersion() 115 self.ReadAndPersistVersion()
99 116
100 date = datetime.date.today().strftime("%Y-%m-%d") 117 date = self.GetDate()
101 self.Persist("date", date) 118 self.Persist("date", date)
102 output = "%s: Version %s.%s.%s\n\n" % (date, 119 output = "%s: Version %s.%s.%s\n\n" % (date,
103 self._state["major"], 120 self._state["major"],
104 self._state["minor"], 121 self._state["minor"],
105 self._state["build"]) 122 self._state["build"])
106 TextToFile(output, self.Config(CHANGELOG_ENTRY_FILE)) 123 TextToFile(output, self.Config(CHANGELOG_ENTRY_FILE))
107 124
108 args = "log %s..HEAD --format=%%H" % self._state["last_push"] 125 args = "log %s..HEAD --format=%%H" % self._state["last_push"]
109 commits = self.Git(args).strip() 126 commits = self.Git(args).strip()
110 127
111 # Cache raw commit messages. 128 # Cache raw commit messages.
112 commit_messages = [ 129 commit_messages = [
113 [ 130 [
114 self.Git("log -1 %s --format=\"%%s\"" % commit), 131 self.Git("log -1 %s --format=\"%%s\"" % commit),
115 self.Git("log -1 %s --format=\"%%B\"" % commit), 132 self.Reload(self.Git("log -1 %s --format=\"%%B\"" % commit)),
116 self.Git("log -1 %s --format=\"%%an\"" % commit), 133 self.Git("log -1 %s --format=\"%%an\"" % commit),
117 ] for commit in commits.splitlines() 134 ] for commit in commits.splitlines()
118 ] 135 ]
119 136
120 # Auto-format commit messages. 137 # Auto-format commit messages.
121 body = MakeChangeLogBody(commit_messages, auto_format=True) 138 body = MakeChangeLogBody(commit_messages, auto_format=True)
122 AppendToFile(body, self.Config(CHANGELOG_ENTRY_FILE)) 139 AppendToFile(body, self.Config(CHANGELOG_ENTRY_FILE))
123 140
124 msg = (" Performance and stability improvements on all platforms." 141 msg = (" Performance and stability improvements on all platforms."
125 "\n#\n# The change log above is auto-generated. Please review if " 142 "\n#\n# The change log above is auto-generated. Please review if "
126 "all relevant\n# commit messages from the list below are included." 143 "all relevant\n# commit messages from the list below are included."
127 "\n# All lines starting with # will be stripped.\n#\n") 144 "\n# All lines starting with # will be stripped.\n#\n")
128 AppendToFile(msg, self.Config(CHANGELOG_ENTRY_FILE)) 145 AppendToFile(msg, self.Config(CHANGELOG_ENTRY_FILE))
129 146
130 # Include unformatted commit messages as a reference in a comment. 147 # Include unformatted commit messages as a reference in a comment.
131 comment_body = MakeComment(MakeChangeLogBody(commit_messages)) 148 comment_body = MakeComment(MakeChangeLogBody(commit_messages))
132 AppendToFile(comment_body, self.Config(CHANGELOG_ENTRY_FILE)) 149 AppendToFile(comment_body, self.Config(CHANGELOG_ENTRY_FILE))
133 150
134 151
135 class EditChangeLog(Step): 152 class EditChangeLog(Step):
136 MESSAGE = "Edit ChangeLog entry." 153 MESSAGE = "Edit ChangeLog entry."
137 154
138 def RunStep(self): 155 def RunStep(self):
139 print ("Please press <Return> to have your EDITOR open the ChangeLog " 156 print ("Please press <Return> to have your EDITOR open the ChangeLog "
140 "entry, then edit its contents to your liking. When you're done, " 157 "entry, then edit its contents to your liking. When you're done, "
141 "save the file and exit your EDITOR. ") 158 "save the file and exit your EDITOR. ")
142 self.ReadLine(default="") 159 self.ReadLine(default="")
143
144 # TODO(machenbach): Don't use EDITOR in forced mode as soon as script is
145 # well tested.
146 self.Editor(self.Config(CHANGELOG_ENTRY_FILE)) 160 self.Editor(self.Config(CHANGELOG_ENTRY_FILE))
147 handle, new_changelog = tempfile.mkstemp() 161 handle, new_changelog = tempfile.mkstemp()
148 os.close(handle) 162 os.close(handle)
149 163
150 # Strip comments and reformat with correct indentation. 164 # Strip comments and reformat with correct indentation.
151 changelog_entry = FileToText(self.Config(CHANGELOG_ENTRY_FILE)).rstrip() 165 changelog_entry = FileToText(self.Config(CHANGELOG_ENTRY_FILE)).rstrip()
152 changelog_entry = StripComments(changelog_entry) 166 changelog_entry = StripComments(changelog_entry)
153 changelog_entry = "\n".join(map(Fill80, changelog_entry.splitlines())) 167 changelog_entry = "\n".join(map(Fill80, changelog_entry.splitlines()))
168 changelog_entry = changelog_entry.lstrip()
154 169
155 if changelog_entry == "": 170 if changelog_entry == "":
156 self.Die("Empty ChangeLog entry.") 171 self.Die("Empty ChangeLog entry.")
157 172
158 with open(new_changelog, "w") as f: 173 with open(new_changelog, "w") as f:
159 f.write(changelog_entry) 174 f.write(changelog_entry)
160 f.write("\n\n\n") # Explicitly insert two empty lines. 175 f.write("\n\n\n") # Explicitly insert two empty lines.
161 176
162 AppendToFile(FileToText(self.Config(CHANGELOG_FILE)), new_changelog) 177 AppendToFile(FileToText(self.Config(CHANGELOG_FILE)), new_changelog)
163 TextToFile(FileToText(new_changelog), self.Config(CHANGELOG_FILE)) 178 TextToFile(FileToText(new_changelog), self.Config(CHANGELOG_FILE))
(...skipping 25 matching lines...) Expand all
189 class CommitLocal(Step): 204 class CommitLocal(Step):
190 MESSAGE = "Commit to local branch." 205 MESSAGE = "Commit to local branch."
191 206
192 def RunStep(self): 207 def RunStep(self):
193 self.RestoreVersionIfUnset("new_") 208 self.RestoreVersionIfUnset("new_")
194 prep_commit_msg = ("Prepare push to trunk. " 209 prep_commit_msg = ("Prepare push to trunk. "
195 "Now working on version %s.%s.%s." % (self._state["new_major"], 210 "Now working on version %s.%s.%s." % (self._state["new_major"],
196 self._state["new_minor"], 211 self._state["new_minor"],
197 self._state["new_build"])) 212 self._state["new_build"]))
198 self.Persist("prep_commit_msg", prep_commit_msg) 213 self.Persist("prep_commit_msg", prep_commit_msg)
199 if self.Git("commit -a -m \"%s\"" % prep_commit_msg) is None: 214
215 # Include optional TBR only in the git command. The persisted commit
216 # message is used for finding the commit again later.
217 review = "\n\nTBR=%s" % self._options.r if not self.IsManual() else ""
218 if self.Git("commit -a -m \"%s%s\"" % (prep_commit_msg, review)) is None:
200 self.Die("'git commit -a' failed.") 219 self.Die("'git commit -a' failed.")
201 220
202 221
203 class CommitRepository(Step): 222 class CommitRepository(Step):
204 MESSAGE = "Commit to the repository." 223 MESSAGE = "Commit to the repository."
205 224
206 def RunStep(self): 225 def RunStep(self):
207 self.WaitForLGTM() 226 self.WaitForLGTM()
208 # Re-read the ChangeLog entry (to pick up possible changes). 227 # Re-read the ChangeLog entry (to pick up possible changes).
209 # FIXME(machenbach): This was hanging once with a broken pipe. 228 # FIXME(machenbach): This was hanging once with a broken pipe.
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 result.splitlines()) 358 result.splitlines())
340 if len(result) > 0: 359 if len(result) > 0:
341 trunk_revision = re.sub(r"^Committed r([0-9]+)", r"\1", result[0]) 360 trunk_revision = re.sub(r"^Committed r([0-9]+)", r"\1", result[0])
342 361
343 # Sometimes grepping for the revision fails. No idea why. If you figure 362 # Sometimes grepping for the revision fails. No idea why. If you figure
344 # out why it is flaky, please do fix it properly. 363 # out why it is flaky, please do fix it properly.
345 if not trunk_revision: 364 if not trunk_revision:
346 print("Sorry, grepping for the SVN revision failed. Please look for it " 365 print("Sorry, grepping for the SVN revision failed. Please look for it "
347 "in the last command's output above and provide it manually (just " 366 "in the last command's output above and provide it manually (just "
348 "the number, without the leading \"r\").") 367 "the number, without the leading \"r\").")
349 self.DieInForcedMode("Can't prompt in forced mode.") 368 self.DieNoManualMode("Can't prompt in forced mode.")
350 while not trunk_revision: 369 while not trunk_revision:
351 print "> ", 370 print "> ",
352 trunk_revision = self.ReadLine() 371 trunk_revision = self.ReadLine()
353 self.Persist("trunk_revision", trunk_revision) 372 self.Persist("trunk_revision", trunk_revision)
354 373
355 374
356 class TagRevision(Step): 375 class TagRevision(Step):
357 MESSAGE = "Tag the new revision." 376 MESSAGE = "Tag the new revision."
358 377
359 def RunStep(self): 378 def RunStep(self):
360 self.RestoreVersionIfUnset() 379 self.RestoreVersionIfUnset()
361 ver = "%s.%s.%s" % (self._state["major"], 380 ver = "%s.%s.%s" % (self._state["major"],
362 self._state["minor"], 381 self._state["minor"],
363 self._state["build"]) 382 self._state["build"])
364 if self.Git("svn tag %s -m \"Tagging version %s\"" % (ver, ver)) is None: 383 if self.Git("svn tag %s -m \"Tagging version %s\"" % (ver, ver)) is None:
365 self.Die("'git svn tag' failed.") 384 self.Die("'git svn tag' failed.")
366 385
367 386
368 class CheckChromium(Step): 387 class CheckChromium(Step):
369 MESSAGE = "Ask for chromium checkout." 388 MESSAGE = "Ask for chromium checkout."
370 389
371 def Run(self): 390 def Run(self):
372 chrome_path = self._options.c 391 chrome_path = self._options.c
373 if not chrome_path: 392 if not chrome_path:
374 self.DieInForcedMode("Please specify the path to a Chromium checkout in " 393 self.DieNoManualMode("Please specify the path to a Chromium checkout in "
375 "forced mode.") 394 "forced mode.")
376 print ("Do you have a \"NewGit\" Chromium checkout and want " 395 print ("Do you have a \"NewGit\" Chromium checkout and want "
377 "this script to automate creation of the roll CL? If yes, enter the " 396 "this script to automate creation of the roll CL? If yes, enter the "
378 "path to (and including) the \"src\" directory here, otherwise just " 397 "path to (and including) the \"src\" directory here, otherwise just "
379 "press <Return>: "), 398 "press <Return>: "),
380 chrome_path = self.ReadLine() 399 chrome_path = self.ReadLine()
381 self.Persist("chrome_path", chrome_path) 400 self.Persist("chrome_path", chrome_path)
382 401
383 402
384 class SwitchChromium(Step): 403 class SwitchChromium(Step):
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 451
433 self.RestoreVersionIfUnset() 452 self.RestoreVersionIfUnset()
434 ver = "%s.%s.%s" % (self._state["major"], 453 ver = "%s.%s.%s" % (self._state["major"],
435 self._state["minor"], 454 self._state["minor"],
436 self._state["build"]) 455 self._state["build"])
437 if self._options and self._options.r: 456 if self._options and self._options.r:
438 print "Using account %s for review." % self._options.r 457 print "Using account %s for review." % self._options.r
439 rev = self._options.r 458 rev = self._options.r
440 else: 459 else:
441 print "Please enter the email address of a reviewer for the roll CL: ", 460 print "Please enter the email address of a reviewer for the roll CL: ",
442 self.DieInForcedMode("A reviewer must be specified in forced mode.") 461 self.DieNoManualMode("A reviewer must be specified in forced mode.")
443 rev = self.ReadLine() 462 rev = self.ReadLine()
444 args = "commit -am \"Update V8 to version %s.\n\nTBR=%s\"" % (ver, rev) 463 args = "commit -am \"Update V8 to version %s.\n\nTBR=%s\"" % (ver, rev)
445 if self.Git(args) is None: 464 if self.Git(args) is None:
446 self.Die("'git commit' failed.") 465 self.Die("'git commit' failed.")
447 force_flag = " -f" if self._options.f else "" 466 force_flag = " -f" if not self.IsManual() else ""
448 if self.Git("cl upload --send-mail%s" % force_flag, pipe=False) is None: 467 if self.Git("cl upload --send-mail%s" % force_flag, pipe=False) is None:
449 self.Die("'git cl upload' failed, please try again.") 468 self.Die("'git cl upload' failed, please try again.")
450 print "CL uploaded." 469 print "CL uploaded."
451 470
452 471
453 class SwitchV8(Step): 472 class SwitchV8(Step):
454 MESSAGE = "Returning to V8 checkout." 473 MESSAGE = "Returning to V8 checkout."
455 REQUIRES = "chrome_path" 474 REQUIRES = "chrome_path"
456 475
457 def RunStep(self): 476 def RunStep(self):
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
522 result = optparse.OptionParser() 541 result = optparse.OptionParser()
523 result.add_option("-c", "--chromium", dest="c", 542 result.add_option("-c", "--chromium", dest="c",
524 help=("Specify the path to your Chromium src/ " 543 help=("Specify the path to your Chromium src/ "
525 "directory to automate the V8 roll.")) 544 "directory to automate the V8 roll."))
526 result.add_option("-f", "--force", dest="f", 545 result.add_option("-f", "--force", dest="f",
527 help="Don't prompt the user.", 546 help="Don't prompt the user.",
528 default=False, action="store_true") 547 default=False, action="store_true")
529 result.add_option("-l", "--last-push", dest="l", 548 result.add_option("-l", "--last-push", dest="l",
530 help=("Manually specify the git commit ID " 549 help=("Manually specify the git commit ID "
531 "of the last push to trunk.")) 550 "of the last push to trunk."))
551 result.add_option("-m", "--manual", dest="m",
552 help="Prompt the user at every important step.",
553 default=False, action="store_true")
532 result.add_option("-r", "--reviewer", dest="r", 554 result.add_option("-r", "--reviewer", dest="r",
533 help=("Specify the account name to be used for reviews.")) 555 help=("Specify the account name to be used for reviews."))
534 result.add_option("-s", "--step", dest="s", 556 result.add_option("-s", "--step", dest="s",
535 help="Specify the step where to start work. Default: 0.", 557 help="Specify the step where to start work. Default: 0.",
536 default=0, type="int") 558 default=0, type="int")
537 return result 559 return result
538 560
539 561
540 def ProcessOptions(options): 562 def ProcessOptions(options):
541 if options.s < 0: 563 if options.s < 0:
542 print "Bad step number %d" % options.s 564 print "Bad step number %d" % options.s
543 return False 565 return False
566 if not options.m and not options.r:
567 print "A reviewer (-r) is required in (semi-)automatic mode."
568 return False
569 if options.f and options.m:
570 print "Manual and forced mode cannot be combined."
571 return False
572 if not options.m and not options.c:
573 print "A chromium checkout (-c) is required in (semi-)automatic mode."
574 return False
544 return True 575 return True
545 576
546 577
547 def Main(): 578 def Main():
548 parser = BuildOptions() 579 parser = BuildOptions()
549 (options, args) = parser.parse_args() 580 (options, args) = parser.parse_args()
550 if not ProcessOptions(options): 581 if not ProcessOptions(options):
551 parser.print_help() 582 parser.print_help()
552 return 1 583 return 1
553 RunPushToTrunk(CONFIG, options) 584 RunPushToTrunk(CONFIG, options)
554 585
555 if __name__ == "__main__": 586 if __name__ == "__main__":
556 sys.exit(Main()) 587 sys.exit(Main())
OLDNEW
« no previous file with comments | « tools/push-to-trunk/common_includes.py ('k') | tools/push-to-trunk/test_scripts.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698