Revision: 18247
Author:   machenb...@chromium.org
Date:     Wed Dec  4 08:47:18 2013 UTC
Log:      Add fully automated mode to push-to-trunk script.

Now there are three modes to run the script:
(1) default: semi-automated
(2) manual (-m option), like in the old script
(3) forced (-f option), no user input required no editor check

R=u...@chromium.org

Review URL: https://codereview.chromium.org/102253002
http://code.google.com/p/v8/source/detail?r=18247

Modified:
 /branches/bleeding_edge/tools/push-to-trunk/auto_roll.py
 /branches/bleeding_edge/tools/push-to-trunk/common_includes.py
 /branches/bleeding_edge/tools/push-to-trunk/push_to_trunk.py
 /branches/bleeding_edge/tools/push-to-trunk/test_scripts.py

=======================================
--- /branches/bleeding_edge/tools/push-to-trunk/auto_roll.py Mon Dec 2 09:53:28 2013 UTC +++ /branches/bleeding_edge/tools/push-to-trunk/auto_roll.py Wed Dec 4 08:47:18 2013 UTC
@@ -96,6 +96,9 @@

 def BuildOptions():
   result = optparse.OptionParser()
+  result.add_option("-f", "--force", dest="f",
+                    help="Don't prompt the user.",
+                    default=True, action="store_true")
   result.add_option("-s", "--step", dest="s",
help="Specify the step where to start work. Default: 0.",
                     default=0, type="int")
=======================================
--- /branches/bleeding_edge/tools/push-to-trunk/common_includes.py Tue Dec 3 12:38:25 2013 UTC +++ /branches/bleeding_edge/tools/push-to-trunk/common_includes.py Wed Dec 4 08:47:18 2013 UTC
@@ -229,6 +229,12 @@
   def Config(self, key):
     return self._config[key]

+  def IsForced(self):
+    return self._options and self._options.f
+
+  def IsManual(self):
+    return self._options and self._options.m
+
   def Run(self):
     if self._requires:
       self.RestoreIfUnset(self._requires)
@@ -271,7 +277,7 @@

   def ReadLine(self, default=None):
     # Don't prompt in forced mode.
-    if self._options and self._options.f and default is not None:
+    if not self.IsManual() and default is not None:
       print "%s (forced)" % default
       return default
     else:
@@ -282,8 +288,9 @@
     return self.Retry(cmd, retry_on, [5, 30])

   def Editor(self, args):
-    return self._side_effect_handler.Command(os.environ["EDITOR"], args,
-                                             pipe=False)
+    if not self.IsForced():
+      return self._side_effect_handler.Command(os.environ["EDITOR"], args,
+                                               pipe=False)

   def ReadURL(self, url, retry_on=None, wait_plan=None):
     wait_plan = wait_plan or [3, 60, 600]
@@ -299,9 +306,9 @@
     print "Exiting"
     raise Exception(msg)

-  def DieInForcedMode(self, msg=""):
-    if self._options and self._options.f:
-      msg = msg or "Not implemented in forced mode."
+  def DieNoManualMode(self, msg=""):
+    if not self.IsManual():
+      msg = msg or "Only available in manual mode."
       self.Die(msg)

   def Confirm(self, msg):
@@ -340,11 +347,9 @@
     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):
+    if (not self.IsForced() and (not os.environ.get("EDITOR") or
+        Command("which", os.environ["EDITOR"]) is None)):
self.Die("Please set your EDITOR environment variable, you'll need it.")

   def CommonPrepare(self):
@@ -413,9 +418,7 @@
     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()
+      answer = self.ReadLine("LGTM" if self.IsForced() else None)
       if answer != "LGTM":
         print "That was not 'LGTM'."

@@ -423,7 +426,7 @@
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()
+    self.DieNoManualMode()
     answer = ""
     while answer != "RESOLVED":
       if answer == "ABORT":
@@ -449,9 +452,9 @@
       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.")
+      self.DieNoManualMode("A reviewer must be specified in forced mode.")
       reviewer = self.ReadLine()
-    force_flag = " -f" if self._options.f else ""
+    force_flag = " -f" if not self.IsManual() else ""
     args = "cl upload -r \"%s\" --send-mail%s" % (reviewer, force_flag)
# TODO(machenbach): Check output in forced mode. Verify that all required
     # base files were uploaded, if not retry.
=======================================
--- /branches/bleeding_edge/tools/push-to-trunk/push_to_trunk.py Tue Dec 3 12:38:25 2013 UTC +++ /branches/bleeding_edge/tools/push-to-trunk/push_to_trunk.py Wed Dec 4 08:47:18 2013 UTC
@@ -157,9 +157,6 @@
"entry, then edit its contents to your liking. When you're done, "
            "save the file and exit your EDITOR. ")
     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)
@@ -214,7 +211,11 @@
                                               self._state["new_minor"],
                                               self._state["new_build"]))
     self.Persist("prep_commit_msg", prep_commit_msg)
-    if self.Git("commit -a -m \"%s\"" % prep_commit_msg) is None:
+
+    # Include optional TBR only in the git command. The persisted commit
+    # message is used for finding the commit again later.
+    review = "\n\nTBR=%s" % self._options.r if not self.IsManual() else ""
+ if self.Git("commit -a -m \"%s%s\"" % (prep_commit_msg, review)) is None:
       self.Die("'git commit -a' failed.")


@@ -364,7 +365,7 @@
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.")
+      self.DieNoManualMode("Can't prompt in forced mode.")
       while not trunk_revision:
         print "> ",
         trunk_revision = self.ReadLine()
@@ -389,7 +390,7 @@
   def Run(self):
     chrome_path = self._options.c
     if not chrome_path:
- self.DieInForcedMode("Please specify the path to a Chromium checkout in " + self.DieNoManualMode("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 "
@@ -457,12 +458,12 @@
       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.")
+      self.DieNoManualMode("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.")
-    force_flag = " -f" if self._options.f else ""
+    force_flag = " -f" if not self.IsManual() else ""
if self.Git("cl upload --send-mail%s" % force_flag, pipe=False) is None:
       self.Die("'git cl upload' failed, please try again.")
     print "CL uploaded."
@@ -547,6 +548,9 @@
   result.add_option("-l", "--last-push", dest="l",
                     help=("Manually specify the git commit ID "
                           "of the last push to trunk."))
+  result.add_option("-m", "--manual", dest="m",
+                    help="Prompt the user at every important step.",
+                    default=False, action="store_true")
   result.add_option("-r", "--reviewer", dest="r",
help=("Specify the account name to be used for reviews."))
   result.add_option("-s", "--step", dest="s",
@@ -559,11 +563,14 @@
   if options.s < 0:
     print "Bad step number %d" % options.s
     return False
-  if options.f and not options.r:
-    print "A reviewer (-r) is required in forced mode."
+  if not options.m and not options.r:
+    print "A reviewer (-r) is required in (semi-)automatic mode."
+    return False
+  if options.f and options.m:
+    print "Manual and forced mode cannot be combined."
     return False
-  if options.f and not options.c:
-    print "A chromium checkout (-c) is required in forced mode."
+  if not options.m and not options.c:
+    print "A chromium checkout (-c) is required in (semi-)automatic mode."
     return False
   return True

=======================================
--- /branches/bleeding_edge/tools/push-to-trunk/test_scripts.py Tue Dec 3 12:38:25 2013 UTC +++ /branches/bleeding_edge/tools/push-to-trunk/test_scripts.py Wed Dec 4 08:47:18 2013 UTC
@@ -51,6 +51,20 @@
   CHROMIUM: "/tmp/test-v8-push-to-trunk-tempfile-chromium",
   DEPS_FILE: "/tmp/test-v8-push-to-trunk-tempfile-chromium/DEPS",
 }
+
+
+def MakeOptions(s=0, l=None, f=False, m=True, r=None, c=None):
+  """Convenience wrapper."""
+  class Options(object):
+      pass
+  options = Options()
+  options.s = s
+  options.l = l
+  options.f = f
+  options.m = m
+  options.r = r
+  options.c = c
+  return options


 class ToplevelTest(unittest.TestCase):
@@ -260,12 +274,15 @@
       f.write("#define IS_CANDIDATE_VERSION 0\n")
     return name

-  def MakeStep(self, step_class=Step, state=None):
+  def MakeStep(self, step_class=Step, state=None, options=None):
     """Convenience wrapper."""
+    options = options or MakeOptions()
     return MakeStep(step_class=step_class, number=0, state=state,
- config=TEST_CONFIG, options=None, side_effect_handler=self)
+                    config=TEST_CONFIG, options=options,
+                    side_effect_handler=self)

   def GitMock(self, cmd, args="", pipe=True):
+    print "%s %s" % (cmd, args)
     return self._git_mock.Call(args)

   def LogMock(self, cmd, args=""):
@@ -555,7 +572,7 @@
     patch = FileToText(TEST_CONFIG[ PATCH_FILE])
     self.assertTrue(re.search(r"patch content", patch))

-  def _PushToTrunk(self, force=False):
+  def _PushToTrunk(self, force=False, manual=False):
     TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile()
     TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile()
     TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile()
@@ -593,7 +610,8 @@
       self.assertTrue(re.search(r"#define PATCH_LEVEL\s+0", version))
self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version))

-    force_flag = " -f" if force else ""
+    force_flag = " -f" if not manual else ""
+    review_suffix = "\n\nTBR=revie...@chromium.org" if not manual else ""
     self.ExpectGit([
       ["status -s -uno", ""],
       ["status -s -b -uno", "## some_branch\n"],
@@ -610,7 +628,7 @@
       ["log -1 rev1 --format=\"%B\"", "Text\nLOG=YES\nBUG=v8:321\nText\n"],
       ["log -1 rev1 --format=\"%an\"", "auth...@chromium.org\n"],
       [("commit -a -m \"Prepare push to trunk.  "
-        "Now working on version 3.22.6.\""),
+        "Now working on version 3.22.6.%s\"" % review_suffix),
        " 2 files changed\n",
         CheckPreparePush],
       ["cl upload -r \"revie...@chromium.org\" --send-mail%s" % force_flag,
@@ -641,32 +659,33 @@
       ["branch -D %s" % TEST_CONFIG[BRANCHNAME], ""],
       ["branch -D %s" % TEST_CONFIG[TRUNKBRANCH], ""],
     ])
-    self.ExpectReadline([
-      "Y",  # Confirm last push.
-      "",  # Open editor.
-      "Y",  # Increment build number.
-      "revie...@chromium.org",  # V8 reviewer.
-      "LGTX",  # Enter LGTM for V8 CL (wrong).
-      "LGTM",  # Enter LGTM for V8 CL.
-      "Y",  # Sanity check.
-      "revie...@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.
+
+    # Expected keyboard input in manual mode:
+    if manual:
       self.ExpectReadline([
+        "Y",  # Confirm last push.
+        "",  # Open editor.
+        "Y",  # Increment build number.
+        "revie...@chromium.org",  # V8 reviewer.
+        "LGTX",  # Enter LGTM for V8 CL (wrong).
         "LGTM",  # Enter LGTM for V8 CL.
+        "Y",  # Sanity check.
+        "revie...@chromium.org",  # Chromium reviewer.
       ])

-    class Options( object ):
-      pass
+    # Expected keyboard input in semi-automatic mode:
+    if not manual and not force:
+      self.ExpectReadline([
+        "LGTM",  # Enter LGTM for V8 CL.
+      ])

-    options = Options()
-    options.s = 0
-    options.l = None
-    options.f = force
-    options.r = "revie...@chromium.org" if force else None
-    options.c = TEST_CONFIG[CHROMIUM]
+    # No keyboard input in forced mode:
+    if force:
+      self.ExpectReadline([])
+
+    options = MakeOptions(f=force, m=manual,
+ r="revie...@chromium.org" if not manual else None,
+                          c = TEST_CONFIG[CHROMIUM])
     RunPushToTrunk(TEST_CONFIG, options, self)

     deps = FileToText(TEST_CONFIG[DEPS_FILE])
@@ -681,7 +700,10 @@
# since the git command that merges to the bleeding edge branch is mocked
     # out.

-  def testPushToTrunk(self):
+  def testPushToTrunkManual(self):
+    self._PushToTrunk(manual=True)
+
+  def testPushToTrunkSemiAutomatic(self):
     self._PushToTrunk()

   def testPushToTrunkForced(self):
@@ -690,9 +712,6 @@
   def testAutoRoll(self):
     TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile()

-    # TODO(machenbach): Get rid of the editor check in automatic mode.
-    os.environ["EDITOR"] = "vi"
-
     self.ExpectReadURL([
       ["https://v8-status.appspot.com/lkgr";, Exception("Network problem")],
       ["https://v8-status.appspot.com/lkgr";, "100"],
@@ -705,14 +724,7 @@
       ["svn log -1 --oneline", "r101 | Text"],
     ])

-    # TODO(machenbach): Make a convenience wrapper for this.
-    class Options( object ):
-      pass
-
-    options = Options()
-    options.s = 0
-
-    auto_roll.RunAutoRoll(TEST_CONFIG, options, self)
+    auto_roll.RunAutoRoll(TEST_CONFIG, MakeOptions(m=False, f=True), self)

     self.assertEquals("100", self.MakeStep().Restore("lkgr"))
     self.assertEquals("101", self.MakeStep().Restore("latest"))

--
--
v8-dev mailing list
v8-dev@googlegroups.com
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to