11cb0ef41Sopenharmony_ci#!/usr/bin/env python3 21cb0ef41Sopenharmony_ci# Copyright 2015 the V8 project authors. All rights reserved. 31cb0ef41Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be 41cb0ef41Sopenharmony_ci# found in the LICENSE file. 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ciimport argparse 71cb0ef41Sopenharmony_ciimport os 81cb0ef41Sopenharmony_ciimport sys 91cb0ef41Sopenharmony_ciimport tempfile 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_cifrom common_includes import * 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_ciimport urllib.request as urllib2 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_ciclass Preparation(Step): 171cb0ef41Sopenharmony_ci MESSAGE = "Preparation." 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ci def RunStep(self): 201cb0ef41Sopenharmony_ci self.Git("fetch origin +refs/heads/*:refs/heads/*") 211cb0ef41Sopenharmony_ci self.GitCheckout("origin/main") 221cb0ef41Sopenharmony_ci self.DeleteBranch("work-branch") 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ciclass PrepareBranchRevision(Step): 261cb0ef41Sopenharmony_ci MESSAGE = "Check from which revision to branch off." 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ci def RunStep(self): 291cb0ef41Sopenharmony_ci self["push_hash"] = (self._options.revision or 301cb0ef41Sopenharmony_ci self.GitLog(n=1, format="%H", branch="origin/main")) 311cb0ef41Sopenharmony_ci assert self["push_hash"] 321cb0ef41Sopenharmony_ci print("Release revision %s" % self["push_hash"]) 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ciclass IncrementVersion(Step): 361cb0ef41Sopenharmony_ci MESSAGE = "Increment version number." 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci def RunStep(self): 391cb0ef41Sopenharmony_ci latest_version = self.GetLatestVersion() 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ci # The version file on main can be used to bump up major/minor at 421cb0ef41Sopenharmony_ci # branch time. 431cb0ef41Sopenharmony_ci self.GitCheckoutFile(VERSION_FILE, self.vc.RemoteMainBranch()) 441cb0ef41Sopenharmony_ci self.ReadAndPersistVersion("main_") 451cb0ef41Sopenharmony_ci main_version = self.ArrayToVersion("main_") 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci # Use the highest version from main or from tags to determine the new 481cb0ef41Sopenharmony_ci # version. 491cb0ef41Sopenharmony_ci authoritative_version = sorted( 501cb0ef41Sopenharmony_ci [main_version, latest_version], key=LooseVersion)[1] 511cb0ef41Sopenharmony_ci self.StoreVersion(authoritative_version, "authoritative_") 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci # Variables prefixed with 'new_' contain the new version numbers for the 541cb0ef41Sopenharmony_ci # ongoing candidates push. 551cb0ef41Sopenharmony_ci self["new_major"] = self["authoritative_major"] 561cb0ef41Sopenharmony_ci self["new_minor"] = self["authoritative_minor"] 571cb0ef41Sopenharmony_ci self["new_build"] = str(int(self["authoritative_build"]) + 1) 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci # Make sure patch level is 0 in a new push. 601cb0ef41Sopenharmony_ci self["new_patch"] = "0" 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ci # The new version is not a candidate. 631cb0ef41Sopenharmony_ci self["new_candidate"] = "0" 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ci self["version"] = "%s.%s.%s" % (self["new_major"], 661cb0ef41Sopenharmony_ci self["new_minor"], 671cb0ef41Sopenharmony_ci self["new_build"]) 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci print ("Incremented version to %s" % self["version"]) 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ciclass DetectLastRelease(Step): 731cb0ef41Sopenharmony_ci MESSAGE = "Detect commit ID of last release base." 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci def RunStep(self): 761cb0ef41Sopenharmony_ci self["last_push_main"] = self.GetLatestReleaseBase() 771cb0ef41Sopenharmony_ci 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ciclass DeleteBranchRef(Step): 801cb0ef41Sopenharmony_ci MESSAGE = "Delete branch ref." 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci def RunStep(self): 831cb0ef41Sopenharmony_ci cmd = "push origin :refs/heads/%s" % self["version"] 841cb0ef41Sopenharmony_ci if self._options.dry_run: 851cb0ef41Sopenharmony_ci print("Dry run. Command:\ngit %s" % cmd) 861cb0ef41Sopenharmony_ci else: 871cb0ef41Sopenharmony_ci try: 881cb0ef41Sopenharmony_ci self.Git(cmd) 891cb0ef41Sopenharmony_ci except Exception: 901cb0ef41Sopenharmony_ci # Be forgiving if branch ref does not exist. 911cb0ef41Sopenharmony_ci pass 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_ciclass PushBranchRef(Step): 951cb0ef41Sopenharmony_ci MESSAGE = "Create branch ref." 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci def RunStep(self): 981cb0ef41Sopenharmony_ci cmd = "push origin %s:refs/heads/%s" % (self["push_hash"], self["version"]) 991cb0ef41Sopenharmony_ci if self._options.dry_run: 1001cb0ef41Sopenharmony_ci print("Dry run. Command:\ngit %s" % cmd) 1011cb0ef41Sopenharmony_ci else: 1021cb0ef41Sopenharmony_ci self.Git(cmd) 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ciclass MakeBranch(Step): 1061cb0ef41Sopenharmony_ci MESSAGE = "Create the branch." 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci def RunStep(self): 1091cb0ef41Sopenharmony_ci self.Git("reset --hard origin/main") 1101cb0ef41Sopenharmony_ci self.Git("new-branch work-branch --upstream origin/%s" % self["version"]) 1111cb0ef41Sopenharmony_ci self.GitCheckoutFile(VERSION_FILE, self["latest_version"]) 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ciclass SetVersion(Step): 1151cb0ef41Sopenharmony_ci MESSAGE = "Set correct version for candidates." 1161cb0ef41Sopenharmony_ci 1171cb0ef41Sopenharmony_ci def RunStep(self): 1181cb0ef41Sopenharmony_ci self.SetVersion(os.path.join(self.default_cwd, VERSION_FILE), "new_") 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ciclass EnableMergeWatchlist(Step): 1221cb0ef41Sopenharmony_ci MESSAGE = "Enable watchlist entry for merge notifications." 1231cb0ef41Sopenharmony_ci 1241cb0ef41Sopenharmony_ci def RunStep(self): 1251cb0ef41Sopenharmony_ci old_watchlist_content = FileToText(os.path.join(self.default_cwd, 1261cb0ef41Sopenharmony_ci WATCHLISTS_FILE)) 1271cb0ef41Sopenharmony_ci new_watchlist_content = re.sub("(# 'v8-merges@googlegroups\.com',)", 1281cb0ef41Sopenharmony_ci "'v8-merges@googlegroups.com',", 1291cb0ef41Sopenharmony_ci old_watchlist_content) 1301cb0ef41Sopenharmony_ci TextToFile(new_watchlist_content, os.path.join(self.default_cwd, 1311cb0ef41Sopenharmony_ci WATCHLISTS_FILE)) 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ciclass CommitBranch(Step): 1351cb0ef41Sopenharmony_ci MESSAGE = "Commit version to new branch." 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ci def RunStep(self): 1381cb0ef41Sopenharmony_ci self["commit_title"] = "Version %s" % self["version"] 1391cb0ef41Sopenharmony_ci text = "%s" % (self["commit_title"]) 1401cb0ef41Sopenharmony_ci TextToFile(text, self.Config("COMMITMSG_FILE")) 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci self.GitCommit(file_name=self.Config("COMMITMSG_FILE")) 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ciclass LandBranch(Step): 1461cb0ef41Sopenharmony_ci MESSAGE = "Upload and land changes." 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci def RunStep(self): 1491cb0ef41Sopenharmony_ci if self._options.dry_run: 1501cb0ef41Sopenharmony_ci print("Dry run - upload CL.") 1511cb0ef41Sopenharmony_ci else: 1521cb0ef41Sopenharmony_ci self.GitUpload(force=True, 1531cb0ef41Sopenharmony_ci bypass_hooks=True, 1541cb0ef41Sopenharmony_ci no_autocc=True, 1551cb0ef41Sopenharmony_ci set_bot_commit=True, 1561cb0ef41Sopenharmony_ci message_file=self.Config("COMMITMSG_FILE")) 1571cb0ef41Sopenharmony_ci # TODO(crbug.com/1176141): This might need to go through CQ. 1581cb0ef41Sopenharmony_ci # We'd need to wait for it to land and then tag it. 1591cb0ef41Sopenharmony_ci cmd = "cl land --bypass-hooks -f" 1601cb0ef41Sopenharmony_ci if self._options.dry_run: 1611cb0ef41Sopenharmony_ci print("Dry run. Command:\ngit %s" % cmd) 1621cb0ef41Sopenharmony_ci else: 1631cb0ef41Sopenharmony_ci self.Git(cmd) 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ci os.remove(self.Config("COMMITMSG_FILE")) 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ciclass TagRevision(Step): 1691cb0ef41Sopenharmony_ci MESSAGE = "Tag the new revision." 1701cb0ef41Sopenharmony_ci 1711cb0ef41Sopenharmony_ci def RunStep(self): 1721cb0ef41Sopenharmony_ci if self._options.dry_run: 1731cb0ef41Sopenharmony_ci print ("Dry run. Tagging \"%s\" with %s" % 1741cb0ef41Sopenharmony_ci (self["commit_title"], self["version"])) 1751cb0ef41Sopenharmony_ci else: 1761cb0ef41Sopenharmony_ci self.vc.Tag(self["version"], 1771cb0ef41Sopenharmony_ci "origin/%s" % self["version"], 1781cb0ef41Sopenharmony_ci self["commit_title"]) 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ci 1811cb0ef41Sopenharmony_ciclass CleanUp(Step): 1821cb0ef41Sopenharmony_ci MESSAGE = "Done!" 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ci def RunStep(self): 1851cb0ef41Sopenharmony_ci print("Congratulations, you have successfully created version %s." 1861cb0ef41Sopenharmony_ci % self["version"]) 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_ci self.GitCheckout("origin/main") 1891cb0ef41Sopenharmony_ci self.DeleteBranch("work-branch") 1901cb0ef41Sopenharmony_ci self.Git("gc") 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci 1931cb0ef41Sopenharmony_ciclass CreateRelease(ScriptsBase): 1941cb0ef41Sopenharmony_ci def _PrepareOptions(self, parser): 1951cb0ef41Sopenharmony_ci group = parser.add_mutually_exclusive_group() 1961cb0ef41Sopenharmony_ci group.add_argument("-f", "--force", 1971cb0ef41Sopenharmony_ci help="Don't prompt the user.", 1981cb0ef41Sopenharmony_ci default=True, action="store_true") 1991cb0ef41Sopenharmony_ci group.add_argument("-m", "--manual", 2001cb0ef41Sopenharmony_ci help="Prompt the user at every important step.", 2011cb0ef41Sopenharmony_ci default=False, action="store_true") 2021cb0ef41Sopenharmony_ci parser.add_argument("-R", "--revision", 2031cb0ef41Sopenharmony_ci help="The git commit ID to push (defaults to HEAD).") 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci def _ProcessOptions(self, options): # pragma: no cover 2061cb0ef41Sopenharmony_ci if not options.author or not options.reviewer: 2071cb0ef41Sopenharmony_ci print("Reviewer (-r) and author (-a) are required.") 2081cb0ef41Sopenharmony_ci return False 2091cb0ef41Sopenharmony_ci return True 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_ci def _Config(self): 2121cb0ef41Sopenharmony_ci return { 2131cb0ef41Sopenharmony_ci "PERSISTFILE_BASENAME": "/tmp/create-releases-tempfile", 2141cb0ef41Sopenharmony_ci "COMMITMSG_FILE": "/tmp/v8-create-releases-tempfile-commitmsg", 2151cb0ef41Sopenharmony_ci } 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_ci def _Steps(self): 2181cb0ef41Sopenharmony_ci return [ 2191cb0ef41Sopenharmony_ci Preparation, 2201cb0ef41Sopenharmony_ci PrepareBranchRevision, 2211cb0ef41Sopenharmony_ci IncrementVersion, 2221cb0ef41Sopenharmony_ci DetectLastRelease, 2231cb0ef41Sopenharmony_ci DeleteBranchRef, 2241cb0ef41Sopenharmony_ci PushBranchRef, 2251cb0ef41Sopenharmony_ci MakeBranch, 2261cb0ef41Sopenharmony_ci SetVersion, 2271cb0ef41Sopenharmony_ci EnableMergeWatchlist, 2281cb0ef41Sopenharmony_ci CommitBranch, 2291cb0ef41Sopenharmony_ci LandBranch, 2301cb0ef41Sopenharmony_ci TagRevision, 2311cb0ef41Sopenharmony_ci CleanUp, 2321cb0ef41Sopenharmony_ci ] 2331cb0ef41Sopenharmony_ci 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ciif __name__ == "__main__": # pragma: no cover 2361cb0ef41Sopenharmony_ci sys.exit(CreateRelease().Run()) 237