Add forced mode to push-to-trunk script.
authormachenbach@chromium.org <machenbach@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 20 Nov 2013 08:49:42 +0000 (08:49 +0000)
committermachenbach@chromium.org <machenbach@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 20 Nov 2013 08:49:42 +0000 (08:49 +0000)
This CL depends on https://codereview.chromium.org/65933003/.

BUG=
R=jkummerow@chromium.org

Review URL: https://codereview.chromium.org/67763005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17893 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

tools/push-to-trunk/common_includes.py
tools/push-to-trunk/push_to_trunk.py
tools/push-to-trunk/test_scripts.py

index 9ab2b14..9547367 100644 (file)
@@ -166,6 +166,7 @@ class Step(object):
   def __init__(self, text="", requires=None):
     self._text = text
     self._number = -1
+    self._options = None
     self._requires = requires
     self._side_effect_handler = DEFAULT_SIDE_EFFECT_HANDLER
 
@@ -202,8 +203,13 @@ class Step(object):
   def RunStep(self):
     raise NotImplementedError
 
-  def ReadLine(self):
-    return self._side_effect_handler.ReadLine()
+  def ReadLine(self, default=None):
+    # Don't prompt in forced mode.
+    if self._options and self._options.f and default is not None:
+      print "%s (forced)" % default
+      return default
+    else:
+      return self._side_effect_handler.ReadLine()
 
   def Git(self, args="", prefix="", pipe=True):
     return self._side_effect_handler.Command("git", args, prefix, pipe)
@@ -218,9 +224,14 @@ class Step(object):
     print "Exiting"
     raise Exception(msg)
 
+  def DieInForcedMode(self, msg=""):
+    if self._options and self._options.f:
+      msg = msg or "Not implemented in forced mode."
+      self.Die(msg)
+
   def Confirm(self, msg):
     print "%s [Y/n] " % msg,
-    answer = self.ReadLine()
+    answer = self.ReadLine(default="Y")
     return answer == "" or answer == "Y" or answer == "y"
 
   def DeleteBranch(self, name):
@@ -254,6 +265,8 @@ class Step(object):
     if not os.path.exists(self._config[DOT_GIT_LOCATION]):
       self.Die("This is not a git checkout, this script won't work for you.")
 
+    # TODO(machenbach): Don't use EDITOR in forced mode as soon as script is
+    # well tested.
     # Cancel if EDITOR is unset or not executable.
     if (not os.environ.get("EDITOR") or
         Command("which", os.environ["EDITOR"]) is None):
@@ -325,6 +338,8 @@ class Step(object):
     answer = ""
     while answer != "LGTM":
       print "> ",
+      # TODO(machenbach): Add default="LGTM" to avoid prompt when script is
+      # well tested and when prepare push cl has TBR flag.
       answer = self.ReadLine()
       if answer != "LGTM":
         print "That was not 'LGTM'."
@@ -333,6 +348,7 @@ class Step(object):
     print("Applying the patch \"%s\" failed. Either type \"ABORT<Return>\", "
           "or resolve the conflicts, stage *all* touched files with "
           "'git add', and type \"RESOLVED<Return>\"")
+    self.DieInForcedMode()
     answer = ""
     while answer != "RESOLVED":
       if answer == "ABORT":
@@ -354,8 +370,13 @@ class UploadStep(Step):
     Step.__init__(self, "Upload for code review.")
 
   def RunStep(self):
-    print "Please enter the email address of a V8 reviewer for your patch: ",
-    reviewer = self.ReadLine()
+    if self._options and self._options.r:
+      print "Using account %s for review." % self._options.r
+      reviewer = self._options.r
+    else:
+      print "Please enter the email address of a V8 reviewer for your patch: ",
+      self.DieInForcedMode("A reviewer must be specified in forced mode.")
+      reviewer = self.ReadLine()
     args = "cl upload -r \"%s\" --send-mail" % reviewer
     if self.Git(args,pipe=False) is None:
       self.Die("'git cl upload' failed, please try again.")
index b1ec658..c8fdc7e 100755 (executable)
@@ -135,8 +135,10 @@ class EditChangeLog(Step):
     print ("Please press <Return> to have your EDITOR open the ChangeLog "
            "entry, then edit its contents to your liking. When you're done, "
            "save the file and exit your EDITOR. ")
-    self.ReadLine()
+    self.ReadLine(default="")
 
+    # TODO(machenbach): Don't use EDITOR in forced mode as soon as script is
+    # well tested.
     self.Editor(self.Config(CHANGELOG_ENTRY_FILE))
     handle, new_changelog = tempfile.mkstemp()
     os.close(handle)
@@ -354,6 +356,7 @@ class CommitSVN(Step):
       print("Sorry, grepping for the SVN revision failed. Please look for it "
             "in the last command's output above and provide it manually (just "
             "the number, without the leading \"r\").")
+      self.DieInForcedMode("Can't prompt in forced mode.")
       while not trunk_revision:
         print "> ",
         trunk_revision = self.ReadLine()
@@ -380,6 +383,8 @@ class CheckChromium(Step):
   def Run(self):
     chrome_path = self._options.c
     if not chrome_path:
+      self.DieInForcedMode("Please specify the path to a Chromium checkout in "
+                          "forced mode.")
       print ("Do you have a \"NewGit\" Chromium checkout and want "
           "this script to automate creation of the roll CL? If yes, enter the "
           "path to (and including) the \"src\" directory here, otherwise just "
@@ -442,8 +447,13 @@ class UploadCL(Step):
     ver = "%s.%s.%s" % (self._state["major"],
                         self._state["minor"],
                         self._state["build"])
-    print "Please enter the email address of a reviewer for the roll CL: ",
-    rev = self.ReadLine()
+    if self._options and self._options.r:
+      print "Using account %s for review." % self._options.r
+      rev = self._options.r
+    else:
+      print "Please enter the email address of a reviewer for the roll CL: ",
+      self.DieInForcedMode("A reviewer must be specified in forced mode.")
+      rev = self.ReadLine()
     args = "commit -am \"Update V8 to version %s.\n\nTBR=%s\"" % (ver, rev)
     if self.Git(args) is None:
       self.Die("'git commit' failed.")
@@ -523,15 +533,20 @@ def RunPushToTrunk(config,
 
 def BuildOptions():
   result = optparse.OptionParser()
-  result.add_option("-s", "--step", dest="s",
-                    help="Specify the step where to start work. Default: 0.",
-                    default=0, type="int")
-  result.add_option("-l", "--last-push", dest="l",
-                    help=("Manually specify the git commit ID "
-                          "of the last push to trunk."))
   result.add_option("-c", "--chromium", dest="c",
                     help=("Specify the path to your Chromium src/ "
                           "directory to automate the V8 roll."))
+  result.add_option("-f", "--force", dest="f",
+                    help="Don't prompt the user.",
+                    default=False, action="store_true")
+  result.add_option("-l", "--last-push", dest="l",
+                    help=("Manually specify the git commit ID "
+                          "of the last push to trunk."))
+  result.add_option("-r", "--reviewer", dest="r",
+                    help=("Specify the account name to be used for reviews."))
+  result.add_option("-s", "--step", dest="s",
+                    help="Specify the step where to start work. Default: 0.",
+                    default=0, type="int")
   return result
 
 
index b44c70b..6ce22de 100644 (file)
@@ -430,7 +430,7 @@ class ScriptTest(unittest.TestCase):
     patch = FileToText(TEST_CONFIG[ PATCH_FILE])
     self.assertTrue(re.search(r"patch content", patch))
 
-  def testPushToTrunk(self):
+  def _PushToTrunk(self, force=False):
     TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile()
     TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile()
     TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile()
@@ -518,6 +518,12 @@ class ScriptTest(unittest.TestCase):
       "Y",  # Sanity check.
       "reviewer@chromium.org",  # Chromium reviewer.
     ]
+    if force:
+      # TODO(machenbach): The lgtm for the prepare push is just temporary.
+      # There should be no user input in "force" mode.
+      self._rl_recipe = [
+        "LGTM",  # Enter LGTM for V8 CL.
+      ]
 
     class Options( object ):
       pass
@@ -525,6 +531,8 @@ class ScriptTest(unittest.TestCase):
     options = Options()
     options.s = 0
     options.l = None
+    options.f = force
+    options.r = "reviewer@chromium.org" if force else None
     options.c = TEST_CONFIG[CHROMIUM]
     RunPushToTrunk(TEST_CONFIG, options, self)
 
@@ -540,3 +548,9 @@ class ScriptTest(unittest.TestCase):
     # Note: The version file is on build number 5 again in the end of this test
     # since the git command that merges to the bleeding edge branch is mocked
     # out.
+
+  def testPushToTrunk(self):
+    self._PushToTrunk()
+
+  def testPushToTrunkForced(self):
+    self._PushToTrunk(force=True)