Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(374)

Side by Side Diff: tools/push-to-trunk/merge_to_branch.py

Issue 170583002: Refactor persisting state in push and merge scripts. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/push-to-trunk/common_includes.py ('k') | tools/push-to-trunk/push_to_trunk.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 def RunStep(self): 69 def RunStep(self):
70 if os.path.exists(self.Config(ALREADY_MERGING_SENTINEL_FILE)): 70 if os.path.exists(self.Config(ALREADY_MERGING_SENTINEL_FILE)):
71 if self._options.delete_sentinel: 71 if self._options.delete_sentinel:
72 os.remove(self.Config(ALREADY_MERGING_SENTINEL_FILE)) 72 os.remove(self.Config(ALREADY_MERGING_SENTINEL_FILE))
73 elif self._options.s == 0: 73 elif self._options.s == 0:
74 self.Die("A merge is already in progress") 74 self.Die("A merge is already in progress")
75 open(self.Config(ALREADY_MERGING_SENTINEL_FILE), "a").close() 75 open(self.Config(ALREADY_MERGING_SENTINEL_FILE), "a").close()
76 76
77 self.InitialEnvironmentChecks() 77 self.InitialEnvironmentChecks()
78 if self._options.revert_bleeding_edge: 78 if self._options.revert_bleeding_edge:
79 self.Persist("merge_to_branch", "bleeding_edge") 79 self["merge_to_branch"] = "bleeding_edge"
80 elif self._options.args[0]: 80 elif self._options.args[0]:
81 self.Persist("merge_to_branch", self._options.args[0]) 81 self["merge_to_branch"] = self._options.args[0]
82 self._options.args = self._options.args[1:] 82 self._options.args = self._options.args[1:]
83 else: 83 else:
84 self.Die("Please specify a branch to merge to") 84 self.Die("Please specify a branch to merge to")
85 85
86 self.CommonPrepare() 86 self.CommonPrepare()
87 self.PrepareBranch() 87 self.PrepareBranch()
88 88
89 89
90 class CreateBranch(Step): 90 class CreateBranch(Step):
91 MESSAGE = "Create a fresh branch for the patch." 91 MESSAGE = "Create a fresh branch for the patch."
92 92
93 def RunStep(self): 93 def RunStep(self):
94 self.RestoreIfUnset("merge_to_branch")
95 args = "checkout -b %s svn/%s" % (self.Config(BRANCHNAME), 94 args = "checkout -b %s svn/%s" % (self.Config(BRANCHNAME),
96 self._state["merge_to_branch"]) 95 self["merge_to_branch"])
97 if self.Git(args) is None: 96 if self.Git(args) is None:
98 self.die("Creating branch %s failed." % self.Config(BRANCHNAME)) 97 self.die("Creating branch %s failed." % self.Config(BRANCHNAME))
99 98
100 99
101 class SearchArchitecturePorts(Step): 100 class SearchArchitecturePorts(Step):
102 MESSAGE = "Search for corresponding architecture ports." 101 MESSAGE = "Search for corresponding architecture ports."
103 102
104 def RunStep(self): 103 def RunStep(self):
105 full_revision_list = list(OrderedDict.fromkeys(self._options.args)) 104 self["full_revision_list"] = list(OrderedDict.fromkeys(self._options.args))
106 port_revision_list = [] 105 port_revision_list = []
107 for revision in full_revision_list: 106 for revision in self["full_revision_list"]:
108 # Search for commits which matches the "Port rXXX" pattern. 107 # Search for commits which matches the "Port rXXX" pattern.
109 args = ("log svn/bleeding_edge --reverse " 108 args = ("log svn/bleeding_edge --reverse "
110 "--format=%%H --grep=\"Port r%d\"" % int(revision)) 109 "--format=%%H --grep=\"Port r%d\"" % int(revision))
111 git_hashes = self.Git(args) or "" 110 git_hashes = self.Git(args) or ""
112 for git_hash in git_hashes.strip().splitlines(): 111 for git_hash in git_hashes.strip().splitlines():
113 args = "svn find-rev %s svn/bleeding_edge" % git_hash 112 args = "svn find-rev %s svn/bleeding_edge" % git_hash
114 svn_revision = self.Git(args).strip() 113 svn_revision = self.Git(args).strip()
115 if not svn_revision: 114 if not svn_revision:
116 self.Die("Cannot determine svn revision for %s" % git_hash) 115 self.Die("Cannot determine svn revision for %s" % git_hash)
117 revision_title = self.Git("log -1 --format=%%s %s" % git_hash) 116 revision_title = self.Git("log -1 --format=%%s %s" % git_hash)
118 117
119 # Is this revision included in the original revision list? 118 # Is this revision included in the original revision list?
120 if svn_revision in full_revision_list: 119 if svn_revision in self["full_revision_list"]:
121 print("Found port of r%s -> r%s (already included): %s" 120 print("Found port of r%s -> r%s (already included): %s"
122 % (revision, svn_revision, revision_title)) 121 % (revision, svn_revision, revision_title))
123 else: 122 else:
124 print("Found port of r%s -> r%s: %s" 123 print("Found port of r%s -> r%s: %s"
125 % (revision, svn_revision, revision_title)) 124 % (revision, svn_revision, revision_title))
126 port_revision_list.append(svn_revision) 125 port_revision_list.append(svn_revision)
127 126
128 # Do we find any port? 127 # Do we find any port?
129 if len(port_revision_list) > 0: 128 if len(port_revision_list) > 0:
130 if self.Confirm("Automatically add corresponding ports (%s)?" 129 if self.Confirm("Automatically add corresponding ports (%s)?"
131 % ", ".join(port_revision_list)): 130 % ", ".join(port_revision_list)):
132 #: 'y': Add ports to revision list. 131 #: 'y': Add ports to revision list.
133 full_revision_list.extend(port_revision_list) 132 self["full_revision_list"].extend(port_revision_list)
134 self.Persist("full_revision_list", ",".join(full_revision_list))
135 133
136 134
137 class FindGitRevisions(Step): 135 class FindGitRevisions(Step):
138 MESSAGE = "Find the git revisions associated with the patches." 136 MESSAGE = "Find the git revisions associated with the patches."
139 137
140 def RunStep(self): 138 def RunStep(self):
141 self.RestoreIfUnset("full_revision_list") 139 self["patch_commit_hashes"] = []
142 self.RestoreIfUnset("merge_to_branch") 140 for revision in self["full_revision_list"]:
143 full_revision_list = self._state["full_revision_list"].split(",")
144 patch_commit_hashes = []
145 for revision in full_revision_list:
146 next_hash = self.Git("svn find-rev \"r%s\" svn/bleeding_edge" % revision) 141 next_hash = self.Git("svn find-rev \"r%s\" svn/bleeding_edge" % revision)
147 if not next_hash: 142 if not next_hash:
148 self.Die("Cannot determine git hash for r%s" % revision) 143 self.Die("Cannot determine git hash for r%s" % revision)
149 patch_commit_hashes.append(next_hash) 144 self["patch_commit_hashes"].append(next_hash)
150 145
151 # Stringify: [123, 234] -> "r123, r234" 146 # Stringify: [123, 234] -> "r123, r234"
152 revision_list = ", ".join(map(lambda s: "r%s" % s, full_revision_list)) 147 self["revision_list"] = ", ".join(map(lambda s: "r%s" % s,
148 self["full_revision_list"]))
153 149
154 if not revision_list: 150 if not self["revision_list"]:
155 self.Die("Revision list is empty.") 151 self.Die("Revision list is empty.")
156 152
157 if self._options.revert: 153 if self._options.revert:
158 if not self._options.revert_bleeding_edge: 154 if not self._options.revert_bleeding_edge:
159 new_commit_msg = ("Rollback of %s in %s branch." 155 self["new_commit_msg"] = ("Rollback of %s in %s branch."
160 % (revision_list, self._state["merge_to_branch"])) 156 % (self["revision_list"], self["merge_to_branch"]))
161 else: 157 else:
162 new_commit_msg = "Revert %s ." % revision_list 158 self["new_commit_msg"] = "Revert %s." % self["revision_list"]
163 else: 159 else:
164 new_commit_msg = ("Merged %s into %s branch." 160 self["new_commit_msg"] = ("Merged %s into %s branch."
165 % (revision_list, self._state["merge_to_branch"])) 161 % (self["revision_list"], self["merge_to_branch"]))
166 new_commit_msg += "\n\n" 162 self["new_commit_msg"] += "\n\n"
167 163
168 for commit_hash in patch_commit_hashes: 164 for commit_hash in self["patch_commit_hashes"]:
169 patch_merge_desc = self.Git("log -1 --format=%%s %s" % commit_hash) 165 patch_merge_desc = self.Git("log -1 --format=%%s %s" % commit_hash)
170 new_commit_msg += "%s\n\n" % patch_merge_desc.strip() 166 self["new_commit_msg"] += "%s\n\n" % patch_merge_desc.strip()
171 167
172 bugs = [] 168 bugs = []
173 for commit_hash in patch_commit_hashes: 169 for commit_hash in self["patch_commit_hashes"]:
174 msg = self.Git("log -1 %s" % commit_hash) 170 msg = self.Git("log -1 %s" % commit_hash)
175 for bug in re.findall(r"^[ \t]*BUG[ \t]*=[ \t]*(.*?)[ \t]*$", msg, 171 for bug in re.findall(r"^[ \t]*BUG[ \t]*=[ \t]*(.*?)[ \t]*$", msg,
176 re.M): 172 re.M):
177 bugs.extend(map(lambda s: s.strip(), bug.split(","))) 173 bugs.extend(map(lambda s: s.strip(), bug.split(",")))
178 bug_aggregate = ",".join(sorted(bugs)) 174 bug_aggregate = ",".join(sorted(bugs))
179 if bug_aggregate: 175 if bug_aggregate:
180 new_commit_msg += "BUG=%s\nLOG=N\n" % bug_aggregate 176 self["new_commit_msg"] += "BUG=%s\nLOG=N\n" % bug_aggregate
181 TextToFile(new_commit_msg, self.Config(COMMITMSG_FILE)) 177 TextToFile(self["new_commit_msg"], self.Config(COMMITMSG_FILE))
182 self.Persist("new_commit_msg", new_commit_msg)
183 self.Persist("revision_list", revision_list)
184 self._state["patch_commit_hashes"] = patch_commit_hashes
185 self.Persist("patch_commit_hashes_list", " ".join(patch_commit_hashes))
186 178
187 179
188 class ApplyPatches(Step): 180 class ApplyPatches(Step):
189 MESSAGE = "Apply patches for selected revisions." 181 MESSAGE = "Apply patches for selected revisions."
190 182
191 def RunStep(self): 183 def RunStep(self):
192 self.RestoreIfUnset("merge_to_branch") 184 for commit_hash in self["patch_commit_hashes"]:
193 self.RestoreIfUnset("patch_commit_hashes_list")
194 patch_commit_hashes = self._state.get("patch_commit_hashes")
195 if not patch_commit_hashes:
196 patch_commit_hashes = (
197 self._state.get("patch_commit_hashes_list").strip().split(" "))
198 if not patch_commit_hashes and not options.patch:
199 self.Die("Variable patch_commit_hashes could not be restored.")
200 for commit_hash in patch_commit_hashes:
201 print("Applying patch for %s to %s..." 185 print("Applying patch for %s to %s..."
202 % (commit_hash, self._state["merge_to_branch"])) 186 % (commit_hash, self["merge_to_branch"]))
203 patch = self.Git("log -1 -p %s" % commit_hash) 187 patch = self.Git("log -1 -p %s" % commit_hash)
204 TextToFile(patch, self.Config(TEMPORARY_PATCH_FILE)) 188 TextToFile(patch, self.Config(TEMPORARY_PATCH_FILE))
205 self.ApplyPatch(self.Config(TEMPORARY_PATCH_FILE), self._options.revert) 189 self.ApplyPatch(self.Config(TEMPORARY_PATCH_FILE), self._options.revert)
206 if self._options.patch: 190 if self._options.patch:
207 self.ApplyPatch(self._options.patch, self._options.revert) 191 self.ApplyPatch(self._options.patch, self._options.revert)
208 192
209 193
210 class PrepareVersion(Step): 194 class PrepareVersion(Step):
211 MESSAGE = "Prepare version file." 195 MESSAGE = "Prepare version file."
212 196
213 def RunStep(self): 197 def RunStep(self):
214 if self._options.revert_bleeding_edge: 198 if self._options.revert_bleeding_edge:
215 return 199 return
216 # These version numbers are used again for creating the tag 200 # These version numbers are used again for creating the tag
217 self.ReadAndPersistVersion() 201 self.ReadAndPersistVersion()
218 202
219 203
220 class IncrementVersion(Step): 204 class IncrementVersion(Step):
221 MESSAGE = "Increment version number." 205 MESSAGE = "Increment version number."
222 206
223 def RunStep(self): 207 def RunStep(self):
224 if self._options.revert_bleeding_edge: 208 if self._options.revert_bleeding_edge:
225 return 209 return
226 self.RestoreIfUnset("patch") 210 new_patch = str(int(self["patch"]) + 1)
227 new_patch = str(int(self._state["patch"]) + 1)
228 if self.Confirm("Automatically increment PATCH_LEVEL? (Saying 'n' will " 211 if self.Confirm("Automatically increment PATCH_LEVEL? (Saying 'n' will "
229 "fire up your EDITOR on %s so you can make arbitrary " 212 "fire up your EDITOR on %s so you can make arbitrary "
230 "changes. When you're done, save the file and exit your " 213 "changes. When you're done, save the file and exit your "
231 "EDITOR.)" % self.Config(VERSION_FILE)): 214 "EDITOR.)" % self.Config(VERSION_FILE)):
232 text = FileToText(self.Config(VERSION_FILE)) 215 text = FileToText(self.Config(VERSION_FILE))
233 text = MSub(r"(?<=#define PATCH_LEVEL)(?P<space>\s+)\d*$", 216 text = MSub(r"(?<=#define PATCH_LEVEL)(?P<space>\s+)\d*$",
234 r"\g<space>%s" % new_patch, 217 r"\g<space>%s" % new_patch,
235 text) 218 text)
236 TextToFile(text, self.Config(VERSION_FILE)) 219 TextToFile(text, self.Config(VERSION_FILE))
237 else: 220 else:
238 self.Editor(self.Config(VERSION_FILE)) 221 self.Editor(self.Config(VERSION_FILE))
239 self.ReadAndPersistVersion("new_") 222 self.ReadAndPersistVersion("new_")
240 223
241 224
242 class CommitLocal(Step): 225 class CommitLocal(Step):
243 MESSAGE = "Commit to local branch." 226 MESSAGE = "Commit to local branch."
244 227
245 def RunStep(self): 228 def RunStep(self):
246 if self.Git("commit -a -F \"%s\"" % self.Config(COMMITMSG_FILE)) is None: 229 if self.Git("commit -a -F \"%s\"" % self.Config(COMMITMSG_FILE)) is None:
247 self.Die("'git commit -a' failed.") 230 self.Die("'git commit -a' failed.")
248 231
249 232
250 class CommitRepository(Step): 233 class CommitRepository(Step):
251 MESSAGE = "Commit to the repository." 234 MESSAGE = "Commit to the repository."
252 235
253 def RunStep(self): 236 def RunStep(self):
254 self.RestoreIfUnset("merge_to_branch")
255 if self.Git("checkout %s" % self.Config(BRANCHNAME)) is None: 237 if self.Git("checkout %s" % self.Config(BRANCHNAME)) is None:
256 self.Die("Cannot ensure that the current branch is %s" 238 self.Die("Cannot ensure that the current branch is %s"
257 % self.Config(BRANCHNAME)) 239 % self.Config(BRANCHNAME))
258 self.WaitForLGTM() 240 self.WaitForLGTM()
259 if self.Git("cl presubmit", "PRESUBMIT_TREE_CHECK=\"skip\"") is None: 241 if self.Git("cl presubmit", "PRESUBMIT_TREE_CHECK=\"skip\"") is None:
260 self.Die("Presubmit failed.") 242 self.Die("Presubmit failed.")
261 243
262 if self.Git("cl dcommit -f --bypass-hooks", 244 if self.Git("cl dcommit -f --bypass-hooks",
263 retry_on=lambda x: x is None) is None: 245 retry_on=lambda x: x is None) is None:
264 self.Die("Failed to commit to %s" % self._status["merge_to_branch"]) 246 self.Die("Failed to commit to %s" % self._status["merge_to_branch"])
265 247
266 248
267 class PrepareSVN(Step): 249 class PrepareSVN(Step):
268 MESSAGE = "Determine svn commit revision." 250 MESSAGE = "Determine svn commit revision."
269 251
270 def RunStep(self): 252 def RunStep(self):
271 if self._options.revert_bleeding_edge: 253 if self._options.revert_bleeding_edge:
272 return 254 return
273 self.RestoreIfUnset("new_commit_msg")
274 self.RestoreIfUnset("merge_to_branch")
275 if self.Git("svn fetch") is None: 255 if self.Git("svn fetch") is None:
276 self.Die("'git svn fetch' failed.") 256 self.Die("'git svn fetch' failed.")
277 args = ("log -1 --format=%%H --grep=\"%s\" svn/%s" 257 args = ("log -1 --format=%%H --grep=\"%s\" svn/%s"
278 % (self._state["new_commit_msg"], self._state["merge_to_branch"])) 258 % (self["new_commit_msg"], self["merge_to_branch"]))
279 commit_hash = self.Git(args).strip() 259 commit_hash = self.Git(args).strip()
280 if not commit_hash: 260 if not commit_hash:
281 self.Die("Unable to map git commit to svn revision.") 261 self.Die("Unable to map git commit to svn revision.")
282 svn_revision = self.Git("svn find-rev %s" % commit_hash).strip() 262 self["svn_revision"] = self.Git(
283 print "subversion revision number is r%s" % svn_revision 263 "svn find-rev %s" % commit_hash).strip()
284 self.Persist("svn_revision", svn_revision) 264 print "subversion revision number is r%s" % self["svn_revision"]
285 265
286 266
287 class TagRevision(Step): 267 class TagRevision(Step):
288 MESSAGE = "Create the tag." 268 MESSAGE = "Create the tag."
289 269
290 def RunStep(self): 270 def RunStep(self):
291 if self._options.revert_bleeding_edge: 271 if self._options.revert_bleeding_edge:
292 return 272 return
293 self.RestoreVersionIfUnset("new_") 273 self["version"] = "%s.%s.%s.%s" % (self["new_major"],
294 self.RestoreIfUnset("svn_revision") 274 self["new_minor"],
295 self.RestoreIfUnset("merge_to_branch") 275 self["new_build"],
296 ver = "%s.%s.%s.%s" % (self._state["new_major"], 276 self["new_patch"])
297 self._state["new_minor"], 277 print "Creating tag svn/tags/%s" % self["version"]
298 self._state["new_build"], 278 if self["merge_to_branch"] == "trunk":
299 self._state["new_patch"]) 279 self["to_url"] = "trunk"
300 print "Creating tag svn/tags/%s" % ver
301 if self._state["merge_to_branch"] == "trunk":
302 to_url = "trunk"
303 else: 280 else:
304 to_url = "branches/%s" % self._state["merge_to_branch"] 281 self["to_url"] = "branches/%s" % self["merge_to_branch"]
305 self.SVN("copy -r %s https://v8.googlecode.com/svn/%s " 282 self.SVN("copy -r %s https://v8.googlecode.com/svn/%s "
306 "https://v8.googlecode.com/svn/tags/%s -m " 283 "https://v8.googlecode.com/svn/tags/%s -m "
307 "\"Tagging version %s\"" 284 "\"Tagging version %s\""
308 % (self._state["svn_revision"], to_url, ver, ver)) 285 % (self["svn_revision"], self["to_url"],
309 self.Persist("to_url", to_url) 286 self["version"], self["version"]))
310 287
311 288
312 class CleanUp(Step): 289 class CleanUp(Step):
313 MESSAGE = "Cleanup." 290 MESSAGE = "Cleanup."
314 291
315 def RunStep(self): 292 def RunStep(self):
316 self.RestoreIfUnset("svn_revision")
317 self.RestoreIfUnset("to_url")
318 self.RestoreIfUnset("revision_list")
319 self.RestoreVersionIfUnset("new_")
320 ver = "%s.%s.%s.%s" % (self._state["new_major"],
321 self._state["new_minor"],
322 self._state["new_build"],
323 self._state["new_patch"])
324 self.CommonCleanup() 293 self.CommonCleanup()
325 if not self._options.revert_bleeding_edge: 294 if not self._options.revert_bleeding_edge:
326 print "*** SUMMARY ***" 295 print "*** SUMMARY ***"
327 print "version: %s" % ver 296 print "version: %s" % self["version"]
328 print "branch: %s" % self._state["to_url"] 297 print "branch: %s" % self["to_url"]
329 print "svn revision: %s" % self._state["svn_revision"] 298 print "svn revision: %s" % self["svn_revision"]
330 if self._state["revision_list"]: 299 if self["revision_list"]:
331 print "patches: %s" % self._state["revision_list"] 300 print "patches: %s" % self["revision_list"]
332 301
333 302
334 def RunMergeToBranch(config, 303 def RunMergeToBranch(config,
335 options, 304 options,
336 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): 305 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER):
337 step_classes = [ 306 step_classes = [
338 Preparation, 307 Preparation,
339 CreateBranch, 308 CreateBranch,
340 SearchArchitecturePorts, 309 SearchArchitecturePorts,
341 FindGitRevisions, 310 FindGitRevisions,
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 def Main(): 366 def Main():
398 parser = BuildOptions() 367 parser = BuildOptions()
399 (options, args) = parser.parse_args() 368 (options, args) = parser.parse_args()
400 if not ProcessOptions(options, args): 369 if not ProcessOptions(options, args):
401 parser.print_help() 370 parser.print_help()
402 return 1 371 return 1
403 RunMergeToBranch(CONFIG, MergeToBranchOptions(options, args)) 372 RunMergeToBranch(CONFIG, MergeToBranchOptions(options, args))
404 373
405 if __name__ == "__main__": 374 if __name__ == "__main__":
406 sys.exit(Main()) 375 sys.exit(Main())
OLDNEW
« no previous file with comments | « tools/push-to-trunk/common_includes.py ('k') | tools/push-to-trunk/push_to_trunk.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698