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""" 7Script for auto-increasing the version on bleeding_edge. 8 9The script can be run regularly by a cron job. It will increase the build 10level 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 15The new version will be the maximum of the bleeding_edge and trunk versions +1. 16E.g. latest bleeding_edge version: 3.22.11.0 and latest trunk 3.23.0.0 gives 17the new version 3.23.1.0. 18 19This script requires a depot tools git checkout. I.e. 'fetch v8'. 20""" 21 22import argparse 23import os 24import sys 25 26from common_includes import * 27 28VERSION_BRANCH = "auto-bump-up-version" 29 30 31class 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 49class 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. 66class 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. 76class 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. 87class 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 113class 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 130class 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 142class 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 173class 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 185class 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 211class 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 244if __name__ == "__main__": # pragma: no cover 245 sys.exit(BumpUpVersion().Run()) 246