cleanup/restore

This commit is contained in:
2010-05-13 14:33:35 -07:00
parent f276b27885
commit 50a8b2f92e
42 changed files with 1929 additions and 0 deletions

0
topfails/__init__.py Normal file
View File

BIN
topfails/images/img5846075.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
topfails/images/nav12971480a.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
topfails/images/nav12971480i.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
topfails/images/nav12971481a.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
topfails/images/nav12971481i.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
topfails/images/nav12971482a.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
topfails/images/nav12971482i.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
topfails/images/nav12971483a.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
topfails/images/nav12971483i.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
topfails/images/nav12971484a.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
topfails/images/nav12971484i.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

11
topfails/manage.py Executable file
View 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
View 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
View 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>

View 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&nbsp; from the&nbsp; 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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Example: 2d&nbsp; =&nbsp;&nbsp; 2 days&nbsp; in the past till&nbsp; now </font></div>
<div style="margin-left:40px;"><font face="Calibri" class="ws11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7h&nbsp; =&nbsp;&nbsp; 7 hours in the past till now</font></div>
<div style="margin-left:40px;"><font face="Calibri" class="ws11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5w =&nbsp; 5 weeks in the past till now</font></div>
<div style="margin-left:40px;"><font face="Calibri" class="ws11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1m =&nbsp; 1 month in the past till now</font></div>
<div style="margin-left:40px;"><font face="Calibri" class="ws11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10y =&nbsp; 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 %}

View 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.

View 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 %}

View 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 %}

View 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 %}

View 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 %}

View 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 %}

View 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> &nbsp; [{{ f.build.changesetlink|safe }}]
<ul>{% endifchanged %}
<!--<li>{{ f.description }}</li>-->{% endfor %}
</ul>
{% endblock %}

View 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>

View 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 %}

View 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/&#123;{.rev}&#125;"
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>

View 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 %}

Binary file not shown.

View 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 %}

View 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
View 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'),
)

View File

115
topfails/viewer/models.py Normal file
View 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
View 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})