Merge lp:~cprov/uci-engine/ticket-conflicts into lp:uci-engine
- ticket-conflicts
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Celso Providelo |
Approved revision: | 799 |
Merged at revision: | 799 |
Proposed branch: | lp:~cprov/uci-engine/ticket-conflicts |
Merge into: | lp:uci-engine |
Diff against target: |
373 lines (+206/-30) 6 files modified
ticket_system/ticket/api.py (+32/-27) ticket_system/ticket/models.py (+29/-0) ticket_system/ticket/tests/test_full_read_api.py (+2/-0) ticket_system/ticket/tests/test_models.py (+107/-2) ticket_system/ticket/tests/test_read_api.py (+28/-0) webui/tickets/static/tickets/webui.js (+8/-1) |
To merge this branch: | bzr merge lp:~cprov/uci-engine/ticket-conflicts |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Francis Ginther | Approve | ||
Review via email: mp+235301@code.launchpad.net |
Commit message
Implement and expose Subticket.
Description of the change
Implement and expose Subticket.
Each subticket may point to currently active tickets including SPUs/MPs for the same source package.
The conflicting tickets are referred by subtickets in order to give the user a better understanding of which *part* (subticket) of his task (ticket) is likely to result in conflicts when landing.
Full conflicting context will be provided during the landing (publishing) step.
PS Jenkins bot (ps-jenkins) wrote : | # |
Francis Ginther (fginther) wrote : | # |
Just one question on excluding NEW tickets. Otherwise this looks good and tests look reasonable.
Celso Providelo (cprov) wrote : | # |
On Fri, Sep 19, 2014 at 5:49 PM, Francis Ginther
<email address hidden> wrote:
> Review: Needs Information
>
> Just one question on excluding NEW tickets. Otherwise this looks good and tests look reasonable.
Thank you.
> What's the reason for not considering 'NEW' tickets as conflicts? Not saying it's wrong, I'm just not seeing the scenario around this.
NEW tickets are not considered by the Lander and I believe it was
implemented this way to cope with the multi-step ticket creation
process we currently have. Recently I've also extended the CLI to
optionally not queue the ticket after creation (create_ticket ... -w).
The intended scenario here is to allow users to register WIP tickets
in a same way we register WIP MPs (to inform/share in-progress tasks).
In the conflicting scenario, NEW (WIP) tickets will list existing
conflict but won't be considered a conflict for other active tickets.
The same behaviour might apply to other static relation/analysis we
can perform on the TS environment.
Does it make more sense ?
--
Celso Providelo
<email address hidden>
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:795
http://
Executed test runs:
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:796
http://
Executed test runs:
Click here to trigger a rebuild:
http://
Francis Ginther (fginther) wrote : | # |
> On Fri, Sep 19, 2014 at 5:49 PM, Francis Ginther
> <email address hidden> wrote:
> > Review: Needs Information
> >
> > Just one question on excluding NEW tickets. Otherwise this looks good and
> tests look reasonable.
>
> Thank you.
>
> > What's the reason for not considering 'NEW' tickets as conflicts? Not saying
> it's wrong, I'm just not seeing the scenario around this.
>
> NEW tickets are not considered by the Lander and I believe it was
> implemented this way to cope with the multi-step ticket creation
> process we currently have. Recently I've also extended the CLI to
> optionally not queue the ticket after creation (create_ticket ... -w).
> The intended scenario here is to allow users to register WIP tickets
> in a same way we register WIP MPs (to inform/share in-progress tasks).
>
> In the conflicting scenario, NEW (WIP) tickets will list existing
> conflict but won't be considered a conflict for other active tickets.
> The same behaviour might apply to other static relation/analysis we
> can perform on the TS environment.
>
> Does it make more sense ?
Yes, this approach makes sense.
Ubuntu CI Bot (uci-bot) wrote : | # |
The attempt to merge lp:~cprov/uci-engine/ticket-conflicts 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...
uploading webui-content.tgz to swift
Updating source dependencies...
Updating source dependencies...
Updating source dependencies...
Checking juju status
Private PPAs: disabled
Preparing local branch upload...
Uploading local branch, fingerprint b2ef646eb9e6fe5
Building charm: lander
Building charm: wsgi-app
Building charm: rabbitmq-worker
Building charm: webui
Building charm: key-secret-
Building charm: system-image-server
Building charm: chroot-builder
Installing keys from bzr+ssh:
Running juju-deployer -v -c /tmp/tmpAqmn35/
Tests running...
ci-utils.
ci-utils.
ci-utils.
ci-utils.
ci-utils.
ci-utils.
ci-utils.
ci-utils.
ci-utils.
ci-utils.
ci-utils.
ci-utils.
ci-utils.
ci-utils.
ci-utils.
ci-utils.
ci-utils.
ci-utils.
ci-utils.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:798
http://
Executed test runs:
Click here to trigger a rebuild:
http://
Ubuntu CI Bot (uci-bot) wrote : | # |
The attempt to merge lp:~cprov/uci-engine/ticket-conflicts 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...
uploading webui-content.tgz to swift
Updating source dependencies...
Updating source dependencies...
Updating source dependencies...
2014-09-24 13:11:07 INFO juju.cmd supercommand.go:37 running jujud [1.20.7.
2014-09-24 13:11:07 DEBUG juju.agent agent.go:377 read agent config, format "1.18"
2014-09-24 13:11:07 INFO juju.jujud unit.go:78 unit agent unit-ci-
2014-09-24 13:11:07 INFO juju.worker runner.go:260 start "api"
2014-09-24 13:11:07 INFO juju.state.api apiclient.go:242 dialing "wss://
2014-09-24 13:11:07 INFO juju.state.api apiclient.go:176 connection established to "wss://
2014-09-24 13:11:07 INFO juju.state.api apiclient.go:242 dialing "wss://
2014-09-24 13:11:07 INFO juju.state.api apiclient.go:176 connection established to "wss://
2014-09-24 13:11:16 INFO juju.state.api apiclient.go:242 dialing "wss://
2014-09-24 13:11:16 INFO juju.state.api apiclient.go:176 connection established to "wss://
2014-09-24 13:11:16 INFO juju.worker runner.go:260 start "upgrader"
2014-09-24 13:11:16 INFO juju.worker runner.go:260 start "logger"
2014-09-24 13:11:16 DEBUG juju.worker.logger logger.go:35 initial log config: "<root>=DEBUG"
2014-09-24 13:11:16 INFO juju.worker runner.go:260 start "uniter"
2014-09-24 13:11:16 DEBUG juju.worker.logger logger.go:60 logger setup
2014-09-24 13:11:16 INFO juju.worker runner.go:260 start "apiaddressupdater"
2014-09-24 13:11:16 INFO juju.worker runner.go:260 start "rsyslog"
2014-09-24 13:11:16 DEBUG juju.worker.rsyslog worker.go:75 starting rsyslog worker mode 1 for "unit-ci-
2014-09-24 13:11:16 DEBUG juju.worker.logger logger.go:45 reconfiguring logging from "<root>=DEBUG" to "<root>
2014-09-24 13:11:34 INFO juju-log Making dir /srv/ci-
2014-09-24 13:11:34 INFO juju-log installing apt packages...
2014-09-24 13:11:38 INFO install gpg: keyring `/tmp/tmpycVR_
2014-09-24 13:11:38 INFO install gpg: keyring `/tmp/tmpycVR_
2014-09-24 13:11:38 INFO install gpg: requesting key 6A8DFC40 from hkp server keyserver.
2014-09-24 13:11:38 INFO install gpg: /tmp/tmpycVR_
2014-09-24 13:11:38 INFO install gpg: key 6A8DFC40: public key "Launchpad PPA for Canonical CI Engineering" imported
2014-09-24 13:11:38 INFO install gpg: Total number processed: 1
2014-09-24 13:11:38 INFO install gpg: imported: 1 (RSA: 1)
2014-09-24 13:11:39 INFO install OK
2014-09-24 13:11:42 INFO install Get:1 http://
2014-09-24 13:11:42 INFO install Hit http://
2014-09-24 13:11:42 INFO...
Ubuntu CI Bot (uci-bot) wrote : | # |
The attempt to merge lp:~cprov/uci-engine/ticket-conflicts 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...
uploading webui-content.tgz to swift
Updating source dependencies...
Updating source dependencies...
Updating source dependencies...
2014-09-24 13:40:53 INFO juju.cmd supercommand.go:37 running jujud [1.20.7.
2014-09-24 13:40:53 DEBUG juju.agent agent.go:377 read agent config, format "1.18"
2014-09-24 13:40:53 INFO juju.jujud unit.go:78 unit agent unit-ci-
2014-09-24 13:40:53 INFO juju.worker runner.go:260 start "api"
2014-09-24 13:40:53 INFO juju.state.api apiclient.go:242 dialing "wss://
2014-09-24 13:40:53 INFO juju.state.api apiclient.go:176 connection established to "wss://
2014-09-24 13:40:53 INFO juju.state.api apiclient.go:242 dialing "wss://
2014-09-24 13:40:53 INFO juju.state.api apiclient.go:176 connection established to "wss://
2014-09-24 13:40:54 INFO juju.state.api apiclient.go:242 dialing "wss://
2014-09-24 13:40:54 INFO juju.state.api apiclient.go:176 connection established to "wss://
2014-09-24 13:40:54 INFO juju.worker runner.go:260 start "upgrader"
2014-09-24 13:40:54 INFO juju.worker runner.go:260 start "logger"
2014-09-24 13:40:54 DEBUG juju.worker.logger logger.go:35 initial log config: "<root>=DEBUG"
2014-09-24 13:40:54 INFO juju.worker runner.go:260 start "uniter"
2014-09-24 13:40:54 DEBUG juju.worker.logger logger.go:60 logger setup
2014-09-24 13:40:54 INFO juju.worker runner.go:260 start "apiaddressupdater"
2014-09-24 13:40:54 INFO juju.worker runner.go:260 start "rsyslog"
2014-09-24 13:40:54 DEBUG juju.worker.rsyslog worker.go:75 starting rsyslog worker mode 1 for "unit-ci-
2014-09-24 13:40:54 DEBUG juju.worker.logger logger.go:45 reconfiguring logging from "<root>=DEBUG" to "<root>
2014-09-24 13:41:03 INFO juju-log Making dir /srv/ci-
2014-09-24 13:41:03 INFO juju-log installing apt packages...
2014-09-24 13:41:08 INFO install gpg: keyring `/tmp/tmpfS7NKC
2014-09-24 13:41:08 INFO install gpg: keyring `/tmp/tmpfS7NKC
2014-09-24 13:41:08 INFO install gpg: requesting key 6A8DFC40 from hkp server keyserver.
2014-09-24 13:41:08 INFO install gpg: /tmp/tmpfS7NKC/
2014-09-24 13:41:08 INFO install gpg: key 6A8DFC40: public key "Launchpad PPA for Canonical CI Engineering" imported
2014-09-24 13:41:08 INFO install gpg: Total number processed: 1
2014-09-24 13:41:08 INFO install gpg: imported: 1 (RSA: 1)
2014-09-24 13:41:08 INFO install OK
2014-09-24 13:41:09 INFO install Hit http://
2014-09-24 13:41:09 INFO install Get:1 http://
2014-09-24 13:41:09 INFO install Get:2 http://
- 799. By Celso Providelo
-
merge trunk
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:799
http://
Executed test runs:
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'ticket_system/ticket/api.py' |
2 | --- ticket_system/ticket/api.py 2014-08-29 18:28:56 +0000 |
3 | +++ ticket_system/ticket/api.py 2014-09-24 17:47:41 +0000 |
4 | @@ -154,22 +154,23 @@ |
5 | return '' |
6 | |
7 | |
8 | -class SubTicketTranslatedResource(ModelResource): |
9 | - |
10 | - def dehydrate_current_workflow_step(self, bundle): |
11 | - return get_enum_title(bundle.data["current_workflow_step"], |
12 | - SubTicketWorkflowStep) |
13 | - |
14 | - def dehydrate_status(self, bundle): |
15 | - return get_enum_title(bundle.data["status"], |
16 | - SubTicketWorkflowStepStatus) |
17 | +class SourcePackageUploadResource(ModelResource): |
18 | + |
19 | + sourcepackage = fields.ToOneField( |
20 | + SourcePackageResource, 'sourcepackage', full=True) |
21 | + |
22 | + class Meta: |
23 | + queryset = SourcePackageUpload.objects.all() |
24 | + allowed_methods = ['get', 'post'] |
25 | + authorization = Authorization() |
26 | + resource_name = 'spu' |
27 | |
28 | |
29 | class TicketResource(TicketTranslatedResource): |
30 | |
31 | class Meta: |
32 | # XXX cprov 20140829: 'private' should only be considered via |
33 | - # authorization mechnisms, not on the local resource queryset. |
34 | + # authorization mechanisms, not on the local resource queryset. |
35 | queryset = Ticket.objects.filter(private=False) |
36 | allowed_methods = ['get', 'post', 'patch'] |
37 | authorization = Authorization() |
38 | @@ -179,22 +180,26 @@ |
39 | paginator_class = PageNumberPaginator |
40 | |
41 | |
42 | -class SourcePackageUploadResource(ModelResource): |
43 | - sourcepackage = fields.ToOneField(SourcePackageResource, 'sourcepackage', |
44 | - full=True) |
45 | - |
46 | - class Meta: |
47 | - queryset = SourcePackageUpload.objects.all() |
48 | - allowed_methods = ['get', 'post'] |
49 | - authorization = Authorization() |
50 | - resource_name = 'spu' |
51 | +class SubTicketTranslatedResource(ModelResource): |
52 | + |
53 | + def dehydrate_current_workflow_step(self, bundle): |
54 | + return get_enum_title(bundle.data["current_workflow_step"], |
55 | + SubTicketWorkflowStep) |
56 | + |
57 | + def dehydrate_status(self, bundle): |
58 | + return get_enum_title(bundle.data["status"], |
59 | + SubTicketWorkflowStepStatus) |
60 | + |
61 | + source_package_upload = fields.ToOneField( |
62 | + SourcePackageUploadResource, 'source_package_upload', full=True) |
63 | + |
64 | + conflicts = fields.ToManyField( |
65 | + TicketResource, 'conflicts', readonly=True, null=True, full=False) |
66 | |
67 | |
68 | class SubTicketResource(SubTicketTranslatedResource): |
69 | + |
70 | ticket = fields.ToOneField(TicketResource, 'ticket', full=True) |
71 | - source_package_upload = fields.ToOneField(SourcePackageUploadResource, |
72 | - 'source_package_upload', |
73 | - full=True) |
74 | |
75 | class Meta: |
76 | queryset = SubTicket.objects.all() |
77 | @@ -216,8 +221,9 @@ |
78 | |
79 | |
80 | class SubTicketArtifactResource(ModelResource): |
81 | - subticket = fields.ToOneField(SubTicketResource, 'subticket', null=True, |
82 | - full=True) |
83 | + |
84 | + subticket = fields.ToOneField(SubTicketResource, 'subticket', |
85 | + readonly=True, null=True, full=True) |
86 | |
87 | class Meta: |
88 | queryset = SubTicketArtifact.objects.all() |
89 | @@ -240,9 +246,7 @@ |
90 | |
91 | |
92 | class FullSubTicketResource(SubTicketTranslatedResource): |
93 | - source_package_upload = fields.ToOneField(SourcePackageUploadResource, |
94 | - 'source_package_upload', |
95 | - full=True) |
96 | + |
97 | artifact = fields.ToManyField(FullSubTicketArtifactResource, |
98 | 'subticketartifact_set', full=True) |
99 | |
100 | @@ -252,6 +256,7 @@ |
101 | |
102 | |
103 | class FullTicketResource(TicketTranslatedResource): |
104 | + |
105 | subticket = fields.ToManyField(FullSubTicketResource, 'subticket_set', |
106 | full=True) |
107 | artifact = fields.ToManyField(FullTicketArtifactResource, |
108 | |
109 | === modified file 'ticket_system/ticket/models.py' |
110 | --- ticket_system/ticket/models.py 2014-09-09 17:25:59 +0000 |
111 | +++ ticket_system/ticket/models.py 2014-09-24 17:47:41 +0000 |
112 | @@ -232,6 +232,7 @@ |
113 | class SubTicket(models.Model): |
114 | class Meta: |
115 | db_table = 'subticket' |
116 | + ordering = ['id'] |
117 | |
118 | current_workflow_step = models.IntegerField( |
119 | choices=_choices(SubTicketWorkflowStep), max_length=4096, |
120 | @@ -246,6 +247,34 @@ |
121 | merge_proposal = models.ForeignKey(MergeProposal, null=True, blank=True, |
122 | default=None) |
123 | |
124 | + @property |
125 | + def conflicts(self): |
126 | + """Return `Ticket`s that conflict with this subticket task. |
127 | + |
128 | + A ticket is considered a conflict if it contains a `SubTicket` |
129 | + with a `SourcePackageUpload` or a `MergeProposal` for the same |
130 | + 'name' of this `SubTicket`. I.e. conflicts may happen between |
131 | + a MP and a SPU. |
132 | + |
133 | + Only *active* (not NEW|FAILED|COMPLETED) tickets are considered |
134 | + for conflicts. |
135 | + """ |
136 | + if self.merge_proposal is not None: |
137 | + sp = self.merge_proposal.sourcepackage |
138 | + else: |
139 | + sp = self.source_package_upload.sourcepackage |
140 | + |
141 | + conflicting_tickets = Ticket.objects.filter( |
142 | + models.Q(subticket__merge_proposal__sourcepackage=sp) |
143 | + | models.Q(subticket__source_package_upload__sourcepackage=sp), |
144 | + ~models.Q(pk=self.ticket.pk), |
145 | + ~models.Q(status=TicketWorkflowStepStatus.FAILED), |
146 | + current_workflow_step__range=( |
147 | + TicketWorkflowStep.QUEUED, TicketWorkflowStep.PKG_PUBLISHING), |
148 | + ) |
149 | + |
150 | + return conflicting_tickets |
151 | + |
152 | def save(self, *args, **kwargs): |
153 | if self.source_package_upload and self.merge_proposal: |
154 | raise IntegrityError("Subtickets only accept a source package " |
155 | |
156 | === modified file 'ticket_system/ticket/tests/test_full_read_api.py' |
157 | --- ticket_system/ticket/tests/test_full_read_api.py 2014-09-08 13:32:31 +0000 |
158 | +++ ticket_system/ticket/tests/test_full_read_api.py 2014-09-24 17:47:41 +0000 |
159 | @@ -98,6 +98,7 @@ |
160 | u'resource_uri': |
161 | u'/api/v1/spu/{0}/'.format(self.spu.pk)}, |
162 | u'id': self.subticket.pk, |
163 | + u'conflicts': [], |
164 | u'resource_uri': u'/api/v1/fullsubticket/{0}/'.format( |
165 | self.subticket.pk)}], |
166 | u'bug_id': self.ticket.bug_id, |
167 | @@ -168,6 +169,7 @@ |
168 | u'resource_uri': |
169 | u'/api/v1/spu/{0}/'.format(self.spu.pk)}, |
170 | u'id': self.subticket.pk, |
171 | + u'conflicts': [], |
172 | u'resource_uri': u'/api/v1/fullsubticket/{0}/'.format( |
173 | self.subticket.pk), |
174 | }) |
175 | |
176 | === modified file 'ticket_system/ticket/tests/test_models.py' |
177 | --- ticket_system/ticket/tests/test_models.py 2014-08-27 11:59:06 +0000 |
178 | +++ ticket_system/ticket/tests/test_models.py 2014-09-24 17:47:41 +0000 |
179 | @@ -44,7 +44,7 @@ |
180 | return sourcepackage |
181 | |
182 | |
183 | -def create_sourcepackageupload(sourcepackage='my-package', version='1.1'): |
184 | +def create_sourcepackageupload(sourcepackage, version='1.1'): |
185 | spu = SourcePackageUpload() |
186 | spu.sourcepackage = sourcepackage |
187 | spu.version = version |
188 | @@ -52,7 +52,7 @@ |
189 | return spu |
190 | |
191 | |
192 | -def create_merge_proposal(project='my-project', sourcepackage='my-package', |
193 | +def create_merge_proposal(sourcepackage, project='my-project', |
194 | lp_url='~foobar/my-project/my-branch/+merge/123456', |
195 | target_branch='lp:~foobar/my-project/trunk', |
196 | approved_revno=100, version='1.1'): |
197 | @@ -350,3 +350,108 @@ |
198 | '''make sure we don't allow invalid json''' |
199 | with self.assertRaises(ValidationError): |
200 | Workflow.objects.create(name='foo', steps='this is not json') |
201 | + |
202 | + |
203 | +class TestTicketConflicts(TestCase): |
204 | + |
205 | + def setUp(self): |
206 | + """Mock container creation and queue dispatching. |
207 | + |
208 | + Also setup a common ticket conflict eco-system. |
209 | + """ |
210 | + _m = mock.patch('ticket.models.Ticket.create_container') |
211 | + _m.start() |
212 | + self.addCleanup(_m.stop) |
213 | + _m = mock.patch('ci_utils.amqp_utils.send') |
214 | + _m.start() |
215 | + self.addCleanup(_m.stop) |
216 | + |
217 | + self.ticket_one = create_ticket(title='One') |
218 | + self.ticket_two = create_ticket(title='Two') |
219 | + sp_one = create_sourcepackage('ding') |
220 | + sp_two = create_sourcepackage('dong') |
221 | + self.spu_one = create_sourcepackageupload(sp_one) |
222 | + self.spu_two = create_sourcepackageupload(sp_two) |
223 | + self.mp_one = create_merge_proposal(sp_one) |
224 | + self.mp_two = create_merge_proposal(sp_two) |
225 | + |
226 | + def test_no_conflicts(self): |
227 | + # Conflicts are only detected for `SourcePackageUpload`s with |
228 | + # the same 'name' and 'version'. |
229 | + subticket_one = create_subticket( |
230 | + ticket=self.ticket_one, source_package_upload=self.spu_one) |
231 | + subticket_two = create_subticket( |
232 | + ticket=self.ticket_two, source_package_upload=self.spu_two) |
233 | + |
234 | + self.assertEqual( |
235 | + [], list(subticket_one.conflicts)) |
236 | + self.assertEqual( |
237 | + [], list(subticket_two.conflicts)) |
238 | + |
239 | + def test_has_single_conflict(self): |
240 | + # Conflicts are symmetrical across 'SubTicket's on active `Ticket`s |
241 | + # (A conflicts with B, thus B conflicts with A) and cover |
242 | + # `SourcePackageUpload` and `MergeProposal`s. |
243 | + subticket_one = create_subticket( |
244 | + ticket=self.ticket_one, source_package_upload=self.spu_one) |
245 | + subticket_two = create_subticket( |
246 | + ticket=self.ticket_two, merge_proposal=self.mp_one) |
247 | + |
248 | + self.assertEqual( |
249 | + [self.ticket_two], list(subticket_one.conflicts)) |
250 | + self.assertEqual( |
251 | + [self.ticket_one], list(subticket_two.conflicts)) |
252 | + |
253 | + def test_no_conflicts_for_inactive(self): |
254 | + # Inactive `Ticket`s (NEW, FAILED or COMPLETED) are not considered |
255 | + # conflict targets, but still pointing to active conflicts. |
256 | + subticket_one = create_subticket( |
257 | + ticket=self.ticket_one, source_package_upload=self.spu_one) |
258 | + subticket_two = create_subticket( |
259 | + ticket=self.ticket_two, source_package_upload=self.spu_one) |
260 | + |
261 | + self.ticket_two.current_workflow_step = TicketWorkflowStep.COMPLETED |
262 | + self.ticket_two.save() |
263 | + |
264 | + self.assertEqual([], list(subticket_one.conflicts)) |
265 | + self.assertEqual([self.ticket_one], list(subticket_two.conflicts)) |
266 | + |
267 | + def test_no_conflicts_for_failures(self): |
268 | + # `Ticket`s that failed in any workflow steps are not considered |
269 | + # conflict targets. |
270 | + subticket_one = create_subticket( |
271 | + ticket=self.ticket_one, source_package_upload=self.spu_one) |
272 | + subticket_two = create_subticket( |
273 | + ticket=self.ticket_two, source_package_upload=self.spu_one) |
274 | + |
275 | + self.ticket_two.current_workflow_step = ( |
276 | + TicketWorkflowStep.PKG_BUILDING) |
277 | + self.ticket_two.status = TicketWorkflowStepStatus.FAILED |
278 | + self.ticket_two.save() |
279 | + |
280 | + self.assertEqual([], list(subticket_one.conflicts)) |
281 | + self.assertEqual([self.ticket_one], list(subticket_two.conflicts)) |
282 | + |
283 | + def test_has_multiple_conflicts(self): |
284 | + # Multiple conflicting tickets are distinct and ordered by id. |
285 | + subticket_one = create_subticket( |
286 | + ticket=self.ticket_one, source_package_upload=self.spu_one) |
287 | + subticket_two = create_subticket( |
288 | + ticket=self.ticket_two, source_package_upload=self.spu_one) |
289 | + # Create a third conflicting ticket on a MP |
290 | + ticket_three = create_ticket(title='Three') |
291 | + subticket_three = create_subticket( |
292 | + ticket=ticket_three, merge_proposal=self.mp_one) |
293 | + # Force a multi-path join to provoke duplicated results. |
294 | + create_subticket( |
295 | + ticket=self.ticket_one, source_package_upload=self.spu_two) |
296 | + create_subticket( |
297 | + ticket=self.ticket_two, merge_proposal=self.mp_two) |
298 | + |
299 | + self.assertEqual( |
300 | + [self.ticket_two, ticket_three], list(subticket_one.conflicts)) |
301 | + self.assertEqual( |
302 | + [self.ticket_one, ticket_three], list(subticket_two.conflicts)) |
303 | + self.assertEqual( |
304 | + [self.ticket_one, self.ticket_two], |
305 | + list(subticket_three.conflicts)) |
306 | |
307 | === modified file 'ticket_system/ticket/tests/test_read_api.py' |
308 | --- ticket_system/ticket/tests/test_read_api.py 2014-09-10 11:41:44 +0000 |
309 | +++ ticket_system/ticket/tests/test_read_api.py 2014-09-24 17:47:41 +0000 |
310 | @@ -153,6 +153,7 @@ |
311 | settings.TEST_DATETIME_FORMAT)), |
312 | u'uuid': self.ticket.uuid}, |
313 | u'id': self.subticket.pk, |
314 | + u'conflicts': [], |
315 | u'resource_uri': u'/api/v1/subticket/{0}/'.format( |
316 | self.subticket.pk)}, |
317 | u'type': unicode(self.artifact_1.type), |
318 | @@ -245,8 +246,35 @@ |
319 | u'updated': unicode(self.ticket.updated.strftime( |
320 | settings.TEST_DATETIME_FORMAT)), |
321 | u'uuid': self.ticket.uuid}, |
322 | + u'conflicts': [], |
323 | }) |
324 | |
325 | + def test_subticket_api_conflicts(self): |
326 | + # Each `Subticket`s points, individually, to conflicting `Tickets` |
327 | + # This way users have a clear indication of which part (subticket) |
328 | + # of their task might result in problem when landing. |
329 | + another_ticket = mommy.make( |
330 | + 'Ticket', current_workflow_step=TicketWorkflowStep.QUEUED) |
331 | + another_spu = mommy.make( |
332 | + 'SourcePackageUpload', sourcepackage=self.sourcepackage, |
333 | + version=self.spu.version) |
334 | + mommy.make( |
335 | + 'SubTicket', ticket=another_ticket, |
336 | + source_package_upload=another_spu) |
337 | + |
338 | + [old, new] = self.getResource('subticket/')['objects'] |
339 | + |
340 | + # The 'old' ticket now conflicts with 'new' (just created). |
341 | + # Remember, 'conflicts' contains the `Ticket` resource URI. |
342 | + self.assertEqual( |
343 | + [new['ticket']['resource_uri']], old['conflicts']) |
344 | + |
345 | + # The 'new' ticket does not conflict with the 'old' because it's |
346 | + # still 'NEW' (not active). See 'test_models' for more descriptive |
347 | + # test on this aspect. |
348 | + self.assertEqual( |
349 | + [], new['conflicts']) |
350 | + |
351 | def test_get_ticket_api(self): |
352 | obj = self.getResource('ticket/') |
353 | self.assertEqual(obj['objects'][0], { |
354 | |
355 | === modified file 'webui/tickets/static/tickets/webui.js' |
356 | --- webui/tickets/static/tickets/webui.js 2014-08-29 18:54:41 +0000 |
357 | +++ webui/tickets/static/tickets/webui.js 2014-09-24 17:47:41 +0000 |
358 | @@ -185,7 +185,14 @@ |
359 | make_subticket: function (data) { |
360 | var div = Y.Node.create("<div class='subticket'></div>"), |
361 | table = div.appendChild(Y.Node.create("<table>")), |
362 | - hidden_fields = Y.Array(['id', 'resource_uri', 'current_workflow_step', 'status', 'source_package_upload']), |
363 | + hidden_fields = Y.Array([ |
364 | + 'id', |
365 | + 'resource_uri', |
366 | + 'current_workflow_step', |
367 | + 'status', |
368 | + 'source_package_upload', |
369 | + 'conflicts', |
370 | + ]), |
371 | key, |
372 | value, |
373 | tmp_th, |
PASSED: Continuous integration, rev:794 s-jenkins. ubuntu- ci:8080/ job/uci- engine- ci/1419/
http://
Executed test runs:
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/uci- engine- ci/1419/ rebuild
http://