diff options
Diffstat (limited to 'WebKitTools/QueueStatusServer')
-rw-r--r-- | WebKitTools/QueueStatusServer/handlers/queuestatus.py | 58 | ||||
-rw-r--r-- | WebKitTools/QueueStatusServer/handlers/recentstatus.py | 76 | ||||
-rw-r--r-- | WebKitTools/QueueStatusServer/main.py | 7 | ||||
-rw-r--r-- | WebKitTools/QueueStatusServer/model/queues.py | 18 | ||||
-rw-r--r-- | WebKitTools/QueueStatusServer/templates/queuestatus.html | 44 | ||||
-rw-r--r-- | WebKitTools/QueueStatusServer/templates/recentstatus.html | 60 |
6 files changed, 225 insertions, 38 deletions
diff --git a/WebKitTools/QueueStatusServer/handlers/queuestatus.py b/WebKitTools/QueueStatusServer/handlers/queuestatus.py new file mode 100644 index 0000000..6282a98 --- /dev/null +++ b/WebKitTools/QueueStatusServer/handlers/queuestatus.py @@ -0,0 +1,58 @@ +# Copyright (C) 2010 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, display_name_for_queue +from model.workitems import WorkItems + +from model import queuestatus + + +class QueueStatus(webapp.RequestHandler): + def _rows_for_work_items(self, work_items): + if not work_items: + return [] + rows = [] + for item_id in work_items.item_ids: + rows.append({ + "attachment_id": item_id, + "bug_id": 1, + }) + return rows + + def get(self, queue_name): + work_items = WorkItems.all().filter("queue_name =", queue_name).get() + statuses = queuestatus.QueueStatus.all().filter("queue_name =", queue_name).order("-date").fetch(6) + template_values = { + "display_queue_name": display_name_for_queue(queue_name), + "work_item_rows": self._rows_for_work_items(work_items), + "statuses": statuses, + } + self.response.out.write(template.render("templates/queuestatus.html", template_values)) diff --git a/WebKitTools/QueueStatusServer/handlers/recentstatus.py b/WebKitTools/QueueStatusServer/handlers/recentstatus.py index d1df78c..e2b8c2f 100644 --- a/WebKitTools/QueueStatusServer/handlers/recentstatus.py +++ b/WebKitTools/QueueStatusServer/handlers/recentstatus.py @@ -26,32 +26,68 @@ # (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 datetime + from google.appengine.ext import webapp from google.appengine.ext.webapp import template -from model.queues import queues +from model.queues import queues, display_name_for_queue from model.queuestatus import QueueStatus +from model.workitems import WorkItems + + +class QueueBubble(object): + """View support class for recentstatus.html""" + def __init__(self, queue_name): + self._queue_name = queue_name + self._work_items = WorkItems.all().filter("queue_name =", queue_name).get() + self._last_status = QueueStatus.all().filter("queue_name =", queue_name).order("-date").get() + + def name(self): + return self._queue_name + + def display_name(self): + return display_name_for_queue(self._queue_name) + + def _last_status_date(self): + if not self._last_status: + return None + return self._last_status.date + + def last_heard_from(self): + if not self._work_items: + return self._last_status_date() + return max(self._last_status_date(), self._work_items.date) + + def is_alive(self): + if not self.last_heard_from(): + return False + return self.last_heard_from() > (datetime.datetime.now() - datetime.timedelta(minutes=30)) + + def status_class(self): + if not self.is_alive(): + return "dead" + if self.pending_items_count() > 1: + return "behind" + return "alive" + + def status_text(self): + if not self._work_items: + return "Offline" + if not self._work_items.item_ids: + return "Idle" + return self._last_status.message + + def pending_items_count(self): + if not self._work_items: + return 0 + return len(self._work_items.item_ids) + -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 +class QueuesOverview(webapp.RequestHandler): + def get(self): template_values = { - "queue_status" : queue_status, + "queues": [QueueBubble(queue_name) for queue_name in queues], } self.response.out.write(template.render("templates/recentstatus.html", template_values)) diff --git a/WebKitTools/QueueStatusServer/main.py b/WebKitTools/QueueStatusServer/main.py index fb6fc4b..e550dc5 100644 --- a/WebKitTools/QueueStatusServer/main.py +++ b/WebKitTools/QueueStatusServer/main.py @@ -37,7 +37,8 @@ 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.queuestatus import QueueStatus +from handlers.recentstatus import QueuesOverview from handlers.showresults import ShowResults from handlers.statusbubble import StatusBubble from handlers.svnrevision import SVNRevision @@ -49,7 +50,7 @@ from handlers.updateworkitems import UpdateWorkItems webapp.template.register_template_library('filters.webkit_extras') routes = [ - ('/', RecentStatus), + ('/', QueuesOverview), ('/dashboard', Dashboard), ('/gc', GC), (r'/patch-status/(.*)/(.*)', PatchStatus), @@ -57,7 +58,7 @@ routes = [ (r'/results/(.*)', ShowResults), (r'/status-bubble/(.*)', StatusBubble), (r'/svn-revision/(.*)', SVNRevision), - (r'/queue-status/(.*)', RecentStatus), + (r'/queue-status/(.*)', QueueStatus), ('/update-status', UpdateStatus), ('/update-work-items', UpdateWorkItems), ('/update-svn-revision', UpdateSVNRevision), diff --git a/WebKitTools/QueueStatusServer/model/queues.py b/WebKitTools/QueueStatusServer/model/queues.py index 46f2f15..2f0884f 100644 --- a/WebKitTools/QueueStatusServer/model/queues.py +++ b/WebKitTools/QueueStatusServer/model/queues.py @@ -41,6 +41,24 @@ queues = [ ] +# FIXME: We need some sort of Queue object. +def _title_case(string): + words = string.split(" ") + words = map(lambda word: word.capitalize(), words) + return " ".join(words) + + +def display_name_for_queue(queue_name): + # HACK: chromium-ews is incorrectly named. + display_name = queue_name.replace("chromium-ews", "cr-linux-ews") + + display_name = display_name.replace("-", " ") + display_name = display_name.replace("cr", "chromium") + display_name = _title_case(display_name) + display_name = display_name.replace("Ews", "EWS") + return display_name + + def name_with_underscores(dashed_name): regexp = re.compile("-") return regexp.sub("_", dashed_name) diff --git a/WebKitTools/QueueStatusServer/templates/queuestatus.html b/WebKitTools/QueueStatusServer/templates/queuestatus.html new file mode 100644 index 0000000..38c125f --- /dev/null +++ b/WebKitTools/QueueStatusServer/templates/queuestatus.html @@ -0,0 +1,44 @@ +<!DOCTYPE html> +<html> +<head> +<title>{{ display_queue_name }} Status</title> +<link type="text/css" rel="stylesheet" href="/stylesheets/dashboard.css" /> +</head> +<body> +<h1>{{ display_queue_name }} Status</h1> + +<h3>Recent Status</h3> + +<div class="status-details"> + <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> + +<h3>Patches in queue</h3> +<table> + <tr><th>Position</th><th>Patch</th></tr> + {% for row in work_item_rows %} + <tr> + <td>#{{ forloop.counter }}</td> + <td> + {{ row.attachment_id|force_escape|webkit_attachment_id|safe }} + </td> + </tr> + {% endfor %} +</table> + +</body> +</html> diff --git a/WebKitTools/QueueStatusServer/templates/recentstatus.html b/WebKitTools/QueueStatusServer/templates/recentstatus.html index 2bb9fbb..808d8d7 100644 --- a/WebKitTools/QueueStatusServer/templates/recentstatus.html +++ b/WebKitTools/QueueStatusServer/templates/recentstatus.html @@ -3,22 +3,52 @@ <head> <title>WebKit Queue Status</title> <link type="text/css" rel="stylesheet" href="/stylesheets/dashboard.css" /> +<style> +.queue_bubble { + border: 1px solid black; + margin-bottom: 10px; + border-radius: 10px; + padding: 5px; +} +.queue_name { + float:left; +} +.last_heard_from { + float: right; +} +.status_text { + clear: both; +} +.alive { + background-color: #8FDF5F; +} +.behind { + background-color: #FFFC6C; +} +.dead { + background-color: #E98080; +} +</style> </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 %} +<h1>WebKit Queue Status</h1> +{% for queue in queues %} +<div class="queue_bubble {{ queue.status_class }}"> + <div class="queue_name"> + <a href="/queue-status/{{ queue.name }}"> + {{ queue.display_name }} + </a> + </div> + {% if queue.last_heard_from %} + <div class="last_heard_from">{{ queue.last_heard_from|timesince }} ago</div> + {% endif %} + <div class="status_text"> + Status: {{ queue.status_text|force_escape|urlize|webkit_linkify|safe }} + </div> + <div> + {{ queue.pending_items_count }} pending + </div> +</div> +{% endfor %} </body> </html> |