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 29 matching lines...) Expand all Loading... |
40 | 40 |
41 def RunStep(self): | 41 def RunStep(self): |
42 if os.path.exists(self.Config("ALREADY_MERGING_SENTINEL_FILE")): | 42 if os.path.exists(self.Config("ALREADY_MERGING_SENTINEL_FILE")): |
43 if self._options.force: | 43 if self._options.force: |
44 os.remove(self.Config("ALREADY_MERGING_SENTINEL_FILE")) | 44 os.remove(self.Config("ALREADY_MERGING_SENTINEL_FILE")) |
45 elif self._options.step == 0: # pragma: no cover | 45 elif self._options.step == 0: # pragma: no cover |
46 self.Die("A merge is already in progress") | 46 self.Die("A merge is already in progress") |
47 open(self.Config("ALREADY_MERGING_SENTINEL_FILE"), "a").close() | 47 open(self.Config("ALREADY_MERGING_SENTINEL_FILE"), "a").close() |
48 | 48 |
49 self.InitialEnvironmentChecks(self.default_cwd) | 49 self.InitialEnvironmentChecks(self.default_cwd) |
50 if self._options.revert_master: | 50 if self._options.branch: |
51 # FIXME(machenbach): Make revert master obsolete? | |
52 self["merge_to_branch"] = "master" | |
53 elif self._options.branch: | |
54 self["merge_to_branch"] = self._options.branch | 51 self["merge_to_branch"] = self._options.branch |
55 else: # pragma: no cover | 52 else: # pragma: no cover |
56 self.Die("Please specify a branch to merge to") | 53 self.Die("Please specify a branch to merge to") |
57 | 54 |
58 self.CommonPrepare() | 55 self.CommonPrepare() |
59 self.PrepareBranch() | 56 self.PrepareBranch() |
60 | 57 |
61 | 58 |
62 class CreateBranch(Step): | 59 class CreateBranch(Step): |
63 MESSAGE = "Create a fresh branch for the patch." | 60 MESSAGE = "Create a fresh branch for the patch." |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 MESSAGE = "Create commit message." | 100 MESSAGE = "Create commit message." |
104 | 101 |
105 def RunStep(self): | 102 def RunStep(self): |
106 | 103 |
107 # Stringify: ["abcde", "12345"] -> "abcde, 12345" | 104 # Stringify: ["abcde", "12345"] -> "abcde, 12345" |
108 self["revision_list"] = ", ".join(self["full_revision_list"]) | 105 self["revision_list"] = ", ".join(self["full_revision_list"]) |
109 | 106 |
110 if not self["revision_list"]: # pragma: no cover | 107 if not self["revision_list"]: # pragma: no cover |
111 self.Die("Revision list is empty.") | 108 self.Die("Revision list is empty.") |
112 | 109 |
113 if self._options.revert and not self._options.revert_master: | 110 action_text = "Merged %s" |
114 action_text = "Rollback of %s" | |
115 else: | |
116 action_text = "Merged %s" | |
117 | 111 |
118 # The commit message title is added below after the version is specified. | 112 # The commit message title is added below after the version is specified. |
119 msg_pieces = [ | 113 msg_pieces = [ |
120 "\n".join(action_text % s for s in self["full_revision_list"]), | 114 "\n".join(action_text % s for s in self["full_revision_list"]), |
121 ] | 115 ] |
122 msg_pieces.append("\n\n") | 116 msg_pieces.append("\n\n") |
123 | 117 |
124 for commit_hash in self["full_revision_list"]: | 118 for commit_hash in self["full_revision_list"]: |
125 patch_merge_desc = self.GitLog(n=1, format="%s", git_hash=commit_hash) | 119 patch_merge_desc = self.GitLog(n=1, format="%s", git_hash=commit_hash) |
126 msg_pieces.append("%s\n\n" % patch_merge_desc) | 120 msg_pieces.append("%s\n\n" % patch_merge_desc) |
(...skipping 12 matching lines...) Expand all Loading... |
139 | 133 |
140 class ApplyPatches(Step): | 134 class ApplyPatches(Step): |
141 MESSAGE = "Apply patches for selected revisions." | 135 MESSAGE = "Apply patches for selected revisions." |
142 | 136 |
143 def RunStep(self): | 137 def RunStep(self): |
144 for commit_hash in self["full_revision_list"]: | 138 for commit_hash in self["full_revision_list"]: |
145 print("Applying patch for %s to %s..." | 139 print("Applying patch for %s to %s..." |
146 % (commit_hash, self["merge_to_branch"])) | 140 % (commit_hash, self["merge_to_branch"])) |
147 patch = self.GitGetPatch(commit_hash) | 141 patch = self.GitGetPatch(commit_hash) |
148 TextToFile(patch, self.Config("TEMPORARY_PATCH_FILE")) | 142 TextToFile(patch, self.Config("TEMPORARY_PATCH_FILE")) |
149 self.ApplyPatch(self.Config("TEMPORARY_PATCH_FILE"), self._options.revert) | 143 self.ApplyPatch(self.Config("TEMPORARY_PATCH_FILE")) |
150 if self._options.patch: | 144 if self._options.patch: |
151 self.ApplyPatch(self._options.patch, self._options.revert) | 145 self.ApplyPatch(self._options.patch) |
152 | 146 |
153 | 147 |
154 class PrepareVersion(Step): | 148 class PrepareVersion(Step): |
155 MESSAGE = "Prepare version file." | 149 MESSAGE = "Prepare version file." |
156 | 150 |
157 def RunStep(self): | 151 def RunStep(self): |
158 if self._options.revert_master: | |
159 return | |
160 # This is used to calculate the patch level increment. | 152 # This is used to calculate the patch level increment. |
161 self.ReadAndPersistVersion() | 153 self.ReadAndPersistVersion() |
162 | 154 |
163 | 155 |
164 class IncrementVersion(Step): | 156 class IncrementVersion(Step): |
165 MESSAGE = "Increment version number." | 157 MESSAGE = "Increment version number." |
166 | 158 |
167 def RunStep(self): | 159 def RunStep(self): |
168 if self._options.revert_master: | |
169 return | |
170 new_patch = str(int(self["patch"]) + 1) | 160 new_patch = str(int(self["patch"]) + 1) |
171 if self.Confirm("Automatically increment V8_PATCH_LEVEL? (Saying 'n' will " | 161 if self.Confirm("Automatically increment V8_PATCH_LEVEL? (Saying 'n' will " |
172 "fire up your EDITOR on %s so you can make arbitrary " | 162 "fire up your EDITOR on %s so you can make arbitrary " |
173 "changes. When you're done, save the file and exit your " | 163 "changes. When you're done, save the file and exit your " |
174 "EDITOR.)" % VERSION_FILE): | 164 "EDITOR.)" % VERSION_FILE): |
175 text = FileToText(os.path.join(self.default_cwd, VERSION_FILE)) | 165 text = FileToText(os.path.join(self.default_cwd, VERSION_FILE)) |
176 text = MSub(r"(?<=#define V8_PATCH_LEVEL)(?P<space>\s+)\d*$", | 166 text = MSub(r"(?<=#define V8_PATCH_LEVEL)(?P<space>\s+)\d*$", |
177 r"\g<space>%s" % new_patch, | 167 r"\g<space>%s" % new_patch, |
178 text) | 168 text) |
179 TextToFile(text, os.path.join(self.default_cwd, VERSION_FILE)) | 169 TextToFile(text, os.path.join(self.default_cwd, VERSION_FILE)) |
180 else: | 170 else: |
181 self.Editor(os.path.join(self.default_cwd, VERSION_FILE)) | 171 self.Editor(os.path.join(self.default_cwd, VERSION_FILE)) |
182 self.ReadAndPersistVersion("new_") | 172 self.ReadAndPersistVersion("new_") |
183 self["version"] = "%s.%s.%s.%s" % (self["new_major"], | 173 self["version"] = "%s.%s.%s.%s" % (self["new_major"], |
184 self["new_minor"], | 174 self["new_minor"], |
185 self["new_build"], | 175 self["new_build"], |
186 self["new_patch"]) | 176 self["new_patch"]) |
187 | 177 |
188 | 178 |
189 class CommitLocal(Step): | 179 class CommitLocal(Step): |
190 MESSAGE = "Commit to local branch." | 180 MESSAGE = "Commit to local branch." |
191 | 181 |
192 def RunStep(self): | 182 def RunStep(self): |
193 # Add a commit message title. | 183 # Add a commit message title. |
194 if self._options.revert and self._options.revert_master: | 184 self["commit_title"] = "Version %s (cherry-pick)" % self["version"] |
195 # TODO(machenbach): Find a better convention if multiple patches are | |
196 # reverted in one CL. | |
197 self["commit_title"] = "Revert on master" | |
198 else: | |
199 self["commit_title"] = "Version %s (cherry-pick)" % self["version"] | |
200 self["new_commit_msg"] = "%s\n\n%s" % (self["commit_title"], | 185 self["new_commit_msg"] = "%s\n\n%s" % (self["commit_title"], |
201 self["new_commit_msg"]) | 186 self["new_commit_msg"]) |
202 TextToFile(self["new_commit_msg"], self.Config("COMMITMSG_FILE")) | 187 TextToFile(self["new_commit_msg"], self.Config("COMMITMSG_FILE")) |
203 self.GitCommit(file_name=self.Config("COMMITMSG_FILE")) | 188 self.GitCommit(file_name=self.Config("COMMITMSG_FILE")) |
204 | 189 |
205 | 190 |
206 class CommitRepository(Step): | 191 class CommitRepository(Step): |
207 MESSAGE = "Commit to the repository." | 192 MESSAGE = "Commit to the repository." |
208 | 193 |
209 def RunStep(self): | 194 def RunStep(self): |
210 self.GitCheckout(self.Config("BRANCHNAME")) | 195 self.GitCheckout(self.Config("BRANCHNAME")) |
211 self.WaitForLGTM() | 196 self.WaitForLGTM() |
212 self.GitPresubmit() | 197 self.GitPresubmit() |
213 self.vc.CLLand() | 198 self.vc.CLLand() |
214 | 199 |
215 | 200 |
216 class TagRevision(Step): | 201 class TagRevision(Step): |
217 MESSAGE = "Create the tag." | 202 MESSAGE = "Create the tag." |
218 | 203 |
219 def RunStep(self): | 204 def RunStep(self): |
220 if self._options.revert_master: | |
221 return | |
222 print "Creating tag %s" % self["version"] | 205 print "Creating tag %s" % self["version"] |
223 self.vc.Tag(self["version"], | 206 self.vc.Tag(self["version"], |
224 self.vc.RemoteBranch(self["merge_to_branch"]), | 207 self.vc.RemoteBranch(self["merge_to_branch"]), |
225 self["commit_title"]) | 208 self["commit_title"]) |
226 | 209 |
227 | 210 |
228 class CleanUp(Step): | 211 class CleanUp(Step): |
229 MESSAGE = "Cleanup." | 212 MESSAGE = "Cleanup." |
230 | 213 |
231 def RunStep(self): | 214 def RunStep(self): |
232 self.CommonCleanup() | 215 self.CommonCleanup() |
233 if not self._options.revert_master: | 216 print "*** SUMMARY ***" |
234 print "*** SUMMARY ***" | 217 print "version: %s" % self["version"] |
235 print "version: %s" % self["version"] | 218 print "branch: %s" % self["merge_to_branch"] |
236 print "branch: %s" % self["merge_to_branch"] | 219 if self["revision_list"]: |
237 if self["revision_list"]: | 220 print "patches: %s" % self["revision_list"] |
238 print "patches: %s" % self["revision_list"] | |
239 | 221 |
240 | 222 |
241 class MergeToBranch(ScriptsBase): | 223 class MergeToBranch(ScriptsBase): |
242 def _Description(self): | 224 def _Description(self): |
243 return ("Performs the necessary steps to merge revisions from " | 225 return ("Performs the necessary steps to merge revisions from " |
244 "master to other branches, including candidates.") | 226 "master to other branches, including candidates.") |
245 | 227 |
246 def _PrepareOptions(self, parser): | 228 def _PrepareOptions(self, parser): |
247 group = parser.add_mutually_exclusive_group(required=True) | 229 group = parser.add_mutually_exclusive_group(required=True) |
248 group.add_argument("--branch", help="The branch to merge to.") | 230 group.add_argument("--branch", help="The branch to merge to.") |
249 group.add_argument("-R", "--revert-master", | |
250 help="Revert specified patches from master.", | |
251 default=False, action="store_true") | |
252 parser.add_argument("revisions", nargs="*", | 231 parser.add_argument("revisions", nargs="*", |
253 help="The revisions to merge.") | 232 help="The revisions to merge.") |
254 parser.add_argument("-f", "--force", | 233 parser.add_argument("-f", "--force", |
255 help="Delete sentinel file.", | 234 help="Delete sentinel file.", |
256 default=False, action="store_true") | 235 default=False, action="store_true") |
257 parser.add_argument("-m", "--message", | 236 parser.add_argument("-m", "--message", |
258 help="A commit message for the patch.") | 237 help="A commit message for the patch.") |
259 parser.add_argument("--revert", | |
260 help="Revert specified patches.", | |
261 default=False, action="store_true") | |
262 parser.add_argument("-p", "--patch", | 238 parser.add_argument("-p", "--patch", |
263 help="A patch file to apply as part of the merge.") | 239 help="A patch file to apply as part of the merge.") |
264 | 240 |
265 def _ProcessOptions(self, options): | 241 def _ProcessOptions(self, options): |
266 # TODO(machenbach): Add a test that covers revert from master | |
267 if len(options.revisions) < 1: | 242 if len(options.revisions) < 1: |
268 if not options.patch: | 243 if not options.patch: |
269 print "Either a patch file or revision numbers must be specified" | 244 print "Either a patch file or revision numbers must be specified" |
270 return False | 245 return False |
271 if not options.message: | 246 if not options.message: |
272 print "You must specify a merge comment if no patches are specified" | 247 print "You must specify a merge comment if no patches are specified" |
273 return False | 248 return False |
274 options.bypass_upload_hooks = True | 249 options.bypass_upload_hooks = True |
275 # CC ulan to make sure that fixes are merged to Google3. | 250 # CC ulan to make sure that fixes are merged to Google3. |
276 options.cc = "ulan@chromium.org" | 251 options.cc = "ulan@chromium.org" |
(...skipping 29 matching lines...) Expand all Loading... |
306 CommitLocal, | 281 CommitLocal, |
307 UploadStep, | 282 UploadStep, |
308 CommitRepository, | 283 CommitRepository, |
309 TagRevision, | 284 TagRevision, |
310 CleanUp, | 285 CleanUp, |
311 ] | 286 ] |
312 | 287 |
313 | 288 |
314 if __name__ == "__main__": # pragma: no cover | 289 if __name__ == "__main__": # pragma: no cover |
315 sys.exit(MergeToBranch().Run()) | 290 sys.exit(MergeToBranch().Run()) |
OLD | NEW |