Chromium Code Reviews| 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 GetLastUntaggedVersion(Step): | |
|
Jarin
2014/07/18 10:05:40
Should not this be named Oldest rather than Last?
| |
| 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 GetLastUntaggedVersion, | |
| 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 |