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

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

Issue 173983002: Refactoring: Redesign option parsing in push and merge scripts. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 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 | « tools/push-to-trunk/merge_to_branch.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 optparse 29 import argparse
30 import sys 30 import sys
31 import tempfile 31 import tempfile
32 import urllib2 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",
43 PERSISTFILE_BASENAME: "/tmp/v8-push-to-trunk-tempfile", 43 PERSISTFILE_BASENAME: "/tmp/v8-push-to-trunk-tempfile",
44 TEMP_BRANCH: "prepare-push-temporary-branch-created-by-script", 44 TEMP_BRANCH: "prepare-push-temporary-branch-created-by-script",
45 DOT_GIT_LOCATION: ".git", 45 DOT_GIT_LOCATION: ".git",
46 VERSION_FILE: "src/version.cc", 46 VERSION_FILE: "src/version.cc",
47 CHANGELOG_FILE: "ChangeLog", 47 CHANGELOG_FILE: "ChangeLog",
48 CHANGELOG_ENTRY_FILE: "/tmp/v8-push-to-trunk-tempfile-changelog-entry", 48 CHANGELOG_ENTRY_FILE: "/tmp/v8-push-to-trunk-tempfile-changelog-entry",
49 PATCH_FILE: "/tmp/v8-push-to-trunk-tempfile-patch-file", 49 PATCH_FILE: "/tmp/v8-push-to-trunk-tempfile-patch-file",
50 COMMITMSG_FILE: "/tmp/v8-push-to-trunk-tempfile-commitmsg", 50 COMMITMSG_FILE: "/tmp/v8-push-to-trunk-tempfile-commitmsg",
51 DEPS_FILE: "DEPS", 51 DEPS_FILE: "DEPS",
52 } 52 }
53 53
54 PUSH_MESSAGE_SUFFIX = " (based on bleeding_edge revision r%d)" 54 PUSH_MESSAGE_SUFFIX = " (based on bleeding_edge revision r%d)"
55 PUSH_MESSAGE_RE = re.compile(r".* \(based on bleeding_edge revision r(\d+)\)$") 55 PUSH_MESSAGE_RE = re.compile(r".* \(based on bleeding_edge revision r(\d+)\)$")
56 56
57 57
58 class PushToTrunkOptions(CommonOptions):
59 @staticmethod
60 def MakeForcedOptions(author, reviewer, chrome_path):
61 """Convenience wrapper."""
62 class Options(object):
63 pass
64 options = Options()
65 options.s = 0
66 options.l = None
67 options.b = None
68 options.f = True
69 options.m = False
70 options.c = chrome_path
71 options.reviewer = reviewer
72 options.a = author
73 return PushToTrunkOptions(options)
74
75 def __init__(self, options):
76 super(PushToTrunkOptions, self).__init__(options, options.m)
77 self.requires_editor = not options.f
78 self.wait_for_lgtm = not options.f
79 self.tbr_commit = not options.m
80 self.l = options.l
81 self.reviewer = options.reviewer
82 self.c = options.c
83 self.b = getattr(options, 'b', None)
84 self.author = getattr(options, 'a', None)
85
86
87 class Preparation(Step): 58 class Preparation(Step):
88 MESSAGE = "Preparation." 59 MESSAGE = "Preparation."
89 60
90 def RunStep(self): 61 def RunStep(self):
91 self.InitialEnvironmentChecks() 62 self.InitialEnvironmentChecks()
92 self.CommonPrepare() 63 self.CommonPrepare()
93 self.PrepareBranch() 64 self.PrepareBranch()
94 self.DeleteBranch(self.Config(TRUNKBRANCH)) 65 self.DeleteBranch(self.Config(TRUNKBRANCH))
95 66
96 67
97 class FreshBranch(Step): 68 class FreshBranch(Step):
98 MESSAGE = "Create a fresh branch." 69 MESSAGE = "Create a fresh branch."
99 70
100 def RunStep(self): 71 def RunStep(self):
101 self.GitCreateBranch(self.Config(BRANCHNAME), "svn/bleeding_edge") 72 self.GitCreateBranch(self.Config(BRANCHNAME), "svn/bleeding_edge")
102 73
103 74
104 class DetectLastPush(Step): 75 class DetectLastPush(Step):
105 MESSAGE = "Detect commit ID of last push to trunk." 76 MESSAGE = "Detect commit ID of last push to trunk."
106 77
107 def RunStep(self): 78 def RunStep(self):
108 last_push = self._options.l or self.FindLastTrunkPush() 79 last_push = self._options.last_push or self.FindLastTrunkPush()
109 while True: 80 while True:
110 # Print assumed commit, circumventing git's pager. 81 # Print assumed commit, circumventing git's pager.
111 print self.GitLog(n=1, git_hash=last_push) 82 print self.GitLog(n=1, git_hash=last_push)
112 if self.Confirm("Is the commit printed above the last push to trunk?"): 83 if self.Confirm("Is the commit printed above the last push to trunk?"):
113 break 84 break
114 last_push = self.FindLastTrunkPush(parent_hash=last_push) 85 last_push = self.FindLastTrunkPush(parent_hash=last_push)
115 86
116 if self._options.b: 87 if self._options.last_bleeding_edge:
117 # Read the bleeding edge revision of the last push from a command-line 88 # Read the bleeding edge revision of the last push from a command-line
118 # option. 89 # option.
119 last_push_bleeding_edge = self._options.b 90 last_push_bleeding_edge = self._options.last_bleeding_edge
120 else: 91 else:
121 # Retrieve the bleeding edge revision of the last push from the text in 92 # Retrieve the bleeding edge revision of the last push from the text in
122 # the push commit message. 93 # the push commit message.
123 last_push_title = self.GitLog(n=1, format="%s", git_hash=last_push) 94 last_push_title = self.GitLog(n=1, format="%s", git_hash=last_push)
124 last_push_be_svn = PUSH_MESSAGE_RE.match(last_push_title).group(1) 95 last_push_be_svn = PUSH_MESSAGE_RE.match(last_push_title).group(1)
125 if not last_push_be_svn: 96 if not last_push_be_svn:
126 self.Die("Could not retrieve bleeding edge revision for trunk push %s" 97 self.Die("Could not retrieve bleeding edge revision for trunk push %s"
127 % last_push) 98 % last_push)
128 last_push_bleeding_edge = self.GitSVNFindGitHash(last_push_be_svn) 99 last_push_bleeding_edge = self.GitSVNFindGitHash(last_push_be_svn)
129 if not last_push_bleeding_edge: 100 if not last_push_bleeding_edge:
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 MESSAGE = "Tag the new revision." 379 MESSAGE = "Tag the new revision."
409 380
410 def RunStep(self): 381 def RunStep(self):
411 self.GitSVNTag(self["version"]) 382 self.GitSVNTag(self["version"])
412 383
413 384
414 class CheckChromium(Step): 385 class CheckChromium(Step):
415 MESSAGE = "Ask for chromium checkout." 386 MESSAGE = "Ask for chromium checkout."
416 387
417 def Run(self): 388 def Run(self):
418 self["chrome_path"] = self._options.c 389 self["chrome_path"] = self._options.chromium
419 if not self["chrome_path"]: 390 if not self["chrome_path"]:
420 self.DieNoManualMode("Please specify the path to a Chromium checkout in " 391 self.DieNoManualMode("Please specify the path to a Chromium checkout in "
421 "forced mode.") 392 "forced mode.")
422 print ("Do you have a \"NewGit\" Chromium checkout and want " 393 print ("Do you have a \"NewGit\" Chromium checkout and want "
423 "this script to automate creation of the roll CL? If yes, enter the " 394 "this script to automate creation of the roll CL? If yes, enter the "
424 "path to (and including) the \"src\" directory here, otherwise just " 395 "path to (and including) the \"src\" directory here, otherwise just "
425 "press <Return>: "), 396 "press <Return>: "),
426 self["chrome_path"] = self.ReadLine() 397 self["chrome_path"] = self.ReadLine()
427 398
428 399
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
504 "Chromium, and to update the v8rel spreadsheet:" 475 "Chromium, and to update the v8rel spreadsheet:"
505 % self["version"]) 476 % self["version"])
506 print "%s\ttrunk\t%s" % (self["version"], 477 print "%s\ttrunk\t%s" % (self["version"],
507 self["trunk_revision"]) 478 self["trunk_revision"])
508 479
509 self.CommonCleanup() 480 self.CommonCleanup()
510 if self.Config(TRUNKBRANCH) != self["current_branch"]: 481 if self.Config(TRUNKBRANCH) != self["current_branch"]:
511 self.GitDeleteBranch(self.Config(TRUNKBRANCH)) 482 self.GitDeleteBranch(self.Config(TRUNKBRANCH))
512 483
513 484
514 def RunPushToTrunk(config, 485 class PushToTrunk(ScriptsBase):
515 options, 486 def _PrepareOptions(self, parser):
516 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): 487 group = parser.add_mutually_exclusive_group()
517 step_classes = [ 488 group.add_argument("-f", "--force",
518 Preparation, 489 help="Don't prompt the user.",
519 FreshBranch, 490 default=False, action="store_true")
520 DetectLastPush, 491 group.add_argument("-m", "--manual",
521 PrepareChangeLog, 492 help="Prompt the user at every important step.",
522 EditChangeLog, 493 default=False, action="store_true")
523 IncrementVersion, 494 parser.add_argument("-b", "--last-bleeding-edge",
524 CommitLocal, 495 help=("The git commit ID of the last bleeding edge "
525 UploadStep, 496 "revision that was pushed to trunk. This is "
526 CommitRepository, 497 "used for the auto-generated ChangeLog entry."))
527 StragglerCommits, 498 parser.add_argument("-c", "--chromium",
528 SquashCommits, 499 help=("The path to your Chromium src/ "
529 NewBranch, 500 "directory to automate the V8 roll."))
530 ApplyChanges, 501 parser.add_argument("-l", "--last-push",
531 SetVersion, 502 help="The git commit ID of the last push to trunk.")
532 CommitTrunk,
533 SanityCheck,
534 CommitSVN,
535 TagRevision,
536 CheckChromium,
537 SwitchChromium,
538 UpdateChromiumCheckout,
539 UploadCL,
540 SwitchV8,
541 CleanUp,
542 ]
543 503
544 RunScript(step_classes, config, options, side_effect_handler) 504 def _ProcessOptions(self, options):
505 if not options.manual and not options.reviewer:
506 print "A reviewer (-r) is required in (semi-)automatic mode."
507 return False
508 if not options.manual and not options.chromium:
509 print "A chromium checkout (-c) is required in (semi-)automatic mode."
510 return False
511 if not options.manual and not options.author:
512 print "Specify your chromium.org email with -a in (semi-)automatic mode."
513 return False
514
515 options.requires_editor = not options.force
516 options.wait_for_lgtm = not options.force
517 options.tbr_commit = not options.manual
518 return True
519
520 def _Steps(self):
521 return [
522 Preparation,
523 FreshBranch,
524 DetectLastPush,
525 PrepareChangeLog,
526 EditChangeLog,
527 IncrementVersion,
528 CommitLocal,
529 UploadStep,
530 CommitRepository,
531 StragglerCommits,
532 SquashCommits,
533 NewBranch,
534 ApplyChanges,
535 SetVersion,
536 CommitTrunk,
537 SanityCheck,
538 CommitSVN,
539 TagRevision,
540 CheckChromium,
541 SwitchChromium,
542 UpdateChromiumCheckout,
543 UploadCL,
544 SwitchV8,
545 CleanUp,
546 ]
545 547
546 548
547 def BuildOptions():
548 result = optparse.OptionParser()
549 result.add_option("-a", "--author", dest="a",
550 help=("Specify the author email used for rietveld."))
551 result.add_option("-b", "--last-bleeding-edge", dest="b",
552 help=("Manually specify the git commit ID of the last "
553 "bleeding edge revision that was pushed to trunk. "
554 "This is used for the auto-generated ChangeLog "
555 "entry."))
556 result.add_option("-c", "--chromium", dest="c",
557 help=("Specify the path to your Chromium src/ "
558 "directory to automate the V8 roll."))
559 result.add_option("-f", "--force", dest="f",
560 help="Don't prompt the user.",
561 default=False, action="store_true")
562 result.add_option("-l", "--last-push", dest="l",
563 help=("Manually specify the git commit ID "
564 "of the last push to trunk."))
565 result.add_option("-m", "--manual", dest="m",
566 help="Prompt the user at every important step.",
567 default=False, action="store_true")
568 result.add_option("-r", "--reviewer",
569 help=("Specify the account name to be used for reviews."))
570 result.add_option("-s", "--step", dest="s",
571 help="Specify the step where to start work. Default: 0.",
572 default=0, type="int")
573 return result
574
575
576 def ProcessOptions(options):
577 if options.s < 0:
578 print "Bad step number %d" % options.s
579 return False
580 if not options.m and not options.reviewer:
581 print "A reviewer (-r) is required in (semi-)automatic mode."
582 return False
583 if options.f and options.m:
584 print "Manual and forced mode cannot be combined."
585 return False
586 if not options.m and not options.c:
587 print "A chromium checkout (-c) is required in (semi-)automatic mode."
588 return False
589 if not options.m and not options.a:
590 print "Specify your chromium.org email with -a in (semi-)automatic mode."
591 return False
592 return True
593
594
595 def Main():
596 parser = BuildOptions()
597 (options, args) = parser.parse_args()
598 if not ProcessOptions(options):
599 parser.print_help()
600 return 1
601 RunPushToTrunk(CONFIG, PushToTrunkOptions(options))
602
603 if __name__ == "__main__": 549 if __name__ == "__main__":
604 sys.exit(Main()) 550 sys.exit(PushToTrunk(CONFIG).Run())
OLDNEW
« no previous file with comments | « tools/push-to-trunk/merge_to_branch.py ('k') | tools/push-to-trunk/test_scripts.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698