OLD | NEW |
(Empty) | |
| 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 import argparse |
| 7 import sys |
| 8 |
| 9 from common_includes import * |
| 10 |
| 11 CONFIG = { |
| 12 BRANCHNAME: "auto-tag-v8", |
| 13 PERSISTFILE_BASENAME: "/tmp/v8-auto-tag-tempfile", |
| 14 DOT_GIT_LOCATION: ".git", |
| 15 VERSION_FILE: "src/version.cc", |
| 16 } |
| 17 |
| 18 |
| 19 class Preparation(Step): |
| 20 MESSAGE = "Preparation." |
| 21 |
| 22 def RunStep(self): |
| 23 self.CommonPrepare() |
| 24 self.PrepareBranch() |
| 25 self.GitCheckout("master") |
| 26 self.GitSVNRebase() |
| 27 |
| 28 |
| 29 class GetTags(Step): |
| 30 MESSAGE = "Get all V8 tags." |
| 31 |
| 32 def RunStep(self): |
| 33 self.GitCreateBranch(self._config[BRANCHNAME]) |
| 34 |
| 35 # Get remote tags. |
| 36 tags = filter(lambda s: re.match(r"^svn/tags/[\d+\.]+$", s), |
| 37 self.GitRemotes()) |
| 38 |
| 39 # Remove 'svn/tags/' prefix. |
| 40 self["tags"] = map(lambda s: s[9:], tags) |
| 41 |
| 42 |
| 43 class GetOldestUntaggedVersion(Step): |
| 44 MESSAGE = "Check if there's a version on bleeding edge without a tag." |
| 45 |
| 46 def RunStep(self): |
| 47 tags = set(self["tags"]) |
| 48 self["candidate"] = None |
| 49 self["candidate_version"] = None |
| 50 self["next"] = None |
| 51 self["next_version"] = None |
| 52 |
| 53 # Iterate backwards through all automatic version updates. |
| 54 for git_hash in self.GitLog( |
| 55 format="%H", grep="\\[Auto\\-roll\\] Bump up version to").splitlines(): |
| 56 |
| 57 # Get the version. |
| 58 if not self.GitCheckoutFileSafe(self._config[VERSION_FILE], git_hash): |
| 59 continue |
| 60 |
| 61 self.ReadAndPersistVersion() |
| 62 version = self.ArrayToVersion("") |
| 63 |
| 64 # Strip off trailing patch level (tags don't include tag level 0). |
| 65 if version.endswith(".0"): |
| 66 version = version[:-2] |
| 67 |
| 68 # Clean up checked-out version file. |
| 69 self.GitCheckoutFileSafe(self._config[VERSION_FILE], "HEAD") |
| 70 |
| 71 if version in tags: |
| 72 if self["candidate"]: |
| 73 # Revision "git_hash" is tagged already and "candidate" was the next |
| 74 # newer revision without a tag. |
| 75 break |
| 76 else: |
| 77 print("Stop as %s is the latest version and it has been tagged." % |
| 78 version) |
| 79 self.CommonCleanup() |
| 80 return True |
| 81 else: |
| 82 # This is the second oldest version without a tag. |
| 83 self["next"] = self["candidate"] |
| 84 self["next_version"] = self["candidate_version"] |
| 85 |
| 86 # This is the oldest version without a tag. |
| 87 self["candidate"] = git_hash |
| 88 self["candidate_version"] = version |
| 89 |
| 90 if not self["candidate"] or not self["candidate_version"]: |
| 91 print "Nothing found to tag." |
| 92 self.CommonCleanup() |
| 93 return True |
| 94 |
| 95 print("Candidate for tagging is %s with version %s" % |
| 96 (self["candidate"], self["candidate_version"])) |
| 97 |
| 98 |
| 99 class GetLKGRs(Step): |
| 100 MESSAGE = "Get the last lkgrs." |
| 101 |
| 102 def RunStep(self): |
| 103 revision_url = "https://v8-status.appspot.com/revisions?format=json" |
| 104 status_json = self.ReadURL(revision_url, wait_plan=[5, 20]) |
| 105 self["lkgrs"] = [entry["revision"] |
| 106 for entry in json.loads(status_json) if entry["status"]] |
| 107 |
| 108 |
| 109 class CalculateTagRevision(Step): |
| 110 MESSAGE = "Calculate the revision to tag." |
| 111 |
| 112 def LastLKGR(self, min_rev, max_rev): |
| 113 """Finds the newest lkgr between min_rev (inclusive) and max_rev |
| 114 (exclusive). |
| 115 """ |
| 116 for lkgr in self["lkgrs"]: |
| 117 # LKGRs are reverse sorted. |
| 118 if int(min_rev) <= int(lkgr) and int(lkgr) < int(max_rev): |
| 119 return lkgr |
| 120 return None |
| 121 |
| 122 def RunStep(self): |
| 123 # Get the lkgr after the tag candidate and before the next tag candidate. |
| 124 candidate_svn = self.GitSVNFindSVNRev(self["candidate"]) |
| 125 if self["next"]: |
| 126 next_svn = self.GitSVNFindSVNRev(self["next"]) |
| 127 else: |
| 128 # Don't include the version change commit itself if there is no upper |
| 129 # limit yet. |
| 130 candidate_svn = str(int(candidate_svn) + 1) |
| 131 next_svn = sys.maxint |
| 132 lkgr_svn = self.LastLKGR(candidate_svn, next_svn) |
| 133 |
| 134 if not lkgr_svn: |
| 135 print "There is no lkgr since the candidate version yet." |
| 136 self.CommonCleanup() |
| 137 return True |
| 138 |
| 139 # Let's check if the lkgr is at least three hours old. |
| 140 self["lkgr"] = self.GitSVNFindGitHash(lkgr_svn) |
| 141 if not self["lkgr"]: |
| 142 print "Couldn't find git hash for lkgr %s" % lkgr_svn |
| 143 self.CommonCleanup() |
| 144 return True |
| 145 |
| 146 lkgr_utc_time = int(self.GitLog(n=1, format="%at", git_hash=self["lkgr"])) |
| 147 current_utc_time = self._side_effect_handler.GetUTCStamp() |
| 148 |
| 149 if current_utc_time < lkgr_utc_time + 10800: |
| 150 print "Candidate lkgr %s is too recent for tagging." % lkgr_svn |
| 151 self.CommonCleanup() |
| 152 return True |
| 153 |
| 154 print "Tagging revision %s with %s" % (lkgr_svn, self["candidate_version"]) |
| 155 |
| 156 |
| 157 class MakeTag(Step): |
| 158 MESSAGE = "Tag the version." |
| 159 |
| 160 def RunStep(self): |
| 161 if not self._options.dry_run: |
| 162 self.GitReset(self["lkgr"]) |
| 163 self.GitSVNTag(self["candidate_version"]) |
| 164 |
| 165 |
| 166 class CleanUp(Step): |
| 167 MESSAGE = "Clean up." |
| 168 |
| 169 def RunStep(self): |
| 170 self.CommonCleanup() |
| 171 |
| 172 |
| 173 class AutoTag(ScriptsBase): |
| 174 def _PrepareOptions(self, parser): |
| 175 parser.add_argument("--dry_run", help="Don't tag the new version.", |
| 176 default=False, action="store_true") |
| 177 |
| 178 def _ProcessOptions(self, options): # pragma: no cover |
| 179 if not options.dry_run and not options.author: |
| 180 print "Specify your chromium.org email with -a" |
| 181 return False |
| 182 options.wait_for_lgtm = False |
| 183 options.force_readline_defaults = True |
| 184 options.force_upload = True |
| 185 return True |
| 186 |
| 187 def _Steps(self): |
| 188 return [ |
| 189 Preparation, |
| 190 GetTags, |
| 191 GetOldestUntaggedVersion, |
| 192 GetLKGRs, |
| 193 CalculateTagRevision, |
| 194 MakeTag, |
| 195 CleanUp, |
| 196 ] |
| 197 |
| 198 |
| 199 if __name__ == "__main__": # pragma: no cover |
| 200 sys.exit(AutoTag(CONFIG).Run()) |
OLD | NEW |