Revision: 22477
Author:   [email protected]
Date:     Fri Jul 18 12:16:14 2014 UTC
Log:      Add automatic tag script.

The script can be run in a cron job to automatically tag
lkgrs.

BUG=391261
LOG=n
TEST=tools/push-to-trunk/script_test.py
TEST=tools/push-to-trunk/auto_tag.py --dry_run
[email protected]

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

Added:
 /branches/bleeding_edge/tools/push-to-trunk/auto_tag.py
Modified:
 /branches/bleeding_edge/tools/push-to-trunk/common_includes.py
 /branches/bleeding_edge/tools/push-to-trunk/git_recipes.py
 /branches/bleeding_edge/tools/push-to-trunk/test_scripts.py

=======================================
--- /dev/null
+++ /branches/bleeding_edge/tools/push-to-trunk/auto_tag.py Fri Jul 18 12:16:14 2014 UTC
@@ -0,0 +1,200 @@
+#!/usr/bin/env python
+# Copyright 2014 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import sys
+
+from common_includes import *
+
+CONFIG = {
+  BRANCHNAME: "auto-tag-v8",
+  PERSISTFILE_BASENAME: "/tmp/v8-auto-tag-tempfile",
+  DOT_GIT_LOCATION: ".git",
+  VERSION_FILE: "src/version.cc",
+}
+
+
+class Preparation(Step):
+  MESSAGE = "Preparation."
+
+  def RunStep(self):
+    self.CommonPrepare()
+    self.PrepareBranch()
+    self.GitCheckout("master")
+    self.GitSVNRebase()
+
+
+class GetTags(Step):
+  MESSAGE = "Get all V8 tags."
+
+  def RunStep(self):
+    self.GitCreateBranch(self._config[BRANCHNAME])
+
+    # Get remote tags.
+    tags = filter(lambda s: re.match(r"^svn/tags/[\d+\.]+$", s),
+                  self.GitRemotes())
+
+    # Remove 'svn/tags/' prefix.
+    self["tags"] = map(lambda s: s[9:], tags)
+
+
+class GetOldestUntaggedVersion(Step):
+  MESSAGE = "Check if there's a version on bleeding edge without a tag."
+
+  def RunStep(self):
+    tags = set(self["tags"])
+    self["candidate"] = None
+    self["candidate_version"] = None
+    self["next"] = None
+    self["next_version"] = None
+
+    # Iterate backwards through all automatic version updates.
+    for git_hash in self.GitLog(
+ format="%H", grep="\\[Auto\\-roll\\] Bump up version to").splitlines():
+
+      # Get the version.
+ if not self.GitCheckoutFileSafe(self._config[VERSION_FILE], git_hash):
+        continue
+
+      self.ReadAndPersistVersion()
+      version = self.ArrayToVersion("")
+
+      # Strip off trailing patch level (tags don't include tag level 0).
+      if version.endswith(".0"):
+        version = version[:-2]
+
+      # Clean up checked-out version file.
+      self.GitCheckoutFileSafe(self._config[VERSION_FILE], "HEAD")
+
+      if version in tags:
+        if self["candidate"]:
+ # Revision "git_hash" is tagged already and "candidate" was the next
+          # newer revision without a tag.
+          break
+        else:
+ print("Stop as %s is the latest version and it has been tagged." %
+                version)
+          self.CommonCleanup()
+          return True
+      else:
+        # This is the second oldest version without a tag.
+        self["next"] = self["candidate"]
+        self["next_version"] = self["candidate_version"]
+
+        # This is the oldest version without a tag.
+        self["candidate"] = git_hash
+        self["candidate_version"] = version
+
+    if not self["candidate"] or not self["candidate_version"]:
+      print "Nothing found to tag."
+      self.CommonCleanup()
+      return True
+
+    print("Candidate for tagging is %s with version %s" %
+          (self["candidate"], self["candidate_version"]))
+
+
+class GetLKGRs(Step):
+  MESSAGE = "Get the last lkgrs."
+
+  def RunStep(self):
+    revision_url = "https://v8-status.appspot.com/revisions?format=json";
+    status_json = self.ReadURL(revision_url, wait_plan=[5, 20])
+    self["lkgrs"] = [entry["revision"]
+ for entry in json.loads(status_json) if entry["status"]]
+
+
+class CalculateTagRevision(Step):
+  MESSAGE = "Calculate the revision to tag."
+
+  def LastLKGR(self, min_rev, max_rev):
+    """Finds the newest lkgr between min_rev (inclusive) and max_rev
+    (exclusive).
+    """
+    for lkgr in self["lkgrs"]:
+      # LKGRs are reverse sorted.
+      if int(min_rev) <= int(lkgr) and int(lkgr) < int(max_rev):
+        return lkgr
+      return None
+
+  def RunStep(self):
+ # Get the lkgr after the tag candidate and before the next tag candidate.
+    candidate_svn = self.GitSVNFindSVNRev(self["candidate"])
+    if self["next"]:
+      next_svn = self.GitSVNFindSVNRev(self["next"])
+    else:
+      # Don't include the version change commit itself if there is no upper
+      # limit yet.
+      candidate_svn =  str(int(candidate_svn) + 1)
+      next_svn = sys.maxint
+    lkgr_svn = self.LastLKGR(candidate_svn, next_svn)
+
+    if not lkgr_svn:
+      print "There is no lkgr since the candidate version yet."
+      self.CommonCleanup()
+      return True
+
+    # Let's check if the lkgr is at least three hours old.
+    self["lkgr"] = self.GitSVNFindGitHash(lkgr_svn)
+    if not self["lkgr"]:
+      print "Couldn't find git hash for lkgr %s" % lkgr_svn
+      self.CommonCleanup()
+      return True
+
+ lkgr_utc_time = int(self.GitLog(n=1, format="%at", git_hash=self["lkgr"]))
+    current_utc_time = self._side_effect_handler.GetUTCStamp()
+
+    if current_utc_time < lkgr_utc_time + 10800:
+      print "Candidate lkgr %s is too recent for tagging." % lkgr_svn
+      self.CommonCleanup()
+      return True
+
+ print "Tagging revision %s with %s" % (lkgr_svn, self["candidate_version"])
+
+
+class MakeTag(Step):
+  MESSAGE = "Tag the version."
+
+  def RunStep(self):
+    if not self._options.dry_run:
+      self.GitReset(self["lkgr"])
+      self.GitSVNTag(self["candidate_version"])
+
+
+class CleanUp(Step):
+  MESSAGE = "Clean up."
+
+  def RunStep(self):
+    self.CommonCleanup()
+
+
+class AutoTag(ScriptsBase):
+  def _PrepareOptions(self, parser):
+    parser.add_argument("--dry_run", help="Don't tag the new version.",
+                        default=False, action="store_true")
+
+  def _ProcessOptions(self, options):  # pragma: no cover
+    if not options.dry_run and not options.author:
+      print "Specify your chromium.org email with -a"
+      return False
+    options.wait_for_lgtm = False
+    options.force_readline_defaults = True
+    options.force_upload = True
+    return True
+
+  def _Steps(self):
+    return [
+      Preparation,
+      GetTags,
+      GetOldestUntaggedVersion,
+      GetLKGRs,
+      CalculateTagRevision,
+      MakeTag,
+      CleanUp,
+    ]
+
+
+if __name__ == "__main__":  # pragma: no cover
+  sys.exit(AutoTag(CONFIG).Run())
=======================================
--- /branches/bleeding_edge/tools/push-to-trunk/common_includes.py Wed Jul 16 07:57:13 2014 UTC +++ /branches/bleeding_edge/tools/push-to-trunk/common_includes.py Fri Jul 18 12:16:14 2014 UTC
@@ -244,6 +244,9 @@
   def GetDate(self):
     return datetime.date.today().strftime("%Y-%m-%d")

+  def GetUTCStamp(self):
+    time.mktime(datetime.datetime.utcnow().timetuple())
+
 DEFAULT_SIDE_EFFECT_HANDLER = SideEffectHandler()


=======================================
--- /branches/bleeding_edge/tools/push-to-trunk/git_recipes.py Wed Jul 16 07:57:13 2014 UTC +++ /branches/bleeding_edge/tools/push-to-trunk/git_recipes.py Fri Jul 18 12:16:14 2014 UTC
@@ -185,6 +185,9 @@
   def GitSVNFetch(self):
     self.Git("svn fetch")

+  def GitSVNRebase(self):
+    self.Git("svn rebase")
+
   # TODO(machenbach): Unused? Remove.
   @Strip
   def GitSVNLog(self):
=======================================
--- /branches/bleeding_edge/tools/push-to-trunk/test_scripts.py Wed Jul 16 07:57:13 2014 UTC +++ /branches/bleeding_edge/tools/push-to-trunk/test_scripts.py Fri Jul 18 12:16:14 2014 UTC
@@ -52,6 +52,7 @@
 from bump_up_version import BumpUpVersion
 from bump_up_version import LastChangeBailout
 from bump_up_version import LKGRVersionUpToDateBailout
+from auto_tag import AutoTag


 TEST_CONFIG = {
@@ -401,6 +402,9 @@
   def GetDate(self):
     return "1999-07-31"

+  def GetUTCStamp(self):
+    return "100000"
+
   def ExpectGit(self, *args):
     """Convenience wrapper."""
     self._git_mock.Expect(*args)
@@ -1323,6 +1327,57 @@

     BumpUpVersion(TEST_CONFIG, self).Run(["-a", "[email protected]"])

+  def testAutoTag(self):
+    TEST_CONFIG[VERSION_FILE] = self.MakeEmptyTempFile()
+    self.WriteFakeVersionFile()
+
+    def ResetVersion(minor, build, patch=0):
+      return lambda: self.WriteFakeVersionFile(minor=minor,
+                                               build=build,
+                                               patch=patch)
+
+    self.ExpectGit([
+      Git("status -s -uno", ""),
+      Git("status -s -b -uno", "## some_branch\n"),
+      Git("svn fetch", ""),
+      Git("branch", "  branch1\n* branch2\n"),
+      Git("checkout -f master", ""),
+      Git("svn rebase", ""),
+      Git("checkout -b %s" % TEST_CONFIG[BRANCHNAME], "",
+          cb=ResetVersion(4, 5)),
+ Git("branch -r", "svn/tags/3.4.2\nsvn/tags/3.2.1.0\nsvn/branches/3.4"), + Git("log --format=%H --grep=\"\\[Auto\\-roll\\] Bump up version to\"",
+          "hash125\nhash118\nhash111\nhash101"),
+      Git("checkout -f hash125 -- %s" % TEST_CONFIG[VERSION_FILE], "",
+          cb=ResetVersion(4, 4)),
+      Git("checkout -f HEAD -- %s" % TEST_CONFIG[VERSION_FILE], "",
+          cb=ResetVersion(4, 5)),
+      Git("checkout -f hash118 -- %s" % TEST_CONFIG[VERSION_FILE], "",
+          cb=ResetVersion(4, 3)),
+      Git("checkout -f HEAD -- %s" % TEST_CONFIG[VERSION_FILE], "",
+          cb=ResetVersion(4, 5)),
+      Git("checkout -f hash111 -- %s" % TEST_CONFIG[VERSION_FILE], "",
+          cb=ResetVersion(4, 2)),
+      Git("checkout -f HEAD -- %s" % TEST_CONFIG[VERSION_FILE], "",
+          cb=ResetVersion(4, 5)),
+      Git("svn find-rev hash118", "118"),
+      Git("svn find-rev hash125", "125"),
+      Git("svn find-rev r123", "hash123"),
+      Git("log -1 --format=%at hash123", "1"),
+      Git("reset --hard hash123", ""),
+      Git("svn tag 3.4.3 -m \"Tagging version 3.4.3\"", ""),
+      Git("checkout -f some_branch", ""),
+      Git("branch -D %s" % TEST_CONFIG[BRANCHNAME], ""),
+    ])
+
+    self.ExpectReadURL([
+      URL("https://v8-status.appspot.com/revisions?format=json";,
+          "[{\"revision\": \"123\", \"status\": true},"
+           "{\"revision\": \"112\", \"status\": true}]"),
+    ])
+
+    AutoTag(TEST_CONFIG, self).Run(["-a", "[email protected]"])
+
   # Test that we bail out if the last change was a version change.
   def testBumpUpVersionBailout1(self):
     TEST_CONFIG[VERSION_FILE] = self.MakeEmptyTempFile()

--
--
v8-dev mailing list
[email protected]
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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to