Merge lp:~dooferlad/linaro-ci-dashboard/add_ci_job_loop into lp:linaro-ci-dashboard

Proposed by James Tunnicliffe
Status: Merged
Merged at revision: 70
Proposed branch: lp:~dooferlad/linaro-ci-dashboard/add_ci_job_loop
Merge into: lp:linaro-ci-dashboard
Diff against target: 562 lines (+349/-17)
18 files modified
HACKING (+12/-0)
Makefile (+2/-0)
README (+1/-0)
config_template/config.xml (+2/-2)
dashboard/frontend/api/api.py (+19/-2)
dashboard/frontend/api/urls.py (+1/-0)
dashboard/frontend/ci_job/migrations/0001_initial.py (+60/-0)
dashboard/frontend/ci_job/models/__init__.py (+1/-0)
dashboard/frontend/ci_job/models/ci_job.py (+107/-0)
dashboard/frontend/ci_job/urls.py (+31/-0)
dashboard/frontend/ci_job/views/ci_job_build_view.py (+25/-0)
dashboard/frontend/ci_job/views/ci_job_detail_view.py (+24/-0)
dashboard/frontend/models/loop_reference.py (+1/-0)
dashboard/frontend/tests/test_api.py (+58/-13)
dashboard/frontend/views/index_view.py (+2/-0)
dashboard/settings.py (+1/-0)
dashboard/urls.py (+1/-0)
requirements.txt (+1/-0)
To merge this branch: bzr merge lp:~dooferlad/linaro-ci-dashboard/add_ci_job_loop
Reviewer Review Type Date Requested Status
Linaro Infrastructure Pending
Review via email: mp+147694@code.launchpad.net
To post a comment you must log in.
Revision history for this message
James Tunnicliffe (dooferlad) wrote :

Crumbs. Got old tests in this. Will remove.

75. By James Tunnicliffe

Removed invalid tests

76. By James Tunnicliffe

Removed commented out code

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'HACKING'
2--- HACKING 2012-09-21 09:24:01 +0000
3+++ HACKING 2013-02-11 15:46:21 +0000
4@@ -49,6 +49,18 @@
5
6 Tests should be written and defined inside each sub-application.
7
8+When defining a new application, make sure the model app_label matches what is
9+listed in settings.py:
10+
11+class CIJob(Loop):
12+ """Defines the base class for a CI Job."""
13+ class Meta:
14+ app_label = 'ci_job'
15+
16+INSTALLED_APPS = (
17+...
18+ 'frontend.ci_job',
19+
20 == Class Hierarchy ==
21
22 === Templates & Views ===
23
24=== modified file 'Makefile'
25--- Makefile 2012-09-24 13:18:02 +0000
26+++ Makefile 2013-02-11 15:46:21 +0000
27@@ -24,6 +24,8 @@
28 echo "No changes to android_textfield_loop models."
29 python dashboard/manage.py schemamigration hwpack_loop --auto || \
30 echo "No changes to hwpack_loop models."
31+ python dashboard/manage.py schemamigration ci_job --auto || \
32+ echo "No changes to ci_job models."
33 python dashboard/manage.py migrate
34
35 migrate: syncdb
36
37=== modified file 'README'
38--- README 2013-02-01 11:49:24 +0000
39+++ README 2013-02-11 15:46:21 +0000
40@@ -17,6 +17,7 @@
41 build-essential
42 openjdk-6-jre-headless
43 python-tastypie
44+ python-simplejson
45
46 To unit test the API that tastypie provides you need Django version of at least
47 1.4. If you have Django 1.3 the API will still work, but not be unit tested.
48
49=== modified file 'config_template/config.xml'
50--- config_template/config.xml 2012-09-20 08:46:37 +0000
51+++ config_template/config.xml 2013-02-11 15:46:21 +0000
52@@ -50,7 +50,7 @@
53 </views>
54 <primaryView>All</primaryView>
55 <slaveAgentPort>0</slaveAgentPort>
56- <label>IntegrationLoop AndroidLoop KernelLoop AndroidTextFieldLoop HwpackLoop</label>
57+ <label>IntegrationLoop AndroidLoop KernelLoop AndroidTextFieldLoop HwpackLoop CIJob</label>
58 <nodeProperties/>
59 <globalNodeProperties/>
60-</hudson>
61\ No newline at end of file
62+</hudson>
63
64=== modified file 'dashboard/frontend/api/api.py'
65--- dashboard/frontend/api/api.py 2013-02-04 10:59:49 +0000
66+++ dashboard/frontend/api/api.py 2013-02-11 15:46:21 +0000
67@@ -16,9 +16,10 @@
68 # along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>.
69
70 from tastypie.resources import ModelResource
71-from tastypie.authorization import DjangoAuthorization
72-from tastypie.authentication import ApiKeyAuthentication
73+from tastypie.authorization import DjangoAuthorization, Authorization
74+from tastypie.authentication import ApiKeyAuthentication, Authentication
75 from dashboard.frontend.models.loop import Loop
76+from frontend.ci_job.models.ci_job import CIJob
77
78 """
79 Add API endpoint logic here. The documentation to do this can be found here:
80@@ -54,3 +55,19 @@
81 resource_name = 'loops'
82 authorization = DjangoAuthorization()
83 authentication = ApiKeyAuthentication()
84+
85+class CIJobResource(ModelResource):
86+ class Meta:
87+ """Returns a list of all loops."""
88+ queryset = CIJob.objects.all()
89+ resource_name = 'jobs'
90+ list_allowed_methods = ['get', 'post']
91+ detail_allowed_methods = ['get', 'post', 'put', 'delete']
92+
93+ #http://django-tastypie.readthedocs.org/en/latest/authorization.html
94+ # Currently everyone who has an API key is equal. Suggest we tie this
95+ # down using a custom Authorization class (see above link) so anyone
96+ # can create and modify their own jobs, but only some users have
97+ # the ability to delete and modify other users' jobs.
98+ authorization = Authorization() #DjangoAuthorization()
99+ authentication = ApiKeyAuthentication()
100
101=== modified file 'dashboard/frontend/api/urls.py'
102--- dashboard/frontend/api/urls.py 2013-02-04 17:55:49 +0000
103+++ dashboard/frontend/api/urls.py 2013-02-11 15:46:21 +0000
104@@ -7,6 +7,7 @@
105 # Register new resources here (probably defined in api.py)
106 v1_api.register(LoginTestResource())
107 v1_api.register(LoopsResource())
108+v1_api.register(CIJobResource())
109
110 urlpatterns = patterns('',
111 (r'^api/', include(v1_api.urls)),
112
113=== added directory 'dashboard/frontend/ci_job'
114=== added file 'dashboard/frontend/ci_job/__init__.py'
115=== added directory 'dashboard/frontend/ci_job/migrations'
116=== added file 'dashboard/frontend/ci_job/migrations/0001_initial.py'
117--- dashboard/frontend/ci_job/migrations/0001_initial.py 1970-01-01 00:00:00 +0000
118+++ dashboard/frontend/ci_job/migrations/0001_initial.py 2013-02-11 15:46:21 +0000
119@@ -0,0 +1,60 @@
120+# -*- coding: utf-8 -*-
121+import datetime
122+from south.db import db
123+from south.v2 import SchemaMigration
124+from django.db import models
125+
126+
127+class Migration(SchemaMigration):
128+
129+ def forwards(self, orm):
130+ # Adding model 'CIJob'
131+ db.create_table('ci_job_cijob', (
132+ ('loop_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['frontend.Loop'], unique=True, primary_key=True)),
133+ ('vcs_url', self.gf('django.db.models.fields.CharField')(max_length=255)),
134+ ('vcs_branch', self.gf('django.db.models.fields.CharField')(default='', max_length=255)),
135+ ('vcs_tag', self.gf('django.db.models.fields.CharField')(default='', max_length=255)),
136+ ('file_name', self.gf('django.db.models.fields.CharField')(max_length=255)),
137+ ('class_name', self.gf('django.db.models.fields.CharField')(max_length=255)),
138+ ('run_when_ready', self.gf('django.db.models.fields.BooleanField')(default=False)),
139+ ))
140+ db.send_create_signal('ci_job', ['CIJob'])
141+
142+
143+ def backwards(self, orm):
144+ # Deleting model 'CIJob'
145+ db.delete_table('ci_job_cijob')
146+
147+
148+ models = {
149+ 'ci_job.cijob': {
150+ 'Meta': {'object_name': 'CIJob', '_ormbases': ['frontend.Loop']},
151+ 'class_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
152+ 'file_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
153+ 'loop_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['frontend.Loop']", 'unique': 'True', 'primary_key': 'True'}),
154+ 'run_when_ready': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
155+ 'vcs_branch': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
156+ 'vcs_tag': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
157+ 'vcs_url': ('django.db.models.fields.CharField', [], {'max_length': '255'})
158+ },
159+ 'frontend.loop': {
160+ 'Meta': {'object_name': 'Loop'},
161+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
162+ 'is_official': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
163+ 'is_restricted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
164+ 'lava_tests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
165+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}),
166+ 'next_loop': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'previous_loop'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['frontend.Loop']", 'blank': 'True', 'unique': 'True'}),
167+ 'server': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['jenkinsserver.JenkinsServer']", 'null': 'True', 'on_delete': 'models.SET_NULL'}),
168+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'})
169+ },
170+ 'jenkinsserver.jenkinsserver': {
171+ 'Meta': {'object_name': 'JenkinsServer'},
172+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
173+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
174+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
175+ 'username': ('django.db.models.fields.CharField', [], {'max_length': '100'})
176+ }
177+ }
178+
179+ complete_apps = ['ci_job']
180\ No newline at end of file
181
182=== added file 'dashboard/frontend/ci_job/migrations/__init__.py'
183=== added directory 'dashboard/frontend/ci_job/models'
184=== added file 'dashboard/frontend/ci_job/models/__init__.py'
185--- dashboard/frontend/ci_job/models/__init__.py 1970-01-01 00:00:00 +0000
186+++ dashboard/frontend/ci_job/models/__init__.py 2013-02-11 15:46:21 +0000
187@@ -0,0 +1,1 @@
188+from frontend.ci_job.models.ci_job import *
189
190=== added file 'dashboard/frontend/ci_job/models/ci_job.py'
191--- dashboard/frontend/ci_job/models/ci_job.py 1970-01-01 00:00:00 +0000
192+++ dashboard/frontend/ci_job/models/ci_job.py 2013-02-11 15:46:21 +0000
193@@ -0,0 +1,107 @@
194+# Copyright (C) 2012 Linaro
195+#
196+# This file is part of linaro-ci-dashboard.
197+#
198+# linaro-ci-dashboard is free software: you can redistribute it and/or modify
199+# it under the terms of the GNU Affero General Public License as published by
200+# the Free Software Foundation, either version 3 of the License, or
201+# (at your option) any later version.
202+#
203+# linaro-ci-dashboard is distributed in the hope that it will be useful,
204+# but WITHOUT ANY WARRANTY; without even the implied warranty of
205+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
206+# GNU Affero General Public License for more details.
207+#
208+# You should have received a copy of the GNU Affero General Public License
209+# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>.
210+
211+from django.db import models
212+from frontend.models.loop import Loop
213+from jenkinsserver.models.jenkins_server import JenkinsServer
214+#from django.contrib.auth.models import User
215+
216+
217+class CIJob(Loop):
218+ """Defines the base class for a CI Job."""
219+ class Meta:
220+ app_label = 'ci_job'
221+
222+ vcs_url = models.CharField(max_length=255,
223+ verbose_name='Configuration repository')
224+ vcs_branch = models.CharField(max_length=255,
225+ verbose_name='Configuration branch',
226+ default='')
227+ vcs_tag = models.CharField(max_length=255,
228+ verbose_name='Configuration tag',
229+ default='')
230+ file_name = models.CharField(max_length=255,
231+ verbose_name='Configuration file name')
232+ class_name = models.CharField(max_length=255,
233+ verbose_name='Configuration class name')
234+ run_when_ready = models.BooleanField(default=False)
235+
236+ #job_owner = models.ForeignKey(User, editable=False,
237+ # verbose_name='Job Owner')
238+
239+ def save(self, *args, **kwargs):
240+ self.server = JenkinsServer.objects.get(id=1)
241+ self.type = self.__class__.__name__
242+ super(self.__class__, self).save(*args, **kwargs)
243+ # We do not want a failure in remote server to affect the
244+ # CI Loop flow.
245+ try:
246+ self.server.create_or_update_loop(self)
247+ except:
248+ # TODO: Log error.
249+ pass
250+
251+ def schedule_build(self, parameters=None):
252+ parameters = {'parameter': [{'delay': '0'}]}
253+ return super(self.__class__, self).schedule_build(parameters)
254+
255+ def base64_config(self,
256+ include=None,
257+ exclude=None,
258+ capitalize=False,
259+ upper=False):
260+ exclude = ['id', 'server', 'loop_ptr', 'next_loop', 'name', 'type']
261+ return super(CIJob, self).base64_config(include=include,
262+ exclude=exclude,
263+ capitalize=capitalize,
264+ upper=True)
265+
266+ def preconfigure(self, configuration=None):
267+ """Makes a build parameter dict from build result configuration.
268+
269+ This method should be overridden by subclasses.
270+ """
271+ if isinstance(configuration, dict):
272+ # The name is the name of the loop that is calling the chained one,
273+ # not the one we want to actually configure, we drop it.
274+ configuration.pop('name')
275+ unmatched_values = u''
276+ for key, value in configuration.iteritems():
277+ if hasattr(self, key.lower()):
278+ setattr(self, key.lower(), value)
279+ else:
280+ # If the attr cannot be found, we throw everything in
281+ # user_defined_values since the text field is free form.
282+ unmatched_values = u'%s=%s\n' % (key.upper(), str(value))
283+
284+ self.user_defined_values = unmatched_values
285+ self.save()
286+ else:
287+ self.log.error("Parameter was not a 'dict' instance.")
288+ return {}
289+
290+ @models.permalink
291+ def get_detail_url(self):
292+ return 'CIJobDetail', (), {'slug': self.name}
293+
294+ @models.permalink
295+ def get_build_url(self):
296+ return 'CIJobBuild', (), {'slug': self.name}
297+
298+ @models.permalink
299+ def get_update_url(self):
300+ return 'CIJobUpdate', (), {'slug': self.name}
301
302=== added file 'dashboard/frontend/ci_job/urls.py'
303--- dashboard/frontend/ci_job/urls.py 1970-01-01 00:00:00 +0000
304+++ dashboard/frontend/ci_job/urls.py 2013-02-11 15:46:21 +0000
305@@ -0,0 +1,31 @@
306+# Copyright (C) 2012 Linaro
307+#
308+# This file is part of linaro-ci-dashboard.
309+#
310+# linaro-ci-dashboard is free software: you can redistribute it and/or modify
311+# it under the terms of the GNU Affero General Public License as published by
312+# the Free Software Foundation, either version 3 of the License, or
313+# (at your option) any later version.
314+#
315+# linaro-ci-dashboard is distributed in the hope that it will be useful,
316+# but WITHOUT ANY WARRANTY; without even the implied warranty of
317+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
318+# GNU Affero General Public License for more details.
319+#
320+# You should have received a copy of the GNU Affero General Public License
321+# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>.
322+
323+from django.conf.urls.defaults import patterns, url
324+
325+from frontend.ci_job.views.ci_job_detail_view \
326+ import CIJobDetailView
327+from frontend.ci_job.views.ci_job_build_view \
328+ import CIJobBuildView
329+
330+
331+urlpatterns = patterns('',
332+ url(r'^ci_job/detail/(?P<slug>[\w|\W]+)/$',
333+ CIJobDetailView.as_view(), name='CIJobDetail'),
334+ url(r'^ci_job/build/(?P<slug>[\w|\W]+)/$',
335+ CIJobBuildView.as_view(), name='CIJobBuild'),
336+)
337
338=== added directory 'dashboard/frontend/ci_job/views'
339=== added file 'dashboard/frontend/ci_job/views/__init__.py'
340=== added file 'dashboard/frontend/ci_job/views/ci_job_build_view.py'
341--- dashboard/frontend/ci_job/views/ci_job_build_view.py 1970-01-01 00:00:00 +0000
342+++ dashboard/frontend/ci_job/views/ci_job_build_view.py 2013-02-11 15:46:21 +0000
343@@ -0,0 +1,25 @@
344+#!/usr/bin/env python
345+# Copyright (C) 2012 Linaro
346+#
347+# This file is part of linaro-ci-dashboard.
348+#
349+# linaro-ci-dashboard is free software: you can redistribute it and/or modify
350+# it under the terms of the GNU Affero General Public License as published by
351+# the Free Software Foundation, either version 3 of the License, or
352+# (at your option) any later version.
353+#
354+# linaro-ci-dashboard is distributed in the hope that it will be useful,
355+# but WITHOUT ANY WARRANTY; without even the implied warranty of
356+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
357+# GNU Affero General Public License for more details.
358+#
359+# You should have received a copy of the GNU Affero General Public License
360+# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>.
361+
362+from frontend.ci_job.models.ci_job import CIJob
363+from frontend.views.loop_build_view import LoopBuildView
364+
365+
366+class CIJobBuildView(LoopBuildView):
367+
368+ model = CIJob
369
370=== added file 'dashboard/frontend/ci_job/views/ci_job_detail_view.py'
371--- dashboard/frontend/ci_job/views/ci_job_detail_view.py 1970-01-01 00:00:00 +0000
372+++ dashboard/frontend/ci_job/views/ci_job_detail_view.py 2013-02-11 15:46:21 +0000
373@@ -0,0 +1,24 @@
374+# Copyright (C) 2012 Linaro
375+#
376+# This file is part of linaro-ci-dashboard.
377+#
378+# linaro-ci-dashboard is free software: you can redistribute it and/or modify
379+# it under the terms of the GNU Affero General Public License as published by
380+# the Free Software Foundation, either version 3 of the License, or
381+# (at your option) any later version.
382+#
383+# linaro-ci-dashboard is distributed in the hope that it will be useful,
384+# but WITHOUT ANY WARRANTY; without even the implied warranty of
385+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
386+# GNU Affero General Public License for more details.
387+#
388+# You should have received a copy of the GNU Affero General Public License
389+# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>.
390+
391+from frontend.ci_job.models.ci_job import CIJob
392+from frontend.views.loop_detail_view import LoopDetailView
393+
394+
395+class CIJobDetailView(LoopDetailView):
396+
397+ model = CIJob
398
399=== modified file 'dashboard/frontend/models/loop_reference.py'
400--- dashboard/frontend/models/loop_reference.py 2012-09-18 12:16:59 +0000
401+++ dashboard/frontend/models/loop_reference.py 2013-02-11 15:46:21 +0000
402@@ -23,3 +23,4 @@
403 INTEGRATION_LOOP = ('IntegrationLoop')
404 ANDROID_TEXTFIELD_LOOP = ('AndroidTextFieldLoop')
405 HWPACK_LOOP = ('HwpackLoop')
406+CI_JOB = ('CIJob')
407
408=== modified file 'dashboard/frontend/tests/test_api.py'
409--- dashboard/frontend/tests/test_api.py 2013-02-04 17:55:49 +0000
410+++ dashboard/frontend/tests/test_api.py 2013-02-11 15:46:21 +0000
411@@ -20,8 +20,10 @@
412 from tastypie.models import ApiKey
413 from dashboard.frontend.models.loop import Loop
414 from dashboard.frontend.android_build.models.android_loop import AndroidLoop
415+from dashboard.frontend.ci_job.models.ci_job import CIJob
416 import requests
417 from urlparse import urljoin
418+import simplejson
419
420
421 class ApiTests(LiveServerTestCase):
422@@ -32,13 +34,18 @@
423 def setUp(self):
424 super(ApiTests, self).setUp()
425
426+ self.settings = {}
427+ self.settings["ci_server"] = "http://localhost:8081"
428+ self.settings["api_prefix"] = "/api/dev/"
429+ self.settings["username"] = 'daniel'
430+ self.settings["password"] = 'pass'
431+ self.settings["api_key"] = "0"
432+
433 # Create a user.
434- self.username = 'daniel'
435- self.password = 'pass'
436 self.user = User.objects.create_user(
437- self.username, 'daniel@example.com', self.password)
438-
439- self.api_key = "0"
440+ self.settings["username"],
441+ 'daniel@example.com',
442+ self.settings["password"])
443
444 # Add a couple of jobs to test against.
445 self.android_loop = AndroidLoop()
446@@ -51,16 +58,35 @@
447 self.loop.type = Loop.__class__.__name__
448 self.loop.save()
449
450- def get(self, url):
451- payload = {"username": self.username,
452- "api_key": self.api_key,
453- "format": "json"}
454- url = urljoin("http://localhost:8081", "/api/dev/" + url)
455- return requests.get(url, params=payload)
456+ def get(self, url, in_params=None):
457+ url, params = self._prep_request(url, in_params)
458+ return requests.get(url, params=params)
459+
460+ def post(self, url, data, in_params=None):
461+ url, params = self._prep_request(url, in_params)
462+ return requests.post(url, data=data, params=params,
463+ headers={"content-type": "application/json"})
464+
465+ def _prep_request(self, url, in_params=None):
466+ params = {"username": self.settings["username"],
467+ "api_key": self.settings["api_key"],
468+ "format": "json"}
469+
470+ url = urljoin(self.settings["ci_server"],
471+ self.settings["api_prefix"] + url)
472+
473+ # If we don't have a trailing slash, we will just be redirected. Avoid
474+ # the extra call.
475+ if url[-1] != "/":
476+ url += "/"
477+
478+ if in_params:
479+ params.update(in_params)
480+
481+ return url, params
482
483 def login(self):
484- self.api_key = ApiKey.objects.create(user=self.user).key
485- #self.create_apikey(self.username, self.api_key)
486+ self.settings["api_key"] = ApiKey.objects.create(user=self.user).key
487
488 def test_login_test_unauthorzied(self):
489 r = self.get("login_test")
490@@ -93,3 +119,22 @@
491 api_test_names = {json[0]['name'], json[1]['name']}
492 test_names = {self.android_loop.name, self.loop.name}
493 self.assertEqual(api_test_names, test_names)
494+
495+ def test_add_job(self):
496+ self.login()
497+ data = {
498+ "vcs_url": "vcsurl",
499+ "file_name": "filename",
500+ "class_name": "classname",
501+ "run": False,
502+ "name": "jobname"
503+ }
504+ json_data = simplejson.dumps(data)
505+
506+ r = self.post("jobs", json_data, {})
507+ self.assertEqual(r.status_code, requests.codes.created)
508+
509+ jobs = CIJob.objects.all()
510+
511+ self.assertEqual(len(jobs), 1)
512+ self.assertEqual(jobs[0].name, data["name"])
513
514=== modified file 'dashboard/frontend/views/index_view.py'
515--- dashboard/frontend/views/index_view.py 2012-09-13 11:37:13 +0000
516+++ dashboard/frontend/views/index_view.py 2013-02-11 15:46:21 +0000
517@@ -25,6 +25,7 @@
518 from frontend.android_textfield_loop.models.android_textfield_loop \
519 import AndroidTextFieldLoop
520 from frontend.hwpack_loop.models.hwpack_loop import HwpackLoop
521+from frontend.ci_job.models.ci_job import CIJob
522
523 class IndexView(TemplateView):
524
525@@ -42,4 +43,5 @@
526 context['kernel_loops'] = KernelLoop.objects.all()
527 context['android_textfield_loops'] = AndroidTextFieldLoop.objects.all()
528 context['hwpack_loops'] = HwpackLoop.objects.all()
529+ context['ci_jobs'] = CIJob.objects.all()
530 return context
531
532=== modified file 'dashboard/settings.py'
533--- dashboard/settings.py 2013-01-30 17:20:40 +0000
534+++ dashboard/settings.py 2013-02-11 15:46:21 +0000
535@@ -158,6 +158,7 @@
536 'frontend.android_textfield_loop',
537 'frontend.hwpack_loop',
538 'frontend.api',
539+ 'frontend.ci_job',
540 'tastypie',
541 'south',
542 # Uncomment the next line to enable admin documentation:
543
544=== modified file 'dashboard/urls.py'
545--- dashboard/urls.py 2013-01-21 16:16:03 +0000
546+++ dashboard/urls.py 2013-02-11 15:46:21 +0000
547@@ -40,4 +40,5 @@
548 url(r'^', include('dashboard.frontend.android_textfield_loop.urls')),
549 url(r'^', include('dashboard.frontend.hwpack_loop.urls')),
550 url(r'^', include('dashboard.frontend.api.urls')),
551+ url(r'^', include('dashboard.frontend.ci_job.urls')),
552 )
553
554=== modified file 'requirements.txt'
555--- requirements.txt 2013-02-01 11:39:17 +0000
556+++ requirements.txt 2013-02-11 15:46:21 +0000
557@@ -12,4 +12,5 @@
558 python-jenkins==0.2
559 python-openid==2.2.5
560 requests==1.1.0
561+simplejson==3.0.7
562 wsgiref==0.1.2

Subscribers

People subscribed via source and target branches