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