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