Merge lp:~abentley/launchpad/jobstatus into lp:launchpad

Proposed by Aaron Bentley
Status: Merged
Approved by: Guilherme Salgado
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~abentley/launchpad/jobstatus
Merge into: lp:launchpad
Diff against target: 280 lines (+119/-7)
10 files modified
lib/canonical/launchpad/icing/style.css (+2/-2)
lib/lp/code/browser/branchmergeproposal.py (+4/-0)
lib/lp/code/configure.zcml (+1/-0)
lib/lp/code/interfaces/branchmergeproposal.py (+3/-0)
lib/lp/code/model/branchmergeproposal.py (+26/-2)
lib/lp/code/model/branchmergeproposaljob.py (+5/-2)
lib/lp/code/model/tests/test_branchmergeproposals.py (+52/-0)
lib/lp/code/stories/branches/xx-branch-merge-proposals.txt (+16/-0)
lib/lp/code/templates/branch-index.pt (+1/-1)
lib/lp/code/templates/branchmergeproposal-index.pt (+9/-0)
To merge this branch: bzr merge lp:~abentley/launchpad/jobstatus
Reviewer Review Type Date Requested Status
Guilherme Salgado (community) code Approve
Review via email: mp+16309@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Aaron Bentley (abentley) wrote :

= Summary =
Fix bug #336936 "Show something on the merge proposal page while diff is being
generated".

== Proposed fix ==
Add a notice similar to the one about branch scanning

== Pre-implementation notes ==
None.

== Implementation details ==

== Tests ==
bin/test -t test_branchmergeproposals -t xx-branch-merge-proposals

== Demo and Q/A ==
Create a branch merge proposal. It should show a notice saying the diff is
being updated. After a few minutes, the diff should appear and the message
should go away. Now push new changes to the source branch. The message should
reappear.

= Launchpad lint =

There is lint here, but not of it seems very rational.

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/canonical/launchpad/icing/style.css
  lib/lp/code/configure.zcml
  lib/lp/code/browser/branchmergeproposal.py
  lib/lp/code/interfaces/branchmergeproposal.py
  lib/lp/code/model/branchmergeproposal.py
  lib/lp/code/model/branchmergeproposaljob.py
  lib/lp/code/model/tests/test_branchmergeproposals.py
  lib/lp/code/stories/branches/xx-branch-merge-proposals.txt
  lib/lp/code/templates/branchmergeproposal-index.pt

== Pylint notices ==

lib/lp/code/interfaces/branchmergeproposal.py
    27: [F0401] Unable to import 'lazr.lifecycle.event' (No module named lifecycle)
    42: [F0401] Unable to import 'lazr.restful.fields' (No module named restful)
    43: [F0401] Unable to import 'lazr.restful.declarations' (No module named restful)
    309: [C0322, IBranchMergeProposal.setStatus] Operator not preceded by a space
    title=_("The new status of the merge proposal."),
    ^
    vocabulary=BranchMergeProposalStatus),
    revision_id=Text(
    description=_("An optional parameter for specifying the "
    "revision of the branch for the status change."),
    required=False))
    @export_write_operation()
    def setStatus(status, user, revision_id):
    459: [C0322, IBranchMergeProposal.createComment] Operator not preceded by a space
    parent=Reference(schema=Interface))
    ^
    @call_with(owner=REQUEST_USER)

    @export_factory_operation(Interface, [])
    def createComment(owner, subject, content=None, vote=None,
    review_type=None, parent=None):
    490: [C0322, IBranchMergeProposal.updatePreviewDiff] Operator not preceded by a space
    target_revision_id=TextLine(), prerequisite_revision_id=TextLine(),
    ^
    conflicts=Text())
    @export_write_operation()
    def updatePreviewDiff(diff_content, source_revision_id,
    target_revision_id, prerequisite_revision_id=None,
    conflicts=None):

lib/lp/code/model/branchmergeproposaljob.py
    20: [F0401] Unable to import 'lazr.delegates' (No module named delegates)
    21: [F0401] Unable to import 'lazr.enum' (No module named enum)

Revision history for this message
Guilherme Salgado (salgado) wrote :
Download full text (6.4 KiB)

Hi Aaron,

I have a few questions/suggestions below, but it looks good overall.

 review needsfixing

On Thu, 2009-12-17 at 21:46 +0000, Aaron Bentley wrote:
> = Summary =
> Fix bug #336936 "Show something on the merge proposal page while diff
> is being
> generated".
>
> == Proposed fix ==
> Add a notice similar to the one about branch scanning
>
> == Pre-implementation notes ==
> None.
>
> == Implementation details ==
>
> == Tests ==
> bin/test -t test_branchmergeproposals -t xx-branch-merge-proposals
>

> === modified file 'lib/canonical/launchpad/icing/style.css'
> --- lib/canonical/launchpad/icing/style.css 2009-12-08 10:57:44 +0000
> +++ lib/canonical/launchpad/icing/style.css 2009-12-17 21:46:16 +0000
> @@ -1104,7 +1104,7 @@
> height: 2.5em;
> }
>
> -#branch-pending-writes {
> +#branch-pending-writes, #diff-pending-update {

Is this not a good opportunity to rename this class to 'pending-update'
or 'update-in-progress' instead of creating an alias to it?

> background: #FFF59C;
> width: 40em;
> margin: 1em auto;
> @@ -1117,7 +1117,7 @@
> -webkit-border-radius: 5px;
> }
>
> -#branch-pending-writes h3 {
> +#branch-pending-writes h3, #diff-pending-update h3 {
> color: black;
> font-weight: bold;
> text-align: center;
>

> === modified file 'lib/lp/code/interfaces/branchmergeproposal.py'
> --- lib/lp/code/interfaces/branchmergeproposal.py 2009-10-23 00:48:47 +0000
> +++ lib/lp/code/interfaces/branchmergeproposal.py 2009-12-17 21:46:16 +0000
> @@ -155,6 +155,8 @@
> IStaticDiff, title=_('The diff to be used for reviews.'),
> readonly=True)
>
> + next_preview_diff_job = Attribute('foo')
> +

!?

> preview_diff = exported(
> Reference(
> IPreviewDiff,
> @@ -511,6 +513,10 @@
> class IBranchMergeProposalJob(Interface):
> """A Job related to a Branch Merge Proposal."""
>
> + id = Int(
> + title=_('DB ID'), required=True, readonly=True,
> + description=_("Database id for this BranchJob."))

Do you really need to expose this in the public interface or is it just
for your test?

> +
> branch_merge_proposal = Object(
> title=_('The BranchMergeProposal this job is about'),
> schema=IBranchMergeProposal, required=True)
>
> === modified file 'lib/lp/code/model/branchmergeproposal.py'
> --- lib/lp/code/model/branchmergeproposal.py 2009-12-01 01:09:38 +0000
> +++ lib/lp/code/model/branchmergeproposal.py 2009-12-17 21:46:16 +0000
[...]
>
>
> def is_valid_transition(proposal, from_state, next_state, user=None):
> @@ -132,6 +134,26 @@
> review_diff = ForeignKey(
> foreignKey='StaticDiff', notNull=False, default=None)
>
> + @property
> + def next_preview_diff_job(self):
> + from lp.code.model.branchmergeproposaljob import (
> + BranchMergeProposalJob, MergeProposalCreatedJob,
> + UpdatePreviewDiffJob)

Circular dependencies? If so, care to leave a comment here?

> + job_classes = [MergeProposalCreatedJob, UpdatePreviewDiffJob]
> + type_classes = dict(
> + (job_class.class_job_type, job_class)
> + for job_class...

Read more...

review: Needs Fixing
Revision history for this message
Aaron Bentley (abentley) wrote :
Download full text (6.0 KiB)

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Guilherme Salgado wrote:

>> === modified file 'lib/canonical/launchpad/icing/style.css'
>> --- lib/canonical/launchpad/icing/style.css 2009-12-08 10:57:44 +0000
>> +++ lib/canonical/launchpad/icing/style.css 2009-12-17 21:46:16 +0000
>> @@ -1104,7 +1104,7 @@
>> height: 2.5em;
>> }
>>
>> -#branch-pending-writes {
>> +#branch-pending-writes, #diff-pending-update {
>
> Is this not a good opportunity to rename this class to 'pending-update'
> or 'update-in-progress' instead of creating an alias to it?

Okay, I can do that.

>> background: #FFF59C;
>> width: 40em;
>> margin: 1em auto;
>> @@ -1117,7 +1117,7 @@
>> -webkit-border-radius: 5px;
>> }
>>
>> -#branch-pending-writes h3 {
>> +#branch-pending-writes h3, #diff-pending-update h3 {
>> color: black;
>> font-weight: bold;
>> text-align: center;
>>
>
>> === modified file 'lib/lp/code/interfaces/branchmergeproposal.py'
>> --- lib/lp/code/interfaces/branchmergeproposal.py 2009-10-23 00:48:47 +0000
>> +++ lib/lp/code/interfaces/branchmergeproposal.py 2009-12-17 21:46:16 +0000
>> @@ -155,6 +155,8 @@
>> IStaticDiff, title=_('The diff to be used for reviews.'),
>> readonly=True)
>>
>> + next_preview_diff_job = Attribute('foo')
>> +
>
> !?

Circular dependencies. I'll make the attribute somewhat better.

>> preview_diff = exported(
>> Reference(
>> IPreviewDiff,
>> @@ -511,6 +513,10 @@
>> class IBranchMergeProposalJob(Interface):
>> """A Job related to a Branch Merge Proposal."""
>>
>> + id = Int(
>> + title=_('DB ID'), required=True, readonly=True,
>> + description=_("Database id for this BranchJob."))
>
> Do you really need to expose this in the public interface or is it just
> for your test?

I think it makes a lot of sense to expose in the public interface, and I
have another branch in which it is necessary to expose it in the public
interface:

https://code.edge.launchpad.net/~abentley/launchpad/ampoulejob/+merge/15982

In this case, once I change the test to use an equality, I don't need it.

>
>> +
>> branch_merge_proposal = Object(
>> title=_('The BranchMergeProposal this job is about'),
>> schema=IBranchMergeProposal, required=True)
>>
>> === modified file 'lib/lp/code/model/branchmergeproposal.py'
>> --- lib/lp/code/model/branchmergeproposal.py 2009-12-01 01:09:38 +0000
>> +++ lib/lp/code/model/branchmergeproposal.py 2009-12-17 21:46:16 +0000
> [...]
>>
>>
>> def is_valid_transition(proposal, from_state, next_state, user=None):
>> @@ -132,6 +134,26 @@
>> review_diff = ForeignKey(
>> foreignKey='StaticDiff', notNull=False, default=None)
>>
>> + @property
>> + def next_preview_diff_job(self):
>> + from lp.code.model.branchmergeproposaljob import (
>> + BranchMergeProposalJob, MergeProposalCreatedJob,
>> + UpdatePreviewDiffJob)
>
> Circular dependencies?

Yes.

> If so, care to leave a comment here?

Alright.

>
>> + job_classes = [MergeProposalCreatedJob, UpdatePreviewDiffJob]
>> + type_classes = dict(
>> + (j...

Read more...

1=== modified file 'lib/canonical/launchpad/icing/style.css'
2--- lib/canonical/launchpad/icing/style.css 2009-12-14 20:08:29 +0000
3+++ lib/canonical/launchpad/icing/style.css 2009-12-18 19:52:27 +0000
4@@ -1104,7 +1104,7 @@
5 height: 2.5em;
6 }
7
8-#branch-pending-writes, #diff-pending-update {
9+.pending-update {
10 background: #FFF59C;
11 width: 40em;
12 margin: 1em auto;
13@@ -1117,7 +1117,7 @@
14 -webkit-border-radius: 5px;
15 }
16
17-#branch-pending-writes h3, #diff-pending-update h3 {
18+.pending-update h3{
19 color: black;
20 font-weight: bold;
21 text-align: center;
22
23=== modified file 'lib/lp/code/interfaces/branchmergeproposal.py'
24--- lib/lp/code/interfaces/branchmergeproposal.py 2009-12-18 14:51:37 +0000
25+++ lib/lp/code/interfaces/branchmergeproposal.py 2009-12-18 19:44:07 +0000
26@@ -118,7 +118,8 @@
27 IStaticDiff, title=_('The diff to be used for reviews.'),
28 readonly=True)
29
30- next_preview_diff_job = Attribute('foo')
31+ next_preview_diff_job = Attribute(
32+ 'The next BranchMergeProposalJob that will update a preview diff.')
33
34 preview_diff = exported(
35 Reference(
36@@ -476,10 +477,6 @@
37 class IBranchMergeProposalJob(Interface):
38 """A Job related to a Branch Merge Proposal."""
39
40- id = Int(
41- title=_('DB ID'), required=True, readonly=True,
42- description=_("Database id for this BranchJob."))
43-
44 branch_merge_proposal = Object(
45 title=_('The BranchMergeProposal this job is about'),
46 schema=IBranchMergeProposal, required=True)
47
48=== modified file 'lib/lp/code/model/branchmergeproposal.py'
49--- lib/lp/code/model/branchmergeproposal.py 2009-12-18 14:51:37 +0000
50+++ lib/lp/code/model/branchmergeproposal.py 2009-12-18 19:44:53 +0000
51@@ -137,6 +137,7 @@
52
53 @property
54 def next_preview_diff_job(self):
55+ # circular dependencies
56 from lp.code.model.branchmergeproposaljob import (
57 BranchMergeProposalJob, MergeProposalCreatedJob,
58 UpdatePreviewDiffJob)
59@@ -147,7 +148,7 @@
60 job = Store.of(self).find(
61 BranchMergeProposalJob,
62 BranchMergeProposalJob.branch_merge_proposal == self,
63- BranchMergeProposalJob.job_type.is_in(type_classes),
64+ BranchMergeProposalJob.job_type.is_in(type_classes.keys()),
65 BranchMergeProposalJob.job == Job.id,
66 Job._status.is_in([JobStatus.WAITING, JobStatus.RUNNING])
67 ).order_by(Job.scheduled_start, Job.date_created).first()
68
69=== modified file 'lib/lp/code/model/tests/test_branchmergeproposals.py'
70--- lib/lp/code/model/tests/test_branchmergeproposals.py 2009-12-18 14:51:37 +0000
71+++ lib/lp/code/model/tests/test_branchmergeproposals.py 2009-12-18 19:41:47 +0000
72@@ -1879,9 +1879,9 @@
73 """Jobs are shown while pending."""
74 bmp = self.factory.makeBranchMergeProposal()
75 job = bmp.next_preview_diff_job
76- self.assertEqual(job.id, bmp.next_preview_diff_job.id)
77+ self.assertEqual(job, bmp.next_preview_diff_job)
78 job.start()
79- self.assertEqual(job.id, bmp.next_preview_diff_job.id)
80+ self.assertEqual(job, bmp.next_preview_diff_job)
81 job.fail()
82 self.assertIs(None, bmp.next_preview_diff_job)
83
84
85=== modified file 'lib/lp/code/templates/branch-index.pt'
86--- lib/lp/code/templates/branch-index.pt 2009-12-03 18:33:22 +0000
87+++ lib/lp/code/templates/branch-index.pt 2009-12-18 19:49:08 +0000
88@@ -162,7 +162,7 @@
89
90 <div class="yui-g" tal:condition="view/pending_writes">
91 <div class="portlet">
92- <div id="branch-pending-writes">
93+ <div id="branch-pending-writes" class="pending-update">
94 <h3>Updating branch...</h3>
95 <p>
96 Launchpad is processing new changes to this branch and will be
97
98=== modified file 'lib/lp/code/templates/branchmergeproposal-index.pt'
99--- lib/lp/code/templates/branchmergeproposal-index.pt 2009-12-14 20:08:29 +0000
100+++ lib/lp/code/templates/branchmergeproposal-index.pt 2009-12-18 19:53:27 +0000
101@@ -181,7 +181,7 @@
102 </div>
103
104 <div class="yui-g" tal:condition="view/pending_diff">
105- <div class="portlet" id="diff-pending-update">
106+ <div class="portlet pending-update" id="diff-pending-update">
107 <h3>Updating diff...</h3>
108 <p>
109 An updated diff will be available in a few minutes. Reload to see the
Revision history for this message
Guilherme Salgado (salgado) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/icing/style.css'
2--- lib/canonical/launchpad/icing/style.css 2010-01-04 17:15:00 +0000
3+++ lib/canonical/launchpad/icing/style.css 2010-01-06 20:54:14 +0000
4@@ -1086,7 +1086,7 @@
5 height: 2.5em;
6 }
7
8-#branch-pending-writes {
9+.pending-update {
10 background: #FFF59C;
11 width: 40em;
12 margin: 1em auto;
13@@ -1099,7 +1099,7 @@
14 -webkit-border-radius: 5px;
15 }
16
17-#branch-pending-writes h3 {
18+.pending-update h3{
19 color: black;
20 font-weight: bold;
21 text-align: center;
22
23=== modified file 'lib/lp/code/browser/branchmergeproposal.py'
24--- lib/lp/code/browser/branchmergeproposal.py 2009-12-11 00:56:16 +0000
25+++ lib/lp/code/browser/branchmergeproposal.py 2010-01-06 20:54:14 +0000
26@@ -626,6 +626,10 @@
27 result.append(dict(style=style, comment=comment))
28 return result
29
30+ @property
31+ def pending_diff(self):
32+ return self.context.next_preview_diff_job is not None
33+
34 @cachedproperty
35 def preview_diff(self):
36 """Return a `Diff` of the preview.
37
38=== modified file 'lib/lp/code/configure.zcml'
39--- lib/lp/code/configure.zcml 2009-12-18 15:59:21 +0000
40+++ lib/lp/code/configure.zcml 2010-01-06 20:54:14 +0000
41@@ -226,6 +226,7 @@
42 date_review_requested
43 date_reviewed
44 review_diff
45+ next_preview_diff_job
46 preview_diff
47 votes
48 root_comment
49
50=== modified file 'lib/lp/code/interfaces/branchmergeproposal.py'
51--- lib/lp/code/interfaces/branchmergeproposal.py 2009-12-18 15:59:21 +0000
52+++ lib/lp/code/interfaces/branchmergeproposal.py 2010-01-06 20:54:14 +0000
53@@ -118,6 +118,9 @@
54 IStaticDiff, title=_('The diff to be used for reviews.'),
55 readonly=True)
56
57+ next_preview_diff_job = Attribute(
58+ 'The next BranchMergeProposalJob that will update a preview diff.')
59+
60 preview_diff = exported(
61 Reference(
62 IPreviewDiff,
63
64=== modified file 'lib/lp/code/model/branchmergeproposal.py'
65--- lib/lp/code/model/branchmergeproposal.py 2009-12-08 09:02:43 +0000
66+++ lib/lp/code/model/branchmergeproposal.py 2010-01-06 20:54:14 +0000
67@@ -38,7 +38,6 @@
68 from lp.code.model.codereviewvote import (
69 CodeReviewVoteReference)
70 from lp.code.model.diff import PreviewDiff
71-from lp.registry.model.person import Person
72 from lp.code.event.branchmergeproposal import (
73 BranchMergeProposalStatusChangeEvent, NewCodeReviewCommentEvent,
74 ReviewerNominatedEvent)
75@@ -48,11 +47,14 @@
76 BRANCH_MERGE_PROPOSAL_FINAL_STATES as FINAL_STATES,
77 IBranchMergeProposal, IBranchMergeProposalGetter)
78 from lp.code.interfaces.branchtarget import IHasBranchTarget
79+from lp.code.mail.branch import RecipientReason
80+from lp.registry.model.person import Person
81 from lp.registry.interfaces.person import IPerson
82 from lp.registry.interfaces.product import IProduct
83-from lp.code.mail.branch import RecipientReason
84 from lp.registry.interfaces.person import validate_public_person
85 from lp.services.mail.sendmail import validate_message
86+from lp.services.job.interfaces.job import JobStatus
87+from lp.services.job.model.job import Job
88
89
90 def is_valid_transition(proposal, from_state, next_state, user=None):
91@@ -133,6 +135,28 @@
92 review_diff = ForeignKey(
93 foreignKey='StaticDiff', notNull=False, default=None)
94
95+ @property
96+ def next_preview_diff_job(self):
97+ # circular dependencies
98+ from lp.code.model.branchmergeproposaljob import (
99+ BranchMergeProposalJob, MergeProposalCreatedJob,
100+ UpdatePreviewDiffJob)
101+ job_classes = [MergeProposalCreatedJob, UpdatePreviewDiffJob]
102+ type_classes = dict(
103+ (job_class.class_job_type, job_class)
104+ for job_class in job_classes)
105+ job = Store.of(self).find(
106+ BranchMergeProposalJob,
107+ BranchMergeProposalJob.branch_merge_proposal == self,
108+ BranchMergeProposalJob.job_type.is_in(type_classes.keys()),
109+ BranchMergeProposalJob.job == Job.id,
110+ Job._status.is_in([JobStatus.WAITING, JobStatus.RUNNING])
111+ ).order_by(Job.scheduled_start, Job.date_created).first()
112+ if job is not None:
113+ return type_classes[job.job_type](job)
114+ else:
115+ return None
116+
117 preview_diff_id = Int(name='merge_diff')
118 preview_diff = Reference(preview_diff_id, 'PreviewDiff.id')
119
120
121=== modified file 'lib/lp/code/model/branchmergeproposaljob.py'
122--- lib/lp/code/model/branchmergeproposaljob.py 2009-12-10 18:20:09 +0000
123+++ lib/lp/code/model/branchmergeproposaljob.py 2010-01-06 20:54:14 +0000
124@@ -15,7 +15,7 @@
125 ]
126
127 import contextlib
128-from email.Utils import parseaddr
129+from email.utils import parseaddr
130 import transaction
131
132 from lazr.delegates import delegates
133@@ -28,6 +28,7 @@
134 from storm.store import Store
135 from zope.component import getUtility
136 from zope.interface import classProvides, implements
137+from zope.security.proxy import removeSecurityProxy
138
139 from canonical.database.enumcol import EnumCol
140 from canonical.launchpad.database.message import MessageJob, MessageJobAction
141@@ -153,7 +154,9 @@
142 self.context = job
143
144 def __eq__(self, job):
145- return (self.__class__ is job.__class__ and self.job == job.job)
146+ return (
147+ self.__class__ is removeSecurityProxy(job.__class__)
148+ and self.job == job.job)
149
150 def __ne__(self, job):
151 return not (self == job)
152
153=== modified file 'lib/lp/code/model/tests/test_branchmergeproposals.py'
154--- lib/lp/code/model/tests/test_branchmergeproposals.py 2009-12-18 15:02:34 +0000
155+++ lib/lp/code/model/tests/test_branchmergeproposals.py 2010-01-06 20:54:14 +0000
156@@ -13,6 +13,7 @@
157
158 from pytz import UTC
159 from sqlobject import SQLObjectNotFound
160+from storm.locals import Store
161 from zope.component import getUtility
162 import transaction
163 from zope.security.proxy import removeSecurityProxy
164@@ -1891,5 +1892,56 @@
165 self.checkExampleMerge(bmp.preview_diff.text)
166
167
168+class TestNextPreviewDiffJob(TestCaseWithFactory):
169+
170+ layer = DatabaseFunctionalLayer
171+
172+ def test_returns_bmp_job(self):
173+ """For new proposals, get the MergeProposalCreatedJob."""
174+ bmp = self.factory.makeBranchMergeProposal()
175+ job = bmp.next_preview_diff_job
176+ self.assertEqual(bmp, job.branch_merge_proposal)
177+ self.assertIs(
178+ MergeProposalCreatedJob, removeSecurityProxy(job).__class__)
179+
180+ def test_returns_none_if_job_not_pending(self):
181+ """Jobs are shown while pending."""
182+ bmp = self.factory.makeBranchMergeProposal()
183+ job = bmp.next_preview_diff_job
184+ self.assertEqual(job, bmp.next_preview_diff_job)
185+ job.start()
186+ self.assertEqual(job, bmp.next_preview_diff_job)
187+ job.fail()
188+ self.assertIs(None, bmp.next_preview_diff_job)
189+
190+ def makeBranchMergeProposalNoPending(self):
191+ bmp = self.factory.makeBranchMergeProposal()
192+ bmp.next_preview_diff_job.start()
193+ bmp.next_preview_diff_job.complete()
194+ return bmp
195+
196+ def test_returns_update_preview_diff_job(self):
197+ """UpdatePreviewDiffJobs can be returned."""
198+ bmp = self.makeBranchMergeProposalNoPending()
199+ updatejob = UpdatePreviewDiffJob.create(bmp)
200+ Store.of(updatejob.context).flush()
201+ self.assertEqual(updatejob, bmp.next_preview_diff_job)
202+
203+ def test_returns_first__job(self):
204+ """First-created job is returned."""
205+ bmp = self.makeBranchMergeProposalNoPending()
206+ updatejob = UpdatePreviewDiffJob.create(bmp)
207+ updatejob2 = UpdatePreviewDiffJob.create(bmp)
208+ self.assertEqual(updatejob, bmp.next_preview_diff_job)
209+
210+ def test_does_not_return_jobs_for_other_proposals(self):
211+ """Jobs for other merge proposals are not returned."""
212+ bmp = self.factory.makeBranchMergeProposal()
213+ bmp.next_preview_diff_job.start()
214+ bmp.next_preview_diff_job.complete()
215+ bmp2 = self.factory.makeBranchMergeProposal()
216+ self.assertIs(None, bmp.next_preview_diff_job)
217+
218+
219 def test_suite():
220 return TestLoader().loadTestsFromName(__name__)
221
222=== modified file 'lib/lp/code/stories/branches/xx-branch-merge-proposals.txt'
223--- lib/lp/code/stories/branches/xx-branch-merge-proposals.txt 2009-11-27 01:29:10 +0000
224+++ lib/lp/code/stories/branches/xx-branch-merge-proposals.txt 2010-01-06 20:54:14 +0000
225@@ -628,6 +628,22 @@
226 Empty
227
228
229+Preview diff generation status
230+------------------------------
231+
232+ >>> update = find_tag_by_id(nopriv_browser.contents, 'diff-pending-update')
233+ >>> print extract_text(update)
234+ Updating diff...
235+ An updated diff will be available in a few minutes. Reload to see the
236+ changes.
237+ >>> bmp.next_preview_diff_job.start()
238+ >>> bmp.next_preview_diff_job.complete()
239+ >>> transaction.commit()
240+ >>> nopriv_browser.open(url)
241+ >>> print find_tag_by_id(nopriv_browser.contents, 'diff-pending-update')
242+ None
243+
244+
245 Merge proposal details shown on the branch page
246 -----------------------------------------------
247
248
249=== modified file 'lib/lp/code/templates/branch-index.pt'
250--- lib/lp/code/templates/branch-index.pt 2010-01-04 19:36:17 +0000
251+++ lib/lp/code/templates/branch-index.pt 2010-01-06 20:54:14 +0000
252@@ -163,7 +163,7 @@
253
254 <div class="yui-g" tal:condition="view/pending_writes">
255 <div class="portlet">
256- <div id="branch-pending-writes">
257+ <div id="branch-pending-writes" class="pending-update">
258 <h3>Updating branch...</h3>
259 <p>
260 Launchpad is processing new changes to this branch and will be
261
262=== modified file 'lib/lp/code/templates/branchmergeproposal-index.pt'
263--- lib/lp/code/templates/branchmergeproposal-index.pt 2009-12-11 05:07:57 +0000
264+++ lib/lp/code/templates/branchmergeproposal-index.pt 2010-01-06 20:54:14 +0000
265@@ -180,6 +180,15 @@
266 </div>
267 </div>
268
269+ <div class="yui-g" tal:condition="view/pending_diff">
270+ <div class="portlet pending-update" id="diff-pending-update">
271+ <h3>Updating diff...</h3>
272+ <p>
273+ An updated diff will be available in a few minutes. Reload to see the
274+ changes.
275+ </p>
276+ </div>
277+ </div>
278 <div id="review-diff" tal:condition="view/preview_diff">
279 <h2>Preview Diff</h2>
280 <div tal:replace="structure context/@@++diff"/>