#!/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. # for py2/py3 compatibility from __future__ import print_function import argparse import sys from common_includes import * class Preparation(Step): MESSAGE = "Preparation." def RunStep(self): # TODO(machenbach): Remove after the git switch. if self.Config("PERSISTFILE_BASENAME") == "/tmp/v8-auto-tag-tempfile": print("This script is disabled until after the v8 git migration.") return True self.CommonPrepare() self.PrepareBranch() self.GitCheckout("master") self.vc.Pull() class GetTags(Step): MESSAGE = "Get all V8 tags." def RunStep(self): self.GitCreateBranch(self._config["BRANCHNAME"]) self["tags"] = self.vc.GetTags() 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(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(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.vc.GitSvn(self["candidate"]) if self["next"]: next_svn = self.vc.GitSvn(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.maxsize 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.vc.SvnGit(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"]) # FIXME(machenbach): Make this work with the git repo. self.vc.Tag(self["candidate_version"], "svn/bleeding_edge", "This won't work!") 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 _Config(self): return { "BRANCHNAME": "auto-tag-v8", "PERSISTFILE_BASENAME": "/tmp/v8-auto-tag-tempfile", } def _Steps(self): return [ Preparation, GetTags, GetOldestUntaggedVersion, GetLKGRs, CalculateTagRevision, MakeTag, CleanUp, ] if __name__ == "__main__": # pragma: no cover sys.exit(AutoTag().Run())