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 |