OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2014 the V8 project authors. All rights reserved. | 2 # Copyright 2014 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 14 matching lines...) Expand all Loading... | |
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
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 from collections import OrderedDict | 30 from collections import OrderedDict |
31 import sys | 31 import sys |
32 | 32 |
33 from common_includes import * | 33 from common_includes import * |
34 | 34 |
35 def IsSvnNumber(rev): | |
36 return rev.isdigit() and len(rev) < 8 | |
37 | |
35 class Preparation(Step): | 38 class Preparation(Step): |
36 MESSAGE = "Preparation." | 39 MESSAGE = "Preparation." |
37 | 40 |
38 def RunStep(self): | 41 def RunStep(self): |
39 if os.path.exists(self.Config("ALREADY_MERGING_SENTINEL_FILE")): | 42 if os.path.exists(self.Config("ALREADY_MERGING_SENTINEL_FILE")): |
40 if self._options.force: | 43 if self._options.force: |
41 os.remove(self.Config("ALREADY_MERGING_SENTINEL_FILE")) | 44 os.remove(self.Config("ALREADY_MERGING_SENTINEL_FILE")) |
42 elif self._options.step == 0: # pragma: no cover | 45 elif self._options.step == 0: # pragma: no cover |
43 self.Die("A merge is already in progress") | 46 self.Die("A merge is already in progress") |
44 open(self.Config("ALREADY_MERGING_SENTINEL_FILE"), "a").close() | 47 open(self.Config("ALREADY_MERGING_SENTINEL_FILE"), "a").close() |
(...skipping 20 matching lines...) Expand all Loading... | |
65 | 68 |
66 | 69 |
67 class SearchArchitecturePorts(Step): | 70 class SearchArchitecturePorts(Step): |
68 MESSAGE = "Search for corresponding architecture ports." | 71 MESSAGE = "Search for corresponding architecture ports." |
69 | 72 |
70 def RunStep(self): | 73 def RunStep(self): |
71 self["full_revision_list"] = list(OrderedDict.fromkeys( | 74 self["full_revision_list"] = list(OrderedDict.fromkeys( |
72 self._options.revisions)) | 75 self._options.revisions)) |
73 port_revision_list = [] | 76 port_revision_list = [] |
74 for revision in self["full_revision_list"]: | 77 for revision in self["full_revision_list"]: |
75 # Search for commits which matches the "Port rXXX" pattern. | 78 # Search for commits which matches the "Port XXX" pattern. |
76 git_hashes = self.GitLog(reverse=True, format="%H", | 79 git_hashes = self.GitLog(reverse=True, format="%H", |
77 grep="Port r%d" % int(revision), | 80 grep="Port %s" % revision, |
78 branch=self.vc.RemoteMasterBranch()) | 81 branch=self.vc.RemoteMasterBranch()) |
79 for git_hash in git_hashes.splitlines(): | 82 for git_hash in git_hashes.splitlines(): |
80 svn_revision = self.vc.GitSvn(git_hash, self.vc.RemoteMasterBranch()) | |
81 if not svn_revision: # pragma: no cover | |
82 self.Die("Cannot determine svn revision for %s" % git_hash) | |
83 revision_title = self.GitLog(n=1, format="%s", git_hash=git_hash) | 83 revision_title = self.GitLog(n=1, format="%s", git_hash=git_hash) |
84 | 84 |
85 # Is this revision included in the original revision list? | 85 # Is this revision included in the original revision list? |
86 if svn_revision in self["full_revision_list"]: | 86 if git_hash in self["full_revision_list"]: |
87 print("Found port of r%s -> r%s (already included): %s" | 87 print("Found port of %s -> %s (already included): %s" |
88 % (revision, svn_revision, revision_title)) | 88 % (revision, git_hash, revision_title)) |
89 else: | 89 else: |
90 print("Found port of r%s -> r%s: %s" | 90 print("Found port of %s -> %s: %s" |
91 % (revision, svn_revision, revision_title)) | 91 % (revision, git_hash, revision_title)) |
92 port_revision_list.append(svn_revision) | 92 port_revision_list.append(git_hash) |
93 | 93 |
94 # Do we find any port? | 94 # Do we find any port? |
95 if len(port_revision_list) > 0: | 95 if len(port_revision_list) > 0: |
96 if self.Confirm("Automatically add corresponding ports (%s)?" | 96 if self.Confirm("Automatically add corresponding ports (%s)?" |
97 % ", ".join(port_revision_list)): | 97 % ", ".join(port_revision_list)): |
98 #: 'y': Add ports to revision list. | 98 #: 'y': Add ports to revision list. |
99 self["full_revision_list"].extend(port_revision_list) | 99 self["full_revision_list"].extend(port_revision_list) |
100 | 100 |
101 | 101 |
102 class FindGitRevisions(Step): | 102 class CreateCommitMessage(Step): |
103 MESSAGE = "Find the git revisions associated with the patches." | 103 MESSAGE = "Create commit message." |
104 | 104 |
105 def RunStep(self): | 105 def RunStep(self): |
106 self["patch_commit_hashes"] = [] | |
107 for revision in self["full_revision_list"]: | |
108 next_hash = self.vc.SvnGit(revision, self.vc.RemoteMasterBranch()) | |
109 if not next_hash: # pragma: no cover | |
110 self.Die("Cannot determine git hash for r%s" % revision) | |
111 self["patch_commit_hashes"].append(next_hash) | |
112 | 106 |
113 # Stringify: [123, 234] -> "r123, r234" | 107 # Stringify: [123, 234] -> "r123, r234" |
114 self["revision_list"] = ", ".join(map(lambda s: "r%s" % s, | 108 self["revision_list"] = ", ".join(map(lambda s: "r%s" % s, |
115 self["full_revision_list"])) | 109 self["full_revision_list"])) |
116 | 110 |
117 if not self["revision_list"]: # pragma: no cover | 111 if not self["revision_list"]: # pragma: no cover |
118 self.Die("Revision list is empty.") | 112 self.Die("Revision list is empty.") |
119 | 113 |
114 if self._options.revert and not self._options.revert_bleeding_edge: | |
115 action_text = "Rollback of %s" | |
116 else: | |
117 action_text = "Merged %s" | |
120 # The commit message title is added below after the version is specified. | 118 # The commit message title is added below after the version is specified. |
121 self["new_commit_msg"] = "" | 119 self["new_commit_msg"] = "\n".join(map(lambda s: action_text % s, |
120 self["full_revision_list"])) | |
tandrii(chromium)
2014/11/05 12:59:15
I think this is shorter and more readable:
join(ac
Michael Achenbach
2014/11/05 13:30:37
Done.
| |
121 self["new_commit_msg"] += "\n\n" | |
122 | 122 |
123 for commit_hash in self["patch_commit_hashes"]: | 123 for commit_hash in self["full_revision_list"]: |
124 patch_merge_desc = self.GitLog(n=1, format="%s", git_hash=commit_hash) | 124 patch_merge_desc = self.GitLog(n=1, format="%s", git_hash=commit_hash) |
125 self["new_commit_msg"] += "%s\n\n" % patch_merge_desc | 125 self["new_commit_msg"] += "%s\n\n" % patch_merge_desc |
126 | 126 |
127 bugs = [] | 127 bugs = [] |
128 for commit_hash in self["patch_commit_hashes"]: | 128 for commit_hash in self["full_revision_list"]: |
129 msg = self.GitLog(n=1, git_hash=commit_hash) | 129 msg = self.GitLog(n=1, git_hash=commit_hash) |
130 for bug in re.findall(r"^[ \t]*BUG[ \t]*=[ \t]*(.*?)[ \t]*$", msg, | 130 for bug in re.findall(r"^[ \t]*BUG[ \t]*=[ \t]*(.*?)[ \t]*$", msg, |
131 re.M): | 131 re.M): |
132 bugs.extend(map(lambda s: s.strip(), bug.split(","))) | 132 bugs.extend(map(lambda s: s.strip(), bug.split(","))) |
tandrii(chromium)
2014/11/05 12:59:15
consider shorter:
bugs.extend(s.strip() for s in b
Michael Achenbach
2014/11/05 13:30:37
Done.
| |
133 bug_aggregate = ",".join(sorted(filter(lambda s: s and s != "none", bugs))) | 133 bug_aggregate = ",".join(sorted(filter(lambda s: s and s != "none", bugs))) |
134 if bug_aggregate: | 134 if bug_aggregate: |
135 self["new_commit_msg"] += "BUG=%s\nLOG=N\n" % bug_aggregate | 135 self["new_commit_msg"] += "BUG=%s\nLOG=N\n" % bug_aggregate |
136 | 136 |
137 | 137 |
138 class ApplyPatches(Step): | 138 class ApplyPatches(Step): |
139 MESSAGE = "Apply patches for selected revisions." | 139 MESSAGE = "Apply patches for selected revisions." |
140 | 140 |
141 def RunStep(self): | 141 def RunStep(self): |
142 for commit_hash in self["patch_commit_hashes"]: | 142 for commit_hash in self["full_revision_list"]: |
143 print("Applying patch for %s to %s..." | 143 print("Applying patch for %s to %s..." |
144 % (commit_hash, self["merge_to_branch"])) | 144 % (commit_hash, self["merge_to_branch"])) |
145 patch = self.GitGetPatch(commit_hash) | 145 patch = self.GitGetPatch(commit_hash) |
146 TextToFile(patch, self.Config("TEMPORARY_PATCH_FILE")) | 146 TextToFile(patch, self.Config("TEMPORARY_PATCH_FILE")) |
147 self.ApplyPatch(self.Config("TEMPORARY_PATCH_FILE"), self._options.revert) | 147 self.ApplyPatch(self.Config("TEMPORARY_PATCH_FILE"), self._options.revert) |
148 if self._options.patch: | 148 if self._options.patch: |
149 self.ApplyPatch(self._options.patch, self._options.revert) | 149 self.ApplyPatch(self._options.patch, self._options.revert) |
150 | 150 |
151 | 151 |
152 class PrepareVersion(Step): | 152 class PrepareVersion(Step): |
(...skipping 29 matching lines...) Expand all Loading... | |
182 self["new_minor"], | 182 self["new_minor"], |
183 self["new_build"], | 183 self["new_build"], |
184 self["new_patch"]) | 184 self["new_patch"]) |
185 | 185 |
186 | 186 |
187 class CommitLocal(Step): | 187 class CommitLocal(Step): |
188 MESSAGE = "Commit to local branch." | 188 MESSAGE = "Commit to local branch." |
189 | 189 |
190 def RunStep(self): | 190 def RunStep(self): |
191 # Add a commit message title. | 191 # Add a commit message title. |
192 if self._options.revert: | 192 if self._options.revert and self._options.revert_bleeding_edge: |
193 if not self._options.revert_bleeding_edge: | 193 # TODO(machenbach): Find a better convention if multiple patches are |
194 title = ("Version %s (rollback of %s)" | 194 # reverted in one CL. |
195 % (self["version"], self["revision_list"])) | 195 self["commit_title"] = "Revert on master" |
196 else: | |
197 title = "Revert %s." % self["revision_list"] | |
198 else: | 196 else: |
199 title = ("Version %s (merged %s)" | 197 self["commit_title"] = "Version %s (cherry-pick)" % self["version"] |
200 % (self["version"], self["revision_list"])) | 198 self["new_commit_msg"] = "%s\n\n%s" % (self["commit_title"], |
201 self["commit_title"] = title | 199 self["new_commit_msg"]) |
202 self["new_commit_msg"] = "%s\n\n%s" % (title, self["new_commit_msg"]) | |
203 TextToFile(self["new_commit_msg"], self.Config("COMMITMSG_FILE")) | 200 TextToFile(self["new_commit_msg"], self.Config("COMMITMSG_FILE")) |
204 self.GitCommit(file_name=self.Config("COMMITMSG_FILE")) | 201 self.GitCommit(file_name=self.Config("COMMITMSG_FILE")) |
205 | 202 |
206 | 203 |
207 class CommitRepository(Step): | 204 class CommitRepository(Step): |
208 MESSAGE = "Commit to the repository." | 205 MESSAGE = "Commit to the repository." |
209 | 206 |
210 def RunStep(self): | 207 def RunStep(self): |
211 self.GitCheckout(self.Config("BRANCHNAME")) | 208 self.GitCheckout(self.Config("BRANCHNAME")) |
212 self.WaitForLGTM() | 209 self.WaitForLGTM() |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
268 if len(options.revisions) < 1: | 265 if len(options.revisions) < 1: |
269 if not options.patch: | 266 if not options.patch: |
270 print "Either a patch file or revision numbers must be specified" | 267 print "Either a patch file or revision numbers must be specified" |
271 return False | 268 return False |
272 if not options.message: | 269 if not options.message: |
273 print "You must specify a merge comment if no patches are specified" | 270 print "You must specify a merge comment if no patches are specified" |
274 return False | 271 return False |
275 options.bypass_upload_hooks = True | 272 options.bypass_upload_hooks = True |
276 # CC ulan to make sure that fixes are merged to Google3. | 273 # CC ulan to make sure that fixes are merged to Google3. |
277 options.cc = "ulan@chromium.org" | 274 options.cc = "ulan@chromium.org" |
275 | |
276 # Thd old git-svn workflow is deprecated for this script. | |
277 assert options.vc_interface != "git_svn" | |
278 | |
279 # Make sure to use git hashes in the new workflows. | |
280 for revision in options.revisions: | |
281 if (IsSvnNumber(revision) or | |
282 (revision[0:1] == "r" and IsSvnNumber(revision[1:]))): | |
283 print "Please provide full git hashes of the patches to merge." | |
284 print "Got: %s" % revision | |
285 return False | |
278 return True | 286 return True |
279 | 287 |
280 def _Config(self): | 288 def _Config(self): |
281 return { | 289 return { |
282 "BRANCHNAME": "prepare-merge", | 290 "BRANCHNAME": "prepare-merge", |
283 "PERSISTFILE_BASENAME": "/tmp/v8-merge-to-branch-tempfile", | 291 "PERSISTFILE_BASENAME": "/tmp/v8-merge-to-branch-tempfile", |
284 "ALREADY_MERGING_SENTINEL_FILE": | 292 "ALREADY_MERGING_SENTINEL_FILE": |
285 "/tmp/v8-merge-to-branch-tempfile-already-merging", | 293 "/tmp/v8-merge-to-branch-tempfile-already-merging", |
286 "TEMPORARY_PATCH_FILE": "/tmp/v8-prepare-merge-tempfile-temporary-patch", | 294 "TEMPORARY_PATCH_FILE": "/tmp/v8-prepare-merge-tempfile-temporary-patch", |
287 "COMMITMSG_FILE": "/tmp/v8-prepare-merge-tempfile-commitmsg", | 295 "COMMITMSG_FILE": "/tmp/v8-prepare-merge-tempfile-commitmsg", |
288 } | 296 } |
289 | 297 |
290 def _Steps(self): | 298 def _Steps(self): |
291 return [ | 299 return [ |
292 Preparation, | 300 Preparation, |
293 CreateBranch, | 301 CreateBranch, |
294 SearchArchitecturePorts, | 302 SearchArchitecturePorts, |
295 FindGitRevisions, | 303 CreateCommitMessage, |
296 ApplyPatches, | 304 ApplyPatches, |
297 PrepareVersion, | 305 PrepareVersion, |
298 IncrementVersion, | 306 IncrementVersion, |
299 CommitLocal, | 307 CommitLocal, |
300 UploadStep, | 308 UploadStep, |
301 CommitRepository, | 309 CommitRepository, |
302 TagRevision, | 310 TagRevision, |
303 CleanUp, | 311 CleanUp, |
304 ] | 312 ] |
305 | 313 |
306 | 314 |
307 if __name__ == "__main__": # pragma: no cover | 315 if __name__ == "__main__": # pragma: no cover |
308 sys.exit(MergeToBranch().Run()) | 316 sys.exit(MergeToBranch().Run()) |
OLD | NEW |