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 R=jarin@chromium.org Review URL: https://codereview.chromium.org/400693002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22477 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
4c136e0baa
commit
d9fa8f77e8
200
tools/push-to-trunk/auto_tag.py
Executable file
200
tools/push-to-trunk/auto_tag.py
Executable file
@ -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())
|
@ -244,6 +244,9 @@ class SideEffectHandler(object): # pragma: no cover
|
||||
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()
|
||||
|
||||
|
||||
|
@ -185,6 +185,9 @@ class GitRecipesMixin(object):
|
||||
def GitSVNFetch(self):
|
||||
self.Git("svn fetch")
|
||||
|
||||
def GitSVNRebase(self):
|
||||
self.Git("svn rebase")
|
||||
|
||||
# TODO(machenbach): Unused? Remove.
|
||||
@Strip
|
||||
def GitSVNLog(self):
|
||||
|
@ -52,6 +52,7 @@ import bump_up_version
|
||||
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 @@ class ScriptTest(unittest.TestCase):
|
||||
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 @@ LOG=N
|
||||
|
||||
BumpUpVersion(TEST_CONFIG, self).Run(["-a", "author@chromium.org"])
|
||||
|
||||
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", "author@chromium.org"])
|
||||
|
||||
# Test that we bail out if the last change was a version change.
|
||||
def testBumpUpVersionBailout1(self):
|
||||
TEST_CONFIG[VERSION_FILE] = self.MakeEmptyTempFile()
|
||||
|
Loading…
Reference in New Issue
Block a user