+2013-02-16 Ryosuke Niwa <rniwa@webkit.org>
+
+ We need a CIA replacement
+ https://bugs.webkit.org/show_bug.cgi?id=110008
+
+ Reviewed by Andreas Kling.
+
+ Added new-commit-bot.
+
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+ (QueueEngine.__init__):
+ (QueueEngine): Made the sleep tiem configurable.
+ (QueueEngine._sleep_message):
+ (QueueEngine._sleep):
+ * Scripts/webkitpy/tool/bot/queueengine_unittest.py:
+ (QueueEngineTest.test_sleep_message):
+ * Scripts/webkitpy/tool/commands/__init__.py:
+ * Scripts/webkitpy/tool/commands/newcommitbot.py: Added.
+ (PingPong): Added. Implements the ping pong protocol.
+ (NewCommitBot):
+ (NewCommitBot.begin_work_queue):
+ (NewCommitBot.work_item_log_path):
+ (NewCommitBot.next_work_item): Update SVN revision and report any new commits made since
+ the last time we checked the head SVN revision.
+ (NewCommitBot.process_work_item):
+ (NewCommitBot._update_checkout): svn up.
+ (NewCommitBot._new_svn_revisions): Returns a range of new revisions.
+ (NewCommitBot._summarize_commit_log): Summarize a commit log to be posted on IRC.
+ (NewCommitBot.handle_unexpected_error):
+ (NewCommitBot.handle_script_error):
+ * Scripts/webkitpy/tool/commands/newcommitbot_unittest.py: Added.
+ (NewCommitBotTest.test_summarize_commit_log_basic): Tests for summarizing non-rollout commits.
+ (NewCommitBotTest.test_summarize_commit_log_rollout): Tests for summarizing rollouts.
+ * Scripts/webkitpy/tool/commands/queues.py:
+ (AbstractQueue.execute):
+ * Scripts/webkitpy/tool/commands/queuestest.py:
+ (MockQueueEngine.__init__):
+ * Scripts/webkitpy/tool/commands/sheriffbot_unittest.py:
+ (SheriffBotTest.test_command_aliases):
+ * Scripts/webkitpy/tool/main.py:
+ (WebKitPatch):
+
2013-02-16 Jochen Eisinger <jochen@chromium.org>
[chromium] initialize all variables of TestRunner classes
class QueueEngine:
- def __init__(self, name, delegate, wakeup_event):
+ def __init__(self, name, delegate, wakeup_event, seconds_to_sleep=120):
self._name = name
self._delegate = delegate
self._wakeup_event = wakeup_event
self._output_tee = OutputTee()
+ self._seconds_to_sleep = seconds_to_sleep
log_date_format = "%Y-%m-%d %H:%M:%S"
- sleep_duration_text = "2 mins" # This could be generated from seconds_to_sleep
- seconds_to_sleep = 120
handled_error_code = 2
# Child processes exit with a special code to the parent queue process can detect the error was handled.
return datetime.now()
def _sleep_message(self, message):
- wake_time = self._now() + timedelta(seconds=self.seconds_to_sleep)
- return "%s Sleeping until %s (%s)." % (message, wake_time.strftime(self.log_date_format), self.sleep_duration_text)
+ wake_time = self._now() + timedelta(seconds=self._seconds_to_sleep)
+ if self._seconds_to_sleep < 3 * 60:
+ sleep_duration_text = str(self._seconds_to_sleep) + ' seconds'
+ else:
+ sleep_duration_text = str(round(self._seconds_to_sleep / 60)) + ' minutes'
+ return "%s Sleeping until %s (%s)." % (message, wake_time.strftime(self.log_date_format), sleep_duration_text)
def _sleep(self, message):
_log.info(self._sleep_message(message))
- self._wakeup_event.wait(self.seconds_to_sleep)
+ self._wakeup_event.wait(self._seconds_to_sleep)
self._wakeup_event.clear()
def test_sleep_message(self):
engine = QueueEngine("test", None, None)
engine._now = lambda: datetime.datetime(2010, 1, 1)
- expected_sleep_message = "MESSAGE Sleeping until 2010-01-01 00:02:00 (2 mins)."
+ expected_sleep_message = "MESSAGE Sleeping until 2010-01-01 00:02:00 (120 seconds)."
self.assertEqual(engine._sleep_message("MESSAGE"), expected_sleep_message)
def setUp(self):
from webkitpy.tool.commands.earlywarningsystem import *
from webkitpy.tool.commands.findusers import FindUsers
from webkitpy.tool.commands.gardenomatic import GardenOMatic
+from webkitpy.tool.commands.newcommitbot import NewCommitBot
from webkitpy.tool.commands.openbugs import OpenBugs
from webkitpy.tool.commands.perfalizer import Perfalizer
from webkitpy.tool.commands.prettydiff import PrettyDiff
--- /dev/null
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Copyright (c) 2013 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+import re
+
+from webkitpy.common.config.committers import CommitterList
+from webkitpy.tool.bot.irc_command import IRCCommand
+from webkitpy.tool.bot.irc_command import Help
+from webkitpy.tool.bot.irc_command import Hi
+from webkitpy.tool.bot.irc_command import Restart
+from webkitpy.tool.bot.ircbot import IRCBot
+from webkitpy.tool.commands.queues import AbstractQueue
+from webkitpy.tool.commands.stepsequence import StepSequenceErrorHandler
+
+_log = logging.getLogger(__name__)
+
+
+class PingPong(IRCCommand):
+ def execute(self, nick, args, tool, sheriff):
+ return nick + ": pong"
+
+
+class NewCommitBot(AbstractQueue, StepSequenceErrorHandler):
+ name = "new-commit-bot"
+ watchers = AbstractQueue.watchers + ["rniwa@webkit.org"]
+
+ _commands = {
+ "ping": PingPong,
+ "restart": Restart,
+ }
+
+ # AbstractQueue methods
+
+ def begin_work_queue(self):
+ AbstractQueue.begin_work_queue(self)
+ self._last_svn_revision = int(self._tool.scm().head_svn_revision())
+ self._irc_bot = IRCBot(self.name, self._tool, None, self._commands)
+ self._tool.ensure_irc_connected(self._irc_bot.irc_delegate())
+
+ def work_item_log_path(self, failure_map):
+ return None
+
+ def next_work_item(self):
+ self._irc_bot.process_pending_messages()
+
+ _log.info('Last SVN revision: %d' % self._last_svn_revision)
+
+ _log.info('Updating checkout')
+ self._update_checkout()
+
+ _log.info('Obtaining new SVN revisions')
+ revisions = self._new_svn_revisions()
+
+ _log.info('Obtaining commit logs for %d revisions' % len(revisions))
+ for revision in revisions:
+ commit_log = self._tool.scm().svn_commit_log(revision)
+ self._tool.irc().post(self._summarize_commit_log(commit_log))
+
+ return
+
+ def process_work_item(self, failure_map):
+ return True
+
+ def _update_checkout(self):
+ tool = self._tool
+ tool.executive.run_and_throw_if_fail(tool.deprecated_port().update_webkit_command(), quiet=True, cwd=tool.scm().checkout_root)
+
+ def _new_svn_revisions(self):
+ scm = self._tool.scm()
+ current_head = int(scm.head_svn_revision())
+ first_new_revision = self._last_svn_revision + 1
+ self._last_svn_revision = current_head
+ return range(max(first_new_revision, current_head - 20), current_head + 1)
+
+ _patch_by_regex = re.compile(r'^Patch\s+by\s+(?P<author>.+?)\s+on(\s+\d{4}-\d{2}-\d{2})?\n?', re.MULTILINE | re.IGNORECASE)
+ _rollout_regex = re.compile(r'(rolling out|reverting) (?P<revisions>r?\d+((,\s*|,?\s*and\s+)?r?\d+)*)\.?', re.MULTILINE | re.IGNORECASE)
+ _requested_by_regex = re.compile(r'^\"?(?P<reason>.+?)\"? \(Requested\s+by\s+(?P<author>.+)\s+on\s+#webkit\)\.', re.MULTILINE | re.IGNORECASE)
+ _bugzilla_url_regex = re.compile(r'http(s?)://bugs\.webkit\.org/show_bug\.cgi\?id=(?P<id>\d+)', re.MULTILINE)
+ _trac_url_regex = re.compile(r'http(s?)://trac.webkit.org/changeset/(?P<revision>\d+)', re.MULTILINE)
+
+ @classmethod
+ def _summarize_commit_log(self, commit_log, committer_list=CommitterList()):
+ patch_by = self._patch_by_regex.search(commit_log)
+ commit_log = self._patch_by_regex.sub('', commit_log, count=1)
+
+ rollout = self._rollout_regex.search(commit_log)
+ commit_log = self._rollout_regex.sub('', commit_log, count=1)
+
+ requested_by = self._requested_by_regex.search(commit_log)
+
+ commit_log = self._bugzilla_url_regex.sub(r'https://webkit.org/b/\g<id>', commit_log)
+ commit_log = self._trac_url_regex.sub(r'https://trac.webkit.org/r\g<revision>', commit_log)
+
+ for contributor in committer_list.contributors():
+ if not contributor.irc_nicknames:
+ continue
+ nickname = contributor.irc_nicknames[0]
+ commit_log = commit_log.replace(contributor.full_name, nickname)
+ for email in contributor.emails:
+ commit_log = commit_log.replace(email, nickname)
+
+ lines = commit_log.split('\n')[1:-2] # Ignore lines with ----------.
+
+ firstline = re.match(r'^(?P<revision>r\d+) \| (?P<email>[^\s\|]+) \| (?P<timestamp>[^|]+) \| [^\n]+', lines[0])
+ assert firstline
+ author = firstline.group('email')
+ if patch_by:
+ author = patch_by.group('author')
+
+ linkified_revision = 'https://trac.webkit.org/%s' % firstline.group('revision')
+ lines[0] = '%s by %s' % (linkified_revision, author)
+
+ if rollout:
+ if requested_by:
+ return '%s rolled out %s in %s: %s' % (requested_by.group('author'), rollout.group('revisions'),
+ linkified_revision, requested_by.group('reason'))
+ lines[0] = '%s rolled out %s in %s' % (author, rollout.group('revisions'), linkified_revision)
+
+ return ' '.join(filter(lambda line: len(line), lines)[0:4])
+
+ def handle_unexpected_error(self, failure_map, message):
+ _log.error(message)
+
+ # StepSequenceErrorHandler methods
+
+ @classmethod
+ def handle_script_error(cls, tool, state, script_error):
+ # Ideally we would post some information to IRC about what went wrong
+ # here, but we don't have the IRC password in the child process.
+ pass
--- /dev/null
+# Copyright (C) 2013 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import unittest2 as unittest
+
+from webkitpy.tool.commands.newcommitbot import NewCommitBot
+
+
+class NewCommitBotTest(unittest.TestCase):
+ def test_summarize_commit_log_basic(self):
+ self.assertEqual(NewCommitBot._summarize_commit_log("""------------------------------------------------------------------------
+r143106 | jochen@chromium.org | 2013-02-16 10:27:07 -0800 (Sat, 16 Feb 2013) | 10 lines
+
+[chromium] initialize all variables of TestRunner classes
+https://bugs.webkit.org/show_bug.cgi?id=110013
+
+Reviewed by Adam Barth.
+
+* DumpRenderTree/chromium/TestRunner/src/TestInterfaces.cpp:
+(WebTestRunner::TestInterfaces::TestInterfaces):
+* DumpRenderTree/chromium/TestRunner/src/TestRunner.cpp:
+(WebTestRunner::TestRunner::TestRunner):
+
+------------------------------------------------------------------------"""),
+ "https://trac.webkit.org/r143106 by jochen__ [chromium] initialize all variables of TestRunner classes"
+ " https://webkit.org/b/110013 Reviewed by abarth.")
+
+ self.assertEqual(NewCommitBot._summarize_commit_log("""------------------------------------------------------------------------
+r140066 | simon.fraser@apple.com | 2013-01-17 16:10:31 -0800 (Thu, 17 Jan 2013) | 10 lines
+
+Allow PaintInfo to carry all PaintBehavior flags
+https://bugs.webkit.org/show_bug.cgi?id=106980
+
+Reviewed by Beth Dakin.
+
+In r139908 I missed one instance of the PaintInfo constructor that should take PaintBehaviorNormal
+instead of "false".
+
+* rendering/RenderScrollbarPart.cpp:
+(WebCore::RenderScrollbarPart::paintIntoRect):
+------------------------------------------------------------------------"""),
+ "https://trac.webkit.org/r140066 by smfr"
+ " Allow PaintInfo to carry all PaintBehavior flags https://webkit.org/b/106980 Reviewed by dethbakin.")
+
+ def test_summarize_commit_log_rollout(self):
+ self.assertEqual(NewCommitBot._summarize_commit_log("""------------------------------------------------------------------------
+r143104 | commit-queue@webkit.org | 2013-02-16 09:09:01 -0800 (Sat, 16 Feb 2013) | 27 lines
+
+Unreviewed, rolling out r142734.
+http://trac.webkit.org/changeset/142734
+https://bugs.webkit.org/show_bug.cgi?id=110018
+
+"Triggered crashes on lots of websites" (Requested by ggaren
+on #webkit).
+
+Patch by Sheriff Bot <webkit.review.bot@gmail.com> on 2013-02-16
+
+Source/WebCore:
+
+------------------------------------------------------------------------"""),
+ "ggaren rolled out r142734 in https://trac.webkit.org/r143104: Triggered crashes on lots of websites")
+
+ self.assertEqual(NewCommitBot._summarize_commit_log("""------------------------------------------------------------------------
+r139884 | kov@webkit.org | 2013-01-16 08:26:10 -0800 (Wed, 16 Jan 2013) | 23 lines
+
+[GStreamer][Soup] Let GStreamer provide the buffer data is downloaded to, to avoid copying
+https://bugs.webkit.org/show_bug.cgi?id=105552
+
+Reverting 139877. It made a couple of API tests fail.
+
+* platform/graphics/gstreamer/GStreamerVersioning.cpp:
+* platform/graphics/gstreamer/GStreamerVersioning.h:
+* platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp:
+(StreamingClient):
+(_WebKitWebSrcPrivate):
+
+------------------------------------------------------------------------"""),
+ "kov rolled out 139877 in https://trac.webkit.org/r139884"
+ " [GStreamer][Soup] Let GStreamer provide the buffer data is downloaded to, to avoid copying"
+ " https://webkit.org/b/105552 It made a couple of API tests fail.")
+
+ self.assertEqual(NewCommitBot._summarize_commit_log("""------------------------------------------------------------------------
+r135487 | commit-queue@webkit.org | 2012-11-22 00:09:25 -0800 (Thu, 22 Nov 2012) | 52 lines
+
+Unreviewed, rolling out r134927 and r134944.
+http://trac.webkit.org/changeset/134927
+http://trac.webkit.org/changeset/134944
+https://bugs.webkit.org/show_bug.cgi?id=103028
+
+Reverting the reverts after merging. (Requested by vsevik on
+#webkit).
+
+Patch by Sheriff Bot <webkit.review.bot@gmail.com> on 2012-11-22
+
+* English.lproj/localizedStrings.js:
+* WebCore.gypi:
+* WebCore.vcproj/WebCore.vcproj:
+* inspector/compile-front-end.py:
+* inspector/front-end/AdvancedSearchController.js:
+* inspector/front-end/CallStackSidebarPane.js:
+
+------------------------------------------------------------------------"""),
+ "vsevik rolled out r134927 and r134944 in https://trac.webkit.org/r135487: Reverting the reverts after merging.")
def execute(self, options, args, tool, engine=QueueEngine):
self._options = options # FIXME: This code is wrong. Command.options is a list, this assumes an Options element!
self._tool = tool # FIXME: This code is wrong too! Command.bind_to_tool handles this!
- return engine(self.name, self, self._tool.wakeup_event).run()
+ return engine(self.name, self, self._tool.wakeup_event, self._options.seconds_to_sleep).run()
@classmethod
def _log_from_script_error_for_upload(cls, script_error, output_limit=None):
class MockQueueEngine(object):
- def __init__(self, name, queue, wakeup_event):
+ def __init__(self, name, queue, wakeup_event, seconds_to_sleep):
pass
def run(self):
tool = MockTool()
options = MockOptions()
options.ensure_value("confirm", False)
+ options.ensure_value("seconds_to_sleep", 120)
sheriffbot = SheriffBot()
sheriffbot.execute(options, [], tool, MockQueueEngine)
sheriffbot.begin_work_queue()
make_option("--status-host", action="store", dest="status_host", type="string", help="Hostname (e.g. localhost or commit.webkit.org) where status updates should be posted."),
make_option("--bot-id", action="store", dest="bot_id", type="string", help="Identifier for this bot (if multiple bots are running for a queue)"),
make_option("--irc-password", action="store", dest="irc_password", type="string", help="Password to use when communicating via IRC."),
+ make_option("--seconds-to-sleep", action="store", default=120, type="int", help="Number of seconds to sleep in the task queue."),
make_option("--port", action="store", dest="port", default=None, help="Specify a port (e.g., mac, qt, gtk, ...)."),
]