summaryrefslogtreecommitdiffstats
path: root/WebKitTools/Scripts/bugzilla-tool
diff options
context:
space:
mode:
Diffstat (limited to 'WebKitTools/Scripts/bugzilla-tool')
-rwxr-xr-xWebKitTools/Scripts/bugzilla-tool122
1 files changed, 72 insertions, 50 deletions
diff --git a/WebKitTools/Scripts/bugzilla-tool b/WebKitTools/Scripts/bugzilla-tool
index ec5aa0d..8e899b5 100755
--- a/WebKitTools/Scripts/bugzilla-tool
+++ b/WebKitTools/Scripts/bugzilla-tool
@@ -73,7 +73,7 @@ def commit_message_for_this_commit(scm):
log("Parsing ChangeLog: %s" % changelog_path)
changelog_entry = ChangeLog(changelog_path).latest_entry()
if not changelog_entry:
- error("Failed to parse ChangeLog: " + os.path.abspath(changelog_path))
+ raise ScriptError(message="Failed to parse ChangeLog: " + os.path.abspath(changelog_path))
changelog_messages.append(changelog_entry)
# FIXME: We should sort and label the ChangeLog messages like commit-log-editor does.
@@ -325,6 +325,11 @@ class LandPatchesFromBugs(Command):
options += WebKitLandingScripts.land_options()
Command.__init__(self, 'Lands all patches on a bug optionally testing them first', 'BUGID', options=options)
+ @staticmethod
+ def handled_error(error):
+ log(error)
+ exit(2) # Exit 2 insted of 1 to indicate to the commit-queue to indicate we handled the error, and that the queue should keep looping.
+
@classmethod
def land_patches(cls, bug_id, patches, options, tool):
try:
@@ -344,11 +349,11 @@ class LandPatchesFromBugs(Command):
except CheckoutNeedsUpdate, e:
log("Commit was rejected because the checkout is out of date. Please update and try again.")
log("You can pass --no-build to skip building/testing after update if you believe the new commits did not affect the results.")
- error(e)
+ cls.handled_error(e)
except ScriptError, e:
# Mark the patch as commit-queue- and comment in the bug.
tool.bugs.reject_patch_from_commit_queue(patch['id'], e.message_with_output())
- error(e)
+ cls.handled_error(e)
@staticmethod
def _fetch_list_of_patches_to_land(options, args, tool):
@@ -420,6 +425,7 @@ class PostDiffAsPatchToBug(Command):
return [
make_option("--no-obsolete", action="store_false", dest="obsolete_patches", default=True, help="Do not obsolete old patches before posting this one."),
make_option("--no-review", action="store_false", dest="review", default=True, help="Do not mark the patch for review."),
+ make_option("--request-commit", action="store_true", dest="request_commit", default=False, help="Mark the patch as needing auto-commit after review."),
]
@staticmethod
@@ -443,7 +449,7 @@ class PostDiffAsPatchToBug(Command):
diff_file = StringIO.StringIO(diff) # add_patch_to_bug expects a file-like object
description = options.description or "Patch v1"
- tool.bugs.add_patch_to_bug(bug_id, diff_file, description, mark_for_review=options.review)
+ tool.bugs.add_patch_to_bug(bug_id, diff_file, description, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
class PostCommitsAsPatchesToBug(Command):
@@ -493,7 +499,7 @@ class PostCommitsAsPatchesToBug(Command):
diff_file = self._diff_file_for_commit(tool, commit_id)
description = options.description or commit_message.description(lstrip=True, strip_url=True)
comment_text = self._comment_text_for_commit(options, commit_message, tool, commit_id)
- tool.bugs.add_patch_to_bug(bug_id, diff_file, description, comment_text, mark_for_review=options.review)
+ tool.bugs.add_patch_to_bug(bug_id, diff_file, description, comment_text, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
class RolloutCommit(Command):
@@ -560,6 +566,7 @@ class CreateBug(Command):
make_option("--component", action="store", type="string", dest="component", help="Component for the new bug."),
make_option("--no-prompt", action="store_false", dest="prompt", default=True, help="Do not prompt for bug title and comment; use commit log instead."),
make_option("--no-review", action="store_false", dest="review", default=True, help="Do not mark the patch for review."),
+ make_option("--request-commit", action="store_true", dest="request_commit", default=False, help="Mark the patch as needing auto-commit after review."),
]
Command.__init__(self, 'Create a bug from local changes or local commits.', '[COMMITISH]', options=options)
@@ -583,7 +590,7 @@ class CreateBug(Command):
diff = tool.scm().create_patch_from_local_commit(commit_id)
diff_file = StringIO.StringIO(diff) # create_bug_with_patch expects a file-like object
- bug_id = tool.bugs.create_bug_with_patch(bug_title, comment_text, options.component, diff_file, "Patch v1", cc=options.cc, mark_for_review=options.review)
+ bug_id = tool.bugs.create_bug_with_patch(bug_title, comment_text, options.component, diff_file, "Patch v1", cc=options.cc, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
if bug_id and len(commit_ids) > 1:
options.bug_id = bug_id
@@ -603,7 +610,7 @@ class CreateBug(Command):
diff = tool.scm().create_patch()
diff_file = StringIO.StringIO(diff) # create_bug_with_patch expects a file-like object
- bug_id = tool.bugs.create_bug_with_patch(bug_title, comment_text, options.component, diff_file, "Patch v1", cc=options.cc, mark_for_review=options.review)
+ bug_id = tool.bugs.create_bug_with_patch(bug_title, comment_text, options.component, diff_file, "Patch v1", cc=options.cc, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
def prompt_for_bug_title_and_comment(self):
bug_title = raw_input("Bug title: ")
@@ -644,6 +651,7 @@ class CheckTreeStatus(Command):
class LandPatchesFromCommitQueue(Command):
def __init__(self):
options = [
+ make_option("--is-relaunch", action="store_true", dest="is_relaunch", default=False, help="Internal: Used by the queue to indicate that it's relaunching itself."),
make_option("--no-confirm", action="store_false", dest="confirm", default=True, help="Do not ask the user for confirmation before running the queue. Dangerous!"),
make_option("--status-host", action="store", type="string", dest="status_host", default=StatusBot.default_host, help="Do not ask the user for confirmation before running the queue. Dangerous!"),
]
@@ -675,16 +683,25 @@ class LandPatchesFromCommitQueue(Command):
wake_time = datetime.now() + timedelta(seconds=cls.seconds_to_sleep)
return "%s Sleeping until %s (%s)." % (message, wake_time.strftime(cls.log_date_format), cls.sleep_duration_text)
- @classmethod
- def _sleep(cls, message):
- log(cls._sleep_message(message))
- time.sleep(cls.seconds_to_sleep)
+ def _sleep(self, message):
+ log(self._sleep_message(message))
+ time.sleep(self.seconds_to_sleep)
+ self._next_patch()
def _update_status_and_sleep(self, message):
status_message = self._sleep_message(message)
self.status_bot.update_status(status_message)
log(status_message)
time.sleep(self.seconds_to_sleep)
+ self._next_patch()
+
+ def _next_patch(self):
+ # Re-exec this script to catch any updates to the script.
+ # Make sure that the re-execed commit-queue does not wait for the user.
+ args = sys.argv[:]
+ if args.count("--is-relaunch") == 0:
+ args.append("--is-relaunch")
+ os.execvp(sys.argv[0], args)
@staticmethod
def _open_log_file(log_path):
@@ -705,50 +722,55 @@ class LandPatchesFromCommitQueue(Command):
log_file.close()
def execute(self, options, args, tool):
- log("CAUTION: commit-queue will discard all local changes in %s" % tool.scm().checkout_root)
- if options.confirm:
- response = raw_input("Are you sure? Type 'yes' to continue: ")
- if (response != 'yes'):
- error("User declined.")
+ if not options.is_relaunch:
+ log("CAUTION: commit-queue will discard all local changes in %s" % tool.scm().checkout_root)
+ if options.confirm:
+ response = raw_input("Are you sure? Type 'yes' to continue: ")
+ if (response != 'yes'):
+ error("User declined.")
queue_log = self._add_log_to_output_tee(self.queue_log_path)
- log("Running WebKit Commit Queue. %s" % datetime.now().strftime(self.log_date_format))
+ if not options.is_relaunch:
+ log("Running WebKit Commit Queue. %s" % datetime.now().strftime(self.log_date_format))
self.status_bot = StatusBot(host=options.status_host)
- while (True):
- # Either of these calls could throw URLError which shouldn't stop the queue.
- # We catch all exceptions just in case.
- try:
- # Fetch patches instead of just bug ids to that we validate reviewer/committer flags on every patch.
- patches = tool.bugs.fetch_patches_from_commit_queue(reject_invalid_patches=True)
- if not len(patches):
- self._update_status_and_sleep("Empty queue.")
- continue
- patch_ids = map(lambda patch: patch['id'], patches)
- first_bug_id = patches[0]['bug_id']
- log("%s in commit queue [%s]" % (pluralize('patch', len(patches)), ", ".join(patch_ids)))
-
- if not tool.buildbot.core_builders_are_green():
- self._update_status_and_sleep("Builders (http://build.webkit.org) are red.")
- continue
-
- self.status_bot.update_status("Landing patches from bug %s." % first_bug_id, bug_id=first_bug_id)
- except Exception, e:
- # Don't try tell the status bot, in case telling it causes an exception.
- self._sleep("Exception while checking queue and bots: %s." % e)
- continue
-
- # Try to land patches on the first bug in the queue before looping
- bug_log_path = os.path.join(self.bug_logs_directory, "%s.log" % first_bug_id)
- bug_log = self._add_log_to_output_tee(bug_log_path)
- bugzilla_tool_path = __file__ # re-execute this script
- bugzilla_tool_args = [bugzilla_tool_path, 'land-patches', '--force-clean', '--commit-queue', '--quiet', first_bug_id]
- WebKitLandingScripts.run_command_with_teed_output(bugzilla_tool_args, sys.stdout)
- self._remove_log_from_output_tee(bug_log)
-
- log("Finished WebKit Commit Queue. %s" % datetime.now().strftime(self.log_date_format))
- self._remove_log_from_output_tee(queue_log)
+ # Either of these calls could throw URLError which shouldn't stop the queue.
+ # We catch all exceptions just in case.
+ try:
+ # Fetch patches instead of just bug ids to that we validate reviewer/committer flags on every patch.
+ patches = tool.bugs.fetch_patches_from_commit_queue(reject_invalid_patches=True)
+ if not len(patches):
+ self._update_status_and_sleep("Empty queue.")
+ patch_ids = map(lambda patch: patch['id'], patches)
+ first_bug_id = patches[0]['bug_id']
+ log("%s in commit queue [%s]" % (pluralize('patch', len(patches)), ", ".join(patch_ids)))
+
+ red_builders_names = tool.buildbot.red_core_builders_names()
+ if red_builders_names:
+ red_builders_names = map(lambda name: '"%s"' % name, red_builders_names) # Add quotes around the names.
+ self._update_status_and_sleep("Builders [%s] are red. See http://build.webkit.org." % ", ".join(red_builders_names))
+
+ self.status_bot.update_status("Landing patches from bug %s." % first_bug_id, bug_id=first_bug_id)
+ except Exception, e:
+ # Don't try tell the status bot, in case telling it causes an exception.
+ self._sleep("Exception while checking queue and bots: %s." % e)
+
+ # Try to land patches on the first bug in the queue before looping
+ bug_log_path = os.path.join(self.bug_logs_directory, "%s.log" % first_bug_id)
+ bug_log = self._add_log_to_output_tee(bug_log_path)
+ bugzilla_tool_path = __file__ # re-execute this script
+ bugzilla_tool_args = [bugzilla_tool_path, 'land-patches', '--force-clean', '--commit-queue', '--quiet', first_bug_id]
+ try:
+ WebKitLandingScripts.run_and_throw_if_fail(bugzilla_tool_args)
+ except ScriptError, e:
+ # Unexpected failure! Mark the patch as commit-queue- and comment in the bug.
+ # exit(2) is a special exit code we use to indicate that the error was already handled by land-patches and we should keep looping anyway.
+ if e.exit_code != 2:
+ tool.bugs.reject_patch_from_commit_queue(patch['id'], "Unexpected failure when landing patch! Please file a bug against bugzilla-tool.\n%s" % e.message_with_output())
+ self._remove_log_from_output_tee(bug_log)
+ # self._remove_log_from_output_tee(queue_log) # implicit in the exec()
+ self._next_patch()
class NonWrappingEpilogIndentedHelpFormatter(IndentedHelpFormatter):