Merge lp:~cjohnston/qa-dashboard/dashboard-sru-2-sru into lp:qa-dashboard

Proposed by Chris Johnston
Status: Rejected
Rejected by: Chris Johnston
Proposed branch: lp:~cjohnston/qa-dashboard/dashboard-sru-2-sru
Merge into: lp:qa-dashboard
Diff against target: 612 lines (+352/-156)
12 files modified
dashboard/migrations/0014_remove_sru_models.py (+18/-0)
dashboard/models.py (+0/-132)
dashboard/templatetags/__init__.py (+0/-15)
qa_dashboard/settings.py (+1/-0)
qa_dashboard/urls.py (+7/-7)
sru/management/__init__.py (+14/-0)
sru/management/commands/__init__.py (+14/-0)
sru/management/commands/jenkins_pull_sru.py (+1/-1)
sru/migrations/0001_add_initial_models.py (+136/-0)
sru/models.py (+144/-0)
sru/tests.py (+16/-0)
sru/views.py (+1/-1)
To merge this branch: bzr merge lp:~cjohnston/qa-dashboard/dashboard-sru-2-sru
Reviewer Review Type Date Requested Status
Joe Talbott Approve
Chris Johnston Pending
Review via email: mp+141944@code.launchpad.net

This proposal supersedes a proposal from 2013-01-04.

Commit message

Moves sru code from dashboard to new sru app

To post a comment you must log in.
Revision history for this message
Joe Talbott (joetalbott) wrote : Posted in a previous version of this proposal

I'd prefer to change have jenkins_get() and friends in common/management/__init__.py rather than common/helpers.py since that code is only used in management commands.

The sru/migrations/0001_initial.py logic needs to test if the table name exists and add it if it doesn't. This means we can't return after each check because none of the other checks will happen. I propose something like this:

   table_names = connection.introspection.table_names()

   if 'kernels' not in table_names:
      db.create_table('kernels'...

   if 'sru_results' not in talbe_names:
      db.create_table('sru_results'...

review: Needs Fixing
Revision history for this message
Chris Johnston (cjohnston) : Posted in a previous version of this proposal
review: Needs Resubmitting
Revision history for this message
Joe Talbott (joetalbott) wrote :

Remove lines 24-93 please.

Line 365 needs inserted 'from django.db import connection'

review: Needs Fixing
Revision history for this message
Joe Talbott (joetalbott) wrote :

Looks good, thanks.

review: Approve
Revision history for this message
Chris Johnston (cjohnston) wrote :
Download full text (3.9 KiB)

The attempt to merge lp:~chrisjohnston/qa-dashboard/dashboard-sru-2-sru into lp:qa-dashboard failed. Below is the output from the failed tests.

Creating test database for alias 'default'...

Traceback (most recent call last):
  File "manage.py", line 26, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/lib/python2.7/dist-packages/django/core/management/__init__.py", line 429, in execute_from_command_line
    utility.execute()
  File "/usr/lib/python2.7/dist-packages/django/core/management/__init__.py", line 379, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/lib/python2.7/dist-packages/django/core/management/base.py", line 191, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/usr/lib/python2.7/dist-packages/django/core/management/base.py", line 220, in execute
    output = self.handle(*args, **options)
  File "/usr/lib/python2.7/dist-packages/south/management/commands/test.py", line 8, in handle
    super(Command, self).handle(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/django/core/management/commands/test.py", line 37, in handle
    failures = test_runner.run_tests(test_labels)
  File "/usr/lib/python2.7/dist-packages/django/test/simple.py", line 359, in run_tests
    old_config = self.setup_databases()
  File "/usr/lib/python2.7/dist-packages/django/test/simple.py", line 296, in setup_databases
    test_db_name = connection.creation.create_test_db(self.verbosity, autoclobber=not self.interactive)
  File "/usr/lib/python2.7/dist-packages/django/db/backends/creation.py", line 366, in create_test_db
    load_initial_data=False)
  File "/usr/lib/python2.7/dist-packages/django/core/management/__init__.py", line 166, in call_command
    return klass.execute(*args, **defaults)
  File "/usr/lib/python2.7/dist-packages/django/core/management/base.py", line 220, in execute
    output = self.handle(*args, **options)
  File "/usr/lib/python2.7/dist-packages/django/core/management/base.py", line 351, in handle
    return self.handle_noargs(**options)
  File "/usr/lib/python2.7/dist-packages/south/management/commands/syncdb.py", line 99, in handle_noargs
    management.call_command('migrate', **options)
  File "/usr/lib/python2.7/dist-packages/django/core/management/__init__.py", line 166, in call_command
    return klass.execute(*args, **defaults)
  File "/usr/lib/python2.7/dist-packages/django/core/management/base.py", line 220, in execute
    output = self.handle(*args, **options)
  File "/usr/lib/python2.7/dist-packages/south/management/commands/migrate.py", line 105, in handle
    ignore_ghosts = ignore_ghosts,
  File "/usr/lib/python2.7/dist-packages/south/migration/__init__.py", line 191, in migrate_app
    success = migrator.migrate_many(target, workplan, database)
  File "/usr/lib/python2.7/dist-packages/south/migration/migrators.py", line 221, in migrate_many
    result = migrator.__class__.migrate_many(migrator, target, migrations, database)
  File "/usr/lib/python2.7/dist-packages/south/migration/migrators.py", line 292, in migrate_many
    result = self.migrate(migration, database)
  File "/usr/lib/python2.7/dist-packages/south/migration/migrators.py", l...

Read more...

Unmerged revisions

205. By Chris Johnston

requested changes

204. By Chris Johnston

Fixes indentation

203. By Chris Johnston

Fixes indentation

202. By Chris Johnston

Updates SRU

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'dashboard/migrations/0014_remove_sru_models.py'
2--- dashboard/migrations/0014_remove_sru_models.py 1970-01-01 00:00:00 +0000
3+++ dashboard/migrations/0014_remove_sru_models.py 2013-01-04 18:06:05 +0000
4@@ -0,0 +1,18 @@
5+# -*- coding: utf-8 -*-
6+import datetime
7+from south.db import db
8+from south.v2 import SchemaMigration
9+from django.db import models
10+
11+
12+class Migration(SchemaMigration):
13+
14+ depends_on = (
15+ ('sru', '0001_add_initial_models'),
16+ )
17+
18+ def forwards(self, orm):
19+ pass
20+
21+ def backwards(self, orm):
22+ pass
23
24=== modified file 'dashboard/models.py'
25--- dashboard/models.py 2013-01-03 19:40:12 +0000
26+++ dashboard/models.py 2013-01-04 18:06:05 +0000
27@@ -19,9 +19,6 @@
28 from common.models import DashboardBaseModel, Bug
29
30
31-###
32-# Smoke
33-###
34 class ResultLog(DashboardBaseModel):
35 class Meta:
36 db_table = 'result_logs'
37@@ -237,132 +234,3 @@
38 @property
39 def log_count(self):
40 return self.resultlog_set.count()
41-
42-###
43-# Kernel SRU
44-###
45-
46-class Kernel(DashboardBaseModel):
47- class Meta:
48- db_table = "kernels"
49-
50- job_type = models.CharField(max_length=100)
51- release = models.CharField(max_length=100)
52- variant = models.CharField(max_length=100)
53- arch = models.CharField(max_length=100)
54- gpu = models.CharField(max_length=100)
55- version = models.CharField(max_length=100)
56-
57- # Used by MySerializer to add property fields to the JSON representation
58- # of an instance of this class.
59- extra_fields = [
60- 'pass_count',
61- 'skip_count',
62- 'fail_count',
63- 'total_count',
64- 'pass_rate',
65- 'pass_rate_pct',
66- 'bug_count',
67- 'log_count',
68- ]
69-
70- def debug_str(self):
71- return "{}-{}-{}-{}".format(
72- self.release,
73- self.variant,
74- self.arch,
75- self.gpu,
76- )
77-
78- @property
79- def name(self):
80- return "{}-{}".format(self.release, self.variant)
81-
82- @property
83- def total_count(self):
84- return self.sruresult_set.aggregate(models.Sum('total_count'))['total_count__sum'] or 0
85-
86- @property
87- def pass_count(self):
88- return self.sruresult_set.aggregate(models.Sum('pass_count'))['pass_count__sum'] or 0
89-
90- @property
91- def fail_count(self):
92- return self.sruresult_set.aggregate(models.Sum('fail_count'))['fail_count__sum'] or 0
93-
94- @property
95- def skip_count(self):
96- return self.sruresult_set.aggregate(models.Sum('skip_count'))['skip_count__sum'] or 0
97-
98- @property
99- def pass_rate(self):
100- return self.pass_count*1.0 / self.total_count if self.total_count > 0 else 0
101-
102- @property
103- def pass_rate_pct(self):
104- return "%d%%" % int(self.pass_rate*100)
105-
106- @property
107- def bug_count(self):
108- return self.sruresult_set.annotate(num_bugs=models.Count('bugs')).aggregate(models.Sum('num_bugs'))['num_bugs__sum'] or 0
109-
110- @property
111- def log_count(self):
112- return self.sruresultlog_set.count()
113-
114- @property
115- def last_run_date(self):
116- return self.sruresult_set.aggregate(models.Max('ran_at'))['ran_at__max'].strftime("%Y-%m-%d %H:%M")
117-
118-# XXX: refactor this and Result
119-class SRUResult(DashboardBaseModel):
120- class Meta:
121- db_table = 'sru_results'
122-
123- kernel = models.ForeignKey(Kernel)
124- bugs = models.ManyToManyField(Bug)
125-
126- jenkins_build = models.CharField(max_length=255)
127- jenkins_url = models.URLField()
128- name = models.CharField(max_length=255)
129- pass_count = models.IntegerField()
130- fail_count = models.IntegerField()
131- skip_count = models.IntegerField()
132- total_count = models.IntegerField()
133- ran_at = models.DateTimeField('date run')
134-
135- # Used by MySerializer to add property fields to the JSON representation
136- # of an instance of this class.
137- extra_fields = [
138- 'pass_rate',
139- 'pass_rate_pct',
140- 'bug_count',
141- 'log_count',
142- ]
143-
144- @property
145- def pass_rate(self):
146- return self.pass_count*1.0 / self.total_count if self.total_count > 0 else 0
147-
148- @property
149- def pass_rate_pct(self):
150- return "%d%%" % int(self.pass_rate*100)
151-
152- @property
153- def bug_count(self):
154- return self.bugs.count()
155-
156- @property
157- def log_count(self):
158- return self.resultlog_set.count()
159-
160-class SRUResultLog(DashboardBaseModel):
161- class Meta:
162- db_table = 'sru_result_logs'
163- display_name = models.CharField(max_length=255, null = True)
164- path = models.TextField()
165- sru_result = models.ForeignKey('SRUResult')
166- remote_url = models.URLField()
167-
168- def __unicode__(self):
169- return self.path
170
171=== removed directory 'dashboard/templatetags'
172=== removed file 'dashboard/templatetags/__init__.py'
173--- dashboard/templatetags/__init__.py 2012-12-02 02:51:10 +0000
174+++ dashboard/templatetags/__init__.py 1970-01-01 00:00:00 +0000
175@@ -1,15 +0,0 @@
176-# QA Dashboard
177-# Copyright 2012 Canonical Ltd.
178-
179-# This program is free software: you can redistribute it and/or modify it
180-# under the terms of the GNU Affero General Public License version 3, as published
181-# by the Free Software Foundation.
182-
183-# This program is distributed in the hope that it will be useful, but
184-# WITHOUT ANY WARRANTY; without even the implied warranties of
185-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
186-# PURPOSE. See the GNU Affero General Public License for more details.
187-
188-# You should have received a copy of the GNU Affero General Public License along
189-# with this program. If not, see <http://www.gnu.org/licenses/>.
190-
191
192=== modified file 'qa_dashboard/settings.py'
193--- qa_dashboard/settings.py 2012-12-14 23:59:31 +0000
194+++ qa_dashboard/settings.py 2013-01-04 18:06:05 +0000
195@@ -146,6 +146,7 @@
196 'bootspeed',
197 'common',
198 'south',
199+ 'sru',
200 )
201
202 # A sample logging configuration. The only tangible logging
203
204=== modified file 'qa_dashboard/urls.py'
205--- qa_dashboard/urls.py 2012-12-13 03:33:47 +0000
206+++ qa_dashboard/urls.py 2013-01-04 18:06:05 +0000
207@@ -35,15 +35,15 @@
208 url(r'^api/smoke/run/(?P<run_id>\d+)/image/(?P<image_id>\d+)/$', 'api.smoke.api_image'),
209 url(r'^api/smoke/run/(?P<run_id>\d+)/image/(?P<image_id>\d+)/result/$', 'api.smoke.api_results'),
210 url(r'^api/smoke/run/(?P<run_id>\d+)/image/(?P<image_id>\d+)/result/(?P<result_id>\d+)/$', 'api.smoke.api_result'),
211- url(r'^sru/$', 'sru.overview', name='sru'),
212- url(r'^sru/(?P<release>\w+)/$', 'sru.overview', name='sru_overview'),
213- url(r'^sru/(?P<release>\w+)/version/(?P<kernel_version>[^/]+)/$', 'sru.overview_kernel', name='sru_overview_kernel'),
214- url(r'^api/sru/$', 'sru.api_overview'),
215- url(r'^api/sru/(?P<release>\w+)/$', 'sru.api_overview'),
216- url(r'^api/sru/(?P<release>\w+)/(?P<version>[^/]+)/$', 'sru.api_overview'),
217 url(r'^api/help/$', 'api.api_help', name='api_help'),
218 )
219-
220+
221+urlpatterns += patterns('sru.views',
222+ url(r'^sru/$', 'overview', name='sru'),
223+ url(r'^sru/(?P<release>\w+)/$', 'overview', name='sru_overview'),
224+ url(r'^sru/(?P<release>\w+)/version/(?P<kernel_version>[^/]+)/$', 'overview_kernel', name='sru_overview_kernel'),
225+)
226+
227 urlpatterns += patterns('bootspeed.views',
228 url(r'^bootspeed/$', 'arch_overview', name='bootspeed_arch'),
229 url(r'^bootspeed/arch/(?P<arch>\w+)/$', 'arch_overview', name='bootspeed_arch_overview'),
230
231=== added directory 'sru'
232=== added file 'sru/__init__.py'
233=== added directory 'sru/management'
234=== added file 'sru/management/__init__.py'
235--- sru/management/__init__.py 1970-01-01 00:00:00 +0000
236+++ sru/management/__init__.py 2013-01-04 18:06:05 +0000
237@@ -0,0 +1,14 @@
238+# QA Dashboard
239+# Copyright 2012 Canonical Ltd.
240+
241+# This program is free software: you can redistribute it and/or modify it
242+# under the terms of the GNU Affero General Public License version 3, as published
243+# by the Free Software Foundation.
244+
245+# This program is distributed in the hope that it will be useful, but
246+# WITHOUT ANY WARRANTY; without even the implied warranties of
247+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
248+# PURPOSE. See the GNU Affero General Public License for more details.
249+
250+# You should have received a copy of the GNU Affero General Public License along
251+# with this program. If not, see <http://www.gnu.org/licenses/>.
252
253=== added directory 'sru/management/commands'
254=== added file 'sru/management/commands/__init__.py'
255--- sru/management/commands/__init__.py 1970-01-01 00:00:00 +0000
256+++ sru/management/commands/__init__.py 2013-01-04 18:06:05 +0000
257@@ -0,0 +1,14 @@
258+# QA Dashboard
259+# Copyright 2012 Canonical Ltd.
260+
261+# This program is free software: you can redistribute it and/or modify it
262+# under the terms of the GNU Affero General Public License version 3, as published
263+# by the Free Software Foundation.
264+
265+# This program is distributed in the hope that it will be useful, but
266+# WITHOUT ANY WARRANTY; without even the implied warranties of
267+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
268+# PURPOSE. See the GNU Affero General Public License for more details.
269+
270+# You should have received a copy of the GNU Affero General Public License along
271+# with this program. If not, see <http://www.gnu.org/licenses/>.
272
273=== renamed file 'dashboard/management/commands/jenkins_pull_sru.py' => 'sru/management/commands/jenkins_pull_sru.py'
274--- dashboard/management/commands/jenkins_pull_sru.py 2013-01-03 21:22:50 +0000
275+++ sru/management/commands/jenkins_pull_sru.py 2013-01-04 18:06:05 +0000
276@@ -28,7 +28,7 @@
277
278 from common.utils import regexes
279
280-from dashboard.models import (
281+from sru.models import (
282 Kernel,
283 SRUResult,
284 SRUResultLog,
285
286=== added directory 'sru/migrations'
287=== added file 'sru/migrations/0001_add_initial_models.py'
288--- sru/migrations/0001_add_initial_models.py 1970-01-01 00:00:00 +0000
289+++ sru/migrations/0001_add_initial_models.py 2013-01-04 18:06:05 +0000
290@@ -0,0 +1,136 @@
291+# -*- coding: utf-8 -*-
292+import datetime
293+from south.db import db
294+from south.v2 import SchemaMigration
295+from django.db import models, connection
296+
297+
298+class Migration(SchemaMigration):
299+
300+ def forwards(self, orm):
301+
302+ table_names = connection.introspection.table_names()
303+
304+ if 'kernels' not in table_names:
305+ # Adding model 'Kernel'
306+ db.create_table('kernels', (
307+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
308+ ('created_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
309+ ('updated_at', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
310+ ('internal', self.gf('django.db.models.fields.BooleanField')(default=True)),
311+ ('publish', self.gf('django.db.models.fields.BooleanField')(default=True)),
312+ ('job_type', self.gf('django.db.models.fields.CharField')(max_length=100)),
313+ ('release', self.gf('django.db.models.fields.CharField')(max_length=100)),
314+ ('variant', self.gf('django.db.models.fields.CharField')(max_length=100)),
315+ ('arch', self.gf('django.db.models.fields.CharField')(max_length=100)),
316+ ('gpu', self.gf('django.db.models.fields.CharField')(max_length=100)),
317+ ('version', self.gf('django.db.models.fields.CharField')(max_length=100)),
318+ ))
319+ db.send_create_signal('sru', ['Kernel'])
320+
321+ if 'sru_results' not in table_names:
322+ # Adding model 'SRUResult'
323+ db.create_table('sru_results', (
324+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
325+ ('created_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
326+ ('updated_at', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
327+ ('internal', self.gf('django.db.models.fields.BooleanField')(default=True)),
328+ ('publish', self.gf('django.db.models.fields.BooleanField')(default=True)),
329+ ('kernel', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['sru.Kernel'])),
330+ ('jenkins_build', self.gf('django.db.models.fields.CharField')(max_length=255)),
331+ ('jenkins_url', self.gf('django.db.models.fields.URLField')(max_length=200)),
332+ ('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
333+ ('pass_count', self.gf('django.db.models.fields.IntegerField')()),
334+ ('fail_count', self.gf('django.db.models.fields.IntegerField')()),
335+ ('skip_count', self.gf('django.db.models.fields.IntegerField')()),
336+ ('total_count', self.gf('django.db.models.fields.IntegerField')()),
337+ ('ran_at', self.gf('django.db.models.fields.DateTimeField')()),
338+ ))
339+ db.send_create_signal('sru', ['SRUResult'])
340+
341+ if 'sru_results_bugs' not in table_names:
342+ # Adding M2M table for field bugs on 'SRUResult'
343+ db.create_table('sru_results_bugs', (
344+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
345+ ('sruresult', models.ForeignKey(orm['sru.sruresult'], null=False)),
346+ ('bug', models.ForeignKey(orm['common.bug'], null=False))
347+ ))
348+ db.create_unique('sru_results_bugs', ['sruresult_id', 'bug_id'])
349+
350+ if 'sru_result_logs' not in table_names:
351+ # Adding model 'SRUResultLog'
352+ db.create_table('sru_result_logs', (
353+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
354+ ('created_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
355+ ('updated_at', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
356+ ('internal', self.gf('django.db.models.fields.BooleanField')(default=True)),
357+ ('publish', self.gf('django.db.models.fields.BooleanField')(default=True)),
358+ ('display_name', self.gf('django.db.models.fields.CharField')(max_length=255, null=True)),
359+ ('path', self.gf('django.db.models.fields.TextField')()),
360+ ('sru_result', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['sru.SRUResult'])),
361+ ('remote_url', self.gf('django.db.models.fields.URLField')(max_length=200)),
362+ ))
363+ db.send_create_signal('sru', ['SRUResultLog'])
364+
365+
366+ def backwards(self, orm):
367+ pass
368+
369+ models = {
370+ 'common.bug': {
371+ 'Meta': {'object_name': 'Bug', 'db_table': "'bugs'"},
372+ 'bug_no': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
373+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
374+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
375+ 'internal': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
376+ 'publish': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
377+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
378+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
379+ },
380+ 'sru.kernel': {
381+ 'Meta': {'object_name': 'Kernel', 'db_table': "'kernels'"},
382+ 'arch': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
383+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
384+ 'gpu': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
385+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
386+ 'internal': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
387+ 'job_type': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
388+ 'publish': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
389+ 'release': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
390+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
391+ 'variant': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
392+ 'version': ('django.db.models.fields.CharField', [], {'max_length': '100'})
393+ },
394+ 'sru.sruresult': {
395+ 'Meta': {'object_name': 'SRUResult', 'db_table': "'sru_results'"},
396+ 'bugs': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['common.Bug']", 'symmetrical': 'False'}),
397+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
398+ 'fail_count': ('django.db.models.fields.IntegerField', [], {}),
399+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
400+ 'internal': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
401+ 'jenkins_build': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
402+ 'jenkins_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
403+ 'kernel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sru.Kernel']"}),
404+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
405+ 'pass_count': ('django.db.models.fields.IntegerField', [], {}),
406+ 'publish': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
407+ 'ran_at': ('django.db.models.fields.DateTimeField', [], {}),
408+ 'skip_count': ('django.db.models.fields.IntegerField', [], {}),
409+ 'total_count': ('django.db.models.fields.IntegerField', [], {}),
410+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
411+ },
412+ 'sru.sruresultlog': {
413+ 'Meta': {'object_name': 'SRUResultLog', 'db_table': "'sru_result_logs'"},
414+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
415+ 'display_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
416+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
417+ 'internal': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
418+ 'path': ('django.db.models.fields.TextField', [], {}),
419+ 'publish': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
420+ 'remote_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
421+ 'sru_result': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sru.SRUResult']"}),
422+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
423+ }
424+ }
425+
426+ complete_apps = ['sru']
427
428=== added file 'sru/migrations/__init__.py'
429=== added file 'sru/models.py'
430--- sru/models.py 1970-01-01 00:00:00 +0000
431+++ sru/models.py 2013-01-04 18:06:05 +0000
432@@ -0,0 +1,144 @@
433+# QA Dashboard
434+# Copyright 2012 Canonical Ltd.
435+
436+# This program is free software: you can redistribute it and/or modify it
437+# under the terms of the GNU Affero General Public License version 3, as published
438+# by the Free Software Foundation.
439+
440+# This program is distributed in the hope that it will be useful, but
441+# WITHOUT ANY WARRANTY; without even the implied warranties of
442+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
443+# PURPOSE. See the GNU Affero General Public License for more details.
444+
445+# You should have received a copy of the GNU Affero General Public License along
446+# with this program. If not, see <http://www.gnu.org/licenses/>.
447+
448+from django.db import models
449+import datetime
450+
451+from common.models import DashboardBaseModel, Bug
452+
453+class Kernel(DashboardBaseModel):
454+ class Meta:
455+ db_table = "kernels"
456+
457+ job_type = models.CharField(max_length=100)
458+ release = models.CharField(max_length=100)
459+ variant = models.CharField(max_length=100)
460+ arch = models.CharField(max_length=100)
461+ gpu = models.CharField(max_length=100)
462+ version = models.CharField(max_length=100)
463+
464+ # Used by MySerializer to add property fields to the JSON representation
465+ # of an instance of this class.
466+ extra_fields = [
467+ 'pass_count',
468+ 'skip_count',
469+ 'fail_count',
470+ 'total_count',
471+ 'pass_rate',
472+ 'pass_rate_pct',
473+ 'bug_count',
474+ 'log_count',
475+ ]
476+
477+ def debug_str(self):
478+ return "{}-{}-{}-{}".format(
479+ self.release,
480+ self.variant,
481+ self.arch,
482+ self.gpu,
483+ )
484+
485+ @property
486+ def name(self):
487+ return "{}-{}".format(self.release, self.variant)
488+
489+ @property
490+ def total_count(self):
491+ return self.sruresult_set.aggregate(models.Sum('total_count'))['total_count__sum'] or 0
492+
493+ @property
494+ def pass_count(self):
495+ return self.sruresult_set.aggregate(models.Sum('pass_count'))['pass_count__sum'] or 0
496+
497+ @property
498+ def fail_count(self):
499+ return self.sruresult_set.aggregate(models.Sum('fail_count'))['fail_count__sum'] or 0
500+
501+ @property
502+ def skip_count(self):
503+ return self.sruresult_set.aggregate(models.Sum('skip_count'))['skip_count__sum'] or 0
504+
505+ @property
506+ def pass_rate(self):
507+ return self.pass_count*1.0 / self.total_count if self.total_count > 0 else 0
508+
509+ @property
510+ def pass_rate_pct(self):
511+ return "%d%%" % int(self.pass_rate*100)
512+
513+ @property
514+ def bug_count(self):
515+ return self.sruresult_set.annotate(num_bugs=models.Count('bugs')).aggregate(models.Sum('num_bugs'))['num_bugs__sum'] or 0
516+
517+ @property
518+ def log_count(self):
519+ return self.sruresultlog_set.count()
520+
521+ @property
522+ def last_run_date(self):
523+ return self.sruresult_set.aggregate(models.Max('ran_at'))['ran_at__max'].strftime("%Y-%m-%d %H:%M")
524+
525+# XXX: refactor this and Result
526+class SRUResult(DashboardBaseModel):
527+ class Meta:
528+ db_table = 'sru_results'
529+
530+ kernel = models.ForeignKey(Kernel)
531+ bugs = models.ManyToManyField(Bug)
532+
533+ jenkins_build = models.CharField(max_length=255)
534+ jenkins_url = models.URLField()
535+ name = models.CharField(max_length=255)
536+ pass_count = models.IntegerField()
537+ fail_count = models.IntegerField()
538+ skip_count = models.IntegerField()
539+ total_count = models.IntegerField()
540+ ran_at = models.DateTimeField('date run')
541+
542+ # Used by MySerializer to add property fields to the JSON representation
543+ # of an instance of this class.
544+ extra_fields = [
545+ 'pass_rate',
546+ 'pass_rate_pct',
547+ 'bug_count',
548+ 'log_count',
549+ ]
550+
551+ @property
552+ def pass_rate(self):
553+ return self.pass_count*1.0 / self.total_count if self.total_count > 0 else 0
554+
555+ @property
556+ def pass_rate_pct(self):
557+ return "%d%%" % int(self.pass_rate*100)
558+
559+ @property
560+ def bug_count(self):
561+ return self.bugs.count()
562+
563+ @property
564+ def log_count(self):
565+ return self.resultlog_set.count()
566+
567+class SRUResultLog(DashboardBaseModel):
568+ class Meta:
569+ db_table = 'sru_result_logs'
570+ display_name = models.CharField(max_length=255, null = True)
571+ path = models.TextField()
572+ sru_result = models.ForeignKey('SRUResult')
573+ remote_url = models.URLField()
574+
575+ def __unicode__(self):
576+ return self.path
577
578=== added directory 'sru/templates'
579=== renamed directory 'dashboard/templates/sru' => 'sru/templates/sru'
580=== added file 'sru/tests.py'
581--- sru/tests.py 1970-01-01 00:00:00 +0000
582+++ sru/tests.py 2013-01-04 18:06:05 +0000
583@@ -0,0 +1,16 @@
584+"""
585+This file demonstrates writing tests using the unittest module. These will pass
586+when you run "manage.py test".
587+
588+Replace this with more appropriate tests for your application.
589+"""
590+
591+from django.test import TestCase
592+
593+
594+class SimpleTest(TestCase):
595+ def test_basic_addition(self):
596+ """
597+ Tests that 1 + 1 always equals 2.
598+ """
599+ self.assertEqual(1 + 1, 2)
600
601=== renamed file 'dashboard/views/sru.py' => 'sru/views.py'
602--- dashboard/views/sru.py 2013-01-03 21:22:50 +0000
603+++ sru/views.py 2013-01-04 18:06:05 +0000
604@@ -18,7 +18,7 @@
605 from django.db.models import Sum, F
606 from django.template import RequestContext
607
608-from dashboard.models import Kernel
609+from sru.models import Kernel
610 from common.utils import (
611 JSONResponse,
612 MySerializer,

Subscribers

People subscribed via source and target branches