Merge lp:~cprov/uci-engine/ts-reviews-ng into lp:uci-engine
- ts-reviews-ng
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Celso Providelo |
Approved revision: | 886 |
Merged at revision: | 885 |
Proposed branch: | lp:~cprov/uci-engine/ts-reviews-ng |
Merge into: | lp:uci-engine |
Diff against target: |
678 lines (+445/-24) 9 files modified
ci-utils/ci_utils/ticket_states.py (+11/-0) ticket_system/ticket/api.py (+18/-1) ticket_system/ticket/migrations/0019_auto__add_field_review_status__chg_field_review_review_type.py (+120/-0) ticket_system/ticket/migrations/0020_fill_review_status.py (+119/-0) ticket_system/ticket/migrations/0021_auto__del_field_review_completed.py (+113/-0) ticket_system/ticket/models.py (+27/-10) ticket_system/ticket/tests/test_models.py (+22/-1) ticket_system/ticket/tests/test_read_api.py (+4/-4) ticket_system/ticket/tests/test_write_api.py (+11/-8) |
To merge this branch: | bzr merge lp:~cprov/uci-engine/ts-reviews-ng |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Ursula Junque (community) | Approve | ||
Review via email: mp+240798@code.launchpad.net |
Commit message
Update TS model to support review 'status' instead of simple 'completed' flag.
Description of the change
Update TS model to support review 'status' instead of simple 'completed' flag.
Now review.status can hold PENDING (default), APPROVED and DISAPPROVED, similarly to LP MP votes.
The reviews in the webui will be broken for a short while, but a subsequent MP is adjusting it and adding tests.
PS Jenkins bot (ps-jenkins) wrote : | # |
Ursula Junque (ursinha) wrote : | # |
I have some comments below, regarding the use of the status you added:
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:885
http://
Executed test runs:
Click here to trigger a rebuild:
http://
Ursula Junque (ursinha) wrote : | # |
As we discussed via IRC, if you are able to leave the review status easily editable before the ticket step changes, then you could go with the NEEDS_* options. I like the idea of having status similar to the MPs, so I won't say no to that, I was just trying to avoid confusion for the user whenever reviewing to a "transitional" status.
Celso Providelo (cprov) wrote : | # |
We will be in a better position to decide if we are already in shape to add extra review status after working out the UI for them. No worries, let's go with it as it is and unblock the subsequent tasks.
Ursula Junque (ursinha) : | # |
Ubuntu CI Bot (uci-bot) wrote : | # |
The attempt to merge lp:~cprov/uci-engine/ts-reviews-ng into lp:uci-engine failed. Below is the output from the failed tests.
Running cm...
Updating source dependencies...
Updating source dependencies...
Updating source dependencies...
Updating source dependencies...
Updating source dependencies...
Updating source dependencies...
uploading webui-content.tgz to swift
Updating source dependencies...
2014-11-06 04:15:04 INFO juju.cmd supercommand.go:37 running jujud [1.20.11.
2014-11-06 04:15:04 DEBUG juju.agent agent.go:377 read agent config, format "1.18"
2014-11-06 04:15:04 INFO juju.jujud unit.go:78 unit agent unit-ci-
2014-11-06 04:15:04 INFO juju.worker runner.go:260 start "api"
2014-11-06 04:15:04 INFO juju.state.api apiclient.go:242 dialing "wss://
2014-11-06 04:15:04 INFO juju.state.api apiclient.go:176 connection established to "wss://
2014-11-06 04:15:05 INFO juju.state.api apiclient.go:242 dialing "wss://
2014-11-06 04:15:05 INFO juju.state.api apiclient.go:176 connection established to "wss://
2014-11-06 04:15:05 INFO juju.state.api apiclient.go:242 dialing "wss://
2014-11-06 04:15:05 INFO juju.state.api apiclient.go:176 connection established to "wss://
2014-11-06 04:15:05 INFO juju.worker runner.go:260 start "upgrader"
2014-11-06 04:15:05 INFO juju.worker runner.go:260 start "logger"
2014-11-06 04:15:05 DEBUG juju.worker.logger logger.go:35 initial log config: "<root>=DEBUG"
2014-11-06 04:15:05 INFO juju.worker runner.go:260 start "uniter"
2014-11-06 04:15:05 DEBUG juju.worker.logger logger.go:60 logger setup
2014-11-06 04:15:05 INFO juju.worker runner.go:260 start "apiaddressupdater"
2014-11-06 04:15:05 INFO juju.worker runner.go:260 start "rsyslog"
2014-11-06 04:15:05 DEBUG juju.worker.rsyslog worker.go:75 starting rsyslog worker mode 1 for "unit-ci-
2014-11-06 04:15:05 DEBUG juju.worker.logger logger.go:45 reconfiguring logging from "<root>=DEBUG" to "<root>
2014-11-06 04:15:10 INFO juju-log Installing python-jinja2 with options: ['--option=
2014-11-06 04:15:57 INFO install Reading package lists...
2014-11-06 04:15:58 INFO install Building dependency tree...
2014-11-06 04:15:58 INFO install Reading state information...
2014-11-06 04:15:59 INFO install The following extra packages will be installed:
2014-11-06 04:15:59 INFO install python-markupsafe
2014-11-06 04:15:59 INFO install Suggested packages:
2014-11-06 04:15:59 INFO install python-jinja2-doc
2014-11-06 04:15:59 INFO install The following NEW packages will be installed:
2014-11-06 04:15:59 INFO install python-jinja2 python-markupsafe
2014-11-06 04:15:59 INFO install 0 upgraded, 2 newly installed, 0 to remove and 3 not upgraded.
2014-11-06 04:15:59 INFO install Need to get 172 kB of archives.
2014-11-06 04:15:59 INFO install After this operation, 1124 kB of additional disk space will be used.
2014-11-06 04:15:59 INFO install Get:1 http://
- 886. By Celso Providelo
-
Fixing Review representation and add a test.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:886
http://
Executed test runs:
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'ci-utils/ci_utils/ticket_states.py' |
2 | --- ci-utils/ci_utils/ticket_states.py 2014-10-23 01:21:04 +0000 |
3 | +++ ci-utils/ci_utils/ticket_states.py 2014-11-06 04:57:04 +0000 |
4 | @@ -80,6 +80,17 @@ |
5 | def __str__(self): |
6 | return str(self.value) |
7 | |
8 | + |
9 | +class ReviewStatus(DBEnumeratedType): |
10 | + |
11 | + PENDING = Item(0, "Pending") |
12 | + APPROVED = Item(10, "Approved") |
13 | + DISAPPROVED = Item(100, "Disapproved") |
14 | + |
15 | + def __str__(self): |
16 | + return str(self.value) |
17 | + |
18 | + |
19 | # we have workflow steps known to the lander (lander_service_wrapper). We |
20 | # also have steps associated in the ticket-system. This provides a mapping |
21 | # to translate between them |
22 | |
23 | === modified file 'ticket_system/ticket/api.py' |
24 | --- ticket_system/ticket/api.py 2014-11-05 05:23:20 +0000 |
25 | +++ ticket_system/ticket/api.py 2014-11-06 04:57:04 +0000 |
26 | @@ -45,6 +45,7 @@ |
27 | get_enum_value, |
28 | MergeProposal, |
29 | Review, |
30 | + ReviewStatus, |
31 | SubTicket, |
32 | SourcePackageUpload, |
33 | SubTicketArtifact, |
34 | @@ -583,6 +584,7 @@ |
35 | |
36 | |
37 | class ReviewResource(ModelResource): |
38 | + |
39 | ticket = fields.ForeignKey(TicketResource, 'ticket') |
40 | |
41 | def dehydrate_workflow_step(self, bundle): |
42 | @@ -601,6 +603,21 @@ |
43 | bundle.data['workflow_step'] = value |
44 | return bundle |
45 | |
46 | + def dehydrate_status(self, bundle): |
47 | + return get_enum_title(bundle.data["status"], ReviewStatus) |
48 | + |
49 | + def hydrate_status(self, bundle): |
50 | + value = bundle.data.get('status') |
51 | + if not value: |
52 | + return bundle |
53 | + try: |
54 | + int(value) |
55 | + except ValueError: |
56 | + # user passed us "Approved" |
57 | + value = get_enum_value(value, ReviewStatus) |
58 | + bundle.data['status'] = value |
59 | + return bundle |
60 | + |
61 | class Meta: |
62 | queryset = Review.objects.all() |
63 | authorization = Authorization() |
64 | @@ -608,7 +625,7 @@ |
65 | filtering = { |
66 | 'ticket': ALL_WITH_RELATIONS, |
67 | 'review_type': ALL, |
68 | - 'completed': ALL, |
69 | + 'status': ALL, |
70 | } |
71 | |
72 | |
73 | |
74 | === added file 'ticket_system/ticket/migrations/0019_auto__add_field_review_status__chg_field_review_review_type.py' |
75 | --- ticket_system/ticket/migrations/0019_auto__add_field_review_status__chg_field_review_review_type.py 1970-01-01 00:00:00 +0000 |
76 | +++ ticket_system/ticket/migrations/0019_auto__add_field_review_status__chg_field_review_review_type.py 2014-11-06 04:57:04 +0000 |
77 | @@ -0,0 +1,120 @@ |
78 | +# -*- coding: utf-8 -*- |
79 | +import datetime |
80 | +from south.db import db |
81 | +from south.v2 import SchemaMigration |
82 | +from django.db import models |
83 | + |
84 | + |
85 | +class Migration(SchemaMigration): |
86 | + |
87 | + def forwards(self, orm): |
88 | + # Adding field 'Review.status' |
89 | + db.add_column(u'ticket_review', 'status', |
90 | + self.gf('django.db.models.fields.IntegerField')(default=0), |
91 | + keep_default=False) |
92 | + |
93 | + |
94 | + # Changing field 'Review.review_type' |
95 | + db.alter_column(u'ticket_review', 'review_type', self.gf('django.db.models.fields.CharField')(max_length=254)) |
96 | + |
97 | + def backwards(self, orm): |
98 | + # Deleting field 'Review.status' |
99 | + db.delete_column(u'ticket_review', 'status') |
100 | + |
101 | + |
102 | + # Changing field 'Review.review_type' |
103 | + db.alter_column(u'ticket_review', 'review_type', self.gf('django.db.models.fields.CharField')(max_length=4096)) |
104 | + |
105 | + models = { |
106 | + u'project.sourcepackage': { |
107 | + 'Meta': {'object_name': 'SourcePackage', 'db_table': "'sourcepackage'"}, |
108 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
109 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '4096'}) |
110 | + }, |
111 | + u'ticket.mergeproposal': { |
112 | + 'Meta': {'unique_together': "(('subticket', 'lp_url'),)", 'object_name': 'MergeProposal', 'db_table': "'mergeproposal'"}, |
113 | + 'approved_revno': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
114 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
115 | + 'lp_url': ('django.db.models.fields.CharField', [], {'max_length': '511'}), |
116 | + 'source_package_upload': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.SourcePackageUpload']", 'null': 'True', 'blank': 'True'}), |
117 | + 'subticket': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'merge_proposals'", 'to': u"orm['ticket.SubTicket']"}) |
118 | + }, |
119 | + u'ticket.review': { |
120 | + 'Meta': {'object_name': 'Review'}, |
121 | + 'completed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
122 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
123 | + 'review_type': ('django.db.models.fields.CharField', [], {'max_length': '254'}), |
124 | + 'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
125 | + 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']"}), |
126 | + 'workflow_step': ('django.db.models.fields.IntegerField', [], {}) |
127 | + }, |
128 | + u'ticket.sourcepackageupload': { |
129 | + 'Meta': {'unique_together': "(('subticket', 'version'),)", 'object_name': 'SourcePackageUpload', 'db_table': "'sourcepackageupload'"}, |
130 | + 'architecture': ('django.db.models.fields.CharField', [], {'max_length': '254'}), |
131 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
132 | + 'subticket': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'source_package_uploads'", 'to': u"orm['ticket.SubTicket']"}), |
133 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '254'}) |
134 | + }, |
135 | + u'ticket.subticket': { |
136 | + 'Meta': {'ordering': "['id']", 'unique_together': "(('ticket', 'sourcepackage'),)", 'object_name': 'SubTicket', 'db_table': "'subticket'"}, |
137 | + 'assignee': ('django.db.models.fields.EmailField', [], {'max_length': '254'}), |
138 | + 'current_workflow_step': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
139 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
140 | + 'sourcepackage': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['project.SourcePackage']"}), |
141 | + 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
142 | + 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']"}) |
143 | + }, |
144 | + u'ticket.subticketartifact': { |
145 | + 'Meta': {'object_name': 'SubTicketArtifact', 'db_table': "'subticket_artifact'"}, |
146 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
147 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
148 | + 'reference': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
149 | + 'subticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.SubTicket']"}), |
150 | + 'type': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
151 | + }, |
152 | + u'ticket.ticket': { |
153 | + 'Meta': {'ordering': "['id']", 'object_name': 'Ticket', 'db_table': "'ticket'"}, |
154 | + 'base_image': ('django.db.models.fields.CharField', [], {'default': "'http://cloud-images.ubuntu.com/utopic/current/utopic-server-cloudimg-amd64-disk1.img'", 'max_length': '4096'}), |
155 | + 'bug_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
156 | + 'build_ppa': ('django.db.models.fields.CharField', [], {'max_length': '4096', 'blank': 'True'}), |
157 | + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
158 | + 'creator': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'null': 'True', 'blank': 'True'}), |
159 | + 'current_workflow_step': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
160 | + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), |
161 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
162 | + 'lander_unit': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
163 | + 'master_ppa': ('django.db.models.fields.CharField', [], {'default': "'ppa:cprov/ci-master'", 'max_length': '4096'}), |
164 | + 'owner': ('django.db.models.fields.EmailField', [], {'max_length': '254'}), |
165 | + 'private': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
166 | + 'series': ('django.db.models.fields.CharField', [], {'default': "'utopic'", 'max_length': '4096'}), |
167 | + 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
168 | + 'title': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
169 | + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), |
170 | + 'uuid': ('django.db.models.fields.CharField', [], {'default': "'37ff8af0-6543-11e4-b341-001c4229f9ac'", 'unique': 'True', 'max_length': '36'}), |
171 | + 'workflow': ('django.db.models.fields.related.ForeignKey', [], {'default': "'default'", 'to': u"orm['ticket.Workflow']"}) |
172 | + }, |
173 | + u'ticket.ticketartifact': { |
174 | + 'Meta': {'object_name': 'TicketArtifact', 'db_table': "'ticket_artifact'"}, |
175 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
176 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
177 | + 'reference': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
178 | + 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']"}), |
179 | + 'type': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
180 | + }, |
181 | + u'ticket.ticketcitrainoverlay': { |
182 | + 'Meta': {'object_name': 'TicketCiTrainOverlay', 'db_table': "'ticketcitrainoverlay'"}, |
183 | + 'comments': ('django.db.models.fields.TextField', [], {}), |
184 | + 'job_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}), |
185 | + 'landers': ('django.db.models.fields.TextField', [], {}), |
186 | + 'sync_request': ('django.db.models.fields.CharField', [], {'max_length': '256'}), |
187 | + 'test_notes': ('django.db.models.fields.TextField', [], {}), |
188 | + 'ticket': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'citrain_overlay'", 'unique': 'True', 'primary_key': 'True', 'to': u"orm['ticket.Ticket']"}) |
189 | + }, |
190 | + u'ticket.workflow': { |
191 | + 'Meta': {'object_name': 'Workflow'}, |
192 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096', 'primary_key': 'True'}), |
193 | + 'steps': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
194 | + } |
195 | + } |
196 | + |
197 | + complete_apps = ['ticket'] |
198 | \ No newline at end of file |
199 | |
200 | === added file 'ticket_system/ticket/migrations/0020_fill_review_status.py' |
201 | --- ticket_system/ticket/migrations/0020_fill_review_status.py 1970-01-01 00:00:00 +0000 |
202 | +++ ticket_system/ticket/migrations/0020_fill_review_status.py 2014-11-06 04:57:04 +0000 |
203 | @@ -0,0 +1,119 @@ |
204 | +# -*- coding: utf-8 -*- |
205 | +import datetime |
206 | +from south.db import db |
207 | +from south.v2 import DataMigration |
208 | +from django.db import models |
209 | + |
210 | +from ci_utils.ticket_states import ReviewStatus |
211 | + |
212 | + |
213 | +class Migration(DataMigration): |
214 | + |
215 | + def forwards(self, orm): |
216 | + "Completed reviews become APPROVED." |
217 | + for r in orm['ticket.Review'].objects.all(): |
218 | + if r.completed: |
219 | + r.status = ReviewStatus.APPROVED.value |
220 | + r.save() |
221 | + |
222 | + def backwards(self, orm): |
223 | + "APPROVED reviews become 'completed'." |
224 | + for r in orm['ticket.Review'].objects.all(): |
225 | + if r.status == ReviewStatus.APPROVED.value: |
226 | + r.completed = True |
227 | + r.save() |
228 | + |
229 | + models = { |
230 | + u'project.sourcepackage': { |
231 | + 'Meta': {'object_name': 'SourcePackage', 'db_table': "'sourcepackage'"}, |
232 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
233 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '4096'}) |
234 | + }, |
235 | + u'ticket.mergeproposal': { |
236 | + 'Meta': {'unique_together': "(('subticket', 'lp_url'),)", 'object_name': 'MergeProposal', 'db_table': "'mergeproposal'"}, |
237 | + 'approved_revno': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
238 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
239 | + 'lp_url': ('django.db.models.fields.CharField', [], {'max_length': '511'}), |
240 | + 'source_package_upload': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.SourcePackageUpload']", 'null': 'True', 'blank': 'True'}), |
241 | + 'subticket': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'merge_proposals'", 'to': u"orm['ticket.SubTicket']"}) |
242 | + }, |
243 | + u'ticket.review': { |
244 | + 'Meta': {'object_name': 'Review'}, |
245 | + 'completed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
246 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
247 | + 'review_type': ('django.db.models.fields.CharField', [], {'max_length': '254'}), |
248 | + 'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
249 | + 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']"}), |
250 | + 'workflow_step': ('django.db.models.fields.IntegerField', [], {}) |
251 | + }, |
252 | + u'ticket.sourcepackageupload': { |
253 | + 'Meta': {'unique_together': "(('subticket', 'version'),)", 'object_name': 'SourcePackageUpload', 'db_table': "'sourcepackageupload'"}, |
254 | + 'architecture': ('django.db.models.fields.CharField', [], {'max_length': '254'}), |
255 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
256 | + 'subticket': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'source_package_uploads'", 'to': u"orm['ticket.SubTicket']"}), |
257 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '254'}) |
258 | + }, |
259 | + u'ticket.subticket': { |
260 | + 'Meta': {'ordering': "['id']", 'unique_together': "(('ticket', 'sourcepackage'),)", 'object_name': 'SubTicket', 'db_table': "'subticket'"}, |
261 | + 'assignee': ('django.db.models.fields.EmailField', [], {'max_length': '254'}), |
262 | + 'current_workflow_step': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
263 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
264 | + 'sourcepackage': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['project.SourcePackage']"}), |
265 | + 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
266 | + 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']"}) |
267 | + }, |
268 | + u'ticket.subticketartifact': { |
269 | + 'Meta': {'object_name': 'SubTicketArtifact', 'db_table': "'subticket_artifact'"}, |
270 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
271 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
272 | + 'reference': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
273 | + 'subticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.SubTicket']"}), |
274 | + 'type': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
275 | + }, |
276 | + u'ticket.ticket': { |
277 | + 'Meta': {'ordering': "['id']", 'object_name': 'Ticket', 'db_table': "'ticket'"}, |
278 | + 'base_image': ('django.db.models.fields.CharField', [], {'default': "'http://cloud-images.ubuntu.com/utopic/current/utopic-server-cloudimg-amd64-disk1.img'", 'max_length': '4096'}), |
279 | + 'bug_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
280 | + 'build_ppa': ('django.db.models.fields.CharField', [], {'max_length': '4096', 'blank': 'True'}), |
281 | + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
282 | + 'creator': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'null': 'True', 'blank': 'True'}), |
283 | + 'current_workflow_step': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
284 | + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), |
285 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
286 | + 'lander_unit': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
287 | + 'master_ppa': ('django.db.models.fields.CharField', [], {'default': "'ppa:cprov/ci-master'", 'max_length': '4096'}), |
288 | + 'owner': ('django.db.models.fields.EmailField', [], {'max_length': '254'}), |
289 | + 'private': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
290 | + 'series': ('django.db.models.fields.CharField', [], {'default': "'utopic'", 'max_length': '4096'}), |
291 | + 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
292 | + 'title': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
293 | + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), |
294 | + 'uuid': ('django.db.models.fields.CharField', [], {'default': "'904d7686-6543-11e4-86b0-001c4229f9ac'", 'unique': 'True', 'max_length': '36'}), |
295 | + 'workflow': ('django.db.models.fields.related.ForeignKey', [], {'default': "'default'", 'to': u"orm['ticket.Workflow']"}) |
296 | + }, |
297 | + u'ticket.ticketartifact': { |
298 | + 'Meta': {'object_name': 'TicketArtifact', 'db_table': "'ticket_artifact'"}, |
299 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
300 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
301 | + 'reference': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
302 | + 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']"}), |
303 | + 'type': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
304 | + }, |
305 | + u'ticket.ticketcitrainoverlay': { |
306 | + 'Meta': {'object_name': 'TicketCiTrainOverlay', 'db_table': "'ticketcitrainoverlay'"}, |
307 | + 'comments': ('django.db.models.fields.TextField', [], {}), |
308 | + 'job_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}), |
309 | + 'landers': ('django.db.models.fields.TextField', [], {}), |
310 | + 'sync_request': ('django.db.models.fields.CharField', [], {'max_length': '256'}), |
311 | + 'test_notes': ('django.db.models.fields.TextField', [], {}), |
312 | + 'ticket': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'citrain_overlay'", 'unique': 'True', 'primary_key': 'True', 'to': u"orm['ticket.Ticket']"}) |
313 | + }, |
314 | + u'ticket.workflow': { |
315 | + 'Meta': {'object_name': 'Workflow'}, |
316 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096', 'primary_key': 'True'}), |
317 | + 'steps': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
318 | + } |
319 | + } |
320 | + |
321 | + complete_apps = ['ticket'] |
322 | + symmetrical = True |
323 | |
324 | === added file 'ticket_system/ticket/migrations/0021_auto__del_field_review_completed.py' |
325 | --- ticket_system/ticket/migrations/0021_auto__del_field_review_completed.py 1970-01-01 00:00:00 +0000 |
326 | +++ ticket_system/ticket/migrations/0021_auto__del_field_review_completed.py 2014-11-06 04:57:04 +0000 |
327 | @@ -0,0 +1,113 @@ |
328 | +# -*- coding: utf-8 -*- |
329 | +import datetime |
330 | +from south.db import db |
331 | +from south.v2 import SchemaMigration |
332 | +from django.db import models |
333 | + |
334 | + |
335 | +class Migration(SchemaMigration): |
336 | + |
337 | + def forwards(self, orm): |
338 | + # Deleting field 'Review.completed' |
339 | + db.delete_column(u'ticket_review', 'completed') |
340 | + |
341 | + |
342 | + def backwards(self, orm): |
343 | + # Adding field 'Review.completed' |
344 | + db.add_column(u'ticket_review', 'completed', |
345 | + self.gf('django.db.models.fields.BooleanField')(default=False), |
346 | + keep_default=False) |
347 | + |
348 | + |
349 | + models = { |
350 | + u'project.sourcepackage': { |
351 | + 'Meta': {'object_name': 'SourcePackage', 'db_table': "'sourcepackage'"}, |
352 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
353 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '4096'}) |
354 | + }, |
355 | + u'ticket.mergeproposal': { |
356 | + 'Meta': {'unique_together': "(('subticket', 'lp_url'),)", 'object_name': 'MergeProposal', 'db_table': "'mergeproposal'"}, |
357 | + 'approved_revno': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
358 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
359 | + 'lp_url': ('django.db.models.fields.CharField', [], {'max_length': '511'}), |
360 | + 'source_package_upload': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.SourcePackageUpload']", 'null': 'True', 'blank': 'True'}), |
361 | + 'subticket': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'merge_proposals'", 'to': u"orm['ticket.SubTicket']"}) |
362 | + }, |
363 | + u'ticket.review': { |
364 | + 'Meta': {'object_name': 'Review'}, |
365 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
366 | + 'review_type': ('django.db.models.fields.CharField', [], {'max_length': '254'}), |
367 | + 'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
368 | + 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']"}), |
369 | + 'workflow_step': ('django.db.models.fields.IntegerField', [], {}) |
370 | + }, |
371 | + u'ticket.sourcepackageupload': { |
372 | + 'Meta': {'unique_together': "(('subticket', 'version'),)", 'object_name': 'SourcePackageUpload', 'db_table': "'sourcepackageupload'"}, |
373 | + 'architecture': ('django.db.models.fields.CharField', [], {'max_length': '254'}), |
374 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
375 | + 'subticket': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'source_package_uploads'", 'to': u"orm['ticket.SubTicket']"}), |
376 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '254'}) |
377 | + }, |
378 | + u'ticket.subticket': { |
379 | + 'Meta': {'ordering': "['id']", 'unique_together': "(('ticket', 'sourcepackage'),)", 'object_name': 'SubTicket', 'db_table': "'subticket'"}, |
380 | + 'assignee': ('django.db.models.fields.EmailField', [], {'max_length': '254'}), |
381 | + 'current_workflow_step': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
382 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
383 | + 'sourcepackage': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['project.SourcePackage']"}), |
384 | + 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
385 | + 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']"}) |
386 | + }, |
387 | + u'ticket.subticketartifact': { |
388 | + 'Meta': {'object_name': 'SubTicketArtifact', 'db_table': "'subticket_artifact'"}, |
389 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
390 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
391 | + 'reference': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
392 | + 'subticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.SubTicket']"}), |
393 | + 'type': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
394 | + }, |
395 | + u'ticket.ticket': { |
396 | + 'Meta': {'ordering': "['id']", 'object_name': 'Ticket', 'db_table': "'ticket'"}, |
397 | + 'base_image': ('django.db.models.fields.CharField', [], {'default': "'http://cloud-images.ubuntu.com/utopic/current/utopic-server-cloudimg-amd64-disk1.img'", 'max_length': '4096'}), |
398 | + 'bug_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
399 | + 'build_ppa': ('django.db.models.fields.CharField', [], {'max_length': '4096', 'blank': 'True'}), |
400 | + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
401 | + 'creator': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'null': 'True', 'blank': 'True'}), |
402 | + 'current_workflow_step': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
403 | + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), |
404 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
405 | + 'lander_unit': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
406 | + 'master_ppa': ('django.db.models.fields.CharField', [], {'default': "'ppa:cprov/ci-master'", 'max_length': '4096'}), |
407 | + 'owner': ('django.db.models.fields.EmailField', [], {'max_length': '254'}), |
408 | + 'private': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
409 | + 'series': ('django.db.models.fields.CharField', [], {'default': "'utopic'", 'max_length': '4096'}), |
410 | + 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
411 | + 'title': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
412 | + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), |
413 | + 'uuid': ('django.db.models.fields.CharField', [], {'default': "'c434306e-6545-11e4-be5c-001c4229f9ac'", 'unique': 'True', 'max_length': '36'}), |
414 | + 'workflow': ('django.db.models.fields.related.ForeignKey', [], {'default': "'default'", 'to': u"orm['ticket.Workflow']"}) |
415 | + }, |
416 | + u'ticket.ticketartifact': { |
417 | + 'Meta': {'object_name': 'TicketArtifact', 'db_table': "'ticket_artifact'"}, |
418 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
419 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
420 | + 'reference': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
421 | + 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']"}), |
422 | + 'type': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
423 | + }, |
424 | + u'ticket.ticketcitrainoverlay': { |
425 | + 'Meta': {'object_name': 'TicketCiTrainOverlay', 'db_table': "'ticketcitrainoverlay'"}, |
426 | + 'comments': ('django.db.models.fields.TextField', [], {}), |
427 | + 'job_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}), |
428 | + 'landers': ('django.db.models.fields.TextField', [], {}), |
429 | + 'sync_request': ('django.db.models.fields.CharField', [], {'max_length': '256'}), |
430 | + 'test_notes': ('django.db.models.fields.TextField', [], {}), |
431 | + 'ticket': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'citrain_overlay'", 'unique': 'True', 'primary_key': 'True', 'to': u"orm['ticket.Ticket']"}) |
432 | + }, |
433 | + u'ticket.workflow': { |
434 | + 'Meta': {'object_name': 'Workflow'}, |
435 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096', 'primary_key': 'True'}), |
436 | + 'steps': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
437 | + } |
438 | + } |
439 | + |
440 | + complete_apps = ['ticket'] |
441 | \ No newline at end of file |
442 | |
443 | === modified file 'ticket_system/ticket/models.py' |
444 | --- ticket_system/ticket/models.py 2014-11-05 05:23:20 +0000 |
445 | +++ ticket_system/ticket/models.py 2014-11-06 04:57:04 +0000 |
446 | @@ -29,6 +29,7 @@ |
447 | from ci_utils import unit_config |
448 | |
449 | from ci_utils.ticket_states import ( |
450 | + ReviewStatus, |
451 | STEP_TO_WORKFLOW_MAPPING, |
452 | SubTicketWorkflowStep, |
453 | SubTicketWorkflowStepStatus, |
454 | @@ -202,7 +203,8 @@ |
455 | def _get_workflow_steps(self): |
456 | '''build workflow steps injecting pauses where reviews are needed''' |
457 | steps = json.loads(self.workflow.steps) |
458 | - reviews = self.review_set.filter(completed=False) |
459 | + reviews = self.review_set.exclude( |
460 | + status=ReviewStatus.APPROVED.value) |
461 | pauses = [x.workflow_step for x in reviews] |
462 | for step in steps: |
463 | step_val = STEP_TO_WORKFLOW_MAPPING.get(step['name'], -1) |
464 | @@ -390,20 +392,35 @@ |
465 | |
466 | |
467 | class Review(models.Model): |
468 | - ticket = models.ForeignKey(Ticket) |
469 | - workflow_step = models.IntegerField(choices=_choices(TicketWorkflowStep)) |
470 | - review_type = models.CharField(max_length=4096) |
471 | - completed = models.BooleanField(default=False) |
472 | + |
473 | + ticket = models.ForeignKey( |
474 | + Ticket, |
475 | + help_text='Context ticket of this review.') |
476 | + |
477 | + workflow_step = models.IntegerField( |
478 | + choices=_choices(TicketWorkflowStep), |
479 | + help_text='Workflow step where the review is required.') |
480 | + |
481 | + review_type = models.CharField( |
482 | + max_length=254, null=False, blank=False, |
483 | + help_text='What type of review is needed.') |
484 | + |
485 | + status = models.IntegerField( |
486 | + choices=_choices(ReviewStatus), |
487 | + default=ReviewStatus.PENDING.value, |
488 | + help_text='Current review status.') |
489 | |
490 | def save(self, *args, **kwargs): |
491 | + """If all reviews are approved, resume the ticket processing.""" |
492 | super(Review, self).save(*args, **kwargs) |
493 | - if self.ticket.review_set.filter(completed=False).count() == 0: |
494 | - # all reviews are complete, if ticket is paused we should |
495 | - # mark it "continue" |
496 | + all_approved = not self.ticket.review_set.exclude( |
497 | + status=ReviewStatus.APPROVED.value).exists() |
498 | + if all_approved: |
499 | if int(self.ticket.status) == int(TicketWorkflowStepStatus.PAUSED): |
500 | self.ticket.status = TicketWorkflowStepStatus.CONTINUE |
501 | self.ticket.save() |
502 | |
503 | def __unicode__(self): |
504 | - return 'ticket-{} - {}: completed({})'.format( |
505 | - self.ticket.uuid, self.review_type, self.completed) |
506 | + return '{} - {}: {}'.format( |
507 | + self.ticket.uuid, self.review_type, |
508 | + get_enum_title(self.status, ReviewStatus)) |
509 | |
510 | === modified file 'ticket_system/ticket/tests/test_models.py' |
511 | --- ticket_system/ticket/tests/test_models.py 2014-10-14 18:58:42 +0000 |
512 | +++ ticket_system/ticket/tests/test_models.py 2014-11-06 04:57:04 +0000 |
513 | @@ -24,6 +24,7 @@ |
514 | from ticket.models import ( |
515 | MergeProposal, |
516 | Review, |
517 | + ReviewStatus, |
518 | SourcePackageUpload, |
519 | SubTicket, |
520 | SubTicketArtifact, |
521 | @@ -298,13 +299,33 @@ |
522 | self.assertEqual(0, send.call_count) |
523 | |
524 | # This will trigger the ticket object to be moved to CONTINUE |
525 | - r.completed = True |
526 | + r.status = ReviewStatus.APPROVED.value |
527 | r.save() |
528 | status = Ticket.objects.get(pk=self.ticket.id).status |
529 | self.assertEqual(TicketWorkflowStepStatus.CONTINUE.value, status) |
530 | self.assertEqual(1, send.call_count) |
531 | |
532 | |
533 | +class TestReview(TestCase): |
534 | + |
535 | + def setUp(self): |
536 | + _m = mock.patch('ticket.models.Ticket.create_container') |
537 | + self.create_container = _m.start() |
538 | + self.addCleanup(_m.stop) |
539 | + self.ticket = create_ticket(owner='test@example.com') |
540 | + |
541 | + def test_title(self): |
542 | + # Ensure review title include the ticket UUID, review type and |
543 | + # its status. |
544 | + review = Review.objects.create( |
545 | + ticket=self.ticket, review_type='packaging', |
546 | + workflow_step=TicketWorkflowStep.PKG_PUBLISHING) |
547 | + |
548 | + self.assertEqual( |
549 | + '{} - packaging: Pending'.format(self.ticket.uuid), |
550 | + unicode(review)) |
551 | + |
552 | + |
553 | class WorkflowTestCase(TestCase): |
554 | def test_unique_name(self): |
555 | '''make sure the workflow name is unique''' |
556 | |
557 | === modified file 'ticket_system/ticket/tests/test_read_api.py' |
558 | --- ticket_system/ticket/tests/test_read_api.py 2014-11-04 09:05:06 +0000 |
559 | +++ ticket_system/ticket/tests/test_read_api.py 2014-11-06 04:57:04 +0000 |
560 | @@ -161,11 +161,11 @@ |
561 | '/api/v1/subticket/{}/'.format(s.pk) |
562 | for s in self.ticket.subticket_set.all()], |
563 | u'reviews': [{ |
564 | - u'completed': False, |
565 | u'id': self.review_1.pk, |
566 | u'resource_uri': unicode( |
567 | '/api/v1/review/{0}/'.format(self.review_1.pk)), |
568 | u'review_type': u'QA', |
569 | + u'status': u'Pending', |
570 | u'ticket': unicode( |
571 | '/api/v1/ticket/{}/'.format(self.ticket.uuid)), |
572 | u'workflow_step': u'Image testing'}], |
573 | @@ -235,11 +235,11 @@ |
574 | '/api/v1/subticket/{}/'.format(s.pk) |
575 | for s in self.ticket.subticket_set.all()], |
576 | u'reviews': [{ |
577 | - u'completed': False, |
578 | u'id': self.review_1.pk, |
579 | u'resource_uri': unicode( |
580 | '/api/v1/review/{0}/'.format(self.review_1.pk)), |
581 | u'review_type': u'QA', |
582 | + u'status': u'Pending', |
583 | u'ticket': unicode( |
584 | '/api/v1/ticket/{}/'.format(self.ticket.uuid)), |
585 | u'workflow_step': u'Image testing'}], |
586 | @@ -314,11 +314,11 @@ |
587 | '/api/v1/subticket/{}/'.format(s.pk) |
588 | for s in self.ticket.subticket_set.all()], |
589 | u'reviews': [{ |
590 | - u'completed': False, |
591 | u'id': self.review_1.pk, |
592 | u'resource_uri': unicode( |
593 | '/api/v1/review/{0}/'.format(self.review_1.pk)), |
594 | u'review_type': u'QA', |
595 | + u'status': u'Pending', |
596 | u'ticket': unicode( |
597 | '/api/v1/ticket/{}/'.format(self.ticket.uuid)), |
598 | u'workflow_step': u'Image testing'}], |
599 | @@ -439,11 +439,11 @@ |
600 | u'/api/v1/subticket/{}/'.format(s.pk) |
601 | for s in self.ticket.subticket_set.all()], |
602 | u'reviews': [{ |
603 | - u'completed': False, |
604 | u'id': self.review_1.pk, |
605 | u'resource_uri': unicode( |
606 | '/api/v1/review/{0}/'.format(self.review_1.pk)), |
607 | u'review_type': u'QA', |
608 | + u'status': u'Pending', |
609 | u'ticket': unicode( |
610 | '/api/v1/ticket/{0}/'.format(self.ticket.uuid)), |
611 | u'workflow_step': u'Image testing'}], |
612 | |
613 | === modified file 'ticket_system/ticket/tests/test_write_api.py' |
614 | --- ticket_system/ticket/tests/test_write_api.py 2014-11-05 05:23:20 +0000 |
615 | +++ ticket_system/ticket/tests/test_write_api.py 2014-11-06 04:57:04 +0000 |
616 | @@ -30,6 +30,7 @@ |
617 | m.start() |
618 | from ticket.models import ( |
619 | Review, |
620 | + ReviewStatus, |
621 | SourcePackageUpload, |
622 | SubTicket, |
623 | SubTicketWorkflowStep, |
624 | @@ -168,11 +169,11 @@ |
625 | self.assertEqual('QA', review_pkg.review_type) |
626 | self.assertEqual( |
627 | TicketWorkflowStep.PKG_VALIDATION.value, review_pkg.workflow_step) |
628 | - self.assertFalse(review_pkg.completed) |
629 | + self.assertEqual(ReviewStatus.PENDING.value, review_pkg.status) |
630 | self.assertEqual('QA', review_img.review_type) |
631 | self.assertEqual( |
632 | TicketWorkflowStep.IMAGE_BUILDING.value, review_img.workflow_step) |
633 | - self.assertFalse(review_img.completed) |
634 | + self.assertFalse(ReviewStatus.PENDING.value, review_img.status) |
635 | |
636 | # Note that the reviews created via POST are new, they are not |
637 | # mysteriously reused/updated by tastypie. |
638 | @@ -189,7 +190,7 @@ |
639 | 'title': 'Atomic Patched Ticket', |
640 | 'reviews': [{ |
641 | 'id': review.id, |
642 | - 'completed': True, |
643 | + 'status': 'Approved', |
644 | 'workflow_step': 'Image building', |
645 | }], |
646 | }) |
647 | @@ -200,7 +201,7 @@ |
648 | self.assertEqual('Atomic Patched Ticket', unicode(ticket)) |
649 | [new_review] = list(ticket.review_set.all()) |
650 | self.assertEqual(review.id, new_review.id) |
651 | - self.assertTrue(new_review.completed) |
652 | + self.assertEqual(ReviewStatus.APPROVED.value, new_review.status) |
653 | |
654 | def test_post_ticket_atomically_reuses_workflows(self): |
655 | # `Ticket` atomic creation re-uses existing `Workflows`s. |
656 | @@ -721,10 +722,12 @@ |
657 | workflow_step=0) |
658 | uri = 'review/' + str(t.pk) + '/' |
659 | params = self.get(uri) |
660 | - self.assertFalse(params['completed']) |
661 | - params['completed'] = True |
662 | + self.assertEqual(ReviewStatus.PENDING.title, params['status']) |
663 | + params['status'] = 'Approved' |
664 | self.patch(uri, params) |
665 | - self.assertTrue(Review.objects.get(pk=t.id).completed) |
666 | + self.assertEqual( |
667 | + ReviewStatus.APPROVED.value, |
668 | + Review.objects.get(pk=t.id).status) |
669 | |
670 | def test_delete(self): |
671 | t = Review.objects.create(ticket=self.ticket, review_type='a', |
672 | @@ -739,5 +742,5 @@ |
673 | resp = self.get('review/', {'ticket': self.ticket.pk}) |
674 | self.assertEqual(1, resp['meta']['total_count']) |
675 | |
676 | - resp = self.get('review/', {'completed': True}) |
677 | + resp = self.get('review/', {'status': '10'}) |
678 | self.assertEqual(0, resp['meta']['total_count']) |
PASSED: Continuous integration, rev:884 s-jenkins. ubuntu- ci:8080/ job/uci- engine- ci/1676/
http://
Executed test runs:
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/uci- engine- ci/1676/ rebuild
http://