OLD | NEW |
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 16 matching lines...) Expand all Loading... |
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | 28 |
29 import argparse | 29 import argparse |
30 import os | 30 import os |
31 import sys | 31 import sys |
32 import tempfile | 32 import tempfile |
33 import urllib2 | 33 import urllib2 |
34 | 34 |
35 from common_includes import * | 35 from common_includes import * |
36 | 36 |
37 TRUNKBRANCH = "TRUNKBRANCH" | |
38 | |
39 CONFIG = { | |
40 BRANCHNAME: "prepare-push", | |
41 TRUNKBRANCH: "trunk-push", | |
42 PERSISTFILE_BASENAME: "/tmp/v8-push-to-trunk-tempfile", | |
43 CHANGELOG_FILE: "ChangeLog", | |
44 CHANGELOG_ENTRY_FILE: "/tmp/v8-push-to-trunk-tempfile-changelog-entry", | |
45 PATCH_FILE: "/tmp/v8-push-to-trunk-tempfile-patch-file", | |
46 COMMITMSG_FILE: "/tmp/v8-push-to-trunk-tempfile-commitmsg", | |
47 } | |
48 | |
49 PUSH_MESSAGE_SUFFIX = " (based on bleeding_edge revision r%d)" | 37 PUSH_MESSAGE_SUFFIX = " (based on bleeding_edge revision r%d)" |
50 PUSH_MESSAGE_RE = re.compile(r".* \(based on bleeding_edge revision r(\d+)\)$") | 38 PUSH_MESSAGE_RE = re.compile(r".* \(based on bleeding_edge revision r(\d+)\)$") |
51 | 39 |
52 class Preparation(Step): | 40 class Preparation(Step): |
53 MESSAGE = "Preparation." | 41 MESSAGE = "Preparation." |
54 | 42 |
55 def RunStep(self): | 43 def RunStep(self): |
56 self.InitialEnvironmentChecks(self.default_cwd) | 44 self.InitialEnvironmentChecks(self.default_cwd) |
57 self.CommonPrepare() | 45 self.CommonPrepare() |
58 | 46 |
59 if(self["current_branch"] == self.Config(TRUNKBRANCH) | 47 if(self["current_branch"] == self.Config("TRUNKBRANCH") |
60 or self["current_branch"] == self.Config(BRANCHNAME)): | 48 or self["current_branch"] == self.Config("BRANCHNAME")): |
61 print "Warning: Script started on branch %s" % self["current_branch"] | 49 print "Warning: Script started on branch %s" % self["current_branch"] |
62 | 50 |
63 self.PrepareBranch() | 51 self.PrepareBranch() |
64 self.DeleteBranch(self.Config(TRUNKBRANCH)) | 52 self.DeleteBranch(self.Config("TRUNKBRANCH")) |
65 | 53 |
66 | 54 |
67 class FreshBranch(Step): | 55 class FreshBranch(Step): |
68 MESSAGE = "Create a fresh branch." | 56 MESSAGE = "Create a fresh branch." |
69 | 57 |
70 def RunStep(self): | 58 def RunStep(self): |
71 self.GitCreateBranch(self.Config(BRANCHNAME), "svn/bleeding_edge") | 59 self.GitCreateBranch(self.Config("BRANCHNAME"), "svn/bleeding_edge") |
72 | 60 |
73 | 61 |
74 class PreparePushRevision(Step): | 62 class PreparePushRevision(Step): |
75 MESSAGE = "Check which revision to push." | 63 MESSAGE = "Check which revision to push." |
76 | 64 |
77 def RunStep(self): | 65 def RunStep(self): |
78 if self._options.revision: | 66 if self._options.revision: |
79 self["push_hash"] = self.GitSVNFindGitHash(self._options.revision) | 67 self["push_hash"] = self.GitSVNFindGitHash(self._options.revision) |
80 else: | 68 else: |
81 self["push_hash"] = self.GitLog(n=1, format="%H", git_hash="HEAD") | 69 self["push_hash"] = self.GitLog(n=1, format="%H", git_hash="HEAD") |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 # Fetch from Rietveld but only retry once with one second delay since | 185 # Fetch from Rietveld but only retry once with one second delay since |
198 # there might be many revisions. | 186 # there might be many revisions. |
199 body = self.ReadURL(cl_url, wait_plan=[1]) | 187 body = self.ReadURL(cl_url, wait_plan=[1]) |
200 except urllib2.URLError: # pragma: no cover | 188 except urllib2.URLError: # pragma: no cover |
201 pass | 189 pass |
202 return body | 190 return body |
203 | 191 |
204 def RunStep(self): | 192 def RunStep(self): |
205 self["date"] = self.GetDate() | 193 self["date"] = self.GetDate() |
206 output = "%s: Version %s\n\n" % (self["date"], self["version"]) | 194 output = "%s: Version %s\n\n" % (self["date"], self["version"]) |
207 TextToFile(output, self.Config(CHANGELOG_ENTRY_FILE)) | 195 TextToFile(output, self.Config("CHANGELOG_ENTRY_FILE")) |
208 commits = self.GitLog(format="%H", | 196 commits = self.GitLog(format="%H", |
209 git_hash="%s..%s" % (self["last_push_bleeding_edge"], | 197 git_hash="%s..%s" % (self["last_push_bleeding_edge"], |
210 self["push_hash"])) | 198 self["push_hash"])) |
211 | 199 |
212 # Cache raw commit messages. | 200 # Cache raw commit messages. |
213 commit_messages = [ | 201 commit_messages = [ |
214 [ | 202 [ |
215 self.GitLog(n=1, format="%s", git_hash=commit), | 203 self.GitLog(n=1, format="%s", git_hash=commit), |
216 self.Reload(self.GitLog(n=1, format="%B", git_hash=commit)), | 204 self.Reload(self.GitLog(n=1, format="%B", git_hash=commit)), |
217 self.GitLog(n=1, format="%an", git_hash=commit), | 205 self.GitLog(n=1, format="%an", git_hash=commit), |
218 ] for commit in commits.splitlines() | 206 ] for commit in commits.splitlines() |
219 ] | 207 ] |
220 | 208 |
221 # Auto-format commit messages. | 209 # Auto-format commit messages. |
222 body = MakeChangeLogBody(commit_messages, auto_format=True) | 210 body = MakeChangeLogBody(commit_messages, auto_format=True) |
223 AppendToFile(body, self.Config(CHANGELOG_ENTRY_FILE)) | 211 AppendToFile(body, self.Config("CHANGELOG_ENTRY_FILE")) |
224 | 212 |
225 msg = (" Performance and stability improvements on all platforms." | 213 msg = (" Performance and stability improvements on all platforms." |
226 "\n#\n# The change log above is auto-generated. Please review if " | 214 "\n#\n# The change log above is auto-generated. Please review if " |
227 "all relevant\n# commit messages from the list below are included." | 215 "all relevant\n# commit messages from the list below are included." |
228 "\n# All lines starting with # will be stripped.\n#\n") | 216 "\n# All lines starting with # will be stripped.\n#\n") |
229 AppendToFile(msg, self.Config(CHANGELOG_ENTRY_FILE)) | 217 AppendToFile(msg, self.Config("CHANGELOG_ENTRY_FILE")) |
230 | 218 |
231 # Include unformatted commit messages as a reference in a comment. | 219 # Include unformatted commit messages as a reference in a comment. |
232 comment_body = MakeComment(MakeChangeLogBody(commit_messages)) | 220 comment_body = MakeComment(MakeChangeLogBody(commit_messages)) |
233 AppendToFile(comment_body, self.Config(CHANGELOG_ENTRY_FILE)) | 221 AppendToFile(comment_body, self.Config("CHANGELOG_ENTRY_FILE")) |
234 | 222 |
235 | 223 |
236 class EditChangeLog(Step): | 224 class EditChangeLog(Step): |
237 MESSAGE = "Edit ChangeLog entry." | 225 MESSAGE = "Edit ChangeLog entry." |
238 | 226 |
239 def RunStep(self): | 227 def RunStep(self): |
240 print ("Please press <Return> to have your EDITOR open the ChangeLog " | 228 print ("Please press <Return> to have your EDITOR open the ChangeLog " |
241 "entry, then edit its contents to your liking. When you're done, " | 229 "entry, then edit its contents to your liking. When you're done, " |
242 "save the file and exit your EDITOR. ") | 230 "save the file and exit your EDITOR. ") |
243 self.ReadLine(default="") | 231 self.ReadLine(default="") |
244 self.Editor(self.Config(CHANGELOG_ENTRY_FILE)) | 232 self.Editor(self.Config("CHANGELOG_ENTRY_FILE")) |
245 | 233 |
246 # Strip comments and reformat with correct indentation. | 234 # Strip comments and reformat with correct indentation. |
247 changelog_entry = FileToText(self.Config(CHANGELOG_ENTRY_FILE)).rstrip() | 235 changelog_entry = FileToText(self.Config("CHANGELOG_ENTRY_FILE")).rstrip() |
248 changelog_entry = StripComments(changelog_entry) | 236 changelog_entry = StripComments(changelog_entry) |
249 changelog_entry = "\n".join(map(Fill80, changelog_entry.splitlines())) | 237 changelog_entry = "\n".join(map(Fill80, changelog_entry.splitlines())) |
250 changelog_entry = changelog_entry.lstrip() | 238 changelog_entry = changelog_entry.lstrip() |
251 | 239 |
252 if changelog_entry == "": # pragma: no cover | 240 if changelog_entry == "": # pragma: no cover |
253 self.Die("Empty ChangeLog entry.") | 241 self.Die("Empty ChangeLog entry.") |
254 | 242 |
255 # Safe new change log for adding it later to the trunk patch. | 243 # Safe new change log for adding it later to the trunk patch. |
256 TextToFile(changelog_entry, self.Config(CHANGELOG_ENTRY_FILE)) | 244 TextToFile(changelog_entry, self.Config("CHANGELOG_ENTRY_FILE")) |
257 | 245 |
258 | 246 |
259 class StragglerCommits(Step): | 247 class StragglerCommits(Step): |
260 MESSAGE = ("Fetch straggler commits that sneaked in since this script was " | 248 MESSAGE = ("Fetch straggler commits that sneaked in since this script was " |
261 "started.") | 249 "started.") |
262 | 250 |
263 def RunStep(self): | 251 def RunStep(self): |
264 self.GitSVNFetch() | 252 self.GitSVNFetch() |
265 self.GitCheckout("svn/bleeding_edge") | 253 self.GitCheckout("svn/bleeding_edge") |
266 | 254 |
267 | 255 |
268 class SquashCommits(Step): | 256 class SquashCommits(Step): |
269 MESSAGE = "Squash commits into one." | 257 MESSAGE = "Squash commits into one." |
270 | 258 |
271 def RunStep(self): | 259 def RunStep(self): |
272 # Instead of relying on "git rebase -i", we'll just create a diff, because | 260 # Instead of relying on "git rebase -i", we'll just create a diff, because |
273 # that's easier to automate. | 261 # that's easier to automate. |
274 TextToFile(self.GitDiff("svn/trunk", self["push_hash"]), | 262 TextToFile(self.GitDiff("svn/trunk", self["push_hash"]), |
275 self.Config(PATCH_FILE)) | 263 self.Config("PATCH_FILE")) |
276 | 264 |
277 # Convert the ChangeLog entry to commit message format. | 265 # Convert the ChangeLog entry to commit message format. |
278 text = FileToText(self.Config(CHANGELOG_ENTRY_FILE)) | 266 text = FileToText(self.Config("CHANGELOG_ENTRY_FILE")) |
279 | 267 |
280 # Remove date and trailing white space. | 268 # Remove date and trailing white space. |
281 text = re.sub(r"^%s: " % self["date"], "", text.rstrip()) | 269 text = re.sub(r"^%s: " % self["date"], "", text.rstrip()) |
282 | 270 |
283 # Retrieve svn revision for showing the used bleeding edge revision in the | 271 # Retrieve svn revision for showing the used bleeding edge revision in the |
284 # commit message. | 272 # commit message. |
285 self["svn_revision"] = self.GitSVNFindSVNRev(self["push_hash"]) | 273 self["svn_revision"] = self.GitSVNFindSVNRev(self["push_hash"]) |
286 suffix = PUSH_MESSAGE_SUFFIX % int(self["svn_revision"]) | 274 suffix = PUSH_MESSAGE_SUFFIX % int(self["svn_revision"]) |
287 text = MSub(r"^(Version \d+\.\d+\.\d+)$", "\\1%s" % suffix, text) | 275 text = MSub(r"^(Version \d+\.\d+\.\d+)$", "\\1%s" % suffix, text) |
288 | 276 |
289 # Remove indentation and merge paragraphs into single long lines, keeping | 277 # Remove indentation and merge paragraphs into single long lines, keeping |
290 # empty lines between them. | 278 # empty lines between them. |
291 def SplitMapJoin(split_text, fun, join_text): | 279 def SplitMapJoin(split_text, fun, join_text): |
292 return lambda text: join_text.join(map(fun, text.split(split_text))) | 280 return lambda text: join_text.join(map(fun, text.split(split_text))) |
293 strip = lambda line: line.strip() | 281 strip = lambda line: line.strip() |
294 text = SplitMapJoin("\n\n", SplitMapJoin("\n", strip, " "), "\n\n")(text) | 282 text = SplitMapJoin("\n\n", SplitMapJoin("\n", strip, " "), "\n\n")(text) |
295 | 283 |
296 if not text: # pragma: no cover | 284 if not text: # pragma: no cover |
297 self.Die("Commit message editing failed.") | 285 self.Die("Commit message editing failed.") |
298 TextToFile(text, self.Config(COMMITMSG_FILE)) | 286 TextToFile(text, self.Config("COMMITMSG_FILE")) |
299 | 287 |
300 | 288 |
301 class NewBranch(Step): | 289 class NewBranch(Step): |
302 MESSAGE = "Create a new branch from trunk." | 290 MESSAGE = "Create a new branch from trunk." |
303 | 291 |
304 def RunStep(self): | 292 def RunStep(self): |
305 self.GitCreateBranch(self.Config(TRUNKBRANCH), "svn/trunk") | 293 self.GitCreateBranch(self.Config("TRUNKBRANCH"), "svn/trunk") |
306 | 294 |
307 | 295 |
308 class ApplyChanges(Step): | 296 class ApplyChanges(Step): |
309 MESSAGE = "Apply squashed changes." | 297 MESSAGE = "Apply squashed changes." |
310 | 298 |
311 def RunStep(self): | 299 def RunStep(self): |
312 self.ApplyPatch(self.Config(PATCH_FILE)) | 300 self.ApplyPatch(self.Config("PATCH_FILE")) |
313 os.remove(self.Config(PATCH_FILE)) | 301 os.remove(self.Config("PATCH_FILE")) |
314 | 302 |
315 | 303 |
316 class AddChangeLog(Step): | 304 class AddChangeLog(Step): |
317 MESSAGE = "Add ChangeLog changes to trunk branch." | 305 MESSAGE = "Add ChangeLog changes to trunk branch." |
318 | 306 |
319 def RunStep(self): | 307 def RunStep(self): |
320 # The change log has been modified by the patch. Reset it to the version | 308 # The change log has been modified by the patch. Reset it to the version |
321 # on trunk and apply the exact changes determined by this PrepareChangeLog | 309 # on trunk and apply the exact changes determined by this PrepareChangeLog |
322 # step above. | 310 # step above. |
323 self.GitCheckoutFile(self.Config(CHANGELOG_FILE), "svn/trunk") | 311 self.GitCheckoutFile(self.Config("CHANGELOG_FILE"), "svn/trunk") |
324 changelog_entry = FileToText(self.Config(CHANGELOG_ENTRY_FILE)) | 312 changelog_entry = FileToText(self.Config("CHANGELOG_ENTRY_FILE")) |
325 old_change_log = FileToText(self.Config(CHANGELOG_FILE)) | 313 old_change_log = FileToText(self.Config("CHANGELOG_FILE")) |
326 new_change_log = "%s\n\n\n%s" % (changelog_entry, old_change_log) | 314 new_change_log = "%s\n\n\n%s" % (changelog_entry, old_change_log) |
327 TextToFile(new_change_log, self.Config(CHANGELOG_FILE)) | 315 TextToFile(new_change_log, self.Config("CHANGELOG_FILE")) |
328 os.remove(self.Config(CHANGELOG_ENTRY_FILE)) | 316 os.remove(self.Config("CHANGELOG_ENTRY_FILE")) |
329 | 317 |
330 | 318 |
331 class SetVersion(Step): | 319 class SetVersion(Step): |
332 MESSAGE = "Set correct version for trunk." | 320 MESSAGE = "Set correct version for trunk." |
333 | 321 |
334 def RunStep(self): | 322 def RunStep(self): |
335 # The version file has been modified by the patch. Reset it to the version | 323 # The version file has been modified by the patch. Reset it to the version |
336 # on trunk and apply the correct version. | 324 # on trunk and apply the correct version. |
337 self.GitCheckoutFile(VERSION_FILE, "svn/trunk") | 325 self.GitCheckoutFile(VERSION_FILE, "svn/trunk") |
338 self.SetVersion(os.path.join(self.default_cwd, VERSION_FILE), "new_") | 326 self.SetVersion(os.path.join(self.default_cwd, VERSION_FILE), "new_") |
339 | 327 |
340 | 328 |
341 class CommitTrunk(Step): | 329 class CommitTrunk(Step): |
342 MESSAGE = "Commit to local trunk branch." | 330 MESSAGE = "Commit to local trunk branch." |
343 | 331 |
344 def RunStep(self): | 332 def RunStep(self): |
345 self.GitCommit(file_name = self.Config(COMMITMSG_FILE)) | 333 self.GitCommit(file_name = self.Config("COMMITMSG_FILE")) |
346 os.remove(self.Config(COMMITMSG_FILE)) | 334 os.remove(self.Config("COMMITMSG_FILE")) |
347 | 335 |
348 | 336 |
349 class SanityCheck(Step): | 337 class SanityCheck(Step): |
350 MESSAGE = "Sanity check." | 338 MESSAGE = "Sanity check." |
351 | 339 |
352 def RunStep(self): | 340 def RunStep(self): |
353 # TODO(machenbach): Run presubmit script here as it is now missing in the | 341 # TODO(machenbach): Run presubmit script here as it is now missing in the |
354 # prepare push process. | 342 # prepare push process. |
355 if not self.Confirm("Please check if your local checkout is sane: Inspect " | 343 if not self.Confirm("Please check if your local checkout is sane: Inspect " |
356 "%s, compile, run tests. Do you want to commit this new trunk " | 344 "%s, compile, run tests. Do you want to commit this new trunk " |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 MESSAGE = "Done!" | 381 MESSAGE = "Done!" |
394 | 382 |
395 def RunStep(self): | 383 def RunStep(self): |
396 print("Congratulations, you have successfully created the trunk " | 384 print("Congratulations, you have successfully created the trunk " |
397 "revision %s. Please don't forget to roll this new version into " | 385 "revision %s. Please don't forget to roll this new version into " |
398 "Chromium, and to update the v8rel spreadsheet:" | 386 "Chromium, and to update the v8rel spreadsheet:" |
399 % self["version"]) | 387 % self["version"]) |
400 print "%s\ttrunk\t%s" % (self["version"], self["trunk_revision"]) | 388 print "%s\ttrunk\t%s" % (self["version"], self["trunk_revision"]) |
401 | 389 |
402 self.CommonCleanup() | 390 self.CommonCleanup() |
403 if self.Config(TRUNKBRANCH) != self["current_branch"]: | 391 if self.Config("TRUNKBRANCH") != self["current_branch"]: |
404 self.GitDeleteBranch(self.Config(TRUNKBRANCH)) | 392 self.GitDeleteBranch(self.Config("TRUNKBRANCH")) |
405 | 393 |
406 | 394 |
407 class PushToTrunk(ScriptsBase): | 395 class PushToTrunk(ScriptsBase): |
408 def _PrepareOptions(self, parser): | 396 def _PrepareOptions(self, parser): |
409 group = parser.add_mutually_exclusive_group() | 397 group = parser.add_mutually_exclusive_group() |
410 group.add_argument("-f", "--force", | 398 group.add_argument("-f", "--force", |
411 help="Don't prompt the user.", | 399 help="Don't prompt the user.", |
412 default=False, action="store_true") | 400 default=False, action="store_true") |
413 group.add_argument("-m", "--manual", | 401 group.add_argument("-m", "--manual", |
414 help="Prompt the user at every important step.", | 402 help="Prompt the user at every important step.", |
(...skipping 15 matching lines...) Expand all Loading... |
430 print "Specify your chromium.org email with -a in (semi-)automatic mode." | 418 print "Specify your chromium.org email with -a in (semi-)automatic mode." |
431 return False | 419 return False |
432 if options.revision and not int(options.revision) > 0: | 420 if options.revision and not int(options.revision) > 0: |
433 print("The --revision flag must be a positiv integer pointing to a " | 421 print("The --revision flag must be a positiv integer pointing to a " |
434 "valid svn revision.") | 422 "valid svn revision.") |
435 return False | 423 return False |
436 | 424 |
437 options.tbr_commit = not options.manual | 425 options.tbr_commit = not options.manual |
438 return True | 426 return True |
439 | 427 |
| 428 def _Config(self): |
| 429 return { |
| 430 "BRANCHNAME": "prepare-push", |
| 431 "TRUNKBRANCH": "trunk-push", |
| 432 "PERSISTFILE_BASENAME": "/tmp/v8-push-to-trunk-tempfile", |
| 433 "CHANGELOG_FILE": "ChangeLog", |
| 434 "CHANGELOG_ENTRY_FILE": "/tmp/v8-push-to-trunk-tempfile-changelog-entry", |
| 435 "PATCH_FILE": "/tmp/v8-push-to-trunk-tempfile-patch-file", |
| 436 "COMMITMSG_FILE": "/tmp/v8-push-to-trunk-tempfile-commitmsg", |
| 437 } |
| 438 |
440 def _Steps(self): | 439 def _Steps(self): |
441 return [ | 440 return [ |
442 Preparation, | 441 Preparation, |
443 FreshBranch, | 442 FreshBranch, |
444 PreparePushRevision, | 443 PreparePushRevision, |
445 DetectLastPush, | 444 DetectLastPush, |
446 GetCurrentBleedingEdgeVersion, | 445 GetCurrentBleedingEdgeVersion, |
447 IncrementVersion, | 446 IncrementVersion, |
448 PrepareChangeLog, | 447 PrepareChangeLog, |
449 EditChangeLog, | 448 EditChangeLog, |
450 StragglerCommits, | 449 StragglerCommits, |
451 SquashCommits, | 450 SquashCommits, |
452 NewBranch, | 451 NewBranch, |
453 ApplyChanges, | 452 ApplyChanges, |
454 AddChangeLog, | 453 AddChangeLog, |
455 SetVersion, | 454 SetVersion, |
456 CommitTrunk, | 455 CommitTrunk, |
457 SanityCheck, | 456 SanityCheck, |
458 CommitSVN, | 457 CommitSVN, |
459 TagRevision, | 458 TagRevision, |
460 CleanUp, | 459 CleanUp, |
461 ] | 460 ] |
462 | 461 |
463 | 462 |
464 if __name__ == "__main__": # pragma: no cover | 463 if __name__ == "__main__": # pragma: no cover |
465 sys.exit(PushToTrunk(CONFIG).Run()) | 464 sys.exit(PushToTrunk().Run()) |
OLD | NEW |