| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2014 the V8 project authors. All rights reserved. | 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 import argparse | 6 import argparse |
| 7 import json | |
| 8 import os | 7 import os |
| 9 import sys | 8 import sys |
| 10 import urllib | |
| 11 | 9 |
| 12 from common_includes import * | 10 from common_includes import * |
| 13 import chromium_roll | 11 |
| 12 ROLL_SUMMARY = ("Summary of changes available at:\n" |
| 13 "https://chromium.googlesource.com/v8/v8/+log/%s..%s") |
| 14 |
| 15 ISSUE_MSG = ( |
| 16 """Please follow these instructions for assigning/CC'ing issues: |
| 17 https://code.google.com/p/v8-wiki/wiki/TriagingIssues |
| 18 |
| 19 Please close rolling in case of a roll revert: |
| 20 https://v8-roll.appspot.com/ |
| 21 This only works with a Google account.""") |
| 22 |
| 23 class Preparation(Step): |
| 24 MESSAGE = "Preparation." |
| 25 |
| 26 def RunStep(self): |
| 27 # Update v8 remote tracking branches. |
| 28 self.GitFetchOrigin() |
| 29 self.Git("fetch origin +refs/tags/*:refs/tags/*") |
| 14 | 30 |
| 15 | 31 |
| 16 class DetectLastRoll(Step): | 32 class DetectLastRoll(Step): |
| 17 MESSAGE = "Detect commit ID of the last Chromium roll." | 33 MESSAGE = "Detect commit ID of the last Chromium roll." |
| 18 | 34 |
| 19 def RunStep(self): | 35 def RunStep(self): |
| 36 self["last_roll"] = self._options.last_roll |
| 37 if not self["last_roll"]: |
| 38 # Interpret the DEPS file to retrieve the v8 revision. |
| 39 # TODO(machenbach): This should be part or the roll-deps api of |
| 40 # depot_tools. |
| 41 Var = lambda var: '%s' |
| 42 exec(FileToText(os.path.join(self._options.chromium, "DEPS"))) |
| 43 |
| 44 # The revision rolled last. |
| 45 self["last_roll"] = vars['v8_revision'] |
| 46 self["last_version"] = self.GetVersionTag(self["last_roll"]) |
| 47 assert self["last_version"], "The last rolled v8 revision is not tagged." |
| 48 |
| 49 |
| 50 class DetectRevisionToRoll(Step): |
| 51 MESSAGE = "Detect commit ID of the V8 revision to roll." |
| 52 |
| 53 def RunStep(self): |
| 54 self["roll"] = self._options.revision |
| 55 if self["roll"]: |
| 56 # If the revision was passed on the cmd line, continue script execution |
| 57 # in the next step. |
| 58 return False |
| 59 |
| 20 # The revision that should be rolled. Check for the latest of the most | 60 # The revision that should be rolled. Check for the latest of the most |
| 21 # recent releases based on commit timestamp. | 61 # recent releases based on commit timestamp. |
| 22 revisions = self.GetRecentReleases( | 62 revisions = self.GetRecentReleases( |
| 23 max_age=self._options.max_age * DAY_IN_SECONDS) | 63 max_age=self._options.max_age * DAY_IN_SECONDS) |
| 24 assert revisions, "Didn't find any recent release." | 64 assert revisions, "Didn't find any recent release." |
| 25 | 65 |
| 26 # Interpret the DEPS file to retrieve the v8 revision. | |
| 27 # TODO(machenbach): This should be part or the roll-deps api of | |
| 28 # depot_tools. | |
| 29 Var = lambda var: '%s' | |
| 30 exec(FileToText(os.path.join(self._options.chromium, "DEPS"))) | |
| 31 | |
| 32 # The revision rolled last. | |
| 33 self["last_roll"] = vars['v8_revision'] | |
| 34 last_version = self.GetVersionTag(self["last_roll"]) | |
| 35 assert last_version, "The last rolled v8 revision is not tagged." | |
| 36 | |
| 37 # There must be some progress between the last roll and the new candidate | 66 # There must be some progress between the last roll and the new candidate |
| 38 # revision (i.e. we don't go backwards). The revisions are ordered newest | 67 # revision (i.e. we don't go backwards). The revisions are ordered newest |
| 39 # to oldest. It is possible that the newest timestamp has no progress | 68 # to oldest. It is possible that the newest timestamp has no progress |
| 40 # compared to the last roll, i.e. if the newest release is a cherry-pick | 69 # compared to the last roll, i.e. if the newest release is a cherry-pick |
| 41 # on a release branch. Then we look further. | 70 # on a release branch. Then we look further. |
| 42 for revision in revisions: | 71 for revision in revisions: |
| 43 version = self.GetVersionTag(revision) | 72 version = self.GetVersionTag(revision) |
| 44 assert version, "Internal error. All recent releases should have a tag" | 73 assert version, "Internal error. All recent releases should have a tag" |
| 45 | 74 |
| 46 if SortingKey(last_version) < SortingKey(version): | 75 if SortingKey(self["last_version"]) < SortingKey(version): |
| 47 self["roll"] = revision | 76 self["roll"] = revision |
| 48 break | 77 break |
| 49 else: | 78 else: |
| 50 print("There is no newer v8 revision than the one in Chromium (%s)." | 79 print("There is no newer v8 revision than the one in Chromium (%s)." |
| 51 % self["last_roll"]) | 80 % self["last_roll"]) |
| 52 return True | 81 return True |
| 53 | 82 |
| 54 | 83 |
| 55 class RollChromium(Step): | 84 class PrepareRollCandidate(Step): |
| 56 MESSAGE = "Roll V8 into Chromium." | 85 MESSAGE = "Robustness checks of the roll candidate." |
| 57 | 86 |
| 58 def RunStep(self): | 87 def RunStep(self): |
| 59 if self._options.roll: | 88 self["roll_title"] = self.GitLog(n=1, format="%s", |
| 60 args = [ | 89 git_hash=self["roll"]) |
| 61 "--author", self._options.author, | 90 |
| 62 "--reviewer", self._options.reviewer, | 91 # Make sure the last roll and the roll candidate are releases. |
| 63 "--chromium", self._options.chromium, | 92 version = self.GetVersionTag(self["roll"]) |
| 64 "--last-roll", self["last_roll"], | 93 assert version, "The revision to roll is not tagged." |
| 65 "--use-commit-queue", | 94 version = self.GetVersionTag(self["last_roll"]) |
| 66 self["roll"], | 95 assert version, "The revision used as last roll is not tagged." |
| 67 ] | 96 |
| 68 if self._options.dry_run: | 97 |
| 69 args.append("--dry-run") | 98 class SwitchChromium(Step): |
| 70 if self._options.work_dir: | 99 MESSAGE = "Switch to Chromium checkout." |
| 71 args.extend(["--work-dir", self._options.work_dir]) | 100 |
| 72 if self._options.chromium_roll_json_output: | 101 def RunStep(self): |
| 73 args.extend(["--json-output", self._options.chromium_roll_json_output]) | 102 cwd = self._options.chromium |
| 74 self._side_effect_handler.Call(chromium_roll.ChromiumRoll().Run, args) | 103 self.InitialEnvironmentChecks(cwd) |
| 104 # Check for a clean workdir. |
| 105 if not self.GitIsWorkdirClean(cwd=cwd): # pragma: no cover |
| 106 self.Die("Workspace is not clean. Please commit or undo your changes.") |
| 107 # Assert that the DEPS file is there. |
| 108 if not os.path.exists(os.path.join(cwd, "DEPS")): # pragma: no cover |
| 109 self.Die("DEPS file not present.") |
| 110 |
| 111 |
| 112 class UpdateChromiumCheckout(Step): |
| 113 MESSAGE = "Update the checkout and create a new branch." |
| 114 |
| 115 def RunStep(self): |
| 116 cwd = self._options.chromium |
| 117 self.GitCheckout("master", cwd=cwd) |
| 118 self.DeleteBranch("work-branch", cwd=cwd) |
| 119 self.Command("gclient", "sync --nohooks", cwd=cwd) |
| 120 self.GitPull(cwd=cwd) |
| 121 |
| 122 # Update v8 remotes. |
| 123 self.GitFetchOrigin() |
| 124 |
| 125 self.GitCreateBranch("work-branch", cwd=cwd) |
| 126 |
| 127 |
| 128 class UploadCL(Step): |
| 129 MESSAGE = "Create and upload CL." |
| 130 |
| 131 def RunStep(self): |
| 132 cwd = self._options.chromium |
| 133 # Patch DEPS file. |
| 134 if self.Command("roll-dep-svn", "v8 %s" % |
| 135 self["roll"], cwd=cwd) is None: |
| 136 self.Die("Failed to create deps for %s" % self["roll"]) |
| 137 |
| 138 message = [] |
| 139 message.append("Update V8 to %s." % self["roll_title"].lower()) |
| 140 |
| 141 message.append( |
| 142 ROLL_SUMMARY % (self["last_roll"][:8], self["roll"][:8])) |
| 143 |
| 144 message.append(ISSUE_MSG) |
| 145 |
| 146 message.append("TBR=%s" % self._options.reviewer) |
| 147 self.GitCommit("\n\n".join(message), author=self._options.author, cwd=cwd) |
| 148 if not self._options.dry_run: |
| 149 self.GitUpload(author=self._options.author, |
| 150 force=True, |
| 151 cq=self._options.use_commit_queue, |
| 152 cwd=cwd) |
| 153 print "CL uploaded." |
| 154 else: |
| 155 print "Dry run - don't upload." |
| 156 |
| 157 self.GitCheckout("master", cwd=cwd) |
| 158 self.GitDeleteBranch("work-branch", cwd=cwd) |
| 159 |
| 160 class CleanUp(Step): |
| 161 MESSAGE = "Done!" |
| 162 |
| 163 def RunStep(self): |
| 164 print("Congratulations, you have successfully rolled %s into " |
| 165 "Chromium." |
| 166 % self["roll"]) |
| 167 |
| 168 # Clean up all temporary files. |
| 169 Command("rm", "-f %s*" % self._config["PERSISTFILE_BASENAME"]) |
| 75 | 170 |
| 76 | 171 |
| 77 class AutoRoll(ScriptsBase): | 172 class AutoRoll(ScriptsBase): |
| 78 def _PrepareOptions(self, parser): | 173 def _PrepareOptions(self, parser): |
| 79 parser.add_argument("-c", "--chromium", required=True, | 174 parser.add_argument("-c", "--chromium", required=True, |
| 80 help=("The path to your Chromium src/ " | 175 help=("The path to your Chromium src/ " |
| 81 "directory to automate the V8 roll.")) | 176 "directory to automate the V8 roll.")) |
| 82 parser.add_argument("--chromium-roll-json-output", | 177 parser.add_argument("--last-roll", |
| 83 help="File to write wrapped results summary to.") | 178 help="The git commit ID of the last rolled version. " |
| 179 "Auto-detected if not specified.") |
| 84 parser.add_argument("--max-age", default=3, type=int, | 180 parser.add_argument("--max-age", default=3, type=int, |
| 85 help="Maximum age in days of the latest release.") | 181 help="Maximum age in days of the latest release.") |
| 86 parser.add_argument("--roll", help="Call Chromium roll script.", | 182 parser.add_argument("--revision", |
| 87 default=False, action="store_true") | 183 help="Revision to roll. Auto-detected if not " |
| 184 "specified."), |
| 185 parser.add_argument("--roll", help="Deprecated.", |
| 186 default=True, action="store_true") |
| 187 parser.add_argument("--use-commit-queue", |
| 188 help="Check the CQ bit on upload.", |
| 189 default=True, action="store_true") |
| 88 | 190 |
| 89 def _ProcessOptions(self, options): # pragma: no cover | 191 def _ProcessOptions(self, options): # pragma: no cover |
| 90 if not options.reviewer: | 192 if not options.author or not options.reviewer: |
| 91 print "A reviewer (-r) is required." | 193 print "A reviewer (-r) and an author (-a) are required." |
| 92 return False | 194 return False |
| 93 if not options.author: | 195 |
| 94 print "An author (-a) is required." | 196 options.requires_editor = False |
| 95 return False | 197 options.force = True |
| 198 options.manual = False |
| 96 return True | 199 return True |
| 97 | 200 |
| 98 def _Config(self): | 201 def _Config(self): |
| 99 return { | 202 return { |
| 100 "PERSISTFILE_BASENAME": "/tmp/v8-auto-roll-tempfile", | 203 "PERSISTFILE_BASENAME": "/tmp/v8-chromium-roll-tempfile", |
| 101 } | 204 } |
| 102 | 205 |
| 103 def _Steps(self): | 206 def _Steps(self): |
| 104 return [ | 207 return [ |
| 208 Preparation, |
| 105 DetectLastRoll, | 209 DetectLastRoll, |
| 106 RollChromium, | 210 DetectRevisionToRoll, |
| 211 PrepareRollCandidate, |
| 212 SwitchChromium, |
| 213 UpdateChromiumCheckout, |
| 214 UploadCL, |
| 215 CleanUp, |
| 107 ] | 216 ] |
| 108 | 217 |
| 109 | 218 |
| 110 if __name__ == "__main__": # pragma: no cover | 219 if __name__ == "__main__": # pragma: no cover |
| 111 sys.exit(AutoRoll().Run()) | 220 sys.exit(AutoRoll().Run()) |
| OLD | NEW |