| 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 PUSH_MESSAGE_SUFFIX = " (based on bleeding_edge revision r%d)" | 37 PUSH_MSG_SVN_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+)\)$") | 38 PUSH_MSG_GIT_SUFFIX = " (based on %s)" |
| 39 PUSH_MSG_GIT_RE = re.compile(r".* \(based on (?P<git_rev>[a-fA-F0-9]+)\)$") |
| 39 | 40 |
| 40 class Preparation(Step): | 41 class Preparation(Step): |
| 41 MESSAGE = "Preparation." | 42 MESSAGE = "Preparation." |
| 42 | 43 |
| 43 def RunStep(self): | 44 def RunStep(self): |
| 44 self.InitialEnvironmentChecks(self.default_cwd) | 45 self.InitialEnvironmentChecks(self.default_cwd) |
| 45 self.CommonPrepare() | 46 self.CommonPrepare() |
| 46 | 47 |
| 47 if(self["current_branch"] == self.Config("TRUNKBRANCH") | 48 if(self["current_branch"] == self.Config("TRUNKBRANCH") |
| 48 or self["current_branch"] == self.Config("BRANCHNAME")): | 49 or self["current_branch"] == self.Config("BRANCHNAME")): |
| 49 print "Warning: Script started on branch %s" % self["current_branch"] | 50 print "Warning: Script started on branch %s" % self["current_branch"] |
| 50 | 51 |
| 51 self.PrepareBranch() | 52 self.PrepareBranch() |
| 52 self.DeleteBranch(self.Config("TRUNKBRANCH")) | 53 self.DeleteBranch(self.Config("TRUNKBRANCH")) |
| 53 | 54 |
| 54 | 55 |
| 55 class FreshBranch(Step): | 56 class FreshBranch(Step): |
| 56 MESSAGE = "Create a fresh branch." | 57 MESSAGE = "Create a fresh branch." |
| 57 | 58 |
| 58 def RunStep(self): | 59 def RunStep(self): |
| 59 self.GitCreateBranch(self.Config("BRANCHNAME"), | 60 self.GitCreateBranch(self.Config("BRANCHNAME"), |
| 60 self.vc.RemoteMasterBranch()) | 61 self.vc.RemoteMasterBranch()) |
| 61 | 62 |
| 62 | 63 |
| 63 class PreparePushRevision(Step): | 64 class PreparePushRevision(Step): |
| 64 MESSAGE = "Check which revision to push." | 65 MESSAGE = "Check which revision to push." |
| 65 | 66 |
| 66 def RunStep(self): | 67 def RunStep(self): |
| 67 if self._options.revision: | 68 if self._options.revision: |
| 68 self["push_hash"] = self.vc.SvnGit(self._options.revision) | 69 self["push_hash"] = self._options.revision |
| 69 else: | 70 else: |
| 70 self["push_hash"] = self.GitLog(n=1, format="%H", git_hash="HEAD") | 71 self["push_hash"] = self.GitLog(n=1, format="%H", git_hash="HEAD") |
| 71 if not self["push_hash"]: # pragma: no cover | 72 if not self["push_hash"]: # pragma: no cover |
| 72 self.Die("Could not determine the git hash for the push.") | 73 self.Die("Could not determine the git hash for the push.") |
| 73 | 74 |
| 74 | 75 |
| 75 class DetectLastPush(Step): | 76 class DetectLastPush(Step): |
| 76 MESSAGE = "Detect commit ID of last push to trunk." | 77 MESSAGE = "Detect commit ID of last push to trunk." |
| 77 | 78 |
| 78 def RunStep(self): | 79 def RunStep(self): |
| 79 last_push = self._options.last_push or self.FindLastTrunkPush() | 80 last_push = self._options.last_push or self.FindLastTrunkPush() |
| 80 while True: | 81 while True: |
| 81 # Print assumed commit, circumventing git's pager. | 82 # Print assumed commit, circumventing git's pager. |
| 82 print self.GitLog(n=1, git_hash=last_push) | 83 print self.GitLog(n=1, git_hash=last_push) |
| 83 if self.Confirm("Is the commit printed above the last push to trunk?"): | 84 if self.Confirm("Is the commit printed above the last push to trunk?"): |
| 84 break | 85 break |
| 85 last_push = self.FindLastTrunkPush(parent_hash=last_push) | 86 last_push = self.FindLastTrunkPush(parent_hash=last_push) |
| 86 | 87 |
| 87 if self._options.last_bleeding_edge: | 88 if self._options.last_bleeding_edge: |
| 88 # Read the bleeding edge revision of the last push from a command-line | 89 # Read the bleeding edge revision of the last push from a command-line |
| 89 # option. | 90 # option. |
| 90 last_push_bleeding_edge = self._options.last_bleeding_edge | 91 last_push_bleeding_edge = self._options.last_bleeding_edge |
| 91 else: | 92 else: |
| 92 # Retrieve the bleeding edge revision of the last push from the text in | 93 # Retrieve the bleeding edge revision of the last push from the text in |
| 93 # the push commit message. | 94 # the push commit message. |
| 94 last_push_title = self.GitLog(n=1, format="%s", git_hash=last_push) | 95 last_push_title = self.GitLog(n=1, format="%s", git_hash=last_push) |
| 95 last_push_be_svn = PUSH_MESSAGE_RE.match(last_push_title).group(1) | 96 # TODO(machenbach): This is only needed for the git transition. Can be |
| 96 if not last_push_be_svn: # pragma: no cover | 97 # removed after one successful trunk push. |
| 97 self.Die("Could not retrieve bleeding edge revision for trunk push %s" | 98 match = PUSH_MSG_SVN_RE.match(last_push_title) |
| 98 % last_push) | 99 if match: |
| 99 last_push_bleeding_edge = self.vc.SvnGit(last_push_be_svn) | 100 last_push_be_svn = match.group(1) |
| 101 if not last_push_be_svn: # pragma: no cover |
| 102 self.Die("Could not retrieve bleeding edge rev for trunk push %s" |
| 103 % last_push) |
| 104 last_push_bleeding_edge = self.vc.SvnGit(last_push_be_svn) |
| 105 else: |
| 106 last_push_bleeding_edge = PUSH_MSG_GIT_RE.match( |
| 107 last_push_title).group("git_rev") |
| 108 |
| 100 if not last_push_bleeding_edge: # pragma: no cover | 109 if not last_push_bleeding_edge: # pragma: no cover |
| 101 self.Die("Could not retrieve bleeding edge git hash for trunk push %s" | 110 self.Die("Could not retrieve bleeding edge git hash for trunk push %s" |
| 102 % last_push) | 111 % last_push) |
| 103 | 112 |
| 104 # This points to the svn revision of the last push on trunk. | 113 # This points to the git hash of the last push on trunk. |
| 105 self["last_push_trunk"] = last_push | 114 self["last_push_trunk"] = last_push |
| 106 # This points to the last bleeding_edge revision that went into the last | 115 # This points to the last bleeding_edge revision that went into the last |
| 107 # push. | 116 # push. |
| 108 # TODO(machenbach): Do we need a check to make sure we're not pushing a | 117 # TODO(machenbach): Do we need a check to make sure we're not pushing a |
| 109 # revision older than the last push? If we do this, the output of the | 118 # revision older than the last push? If we do this, the output of the |
| 110 # current change log preparation won't make much sense. | 119 # current change log preparation won't make much sense. |
| 111 self["last_push_bleeding_edge"] = last_push_bleeding_edge | 120 self["last_push_bleeding_edge"] = last_push_bleeding_edge |
| 112 | 121 |
| 113 | 122 |
| 114 # TODO(machenbach): Code similarities with bump_up_version.py. Merge after | 123 # TODO(machenbach): Code similarities with bump_up_version.py. Merge after |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 TextToFile(self.GitDiff(self.vc.RemoteCandidateBranch(), | 272 TextToFile(self.GitDiff(self.vc.RemoteCandidateBranch(), |
| 264 self["push_hash"]), | 273 self["push_hash"]), |
| 265 self.Config("PATCH_FILE")) | 274 self.Config("PATCH_FILE")) |
| 266 | 275 |
| 267 # Convert the ChangeLog entry to commit message format. | 276 # Convert the ChangeLog entry to commit message format. |
| 268 text = FileToText(self.Config("CHANGELOG_ENTRY_FILE")) | 277 text = FileToText(self.Config("CHANGELOG_ENTRY_FILE")) |
| 269 | 278 |
| 270 # Remove date and trailing white space. | 279 # Remove date and trailing white space. |
| 271 text = re.sub(r"^%s: " % self["date"], "", text.rstrip()) | 280 text = re.sub(r"^%s: " % self["date"], "", text.rstrip()) |
| 272 | 281 |
| 273 # Retrieve svn revision for showing the used bleeding edge revision in the | 282 # Show the used master hash in the commit message. |
| 274 # commit message. | 283 suffix = PUSH_MSG_GIT_SUFFIX % self["push_hash"] |
| 275 self["svn_revision"] = self.vc.GitSvn(self["push_hash"]) | |
| 276 suffix = PUSH_MESSAGE_SUFFIX % int(self["svn_revision"]) | |
| 277 text = MSub(r"^(Version \d+\.\d+\.\d+)$", "\\1%s" % suffix, text) | 284 text = MSub(r"^(Version \d+\.\d+\.\d+)$", "\\1%s" % suffix, text) |
| 278 | 285 |
| 279 # Remove indentation and merge paragraphs into single long lines, keeping | 286 # Remove indentation and merge paragraphs into single long lines, keeping |
| 280 # empty lines between them. | 287 # empty lines between them. |
| 281 def SplitMapJoin(split_text, fun, join_text): | 288 def SplitMapJoin(split_text, fun, join_text): |
| 282 return lambda text: join_text.join(map(fun, text.split(split_text))) | 289 return lambda text: join_text.join(map(fun, text.split(split_text))) |
| 283 strip = lambda line: line.strip() | 290 strip = lambda line: line.strip() |
| 284 text = SplitMapJoin("\n\n", SplitMapJoin("\n", strip, " "), "\n\n")(text) | 291 text = SplitMapJoin("\n\n", SplitMapJoin("\n", strip, " "), "\n\n")(text) |
| 285 | 292 |
| 286 if not text: # pragma: no cover | 293 if not text: # pragma: no cover |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 group.add_argument("-m", "--manual", | 395 group.add_argument("-m", "--manual", |
| 389 help="Prompt the user at every important step.", | 396 help="Prompt the user at every important step.", |
| 390 default=False, action="store_true") | 397 default=False, action="store_true") |
| 391 parser.add_argument("-b", "--last-bleeding-edge", | 398 parser.add_argument("-b", "--last-bleeding-edge", |
| 392 help=("The git commit ID of the last bleeding edge " | 399 help=("The git commit ID of the last bleeding edge " |
| 393 "revision that was pushed to trunk. This is " | 400 "revision that was pushed to trunk. This is " |
| 394 "used for the auto-generated ChangeLog entry.")) | 401 "used for the auto-generated ChangeLog entry.")) |
| 395 parser.add_argument("-l", "--last-push", | 402 parser.add_argument("-l", "--last-push", |
| 396 help="The git commit ID of the last push to trunk.") | 403 help="The git commit ID of the last push to trunk.") |
| 397 parser.add_argument("-R", "--revision", | 404 parser.add_argument("-R", "--revision", |
| 398 help="The svn revision to push (defaults to HEAD).") | 405 help="The git commit ID to push (defaults to HEAD).") |
| 399 | 406 |
| 400 def _ProcessOptions(self, options): # pragma: no cover | 407 def _ProcessOptions(self, options): # pragma: no cover |
| 401 if not options.manual and not options.reviewer: | 408 if not options.manual and not options.reviewer: |
| 402 print "A reviewer (-r) is required in (semi-)automatic mode." | 409 print "A reviewer (-r) is required in (semi-)automatic mode." |
| 403 return False | 410 return False |
| 404 if not options.manual and not options.author: | 411 if not options.manual and not options.author: |
| 405 print "Specify your chromium.org email with -a in (semi-)automatic mode." | 412 print "Specify your chromium.org email with -a in (semi-)automatic mode." |
| 406 return False | 413 return False |
| 407 if options.revision and not int(options.revision) > 0: | |
| 408 print("The --revision flag must be a positiv integer pointing to a " | |
| 409 "valid svn revision.") | |
| 410 return False | |
| 411 | 414 |
| 412 options.tbr_commit = not options.manual | 415 options.tbr_commit = not options.manual |
| 413 return True | 416 return True |
| 414 | 417 |
| 415 def _Config(self): | 418 def _Config(self): |
| 416 return { | 419 return { |
| 417 "BRANCHNAME": "prepare-push", | 420 "BRANCHNAME": "prepare-push", |
| 418 "TRUNKBRANCH": "trunk-push", | 421 "TRUNKBRANCH": "trunk-push", |
| 419 "PERSISTFILE_BASENAME": "/tmp/v8-push-to-trunk-tempfile", | 422 "PERSISTFILE_BASENAME": "/tmp/v8-push-to-trunk-tempfile", |
| 420 "CHANGELOG_FILE": "ChangeLog", | 423 "CHANGELOG_FILE": "ChangeLog", |
| (...skipping 21 matching lines...) Expand all Loading... |
| 442 CommitTrunk, | 445 CommitTrunk, |
| 443 SanityCheck, | 446 SanityCheck, |
| 444 CommitSVN, | 447 CommitSVN, |
| 445 TagRevision, | 448 TagRevision, |
| 446 CleanUp, | 449 CleanUp, |
| 447 ] | 450 ] |
| 448 | 451 |
| 449 | 452 |
| 450 if __name__ == "__main__": # pragma: no cover | 453 if __name__ == "__main__": # pragma: no cover |
| 451 sys.exit(PushToTrunk().Run()) | 454 sys.exit(PushToTrunk().Run()) |
| OLD | NEW |