Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(156)

Side by Side Diff: tools/push-to-trunk/push_to_trunk.py

Issue 110573004: Merge bleeding_edge 17696:18016. (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/parser
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2013 the V8 project authors. All rights reserved. 2 # Copyright 2013 the V8 project authors. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without 3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are 4 # modification, are permitted provided that the following conditions are
5 # met: 5 # met:
6 # 6 #
7 # * Redistributions of source code must retain the above copyright 7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer. 8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above 9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following 10 # copyright notice, this list of conditions and the following
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 VERSION_FILE: "src/version.cc", 46 VERSION_FILE: "src/version.cc",
47 CHANGELOG_FILE: "ChangeLog", 47 CHANGELOG_FILE: "ChangeLog",
48 CHANGELOG_ENTRY_FILE: "/tmp/v8-push-to-trunk-tempfile-changelog-entry", 48 CHANGELOG_ENTRY_FILE: "/tmp/v8-push-to-trunk-tempfile-changelog-entry",
49 PATCH_FILE: "/tmp/v8-push-to-trunk-tempfile-patch-file", 49 PATCH_FILE: "/tmp/v8-push-to-trunk-tempfile-patch-file",
50 COMMITMSG_FILE: "/tmp/v8-push-to-trunk-tempfile-commitmsg", 50 COMMITMSG_FILE: "/tmp/v8-push-to-trunk-tempfile-commitmsg",
51 DEPS_FILE: "DEPS", 51 DEPS_FILE: "DEPS",
52 } 52 }
53 53
54 54
55 class Preparation(Step): 55 class Preparation(Step):
56 def __init__(self): 56 MESSAGE = "Preparation."
57 Step.__init__(self, "Preparation.")
58 57
59 def RunStep(self): 58 def RunStep(self):
60 self.InitialEnvironmentChecks() 59 self.InitialEnvironmentChecks()
61 self.CommonPrepare() 60 self.CommonPrepare()
61 self.PrepareBranch()
62 self.DeleteBranch(self.Config(TRUNKBRANCH)) 62 self.DeleteBranch(self.Config(TRUNKBRANCH))
63 63
64 64
65 class FreshBranch(Step): 65 class FreshBranch(Step):
66 def __init__(self): 66 MESSAGE = "Create a fresh branch."
67 Step.__init__(self, "Create a fresh branch.")
68 67
69 def RunStep(self): 68 def RunStep(self):
70 args = "checkout -b %s svn/bleeding_edge" % self.Config(BRANCHNAME) 69 args = "checkout -b %s svn/bleeding_edge" % self.Config(BRANCHNAME)
71 if self.Git(args) is None: 70 if self.Git(args) is None:
72 self.Die("Creating branch %s failed." % self.Config(BRANCHNAME)) 71 self.Die("Creating branch %s failed." % self.Config(BRANCHNAME))
73 72
74 73
75 class DetectLastPush(Step): 74 class DetectLastPush(Step):
76 def __init__(self): 75 MESSAGE = "Detect commit ID of last push to trunk."
77 Step.__init__(self, "Detect commit ID of last push to trunk.")
78 76
79 def RunStep(self): 77 def RunStep(self):
80 last_push = (self._options.l or 78 last_push = (self._options.l or
81 self.Git("log -1 --format=%H ChangeLog").strip()) 79 self.Git("log -1 --format=%H ChangeLog").strip())
82 while True: 80 while True:
83 # Print assumed commit, circumventing git's pager. 81 # Print assumed commit, circumventing git's pager.
84 print self.Git("log -1 %s" % last_push) 82 print self.Git("log -1 %s" % last_push)
85 if self.Confirm("Is the commit printed above the last push to trunk?"): 83 if self.Confirm("Is the commit printed above the last push to trunk?"):
86 break 84 break
87 args = "log -1 --format=%H %s^ ChangeLog" % last_push 85 args = "log -1 --format=%H %s^ ChangeLog" % last_push
88 last_push = self.Git(args).strip() 86 last_push = self.Git(args).strip()
89 self.Persist("last_push", last_push) 87 self.Persist("last_push", last_push)
90 self._state["last_push"] = last_push 88 self._state["last_push"] = last_push
91 89
92 90
93 class PrepareChangeLog(Step): 91 class PrepareChangeLog(Step):
94 def __init__(self): 92 MESSAGE = "Prepare raw ChangeLog entry."
95 Step.__init__(self, "Prepare raw ChangeLog entry.")
96 93
97 def RunStep(self): 94 def RunStep(self):
98 self.RestoreIfUnset("last_push") 95 self.RestoreIfUnset("last_push")
99 96
100 # These version numbers are used again later for the trunk commit. 97 # These version numbers are used again later for the trunk commit.
101 self.ReadAndPersistVersion() 98 self.ReadAndPersistVersion()
102 99
103 date = datetime.date.today().strftime("%Y-%m-%d") 100 date = datetime.date.today().strftime("%Y-%m-%d")
104 self.Persist("date", date) 101 self.Persist("date", date)
105 output = "%s: Version %s.%s.%s\n\n" % (date, 102 output = "%s: Version %s.%s.%s\n\n" % (date,
106 self._state["major"], 103 self._state["major"],
107 self._state["minor"], 104 self._state["minor"],
108 self._state["build"]) 105 self._state["build"])
109 TextToFile(output, self.Config(CHANGELOG_ENTRY_FILE)) 106 TextToFile(output, self.Config(CHANGELOG_ENTRY_FILE))
110 107
111 args = "log %s..HEAD --format=%%H" % self._state["last_push"] 108 args = "log %s..HEAD --format=%%H" % self._state["last_push"]
112 commits = self.Git(args).strip() 109 commits = self.Git(args).strip()
113 for commit in commits.splitlines():
114 # Get the commit's title line.
115 args = "log -1 %s --format=\"%%w(80,8,8)%%s\"" % commit
116 title = "%s\n" % self.Git(args).rstrip()
117 AppendToFile(title, self.Config(CHANGELOG_ENTRY_FILE))
118 110
119 # Grep for "BUG=xxxx" lines in the commit message and convert them to 111 # Cache raw commit messages.
120 # "(issue xxxx)". 112 commit_messages = [
121 out = self.Git("log -1 %s --format=\"%%B\"" % commit).splitlines() 113 [
122 out = filter(lambda x: re.search(r"^BUG=", x), out) 114 self.Git("log -1 %s --format=\"%%s\"" % commit),
123 out = filter(lambda x: not re.search(r"BUG=$", x), out) 115 self.Git("log -1 %s --format=\"%%B\"" % commit),
124 out = filter(lambda x: not re.search(r"BUG=none$", x), out) 116 self.Git("log -1 %s --format=\"%%an\"" % commit),
117 ] for commit in commits.splitlines()
118 ]
125 119
126 # TODO(machenbach): Handle multiple entries (e.g. BUG=123, 234). 120 # Auto-format commit messages.
127 def FormatIssue(text): 121 body = MakeChangeLogBody(commit_messages, auto_format=True)
128 text = re.sub(r"BUG=v8:(.*)$", r"(issue \1)", text) 122 AppendToFile(body, self.Config(CHANGELOG_ENTRY_FILE))
129 text = re.sub(r"BUG=chromium:(.*)$", r"(Chromium issue \1)", text)
130 text = re.sub(r"BUG=(.*)$", r"(Chromium issue \1)", text)
131 return " %s\n" % text
132 123
133 for line in map(FormatIssue, out): 124 msg = (" Performance and stability improvements on all platforms."
134 AppendToFile(line, self.Config(CHANGELOG_ENTRY_FILE)) 125 "\n#\n# The change log above is auto-generated. Please review if "
135 126 "all relevant\n# commit messages from the list below are included."
136 # Append the commit's author for reference. 127 "\n# All lines starting with # will be stripped.\n#\n")
137 args = "log -1 %s --format=\"%%w(80,8,8)(%%an)\"" % commit
138 author = self.Git(args).rstrip()
139 AppendToFile("%s\n\n" % author, self.Config(CHANGELOG_ENTRY_FILE))
140
141 msg = " Performance and stability improvements on all platforms.\n"
142 AppendToFile(msg, self.Config(CHANGELOG_ENTRY_FILE)) 128 AppendToFile(msg, self.Config(CHANGELOG_ENTRY_FILE))
143 129
130 # Include unformatted commit messages as a reference in a comment.
131 comment_body = MakeComment(MakeChangeLogBody(commit_messages))
132 AppendToFile(comment_body, self.Config(CHANGELOG_ENTRY_FILE))
133
134
144 class EditChangeLog(Step): 135 class EditChangeLog(Step):
145 def __init__(self): 136 MESSAGE = "Edit ChangeLog entry."
146 Step.__init__(self, "Edit ChangeLog entry.")
147 137
148 def RunStep(self): 138 def RunStep(self):
149 print ("Please press <Return> to have your EDITOR open the ChangeLog " 139 print ("Please press <Return> to have your EDITOR open the ChangeLog "
150 "entry, then edit its contents to your liking. When you're done, " 140 "entry, then edit its contents to your liking. When you're done, "
151 "save the file and exit your EDITOR. ") 141 "save the file and exit your EDITOR. ")
152 self.ReadLine() 142 self.ReadLine(default="")
153 143
144 # TODO(machenbach): Don't use EDITOR in forced mode as soon as script is
145 # well tested.
154 self.Editor(self.Config(CHANGELOG_ENTRY_FILE)) 146 self.Editor(self.Config(CHANGELOG_ENTRY_FILE))
155 handle, new_changelog = tempfile.mkstemp() 147 handle, new_changelog = tempfile.mkstemp()
156 os.close(handle) 148 os.close(handle)
157 149
158 # (1) Eliminate tabs, (2) fix too little and (3) too much indentation, and 150 # Strip comments and reformat with correct indentation.
159 # (4) eliminate trailing whitespace.
160 changelog_entry = FileToText(self.Config(CHANGELOG_ENTRY_FILE)).rstrip() 151 changelog_entry = FileToText(self.Config(CHANGELOG_ENTRY_FILE)).rstrip()
161 changelog_entry = MSub(r"\t", r" ", changelog_entry) 152 changelog_entry = StripComments(changelog_entry)
162 changelog_entry = MSub(r"^ {1,7}([^ ])", r" \1", changelog_entry) 153 changelog_entry = "\n".join(map(Fill80, changelog_entry.splitlines()))
163 changelog_entry = MSub(r"^ {9,80}([^ ])", r" \1", changelog_entry)
164 changelog_entry = MSub(r" +$", r"", changelog_entry)
165 154
166 if changelog_entry == "": 155 if changelog_entry == "":
167 self.Die("Empty ChangeLog entry.") 156 self.Die("Empty ChangeLog entry.")
168 157
169 with open(new_changelog, "w") as f: 158 with open(new_changelog, "w") as f:
170 f.write(changelog_entry) 159 f.write(changelog_entry)
171 f.write("\n\n\n") # Explicitly insert two empty lines. 160 f.write("\n\n\n") # Explicitly insert two empty lines.
172 161
173 AppendToFile(FileToText(self.Config(CHANGELOG_FILE)), new_changelog) 162 AppendToFile(FileToText(self.Config(CHANGELOG_FILE)), new_changelog)
174 TextToFile(FileToText(new_changelog), self.Config(CHANGELOG_FILE)) 163 TextToFile(FileToText(new_changelog), self.Config(CHANGELOG_FILE))
175 os.remove(new_changelog) 164 os.remove(new_changelog)
176 165
177 166
178 class IncrementVersion(Step): 167 class IncrementVersion(Step):
179 def __init__(self): 168 MESSAGE = "Increment version number."
180 Step.__init__(self, "Increment version number.")
181 169
182 def RunStep(self): 170 def RunStep(self):
183 self.RestoreIfUnset("build") 171 self.RestoreIfUnset("build")
184 new_build = str(int(self._state["build"]) + 1) 172 new_build = str(int(self._state["build"]) + 1)
185 173
186 if self.Confirm(("Automatically increment BUILD_NUMBER? (Saying 'n' will " 174 if self.Confirm(("Automatically increment BUILD_NUMBER? (Saying 'n' will "
187 "fire up your EDITOR on %s so you can make arbitrary " 175 "fire up your EDITOR on %s so you can make arbitrary "
188 "changes. When you're done, save the file and exit your " 176 "changes. When you're done, save the file and exit your "
189 "EDITOR.)" % self.Config(VERSION_FILE))): 177 "EDITOR.)" % self.Config(VERSION_FILE))):
190 text = FileToText(self.Config(VERSION_FILE)) 178 text = FileToText(self.Config(VERSION_FILE))
191 text = MSub(r"(?<=#define BUILD_NUMBER)(?P<space>\s+)\d*$", 179 text = MSub(r"(?<=#define BUILD_NUMBER)(?P<space>\s+)\d*$",
192 r"\g<space>%s" % new_build, 180 r"\g<space>%s" % new_build,
193 text) 181 text)
194 TextToFile(text, self.Config(VERSION_FILE)) 182 TextToFile(text, self.Config(VERSION_FILE))
195 else: 183 else:
196 self.Editor(self.Config(VERSION_FILE)) 184 self.Editor(self.Config(VERSION_FILE))
197 185
198 self.ReadAndPersistVersion("new_") 186 self.ReadAndPersistVersion("new_")
199 187
200 188
201 class CommitLocal(Step): 189 class CommitLocal(Step):
202 def __init__(self): 190 MESSAGE = "Commit to local branch."
203 Step.__init__(self, "Commit to local branch.")
204 191
205 def RunStep(self): 192 def RunStep(self):
206 self.RestoreVersionIfUnset("new_") 193 self.RestoreVersionIfUnset("new_")
207 prep_commit_msg = ("Prepare push to trunk. " 194 prep_commit_msg = ("Prepare push to trunk. "
208 "Now working on version %s.%s.%s." % (self._state["new_major"], 195 "Now working on version %s.%s.%s." % (self._state["new_major"],
209 self._state["new_minor"], 196 self._state["new_minor"],
210 self._state["new_build"])) 197 self._state["new_build"]))
211 self.Persist("prep_commit_msg", prep_commit_msg) 198 self.Persist("prep_commit_msg", prep_commit_msg)
212 if self.Git("commit -a -m \"%s\"" % prep_commit_msg) is None: 199 if self.Git("commit -a -m \"%s\"" % prep_commit_msg) is None:
213 self.Die("'git commit -a' failed.") 200 self.Die("'git commit -a' failed.")
214 201
215 202
216 class CommitRepository(Step): 203 class CommitRepository(Step):
217 def __init__(self): 204 MESSAGE = "Commit to the repository."
218 Step.__init__(self, "Commit to the repository.")
219 205
220 def RunStep(self): 206 def RunStep(self):
221 self.WaitForLGTM() 207 self.WaitForLGTM()
222 # Re-read the ChangeLog entry (to pick up possible changes). 208 # Re-read the ChangeLog entry (to pick up possible changes).
223 # FIXME(machenbach): This was hanging once with a broken pipe. 209 # FIXME(machenbach): This was hanging once with a broken pipe.
224 TextToFile(GetLastChangeLogEntries(self.Config(CHANGELOG_FILE)), 210 TextToFile(GetLastChangeLogEntries(self.Config(CHANGELOG_FILE)),
225 self.Config(CHANGELOG_ENTRY_FILE)) 211 self.Config(CHANGELOG_ENTRY_FILE))
226 212
227 if self.Git("cl dcommit -v", "PRESUBMIT_TREE_CHECK=\"skip\"") is None: 213 if self.Git("cl dcommit -f", "PRESUBMIT_TREE_CHECK=\"skip\"") is None:
228 self.Die("'git cl dcommit' failed, please try again.") 214 self.Die("'git cl dcommit' failed, please try again.")
229 215
230 216
231 class StragglerCommits(Step): 217 class StragglerCommits(Step):
232 def __init__(self): 218 MESSAGE = ("Fetch straggler commits that sneaked in since this script was "
233 Step.__init__(self, "Fetch straggler commits that sneaked in since this " 219 "started.")
234 "script was started.")
235 220
236 def RunStep(self): 221 def RunStep(self):
237 if self.Git("svn fetch") is None: 222 if self.Git("svn fetch") is None:
238 self.Die("'git svn fetch' failed.") 223 self.Die("'git svn fetch' failed.")
239 self.Git("checkout svn/bleeding_edge") 224 self.Git("checkout svn/bleeding_edge")
240 self.RestoreIfUnset("prep_commit_msg") 225 self.RestoreIfUnset("prep_commit_msg")
241 args = "log -1 --format=%%H --grep=\"%s\"" % self._state["prep_commit_msg"] 226 args = "log -1 --format=%%H --grep=\"%s\"" % self._state["prep_commit_msg"]
242 prepare_commit_hash = self.Git(args).strip() 227 prepare_commit_hash = self.Git(args).strip()
243 self.Persist("prepare_commit_hash", prepare_commit_hash) 228 self.Persist("prepare_commit_hash", prepare_commit_hash)
244 229
245 230
246 class SquashCommits(Step): 231 class SquashCommits(Step):
247 def __init__(self): 232 MESSAGE = "Squash commits into one."
248 Step.__init__(self, "Squash commits into one.")
249 233
250 def RunStep(self): 234 def RunStep(self):
251 # Instead of relying on "git rebase -i", we'll just create a diff, because 235 # Instead of relying on "git rebase -i", we'll just create a diff, because
252 # that's easier to automate. 236 # that's easier to automate.
253 self.RestoreIfUnset("prepare_commit_hash") 237 self.RestoreIfUnset("prepare_commit_hash")
254 args = "diff svn/trunk %s" % self._state["prepare_commit_hash"] 238 args = "diff svn/trunk %s" % self._state["prepare_commit_hash"]
255 TextToFile(self.Git(args), self.Config(PATCH_FILE)) 239 TextToFile(self.Git(args), self.Config(PATCH_FILE))
256 240
257 # Convert the ChangeLog entry to commit message format: 241 # Convert the ChangeLog entry to commit message format:
258 # - remove date 242 # - remove date
(...skipping 21 matching lines...) Expand all
280 }\ 264 }\
281 }'" % (changelog_entry, self._state["date"])) 265 }'" % (changelog_entry, self._state["date"]))
282 266
283 if not text: 267 if not text:
284 self.Die("Commit message editing failed.") 268 self.Die("Commit message editing failed.")
285 TextToFile(text, self.Config(COMMITMSG_FILE)) 269 TextToFile(text, self.Config(COMMITMSG_FILE))
286 os.remove(self.Config(CHANGELOG_ENTRY_FILE)) 270 os.remove(self.Config(CHANGELOG_ENTRY_FILE))
287 271
288 272
289 class NewBranch(Step): 273 class NewBranch(Step):
290 def __init__(self): 274 MESSAGE = "Create a new branch from trunk."
291 Step.__init__(self, "Create a new branch from trunk.")
292 275
293 def RunStep(self): 276 def RunStep(self):
294 if self.Git("checkout -b %s svn/trunk" % self.Config(TRUNKBRANCH)) is None: 277 if self.Git("checkout -b %s svn/trunk" % self.Config(TRUNKBRANCH)) is None:
295 self.Die("Checking out a new branch '%s' failed." % 278 self.Die("Checking out a new branch '%s' failed." %
296 self.Config(TRUNKBRANCH)) 279 self.Config(TRUNKBRANCH))
297 280
298 281
299 class ApplyChanges(Step): 282 class ApplyChanges(Step):
300 def __init__(self): 283 MESSAGE = "Apply squashed changes."
301 Step.__init__(self, "Apply squashed changes.")
302 284
303 def RunStep(self): 285 def RunStep(self):
304 self.ApplyPatch(self.Config(PATCH_FILE)) 286 self.ApplyPatch(self.Config(PATCH_FILE))
305 Command("rm", "-f %s*" % self.Config(PATCH_FILE)) 287 Command("rm", "-f %s*" % self.Config(PATCH_FILE))
306 288
307 289
308 class SetVersion(Step): 290 class SetVersion(Step):
309 def __init__(self): 291 MESSAGE = "Set correct version for trunk."
310 Step.__init__(self, "Set correct version for trunk.")
311 292
312 def RunStep(self): 293 def RunStep(self):
313 self.RestoreVersionIfUnset() 294 self.RestoreVersionIfUnset()
314 output = "" 295 output = ""
315 for line in FileToText(self.Config(VERSION_FILE)).splitlines(): 296 for line in FileToText(self.Config(VERSION_FILE)).splitlines():
316 if line.startswith("#define MAJOR_VERSION"): 297 if line.startswith("#define MAJOR_VERSION"):
317 line = re.sub("\d+$", self._state["major"], line) 298 line = re.sub("\d+$", self._state["major"], line)
318 elif line.startswith("#define MINOR_VERSION"): 299 elif line.startswith("#define MINOR_VERSION"):
319 line = re.sub("\d+$", self._state["minor"], line) 300 line = re.sub("\d+$", self._state["minor"], line)
320 elif line.startswith("#define BUILD_NUMBER"): 301 elif line.startswith("#define BUILD_NUMBER"):
321 line = re.sub("\d+$", self._state["build"], line) 302 line = re.sub("\d+$", self._state["build"], line)
322 elif line.startswith("#define PATCH_LEVEL"): 303 elif line.startswith("#define PATCH_LEVEL"):
323 line = re.sub("\d+$", "0", line) 304 line = re.sub("\d+$", "0", line)
324 elif line.startswith("#define IS_CANDIDATE_VERSION"): 305 elif line.startswith("#define IS_CANDIDATE_VERSION"):
325 line = re.sub("\d+$", "0", line) 306 line = re.sub("\d+$", "0", line)
326 output += "%s\n" % line 307 output += "%s\n" % line
327 TextToFile(output, self.Config(VERSION_FILE)) 308 TextToFile(output, self.Config(VERSION_FILE))
328 309
329 310
330 class CommitTrunk(Step): 311 class CommitTrunk(Step):
331 def __init__(self): 312 MESSAGE = "Commit to local trunk branch."
332 Step.__init__(self, "Commit to local trunk branch.")
333 313
334 def RunStep(self): 314 def RunStep(self):
335 self.Git("add \"%s\"" % self.Config(VERSION_FILE)) 315 self.Git("add \"%s\"" % self.Config(VERSION_FILE))
336 if self.Git("commit -F \"%s\"" % self.Config(COMMITMSG_FILE)) is None: 316 if self.Git("commit -F \"%s\"" % self.Config(COMMITMSG_FILE)) is None:
337 self.Die("'git commit' failed.") 317 self.Die("'git commit' failed.")
338 Command("rm", "-f %s*" % self.Config(COMMITMSG_FILE)) 318 Command("rm", "-f %s*" % self.Config(COMMITMSG_FILE))
339 319
340 320
341 class SanityCheck(Step): 321 class SanityCheck(Step):
342 def __init__(self): 322 MESSAGE = "Sanity check."
343 Step.__init__(self, "Sanity check.")
344 323
345 def RunStep(self): 324 def RunStep(self):
346 if not self.Confirm("Please check if your local checkout is sane: Inspect " 325 if not self.Confirm("Please check if your local checkout is sane: Inspect "
347 "%s, compile, run tests. Do you want to commit this new trunk " 326 "%s, compile, run tests. Do you want to commit this new trunk "
348 "revision to the repository?" % self.Config(VERSION_FILE)): 327 "revision to the repository?" % self.Config(VERSION_FILE)):
349 self.Die("Execution canceled.") 328 self.Die("Execution canceled.")
350 329
351 330
352 class CommitSVN(Step): 331 class CommitSVN(Step):
353 def __init__(self): 332 MESSAGE = "Commit to SVN."
354 Step.__init__(self, "Commit to SVN.")
355 333
356 def RunStep(self): 334 def RunStep(self):
357 result = self.Git("svn dcommit 2>&1") 335 result = self.Git("svn dcommit 2>&1")
358 if not result: 336 if not result:
359 self.Die("'git svn dcommit' failed.") 337 self.Die("'git svn dcommit' failed.")
360 result = filter(lambda x: re.search(r"^Committed r[0-9]+", x), 338 result = filter(lambda x: re.search(r"^Committed r[0-9]+", x),
361 result.splitlines()) 339 result.splitlines())
362 if len(result) > 0: 340 if len(result) > 0:
363 trunk_revision = re.sub(r"^Committed r([0-9]+)", r"\1", result[0]) 341 trunk_revision = re.sub(r"^Committed r([0-9]+)", r"\1", result[0])
364 342
365 # Sometimes grepping for the revision fails. No idea why. If you figure 343 # Sometimes grepping for the revision fails. No idea why. If you figure
366 # out why it is flaky, please do fix it properly. 344 # out why it is flaky, please do fix it properly.
367 if not trunk_revision: 345 if not trunk_revision:
368 print("Sorry, grepping for the SVN revision failed. Please look for it " 346 print("Sorry, grepping for the SVN revision failed. Please look for it "
369 "in the last command's output above and provide it manually (just " 347 "in the last command's output above and provide it manually (just "
370 "the number, without the leading \"r\").") 348 "the number, without the leading \"r\").")
349 self.DieInForcedMode("Can't prompt in forced mode.")
371 while not trunk_revision: 350 while not trunk_revision:
372 print "> ", 351 print "> ",
373 trunk_revision = self.ReadLine() 352 trunk_revision = self.ReadLine()
374 self.Persist("trunk_revision", trunk_revision) 353 self.Persist("trunk_revision", trunk_revision)
375 354
376 355
377 class TagRevision(Step): 356 class TagRevision(Step):
378 def __init__(self): 357 MESSAGE = "Tag the new revision."
379 Step.__init__(self, "Tag the new revision.")
380 358
381 def RunStep(self): 359 def RunStep(self):
382 self.RestoreVersionIfUnset() 360 self.RestoreVersionIfUnset()
383 ver = "%s.%s.%s" % (self._state["major"], 361 ver = "%s.%s.%s" % (self._state["major"],
384 self._state["minor"], 362 self._state["minor"],
385 self._state["build"]) 363 self._state["build"])
386 if self.Git("svn tag %s -m \"Tagging version %s\"" % (ver, ver)) is None: 364 if self.Git("svn tag %s -m \"Tagging version %s\"" % (ver, ver)) is None:
387 self.Die("'git svn tag' failed.") 365 self.Die("'git svn tag' failed.")
388 366
389 367
390 class CheckChromium(Step): 368 class CheckChromium(Step):
391 def __init__(self): 369 MESSAGE = "Ask for chromium checkout."
392 Step.__init__(self, "Ask for chromium checkout.")
393 370
394 def Run(self): 371 def Run(self):
395 chrome_path = self._options.c 372 chrome_path = self._options.c
396 if not chrome_path: 373 if not chrome_path:
374 self.DieInForcedMode("Please specify the path to a Chromium checkout in "
375 "forced mode.")
397 print ("Do you have a \"NewGit\" Chromium checkout and want " 376 print ("Do you have a \"NewGit\" Chromium checkout and want "
398 "this script to automate creation of the roll CL? If yes, enter the " 377 "this script to automate creation of the roll CL? If yes, enter the "
399 "path to (and including) the \"src\" directory here, otherwise just " 378 "path to (and including) the \"src\" directory here, otherwise just "
400 "press <Return>: "), 379 "press <Return>: "),
401 chrome_path = self.ReadLine() 380 chrome_path = self.ReadLine()
402 self.Persist("chrome_path", chrome_path) 381 self.Persist("chrome_path", chrome_path)
403 382
404 383
405 class SwitchChromium(Step): 384 class SwitchChromium(Step):
406 def __init__(self): 385 MESSAGE = "Switch to Chromium checkout."
407 Step.__init__(self, "Switch to Chromium checkout.", requires="chrome_path") 386 REQUIRES = "chrome_path"
408 387
409 def RunStep(self): 388 def RunStep(self):
410 v8_path = os.getcwd() 389 v8_path = os.getcwd()
411 self.Persist("v8_path", v8_path) 390 self.Persist("v8_path", v8_path)
412 os.chdir(self._state["chrome_path"]) 391 os.chdir(self._state["chrome_path"])
413 self.InitialEnvironmentChecks() 392 self.InitialEnvironmentChecks()
414 # Check for a clean workdir. 393 # Check for a clean workdir.
415 if self.Git("status -s -uno").strip() != "": 394 if self.Git("status -s -uno").strip() != "":
416 self.Die("Workspace is not clean. Please commit or undo your changes.") 395 self.Die("Workspace is not clean. Please commit or undo your changes.")
417 # Assert that the DEPS file is there. 396 # Assert that the DEPS file is there.
418 if not os.path.exists(self.Config(DEPS_FILE)): 397 if not os.path.exists(self.Config(DEPS_FILE)):
419 self.Die("DEPS file not present.") 398 self.Die("DEPS file not present.")
420 399
421 400
422 class UpdateChromiumCheckout(Step): 401 class UpdateChromiumCheckout(Step):
423 def __init__(self): 402 MESSAGE = "Update the checkout and create a new branch."
424 Step.__init__(self, "Update the checkout and create a new branch.", 403 REQUIRES = "chrome_path"
425 requires="chrome_path")
426 404
427 def RunStep(self): 405 def RunStep(self):
428 os.chdir(self._state["chrome_path"]) 406 os.chdir(self._state["chrome_path"])
429 if self.Git("checkout master") is None: 407 if self.Git("checkout master") is None:
430 self.Die("'git checkout master' failed.") 408 self.Die("'git checkout master' failed.")
431 if self.Git("pull") is None: 409 if self.Git("pull") is None:
432 self.Die("'git pull' failed, please try again.") 410 self.Die("'git pull' failed, please try again.")
433 411
434 self.RestoreIfUnset("trunk_revision") 412 self.RestoreIfUnset("trunk_revision")
435 args = "checkout -b v8-roll-%s" % self._state["trunk_revision"] 413 args = "checkout -b v8-roll-%s" % self._state["trunk_revision"]
436 if self.Git(args) is None: 414 if self.Git(args) is None:
437 self.Die("Failed to checkout a new branch.") 415 self.Die("Failed to checkout a new branch.")
438 416
439 417
440 class UploadCL(Step): 418 class UploadCL(Step):
441 def __init__(self): 419 MESSAGE = "Create and upload CL."
442 Step.__init__(self, "Create and upload CL.", requires="chrome_path") 420 REQUIRES = "chrome_path"
443 421
444 def RunStep(self): 422 def RunStep(self):
445 os.chdir(self._state["chrome_path"]) 423 os.chdir(self._state["chrome_path"])
446 424
447 # Patch DEPS file. 425 # Patch DEPS file.
448 self.RestoreIfUnset("trunk_revision") 426 self.RestoreIfUnset("trunk_revision")
449 deps = FileToText(self.Config(DEPS_FILE)) 427 deps = FileToText(self.Config(DEPS_FILE))
450 deps = re.sub("(?<=\"v8_revision\": \")([0-9]+)(?=\")", 428 deps = re.sub("(?<=\"v8_revision\": \")([0-9]+)(?=\")",
451 self._state["trunk_revision"], 429 self._state["trunk_revision"],
452 deps) 430 deps)
453 TextToFile(deps, self.Config(DEPS_FILE)) 431 TextToFile(deps, self.Config(DEPS_FILE))
454 432
455 self.RestoreVersionIfUnset() 433 self.RestoreVersionIfUnset()
456 ver = "%s.%s.%s" % (self._state["major"], 434 ver = "%s.%s.%s" % (self._state["major"],
457 self._state["minor"], 435 self._state["minor"],
458 self._state["build"]) 436 self._state["build"])
459 print "Please enter the email address of a reviewer for the roll CL: ", 437 if self._options and self._options.r:
460 rev = self.ReadLine() 438 print "Using account %s for review." % self._options.r
439 rev = self._options.r
440 else:
441 print "Please enter the email address of a reviewer for the roll CL: ",
442 self.DieInForcedMode("A reviewer must be specified in forced mode.")
443 rev = self.ReadLine()
461 args = "commit -am \"Update V8 to version %s.\n\nTBR=%s\"" % (ver, rev) 444 args = "commit -am \"Update V8 to version %s.\n\nTBR=%s\"" % (ver, rev)
462 if self.Git(args) is None: 445 if self.Git(args) is None:
463 self.Die("'git commit' failed.") 446 self.Die("'git commit' failed.")
464 if self.Git("cl upload --send-mail", pipe=False) is None: 447 force_flag = " -f" if self._options.f else ""
448 if self.Git("cl upload --send-mail%s" % force_flag, pipe=False) is None:
465 self.Die("'git cl upload' failed, please try again.") 449 self.Die("'git cl upload' failed, please try again.")
466 print "CL uploaded." 450 print "CL uploaded."
467 451
468 452
469 class SwitchV8(Step): 453 class SwitchV8(Step):
470 def __init__(self): 454 MESSAGE = "Returning to V8 checkout."
471 Step.__init__(self, "Returning to V8 checkout.", requires="chrome_path") 455 REQUIRES = "chrome_path"
472 456
473 def RunStep(self): 457 def RunStep(self):
474 self.RestoreIfUnset("v8_path") 458 self.RestoreIfUnset("v8_path")
475 os.chdir(self._state["v8_path"]) 459 os.chdir(self._state["v8_path"])
476 460
477 461
478 class CleanUp(Step): 462 class CleanUp(Step):
479 def __init__(self): 463 MESSAGE = "Done!"
480 Step.__init__(self, "Done!")
481 464
482 def RunStep(self): 465 def RunStep(self):
483 self.RestoreVersionIfUnset() 466 self.RestoreVersionIfUnset()
484 ver = "%s.%s.%s" % (self._state["major"], 467 ver = "%s.%s.%s" % (self._state["major"],
485 self._state["minor"], 468 self._state["minor"],
486 self._state["build"]) 469 self._state["build"])
487 self.RestoreIfUnset("trunk_revision") 470 self.RestoreIfUnset("trunk_revision")
488 self.RestoreIfUnset("chrome_path") 471 self.RestoreIfUnset("chrome_path")
489 472
490 if self._state["chrome_path"]: 473 if self._state["chrome_path"]:
491 print("Congratulations, you have successfully created the trunk " 474 print("Congratulations, you have successfully created the trunk "
492 "revision %s and rolled it into Chromium. Please don't forget to " 475 "revision %s and rolled it into Chromium. Please don't forget to "
493 "update the v8rel spreadsheet:" % ver) 476 "update the v8rel spreadsheet:" % ver)
494 else: 477 else:
495 print("Congratulations, you have successfully created the trunk " 478 print("Congratulations, you have successfully created the trunk "
496 "revision %s. Please don't forget to roll this new version into " 479 "revision %s. Please don't forget to roll this new version into "
497 "Chromium, and to update the v8rel spreadsheet:" % ver) 480 "Chromium, and to update the v8rel spreadsheet:" % ver)
498 print "%s\ttrunk\t%s" % (ver, self._state["trunk_revision"]) 481 print "%s\ttrunk\t%s" % (ver, self._state["trunk_revision"])
499 482
500 self.CommonCleanup() 483 self.CommonCleanup()
501 if self.Config(TRUNKBRANCH) != self._state["current_branch"]: 484 if self.Config(TRUNKBRANCH) != self._state["current_branch"]:
502 self.Git("branch -D %s" % self.Config(TRUNKBRANCH)) 485 self.Git("branch -D %s" % self.Config(TRUNKBRANCH))
503 486
504 487
505 def RunScript(config, 488 def RunPushToTrunk(config,
506 options, 489 options,
507 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): 490 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER):
508 step_classes = [ 491 step_classes = [
509 Preparation, 492 Preparation,
510 FreshBranch, 493 FreshBranch,
511 DetectLastPush, 494 DetectLastPush,
512 PrepareChangeLog, 495 PrepareChangeLog,
513 EditChangeLog, 496 EditChangeLog,
514 IncrementVersion, 497 IncrementVersion,
515 CommitLocal, 498 CommitLocal,
516 UploadStep, 499 UploadStep,
517 CommitRepository, 500 CommitRepository,
518 StragglerCommits, 501 StragglerCommits,
519 SquashCommits, 502 SquashCommits,
520 NewBranch, 503 NewBranch,
521 ApplyChanges, 504 ApplyChanges,
522 SetVersion, 505 SetVersion,
523 CommitTrunk, 506 CommitTrunk,
524 SanityCheck, 507 SanityCheck,
525 CommitSVN, 508 CommitSVN,
526 TagRevision, 509 TagRevision,
527 CheckChromium, 510 CheckChromium,
528 SwitchChromium, 511 SwitchChromium,
529 UpdateChromiumCheckout, 512 UpdateChromiumCheckout,
530 UploadCL, 513 UploadCL,
531 SwitchV8, 514 SwitchV8,
532 CleanUp, 515 CleanUp,
533 ] 516 ]
534 517
535 state = {} 518 RunScript(step_classes, config, options, side_effect_handler)
536 steps = []
537 number = 0
538
539 for step_class in step_classes:
540 # TODO(machenbach): Factory methods.
541 step = step_class()
542 step.SetNumber(number)
543 step.SetConfig(config)
544 step.SetOptions(options)
545 step.SetState(state)
546 step.SetSideEffectHandler(side_effect_handler)
547 steps.append(step)
548 number += 1
549
550 for step in steps[options.s:]:
551 step.Run()
552 519
553 520
554 def BuildOptions(): 521 def BuildOptions():
555 result = optparse.OptionParser() 522 result = optparse.OptionParser()
523 result.add_option("-c", "--chromium", dest="c",
524 help=("Specify the path to your Chromium src/ "
525 "directory to automate the V8 roll."))
526 result.add_option("-f", "--force", dest="f",
527 help="Don't prompt the user.",
528 default=False, action="store_true")
529 result.add_option("-l", "--last-push", dest="l",
530 help=("Manually specify the git commit ID "
531 "of the last push to trunk."))
532 result.add_option("-r", "--reviewer", dest="r",
533 help=("Specify the account name to be used for reviews."))
556 result.add_option("-s", "--step", dest="s", 534 result.add_option("-s", "--step", dest="s",
557 help="Specify the step where to start work. Default: 0.", 535 help="Specify the step where to start work. Default: 0.",
558 default=0, type="int") 536 default=0, type="int")
559 result.add_option("-l", "--last-push", dest="l",
560 help=("Manually specify the git commit ID "
561 "of the last push to trunk."))
562 result.add_option("-c", "--chromium", dest="c",
563 help=("Specify the path to your Chromium src/ "
564 "directory to automate the V8 roll."))
565 return result 537 return result
566 538
567 539
568 def ProcessOptions(options): 540 def ProcessOptions(options):
569 if options.s < 0: 541 if options.s < 0:
570 print "Bad step number %d" % options.s 542 print "Bad step number %d" % options.s
571 return False 543 return False
572 return True 544 return True
573 545
574 546
575 def Main(): 547 def Main():
576 parser = BuildOptions() 548 parser = BuildOptions()
577 (options, args) = parser.parse_args() 549 (options, args) = parser.parse_args()
578 if not ProcessOptions(options): 550 if not ProcessOptions(options):
579 parser.print_help() 551 parser.print_help()
580 return 1 552 return 1
581 RunScript(CONFIG, options) 553 RunPushToTrunk(CONFIG, options)
582 554
583 if __name__ == "__main__": 555 if __name__ == "__main__":
584 sys.exit(Main()) 556 sys.exit(Main())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698