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