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

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

Issue 178223011: Reset trunk to 3.24.35.4 (Closed) Base URL: https://v8.googlecode.com/svn/trunk
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/merge_to_branch.py ('k') | tools/push-to-trunk/test_scripts.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 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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 TEMP_BRANCH: "prepare-push-temporary-branch-created-by-script", 44 TEMP_BRANCH: "prepare-push-temporary-branch-created-by-script",
45 DOT_GIT_LOCATION: ".git", 45 DOT_GIT_LOCATION: ".git",
46 VERSION_FILE: "src/version.cc", 46 VERSION_FILE: "src/version.cc",
47 CHANGELOG_FILE: "ChangeLog", 47 CHANGELOG_FILE: "ChangeLog",
48 CHANGELOG_ENTRY_FILE: "/tmp/v8-push-to-trunk-tempfile-changelog-entry", 48 CHANGELOG_ENTRY_FILE: "/tmp/v8-push-to-trunk-tempfile-changelog-entry",
49 PATCH_FILE: "/tmp/v8-push-to-trunk-tempfile-patch-file", 49 PATCH_FILE: "/tmp/v8-push-to-trunk-tempfile-patch-file",
50 COMMITMSG_FILE: "/tmp/v8-push-to-trunk-tempfile-commitmsg", 50 COMMITMSG_FILE: "/tmp/v8-push-to-trunk-tempfile-commitmsg",
51 DEPS_FILE: "DEPS", 51 DEPS_FILE: "DEPS",
52 } 52 }
53 53
54 PUSH_MESSAGE_SUFFIX = " (based on bleeding_edge revision r%d)"
55 PUSH_MESSAGE_RE = re.compile(r".* \(based on bleeding_edge revision r(\d+)\)$")
56
57 54
58 class PushToTrunkOptions(CommonOptions): 55 class PushToTrunkOptions(CommonOptions):
59 @staticmethod 56 @staticmethod
60 def MakeForcedOptions(author, reviewer, chrome_path): 57 def MakeForcedOptions(reviewer, chrome_path):
61 """Convenience wrapper.""" 58 """Convenience wrapper."""
62 class Options(object): 59 class Options(object):
63 pass 60 pass
64 options = Options() 61 options = Options()
65 options.s = 0 62 options.s = 0
66 options.l = None 63 options.l = None
67 options.b = None
68 options.f = True 64 options.f = True
69 options.m = False 65 options.m = False
66 options.r = reviewer
70 options.c = chrome_path 67 options.c = chrome_path
71 options.reviewer = reviewer
72 options.a = author
73 return PushToTrunkOptions(options) 68 return PushToTrunkOptions(options)
74 69
75 def __init__(self, options): 70 def __init__(self, options):
76 super(PushToTrunkOptions, self).__init__(options, options.m) 71 super(PushToTrunkOptions, self).__init__(options, options.m)
77 self.requires_editor = not options.f 72 self.requires_editor = not options.f
78 self.wait_for_lgtm = not options.f 73 self.wait_for_lgtm = not options.f
79 self.tbr_commit = not options.m 74 self.tbr_commit = not options.m
80 self.l = options.l 75 self.l = options.l
81 self.reviewer = options.reviewer 76 self.r = options.r
82 self.c = options.c 77 self.c = options.c
83 self.b = getattr(options, 'b', None)
84 self.author = getattr(options, 'a', None)
85
86 78
87 class Preparation(Step): 79 class Preparation(Step):
88 MESSAGE = "Preparation." 80 MESSAGE = "Preparation."
89 81
90 def RunStep(self): 82 def RunStep(self):
91 self.InitialEnvironmentChecks() 83 self.InitialEnvironmentChecks()
92 self.CommonPrepare() 84 self.CommonPrepare()
93 self.PrepareBranch() 85 self.PrepareBranch()
94 self.DeleteBranch(self.Config(TRUNKBRANCH)) 86 self.DeleteBranch(self.Config(TRUNKBRANCH))
95 87
96 88
97 class FreshBranch(Step): 89 class FreshBranch(Step):
98 MESSAGE = "Create a fresh branch." 90 MESSAGE = "Create a fresh branch."
99 91
100 def RunStep(self): 92 def RunStep(self):
101 self.GitCreateBranch(self.Config(BRANCHNAME), "svn/bleeding_edge") 93 args = "checkout -b %s svn/bleeding_edge" % self.Config(BRANCHNAME)
94 if self.Git(args) is None:
95 self.Die("Creating branch %s failed." % self.Config(BRANCHNAME))
102 96
103 97
104 class DetectLastPush(Step): 98 class DetectLastPush(Step):
105 MESSAGE = "Detect commit ID of last push to trunk." 99 MESSAGE = "Detect commit ID of last push to trunk."
106 100
107 def RunStep(self): 101 def RunStep(self):
108 last_push = self._options.l or self.FindLastTrunkPush() 102 last_push = (self._options.l or
103 self.Git("log -1 --format=%H ChangeLog").strip())
109 while True: 104 while True:
110 # Print assumed commit, circumventing git's pager. 105 # Print assumed commit, circumventing git's pager.
111 print self.GitLog(n=1, git_hash=last_push) 106 print self.Git("log -1 %s" % last_push)
112 if self.Confirm("Is the commit printed above the last push to trunk?"): 107 if self.Confirm("Is the commit printed above the last push to trunk?"):
113 break 108 break
114 last_push = self.FindLastTrunkPush(parent_hash=last_push) 109 args = "log -1 --format=%H %s^ ChangeLog" % last_push
115 110 last_push = self.Git(args).strip()
116 if self._options.b: 111 self.Persist("last_push", last_push)
117 # Read the bleeding edge revision of the last push from a command-line 112 self._state["last_push"] = last_push
118 # option.
119 last_push_bleeding_edge = self._options.b
120 else:
121 # Retrieve the bleeding edge revision of the last push from the text in
122 # the push commit message.
123 last_push_title = self.GitLog(n=1, format="%s", git_hash=last_push)
124 last_push_be_svn = PUSH_MESSAGE_RE.match(last_push_title).group(1)
125 if not last_push_be_svn:
126 self.Die("Could not retrieve bleeding edge revision for trunk push %s"
127 % last_push)
128 last_push_bleeding_edge = self.GitSVNFindGitHash(last_push_be_svn)
129 if not last_push_bleeding_edge:
130 self.Die("Could not retrieve bleeding edge git hash for trunk push %s"
131 % last_push)
132
133 # TODO(machenbach): last_push_trunk points to the svn revision on trunk.
134 # It is not used yet but we'll need it for retrieving the current version.
135 self["last_push_trunk"] = last_push
136 # TODO(machenbach): This currently points to the prepare push revision that
137 # will be deprecated soon. After the deprecation it will point to the last
138 # bleeding_edge revision that went into the last push.
139 self["last_push_bleeding_edge"] = last_push_bleeding_edge
140 113
141 114
142 class PrepareChangeLog(Step): 115 class PrepareChangeLog(Step):
143 MESSAGE = "Prepare raw ChangeLog entry." 116 MESSAGE = "Prepare raw ChangeLog entry."
144 117
145 def Reload(self, body): 118 def Reload(self, body):
146 """Attempts to reload the commit message from rietveld in order to allow 119 """Attempts to reload the commit message from rietveld in order to allow
147 late changes to the LOG flag. Note: This is brittle to future changes of 120 late changes to the LOG flag. Note: This is brittle to future changes of
148 the web page name or structure. 121 the web page name or structure.
149 """ 122 """
150 match = re.search(r"^Review URL: https://codereview\.chromium\.org/(\d+)$", 123 match = re.search(r"^Review URL: https://codereview\.chromium\.org/(\d+)$",
151 body, flags=re.M) 124 body, flags=re.M)
152 if match: 125 if match:
153 cl_url = ("https://codereview.chromium.org/%s/description" 126 cl_url = "https://codereview.chromium.org/%s/description" % match.group(1)
154 % match.group(1))
155 try: 127 try:
156 # Fetch from Rietveld but only retry once with one second delay since 128 # Fetch from Rietveld but only retry once with one second delay since
157 # there might be many revisions. 129 # there might be many revisions.
158 body = self.ReadURL(cl_url, wait_plan=[1]) 130 body = self.ReadURL(cl_url, wait_plan=[1])
159 except urllib2.URLError: 131 except urllib2.URLError:
160 pass 132 pass
161 return body 133 return body
162 134
163 def RunStep(self): 135 def RunStep(self):
136 self.RestoreIfUnset("last_push")
137
164 # These version numbers are used again later for the trunk commit. 138 # These version numbers are used again later for the trunk commit.
165 self.ReadAndPersistVersion() 139 self.ReadAndPersistVersion()
166 self["date"] = self.GetDate() 140
167 self["version"] = "%s.%s.%s" % (self["major"], 141 date = self.GetDate()
168 self["minor"], 142 self.Persist("date", date)
169 self["build"]) 143 output = "%s: Version %s.%s.%s\n\n" % (date,
170 output = "%s: Version %s\n\n" % (self["date"], 144 self._state["major"],
171 self["version"]) 145 self._state["minor"],
146 self._state["build"])
172 TextToFile(output, self.Config(CHANGELOG_ENTRY_FILE)) 147 TextToFile(output, self.Config(CHANGELOG_ENTRY_FILE))
173 commits = self.GitLog(format="%H", 148
174 git_hash="%s..HEAD" % self["last_push_bleeding_edge"]) 149 args = "log %s..HEAD --format=%%H" % self._state["last_push"]
150 commits = self.Git(args).strip()
175 151
176 # Cache raw commit messages. 152 # Cache raw commit messages.
177 commit_messages = [ 153 commit_messages = [
178 [ 154 [
179 self.GitLog(n=1, format="%s", git_hash=commit), 155 self.Git("log -1 %s --format=\"%%s\"" % commit),
180 self.Reload(self.GitLog(n=1, format="%B", git_hash=commit)), 156 self.Reload(self.Git("log -1 %s --format=\"%%B\"" % commit)),
181 self.GitLog(n=1, format="%an", git_hash=commit), 157 self.Git("log -1 %s --format=\"%%an\"" % commit),
182 ] for commit in commits.splitlines() 158 ] for commit in commits.splitlines()
183 ] 159 ]
184 160
185 # Auto-format commit messages. 161 # Auto-format commit messages.
186 body = MakeChangeLogBody(commit_messages, auto_format=True) 162 body = MakeChangeLogBody(commit_messages, auto_format=True)
187 AppendToFile(body, self.Config(CHANGELOG_ENTRY_FILE)) 163 AppendToFile(body, self.Config(CHANGELOG_ENTRY_FILE))
188 164
189 msg = (" Performance and stability improvements on all platforms." 165 msg = (" Performance and stability improvements on all platforms."
190 "\n#\n# The change log above is auto-generated. Please review if " 166 "\n#\n# The change log above is auto-generated. Please review if "
191 "all relevant\n# commit messages from the list below are included." 167 "all relevant\n# commit messages from the list below are included."
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 200
225 AppendToFile(FileToText(self.Config(CHANGELOG_FILE)), new_changelog) 201 AppendToFile(FileToText(self.Config(CHANGELOG_FILE)), new_changelog)
226 TextToFile(FileToText(new_changelog), self.Config(CHANGELOG_FILE)) 202 TextToFile(FileToText(new_changelog), self.Config(CHANGELOG_FILE))
227 os.remove(new_changelog) 203 os.remove(new_changelog)
228 204
229 205
230 class IncrementVersion(Step): 206 class IncrementVersion(Step):
231 MESSAGE = "Increment version number." 207 MESSAGE = "Increment version number."
232 208
233 def RunStep(self): 209 def RunStep(self):
234 new_build = str(int(self["build"]) + 1) 210 self.RestoreIfUnset("build")
211 new_build = str(int(self._state["build"]) + 1)
235 212
236 if self.Confirm(("Automatically increment BUILD_NUMBER? (Saying 'n' will " 213 if self.Confirm(("Automatically increment BUILD_NUMBER? (Saying 'n' will "
237 "fire up your EDITOR on %s so you can make arbitrary " 214 "fire up your EDITOR on %s so you can make arbitrary "
238 "changes. When you're done, save the file and exit your " 215 "changes. When you're done, save the file and exit your "
239 "EDITOR.)" % self.Config(VERSION_FILE))): 216 "EDITOR.)" % self.Config(VERSION_FILE))):
240 text = FileToText(self.Config(VERSION_FILE)) 217 text = FileToText(self.Config(VERSION_FILE))
241 text = MSub(r"(?<=#define BUILD_NUMBER)(?P<space>\s+)\d*$", 218 text = MSub(r"(?<=#define BUILD_NUMBER)(?P<space>\s+)\d*$",
242 r"\g<space>%s" % new_build, 219 r"\g<space>%s" % new_build,
243 text) 220 text)
244 TextToFile(text, self.Config(VERSION_FILE)) 221 TextToFile(text, self.Config(VERSION_FILE))
245 else: 222 else:
246 self.Editor(self.Config(VERSION_FILE)) 223 self.Editor(self.Config(VERSION_FILE))
247 224
248 self.ReadAndPersistVersion("new_") 225 self.ReadAndPersistVersion("new_")
249 226
250 227
251 class CommitLocal(Step): 228 class CommitLocal(Step):
252 MESSAGE = "Commit to local branch." 229 MESSAGE = "Commit to local branch."
253 230
254 def RunStep(self): 231 def RunStep(self):
255 self["prep_commit_msg"] = ("Prepare push to trunk. " 232 self.RestoreVersionIfUnset("new_")
256 "Now working on version %s.%s.%s." % (self["new_major"], 233 prep_commit_msg = ("Prepare push to trunk. "
257 self["new_minor"], 234 "Now working on version %s.%s.%s." % (self._state["new_major"],
258 self["new_build"])) 235 self._state["new_minor"],
236 self._state["new_build"]))
237 self.Persist("prep_commit_msg", prep_commit_msg)
259 238
260 # Include optional TBR only in the git command. The persisted commit 239 # Include optional TBR only in the git command. The persisted commit
261 # message is used for finding the commit again later. 240 # message is used for finding the commit again later.
262 if self._options.tbr_commit: 241 review = "\n\nTBR=%s" % self._options.r if self._options.tbr_commit else ""
263 message = "%s\n\nTBR=%s" % (self["prep_commit_msg"], 242 if self.Git("commit -a -m \"%s%s\"" % (prep_commit_msg, review)) is None:
264 self._options.reviewer) 243 self.Die("'git commit -a' failed.")
265 else:
266 message = "%s" % self["prep_commit_msg"]
267 self.GitCommit(message)
268 244
269 245
270 class CommitRepository(Step): 246 class CommitRepository(Step):
271 MESSAGE = "Commit to the repository." 247 MESSAGE = "Commit to the repository."
272 248
273 def RunStep(self): 249 def RunStep(self):
274 self.WaitForLGTM() 250 self.WaitForLGTM()
275 # Re-read the ChangeLog entry (to pick up possible changes). 251 # Re-read the ChangeLog entry (to pick up possible changes).
276 # FIXME(machenbach): This was hanging once with a broken pipe. 252 # FIXME(machenbach): This was hanging once with a broken pipe.
277 TextToFile(GetLastChangeLogEntries(self.Config(CHANGELOG_FILE)), 253 TextToFile(GetLastChangeLogEntries(self.Config(CHANGELOG_FILE)),
278 self.Config(CHANGELOG_ENTRY_FILE)) 254 self.Config(CHANGELOG_ENTRY_FILE))
279 255
280 self.GitPresubmit() 256 if self.Git("cl presubmit", "PRESUBMIT_TREE_CHECK=\"skip\"") is None:
281 self.GitDCommit() 257 self.Die("'git cl presubmit' failed, please try again.")
258
259 if self.Git("cl dcommit -f --bypass-hooks",
260 retry_on=lambda x: x is None) is None:
261 self.Die("'git cl dcommit' failed, please try again.")
282 262
283 263
284 class StragglerCommits(Step): 264 class StragglerCommits(Step):
285 MESSAGE = ("Fetch straggler commits that sneaked in since this script was " 265 MESSAGE = ("Fetch straggler commits that sneaked in since this script was "
286 "started.") 266 "started.")
287 267
288 def RunStep(self): 268 def RunStep(self):
289 self.GitSVNFetch() 269 if self.Git("svn fetch") is None:
290 self.GitCheckout("svn/bleeding_edge") 270 self.Die("'git svn fetch' failed.")
291 self["prepare_commit_hash"] = self.GitLog(n=1, format="%H", 271 self.Git("checkout svn/bleeding_edge")
292 grep=self["prep_commit_msg"]) 272 self.RestoreIfUnset("prep_commit_msg")
273 args = "log -1 --format=%%H --grep=\"%s\"" % self._state["prep_commit_msg"]
274 prepare_commit_hash = self.Git(args).strip()
275 self.Persist("prepare_commit_hash", prepare_commit_hash)
293 276
294 277
295 class SquashCommits(Step): 278 class SquashCommits(Step):
296 MESSAGE = "Squash commits into one." 279 MESSAGE = "Squash commits into one."
297 280
298 def RunStep(self): 281 def RunStep(self):
299 # Instead of relying on "git rebase -i", we'll just create a diff, because 282 # Instead of relying on "git rebase -i", we'll just create a diff, because
300 # that's easier to automate. 283 # that's easier to automate.
301 TextToFile(self.GitDiff("svn/trunk", self["prepare_commit_hash"]), 284 self.RestoreIfUnset("prepare_commit_hash")
302 self.Config(PATCH_FILE)) 285 args = "diff svn/trunk %s" % self._state["prepare_commit_hash"]
286 TextToFile(self.Git(args), self.Config(PATCH_FILE))
303 287
304 # Convert the ChangeLog entry to commit message format. 288 # Convert the ChangeLog entry to commit message format.
289 self.RestoreIfUnset("date")
305 text = FileToText(self.Config(CHANGELOG_ENTRY_FILE)) 290 text = FileToText(self.Config(CHANGELOG_ENTRY_FILE))
306 291
307 # Remove date and trailing white space. 292 # Remove date and trailing white space.
308 text = re.sub(r"^%s: " % self["date"], "", text.rstrip()) 293 text = re.sub(r"^%s: " % self._state["date"], "", text.rstrip())
309 294
310 # Retrieve svn revision for showing the used bleeding edge revision in the 295 # Retrieve svn revision for showing the used bleeding edge revision in the
311 # commit message. 296 # commit message.
312 self["svn_revision"] = self.GitSVNFindSVNRev(self["prepare_commit_hash"]) 297 args = "svn find-rev %s" % self._state["prepare_commit_hash"]
313 suffix = PUSH_MESSAGE_SUFFIX % int(self["svn_revision"]) 298 svn_revision = self.Git(args).strip()
314 text = MSub(r"^(Version \d+\.\d+\.\d+)$", "\\1%s" % suffix, text) 299 self.Persist("svn_revision", svn_revision)
300 text = MSub(r"^(Version \d+\.\d+\.\d+)$",
301 "\\1 (based on bleeding_edge revision r%s)" % svn_revision,
302 text)
315 303
316 # Remove indentation and merge paragraphs into single long lines, keeping 304 # Remove indentation and merge paragraphs into single long lines, keeping
317 # empty lines between them. 305 # empty lines between them.
318 def SplitMapJoin(split_text, fun, join_text): 306 def SplitMapJoin(split_text, fun, join_text):
319 return lambda text: join_text.join(map(fun, text.split(split_text))) 307 return lambda text: join_text.join(map(fun, text.split(split_text)))
320 strip = lambda line: line.strip() 308 strip = lambda line: line.strip()
321 text = SplitMapJoin("\n\n", SplitMapJoin("\n", strip, " "), "\n\n")(text) 309 text = SplitMapJoin("\n\n", SplitMapJoin("\n", strip, " "), "\n\n")(text)
322 310
323 if not text: 311 if not text:
324 self.Die("Commit message editing failed.") 312 self.Die("Commit message editing failed.")
325 TextToFile(text, self.Config(COMMITMSG_FILE)) 313 TextToFile(text, self.Config(COMMITMSG_FILE))
326 os.remove(self.Config(CHANGELOG_ENTRY_FILE)) 314 os.remove(self.Config(CHANGELOG_ENTRY_FILE))
327 315
328 316
329 class NewBranch(Step): 317 class NewBranch(Step):
330 MESSAGE = "Create a new branch from trunk." 318 MESSAGE = "Create a new branch from trunk."
331 319
332 def RunStep(self): 320 def RunStep(self):
333 self.GitCreateBranch(self.Config(TRUNKBRANCH), "svn/trunk") 321 if self.Git("checkout -b %s svn/trunk" % self.Config(TRUNKBRANCH)) is None:
322 self.Die("Checking out a new branch '%s' failed." %
323 self.Config(TRUNKBRANCH))
334 324
335 325
336 class ApplyChanges(Step): 326 class ApplyChanges(Step):
337 MESSAGE = "Apply squashed changes." 327 MESSAGE = "Apply squashed changes."
338 328
339 def RunStep(self): 329 def RunStep(self):
340 self.ApplyPatch(self.Config(PATCH_FILE)) 330 self.ApplyPatch(self.Config(PATCH_FILE))
341 Command("rm", "-f %s*" % self.Config(PATCH_FILE)) 331 Command("rm", "-f %s*" % self.Config(PATCH_FILE))
342 332
343 333
344 class SetVersion(Step): 334 class SetVersion(Step):
345 MESSAGE = "Set correct version for trunk." 335 MESSAGE = "Set correct version for trunk."
346 336
347 def RunStep(self): 337 def RunStep(self):
338 self.RestoreVersionIfUnset()
348 output = "" 339 output = ""
349 for line in FileToText(self.Config(VERSION_FILE)).splitlines(): 340 for line in FileToText(self.Config(VERSION_FILE)).splitlines():
350 if line.startswith("#define MAJOR_VERSION"): 341 if line.startswith("#define MAJOR_VERSION"):
351 line = re.sub("\d+$", self["major"], line) 342 line = re.sub("\d+$", self._state["major"], line)
352 elif line.startswith("#define MINOR_VERSION"): 343 elif line.startswith("#define MINOR_VERSION"):
353 line = re.sub("\d+$", self["minor"], line) 344 line = re.sub("\d+$", self._state["minor"], line)
354 elif line.startswith("#define BUILD_NUMBER"): 345 elif line.startswith("#define BUILD_NUMBER"):
355 line = re.sub("\d+$", self["build"], line) 346 line = re.sub("\d+$", self._state["build"], line)
356 elif line.startswith("#define PATCH_LEVEL"): 347 elif line.startswith("#define PATCH_LEVEL"):
357 line = re.sub("\d+$", "0", line) 348 line = re.sub("\d+$", "0", line)
358 elif line.startswith("#define IS_CANDIDATE_VERSION"): 349 elif line.startswith("#define IS_CANDIDATE_VERSION"):
359 line = re.sub("\d+$", "0", line) 350 line = re.sub("\d+$", "0", line)
360 output += "%s\n" % line 351 output += "%s\n" % line
361 TextToFile(output, self.Config(VERSION_FILE)) 352 TextToFile(output, self.Config(VERSION_FILE))
362 353
363 354
364 class CommitTrunk(Step): 355 class CommitTrunk(Step):
365 MESSAGE = "Commit to local trunk branch." 356 MESSAGE = "Commit to local trunk branch."
366 357
367 def RunStep(self): 358 def RunStep(self):
368 self.GitAdd(self.Config(VERSION_FILE)) 359 self.Git("add \"%s\"" % self.Config(VERSION_FILE))
369 self.GitCommit(file_name = self.Config(COMMITMSG_FILE)) 360 if self.Git("commit -F \"%s\"" % self.Config(COMMITMSG_FILE)) is None:
361 self.Die("'git commit' failed.")
370 Command("rm", "-f %s*" % self.Config(COMMITMSG_FILE)) 362 Command("rm", "-f %s*" % self.Config(COMMITMSG_FILE))
371 363
372 364
373 class SanityCheck(Step): 365 class SanityCheck(Step):
374 MESSAGE = "Sanity check." 366 MESSAGE = "Sanity check."
375 367
376 def RunStep(self): 368 def RunStep(self):
377 if not self.Confirm("Please check if your local checkout is sane: Inspect " 369 if not self.Confirm("Please check if your local checkout is sane: Inspect "
378 "%s, compile, run tests. Do you want to commit this new trunk " 370 "%s, compile, run tests. Do you want to commit this new trunk "
379 "revision to the repository?" % self.Config(VERSION_FILE)): 371 "revision to the repository?" % self.Config(VERSION_FILE)):
380 self.Die("Execution canceled.") 372 self.Die("Execution canceled.")
381 373
382 374
383 class CommitSVN(Step): 375 class CommitSVN(Step):
384 MESSAGE = "Commit to SVN." 376 MESSAGE = "Commit to SVN."
385 377
386 def RunStep(self): 378 def RunStep(self):
387 result = self.GitSVNDCommit() 379 result = self.Git("svn dcommit 2>&1", retry_on=lambda x: x is None)
388 if not result: 380 if not result:
389 self.Die("'git svn dcommit' failed.") 381 self.Die("'git svn dcommit' failed.")
390 result = filter(lambda x: re.search(r"^Committed r[0-9]+", x), 382 result = filter(lambda x: re.search(r"^Committed r[0-9]+", x),
391 result.splitlines()) 383 result.splitlines())
392 if len(result) > 0: 384 if len(result) > 0:
393 self["trunk_revision"] = re.sub(r"^Committed r([0-9]+)", r"\1",result[0]) 385 trunk_revision = re.sub(r"^Committed r([0-9]+)", r"\1", result[0])
394 386
395 # Sometimes grepping for the revision fails. No idea why. If you figure 387 # Sometimes grepping for the revision fails. No idea why. If you figure
396 # out why it is flaky, please do fix it properly. 388 # out why it is flaky, please do fix it properly.
397 if not self["trunk_revision"]: 389 if not trunk_revision:
398 print("Sorry, grepping for the SVN revision failed. Please look for it " 390 print("Sorry, grepping for the SVN revision failed. Please look for it "
399 "in the last command's output above and provide it manually (just " 391 "in the last command's output above and provide it manually (just "
400 "the number, without the leading \"r\").") 392 "the number, without the leading \"r\").")
401 self.DieNoManualMode("Can't prompt in forced mode.") 393 self.DieNoManualMode("Can't prompt in forced mode.")
402 while not self["trunk_revision"]: 394 while not trunk_revision:
403 print "> ", 395 print "> ",
404 self["trunk_revision"] = self.ReadLine() 396 trunk_revision = self.ReadLine()
397 self.Persist("trunk_revision", trunk_revision)
405 398
406 399
407 class TagRevision(Step): 400 class TagRevision(Step):
408 MESSAGE = "Tag the new revision." 401 MESSAGE = "Tag the new revision."
409 402
410 def RunStep(self): 403 def RunStep(self):
411 self.GitSVNTag(self["version"]) 404 self.RestoreVersionIfUnset()
405 ver = "%s.%s.%s" % (self._state["major"],
406 self._state["minor"],
407 self._state["build"])
408 if self.Git("svn tag %s -m \"Tagging version %s\"" % (ver, ver),
409 retry_on=lambda x: x is None) is None:
410 self.Die("'git svn tag' failed.")
412 411
413 412
414 class CheckChromium(Step): 413 class CheckChromium(Step):
415 MESSAGE = "Ask for chromium checkout." 414 MESSAGE = "Ask for chromium checkout."
416 415
417 def Run(self): 416 def Run(self):
418 self["chrome_path"] = self._options.c 417 chrome_path = self._options.c
419 if not self["chrome_path"]: 418 if not chrome_path:
420 self.DieNoManualMode("Please specify the path to a Chromium checkout in " 419 self.DieNoManualMode("Please specify the path to a Chromium checkout in "
421 "forced mode.") 420 "forced mode.")
422 print ("Do you have a \"NewGit\" Chromium checkout and want " 421 print ("Do you have a \"NewGit\" Chromium checkout and want "
423 "this script to automate creation of the roll CL? If yes, enter the " 422 "this script to automate creation of the roll CL? If yes, enter the "
424 "path to (and including) the \"src\" directory here, otherwise just " 423 "path to (and including) the \"src\" directory here, otherwise just "
425 "press <Return>: "), 424 "press <Return>: "),
426 self["chrome_path"] = self.ReadLine() 425 chrome_path = self.ReadLine()
426 self.Persist("chrome_path", chrome_path)
427 427
428 428
429 class SwitchChromium(Step): 429 class SwitchChromium(Step):
430 MESSAGE = "Switch to Chromium checkout." 430 MESSAGE = "Switch to Chromium checkout."
431 REQUIRES = "chrome_path" 431 REQUIRES = "chrome_path"
432 432
433 def RunStep(self): 433 def RunStep(self):
434 self["v8_path"] = os.getcwd() 434 v8_path = os.getcwd()
435 os.chdir(self["chrome_path"]) 435 self.Persist("v8_path", v8_path)
436 os.chdir(self._state["chrome_path"])
436 self.InitialEnvironmentChecks() 437 self.InitialEnvironmentChecks()
437 # Check for a clean workdir. 438 # Check for a clean workdir.
438 if not self.GitIsWorkdirClean(): 439 if self.Git("status -s -uno").strip() != "":
439 self.Die("Workspace is not clean. Please commit or undo your changes.") 440 self.Die("Workspace is not clean. Please commit or undo your changes.")
440 # Assert that the DEPS file is there. 441 # Assert that the DEPS file is there.
441 if not os.path.exists(self.Config(DEPS_FILE)): 442 if not os.path.exists(self.Config(DEPS_FILE)):
442 self.Die("DEPS file not present.") 443 self.Die("DEPS file not present.")
443 444
444 445
445 class UpdateChromiumCheckout(Step): 446 class UpdateChromiumCheckout(Step):
446 MESSAGE = "Update the checkout and create a new branch." 447 MESSAGE = "Update the checkout and create a new branch."
447 REQUIRES = "chrome_path" 448 REQUIRES = "chrome_path"
448 449
449 def RunStep(self): 450 def RunStep(self):
450 os.chdir(self["chrome_path"]) 451 os.chdir(self._state["chrome_path"])
451 self.GitCheckout("master") 452 if self.Git("checkout master") is None:
452 self.GitPull() 453 self.Die("'git checkout master' failed.")
453 self.GitCreateBranch("v8-roll-%s" % self["trunk_revision"]) 454 if self.Git("pull") is None:
455 self.Die("'git pull' failed, please try again.")
456
457 self.RestoreIfUnset("trunk_revision")
458 args = "checkout -b v8-roll-%s" % self._state["trunk_revision"]
459 if self.Git(args) is None:
460 self.Die("Failed to checkout a new branch.")
454 461
455 462
456 class UploadCL(Step): 463 class UploadCL(Step):
457 MESSAGE = "Create and upload CL." 464 MESSAGE = "Create and upload CL."
458 REQUIRES = "chrome_path" 465 REQUIRES = "chrome_path"
459 466
460 def RunStep(self): 467 def RunStep(self):
461 os.chdir(self["chrome_path"]) 468 os.chdir(self._state["chrome_path"])
462 469
463 # Patch DEPS file. 470 # Patch DEPS file.
471 self.RestoreIfUnset("trunk_revision")
464 deps = FileToText(self.Config(DEPS_FILE)) 472 deps = FileToText(self.Config(DEPS_FILE))
465 deps = re.sub("(?<=\"v8_revision\": \")([0-9]+)(?=\")", 473 deps = re.sub("(?<=\"v8_revision\": \")([0-9]+)(?=\")",
466 self["trunk_revision"], 474 self._state["trunk_revision"],
467 deps) 475 deps)
468 TextToFile(deps, self.Config(DEPS_FILE)) 476 TextToFile(deps, self.Config(DEPS_FILE))
469 477
470 if self._options.reviewer: 478 self.RestoreVersionIfUnset()
471 print "Using account %s for review." % self._options.reviewer 479 ver = "%s.%s.%s" % (self._state["major"],
472 rev = self._options.reviewer 480 self._state["minor"],
481 self._state["build"])
482 if self._options.r:
483 print "Using account %s for review." % self._options.r
484 rev = self._options.r
473 else: 485 else:
474 print "Please enter the email address of a reviewer for the roll CL: ", 486 print "Please enter the email address of a reviewer for the roll CL: ",
475 self.DieNoManualMode("A reviewer must be specified in forced mode.") 487 self.DieNoManualMode("A reviewer must be specified in forced mode.")
476 rev = self.ReadLine() 488 rev = self.ReadLine()
477 suffix = PUSH_MESSAGE_SUFFIX % int(self["svn_revision"]) 489 self.RestoreIfUnset("svn_revision")
478 self.GitCommit("Update V8 to version %s%s.\n\nTBR=%s" 490 args = ("commit -am \"Update V8 to version %s "
479 % (self["version"], suffix, rev)) 491 "(based on bleeding_edge revision r%s).\n\nTBR=%s\""
480 self.GitUpload(author=self._options.author, 492 % (ver, self._state["svn_revision"], rev))
481 force=self._options.force_upload) 493 if self.Git(args) is None:
494 self.Die("'git commit' failed.")
495 force_flag = " -f" if self._options.force_upload else ""
496 if self.Git("cl upload --send-mail%s" % force_flag, pipe=False) is None:
497 self.Die("'git cl upload' failed, please try again.")
482 print "CL uploaded." 498 print "CL uploaded."
483 499
484 500
485 class SwitchV8(Step): 501 class SwitchV8(Step):
486 MESSAGE = "Returning to V8 checkout." 502 MESSAGE = "Returning to V8 checkout."
487 REQUIRES = "chrome_path" 503 REQUIRES = "chrome_path"
488 504
489 def RunStep(self): 505 def RunStep(self):
490 os.chdir(self["v8_path"]) 506 self.RestoreIfUnset("v8_path")
507 os.chdir(self._state["v8_path"])
491 508
492 509
493 class CleanUp(Step): 510 class CleanUp(Step):
494 MESSAGE = "Done!" 511 MESSAGE = "Done!"
495 512
496 def RunStep(self): 513 def RunStep(self):
497 if self["chrome_path"]: 514 self.RestoreVersionIfUnset()
515 ver = "%s.%s.%s" % (self._state["major"],
516 self._state["minor"],
517 self._state["build"])
518 self.RestoreIfUnset("trunk_revision")
519 self.RestoreIfUnset("chrome_path")
520
521 if self._state["chrome_path"]:
498 print("Congratulations, you have successfully created the trunk " 522 print("Congratulations, you have successfully created the trunk "
499 "revision %s and rolled it into Chromium. Please don't forget to " 523 "revision %s and rolled it into Chromium. Please don't forget to "
500 "update the v8rel spreadsheet:" % self["version"]) 524 "update the v8rel spreadsheet:" % ver)
501 else: 525 else:
502 print("Congratulations, you have successfully created the trunk " 526 print("Congratulations, you have successfully created the trunk "
503 "revision %s. Please don't forget to roll this new version into " 527 "revision %s. Please don't forget to roll this new version into "
504 "Chromium, and to update the v8rel spreadsheet:" 528 "Chromium, and to update the v8rel spreadsheet:" % ver)
505 % self["version"]) 529 print "%s\ttrunk\t%s" % (ver, self._state["trunk_revision"])
506 print "%s\ttrunk\t%s" % (self["version"],
507 self["trunk_revision"])
508 530
509 self.CommonCleanup() 531 self.CommonCleanup()
510 if self.Config(TRUNKBRANCH) != self["current_branch"]: 532 if self.Config(TRUNKBRANCH) != self._state["current_branch"]:
511 self.GitDeleteBranch(self.Config(TRUNKBRANCH)) 533 self.Git("branch -D %s" % self.Config(TRUNKBRANCH))
512 534
513 535
514 def RunPushToTrunk(config, 536 def RunPushToTrunk(config,
515 options, 537 options,
516 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): 538 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER):
517 step_classes = [ 539 step_classes = [
518 Preparation, 540 Preparation,
519 FreshBranch, 541 FreshBranch,
520 DetectLastPush, 542 DetectLastPush,
521 PrepareChangeLog, 543 PrepareChangeLog,
(...skipping 17 matching lines...) Expand all
539 UploadCL, 561 UploadCL,
540 SwitchV8, 562 SwitchV8,
541 CleanUp, 563 CleanUp,
542 ] 564 ]
543 565
544 RunScript(step_classes, config, options, side_effect_handler) 566 RunScript(step_classes, config, options, side_effect_handler)
545 567
546 568
547 def BuildOptions(): 569 def BuildOptions():
548 result = optparse.OptionParser() 570 result = optparse.OptionParser()
549 result.add_option("-a", "--author", dest="a",
550 help=("Specify the author email used for rietveld."))
551 result.add_option("-b", "--last-bleeding-edge", dest="b",
552 help=("Manually specify the git commit ID of the last "
553 "bleeding edge revision that was pushed to trunk. "
554 "This is used for the auto-generated ChangeLog "
555 "entry."))
556 result.add_option("-c", "--chromium", dest="c", 571 result.add_option("-c", "--chromium", dest="c",
557 help=("Specify the path to your Chromium src/ " 572 help=("Specify the path to your Chromium src/ "
558 "directory to automate the V8 roll.")) 573 "directory to automate the V8 roll."))
559 result.add_option("-f", "--force", dest="f", 574 result.add_option("-f", "--force", dest="f",
560 help="Don't prompt the user.", 575 help="Don't prompt the user.",
561 default=False, action="store_true") 576 default=False, action="store_true")
562 result.add_option("-l", "--last-push", dest="l", 577 result.add_option("-l", "--last-push", dest="l",
563 help=("Manually specify the git commit ID " 578 help=("Manually specify the git commit ID "
564 "of the last push to trunk.")) 579 "of the last push to trunk."))
565 result.add_option("-m", "--manual", dest="m", 580 result.add_option("-m", "--manual", dest="m",
566 help="Prompt the user at every important step.", 581 help="Prompt the user at every important step.",
567 default=False, action="store_true") 582 default=False, action="store_true")
568 result.add_option("-r", "--reviewer", 583 result.add_option("-r", "--reviewer", dest="r",
569 help=("Specify the account name to be used for reviews.")) 584 help=("Specify the account name to be used for reviews."))
570 result.add_option("-s", "--step", dest="s", 585 result.add_option("-s", "--step", dest="s",
571 help="Specify the step where to start work. Default: 0.", 586 help="Specify the step where to start work. Default: 0.",
572 default=0, type="int") 587 default=0, type="int")
573 return result 588 return result
574 589
575 590
576 def ProcessOptions(options): 591 def ProcessOptions(options):
577 if options.s < 0: 592 if options.s < 0:
578 print "Bad step number %d" % options.s 593 print "Bad step number %d" % options.s
579 return False 594 return False
580 if not options.m and not options.reviewer: 595 if not options.m and not options.r:
581 print "A reviewer (-r) is required in (semi-)automatic mode." 596 print "A reviewer (-r) is required in (semi-)automatic mode."
582 return False 597 return False
583 if options.f and options.m: 598 if options.f and options.m:
584 print "Manual and forced mode cannot be combined." 599 print "Manual and forced mode cannot be combined."
585 return False 600 return False
586 if not options.m and not options.c: 601 if not options.m and not options.c:
587 print "A chromium checkout (-c) is required in (semi-)automatic mode." 602 print "A chromium checkout (-c) is required in (semi-)automatic mode."
588 return False 603 return False
589 if not options.m and not options.a:
590 print "Specify your chromium.org email with -a in (semi-)automatic mode."
591 return False
592 return True 604 return True
593 605
594 606
595 def Main(): 607 def Main():
596 parser = BuildOptions() 608 parser = BuildOptions()
597 (options, args) = parser.parse_args() 609 (options, args) = parser.parse_args()
598 if not ProcessOptions(options): 610 if not ProcessOptions(options):
599 parser.print_help() 611 parser.print_help()
600 return 1 612 return 1
601 RunPushToTrunk(CONFIG, PushToTrunkOptions(options)) 613 RunPushToTrunk(CONFIG, PushToTrunkOptions(options))
602 614
603 if __name__ == "__main__": 615 if __name__ == "__main__":
604 sys.exit(Main()) 616 sys.exit(Main())
OLDNEW
« no previous file with comments | « tools/push-to-trunk/merge_to_branch.py ('k') | tools/push-to-trunk/test_scripts.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698