diff options
Diffstat (limited to 'WebKitTools/QueueStatusServer')
27 files changed, 930 insertions, 246 deletions
diff --git a/WebKitTools/QueueStatusServer/app.yaml b/WebKitTools/QueueStatusServer/app.yaml index 2756112..f6ff870 100644 --- a/WebKitTools/QueueStatusServer/app.yaml +++ b/WebKitTools/QueueStatusServer/app.yaml @@ -8,4 +8,4 @@ handlers: static_dir: stylesheets - url: /.* - script: queue_status.py + script: main.py diff --git a/WebKitTools/QueueStatusServer/cron.yaml b/WebKitTools/QueueStatusServer/cron.yaml new file mode 100644 index 0000000..09b9945 --- /dev/null +++ b/WebKitTools/QueueStatusServer/cron.yaml @@ -0,0 +1,4 @@ +cron: +- description: collect the garbage + url: /gc + schedule: every 4 hours diff --git a/WebKitTools/QueueStatusServer/filters/webkit_extras.py b/WebKitTools/QueueStatusServer/filters/webkit_extras.py index 6a08727..b645f78 100644 --- a/WebKitTools/QueueStatusServer/filters/webkit_extras.py +++ b/WebKitTools/QueueStatusServer/filters/webkit_extras.py @@ -26,19 +26,34 @@ # (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 re + from django.template.defaultfilters import stringfilter from google.appengine.ext import webapp -import re +register = webapp.template.create_template_register() bug_regexp = re.compile(r"bug (?P<bug_id>\d+)") patch_regexp = re.compile(r"patch (?P<patch_id>\d+)") +@register.filter @stringfilter def webkit_linkify(value): value = bug_regexp.sub(r'<a href="http://webkit.org/b/\g<bug_id>">bug \g<bug_id></a>', value) value = patch_regexp.sub(r'<a href="https://bugs.webkit.org/attachment.cgi?id=\g<patch_id>&action=prettypatch">patch \g<patch_id></a>', value) return value -register = webapp.template.create_template_register() -register.filter(webkit_linkify) +@register.filter +@stringfilter +def webkit_bug_id(value): + return '<a href="http://webkit.org/b/%s">%s</a>' % (value, value) + +@register.filter +@stringfilter +def webkit_attachment_id(value): + return '<a href="https://bugs.webkit.org/attachment.cgi?id=%s&action=prettypatch">%s</a>' % (value, value) + +@register.filter +@stringfilter +def results_link(status_id): + return '<a href="/results/%s">results</a>' % status_id diff --git a/WebKitTools/QueueStatusServer/handlers/__init__.py b/WebKitTools/QueueStatusServer/handlers/__init__.py new file mode 100644 index 0000000..ef65bee --- /dev/null +++ b/WebKitTools/QueueStatusServer/handlers/__init__.py @@ -0,0 +1 @@ +# Required for Python to search this directory for module files diff --git a/WebKitTools/QueueStatusServer/handlers/dashboard.py b/WebKitTools/QueueStatusServer/handlers/dashboard.py new file mode 100644 index 0000000..80f30ec --- /dev/null +++ b/WebKitTools/QueueStatusServer/handlers/dashboard.py @@ -0,0 +1,41 @@ +# Copyright (C) 2009 Google 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. + +from google.appengine.ext import webapp +from google.appengine.ext.webapp import template + +from model.attachment import Attachment + +class Dashboard(webapp.RequestHandler): + def get(self): + attachments = Attachment.recent(limit=25) + + template_values = { + "summaries" : [attachment.summary() for attachment in attachments], + } + self.response.out.write(template.render("templates/dashboard.html", template_values)) diff --git a/WebKitTools/QueueStatusServer/handlers/gc.py b/WebKitTools/QueueStatusServer/handlers/gc.py new file mode 100644 index 0000000..d04ee4d --- /dev/null +++ b/WebKitTools/QueueStatusServer/handlers/gc.py @@ -0,0 +1,44 @@ +# Copyright (C) 2009 Google 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. + +from google.appengine.ext import webapp + +from model.queuestatus import QueueStatus + + +class GC(webapp.RequestHandler): + def get(self): + statuses = QueueStatus.all().order("-date") + seen_queues = set() + for status in statuses: + if status.active_patch_id or status.active_bug_id: + continue + if status.queue_name in seen_queues: + status.delete() + seen_queues.add(status.queue_name) + self.response.out.write("Done!") diff --git a/WebKitTools/QueueStatusServer/handlers/patch.py b/WebKitTools/QueueStatusServer/handlers/patch.py new file mode 100644 index 0000000..3219212 --- /dev/null +++ b/WebKitTools/QueueStatusServer/handlers/patch.py @@ -0,0 +1,53 @@ +# Copyright (C) 2009 Google 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. + +from google.appengine.ext import webapp +from google.appengine.ext.webapp import template + +from model.queuestatus import QueueStatus + + +class Patch(webapp.RequestHandler): + def get(self, attachment_id_string): + attachment_id = int(attachment_id_string) + statuses = QueueStatus.all().filter("active_patch_id =", attachment_id).order("-date") + + bug_id = None + queue_status = {} + for status in statuses: + bug_id = status.active_bug_id # Should be the same for every status. + per_queue_statuses = queue_status.get(status.queue_name, []) + per_queue_statuses.append(status) + queue_status[status.queue_name] = per_queue_statuses + + template_values = { + "attachment_id" : attachment_id, + "bug_id" : bug_id, + "queue_status" : queue_status, + } + self.response.out.write(template.render("templates/patch.html", template_values)) diff --git a/WebKitTools/QueueStatusServer/handlers/patchstatus.py b/WebKitTools/QueueStatusServer/handlers/patchstatus.py new file mode 100644 index 0000000..1a5422e --- /dev/null +++ b/WebKitTools/QueueStatusServer/handlers/patchstatus.py @@ -0,0 +1,40 @@ +# Copyright (C) 2009 Google 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. + +from google.appengine.ext import webapp + +from model.queuestatus import QueueStatus + + +class PatchStatus(webapp.RequestHandler): + def get(self, queue_name, attachment_id): + statuses = QueueStatus.all().filter('queue_name =', queue_name).filter('active_patch_id =', int(attachment_id)).order('-date').fetch(1) + if not statuses: + self.error(404) + return + self.response.out.write(statuses[0].message) diff --git a/WebKitTools/QueueStatusServer/handlers/recentstatus.py b/WebKitTools/QueueStatusServer/handlers/recentstatus.py new file mode 100644 index 0000000..d1df78c --- /dev/null +++ b/WebKitTools/QueueStatusServer/handlers/recentstatus.py @@ -0,0 +1,57 @@ +# Copyright (C) 2009 Google 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. + +from google.appengine.ext import webapp +from google.appengine.ext.webapp import template + +from model.queues import queues +from model.queuestatus import QueueStatus + +class RecentStatus(webapp.RequestHandler): + def _title_case(self, string): + words = string.split(" ") + words = map(lambda word: word.capitalize(), words) + return " ".join(words) + + def _pretty_queue_name(self, queue_name): + return self._title_case(queue_name.replace("-", " ")) + + # We could change "/" to just redirect to /queue-status/commit-queue in the future + # at which point we would not need a default value for queue_name here. + def get(self, queue_name="commit-queue"): + queue_status = {} + for queue in queues: + statuses = QueueStatus.all().filter("queue_name =", queue).order("-date").fetch(6) + if not statuses: + continue + queue_status[queue] = statuses + + template_values = { + "queue_status" : queue_status, + } + self.response.out.write(template.render("templates/recentstatus.html", template_values)) diff --git a/WebKitTools/QueueStatusServer/handlers/showresults.py b/WebKitTools/QueueStatusServer/handlers/showresults.py new file mode 100644 index 0000000..e4cb71b --- /dev/null +++ b/WebKitTools/QueueStatusServer/handlers/showresults.py @@ -0,0 +1,41 @@ +# Copyright (C) 2009 Google 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. + +from google.appengine.ext import webapp + +from model.queuestatus import QueueStatus + + +class ShowResults(webapp.RequestHandler): + def get(self, status_id): + status = QueueStatus.get_by_id(int(status_id)) + if not status: + self.error(404) + return + self.response.headers["Content-Type"] = "text/plain; charset=utf-8" + self.response.out.write(status.results_file) diff --git a/WebKitTools/QueueStatusServer/handlers/statusbubble.py b/WebKitTools/QueueStatusServer/handlers/statusbubble.py new file mode 100644 index 0000000..d52509f --- /dev/null +++ b/WebKitTools/QueueStatusServer/handlers/statusbubble.py @@ -0,0 +1,42 @@ +# Copyright (C) 2009 Google 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. + +from google.appengine.ext import webapp +from google.appengine.ext.webapp import template + +from model.attachment import Attachment + + +class StatusBubble(webapp.RequestHandler): + def get(self, attachment_id): + attachment = Attachment(int(attachment_id)) + + template_values = { + "summary" : attachment.summary() + } + self.response.out.write(template.render("templates/statusbubble.html", template_values)) diff --git a/WebKitTools/QueueStatusServer/handlers/updatestatus.py b/WebKitTools/QueueStatusServer/handlers/updatestatus.py new file mode 100644 index 0000000..3ad7b77 --- /dev/null +++ b/WebKitTools/QueueStatusServer/handlers/updatestatus.py @@ -0,0 +1,67 @@ +# Copyright (C) 2009 Google 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. + +from google.appengine.api import users +from google.appengine.ext import webapp, db +from google.appengine.ext.webapp import template + +from model.attachment import Attachment +from model.queuestatus import QueueStatus + + +class UpdateStatus(webapp.RequestHandler): + def get(self): + self.response.out.write(template.render("templates/updatestatus.html", None)) + + def _int_from_request(self, name): + string_value = self.request.get(name) + try: + int_value = int(string_value) + return int_value + except ValueError, TypeError: + pass + return None + + def post(self): + queue_status = QueueStatus() + + if users.get_current_user(): + queue_status.author = users.get_current_user() + + bug_id = self._int_from_request("bug_id") + patch_id = self._int_from_request("patch_id") + queue_name = self.request.get("queue_name") + queue_status.queue_name = queue_name + queue_status.active_bug_id = bug_id + queue_status.active_patch_id = patch_id + queue_status.message = self.request.get("status") + results_file = self.request.get("results_file") + queue_status.results_file = db.Blob(str(results_file)) + queue_status.put() + Attachment.dirty(patch_id) + self.response.out.write(queue_status.key().id()) diff --git a/WebKitTools/QueueStatusServer/index.html b/WebKitTools/QueueStatusServer/index.html deleted file mode 100644 index fbd51fb..0000000 --- a/WebKitTools/QueueStatusServer/index.html +++ /dev/null @@ -1,29 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title>WebKit Commit Queue Status</title> - <link type="text/css" rel="stylesheet" href="/stylesheets/main.css" /> -</head> -<body> - <center> - <div id="current_status"> - {{ last_status.message|force_escape|urlize|webkit_linkify|safe }} - <div id="last_status_date">As of {{ last_status.date|timesince }} ago</div> - </div> - - <table id="recent_status_table"> - <tr> - <th colspan=2>Recent Status</th> - </tr> - {% for recent_status in recent_statuses %} - <tr> - <td class='status_date'>{{ recent_status.date|timesince }} ago</td> - <td class="recent_status">{{ recent_status.message|force_escape|urlize|webkit_linkify|safe }}</td> - </tr> - {% endfor %} - </table> - - <div id="footer"><a href="https://bugs.webkit.org/buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=commit-queue%2B">queued bugs</a> | <a href="http://trac.webkit.org/wiki/CommitQueue">documentation</a> | <a href="http://webkit.org/">webkit.org</a></div> - </center> -</body> -</html> diff --git a/WebKitTools/QueueStatusServer/index.yaml b/WebKitTools/QueueStatusServer/index.yaml index bf11262..60ba3df 100644 --- a/WebKitTools/QueueStatusServer/index.yaml +++ b/WebKitTools/QueueStatusServer/index.yaml @@ -13,6 +13,12 @@ indexes: - kind: QueueStatus properties: - name: active_patch_id + - name: date + direction: desc + +- kind: QueueStatus + properties: + - name: active_patch_id - name: queue_name - name: date direction: desc diff --git a/WebKitTools/QueueStatusServer/main.py b/WebKitTools/QueueStatusServer/main.py new file mode 100644 index 0000000..8efc771 --- /dev/null +++ b/WebKitTools/QueueStatusServer/main.py @@ -0,0 +1,65 @@ +# Copyright (C) 2009 Google 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. + +# Request a modern Django +from google.appengine.dist import use_library +use_library('django', '1.1') + +from google.appengine.ext import webapp +from google.appengine.ext.webapp.util import run_wsgi_app + +from handlers.dashboard import Dashboard +from handlers.gc import GC +from handlers.patch import Patch +from handlers.patchstatus import PatchStatus +from handlers.recentstatus import RecentStatus +from handlers.showresults import ShowResults +from handlers.statusbubble import StatusBubble +from handlers.updatestatus import UpdateStatus + +webapp.template.register_template_library('filters.webkit_extras') + +routes = [ + ('/', RecentStatus), + ('/dashboard', Dashboard), + ('/gc', GC), + (r'/patch-status/(.*)/(.*)', PatchStatus), + (r'/patch/(.*)', Patch), + (r'/results/(.*)', ShowResults), + (r'/status-bubble/(.*)', StatusBubble), + (r'/queue-status/(.*)', RecentStatus), + ('/update-status', UpdateStatus), +] + +application = webapp.WSGIApplication(routes, debug=True) + +def main(): + run_wsgi_app(application) + +if __name__ == "__main__": + main() diff --git a/WebKitTools/QueueStatusServer/model/__init__.py b/WebKitTools/QueueStatusServer/model/__init__.py new file mode 100644 index 0000000..ef65bee --- /dev/null +++ b/WebKitTools/QueueStatusServer/model/__init__.py @@ -0,0 +1 @@ +# Required for Python to search this directory for module files diff --git a/WebKitTools/QueueStatusServer/model/attachment.py b/WebKitTools/QueueStatusServer/model/attachment.py new file mode 100644 index 0000000..751f78e --- /dev/null +++ b/WebKitTools/QueueStatusServer/model/attachment.py @@ -0,0 +1,109 @@ +# Copyright (C) 2009 Google 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 re + +from google.appengine.api import memcache + +from model.queues import queues +from model.queuestatus import QueueStatus + + +class Attachment(object): + @classmethod + def dirty(cls, attachment_id): + memcache.delete(str(attachment_id), namespace="attachment-summary") + + @classmethod + def recent(cls, limit=1): + statuses = QueueStatus.all().order("-date") + # Notice that we use both a set and a list here to keep the -date ordering. + ids = [] + visited_ids = set() + for status in statuses: + attachment_id = status.active_patch_id + if not attachment_id: + continue + if attachment_id in visited_ids: + continue + visited_ids.add(attachment_id) + ids.append(attachment_id) + if len(visited_ids) >= limit: + break + return map(cls, ids) + + def __init__(self, attachment_id): + self.id = attachment_id + self._summary = None + + def summary(self): + if self._summary: + return self._summary + self._summary = memcache.get(str(self.id), namespace="attachment-summary") + if self._summary: + return self._summary + self._summary = self._fetch_summary() + memcache.set(str(self.id), self._summary, namespace="attachment-summary") + return self._summary + + def _dash_to_underscore(self, dashed_name): + regexp = re.compile("-") + return regexp.sub("_", dashed_name) + + def _state_from_status(self, status): + table = { + "Pass" : "pass", + "Fail" : "fail", + } + state = table.get(status.message) + if state: + return state + if status.message.startswith("Error:"): + return "error" + if status: + return "pending" + return None + + def _fetch_summary(self): + summary = { "attachment_id" : self.id } + + first_status = QueueStatus.all().filter('active_patch_id =', self.id).get() + if not first_status: + # We don't have any record of this attachment. + return summary + summary["bug_id"] = first_status.active_bug_id + + for queue in queues: + summary[queue] = None + status = QueueStatus.all().filter('queue_name =', queue).filter('active_patch_id =', self.id).order('-date').get() + if status: + summary[self._dash_to_underscore(queue)] = { + "state" : self._state_from_status(status), + "status" : status, + } + return summary diff --git a/WebKitTools/QueueStatusServer/model/queues.py b/WebKitTools/QueueStatusServer/model/queues.py new file mode 100644 index 0000000..8d48aff --- /dev/null +++ b/WebKitTools/QueueStatusServer/model/queues.py @@ -0,0 +1,36 @@ +# Copyright (C) 2009 Google 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. + +queues = [ + "style-queue", + "chromium-ews", + "qt-ews", + "mac-ews", + "gtk-ews", + "commit-queue", +] diff --git a/WebKitTools/QueueStatusServer/model/queuestatus.py b/WebKitTools/QueueStatusServer/model/queuestatus.py new file mode 100644 index 0000000..3d7e599 --- /dev/null +++ b/WebKitTools/QueueStatusServer/model/queuestatus.py @@ -0,0 +1,38 @@ +# Copyright (C) 2009 Google 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. + +from google.appengine.ext import db + +class QueueStatus(db.Model): + author = db.UserProperty() + queue_name = db.StringProperty() + active_bug_id = db.IntegerProperty() + active_patch_id = db.IntegerProperty() + message = db.StringProperty(multiline=True) + date = db.DateTimeProperty(auto_now_add=True) + results_file = db.BlobProperty() diff --git a/WebKitTools/QueueStatusServer/queue_status.py b/WebKitTools/QueueStatusServer/queue_status.py deleted file mode 100644 index 65197bb..0000000 --- a/WebKitTools/QueueStatusServer/queue_status.py +++ /dev/null @@ -1,177 +0,0 @@ -# Copyright (C) 2009 Google 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 cgi -import os - -# Request a modern Django -from google.appengine.dist import use_library -use_library('django', '1.1') - -from google.appengine.ext.webapp import template -from google.appengine.api import users -from google.appengine.ext import webapp, db -from google.appengine.ext.webapp.util import run_wsgi_app - -webapp.template.register_template_library('filters.webkit_extras') - - -class QueueStatus(db.Model): - author = db.UserProperty() - queue_name = db.StringProperty() - active_bug_id = db.IntegerProperty() - active_patch_id = db.IntegerProperty() - message = db.StringProperty(multiline=True) - date = db.DateTimeProperty(auto_now_add=True) - results_file = db.BlobProperty() - - -class MainPage(webapp.RequestHandler): - def get(self): - statuses_query = QueueStatus.all().filter('queue_name =', 'commit-queue').order('-date') - statuses = statuses_query.fetch(6) - if not statuses: - return self.response.out.write("No status to report.") - template_values = { - 'last_status' : statuses[0], - 'recent_statuses' : statuses[1:], - } - self.response.out.write(template.render('index.html', template_values)) - - -class PatchStatus(webapp.RequestHandler): - def get(self, queue_name, attachment_id): - statuses = QueueStatus.all().filter('queue_name =', queue_name).filter('active_patch_id =', int(attachment_id)).order('-date').fetch(1) - if not statuses: - self.error(404) - return - self.response.out.write(statuses[0].message) - - -class StatusSummary(object): - def _status_to_code(self, status): - code_names = { - "Pass": "pass", - "Pending": "pending", - "Fail": "fail", - "Error": "error", - } - return code_names.get(status, "none") - - def _queue_name_to_code(self, queue_name): - code_names = { - "style-queue": "style", - } - return code_names[queue_name] - - queues = [ - "style-queue", - ] - - def __init__(self): - self._summary = {} - - def summarize(self, attachment_id): - if self._summary.get(attachment_id): - return self._summary.get(attachment_id) - - attachment_summary = {} - for queue in self.queues: - statuses = QueueStatus.all().filter('queue_name =', queue).filter('active_patch_id =', attachment_id).order('-date').fetch(1) - status_code = self._status_to_code(statuses[0].message if statuses else None) - queue_code = self._queue_name_to_code(queue) - attachment_summary[queue_code] = status_code - - self._summary[attachment_id] = attachment_summary - return attachment_summary - - -class StatusBubble(webapp.RequestHandler): - def get(self, attachment_id): - status_summary = StatusSummary() - template_values = { - "queue_status" : status_summary.summarize(int(attachment_id)), - } - self.response.out.write(template.render('status_bubble.html', template_values)) - - -class UpdateStatus(webapp.RequestHandler): - def get(self): - self.response.out.write(template.render('update_status.html', None)) - - def _int_from_request(self, name): - string_value = self.request.get(name) - try: - int_value = int(string_value) - return int_value - except ValueError, TypeError: - pass - return None - - def post(self): - queue_status = QueueStatus() - - if users.get_current_user(): - queue_status.author = users.get_current_user() - - queue_name = self.request.get('queue_name') - queue_status.queue_name = queue_name - queue_status.active_bug_id = self._int_from_request('bug_id') - queue_status.active_patch_id = self._int_from_request('patch_id') - queue_status.message = self.request.get('status') - results_file = self.request.get("results_file") - queue_status.results_file = db.Blob(results_file) - queue_status.put() - self.redirect('/') - - -class ShowResults(webapp.RequestHandler): - def get(self, status_id): - status = QueueStatus.get_by_id(int(status_id)) - if not status: - self.error(404) - return - self.response.headers["Content-Type"] = "text/plain" - self.response.out.write(status.results_file) - - -routes = [ - ('/', MainPage), - ('/update-status', UpdateStatus), - (r'/patch-status/(.*)/(.*)', PatchStatus), - (r'/status-bubble/(.*)', StatusBubble), - (r'/results/(.*)', ShowResults) -] - -application = webapp.WSGIApplication(routes, debug=True) - -def main(): - run_wsgi_app(application) - -if __name__ == "__main__": - main() diff --git a/WebKitTools/QueueStatusServer/status_bubble.html b/WebKitTools/QueueStatusServer/status_bubble.html deleted file mode 100644 index f8959d9..0000000 --- a/WebKitTools/QueueStatusServer/status_bubble.html +++ /dev/null @@ -1,36 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<style> -body { - font-family: Verdana, sans-serif; - margin: 0px; - padding: 0px; -} -.status { - display: block; - float: left; - margin: 1px; - padding: 1px 2px; - border-radius: 5px; - border: 1px solid #AAA; - font-size: 11px; -} -.pass { - background-color: #8FDF5F; - border: 1px solid #4F8530; -} -.fail { - background-color: #E98080; - border: 1px solid #A77272; -} -.pending { - background-color: #FFFC6C; - border: 1px solid #C5C56D; -} -</style> -</head> -<body>{% for key, value in queue_status.items %} -<div class="status {{value}}" title="{{key}}: {{value}}">{{key}}</div>{% endfor %} -</body> -</html> diff --git a/WebKitTools/QueueStatusServer/stylesheets/dashboard.css b/WebKitTools/QueueStatusServer/stylesheets/dashboard.css new file mode 100644 index 0000000..1ecf2eb --- /dev/null +++ b/WebKitTools/QueueStatusServer/stylesheets/dashboard.css @@ -0,0 +1,80 @@ +body { + font-family: Verdana, Helvetica, sans-serif; + width: 600px; + padding: 0px; + color: #444; +} +h1 { + background-color: #EEE; + color: #444; + font-size: 14pt; + font-style: italic; + margin: 0px; + padding: 5px; +} +h2 { + background-color: #AAA; + color: white; + font-weight: bold; + font-size: 9pt; + margin: 0px; + padding: 5px; +} +ul { + margin: 0px; + padding: 0px; + list-style: none; +} +li { + padding: 5px; +} +table { + border-spacing: 0px; +} +th { + background-color: #AAA; + color: white; + padding: 5px; + width: 100px; + font-size: 9pt; +} +td { + text-align: center; +} +tr:hover, li:hover { + background-color: #EEE; +} +.status-date { + color: #AAA; + float: right; + font-size: 8pt; +} +.status { + margin: 1px; + padding: 1px 2px; + font-size: 9pt; + border: 1px solid transparent; +} +.status:hover { + border: 1px solid black; +} +.pass { + background-color: #8FDF5F; + cursor: pointer; + /* border: 1px solid #4F8530; */ +} +.fail { + background-color: #E98080; + cursor: pointer; + /* border: 1px solid #A77272; */ +} +.pending { + background-color: #FFFC6C; + cursor: pointer; + /* border: 1px solid #C5C56D; */ +} +.error { + background-color: #E0B0FF; + cursor: pointer; + /* border: 1px solid #ACA0B3; */ +} diff --git a/WebKitTools/QueueStatusServer/templates/dashboard.html b/WebKitTools/QueueStatusServer/templates/dashboard.html new file mode 100644 index 0000000..84ecabb --- /dev/null +++ b/WebKitTools/QueueStatusServer/templates/dashboard.html @@ -0,0 +1,64 @@ +<!DOCTYPE html> +<html> +<head> +<title>WebKit Bot Status</title> +<link type="text/css" rel="stylesheet" href="/stylesheets/dashboard.css" /> +<script> +function statusDetail(patch_id) { + // FIXME: We'd like to use AJAX to show the details on this page. + window.location = "/patch/" + patch_id +} +</script> +</head> +<body> +<h1>WebKit Bot Status</h1> +<table> + <theader> + <tr> + <th>Bug</th> + <th>Attachment</th> + <th>Style</th> + <th>Chromium</th> + <th>Qt</th> + <th>Mac</th> + <th>Gtk</th> + <th>Commit</th> + </tr> + </thead> + <tbody>{% for summary in summaries %} + <tr> + <td class="status"> + {{ summary.bug_id|force_escape|webkit_bug_id|safe }} + </td> + <td class="status"> + {{ summary.attachment_id|force_escape|webkit_attachment_id|safe }} + </td> + <!-- FIXME: Find some way to remove this copy-and-paste code! --> + <td class="status {{ summary.style_queue.state }}"{% if summary.style_queue.status %} + onclick="statusDetail({{ summary.attachment_id }})" + title="{{ summary.style_queue.status.date|timesince }}"{% endif %}> + </td> + <td class="status {{ summary.chromium_ews.state }}"{% if summary.chromium_ews.status %} + onclick="statusDetail({{ summary.attachment_id }})" + title="{{ summary.chromium_ews.status.date|timesince }} ago"{% endif %}> + </td> + <td class="status {{ summary.qt_ews.state }}"{% if summary.qt_ews.status %} + onclick="statusDetail({{ summary.attachment_id }})" + title="{{ summary.qt_ews.status.date|timesince }} ago"{% endif %}> + </td> + <td class="status {{ summary.mac_ews.state }}"{% if summary.mac_ews.status %} + onclick="statusDetail({{ summary.attachment_id }})" + title="{{ summary.mac_ews.status.date|timesince }} ago"{% endif %}> + </td> + <td class="status {{ summary.gtk_ews.state }}"{% if summary.gtk_ews.status %} + onclick="statusDetail({{ summary.attachment_id }})" + title="{{ summary.gtk_ews.status.date|timesince }} ago"{% endif %}> + </td> + <td class="status {{ summary.commit_queue.state }}"{% if summary.commit_queue.status %} + onclick="statusDetail({{ summary.attachment_id }})" + title="{{ summary.commit_queue.status.date|timesince }} ago"{% endif %}> + </td> + </tr>{% endfor %} + </tbody> +</table> +</html> diff --git a/WebKitTools/QueueStatusServer/templates/patch.html b/WebKitTools/QueueStatusServer/templates/patch.html new file mode 100644 index 0000000..de334a5 --- /dev/null +++ b/WebKitTools/QueueStatusServer/templates/patch.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> +<head> +<title>Patch Status</title> +<link type="text/css" rel="stylesheet" href="/stylesheets/dashboard.css" /> +</head> +<body> +<h1> + Patch {{ attachment_id|force_escape|webkit_attachment_id|safe }} (Bug {{ bug_id|force_escape|webkit_bug_id|safe }}) +</h1>{% for queue_name, statuses in queue_status.items %} +<div class="status-details"> + <h2>{{ queue_name }}</h2> + <ul>{% for status in statuses %} + <li> + <span class="status-message">{{ status.message|force_escape|urlize|webkit_linkify|safe }}</span>{% if status.results_file %} + <span class="status-results">[{{ status.key.id|results_link|safe }}]</span>{% endif %} + <span class="status-date">{{ status.date|timesince }} ago</span> + </li>{% endfor %} + </ul> +</div>{% endfor %} +</html> diff --git a/WebKitTools/QueueStatusServer/templates/recentstatus.html b/WebKitTools/QueueStatusServer/templates/recentstatus.html new file mode 100644 index 0000000..2bb9fbb --- /dev/null +++ b/WebKitTools/QueueStatusServer/templates/recentstatus.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<html> +<head> +<title>WebKit Queue Status</title> +<link type="text/css" rel="stylesheet" href="/stylesheets/dashboard.css" /> +</head> +<body> +<h1>WebKit Queue Status</h1>{% for queue_name, statuses in queue_status.items %} +<div class="status-details"> + <h2>{{ queue_name }}</h2> + <ul>{% for status in statuses %} + <li>{% if status.active_bug_id %} + <span class="status-bug"> + Patch {{ status.active_patch_id|force_escape|webkit_attachment_id|safe }} from bug + {{ status.active_bug_id|force_escape|webkit_bug_id|safe }}: + </span>{% endif %} + <span class="status-message">{{ status.message|force_escape|urlize|webkit_linkify|safe }}</span>{% if status.results_file %} + <span class="status-results">[{{ status.key.id|results_link|safe }}]</span>{% endif %} + <span class="status-date">{{ status.date|timesince }} ago</span> + </li>{% endfor %} + </ul> +</div>{% endfor %} +</body> +</html> diff --git a/WebKitTools/QueueStatusServer/templates/statusbubble.html b/WebKitTools/QueueStatusServer/templates/statusbubble.html new file mode 100644 index 0000000..d1f331c --- /dev/null +++ b/WebKitTools/QueueStatusServer/templates/statusbubble.html @@ -0,0 +1,77 @@ +<!DOCTYPE html> +<html> +<head> +<style> +body { + font-family: Verdana, sans-serif; + margin: 0px; + padding: 0px; +} +.status { + display: block; + float: left; + margin: 1px; + padding: 1px 2px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + border: 1px solid #AAA; + background-color: white; + font-size: 11px; +} +.pass { + background-color: #8FDF5F; + border: 1px solid #4F8530; + cursor: pointer; +} +.fail { + background-color: #E98080; + border: 1px solid #A77272; + cursor: pointer; +} +.pending { + background-color: #FFFC6C; + border: 1px solid #C5C56D; + cursor: pointer; +} +.error { + background-color: #E0B0FF; + border: 1px solid #ACA0B3; + cursor: pointer; +} +</style> +<script> +function statusDetail(patch_id) { + top.location = "/patch/" + patch_id +} +</script> +</head> +<body> +<!-- FIXME: Find some way to remove this copy-and-paste code! --> +<div class="status {{ summary.style_queue.state }}"{% if summary.style_queue.status %} + onclick="statusDetail({{ summary.attachment_id }})" + title="{{ summary.style_queue.status.date|timesince }} ago"{% endif %}> + style +</div> +<div class="status {{ summary.chromium_ews.state }}"{% if summary.chromium_ews.status %} + onclick="statusDetail({{ summary.attachment_id }})" + title="{{ summary.chromium_ews.status.date|timesince }} ago"{% endif %}> + chromium +</div> +<div class="status {{ summary.qt_ews.state }}"{% if summary.qt_ews.status %} + onclick="statusDetail({{ summary.attachment_id }})" + title="{{ summary.qt_ews.status.date|timesince }} ago"{% endif %}> + qt +</div> +<div class="status {{ summary.gtk_ews.state }}"{% if summary.gtk_ews.status %} + onclick="statusDetail({{ summary.attachment_id }})" + title="{{ summary.gtk_ews.status.date|timesince }} ago"{% endif %}> + gtk +</div> +<div class="status {{ summary.mac_ews.state }}"{% if summary.mac_ews.status %} + onclick="statusDetail({{ summary.attachment_id }})" + title="{{ summary.mac_ews.status.date|timesince }} ago"{% endif %}> + mac +</div> +</body> +</html> diff --git a/WebKitTools/QueueStatusServer/update_status.html b/WebKitTools/QueueStatusServer/templates/updatestatus.html index 9343c60..9343c60 100644 --- a/WebKitTools/QueueStatusServer/update_status.html +++ b/WebKitTools/QueueStatusServer/templates/updatestatus.html |
