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 |