summaryrefslogtreecommitdiffstats
path: root/WebKitTools/QueueStatusServer
diff options
context:
space:
mode:
Diffstat (limited to 'WebKitTools/QueueStatusServer')
-rw-r--r--WebKitTools/QueueStatusServer/app.yaml2
-rw-r--r--WebKitTools/QueueStatusServer/cron.yaml4
-rw-r--r--WebKitTools/QueueStatusServer/filters/webkit_extras.py21
-rw-r--r--WebKitTools/QueueStatusServer/handlers/__init__.py1
-rw-r--r--WebKitTools/QueueStatusServer/handlers/dashboard.py41
-rw-r--r--WebKitTools/QueueStatusServer/handlers/gc.py44
-rw-r--r--WebKitTools/QueueStatusServer/handlers/patch.py53
-rw-r--r--WebKitTools/QueueStatusServer/handlers/patchstatus.py40
-rw-r--r--WebKitTools/QueueStatusServer/handlers/recentstatus.py57
-rw-r--r--WebKitTools/QueueStatusServer/handlers/showresults.py41
-rw-r--r--WebKitTools/QueueStatusServer/handlers/statusbubble.py42
-rw-r--r--WebKitTools/QueueStatusServer/handlers/updatestatus.py67
-rw-r--r--WebKitTools/QueueStatusServer/index.html29
-rw-r--r--WebKitTools/QueueStatusServer/index.yaml6
-rw-r--r--WebKitTools/QueueStatusServer/main.py65
-rw-r--r--WebKitTools/QueueStatusServer/model/__init__.py1
-rw-r--r--WebKitTools/QueueStatusServer/model/attachment.py109
-rw-r--r--WebKitTools/QueueStatusServer/model/queues.py36
-rw-r--r--WebKitTools/QueueStatusServer/model/queuestatus.py38
-rw-r--r--WebKitTools/QueueStatusServer/queue_status.py177
-rw-r--r--WebKitTools/QueueStatusServer/status_bubble.html36
-rw-r--r--WebKitTools/QueueStatusServer/stylesheets/dashboard.css80
-rw-r--r--WebKitTools/QueueStatusServer/templates/dashboard.html64
-rw-r--r--WebKitTools/QueueStatusServer/templates/patch.html21
-rw-r--r--WebKitTools/QueueStatusServer/templates/recentstatus.html24
-rw-r--r--WebKitTools/QueueStatusServer/templates/statusbubble.html77
-rw-r--r--WebKitTools/QueueStatusServer/templates/updatestatus.html (renamed from WebKitTools/QueueStatusServer/update_status.html)0
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