Home | History | Annotate | Download | only in push-to-trunk
      1 #!/usr/bin/env python
      2 # Copyright 2014 the V8 project authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 """
      7 Script for auto-increasing the version on bleeding_edge.
      8 
      9 The script can be run regularly by a cron job. It will increase the build
     10 level of the version on bleeding_edge if:
     11 - the lkgr version is smaller than the version of the latest revision,
     12 - the lkgr version is not a version change itself,
     13 - the tree is not closed for maintenance.
     14 
     15 The new version will be the maximum of the bleeding_edge and trunk versions +1.
     16 E.g. latest bleeding_edge version: 3.22.11.0 and latest trunk 3.23.0.0 gives
     17 the new version 3.23.1.0.
     18 
     19 This script requires a depot tools git checkout. I.e. 'fetch v8'.
     20 """
     21 
     22 import argparse
     23 import os
     24 import sys
     25 
     26 from common_includes import *
     27 
     28 VERSION_BRANCH = "auto-bump-up-version"
     29 
     30 
     31 class Preparation(Step):
     32   MESSAGE = "Preparation."
     33 
     34   def RunStep(self):
     35     # Check for a clean workdir.
     36     if not self.GitIsWorkdirClean():  # pragma: no cover
     37       # This is in case a developer runs this script on a dirty tree.
     38       self.GitStash()
     39 
     40     # TODO(machenbach): This should be called master after the git switch.
     41     self.GitCheckout("bleeding_edge")
     42 
     43     self.GitPull()
     44 
     45     # Ensure a clean version branch.
     46     self.DeleteBranch(VERSION_BRANCH)
     47 
     48 
     49 class GetCurrentBleedingEdgeVersion(Step):
     50   MESSAGE = "Get latest bleeding edge version."
     51 
     52   def RunStep(self):
     53     # TODO(machenbach): This should be called master after the git switch.
     54     self.GitCheckout("bleeding_edge")
     55 
     56     # Store latest version and revision.
     57     self.ReadAndPersistVersion()
     58     self["latest_version"] = self.ArrayToVersion("")
     59     self["latest"] = self.GitLog(n=1, format="%H")
     60     print "Bleeding edge version: %s" % self["latest_version"]
     61 
     62 
     63 # This step is pure paranoia. It forbids the script to continue if the last
     64 # commit changed version.cc. Just in case the other bailout has a bug, this
     65 # prevents the script from continuously commiting version changes.
     66 class LastChangeBailout(Step):
     67   MESSAGE = "Stop script if the last change modified the version."
     68 
     69   def RunStep(self):
     70     if VERSION_FILE in self.GitChangedFiles(self["latest"]):
     71       print "Stop due to recent version change."
     72       return True
     73 
     74 
     75 # TODO(machenbach): Implement this for git.
     76 class FetchLKGR(Step):
     77   MESSAGE = "Fetching V8 LKGR."
     78 
     79   def RunStep(self):
     80     lkgr_url = "https://v8-status.appspot.com/lkgr"
     81     self["lkgr_svn"] = self.ReadURL(lkgr_url, wait_plan=[5])
     82 
     83 
     84 # TODO(machenbach): Implement this for git. With a git lkgr we could simply
     85 # checkout that revision. With svn, we have to search backwards until that
     86 # revision is found.
     87 class GetLKGRVersion(Step):
     88   MESSAGE = "Get bleeding edge lkgr version."
     89 
     90   def RunStep(self):
     91     self.GitCheckout("bleeding_edge")
     92     # If the commit was made from svn, there is a mapping entry in the commit
     93     # message.
     94     self["lkgr"] = self.GitLog(
     95         grep="^git-svn-id: [^@]*@%s [A-Za-z0-9-]*$" % self["lkgr_svn"],
     96         format="%H")
     97 
     98     # FIXME(machenbach): http://crbug.com/391712 can lead to svn lkgrs on the
     99     # trunk branch (rarely).
    100     if not self["lkgr"]:  # pragma: no cover
    101       self.Die("No git hash found for svn lkgr.")
    102 
    103     self.GitCreateBranch(VERSION_BRANCH, self["lkgr"])
    104     self.ReadAndPersistVersion("lkgr_")
    105     self["lkgr_version"] = self.ArrayToVersion("lkgr_")
    106     print "LKGR version: %s" % self["lkgr_version"]
    107 
    108     # Ensure a clean version branch.
    109     self.GitCheckout("bleeding_edge")
    110     self.DeleteBranch(VERSION_BRANCH)
    111 
    112 
    113 class LKGRVersionUpToDateBailout(Step):
    114   MESSAGE = "Stop script if the lkgr has a renewed version."
    115 
    116   def RunStep(self):
    117     # If a version-change commit becomes the lkgr, don't bump up the version
    118     # again.
    119     if VERSION_FILE in self.GitChangedFiles(self["lkgr"]):
    120       print "Stop because the lkgr is a version change itself."
    121       return True
    122 
    123     # Don't bump up the version if it got updated already after the lkgr.
    124     if SortingKey(self["lkgr_version"]) < SortingKey(self["latest_version"]):
    125       print("Stop because the latest version already changed since the lkgr "
    126             "version.")
    127       return True
    128 
    129 
    130 class GetTrunkVersion(Step):
    131   MESSAGE = "Get latest trunk version."
    132 
    133   def RunStep(self):
    134     # TODO(machenbach): This should be called trunk after the git switch.
    135     self.GitCheckout("master")
    136     self.GitPull()
    137     self.ReadAndPersistVersion("trunk_")
    138     self["trunk_version"] = self.ArrayToVersion("trunk_")
    139     print "Trunk version: %s" % self["trunk_version"]
    140 
    141 
    142 class CalculateVersion(Step):
    143   MESSAGE = "Calculate the new version."
    144 
    145   def RunStep(self):
    146     if self["lkgr_build"] == "9999":  # pragma: no cover
    147       # If version control on bleeding edge was switched off, just use the last
    148       # trunk version.
    149       self["lkgr_version"] = self["trunk_version"]
    150 
    151     # The new version needs to be greater than the max on bleeding edge and
    152     # trunk.
    153     max_version = max(self["trunk_version"],
    154                       self["lkgr_version"],
    155                       key=SortingKey)
    156 
    157     # Strip off possible leading zeros.
    158     self["new_major"], self["new_minor"], self["new_build"], _ = (
    159         map(str, map(int, max_version.split("."))))
    160 
    161     self["new_build"] = str(int(self["new_build"]) + 1)
    162     self["new_patch"] = "0"
    163 
    164     self["new_version"] = ("%s.%s.%s.0" %
    165         (self["new_major"], self["new_minor"], self["new_build"]))
    166     print "New version is %s" % self["new_version"]
    167 
    168     if self._options.dry_run:  # pragma: no cover
    169       print "Dry run, skipping version change."
    170       return True
    171 
    172 
    173 class CheckTreeStatus(Step):
    174   MESSAGE = "Checking v8 tree status message."
    175 
    176   def RunStep(self):
    177     status_url = "https://v8-status.appspot.com/current?format=json"
    178     status_json = self.ReadURL(status_url, wait_plan=[5, 20, 300, 300])
    179     message = json.loads(status_json)["message"]
    180     if re.search(r"maintenance|no commits", message, flags=re.I):
    181       print "Skip version change by tree status: \"%s\"" % message
    182       return True
    183 
    184 
    185 class ChangeVersion(Step):
    186   MESSAGE = "Bump up the version."
    187 
    188   def RunStep(self):
    189     self.GitCreateBranch(VERSION_BRANCH, "bleeding_edge")
    190 
    191     self.SetVersion(os.path.join(self.default_cwd, VERSION_FILE), "new_")
    192 
    193     try:
    194       msg = "[Auto-roll] Bump up version to %s" % self["new_version"]
    195       self.GitCommit("%s\n\nTBR=%s" % (msg, self._options.author),
    196                      author=self._options.author)
    197       if self._options.svn:
    198         self.SVNCommit("branches/bleeding_edge", msg)
    199       else:
    200         self.GitUpload(author=self._options.author,
    201                        force=self._options.force_upload,
    202                        bypass_hooks=True)
    203         self.GitDCommit()
    204       print "Successfully changed the version."
    205     finally:
    206       # Clean up.
    207       self.GitCheckout("bleeding_edge")
    208       self.DeleteBranch(VERSION_BRANCH)
    209 
    210 
    211 class BumpUpVersion(ScriptsBase):
    212   def _PrepareOptions(self, parser):
    213     parser.add_argument("--dry_run", help="Don't commit the new version.",
    214                         default=False, action="store_true")
    215 
    216   def _ProcessOptions(self, options):  # pragma: no cover
    217     if not options.dry_run and not options.author:
    218       print "Specify your chromium.org email with -a"
    219       return False
    220     options.wait_for_lgtm = False
    221     options.force_readline_defaults = True
    222     options.force_upload = True
    223     return True
    224 
    225   def _Config(self):
    226     return {
    227       "PERSISTFILE_BASENAME": "/tmp/v8-bump-up-version-tempfile",
    228     }
    229 
    230   def _Steps(self):
    231     return [
    232       Preparation,
    233       GetCurrentBleedingEdgeVersion,
    234       LastChangeBailout,
    235       FetchLKGR,
    236       GetLKGRVersion,
    237       LKGRVersionUpToDateBailout,
    238       GetTrunkVersion,
    239       CalculateVersion,
    240       CheckTreeStatus,
    241       ChangeVersion,
    242     ]
    243 
    244 if __name__ == "__main__":  # pragma: no cover
    245   sys.exit(BumpUpVersion().Run())
    246