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

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

Issue 102253002: Add fully automated mode to push-to-trunk script. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Rename debug mode to manual mode. Created 7 years 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/auto_roll.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 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 211 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 self._options = options 222 self._options = options
223 self._side_effect_handler = handler 223 self._side_effect_handler = handler
224 assert self._number >= 0 224 assert self._number >= 0
225 assert self._config is not None 225 assert self._config is not None
226 assert self._state is not None 226 assert self._state is not None
227 assert self._side_effect_handler is not None 227 assert self._side_effect_handler is not None
228 228
229 def Config(self, key): 229 def Config(self, key):
230 return self._config[key] 230 return self._config[key]
231 231
232 def IsForced(self):
233 return self._options and self._options.f
234
235 def IsManual(self):
236 return self._options and self._options.m
237
232 def Run(self): 238 def Run(self):
233 if self._requires: 239 if self._requires:
234 self.RestoreIfUnset(self._requires) 240 self.RestoreIfUnset(self._requires)
235 if not self._state[self._requires]: 241 if not self._state[self._requires]:
236 return 242 return
237 print ">>> Step %d: %s" % (self._number, self._text) 243 print ">>> Step %d: %s" % (self._number, self._text)
238 self.RunStep() 244 self.RunStep()
239 245
240 def RunStep(self): 246 def RunStep(self):
241 raise NotImplementedError 247 raise NotImplementedError
(...skipping 22 matching lines...) Expand all
264 raise Exception("Retried too often. Giving up.") 270 raise Exception("Retried too often. Giving up.")
265 wait_time = wait_plan.pop() 271 wait_time = wait_plan.pop()
266 print "Waiting for %f seconds." % wait_time 272 print "Waiting for %f seconds." % wait_time
267 self._side_effect_handler.Sleep(wait_time) 273 self._side_effect_handler.Sleep(wait_time)
268 print "Retrying..." 274 print "Retrying..."
269 else: 275 else:
270 return result 276 return result
271 277
272 def ReadLine(self, default=None): 278 def ReadLine(self, default=None):
273 # Don't prompt in forced mode. 279 # Don't prompt in forced mode.
274 if self._options and self._options.f and default is not None: 280 if not self.IsManual() and default is not None:
275 print "%s (forced)" % default 281 print "%s (forced)" % default
276 return default 282 return default
277 else: 283 else:
278 return self._side_effect_handler.ReadLine() 284 return self._side_effect_handler.ReadLine()
279 285
280 def Git(self, args="", prefix="", pipe=True, retry_on=None): 286 def Git(self, args="", prefix="", pipe=True, retry_on=None):
281 cmd = lambda: self._side_effect_handler.Command("git", args, prefix, pipe) 287 cmd = lambda: self._side_effect_handler.Command("git", args, prefix, pipe)
282 return self.Retry(cmd, retry_on, [5, 30]) 288 return self.Retry(cmd, retry_on, [5, 30])
283 289
284 def Editor(self, args): 290 def Editor(self, args):
285 return self._side_effect_handler.Command(os.environ["EDITOR"], args, 291 if not self.IsForced():
286 pipe=False) 292 return self._side_effect_handler.Command(os.environ["EDITOR"], args,
293 pipe=False)
287 294
288 def ReadURL(self, url, retry_on=None, wait_plan=None): 295 def ReadURL(self, url, retry_on=None, wait_plan=None):
289 wait_plan = wait_plan or [3, 60, 600] 296 wait_plan = wait_plan or [3, 60, 600]
290 cmd = lambda: self._side_effect_handler.ReadURL(url) 297 cmd = lambda: self._side_effect_handler.ReadURL(url)
291 return self.Retry(cmd, retry_on, wait_plan) 298 return self.Retry(cmd, retry_on, wait_plan)
292 299
293 def GetDate(self): 300 def GetDate(self):
294 return self._side_effect_handler.GetDate() 301 return self._side_effect_handler.GetDate()
295 302
296 def Die(self, msg=""): 303 def Die(self, msg=""):
297 if msg != "": 304 if msg != "":
298 print "Error: %s" % msg 305 print "Error: %s" % msg
299 print "Exiting" 306 print "Exiting"
300 raise Exception(msg) 307 raise Exception(msg)
301 308
302 def DieInForcedMode(self, msg=""): 309 def DieNoManualMode(self, msg=""):
303 if self._options and self._options.f: 310 if not self.IsManual():
304 msg = msg or "Not implemented in forced mode." 311 msg = msg or "Only available in manual mode."
305 self.Die(msg) 312 self.Die(msg)
306 313
307 def Confirm(self, msg): 314 def Confirm(self, msg):
308 print "%s [Y/n] " % msg, 315 print "%s [Y/n] " % msg,
309 answer = self.ReadLine(default="Y") 316 answer = self.ReadLine(default="Y")
310 return answer == "" or answer == "Y" or answer == "y" 317 return answer == "" or answer == "Y" or answer == "y"
311 318
312 def DeleteBranch(self, name): 319 def DeleteBranch(self, name):
313 git_result = self.Git("branch").strip() 320 git_result = self.Git("branch").strip()
314 for line in git_result.splitlines(): 321 for line in git_result.splitlines():
(...skipping 18 matching lines...) Expand all
333 340
334 def RestoreIfUnset(self, var_name): 341 def RestoreIfUnset(self, var_name):
335 if self._state.get(var_name) is None: 342 if self._state.get(var_name) is None:
336 self._state[var_name] = self.Restore(var_name) 343 self._state[var_name] = self.Restore(var_name)
337 344
338 def InitialEnvironmentChecks(self): 345 def InitialEnvironmentChecks(self):
339 # Cancel if this is not a git checkout. 346 # Cancel if this is not a git checkout.
340 if not os.path.exists(self._config[DOT_GIT_LOCATION]): 347 if not os.path.exists(self._config[DOT_GIT_LOCATION]):
341 self.Die("This is not a git checkout, this script won't work for you.") 348 self.Die("This is not a git checkout, this script won't work for you.")
342 349
343 # TODO(machenbach): Don't use EDITOR in forced mode as soon as script is
344 # well tested.
345 # Cancel if EDITOR is unset or not executable. 350 # Cancel if EDITOR is unset or not executable.
346 if (not os.environ.get("EDITOR") or 351 if (not self.IsForced() and (not os.environ.get("EDITOR") or
347 Command("which", os.environ["EDITOR"]) is None): 352 Command("which", os.environ["EDITOR"]) is None)):
348 self.Die("Please set your EDITOR environment variable, you'll need it.") 353 self.Die("Please set your EDITOR environment variable, you'll need it.")
349 354
350 def CommonPrepare(self): 355 def CommonPrepare(self):
351 # Check for a clean workdir. 356 # Check for a clean workdir.
352 if self.Git("status -s -uno").strip() != "": 357 if self.Git("status -s -uno").strip() != "":
353 self.Die("Workspace is not clean. Please commit or undo your changes.") 358 self.Die("Workspace is not clean. Please commit or undo your changes.")
354 359
355 # Persist current branch. 360 # Persist current branch.
356 current_branch = "" 361 current_branch = ""
357 git_result = self.Git("status -s -b -uno").strip() 362 git_result = self.Git("status -s -b -uno").strip()
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 self.RestoreIfUnset("%s%s" % (prefix, v)) 411 self.RestoreIfUnset("%s%s" % (prefix, v))
407 412
408 def WaitForLGTM(self): 413 def WaitForLGTM(self):
409 print ("Please wait for an LGTM, then type \"LGTM<Return>\" to commit " 414 print ("Please wait for an LGTM, then type \"LGTM<Return>\" to commit "
410 "your change. (If you need to iterate on the patch or double check " 415 "your change. (If you need to iterate on the patch or double check "
411 "that it's sane, do so in another shell, but remember to not " 416 "that it's sane, do so in another shell, but remember to not "
412 "change the headline of the uploaded CL.") 417 "change the headline of the uploaded CL.")
413 answer = "" 418 answer = ""
414 while answer != "LGTM": 419 while answer != "LGTM":
415 print "> ", 420 print "> ",
416 # TODO(machenbach): Add default="LGTM" to avoid prompt when script is 421 answer = self.ReadLine("LGTM" if self.IsForced() else None)
417 # well tested and when prepare push cl has TBR flag.
418 answer = self.ReadLine()
419 if answer != "LGTM": 422 if answer != "LGTM":
420 print "That was not 'LGTM'." 423 print "That was not 'LGTM'."
421 424
422 def WaitForResolvingConflicts(self, patch_file): 425 def WaitForResolvingConflicts(self, patch_file):
423 print("Applying the patch \"%s\" failed. Either type \"ABORT<Return>\", " 426 print("Applying the patch \"%s\" failed. Either type \"ABORT<Return>\", "
424 "or resolve the conflicts, stage *all* touched files with " 427 "or resolve the conflicts, stage *all* touched files with "
425 "'git add', and type \"RESOLVED<Return>\"") 428 "'git add', and type \"RESOLVED<Return>\"")
426 self.DieInForcedMode() 429 self.DieNoManualMode()
427 answer = "" 430 answer = ""
428 while answer != "RESOLVED": 431 while answer != "RESOLVED":
429 if answer == "ABORT": 432 if answer == "ABORT":
430 self.Die("Applying the patch failed.") 433 self.Die("Applying the patch failed.")
431 if answer != "": 434 if answer != "":
432 print "That was not 'RESOLVED' or 'ABORT'." 435 print "That was not 'RESOLVED' or 'ABORT'."
433 print "> ", 436 print "> ",
434 answer = self.ReadLine() 437 answer = self.ReadLine()
435 438
436 # Takes a file containing the patch to apply as first argument. 439 # Takes a file containing the patch to apply as first argument.
437 def ApplyPatch(self, patch_file, reverse_patch=""): 440 def ApplyPatch(self, patch_file, reverse_patch=""):
438 args = "apply --index --reject %s \"%s\"" % (reverse_patch, patch_file) 441 args = "apply --index --reject %s \"%s\"" % (reverse_patch, patch_file)
439 if self.Git(args) is None: 442 if self.Git(args) is None:
440 self.WaitForResolvingConflicts(patch_file) 443 self.WaitForResolvingConflicts(patch_file)
441 444
442 445
443 class UploadStep(Step): 446 class UploadStep(Step):
444 MESSAGE = "Upload for code review." 447 MESSAGE = "Upload for code review."
445 448
446 def RunStep(self): 449 def RunStep(self):
447 if self._options.r: 450 if self._options.r:
448 print "Using account %s for review." % self._options.r 451 print "Using account %s for review." % self._options.r
449 reviewer = self._options.r 452 reviewer = self._options.r
450 else: 453 else:
451 print "Please enter the email address of a V8 reviewer for your patch: ", 454 print "Please enter the email address of a V8 reviewer for your patch: ",
452 self.DieInForcedMode("A reviewer must be specified in forced mode.") 455 self.DieNoManualMode("A reviewer must be specified in forced mode.")
453 reviewer = self.ReadLine() 456 reviewer = self.ReadLine()
454 force_flag = " -f" if self._options.f else "" 457 force_flag = " -f" if not self.IsManual() else ""
455 args = "cl upload -r \"%s\" --send-mail%s" % (reviewer, force_flag) 458 args = "cl upload -r \"%s\" --send-mail%s" % (reviewer, force_flag)
456 # TODO(machenbach): Check output in forced mode. Verify that all required 459 # TODO(machenbach): Check output in forced mode. Verify that all required
457 # base files were uploaded, if not retry. 460 # base files were uploaded, if not retry.
458 if self.Git(args, pipe=False) is None: 461 if self.Git(args, pipe=False) is None:
459 self.Die("'git cl upload' failed, please try again.") 462 self.Die("'git cl upload' failed, please try again.")
460 463
461 464
462 def MakeStep(step_class=Step, number=0, state=None, config=None, 465 def MakeStep(step_class=Step, number=0, state=None, config=None,
463 options=None, side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): 466 options=None, side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER):
464 # Allow to pass in empty dictionaries. 467 # Allow to pass in empty dictionaries.
(...skipping 19 matching lines...) Expand all
484 options, 487 options,
485 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): 488 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER):
486 state = {} 489 state = {}
487 steps = [] 490 steps = []
488 for (number, step_class) in enumerate(step_classes): 491 for (number, step_class) in enumerate(step_classes):
489 steps.append(MakeStep(step_class, number, state, config, 492 steps.append(MakeStep(step_class, number, state, config,
490 options, side_effect_handler)) 493 options, side_effect_handler))
491 494
492 for step in steps[options.s:]: 495 for step in steps[options.s:]:
493 step.Run() 496 step.Run()
OLDNEW
« no previous file with comments | « tools/push-to-trunk/auto_roll.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