cleanup/restore
0
topfails/__init__.py
Normal file
BIN
topfails/images/img5846075.png
Executable file
|
After Width: | Height: | Size: 15 KiB |
BIN
topfails/images/nav12971480a.gif
Executable file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
topfails/images/nav12971480i.gif
Executable file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
topfails/images/nav12971481a.gif
Executable file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
topfails/images/nav12971481i.gif
Executable file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
topfails/images/nav12971482a.gif
Executable file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
topfails/images/nav12971482i.gif
Executable file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
topfails/images/nav12971483a.gif
Executable file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
topfails/images/nav12971483i.gif
Executable file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
topfails/images/nav12971484a.gif
Executable file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
topfails/images/nav12971484i.gif
Executable file
|
After Width: | Height: | Size: 2.7 KiB |
11
topfails/manage.py
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/python
|
||||
from django.core.management import execute_manager
|
||||
try:
|
||||
import settings # Assumed to be in the same directory.
|
||||
except ImportError:
|
||||
import sys
|
||||
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
execute_manager(settings)
|
||||
86
topfails/settings.py
Normal file
@@ -0,0 +1,86 @@
|
||||
# Django settings for topfails project.
|
||||
import os
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
DBUSER = DBPASSWD = ''
|
||||
if os.environ.has_key('dbuser'):
|
||||
DBUSER=os.environ.get('dbuser')
|
||||
#print DBUSER
|
||||
if os.environ.has_key('dbpasswd'):
|
||||
DBPASSWD=os.environ.get('dbpasswd')
|
||||
#print DBPASSWD
|
||||
ADMINS = (
|
||||
('Murali Nandigama', 'murali.nandigama@gmail.com'),
|
||||
)
|
||||
|
||||
MANAGERS = ADMINS
|
||||
|
||||
DATABASE_ENGINE = 'mysql' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
|
||||
DATABASE_NAME = 'topfails' # Or path to database file if using sqlite3.
|
||||
DATABASE_USER = DBUSER # Not used with sqlite3.
|
||||
DATABASE_PASSWORD = DBPASSWD # Not used with sqlite3.
|
||||
DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
|
||||
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
|
||||
|
||||
# Local time zone for this installation. Choices can be found here:
|
||||
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
||||
# although not all choices may be available on all operating systems.
|
||||
# If running in a Windows environment this must be set to the same as your
|
||||
# system time zone.
|
||||
TIME_ZONE = 'America/Chicago'
|
||||
|
||||
# Language code for this installation. All choices can be found here:
|
||||
# http://www.i18nguy.com/unicode/language-identifiers.html
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
# If you set this to False, Django will make some optimizations so as not
|
||||
# to load the internationalization machinery.
|
||||
USE_I18N = True
|
||||
|
||||
# Absolute path to the directory that holds media.
|
||||
# Example: "/home/media/media.lawrence.com/"
|
||||
MEDIA_ROOT = ''
|
||||
|
||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
||||
# trailing slash if there is a path component (optional in other cases).
|
||||
# Examples: "http://media.lawrence.com", "http://example.com/media/"
|
||||
MEDIA_URL = ''
|
||||
|
||||
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
|
||||
# trailing slash.
|
||||
# Examples: "http://foo.com/media/", "/media/".
|
||||
ADMIN_MEDIA_PREFIX = '/media/'
|
||||
|
||||
# Make this unique, and don't share it with anybody.
|
||||
SECRET_KEY = '^_5(02(8sng5+6+x=c$w+3(4xv+x^&b)2ty4y8m01(o7vz$o5_'
|
||||
|
||||
# List of callables that know how to import templates from various sources.
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.load_template_source',
|
||||
'django.template.loaders.app_directories.load_template_source',
|
||||
# 'django.template.loaders.eggs.load_template_source',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'topfails.urls'
|
||||
|
||||
TEMPLATE_DIRS = (
|
||||
'./templates/'
|
||||
)
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'topfails.viewer'
|
||||
)
|
||||
121
topfails/templates/base.html
Executable file
@@ -0,0 +1,121 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Topfails</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
|
||||
<style>
|
||||
.linear{
|
||||
display: block;
|
||||
|
||||
font-family: Helvetica,Arial,sans-serif;
|
||||
font-weight: bold;
|
||||
font-size: 110.5%;
|
||||
|
||||
|
||||
text-decoration: none;
|
||||
|
||||
padding: 2px;
|
||||
|
||||
-moz-border-radius: 5px;
|
||||
border: 1px solid #000000;
|
||||
|
||||
color: #999999;
|
||||
|
||||
background-image:url("http://people.mozilla.com/~mnandigama/bg.png")
|
||||
}
|
||||
.linear:hover {
|
||||
color: #cc3300;
|
||||
font-style:italic
|
||||
|
||||
}
|
||||
.info {
|
||||
font-size: 81%;
|
||||
font-weight: normal;
|
||||
}
|
||||
.ralign{
|
||||
text-align: right;
|
||||
}
|
||||
.lalign {
|
||||
text-align: left;
|
||||
}
|
||||
.calign{
|
||||
text-align: center;
|
||||
}
|
||||
DIV,UL,OL /* Left */
|
||||
{
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div style="width: 180px;position:absolute; left:3px; top:102px; z-index:0">
|
||||
<a class="linear ralign" href="{% url latest tree=tree %}">
|
||||
<span> Latest Fails</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div style="width: 180px;position:absolute; left:3px; top:135px; z-index:0">
|
||||
<a class="linear ralign" href="{% url topfails tree=tree %}">
|
||||
<span> Top 25 Fails</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div style="width: 180px;position:absolute; left:3px; top:168px; z-index:0">
|
||||
<a class="linear ralign" href="{% url tests tree=tree %}">
|
||||
<span> All Failed Tests</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div style="width: 180px;position:absolute; left:3px; top:201px; z-index:0">
|
||||
<a class="linear ralign" href="{% url failswindow tree=tree %}?window=7d">
|
||||
<span> Fails from X days</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div style="width: 180px;position:absolute; left:3px; top:234px; z-index:0">
|
||||
<a class="linear ralign" href="{% url Help tree=tree %}">
|
||||
<span>Help</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div id="image1" style="position:absolute; overflow:hidden; left:3px; top:1px; width:180px; height:68px; z-index:1">
|
||||
<img src="http://people.mozilla.com/~mnandigama/images/logo-wordmark.png" alt="Firefox Logo" title="http://www.mozilla.com" border=0 width=179 height=68>
|
||||
</div>
|
||||
|
||||
<div id="text1" style="position:absolute; overflow:hidden; left:321px; top:2px; width:591px; height:41px; z-index:3">
|
||||
<div>
|
||||
<div><font color="#CC4200" face="Tahoma" size="+3"><B>Mozilla Tinderbox Topfails Dashboard</B></font></div>
|
||||
</div></div>
|
||||
|
||||
<div id="ff" style="width: 111px;position:absolute; left:311px; top:45px; z-index:2;">
|
||||
<a class="linear calign" title="Click for Firefox Trunk Topfails Dashboard" href="{% url latest tree='Firefox' %}" >
|
||||
<span> Firefox </span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="ff36" style="width: 111px;position:absolute; left:423px; top:45px; z-index:2">
|
||||
<a class="linear calign" href="{% url latest tree='Firefox3.6' %}" title="Click for Firefox 3.6 Topfails Dashboard">
|
||||
<span> Firefox3.6</span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="tb" style="width: 111px;position:absolute; left:535px; top:45px; z-index:2">
|
||||
<a class="linear calign" title="Click for Thunderbird Trunk Topfails Dashboard" href="{% url latest tree='Thunderbird' %}">
|
||||
<span>Thunderbird</span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="sm" style="width: 111px;position:absolute; left:647px; top:45px; z-index:2">
|
||||
<a class="linear calign" title="Click for SeaMonkey Topfails Dashboard" href="{% url latest tree='SeaMonkey' %}">
|
||||
<span> SeaMonkey</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div id="text2" style="position:absolute; overflow:hidden; left:190px; top:102px; width:800px; z-index:4">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
21
topfails/templates/viewer/Help.html
Executable file
@@ -0,0 +1,21 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div><font face="Calibri" class="ws11">This web site provides the bird eye view of top failures and other details of Firefox unit tests from the Tinderbox daily runs.</font></div>
|
||||
<div><font face="Calibri" class="ws11"><BR></font></div>
|
||||
<div><font face="Calibri" class="ws11">Meaning of the Left navigation links</font></div>
|
||||
<UL>
|
||||
<li><font face="Calibri" class="ws11">Latest Failures : This link provides the list of latest failures from the Tinderbox.</font></li>
|
||||
<li><font face="Calibri" class="ws11">Top 25 Failures : This link provides the list of top 25 failures from the entire history of the topfails database. Please note that this data is as complete as the first date we started collecting results. The data we have in the topfails database does not contain all the failures details from the Time ZERO of tinderbox runs.</font></li>
|
||||
<li><font face="Calibri" class="ws11">All Failed Tests: This link displays all the known failures that are stored in the topfails DB.</font></li>
|
||||
<li><font face="Calibri" class="ws11"><b>Failures from X days</b>: This is a link which allows you to query for failures from NOW till a specific period in the past.</font></li>
|
||||
</UL>
|
||||
<div style="margin-left:40px;"><font face="Calibri" class="ws11"> Example: 2d = 2 days in the past till now </font></div>
|
||||
<div style="margin-left:40px;"><font face="Calibri" class="ws11"> 7h = 7 hours in the past till now</font></div>
|
||||
<div style="margin-left:40px;"><font face="Calibri" class="ws11"> 5w = 5 weeks in the past till now</font></div>
|
||||
<div style="margin-left:40px;"><font face="Calibri" class="ws11"> 1m = 1 month in the past till now</font></div>
|
||||
<div style="margin-left:40px;"><font face="Calibri" class="ws11"> 10y = 10 years in the past till now</font></div>
|
||||
<div style="margin-left:40px;"><font face="Calibri" class="ws11">Example queries for advanced users <a href="../failswindow/Firefox?window=2w">2 weeks 'Firefox' failures</a></div>
|
||||
<div style="margin-left:40px;"><font face="Calibri" class="ws11">Example queries for advanced users <a href="../failswindow/Firefox?window=2d">2 days 'Firefox' failures</a></div>
|
||||
<div style="margin-left:40px;"><font face="Calibri" class="ws11">Example queries for advanced users <a href="../failswindow/Firefox?window=24h">24 hours 'Firefox' failures</a></div>
|
||||
<div style="margin-left:40px;"><font face="Calibri" class="ws11">Example queries for advanced users <a href="../failswindow/Firefox?window=1m">1 month 'Firefox' failures</a></div>
|
||||
{% endblock %}
|
||||
5
topfails/templates/viewer/README
Normal file
@@ -0,0 +1,5 @@
|
||||
I have done a very bad and crude hack to add a top level navigation page. Instead of storing images for top navigation page in the correct location , I am jammin gall the top site nav stuff in here.
|
||||
|
||||
Should fix it when time permits.
|
||||
|
||||
|
||||
9
topfails/templates/viewer/changeset.html
Executable file
@@ -0,0 +1,9 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h3>Changeset {{ changeset }}</h3>
|
||||
<ul>
|
||||
{% for build in builds %}
|
||||
<li>{{ build.tree }}: {{ build.get_os_display }}: {{ build.get_status_display }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
9
topfails/templates/viewer/changesets.html
Executable file
@@ -0,0 +1,9 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h3>Changesets</h3>
|
||||
<ul>
|
||||
{% for c in changesets %}
|
||||
<li><a href="{% url viewer.views.changeset c %}">{{ c }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
10
topfails/templates/viewer/failswindow.html
Normal file
@@ -0,0 +1,10 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h3>Failed tests from last {{n}} {{d}} up to now</h3>
|
||||
<table>
|
||||
<tr><th>Count</th><th align="left">Test name</th></tr>
|
||||
{% for f in failures %}
|
||||
<tr><td>{{ f.count }}</td><td><a href="{% url viewer.views.test tree=tree %}?name={{ f.test__name }}">{{ f.test__name }}</a></td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endblock %}
|
||||
15
topfails/templates/viewer/index.html
Executable file
@@ -0,0 +1,15 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<style type="text/css">
|
||||
li {
|
||||
padding-bottom: 10px; }
|
||||
</style>
|
||||
<h3>Most recent test failures</h3>
|
||||
<ul>
|
||||
{% for f in failures %}
|
||||
<li>{{ f.build.startdate|date:"Y-m-d H:i" }} {{ f.build.tree.name }} {{ f.build.get_os_display }}: <a href="{% url viewer.views.test %}?name={{ f.name }}">{{ f.name }}</a>,
|
||||
<a href="{% url viewer.views.timeline %}?name={{ f.name }}">timeline</a>
|
||||
- {{ f.description }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
15
topfails/templates/viewer/latest.html
Executable file
@@ -0,0 +1,15 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<style type="text/css">
|
||||
li {
|
||||
padding-bottom: 10px; }
|
||||
</style>
|
||||
<h3>Most recent test failures</h3>
|
||||
<ul>
|
||||
{% for f in failures %}
|
||||
<li>{{ f.build.startdate|date:"Y-m-d H:i" }} {{ f.build.tree.name }} {{ f.build.get_os_display }}: <a href="{% url viewer.views.test tree=tree %}?name={{ f.test.name }}">{{ f.test.name }}</a>
|
||||
<!--<a href="{% url viewer.views.timeline tree=tree %}?name={{ f.test.name }}">timeline</a> -->
|
||||
- {{ f.failtext }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
13
topfails/templates/viewer/test.html
Executable file
@@ -0,0 +1,13 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h3>Logfile links and Changeset links for {{ test }} failures</h3>
|
||||
[ Showing up to latest 10000 failures' related log links ]<br />
|
||||
<br />
|
||||
<ul>
|
||||
<li style="display:none"><ul>
|
||||
{% for f in failures %}{% ifchanged f.build.id %}</ul></li><li>
|
||||
<a href="{{ f.build.tinderboxlink|safe }}">{{ f.build.startdate|date:"Y-m-d H:i" }} {{ f.build.tree }} {{ f.build.get_os_display }}</a> [{{ f.build.changesetlink|safe }}]
|
||||
<ul>{% endifchanged %}
|
||||
<!--<li>{{ f.description }}</li>-->{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
27
topfails/templates/viewer/test.html.orig
Executable file
@@ -0,0 +1,27 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h3>Logfile links and Changeset links for {{ test }} failures</h3>
|
||||
<ul>
|
||||
<li style="display:none"><ul>
|
||||
{% for f in section %}{% ifchanged f.build.id %}</ul></li><li>
|
||||
<a href="{{ f.build.tinderboxlink|safe }}">{{ f.build.startdate|date:"Y-m-d H:i" }} {{ f.build.tree }} {{ f.build.get_os_display }}</a> [{{ f.build.changesetlink|safe }}]:
|
||||
<ul>{% endifchanged %}
|
||||
<!--<li>{{ f.description }}</li>-->{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
<div class="pagination">
|
||||
<span class="step-links">
|
||||
{% if section.has_previous %}
|
||||
<a href="?page={{ section.previous_page_number }}">previous</a>
|
||||
{% endif %}
|
||||
|
||||
<span class="current">
|
||||
Page {{ section.number }} of {{ section.paginator.num_pages }}.
|
||||
</span>
|
||||
|
||||
{% if section.has_next %}
|
||||
<a href="?page={{ section.next_page_number }}">next</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
14
topfails/templates/viewer/tests.html
Executable file
@@ -0,0 +1,14 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<style type="text/css">
|
||||
li {
|
||||
padding-bottom: 10px; }
|
||||
</style>
|
||||
|
||||
<h3>All known failing tests</h3>
|
||||
<ul>
|
||||
{% for t in tests %}
|
||||
<li><a href="{% url viewer.views.test tree=tree %}?name={{ t }}">{{ t }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
72
topfails/templates/viewer/timeline.html
Executable file
@@ -0,0 +1,72 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Timeline for {{ test }}</title>
|
||||
<script src="http://static.simile.mit.edu/exhibit/api-2.0/exhibit-api.js?autoCreate=false"
|
||||
type="text/javascript"></script>
|
||||
<script src="http://static.simile.mit.edu/exhibit/extensions-2.0/time/time-extension.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
var json = {"items": [
|
||||
{% for bd in builds %}
|
||||
{
|
||||
"type": "Build",
|
||||
"id": "bld{{ bd.build.id }}",
|
||||
"label": "{{ bd.os }} {{ bd.build.changeset }}",
|
||||
"desc": "{{ bd.description|escapejs|escape }}",
|
||||
"desc_id": "{{ bd.desctype }}",
|
||||
"time": "{{ bd.time }}",
|
||||
"os": "{{ bd.os }}",
|
||||
"rev": "{{ bd.build.changeset }}",
|
||||
},
|
||||
{% endfor %}
|
||||
],
|
||||
"properties": {
|
||||
"time": {"valueType": "date"},
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
window.database = Exhibit.Database.create();
|
||||
window.database.loadData(json);
|
||||
window.exhibit = Exhibit.create();
|
||||
window.exhibit.configureFromDOM();
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Timeline for {{ test }}</h2>
|
||||
|
||||
<div ex:role="lens" ex:itemTypes="Build">
|
||||
<div><span ex:content=".os"></span> <a
|
||||
ex:href-subcontent="http://hg.mozilla.org/mozilla-central/rev/{{.rev}}"
|
||||
target="_blank" ex:content=".rev"></a></div> <pre ex:content=".desc"></pre>
|
||||
</div>
|
||||
<div id="blds" ex:role="exhibit-collection" ex:itemTypes="Build"></div>
|
||||
|
||||
<div ex:role="view"
|
||||
ex:viewClass="Timeline"
|
||||
ex:start=".time"
|
||||
ex:topBandPixelsPerUnit="50",
|
||||
ex:bottomBandPixelsPerUnit="50",
|
||||
></div>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td>
|
||||
{% for desc in descriptions %}
|
||||
<pre>{{desc}}</pre>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td valign="top" style="padding-left: 5em;">
|
||||
<div ex:role="facet" ex:expression=".desc_id"
|
||||
ex:facetLabel="Description"></div>
|
||||
</td>
|
||||
<td valign="top" style="padding-left: 5em;">
|
||||
<div ex:role="facet" ex:expression=".os"
|
||||
ex:facetLabel="OS"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body> </html>
|
||||
10
topfails/templates/viewer/topfails.html
Executable file
@@ -0,0 +1,10 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h3>Top 25 failing tests</h3>
|
||||
<table>
|
||||
<tr><th>Count</th><th align="left">Test name</th></tr>
|
||||
{% for f in failures %}
|
||||
<tr><td>{{ f.count }}</td><td><a href="{% url viewer.views.test tree=tree %}?name={{ f.test__name }}">{{ f.test__name}}</a></td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endblock %}
|
||||
BIN
topfails/templates/viewer/topfails.rar
Executable file
9
topfails/templates/viewer/tree.html
Executable file
@@ -0,0 +1,9 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h3>{{ tree }}</h3>
|
||||
<ul>
|
||||
{% for build in newestbuilds %}
|
||||
<li>{{ build.get_os_display }}: {{ build.get_status_display }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
10
topfails/templates/viewer/trees.html
Executable file
@@ -0,0 +1,10 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<h3>Trees</h3>
|
||||
<ul>
|
||||
{% for tree in trees %}
|
||||
<li><a href="{% url viewer.views.tree tree.name %}">{{ tree.name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
20
topfails/urls.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
# Uncomment the next two lines to enable the admin:
|
||||
from django.contrib import admin
|
||||
admin.autodiscover()
|
||||
|
||||
urlpatterns = patterns('topfails.viewer.views',
|
||||
(r'^$', 'index'),
|
||||
url(r'^trees/(?P<tree>.+)?$','trees', name='trees'),
|
||||
url(r'^tree/(?P<tree>.+)?$','tree', name='tree'),
|
||||
url(r'^changesets/(?P<tree>.+)?$','changesets', name='changesets'),
|
||||
url(r'^changesets/(?P<tree>.+)/(?P<changeset>[a-f0-9]+)$', 'changeset', name='changeset'),
|
||||
url(r'^tests/(?P<tree>.+)?$','tests', name='tests'),
|
||||
url(r'^test/(?P<tree>.+)?$','test', name='test'),
|
||||
url(r'^timeline/(?P<tree>.+)?$','timeline', name='timeline'),
|
||||
url(r'^topfails/(?P<tree>.+)?$','topfails', name='topfails'),
|
||||
url(r'^failswindow/(?P<tree>.+)?$','failswindow', name='failswindow'),
|
||||
url(r'^latest/(?P<tree>.+)?$','latest', name='latest'),
|
||||
url(r'^Help/(?P<tree>.+)?$','Help', name='Help'),
|
||||
)
|
||||
0
topfails/viewer/__init__.py
Normal file
115
topfails/viewer/models.py
Normal file
@@ -0,0 +1,115 @@
|
||||
import re
|
||||
from django.db import models, connection
|
||||
from datetime import datetime
|
||||
from time import ctime, sleep, time
|
||||
|
||||
class OS():
|
||||
Windows = 0
|
||||
Mac = 1
|
||||
Linux = 2
|
||||
Unknown = 3
|
||||
|
||||
OS_CHOICES = (
|
||||
(OS.Windows, 'Windows'),
|
||||
(OS.Mac, 'Mac'),
|
||||
(OS.Linux, 'Linux'),
|
||||
(OS.Unknown, 'Unknown')
|
||||
)
|
||||
|
||||
class BuildStatus():
|
||||
Success = 0
|
||||
TestFailed = 1
|
||||
Burning = 2
|
||||
Exception = 3
|
||||
Unknown = 4
|
||||
|
||||
BUILDSTATUS_CHOICES = (
|
||||
(BuildStatus.Success, 'Success'),
|
||||
(BuildStatus.TestFailed, 'Test Failed'),
|
||||
(BuildStatus.Burning, 'Burning'),
|
||||
(BuildStatus.Exception, 'Exception'),
|
||||
(BuildStatus.Unknown, 'Unknown')
|
||||
)
|
||||
|
||||
|
||||
class Tree(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
name = models.CharField(max_length=45, blank=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Build(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
os = models.IntegerField(choices=OS_CHOICES)
|
||||
tree = models.ForeignKey(Tree)
|
||||
starttime = models.IntegerField(null=True, blank=True)
|
||||
status = models.IntegerField(choices=BUILDSTATUS_CHOICES)
|
||||
changeset = models.CharField(max_length=80,blank=True)
|
||||
logfile = models.CharField(max_length=300,blank=True)
|
||||
|
||||
def startdate(self):
|
||||
return datetime.fromtimestamp(self.starttime)
|
||||
|
||||
def changesetlink(self):
|
||||
if str(self.tree) == 'Firefox':
|
||||
return '<a href="%s/rev/%s">%s</a>' % ("http://hg.mozilla.org/mozilla-central", self.changeset, self.changeset)
|
||||
elif str(self.tree) == 'Firefox3.6':
|
||||
return '<a href="%s/rev/%s">%s</a>' % ("http://hg.mozilla.org/releases/mozilla-1.9.2", self.changeset, self.changeset)
|
||||
elif str(self.tree) == 'Thunderbird' or str(self.tree) == 'SeaMonkey':
|
||||
return '<a href="%s/rev/%s">%s</a>' % ("http://hg.mozilla.org/comm-central", self.changeset, self.changeset)
|
||||
else :
|
||||
return '<a href="%s/rev/%s">%s</a>' % ("http://hg.mozilla.org/mozilla-central", self.changeset, self.changeset)
|
||||
|
||||
def jsonchangesetlink(self):
|
||||
return "%s/rev/%s" % ("http://hg.mozilla.org/mozilla-central", self.changeset)
|
||||
|
||||
def tinderboxlink(self):
|
||||
if self.logfile:
|
||||
return "http://tinderbox.mozilla.org/showlog.cgi?log=%s/%s" % (self.tree.name, self.logfile)
|
||||
return "http://tinderbox.mozilla.org/showbuilds.cgi?tree=%s&maxdate=%d&hours=3" % (self.tree.name, self.starttime)
|
||||
|
||||
|
||||
class Test(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
name = models.CharField(max_length=300, blank=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class TestFailure(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
build = models.ForeignKey(Build)
|
||||
test = models.ForeignKey(Test)
|
||||
failtext = models.CharField(max_length=400, blank=True)
|
||||
|
||||
@classmethod
|
||||
def get_most_failing_tests(cls,tree):
|
||||
return cls.objects.filter(build__tree__name=tree).values('test__name').annotate(count=models.Count('test__name')).order_by('-count')[:25]
|
||||
|
||||
@classmethod
|
||||
def get_time_failing_tests(cls,tree):
|
||||
return cls.objects.filter(build__tree__name=tree).values('test__name').annotate(count=models.Count('test__name')).order_by('-count')
|
||||
|
||||
@classmethod
|
||||
def get_fails_in_timerange(cls,period,tree):
|
||||
|
||||
# Get current time, in seconds.
|
||||
endtime = int(time())
|
||||
|
||||
m = re.match("(\d+)([ymwdh])", period)
|
||||
if m is None:
|
||||
print >>sys.stderr, "ERROR: bad timespan = '%s'!" % options.timespan
|
||||
sys.exit(1)
|
||||
|
||||
timespan = int(m.group(1)) * {'y': 365 * 24 * 3600,
|
||||
'm': 30 * 24 * 3600,
|
||||
'w': 7 * 24 * 3600,
|
||||
'd': 24 * 3600,
|
||||
'h': 3600}[m.group(2)]
|
||||
# Set current time to beginning of requested timespan ending now.
|
||||
curtime = endtime - timespan
|
||||
qs = cls.get_time_failing_tests(tree)
|
||||
return qs.filter(build__starttime__gt=curtime)
|
||||
|
||||
|
||||
107
topfails/viewer/views.py
Normal file
@@ -0,0 +1,107 @@
|
||||
from django.shortcuts import render_to_response, get_list_or_404
|
||||
from topfails.viewer.models import Build, Tree, Test,TestFailure, OS_CHOICES
|
||||
import re
|
||||
from django.http import HttpResponse
|
||||
import json
|
||||
|
||||
def latest(request,tree='Firefox'):
|
||||
failures = get_list_or_404(TestFailure.objects.filter(build__tree__name=tree).order_by('-build__starttime')[:20])
|
||||
if request.GET.has_key('json'):
|
||||
jtext = [{"testname":f.test.name, "buildstatus":f.build.status, "logfile": f.build.tinderboxlink(),"changeset":f.build.jsonchangesetlink() , "failtext":f.failtext} for f in failures]
|
||||
return HttpResponse(json.dumps(jtext))
|
||||
else:
|
||||
return render_to_response('viewer/latest.html', {'failures': failures, 'tree' : tree})
|
||||
|
||||
def index(request,tree='Firefox'):
|
||||
failures = get_list_or_404(TestFailure.objects.filter(build__tree__name=tree).order_by('-build__starttime')[:20])
|
||||
return render_to_response('viewer/latest.html', {'failures': failures, 'tree' : tree})
|
||||
|
||||
|
||||
def trees(request,tree='Firefox'):
|
||||
alltrees = Tree.objects.all().order_by('name')
|
||||
return render_to_response('viewer/trees.html', {'trees': alltrees , 'tree' : tree})
|
||||
|
||||
def tree(request, tree='Firefox'):
|
||||
newestbuilds = get_list_or_404(Build.objects.filter(tree__name__exact=tree).order_by('-starttime')[:5])
|
||||
return render_to_response('viewer/tree.html', {'tree': tree, 'newestbuilds': newestbuilds})
|
||||
|
||||
def changesets(request,tree='Firefox'):
|
||||
build_csets = Build.objects.filter(tree__name__exact=tree).values('changeset').distinct()
|
||||
return render_to_response('viewer/changesets.html', { 'tree' : tree,'changesets': [b['changeset'] for b in build_csets]})
|
||||
|
||||
def changeset(request, changeset,tree='Firefox'):
|
||||
builds = get_list_or_404(Build, changeset__exact=changeset)
|
||||
return render_to_response('viewer/changeset.html', {'changeset': changeset, 'builds': builds, 'tree' : tree})
|
||||
|
||||
def tests(request,tree='Firefox'):
|
||||
test_names = TestFailure.objects.filter(build__tree__name__exact=tree).values('test__name').distinct()
|
||||
if request.GET.has_key('json'):
|
||||
jtext = list(test_names)
|
||||
return HttpResponse(json.dumps(jtext))
|
||||
else:
|
||||
return render_to_response('viewer/tests.html', { 'tree' : tree, 'tests': [t['test__name'] for t in test_names]})
|
||||
|
||||
def test(request,tree='Firefox'):
|
||||
failures = get_list_or_404(TestFailure.objects.filter(build__tree__name__exact=tree).filter(test__name__exact=request.GET['name']).order_by('-build__starttime')[:10000])
|
||||
#if request.GET.has_key('json'):
|
||||
#jtext = list(failures)
|
||||
#return HttpResponse(json.dumps(jtext))
|
||||
#else:
|
||||
return render_to_response('viewer/test.html', {'test': request.GET['name'], 'failures': failures, 'tree' : tree})
|
||||
|
||||
def topfails(request,tree='Firefox'):
|
||||
failures = TestFailure.get_most_failing_tests(tree)
|
||||
if request.GET.has_key('json'):
|
||||
jtext = list(failures)
|
||||
return HttpResponse(json.dumps(jtext))
|
||||
else:
|
||||
return render_to_response('viewer/topfails.html', {'failures': failures, 'tree' : tree})
|
||||
|
||||
def Help(request,tree):
|
||||
return render_to_response('viewer/Help.html',{'tree':tree})
|
||||
|
||||
def timeline(request,tree='Firefox'):
|
||||
name = request.GET['name']
|
||||
builds = get_list_or_404(Build.objects.filter(tree__name__exact=tree), test__name__exact=name)
|
||||
buildlist = []
|
||||
desc_list = []
|
||||
for b in builds:
|
||||
descs = b.testfailure_set.filter(testfailure__name__exact=name).order_by('id')
|
||||
desc = '\n'.join(descs.values_list('description', flat=True))
|
||||
if desc not in desc_list:
|
||||
desc_list.append(desc)
|
||||
desc_i = desc_list.index(desc)
|
||||
buildlist.append({'build': b,
|
||||
'desctype': desc_i,
|
||||
'description': desc,
|
||||
'os': OS_CHOICES[b.os][1],
|
||||
'time': b.startdate().isoformat() + "Z",
|
||||
})
|
||||
return render_to_response('viewer/timeline.html', {'test': name,
|
||||
'descriptions': desc_list,
|
||||
'builds': buildlist, 'tree' : tree})
|
||||
|
||||
def failswindow(request,tree='Firefox'):
|
||||
period=request.GET['window']
|
||||
m = re.match("(\d+)([ymwdh])", period)
|
||||
failures = TestFailure.get_fails_in_timerange(period,tree)
|
||||
if request.GET.has_key('json'):
|
||||
jtext = list(failures)
|
||||
return HttpResponse(json.dumps(jtext))
|
||||
else:
|
||||
if m.group(2) == 'd':
|
||||
prd='days'
|
||||
elif m.group(2) == 'h':
|
||||
prd = 'hours'
|
||||
elif m.group(2) == 'w':
|
||||
prd = 'weeks'
|
||||
elif m.group(2) == 'm':
|
||||
prd = 'months'
|
||||
elif m.group(2) == 'y':
|
||||
prd = 'years'
|
||||
else:
|
||||
prd = 'days'
|
||||
|
||||
|
||||
return render_to_response('viewer/failswindow.html', {'failures': failures,'n':m.group(1),'d':prd, 'tree' : tree})
|
||||
|
||||