| Index: tools/push-to-trunk/auto_tag.py
|
| diff --git a/tools/push-to-trunk/auto_tag.py b/tools/push-to-trunk/auto_tag.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..d2bf9234310e4b137362689183e0b24a548a6e21
|
| --- /dev/null
|
| +++ b/tools/push-to-trunk/auto_tag.py
|
| @@ -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())
|
|
|