Merge lp:~cjohnston/ubuntu-ci-services-itself/ts-project into lp:ubuntu-ci-services-itself
- ts-project
- Merge into trunk
Proposed by
Chris Johnston
Status: | Merged |
---|---|
Approved by: | Chris Johnston |
Approved revision: | 19 |
Merged at revision: | 22 |
Proposed branch: | lp:~cjohnston/ubuntu-ci-services-itself/ts-project |
Merge into: | lp:ubuntu-ci-services-itself |
Diff against target: |
375 lines (+316/-0) 8 files modified
ticket_system/project/__init__.py (+14/-0) ticket_system/project/admin.py (+31/-0) ticket_system/project/api.py (+42/-0) ticket_system/project/migrations/0001_initial.py (+51/-0) ticket_system/project/models.py (+38/-0) ticket_system/project/tests.py (+136/-0) ticket_system/ticket_system/settings.py (+1/-0) ticket_system/ticket_system/urls.py (+3/-0) |
To merge this branch: | bzr merge lp:~cjohnston/ubuntu-ci-services-itself/ts-project |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andy Doan (community) | Approve | ||
Review via email:
|
Commit message
Add project app and read API
Description of the change
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andy Doan (doanac) wrote : | # |
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andy Doan (doanac) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory 'ticket_system/project' |
2 | === added file 'ticket_system/project/__init__.py' |
3 | --- ticket_system/project/__init__.py 1970-01-01 00:00:00 +0000 |
4 | +++ ticket_system/project/__init__.py 2013-12-09 19:42:24 +0000 |
5 | @@ -0,0 +1,14 @@ |
6 | +# Ubuntu Continuous Integration Engine |
7 | +# Copyright 2013 Canonical Ltd. |
8 | + |
9 | +# This program is free software: you can redistribute it and/or modify it |
10 | +# under the terms of the GNU Affero General Public License version 3, as |
11 | +# published by the Free Software Foundation. |
12 | + |
13 | +# This program is distributed in the hope that it will be useful, but |
14 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
15 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
16 | +# PURPOSE. See the GNU Affero General Public License for more details. |
17 | + |
18 | +# You should have received a copy of the GNU Affero General Public License |
19 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
20 | |
21 | === added file 'ticket_system/project/admin.py' |
22 | --- ticket_system/project/admin.py 1970-01-01 00:00:00 +0000 |
23 | +++ ticket_system/project/admin.py 2013-12-09 19:42:24 +0000 |
24 | @@ -0,0 +1,31 @@ |
25 | +# Ubuntu Continuous Integration Engine |
26 | +# Copyright 2013 Canonical Ltd. |
27 | + |
28 | +# This program is free software: you can redistribute it and/or modify it |
29 | +# under the terms of the GNU Affero General Public License version 3, as |
30 | +# published by the Free Software Foundation. |
31 | + |
32 | +# This program is distributed in the hope that it will be useful, but |
33 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
34 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
35 | +# PURPOSE. See the GNU Affero General Public License for more details. |
36 | + |
37 | +# You should have received a copy of the GNU Affero General Public License |
38 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
39 | + |
40 | +from django.contrib import admin |
41 | +from project.models import SourcePackage, BinaryPackage |
42 | + |
43 | + |
44 | +class SourcePackageAdmin(admin.ModelAdmin): |
45 | + search_fields = ['name'] |
46 | + list_display = ('name',) |
47 | + |
48 | + |
49 | +class BinaryPackageAdmin(admin.ModelAdmin): |
50 | + list_filter = ['seeded'] |
51 | + search_fields = ['name', 'sourcepackage'] |
52 | + list_display = ('name', 'sourcepackage', 'seeded') |
53 | + |
54 | +admin.site.register(SourcePackage, SourcePackageAdmin) |
55 | +admin.site.register(BinaryPackage, BinaryPackageAdmin) |
56 | |
57 | === added file 'ticket_system/project/api.py' |
58 | --- ticket_system/project/api.py 1970-01-01 00:00:00 +0000 |
59 | +++ ticket_system/project/api.py 2013-12-09 19:42:24 +0000 |
60 | @@ -0,0 +1,42 @@ |
61 | +# Ubuntu Continuous Integration Engine |
62 | +# Copyright 2013 Canonical Ltd. |
63 | + |
64 | +# This program is free software: you can redistribute it and/or modify it |
65 | +# under the terms of the GNU Affero General Public License version 3, as |
66 | +# published by the Free Software Foundation. |
67 | + |
68 | +# This program is distributed in the hope that it will be useful, but |
69 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
70 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
71 | +# PURPOSE. See the GNU Affero General Public License for more details. |
72 | + |
73 | +# You should have received a copy of the GNU Affero General Public License |
74 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
75 | + |
76 | +from tastypie import fields |
77 | +from tastypie.resources import ModelResource |
78 | +from tastypie.constants import ALL |
79 | +from project.models import SourcePackage, BinaryPackage |
80 | + |
81 | + |
82 | +class SourcePackageResource(ModelResource): |
83 | + |
84 | + class Meta: |
85 | + queryset = SourcePackage.objects.all() |
86 | + allowed_methods = ['get'] |
87 | + filtering = { |
88 | + "name": ('exact', 'startswith'), |
89 | + } |
90 | + |
91 | + |
92 | +class BinaryPackageResource(ModelResource): |
93 | + sourcepackage = fields.ToOneField(SourcePackageResource, 'sourcepackage', |
94 | + full=True) |
95 | + |
96 | + class Meta: |
97 | + queryset = BinaryPackage.objects.all() |
98 | + allowed_methods = ['get'] |
99 | + filtering = { |
100 | + "name": ('exact', 'startswith'), |
101 | + "seeded": ALL, |
102 | + } |
103 | |
104 | === added directory 'ticket_system/project/migrations' |
105 | === added file 'ticket_system/project/migrations/0001_initial.py' |
106 | --- ticket_system/project/migrations/0001_initial.py 1970-01-01 00:00:00 +0000 |
107 | +++ ticket_system/project/migrations/0001_initial.py 2013-12-09 19:42:24 +0000 |
108 | @@ -0,0 +1,51 @@ |
109 | +# -*- coding: utf-8 -*- |
110 | +import datetime |
111 | +from south.db import db |
112 | +from south.v2 import SchemaMigration |
113 | +from django.db import models |
114 | + |
115 | + |
116 | +class Migration(SchemaMigration): |
117 | + |
118 | + def forwards(self, orm): |
119 | + # Adding model 'SourcePackage' |
120 | + db.create_table('sourcepackage', ( |
121 | + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), |
122 | + ('name', self.gf('django.db.models.fields.CharField')(max_length=4096)), |
123 | + )) |
124 | + db.send_create_signal(u'project', ['SourcePackage']) |
125 | + |
126 | + # Adding model 'BinaryPackage' |
127 | + db.create_table('binarypackage', ( |
128 | + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), |
129 | + ('name', self.gf('django.db.models.fields.CharField')(max_length=4096)), |
130 | + ('sourcepackage', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['project.SourcePackage'])), |
131 | + ('seeded', self.gf('django.db.models.fields.BooleanField')(default=False)), |
132 | + )) |
133 | + db.send_create_signal(u'project', ['BinaryPackage']) |
134 | + |
135 | + |
136 | + def backwards(self, orm): |
137 | + # Deleting model 'SourcePackage' |
138 | + db.delete_table('sourcepackage') |
139 | + |
140 | + # Deleting model 'BinaryPackage' |
141 | + db.delete_table('binarypackage') |
142 | + |
143 | + |
144 | + models = { |
145 | + u'project.binarypackage': { |
146 | + 'Meta': {'object_name': 'BinaryPackage', 'db_table': "'binarypackage'"}, |
147 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
148 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
149 | + 'seeded': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
150 | + 'sourcepackage': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['project.SourcePackage']"}) |
151 | + }, |
152 | + u'project.sourcepackage': { |
153 | + 'Meta': {'object_name': 'SourcePackage', 'db_table': "'sourcepackage'"}, |
154 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
155 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
156 | + } |
157 | + } |
158 | + |
159 | + complete_apps = ['project'] |
160 | \ No newline at end of file |
161 | |
162 | === added file 'ticket_system/project/migrations/__init__.py' |
163 | === added file 'ticket_system/project/models.py' |
164 | --- ticket_system/project/models.py 1970-01-01 00:00:00 +0000 |
165 | +++ ticket_system/project/models.py 2013-12-09 19:42:24 +0000 |
166 | @@ -0,0 +1,38 @@ |
167 | +# Ubuntu Continuous Integration Engine |
168 | +# Copyright 2013 Canonical Ltd. |
169 | + |
170 | +# This program is free software: you can redistribute it and/or modify it |
171 | +# under the terms of the GNU Affero General Public License version 3, as |
172 | +# published by the Free Software Foundation. |
173 | + |
174 | +# This program is distributed in the hope that it will be useful, but |
175 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
176 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
177 | +# PURPOSE. See the GNU Affero General Public License for more details. |
178 | + |
179 | +# You should have received a copy of the GNU Affero General Public License |
180 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
181 | + |
182 | +from django.db import models |
183 | + |
184 | + |
185 | +class SourcePackage(models.Model): |
186 | + class Meta: |
187 | + db_table = "sourcepackage" |
188 | + |
189 | + name = models.CharField(max_length=4096) |
190 | + |
191 | + def __unicode__(self): |
192 | + return self.name |
193 | + |
194 | + |
195 | +class BinaryPackage(models.Model): |
196 | + class Meta: |
197 | + db_table = "binarypackage" |
198 | + |
199 | + name = models.CharField(max_length=4096) |
200 | + sourcepackage = models.ForeignKey("SourcePackage") |
201 | + seeded = models.BooleanField(default=False) |
202 | + |
203 | + def __unicode__(self): |
204 | + return self.name |
205 | |
206 | === added file 'ticket_system/project/tests.py' |
207 | --- ticket_system/project/tests.py 1970-01-01 00:00:00 +0000 |
208 | +++ ticket_system/project/tests.py 2013-12-09 19:42:24 +0000 |
209 | @@ -0,0 +1,136 @@ |
210 | +# Ubuntu Continuous Integration Engine |
211 | +# Copyright 2013 Canonical Ltd. |
212 | + |
213 | +# This program is free software: you can redistribute it and/or modify it |
214 | +# under the terms of the GNU Affero General Public License version 3, as |
215 | +# published by the Free Software Foundation. |
216 | + |
217 | +# This program is distributed in the hope that it will be useful, but |
218 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
219 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
220 | +# PURPOSE. See the GNU Affero General Public License for more details. |
221 | + |
222 | +# You should have received a copy of the GNU Affero General Public License |
223 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
224 | + |
225 | +from django.test import TestCase |
226 | +from tastypie.test import ResourceTestCase |
227 | +from project.models import SourcePackage, BinaryPackage |
228 | + |
229 | + |
230 | +def create_sourcepackage(name="awesome-package"): |
231 | + package = SourcePackage() |
232 | + package.name = name |
233 | + package.save() |
234 | + return package |
235 | + |
236 | + |
237 | +def create_binarypackage(name="awesome-binary", sourcepackage=None, |
238 | + seeded=False): |
239 | + binary = BinaryPackage() |
240 | + binary.name = name |
241 | + binary.sourcepackage = sourcepackage |
242 | + binary.seeded = seeded |
243 | + binary.save() |
244 | + return binary |
245 | + |
246 | + |
247 | +class SourcePackageModelTest(TestCase): |
248 | + |
249 | + def test_creating_a_sourcepackage(self): |
250 | + package = create_sourcepackage() |
251 | + package_in_database = SourcePackage.objects.all() |
252 | + self.assertEquals(len(package_in_database), 1) |
253 | + only_package_in_database = package_in_database[0] |
254 | + self.assertEquals(only_package_in_database, package) |
255 | + |
256 | + self.assertEquals(only_package_in_database.name, "awesome-package") |
257 | + |
258 | + |
259 | +class BinaryPackageModelTest(TestCase): |
260 | + |
261 | + def setUp(self): |
262 | + self.sourcepackage = create_sourcepackage() |
263 | + self.binarypackage = create_binarypackage( |
264 | + sourcepackage=self.sourcepackage) |
265 | + |
266 | + def test_creating_a_binarypackage(self): |
267 | + binarypackage_in_database = BinaryPackage.objects.all() |
268 | + self.assertEquals(len(binarypackage_in_database), 1) |
269 | + only_binarypackage_in_database = binarypackage_in_database[0] |
270 | + self.assertEquals(only_binarypackage_in_database, self.binarypackage) |
271 | + |
272 | + self.assertEquals(only_binarypackage_in_database.name, |
273 | + "awesome-binary") |
274 | + |
275 | + |
276 | +class SourcePackageResourceTest(ResourceTestCase): |
277 | + |
278 | + def setUp(self): |
279 | + super(SourcePackageResourceTest, self).setUp() |
280 | + create_sourcepackage() |
281 | + self.sourcepackage_1 = SourcePackage.objects.get( |
282 | + name='awesome-package') |
283 | + self.detail_url = '/api/v1/sourcepackage/{0}/'.format( |
284 | + self.sourcepackage_1.pk) |
285 | + |
286 | + def test_get_sourcepackage_list_json(self): |
287 | + resp = self.api_client.get('/api/v1/sourcepackage/', format='json') |
288 | + self.assertValidJSONResponse(resp) |
289 | + self.assertEqual(len(self.deserialize(resp)['objects']), 1) |
290 | + self.assertEqual(self.deserialize(resp)['objects'][0], { |
291 | + u'id': self.sourcepackage_1.pk, |
292 | + u'name': u'awesome-package', |
293 | + u'resource_uri': u'/api/v1/sourcepackage/{0}/'.format( |
294 | + self.sourcepackage_1.pk) |
295 | + }) |
296 | + |
297 | + def test_get_sourcepackage_detail_json(self): |
298 | + resp = self.api_client.get(self.detail_url) |
299 | + self.assertValidJSONResponse(resp) |
300 | + |
301 | + # We use ``assertKeys`` here to just verify the keys, not all the data. |
302 | + self.assertKeys(self.deserialize(resp), |
303 | + ['id', 'name', 'resource_uri']) |
304 | + self.assertEqual(self.deserialize(resp)['name'], 'awesome-package') |
305 | + |
306 | + |
307 | +class BinaryPackageResourceTest(ResourceTestCase): |
308 | + |
309 | + def setUp(self): |
310 | + super(BinaryPackageResourceTest, self).setUp() |
311 | + create_sourcepackage() |
312 | + self.sourcepackage_1 = SourcePackage.objects.get( |
313 | + name='awesome-package') |
314 | + create_binarypackage(sourcepackage=self.sourcepackage_1) |
315 | + self.binarypackage_1 = BinaryPackage.objects.get( |
316 | + name='awesome-binary') |
317 | + self.detail_url = '/api/v1/binarypackage/{0}/'.format( |
318 | + self.binarypackage_1.pk) |
319 | + |
320 | + def test_get_binarypackage_list_json(self): |
321 | + resp = self.api_client.get('/api/v1/binarypackage/', format='json') |
322 | + self.assertValidJSONResponse(resp) |
323 | + self.assertEqual(len(self.deserialize(resp)['objects']), 1) |
324 | + self.assertEqual(self.deserialize(resp)['objects'][0], { |
325 | + u'id': self.binarypackage_1.pk, |
326 | + u'name': u'awesome-binary', |
327 | + u'seeded': False, |
328 | + u'sourcepackage': { |
329 | + u'id': self.sourcepackage_1.pk, |
330 | + u'name': u'awesome-package', |
331 | + u'resource_uri': u'/api/v1/sourcepackage/{0}/'.format( |
332 | + self.sourcepackage_1.pk)}, |
333 | + u'resource_uri': u'/api/v1/binarypackage/{0}/'.format( |
334 | + self.binarypackage_1.pk) |
335 | + }) |
336 | + |
337 | + def test_get_binarypackage_detail_json(self): |
338 | + resp = self.api_client.get(self.detail_url) |
339 | + self.assertValidJSONResponse(resp) |
340 | + |
341 | + # We use ``assertKeys`` here to just verify the keys, not all the data. |
342 | + self.assertKeys(self.deserialize(resp), |
343 | + ['id', 'name', 'resource_uri', 'seeded', |
344 | + 'sourcepackage']) |
345 | + self.assertEqual(self.deserialize(resp)['name'], 'awesome-binary') |
346 | |
347 | === modified file 'ticket_system/ticket_system/settings.py' |
348 | --- ticket_system/ticket_system/settings.py 2013-12-09 17:43:12 +0000 |
349 | +++ ticket_system/ticket_system/settings.py 2013-12-09 19:42:24 +0000 |
350 | @@ -140,6 +140,7 @@ |
351 | |
352 | LOCAL_APPS = ( |
353 | 'people', |
354 | + 'project', |
355 | ) |
356 | |
357 | INSTALLED_APPS = LOCAL_APPS + INSTALLED_APPS |
358 | |
359 | === modified file 'ticket_system/ticket_system/urls.py' |
360 | --- ticket_system/ticket_system/urls.py 2013-12-09 17:43:12 +0000 |
361 | +++ ticket_system/ticket_system/urls.py 2013-12-09 19:42:24 +0000 |
362 | @@ -17,10 +17,13 @@ |
363 | from django.contrib import admin |
364 | from tastypie.api import Api |
365 | from people.api import PersonResource |
366 | +from project.api import SourcePackageResource, BinaryPackageResource |
367 | |
368 | admin.autodiscover() |
369 | v1_api = Api(api_name='v1') |
370 | v1_api.register(PersonResource()) |
371 | +v1_api.register(SourcePackageResource()) |
372 | +v1_api.register(BinaryPackageResource()) |
373 | |
374 | urlpatterns = patterns( |
375 | '', |
stuff like:
287 + resp = self.api_ client. get('/api/ v1/sourcepackag e/', format='json') dJSONResponse( resp) l(len(self. deserialize( resp)[' objects' ]), 1)
288 + self.assertVali
289 + self.assertEqua
could probably get folded into:
http:// bazaar. launchpad. net/~canonical- ci-engineering/ ubuntu- ci-services- itself/ trunk/view/ head:/ci- utils/ci_ utils/tastypie/ test.py
In particular it could probably work with the getResource method.