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