13779.3.4
by Steve Kowalik
Update copyright years, and fix more test failures for dead things. |
1 |
# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
|
8687.15.17
by Karl Fogel
Add the copyright header block to the rest of the files under lib/lp/. |
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
3 |
||
8511.2.13
by Aaron Bentley
Fix line wrap |
4 |
# pylint: disable-msg=C0322,F0401
|
4414.5.13
by Tim Penhey
Still work in progress |
5 |
|
6 |
"""Views, navigation and actions for BranchMergeProposals."""
|
|
7 |
||
8 |
__metaclass__ = type |
|
9 |
__all__ = [ |
|
6699.2.12
by Paul Hummer
Adds merge candidate views |
10 |
'BranchMergeCandidateView', |
9476.1.3
by Tim Penhey
Breadcrumbs for branches, and fix bmp-index a bit. |
11 |
'BranchMergeProposalActionNavigationMenu', |
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
12 |
'BranchMergeProposalAddVoteView', |
7055.6.6
by Tim Penhey
Add an edit status view for merge proposals and remove the menu links. |
13 |
'BranchMergeProposalChangeStatusView', |
7954.3.6
by Paul Hummer
Responded to review |
14 |
'BranchMergeProposalCommitMessageEditView', |
4414.5.13
by Tim Penhey
Still work in progress |
15 |
'BranchMergeProposalContextMenu', |
5280.4.24
by Tim Penhey
First cut of changes following review. |
16 |
'BranchMergeProposalDeleteView', |
5579.2.1
by Tim Penhey
Some queue management |
17 |
'BranchMergeProposalDequeueView', |
7675.548.2
by Tim Penhey
Update for the description field. |
18 |
'BranchMergeProposalDescriptionEditView', |
9301.2.43
by Paul Hummer
Re-arranged again, implemented menu |
19 |
'BranchMergeProposalEditMenu', |
4414.5.13
by Tim Penhey
Still work in progress |
20 |
'BranchMergeProposalEditView', |
5579.2.1
by Tim Penhey
Some queue management |
21 |
'BranchMergeProposalEnqueueView', |
5579.2.4
by Tim Penhey
UI works now. |
22 |
'BranchMergeProposalInlineDequeueView', |
23 |
'BranchMergeProposalJumpQueueView', |
|
5608.11.5
by Aaron Bentley
Make comment pages reachable |
24 |
'BranchMergeProposalNavigation', |
4414.5.13
by Tim Penhey
Still work in progress |
25 |
'BranchMergeProposalMergedView', |
6998.1.1
by Tim Penhey
Update the primary contexts for branch merge proposals, branch subscriptions, code review comments, and bug branch links. |
26 |
'BranchMergeProposalPrimaryContext', |
5280.4.2
by Tim Penhey
Request review done. |
27 |
'BranchMergeProposalRequestReviewView', |
5600.2.2
by Tim Penhey
Resubmit merge proposals. |
28 |
'BranchMergeProposalResubmitView', |
6699.2.1
by Paul Hummer
Modifies views for some of the subscription stuff |
29 |
'BranchMergeProposalSubscribersView', |
5280.4.8
by Tim Penhey
Added +index view for proposals |
30 |
'BranchMergeProposalView', |
6438.2.3
by Tim Penhey
Add the tables for reviews done, and requested reviews. |
31 |
'BranchMergeProposalVoteView', |
9691.7.9
by Tim Penhey
Extract the logic into a common method and test it. |
32 |
'latest_proposals_for_each_branch', |
4414.5.13
by Tim Penhey
Still work in progress |
33 |
]
|
34 |
||
13333.13.40
by Gavin Panella
Use BranchMergeProposalDelta.monitor() in browser code. |
35 |
from functools import wraps |
6438.2.3
by Tim Penhey
Add the tables for reviews done, and requested reviews. |
36 |
import operator |
37 |
||
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
38 |
from lazr.delegates import delegates |
39 |
from lazr.restful.interface import copy_field |
|
13333.6.43
by Gavin Panella
Revert changes to lp.code; these will appear in a later branch. |
40 |
from lazr.restful.interfaces import ( |
13302.8.3
by Andrew Bennetts
Generate correct links to fetch diffs from. |
41 |
IJSONRequestCache, |
13333.6.43
by Gavin Panella
Revert changes to lp.code; these will appear in a later branch. |
42 |
IWebServiceClientRequest, |
43 |
)
|
|
9848.1.5
by Paul Hummer
Got the widget working with the API. |
44 |
import simplejson |
7285.2.1
by Paul Hummer
Added class to the comment form in a reply |
45 |
from zope.app.form.browser import TextAreaWidget |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
46 |
from zope.component import ( |
47 |
adapts, |
|
48 |
getMultiAdapter, |
|
49 |
getUtility, |
|
50 |
)
|
|
6080.5.8
by Aaron Bentley
Resubmit passes tests |
51 |
from zope.formlib import form |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
52 |
from zope.interface import ( |
53 |
implements, |
|
54 |
Interface, |
|
55 |
)
|
|
56 |
from zope.schema import ( |
|
11812.2.3
by Aaron Bentley
Add break link option to resubmit. |
57 |
Bool, |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
58 |
Choice, |
59 |
Int, |
|
60 |
Text, |
|
61 |
)
|
|
62 |
from zope.schema.vocabulary import ( |
|
63 |
SimpleTerm, |
|
64 |
SimpleVocabulary, |
|
65 |
)
|
|
7876.3.6
by Francis J. Lacoste
Used ISQLObject from lazr.lifecycle |
66 |
|
7675.292.6
by Tim Penhey
Let the users know if the diff has been truncated. |
67 |
from canonical.config import config |
14600.1.12
by Curtis Hovey
Move i18n to lp. |
68 |
from lp import _ |
14600.2.2
by Curtis Hovey
Moved webapp to lp.services. |
69 |
from lp.services.webapp import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
70 |
canonical_url, |
71 |
ContextMenu, |
|
72 |
enabled_with_permission, |
|
73 |
LaunchpadView, |
|
74 |
Link, |
|
75 |
Navigation, |
|
76 |
stepthrough, |
|
77 |
stepto, |
|
78 |
)
|
|
14600.2.2
by Curtis Hovey
Moved webapp to lp.services. |
79 |
from lp.services.webapp.authorization import check_permission |
80 |
from lp.services.webapp.breadcrumb import Breadcrumb |
|
81 |
from lp.services.webapp.interfaces import IPrimaryContext |
|
82 |
from lp.services.webapp.menu import ( |
|
13333.15.1
by Gavin Panella
Subscribe merge proposal pages to pending diff job completion events. |
83 |
NavigationMenu, |
84 |
structured, |
|
85 |
)
|
|
11929.9.1
by Tim Penhey
Move launchpadform into lp.app.browser. |
86 |
from lp.app.browser.launchpadform import ( |
87 |
action, |
|
88 |
custom_widget, |
|
89 |
LaunchpadEditFormView, |
|
90 |
LaunchpadFormView, |
|
13333.15.1
by Gavin Panella
Subscribe merge proposal pages to pending diff job completion events. |
91 |
)
|
12268.3.18
by Tim Penhey
Move the widgets around. |
92 |
from lp.app.browser.lazrjs import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
93 |
TextAreaEditorWidget, |
94 |
vocabulary_to_choice_edit_items, |
|
95 |
)
|
|
12268.3.18
by Tim Penhey
Move the widgets around. |
96 |
from lp.app.browser.tales import DateTimeFormatterAPI |
13333.15.1
by Gavin Panella
Subscribe merge proposal pages to pending diff job completion events. |
97 |
from lp.app.longpoll import subscribe |
13333.13.54
by Gavin Panella
Rename BranchMergeProposalDelta to BranchMergeProposalNoPreviewDiffDelta and BranchMergeProposalWithPreviewDiffDelta to BranchMergeProposalDelta, and change BranchMergeProposalNoPreviewDiffDelta to inherit from BranchMergeProposalDelta. |
98 |
from lp.code.adapters.branch import BranchMergeProposalNoPreviewDiffDelta |
8971.8.1
by Tim Penhey
Make the +reply and +comment views use the service/comment rendering. |
99 |
from lp.code.browser.codereviewcomment import CodeReviewDisplayComment |
12505.6.1
by Ian Booth
Remove DecoratedBug and refactor mp linked_bugs to use branch.getRelatedBugTasks |
100 |
from lp.code.browser.decorations import DecoratedBranch |
8555.2.5
by Tim Penhey
Move the branch subscription enums. |
101 |
from lp.code.enums import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
102 |
BranchMergeProposalStatus, |
103 |
BranchType, |
|
104 |
CodeReviewNotificationLevel, |
|
105 |
CodeReviewVote, |
|
106 |
)
|
|
12959.1.3
by Aaron Bentley
Review claim failures generate error notification, not oops. |
107 |
from lp.code.errors import ( |
13278.2.4
by Aaron Bentley
Handle BranchMergeProposalExists as a user error. |
108 |
BranchMergeProposalExists, |
12959.1.3
by Aaron Bentley
Review claim failures generate error notification, not oops. |
109 |
ClaimReviewFailed, |
13618.3.1
by Aaron Bentley
InvalidMergeProposal is handled as a user error. |
110 |
InvalidBranchMergeProposal, |
12959.1.3
by Aaron Bentley
Review claim failures generate error notification, not oops. |
111 |
WrongBranchMergeProposal, |
112 |
)
|
|
7675.429.3
by Tim Penhey
Move merge proposal errors to lp.code.errors. |
113 |
from lp.code.interfaces.branchmergeproposal import IBranchMergeProposal |
8555.2.9
by Tim Penhey
Move CodeReviewVote enum. |
114 |
from lp.code.interfaces.codereviewcomment import ICodeReviewComment |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
115 |
from lp.code.interfaces.codereviewvote import ICodeReviewVoteReference |
9691.6.10
by Tim Penhey
Make the diff load using the API rather than hitting the page. |
116 |
from lp.code.interfaces.diff import IPreviewDiff |
7675.293.10
by Aaron Bentley
Remove unused import. |
117 |
from lp.registry.interfaces.person import IPersonSet |
9984.4.3
by Tim Penhey
Broken tests are there... |
118 |
from lp.services.comments.interfaces.conversation import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
119 |
IComment, |
120 |
IConversation, |
|
121 |
)
|
|
7675.916.98
by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes. |
122 |
from lp.services.features import getFeatureFlag |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
123 |
from lp.services.fields import ( |
124 |
Summary, |
|
125 |
Whiteboard, |
|
126 |
)
|
|
13333.15.1
by Gavin Panella
Subscribe merge proposal pages to pending diff job completion events. |
127 |
from lp.services.messages.interfaces.message import IMessageSet |
11382.6.34
by Gavin Panella
Reformat imports in all files touched so far. |
128 |
from lp.services.propertycache import cachedproperty |
6438.2.1
by Tim Penhey
Renamed the CodeReviewVote class to avoid name clash with CodeReviewVote enumerated type. |
129 |
|
4414.5.13
by Tim Penhey
Still work in progress |
130 |
|
9691.7.9
by Tim Penhey
Extract the logic into a common method and test it. |
131 |
def latest_proposals_for_each_branch(proposals): |
132 |
"""Returns the most recent merge proposals for any particular branch.
|
|
133 |
||
134 |
Also filters out proposals that the logged in user can't see.
|
|
135 |
"""
|
|
136 |
targets = {} |
|
137 |
for proposal in proposals: |
|
138 |
# Don't show the proposal if the user can't see it.
|
|
139 |
if not check_permission('launchpad.View', proposal): |
|
140 |
continue
|
|
141 |
# Only show the must recent proposal for any given target.
|
|
142 |
date_created = proposal.date_created |
|
143 |
target_id = proposal.target_branch.id |
|
9691.7.28
by Tim Penhey
Tweak latest_proposals_for_each_branch as per review suggestion. |
144 |
|
145 |
if target_id not in targets or date_created > targets[target_id][1]: |
|
9691.7.9
by Tim Penhey
Extract the logic into a common method and test it. |
146 |
targets[target_id] = (proposal, date_created) |
147 |
||
148 |
return sorted( |
|
149 |
[proposal for proposal, date_created in targets.itervalues()], |
|
150 |
key=operator.attrgetter('date_created'), reverse=True) |
|
151 |
||
152 |
||
6998.1.1
by Tim Penhey
Update the primary contexts for branch merge proposals, branch subscriptions, code review comments, and bug branch links. |
153 |
class BranchMergeProposalPrimaryContext: |
154 |
"""The primary context is the proposal is that of the source branch."""
|
|
155 |
||
156 |
implements(IPrimaryContext) |
|
157 |
||
158 |
def __init__(self, branch_merge_proposal): |
|
159 |
self.context = IPrimaryContext( |
|
160 |
branch_merge_proposal.source_branch).context |
|
161 |
||
162 |
||
9476.1.4
by Tim Penhey
Give merge proposals a breadcrumb, and some minor drive by fixes. |
163 |
class BranchMergeProposalBreadcrumb(Breadcrumb): |
164 |
"""An `IBreadcrumb` for a merge proposal."""
|
|
165 |
||
166 |
@property
|
|
167 |
def text(self): |
|
168 |
return 'Merge into %s' % self.context.target_branch.name |
|
169 |
||
170 |
||
6080.6.1
by Aaron Bentley
Refactor notify decorator out of update_and_notify |
171 |
def notify(func): |
6080.6.3
by Aaron Bentley
Add final punctuation to docstrings |
172 |
"""Decorate a view method to send a notification."""
|
13333.13.40
by Gavin Panella
Use BranchMergeProposalDelta.monitor() in browser code. |
173 |
@wraps(func) |
6080.6.2
by Aaron Bentley
Tweak and update docs |
174 |
def decorator(view, *args, **kwargs): |
13333.13.54
by Gavin Panella
Rename BranchMergeProposalDelta to BranchMergeProposalNoPreviewDiffDelta and BranchMergeProposalWithPreviewDiffDelta to BranchMergeProposalDelta, and change BranchMergeProposalNoPreviewDiffDelta to inherit from BranchMergeProposalDelta. |
175 |
with BranchMergeProposalNoPreviewDiffDelta.monitor(view.context): |
13333.13.40
by Gavin Panella
Use BranchMergeProposalDelta.monitor() in browser code. |
176 |
return func(view, *args, **kwargs) |
6080.6.1
by Aaron Bentley
Refactor notify decorator out of update_and_notify |
177 |
return decorator |
178 |
||
179 |
||
180 |
def update_and_notify(func): |
|
6080.6.3
by Aaron Bentley
Add final punctuation to docstrings |
181 |
"""Decorate an action to update from a form and send a notification."""
|
11626.3.10
by Curtis Hovey
Hush lints epic complaints about the changes files. |
182 |
|
6080.6.1
by Aaron Bentley
Refactor notify decorator out of update_and_notify |
183 |
@notify
|
184 |
def decorator(view, action, data): |
|
185 |
result = func(view, action, data) |
|
6080.5.8
by Aaron Bentley
Resubmit passes tests |
186 |
form.applyChanges( |
187 |
view.context, view.form_fields, data, view.adapters) |
|
188 |
return result |
|
189 |
return decorator |
|
190 |
||
191 |
||
6699.2.12
by Paul Hummer
Adds merge candidate views |
192 |
class BranchMergeCandidateView(LaunchpadView): |
193 |
"""Provides a small fragment of landing targets"""
|
|
194 |
||
195 |
def friendly_text(self): |
|
196 |
"""Prints friendly text for a branch."""
|
|
197 |
friendly_texts = { |
|
11626.3.10
by Curtis Hovey
Hush lints epic complaints about the changes files. |
198 |
BranchMergeProposalStatus.WORK_IN_PROGRESS: 'On hold', |
199 |
BranchMergeProposalStatus.NEEDS_REVIEW: 'Ready for review', |
|
200 |
BranchMergeProposalStatus.CODE_APPROVED: 'Approved', |
|
201 |
BranchMergeProposalStatus.REJECTED: 'Rejected', |
|
202 |
BranchMergeProposalStatus.MERGED: 'Merged', |
|
203 |
BranchMergeProposalStatus.MERGE_FAILED: |
|
6735.1.1
by Paul Hummer
Adds merge proposal stuffs |
204 |
'Approved [Merge Failed]', |
11626.3.10
by Curtis Hovey
Hush lints epic complaints about the changes files. |
205 |
BranchMergeProposalStatus.QUEUED: 'Queued', |
206 |
BranchMergeProposalStatus.SUPERSEDED: 'Superseded', |
|
11486.5.14
by Aaron Bentley
Get incremental diffs displaying |
207 |
}
|
6699.2.12
by Paul Hummer
Adds merge candidate views |
208 |
return friendly_texts[self.context.queue_status] |
209 |
||
9691.5.5
by Tim Penhey
Confirm that the title is set properly. |
210 |
@property
|
9691.4.1
by Tim Penhey
Add title to the link summary, move the link summary to have a consistent file name, add the vote summary view, template and show it on the branch page. |
211 |
def status_title(self): |
212 |
"""The title for the status text.
|
|
213 |
||
214 |
Only set if the status is approved or rejected.
|
|
215 |
"""
|
|
216 |
result = '' |
|
217 |
if self.context.queue_status in ( |
|
218 |
BranchMergeProposalStatus.CODE_APPROVED, |
|
11486.5.14
by Aaron Bentley
Get incremental diffs displaying |
219 |
BranchMergeProposalStatus.REJECTED): |
9691.4.1
by Tim Penhey
Add title to the link summary, move the link summary to have a consistent file name, add the vote summary view, template and show it on the branch page. |
220 |
formatter = DateTimeFormatterAPI(self.context.date_reviewed) |
221 |
result = '%s %s' % ( |
|
222 |
self.context.reviewer.displayname, |
|
223 |
formatter.displaydate()) |
|
224 |
return result |
|
225 |
||
6699.2.12
by Paul Hummer
Adds merge candidate views |
226 |
|
9476.1.3
by Tim Penhey
Breadcrumbs for branches, and fix bmp-index a bit. |
227 |
class BranchMergeProposalMenuMixin: |
228 |
"""Mixin class for merge proposal menus."""
|
|
6438.3.24
by Aaron Bentley
Updates for LP2.0 |
229 |
|
230 |
@enabled_with_permission('launchpad.AnyPerson') |
|
231 |
def add_comment(self): |
|
9461.9.1
by Aaron Bentley
Allow voting and reviewing when proposal isn't mergeable. |
232 |
return Link('+comment', 'Add a review or comment', icon='add') |
5280.4.11
by Tim Penhey
Read only page is now the default view, edit pages hang off that. |
233 |
|
234 |
@enabled_with_permission('launchpad.Edit') |
|
235 |
def edit(self): |
|
236 |
text = 'Edit details' |
|
7055.6.17
by Tim Penhey
Fixed resubmit and link visibility. |
237 |
enabled = self.context.isMergable() |
5600.2.7
by Tim Penhey
Updated pagetest for resubmissions. |
238 |
return Link('+edit', text, icon='edit', enabled=enabled) |
5280.4.8
by Tim Penhey
Added +index view for proposals |
239 |
|
240 |
@enabled_with_permission('launchpad.Edit') |
|
7675.548.2
by Tim Penhey
Update for the description field. |
241 |
def set_description(self): |
242 |
text = 'Set description' |
|
243 |
return Link('+edit-description', text, icon='add') |
|
244 |
||
245 |
@enabled_with_permission('launchpad.Edit') |
|
9928.2.1
by Tim Penhey
First hack. |
246 |
def set_commit_message(self): |
247 |
text = 'Set commit message' |
|
7954.3.3
by Paul Hummer
Added link to the commit message edit view |
248 |
enabled = self.context.isMergable() |
9928.2.3
by Tim Penhey
Trying... but it seems that simulate is 3.0 release. |
249 |
return Link('+edit-commit-message', text, icon='add', |
8511.2.13
by Aaron Bentley
Fix line wrap |
250 |
enabled=enabled) |
7954.3.3
by Paul Hummer
Added link to the commit message edit view |
251 |
|
252 |
@enabled_with_permission('launchpad.Edit') |
|
7055.6.6
by Tim Penhey
Add an edit status view for merge proposals and remove the menu links. |
253 |
def edit_status(self): |
254 |
text = 'Change status' |
|
8511.2.12
by Aaron Bentley
Allow status changes for merged or superseded BMP |
255 |
return Link('+edit-status', text, icon='edit') |
7055.6.6
by Tim Penhey
Add an edit status view for merge proposals and remove the menu links. |
256 |
|
257 |
@enabled_with_permission('launchpad.Edit') |
|
5280.4.24
by Tim Penhey
First cut of changes following review. |
258 |
def delete(self): |
259 |
text = 'Delete proposal to merge' |
|
9476.1.3
by Tim Penhey
Breadcrumbs for branches, and fix bmp-index a bit. |
260 |
return Link('+delete', text, icon='trash-icon') |
5280.4.24
by Tim Penhey
First cut of changes following review. |
261 |
|
5579.2.4
by Tim Penhey
UI works now. |
262 |
def _enabledForStatus(self, next_state): |
263 |
"""True if the next_state is a valid transition for the current user.
|
|
264 |
||
265 |
Return False if the current state is next_state.
|
|
266 |
"""
|
|
9476.1.3
by Tim Penhey
Breadcrumbs for branches, and fix bmp-index a bit. |
267 |
bmp = self.branch_merge_proposal |
268 |
status = bmp.queue_status |
|
5579.2.4
by Tim Penhey
UI works now. |
269 |
if status == next_state: |
270 |
return False |
|
271 |
else: |
|
9476.1.3
by Tim Penhey
Breadcrumbs for branches, and fix bmp-index a bit. |
272 |
return bmp.isValidTransition(next_state, self.user) |
5579.2.4
by Tim Penhey
UI works now. |
273 |
|
5280.4.24
by Tim Penhey
First cut of changes following review. |
274 |
@enabled_with_permission('launchpad.Edit') |
5280.4.1
by Tim Penhey
Adding menu bits. |
275 |
def request_review(self): |
6602.1.1
by Tim Penhey
Some touchy feely changes to code review page.! |
276 |
text = 'Request a review' |
5579.2.4
by Tim Penhey
UI works now. |
277 |
enabled = self._enabledForStatus( |
278 |
BranchMergeProposalStatus.NEEDS_REVIEW) |
|
6438.3.9
by Aaron Bentley
Support requesting additional reviewers |
279 |
if (self.context.queue_status == |
280 |
BranchMergeProposalStatus.NEEDS_REVIEW): |
|
281 |
enabled = True |
|
6438.3.23
by Aaron Bentley
Update from review |
282 |
if (self.context.votes.count()) > 0: |
6438.3.9
by Aaron Bentley
Support requesting additional reviewers |
283 |
text = 'Request another review' |
6735.1.1
by Paul Hummer
Adds merge proposal stuffs |
284 |
return Link('+request-review', text, icon='add', enabled=enabled) |
5280.4.1
by Tim Penhey
Adding menu bits. |
285 |
|
286 |
@enabled_with_permission('launchpad.Edit') |
|
4414.5.13
by Tim Penhey
Still work in progress |
287 |
def merge(self): |
288 |
text = 'Mark as merged' |
|
5579.2.4
by Tim Penhey
UI works now. |
289 |
enabled = self._enabledForStatus( |
290 |
BranchMergeProposalStatus.MERGED) |
|
6735.1.1
by Paul Hummer
Adds merge proposal stuffs |
291 |
return Link('+merged', text, enabled=enabled) |
4414.5.13
by Tim Penhey
Still work in progress |
292 |
|
5579.2.1
by Tim Penhey
Some queue management |
293 |
@enabled_with_permission('launchpad.Edit') |
6914.1.10
by Paul Hummer
For some boneheaded reason, I did originally make that edit of merge revision a |
294 |
def update_merge_revno(self): |
295 |
text = 'Update revision number' |
|
296 |
return Link('+merged', text) |
|
297 |
||
298 |
@enabled_with_permission('launchpad.Edit') |
|
5579.2.1
by Tim Penhey
Some queue management |
299 |
def enqueue(self): |
300 |
text = 'Queue for merging' |
|
5579.2.4
by Tim Penhey
UI works now. |
301 |
enabled = self._enabledForStatus( |
302 |
BranchMergeProposalStatus.QUEUED) |
|
6735.1.1
by Paul Hummer
Adds merge proposal stuffs |
303 |
return Link('+enqueue', text, enabled=enabled) |
5579.2.1
by Tim Penhey
Some queue management |
304 |
|
5579.2.3
by Tim Penhey
Merged dependent branch. |
305 |
@enabled_with_permission('launchpad.Edit') |
5579.2.4
by Tim Penhey
UI works now. |
306 |
def dequeue(self): |
307 |
text = 'Remove from queue' |
|
308 |
enabled = (self.context.queue_status == |
|
309 |
BranchMergeProposalStatus.QUEUED) |
|
6735.1.1
by Paul Hummer
Adds merge proposal stuffs |
310 |
return Link('+dequeue', text, enabled=enabled) |
5579.2.4
by Tim Penhey
UI works now. |
311 |
|
312 |
@enabled_with_permission('launchpad.Edit') |
|
5600.2.2
by Tim Penhey
Resubmit merge proposals. |
313 |
def resubmit(self): |
314 |
text = 'Resubmit proposal' |
|
5579.2.4
by Tim Penhey
UI works now. |
315 |
enabled = self._enabledForStatus( |
5600.2.10
by Tim Penhey
Rename supercede to supersede, and shorten the databse field name. |
316 |
BranchMergeProposalStatus.SUPERSEDED) |
9327.2.4
by Aaron Bentley
Use edit icon. |
317 |
return Link('+resubmit', text, enabled=enabled, icon='edit') |
5600.2.2
by Tim Penhey
Resubmit merge proposals. |
318 |
|
4414.5.13
by Tim Penhey
Still work in progress |
319 |
|
9301.2.43
by Paul Hummer
Re-arranged again, implemented menu |
320 |
class BranchMergeProposalEditMenu(NavigationMenu, |
321 |
BranchMergeProposalMenuMixin): |
|
322 |
"""Edit menu for Branch Merge Proposals."""
|
|
323 |
||
324 |
usedfor = IBranchMergeProposal |
|
325 |
title = 'Edit Proposal' |
|
326 |
facet = 'branches' |
|
9570.13.3
by Paul Hummer
General housekeeping |
327 |
links = ['resubmit', 'delete'] |
9301.2.43
by Paul Hummer
Re-arranged again, implemented menu |
328 |
|
329 |
@property
|
|
330 |
def branch_merge_proposal(self): |
|
331 |
return self.context |
|
332 |
||
333 |
||
9476.1.3
by Tim Penhey
Breadcrumbs for branches, and fix bmp-index a bit. |
334 |
class BranchMergeProposalContextMenu(ContextMenu, |
335 |
BranchMergeProposalMenuMixin): |
|
336 |
"""Context menu for merge proposals."""
|
|
337 |
||
338 |
usedfor = IBranchMergeProposal |
|
339 |
links = [ |
|
340 |
'add_comment', |
|
9570.13.3
by Paul Hummer
General housekeeping |
341 |
'dequeue', |
9928.2.1
by Tim Penhey
First hack. |
342 |
'set_commit_message', |
7675.548.2
by Tim Penhey
Update for the description field. |
343 |
'set_description', |
9570.13.3
by Paul Hummer
General housekeeping |
344 |
'edit_status', |
345 |
'enqueue', |
|
9476.1.3
by Tim Penhey
Breadcrumbs for branches, and fix bmp-index a bit. |
346 |
'merge', |
9570.13.3
by Paul Hummer
General housekeeping |
347 |
'request_review', |
9476.1.3
by Tim Penhey
Breadcrumbs for branches, and fix bmp-index a bit. |
348 |
'resubmit', |
349 |
'update_merge_revno', |
|
350 |
]
|
|
351 |
||
352 |
@property
|
|
353 |
def branch_merge_proposal(self): |
|
354 |
return self.context |
|
355 |
||
356 |
||
357 |
class IBranchMergeProposalActionMenu(Interface): |
|
358 |
"""A marker interface for the global action navigation menu."""
|
|
359 |
||
360 |
||
361 |
class BranchMergeProposalActionNavigationMenu(NavigationMenu, |
|
362 |
BranchMergeProposalMenuMixin): |
|
363 |
"""A sub-menu for acting upon a Product."""
|
|
364 |
||
365 |
usedfor = IBranchMergeProposalActionMenu |
|
366 |
facet = 'branches' |
|
367 |
links = ('resubmit', 'delete') |
|
368 |
||
369 |
@property
|
|
370 |
def branch_merge_proposal(self): |
|
371 |
# This context is the view, the view's context is the bmp.
|
|
372 |
return self.context.context |
|
373 |
||
374 |
||
5280.4.8
by Tim Penhey
Added +index view for proposals |
375 |
class UnmergedRevisionsMixin: |
376 |
"""Provides the methods needed to show unmerged revisions."""
|
|
377 |
||
378 |
@cachedproperty
|
|
379 |
def unlanded_revisions(self): |
|
380 |
"""Return the unlanded revisions from the source branch."""
|
|
381 |
return self.context.getUnlandedSourceBranchRevisions() |
|
382 |
||
383 |
@property
|
|
8128.7.7
by Jonathan Lange
Make the template use the view for obtaining pending-writes, since the |
384 |
def pending_writes(self): |
385 |
"""Needed to make the branch-revisions metal macro work."""
|
|
386 |
return False |
|
387 |
||
388 |
@property
|
|
5280.4.8
by Tim Penhey
Added +index view for proposals |
389 |
def codebrowse_url(self): |
390 |
"""Return the link to codebrowse for this branch."""
|
|
7622.1.11
by Michael Hudson
boy i wish this mistake had turned up some other way than an obscure failure in a page test :/ |
391 |
return self.context.source_branch.codebrowse_url() |
5280.4.8
by Tim Penhey
Added +index view for proposals |
392 |
|
393 |
||
5579.2.4
by Tim Penhey
UI works now. |
394 |
class BranchMergeProposalRevisionIdMixin: |
395 |
"""A mixin class to provide access to the revision ids."""
|
|
5579.2.1
by Tim Penhey
Some queue management |
396 |
|
397 |
def _getRevisionNumberForRevisionId(self, revision_id): |
|
398 |
"""Find the revision number that corresponds to the revision id.
|
|
5763.1.6
by Tim Penhey
Some view refactoring. |
399 |
|
400 |
If there was no last reviewed revision, None is returned.
|
|
401 |
||
402 |
If the reviewed revision is no longer in the revision history of
|
|
403 |
the source branch, then a message is returned.
|
|
404 |
"""
|
|
5579.2.1
by Tim Penhey
Some queue management |
405 |
if revision_id is None: |
406 |
return None |
|
5763.1.6
by Tim Penhey
Some view refactoring. |
407 |
# If the source branch is REMOTE, then there won't be any ids.
|
408 |
source_branch = self.context.source_branch |
|
409 |
if source_branch.branch_type == BranchType.REMOTE: |
|
5579.2.1
by Tim Penhey
Some queue management |
410 |
return revision_id |
5763.1.6
by Tim Penhey
Some view refactoring. |
411 |
else: |
6736.3.5
by Tim Penhey
Clean up the Branch.getBranchRevision method. |
412 |
branch_revision = source_branch.getBranchRevision( |
413 |
revision_id=revision_id) |
|
5763.1.6
by Tim Penhey
Some view refactoring. |
414 |
if branch_revision is None: |
415 |
return "no longer in the source branch." |
|
416 |
elif branch_revision.sequence is None: |
|
417 |
return ( |
|
418 |
"no longer in the revision history of the source branch.") |
|
419 |
else: |
|
420 |
return branch_revision.sequence |
|
421 |
||
5579.2.1
by Tim Penhey
Some queue management |
422 |
@cachedproperty
|
423 |
def reviewed_revision_number(self): |
|
424 |
"""Return the number of the reviewed revision."""
|
|
425 |
return self._getRevisionNumberForRevisionId( |
|
426 |
self.context.reviewed_revision_id) |
|
427 |
||
428 |
@cachedproperty
|
|
429 |
def queued_revision_number(self): |
|
430 |
"""Return the number of the queued revision."""
|
|
431 |
return self._getRevisionNumberForRevisionId( |
|
432 |
self.context.queued_revision_id) |
|
5763.1.6
by Tim Penhey
Some view refactoring. |
433 |
|
434 |
||
5608.11.5
by Aaron Bentley
Make comment pages reachable |
435 |
class BranchMergeProposalNavigation(Navigation): |
5608.13.23
by Aaron Bentley
update docs |
436 |
"""Navigation from BranchMergeProposal to CodeReviewComment views."""
|
5608.11.5
by Aaron Bentley
Make comment pages reachable |
437 |
|
438 |
usedfor = IBranchMergeProposal |
|
439 |
||
7675.293.8
by Aaron Bentley
Allow reassigning code review. |
440 |
@stepthrough('reviews') |
441 |
def traverse_review(self, id): |
|
7675.293.19
by Aaron Bentley
Cleanup |
442 |
"""Navigate to a CodeReviewVoteReference through its BMP."""
|
7675.293.8
by Aaron Bentley
Allow reassigning code review. |
443 |
try: |
444 |
id = int(id) |
|
445 |
except ValueError: |
|
446 |
return None |
|
447 |
try: |
|
448 |
return self.context.getVoteReference(id) |
|
449 |
except WrongBranchMergeProposal: |
|
450 |
return None |
|
451 |
||
5608.11.7
by Aaron Bentley
Update code review comment traversal to match canonical_url |
452 |
@stepthrough('comments') |
5608.11.5
by Aaron Bentley
Make comment pages reachable |
453 |
def traverse_comment(self, id): |
454 |
try: |
|
455 |
id = int(id) |
|
456 |
except ValueError: |
|
457 |
return None |
|
5608.11.61
by Aaron Bentley
Handle BranchMergeProposal.getMessage when merge proposal doesn't match |
458 |
try: |
6334.6.36
by Aaron Bentley
Rename code review messages to code review comments |
459 |
return self.context.getComment(id) |
5608.11.61
by Aaron Bentley
Handle BranchMergeProposal.getMessage when merge proposal doesn't match |
460 |
except WrongBranchMergeProposal: |
5608.11.59
by Aaron Bentley
Apply many review comments |
461 |
return None |
5608.11.5
by Aaron Bentley
Make comment pages reachable |
462 |
|
7667.9.6
by Tim Penhey
Add traversal and tests. |
463 |
@stepto("+preview-diff") |
464 |
def preview_diff(self): |
|
465 |
"""Step to the preview diff."""
|
|
466 |
return self.context.preview_diff |
|
467 |
||
7719.2.15
by Paul Hummer
Implemented getVote for IBranchMergeProposal |
468 |
@stepthrough('+review') |
469 |
def review(self, id): |
|
470 |
"""Step to the CodeReviewVoteReference."""
|
|
471 |
try: |
|
7719.2.16
by Paul Hummer
Implemented IBranchMergeProposal.id |
472 |
id = int(id) |
7719.2.15
by Paul Hummer
Implemented getVote for IBranchMergeProposal |
473 |
except ValueError: |
474 |
return None |
|
475 |
try: |
|
476 |
return self.context.getVoteReference(id) |
|
477 |
except WrongBranchMergeProposal: |
|
478 |
return None |
|
5608.11.5
by Aaron Bentley
Make comment pages reachable |
479 |
|
8624.1.3
by Tim Penhey
Working but needs clean up. |
480 |
|
481 |
class CodeReviewConversation: |
|
482 |
"""A code review conversation."""
|
|
483 |
||
484 |
implements(IConversation) |
|
485 |
||
486 |
def __init__(self, comments): |
|
487 |
self.comments = comments |
|
488 |
||
9476.1.3
by Tim Penhey
Breadcrumbs for branches, and fix bmp-index a bit. |
489 |
|
7675.293.1
by Aaron Bentley
Start work on review claiming. |
490 |
class ClaimButton(Interface): |
491 |
"""A simple interface to populate the form to enqueue a proposal."""
|
|
492 |
||
7675.293.4
by Aaron Bentley
Start testing claim_action. |
493 |
review_id = Int(required=True) |
7675.293.1
by Aaron Bentley
Start work on review claiming. |
494 |
|
495 |
||
9848.1.13
by Paul Hummer
Fixed the status vocabulary to be generated based on what's enabled. |
496 |
class BranchMergeProposalStatusMixin: |
497 |
'''A mixin for generating status vocabularies.'''
|
|
498 |
||
499 |
def _createStatusVocabulary(self): |
|
500 |
# Create the vocabulary that is used for the status widget.
|
|
501 |
possible_next_states = ( |
|
502 |
BranchMergeProposalStatus.WORK_IN_PROGRESS, |
|
503 |
BranchMergeProposalStatus.NEEDS_REVIEW, |
|
504 |
BranchMergeProposalStatus.CODE_APPROVED, |
|
505 |
BranchMergeProposalStatus.REJECTED, |
|
506 |
# BranchMergeProposalStatus.QUEUED,
|
|
507 |
BranchMergeProposalStatus.MERGED, |
|
508 |
)
|
|
509 |
terms = [] |
|
510 |
for status in possible_next_states: |
|
511 |
if not self.context.isValidTransition(status, self.user): |
|
512 |
continue
|
|
513 |
else: |
|
514 |
title = status.title |
|
515 |
terms.append(SimpleTerm(status, status.name, title)) |
|
516 |
return SimpleVocabulary(terms) |
|
517 |
||
518 |
||
9691.6.10
by Tim Penhey
Make the diff load using the API rather than hitting the page. |
519 |
class DiffRenderingMixin: |
520 |
"""A mixin class for handling diff text."""
|
|
521 |
||
522 |
@cachedproperty
|
|
523 |
def preview_diff_text(self): |
|
524 |
"""Return a (hopefully) intelligently encoded review diff."""
|
|
525 |
preview_diff = self.preview_diff |
|
526 |
if preview_diff is None: |
|
527 |
return None |
|
528 |
try: |
|
529 |
diff = preview_diff.text.decode('utf-8') |
|
530 |
except UnicodeDecodeError: |
|
531 |
diff = preview_diff.text.decode('windows-1252', 'replace') |
|
532 |
# Strip off the trailing carriage returns.
|
|
533 |
return diff.rstrip('\n') |
|
534 |
||
535 |
@cachedproperty
|
|
536 |
def diff_oversized(self): |
|
13779.3.1
by Steve Kowalik
Consign StaticDiff and all that supported it to a watery grave. |
537 |
"""Return True if the preview_diff is over the configured size limit.
|
9691.6.10
by Tim Penhey
Make the diff load using the API rather than hitting the page. |
538 |
|
539 |
The diff can be over the limit in two ways. If the diff is oversized
|
|
540 |
in bytes it will be cut off at the Diff.text method. If the number of
|
|
541 |
lines is over the max_format_lines, then it is cut off at the fmt:diff
|
|
542 |
processing.
|
|
543 |
"""
|
|
13779.3.1
by Steve Kowalik
Consign StaticDiff and all that supported it to a watery grave. |
544 |
preview_diff = self.preview_diff |
545 |
if preview_diff is None: |
|
9691.6.10
by Tim Penhey
Make the diff load using the API rather than hitting the page. |
546 |
return False |
547 |
diff_text = self.preview_diff_text |
|
548 |
return diff_text.count('\n') >= config.diff.max_format_lines |
|
549 |
||
9848.1.13
by Paul Hummer
Fixed the status vocabulary to be generated based on what's enabled. |
550 |
|
7675.831.1
by Michael Nelson
Fixed failing code tests that were rendering the default comment template. |
551 |
class ICodeReviewNewRevisions(IComment): |
9984.4.11
by Tim Penhey
Include the revisions in the conversation. |
552 |
"""Marker interface used to register views for CodeReviewNewRevisions."""
|
553 |
||
554 |
||
9984.4.3
by Tim Penhey
Broken tests are there... |
555 |
class CodeReviewNewRevisions: |
556 |
"""Represents a logical grouping of revisions.
|
|
557 |
||
558 |
Each object instance represents a number of revisions scanned at a
|
|
559 |
particular time.
|
|
560 |
"""
|
|
7675.831.1
by Michael Nelson
Fixed failing code tests that were rendering the default comment template. |
561 |
implements(ICodeReviewNewRevisions) |
9984.4.3
by Tim Penhey
Broken tests are there... |
562 |
|
11486.5.37
by Aaron Bentley
Show incremental diffs as part of revision list. |
563 |
def __init__(self, revisions, date, branch, diff): |
9984.4.3
by Tim Penhey
Broken tests are there... |
564 |
self.revisions = revisions |
9984.4.9
by Tim Penhey
Test for groups. |
565 |
self.branch = branch |
9984.4.3
by Tim Penhey
Broken tests are there... |
566 |
self.has_body = False |
567 |
self.has_footer = True |
|
568 |
# The date attribute is used to sort the comments in the conversation.
|
|
569 |
self.date = date |
|
11486.5.37
by Aaron Bentley
Show incremental diffs as part of revision list. |
570 |
self.diff = diff |
9984.4.3
by Tim Penhey
Broken tests are there... |
571 |
|
7675.831.1
by Michael Nelson
Fixed failing code tests that were rendering the default comment template. |
572 |
# Other standard IComment attributes are not used.
|
573 |
self.extra_css_class = None |
|
574 |
self.comment_author = None |
|
575 |
self.body_text = None |
|
576 |
self.comment_date = None |
|
577 |
self.display_attachments = False |
|
578 |
||
9984.4.3
by Tim Penhey
Broken tests are there... |
579 |
|
9984.4.11
by Tim Penhey
Include the revisions in the conversation. |
580 |
class CodeReviewNewRevisionsView(LaunchpadView): |
581 |
"""The view for rendering the new revisions."""
|
|
582 |
||
583 |
@property
|
|
584 |
def codebrowse_url(self): |
|
585 |
"""Return the link to codebrowse for this branch."""
|
|
586 |
return self.context.branch.codebrowse_url() |
|
587 |
||
588 |
||
7675.293.1
by Aaron Bentley
Start work on review claiming. |
589 |
class BranchMergeProposalView(LaunchpadFormView, UnmergedRevisionsMixin, |
9848.1.13
by Paul Hummer
Fixed the status vocabulary to be generated based on what's enabled. |
590 |
BranchMergeProposalRevisionIdMixin, |
9691.6.10
by Tim Penhey
Make the diff load using the API rather than hitting the page. |
591 |
BranchMergeProposalStatusMixin, |
592 |
DiffRenderingMixin): |
|
5579.2.4
by Tim Penhey
UI works now. |
593 |
"""A basic view used for the index page."""
|
594 |
||
9476.1.3
by Tim Penhey
Breadcrumbs for branches, and fix bmp-index a bit. |
595 |
implements(IBranchMergeProposalActionMenu) |
596 |
||
7675.293.1
by Aaron Bentley
Start work on review claiming. |
597 |
schema = ClaimButton |
598 |
||
13302.8.3
by Andrew Bennetts
Generate correct links to fetch diffs from. |
599 |
def initialize(self): |
600 |
super(BranchMergeProposalView, self).initialize() |
|
601 |
cache = IJSONRequestCache(self.request) |
|
602 |
cache.objects.update({ |
|
603 |
'branch_diff_link': |
|
13333.15.33
by Gavin Panella
Subscribe to the BranchMergeProposal rather than the preview diff job. |
604 |
'https://%s/+loggerhead/%s/diff/' % ( |
605 |
config.launchpad.code_domain, |
|
606 |
self.context.source_branch.unique_name), |
|
13302.8.3
by Andrew Bennetts
Generate correct links to fetch diffs from. |
607 |
})
|
13333.15.48
by Gavin Panella
Only subscribe the page when the longpoll.merge_proposals.enabled feature flag is enabled. |
608 |
if getFeatureFlag("longpoll.merge_proposals.enabled"): |
13333.15.50
by Gavin Panella
Switch from new_mp_diff_event to merge_proposal_event_key. |
609 |
cache.objects['merge_proposal_event_key'] = ( |
610 |
subscribe(self.context).event_key) |
|
13302.8.3
by Andrew Bennetts
Generate correct links to fetch diffs from. |
611 |
|
7675.429.19
by Tim Penhey
Update the story for reassignment. |
612 |
@action('Claim', name='claim') |
7675.293.1
by Aaron Bentley
Start work on review claiming. |
613 |
def claim_action(self, action, data): |
7675.293.4
by Aaron Bentley
Start testing claim_action. |
614 |
"""Claim this proposal."""
|
7675.293.1
by Aaron Bentley
Start work on review claiming. |
615 |
request = self.context.getVoteReference(data['review_id']) |
7675.429.9
by Tim Penhey
Use the new claimReview method to actually get the review. |
616 |
if request is not None: |
12959.1.3
by Aaron Bentley
Review claim failures generate error notification, not oops. |
617 |
try: |
618 |
request.claimReview(self.user) |
|
619 |
except ClaimReviewFailed as e: |
|
620 |
self.request.response.addErrorNotification(unicode(e)) |
|
7675.293.1
by Aaron Bentley
Start work on review claiming. |
621 |
self.next_url = canonical_url(self.context) |
5579.2.4
by Tim Penhey
UI works now. |
622 |
|
623 |
@property
|
|
5608.11.26
by Aaron Bentley
Add page and link for creating CodeReviewMessage |
624 |
def comment_location(self): |
5608.15.9
by Aaron Bentley
Update docs |
625 |
"""Location of page for commenting on this proposal."""
|
5608.11.26
by Aaron Bentley
Add page and link for creating CodeReviewMessage |
626 |
return canonical_url(self.context, view_name='+comment') |
627 |
||
8624.1.3
by Tim Penhey
Working but needs clean up. |
628 |
@cachedproperty
|
629 |
def conversation(self): |
|
630 |
"""Return a conversation that is to be rendered."""
|
|
631 |
# Sort the comments by date order.
|
|
10272.1.1
by Aaron Bentley
Include comments from superseded proposals. |
632 |
merge_proposal = self.context |
11486.5.42
by Aaron Bentley
Optimize diff lookup. |
633 |
groups = list(merge_proposal.getRevisionsSinceReviewStart()) |
11486.2.7
by Aaron Bentley
Move revision selection to model code. |
634 |
source = DecoratedBranch(merge_proposal.source_branch) |
11486.5.37
by Aaron Bentley
Show incremental diffs as part of revision list. |
635 |
comments = [] |
11486.5.42
by Aaron Bentley
Optimize diff lookup. |
636 |
if getFeatureFlag('code.incremental_diffs.enabled'): |
637 |
ranges = [ |
|
638 |
(revisions[0].revision.getLefthandParent(), |
|
639 |
revisions[-1].revision) |
|
640 |
for revisions in groups] |
|
641 |
diffs = merge_proposal.getIncrementalDiffs(ranges) |
|
642 |
else: |
|
643 |
diffs = [None] * len(groups) |
|
644 |
for revisions, diff in zip(groups, diffs): |
|
11486.5.38
by Aaron Bentley
Clean up old approach. |
645 |
newrevs = CodeReviewNewRevisions( |
646 |
revisions, revisions[-1].revision.date_created, source, diff) |
|
11486.5.37
by Aaron Bentley
Show incremental diffs as part of revision list. |
647 |
comments.append(newrevs) |
10272.1.1
by Aaron Bentley
Include comments from superseded proposals. |
648 |
while merge_proposal is not None: |
10272.1.2
by Aaron Bentley
Distinguish betwen comments on this proposal and superseded ones. |
649 |
from_superseded = merge_proposal != self.context |
10272.1.1
by Aaron Bentley
Include comments from superseded proposals. |
650 |
comments.extend( |
10272.1.2
by Aaron Bentley
Distinguish betwen comments on this proposal and superseded ones. |
651 |
CodeReviewDisplayComment(comment, from_superseded) |
10272.1.1
by Aaron Bentley
Include comments from superseded proposals. |
652 |
for comment in merge_proposal.all_comments) |
653 |
merge_proposal = merge_proposal.supersedes |
|
8624.1.3
by Tim Penhey
Working but needs clean up. |
654 |
comments = sorted(comments, key=operator.attrgetter('date')) |
655 |
return CodeReviewConversation(comments) |
|
656 |
||
5608.11.41
by Aaron Bentley
Add nearly-threaded display of message subjects |
657 |
@property
|
658 |
def comments(self): |
|
5608.11.51
by Aaron Bentley
Cleanup |
659 |
"""Return comments associated with this proposal, plus styling info.
|
660 |
||
661 |
Comments are in threaded order, and the style indicates indenting
|
|
662 |
for use with threads.
|
|
663 |
"""
|
|
5608.11.41
by Aaron Bentley
Add nearly-threaded display of message subjects |
664 |
message_to_comment = {} |
665 |
messages = [] |
|
6334.6.36
by Aaron Bentley
Rename code review messages to code review comments |
666 |
for comment in self.context.all_comments: |
5608.11.41
by Aaron Bentley
Add nearly-threaded display of message subjects |
667 |
message_to_comment[comment.message] = comment |
668 |
messages.append(comment.message) |
|
5608.11.53
by Aaron Bentley
Move message-threading functionality onto MessageSet |
669 |
message_set = getUtility(IMessageSet) |
670 |
threads = message_set.threadMessages(messages) |
|
5608.11.41
by Aaron Bentley
Add nearly-threaded display of message subjects |
671 |
result = [] |
5608.11.53
by Aaron Bentley
Move message-threading functionality onto MessageSet |
672 |
for depth, message in message_set.flattenThreads(threads): |
5608.11.41
by Aaron Bentley
Add nearly-threaded display of message subjects |
673 |
comment = message_to_comment[message] |
5608.11.42
by Aaron Bentley
Get actual threading working |
674 |
style = 'margin-left: %dem;' % (2 * depth) |
5608.11.41
by Aaron Bentley
Add nearly-threaded display of message subjects |
675 |
result.append(dict(style=style, comment=comment)) |
676 |
return result |
|
677 |
||
10054.23.1
by Aaron Bentley
Merged stable into jobstatus. |
678 |
@property
|
14412.3.6
by mbp at canonical
Better page label on merge proposals |
679 |
def label(self): |
680 |
return "Merge %s into %s" % ( |
|
681 |
self.context.source_branch.bzr_identity, |
|
682 |
self.context.target_branch.bzr_identity) |
|
683 |
||
684 |
@property
|
|
10054.23.1
by Aaron Bentley
Merged stable into jobstatus. |
685 |
def pending_diff(self): |
12112.2.1
by Aaron Bentley
Merge proposal diff update message shown when source updated. |
686 |
return ( |
13333.15.33
by Gavin Panella
Subscribe to the BranchMergeProposal rather than the preview diff job. |
687 |
self.context.next_preview_diff_job is not None or |
12112.2.1
by Aaron Bentley
Merge proposal diff update message shown when source updated. |
688 |
self.context.source_branch.pending_writes) |
10054.23.1
by Aaron Bentley
Merged stable into jobstatus. |
689 |
|
7675.292.6
by Tim Penhey
Let the users know if the diff has been truncated. |
690 |
@cachedproperty
|
9373.3.2
by Aaron Bentley
Prefer preview diff, fall back to review diff, cleanup. |
691 |
def preview_diff(self): |
692 |
"""Return a `Diff` of the preview.
|
|
693 |
||
694 |
If no preview is available, try using the review diff.
|
|
695 |
"""
|
|
696 |
if self.context.preview_diff is not None: |
|
697 |
return self.context.preview_diff |
|
698 |
return None |
|
699 |
||
7623.1.3
by Paul Hummer
Added review_diff method to the BMP view |
700 |
@property
|
6757.2.1
by Paul Hummer
Added support for displaying the bug and spec links in the branch merge |
701 |
def has_bug_or_spec(self): |
702 |
"""Return whether or not the merge proposal has a linked bug or spec.
|
|
703 |
"""
|
|
704 |
branch = self.context.source_branch |
|
12505.6.1
by Ian Booth
Remove DecoratedBug and refactor mp linked_bugs to use branch.getRelatedBugTasks |
705 |
return self.linked_bugtasks or branch.spec_links |
6757.2.1
by Paul Hummer
Added support for displaying the bug and spec links in the branch merge |
706 |
|
12457.2.8
by Robert Collins
Fix branch merge proposals which use a macro now wanting bugtasks. |
707 |
@cachedproperty
|
708 |
def linked_bugtasks(self): |
|
12505.6.1
by Ian Booth
Remove DecoratedBug and refactor mp linked_bugs to use branch.getRelatedBugTasks |
709 |
"""Return BugTasks linked to the source branch."""
|
12505.6.7
by Ian Booth
Test fixes |
710 |
return self.context.getRelatedBugTasks(self.user) |
12457.2.8
by Robert Collins
Fix branch merge proposals which use a macro now wanting bugtasks. |
711 |
|
9737.2.2
by Tim Penhey
Add an inline editor for commit message. |
712 |
@property
|
12268.3.8
by Tim Penhey
Refactor the TextAreaEditorWidget so it doesn't need extra HTML code in the page template. |
713 |
def edit_description_link_class(self): |
714 |
if self.context.description: |
|
715 |
return "unseen" |
|
716 |
else: |
|
717 |
return "" |
|
718 |
||
719 |
@property
|
|
7675.548.2
by Tim Penhey
Update for the description field. |
720 |
def description_html(self): |
721 |
"""The description as widget HTML."""
|
|
12268.3.19
by Tim Penhey
Reorder the title parameter to match the call sites. |
722 |
mp = self.context |
723 |
description = IBranchMergeProposal['description'] |
|
724 |
title = "Description of the Change" |
|
7675.548.2
by Tim Penhey
Update for the description field. |
725 |
return TextAreaEditorWidget( |
12268.3.19
by Tim Penhey
Reorder the title parameter to match the call sites. |
726 |
mp, description, title, edit_view='+edit-description') |
12268.3.8
by Tim Penhey
Refactor the TextAreaEditorWidget so it doesn't need extra HTML code in the page template. |
727 |
|
728 |
@property
|
|
729 |
def edit_commit_message_link_class(self): |
|
730 |
if self.context.commit_message: |
|
731 |
return "unseen" |
|
732 |
else: |
|
733 |
return "" |
|
7675.548.2
by Tim Penhey
Update for the description field. |
734 |
|
735 |
@property
|
|
9737.2.2
by Tim Penhey
Add an inline editor for commit message. |
736 |
def commit_message_html(self): |
737 |
"""The commit message as widget HTML."""
|
|
12268.3.29
by Tim Penhey
A single trailing comma can be so distructive. |
738 |
mp = self.context |
12268.3.19
by Tim Penhey
Reorder the title parameter to match the call sites. |
739 |
commit_message = IBranchMergeProposal['commit_message'] |
740 |
title = "Commit Message" |
|
9737.2.2
by Tim Penhey
Add an inline editor for commit message. |
741 |
return TextAreaEditorWidget( |
12268.3.19
by Tim Penhey
Reorder the title parameter to match the call sites. |
742 |
mp, commit_message, title, edit_view='+edit-commit-message') |
9737.2.2
by Tim Penhey
Add an inline editor for commit message. |
743 |
|
9848.1.5
by Paul Hummer
Got the widget working with the API. |
744 |
@property
|
745 |
def status_config(self): |
|
746 |
"""The config to configure the ChoiceSource JS widget."""
|
|
747 |
return simplejson.dumps({ |
|
748 |
'status_widget_items': vocabulary_to_choice_edit_items( |
|
9848.1.13
by Paul Hummer
Fixed the status vocabulary to be generated based on what's enabled. |
749 |
self._createStatusVocabulary(), |
9848.1.5
by Paul Hummer
Got the widget working with the API. |
750 |
css_class_prefix='mergestatus'), |
751 |
'status_value': self.context.queue_status.title, |
|
7675.508.1
by Tim Penhey
Send the revision id as well. |
752 |
'source_revid': self.context.source_branch.last_scanned_id, |
9848.1.5
by Paul Hummer
Got the widget working with the API. |
753 |
'user_can_edit_status': check_permission( |
754 |
'launchpad.Edit', self.context), |
|
755 |
})
|
|
756 |
||
5579.2.4
by Tim Penhey
UI works now. |
757 |
|
6438.2.3
by Tim Penhey
Add the tables for reviews done, and requested reviews. |
758 |
class DecoratedCodeReviewVoteReference: |
759 |
"""Provide a code review vote that knows if it is important or not."""
|
|
760 |
||
7465.5.1
by Gary Poster
integrate lazr.config and lazr.delegates |
761 |
delegates(ICodeReviewVoteReference) |
6438.2.3
by Tim Penhey
Add the tables for reviews done, and requested reviews. |
762 |
|
7055.6.8
by Tim Penhey
Merge the two tables showing pending and completed reviews, and add nice colours everywhere. |
763 |
status_text_map = { |
7055.6.27
by Paul Hummer
Referenced .title in status text map |
764 |
CodeReviewVote.DISAPPROVE: CodeReviewVote.DISAPPROVE.title, |
765 |
CodeReviewVote.APPROVE: CodeReviewVote.APPROVE.title, |
|
766 |
CodeReviewVote.ABSTAIN: CodeReviewVote.ABSTAIN.title, |
|
8486.1.3
by Michael Hudson
fix |
767 |
CodeReviewVote.NEEDS_INFO: CodeReviewVote.NEEDS_INFO.title, |
7055.6.12
by Tim Penhey
Add extra vote types, and format nicely the listing. |
768 |
CodeReviewVote.NEEDS_FIXING: CodeReviewVote.NEEDS_FIXING.title, |
769 |
CodeReviewVote.RESUBMIT: CodeReviewVote.RESUBMIT.title, |
|
7055.6.8
by Tim Penhey
Merge the two tables showing pending and completed reviews, and add nice colours everywhere. |
770 |
}
|
771 |
||
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
772 |
def __init__(self, context, user, users_vote): |
6438.2.3
by Tim Penhey
Add the tables for reviews done, and requested reviews. |
773 |
self.context = context |
9461.9.1
by Aaron Bentley
Allow voting and reviewing when proposal isn't mergeable. |
774 |
self.can_change_review = (user == context.reviewer) |
7055.6.14
by Tim Penhey
Fix the tests. |
775 |
if user is None: |
7055.9.1
by Tim Penhey
Merge in table munging updates and resolve conflicts. |
776 |
self.user_can_review = False |
6438.2.7
by Tim Penhey
Set the title on the star. |
777 |
else: |
7055.6.24
by Tim Penhey
More review updates. |
778 |
# The user cannot review for a requested team review if the user
|
779 |
# has already reviewed this proposal.
|
|
9461.9.1
by Aaron Bentley
Allow voting and reviewing when proposal isn't mergeable. |
780 |
self.user_can_review = (self.can_change_review or |
781 |
(user.inTeam(context.reviewer) and (users_vote is None))) |
|
7675.293.5
by Aaron Bentley
Restrict display of claim button. |
782 |
if context.reviewer == user: |
783 |
self.user_can_claim = False |
|
784 |
else: |
|
785 |
self.user_can_claim = self.user_can_review |
|
7675.293.8
by Aaron Bentley
Allow reassigning code review. |
786 |
if user in (context.reviewer, context.registrant): |
787 |
self.user_can_reassign = True |
|
788 |
else: |
|
789 |
self.user_can_reassign = False |
|
6438.2.3
by Tim Penhey
Add the tables for reviews done, and requested reviews. |
790 |
|
14509.2.8
by Ian Booth
Undo move of Person.inTeam() to IPersonLimitedView and refactor view that relied on it |
791 |
@cachedproperty
|
792 |
def trusted(self): |
|
793 |
""" Is the person a trusted reviewer."""
|
|
794 |
proposal = self.context.branch_merge_proposal |
|
795 |
return proposal.target_branch.isPersonTrustedReviewer( |
|
796 |
self.context.reviewer) |
|
797 |
||
6438.2.3
by Tim Penhey
Add the tables for reviews done, and requested reviews. |
798 |
@property
|
7055.8.7
by Tim Penhey
Updates following review. |
799 |
def show_date_requested(self): |
800 |
"""Show the requested date if the reviewer is not the requester."""
|
|
801 |
return self.context.registrant != self.context.reviewer |
|
802 |
||
803 |
@property
|
|
7055.6.8
by Tim Penhey
Merge the two tables showing pending and completed reviews, and add nice colours everywhere. |
804 |
def date_requested(self): |
805 |
"""When the review was requested or None."""
|
|
7055.8.7
by Tim Penhey
Updates following review. |
806 |
return self.context.date_created |
7055.6.8
by Tim Penhey
Merge the two tables showing pending and completed reviews, and add nice colours everywhere. |
807 |
|
808 |
@property
|
|
7310.1.1
by Tim Penhey
Claiming a team review without a review type didn't work. |
809 |
def review_type_str(self): |
810 |
"""We want '' not 'None' if no type set."""
|
|
811 |
if self.context.review_type is None: |
|
812 |
return '' |
|
813 |
return self.context.review_type |
|
814 |
||
815 |
@property
|
|
6438.2.3
by Tim Penhey
Add the tables for reviews done, and requested reviews. |
816 |
def date_of_comment(self): |
817 |
"""The date of the comment, not the date_created of the vote."""
|
|
818 |
return self.context.comment.message.datecreated |
|
819 |
||
7055.6.8
by Tim Penhey
Merge the two tables showing pending and completed reviews, and add nice colours everywhere. |
820 |
@property
|
821 |
def status_text(self): |
|
822 |
"""The text shown in the table of the users vote."""
|
|
823 |
return self.status_text_map[self.context.comment.vote] |
|
824 |
||
7675.293.19
by Aaron Bentley
Cleanup |
825 |
|
6438.2.3
by Tim Penhey
Add the tables for reviews done, and requested reviews. |
826 |
class BranchMergeProposalVoteView(LaunchpadView): |
827 |
"""The view used for the tables of votes and requested reviews."""
|
|
828 |
||
7055.6.8
by Tim Penhey
Merge the two tables showing pending and completed reviews, and add nice colours everywhere. |
829 |
@property
|
830 |
def show_table(self): |
|
831 |
"""Should the reviewer table be shown at all?
|
|
832 |
||
7055.8.7
by Tim Penhey
Updates following review. |
833 |
We want to show the table when there is something for the user to do
|
834 |
with it. If the user can request a review, or is a reviewer with
|
|
835 |
reviews to do, then show the table.
|
|
7055.6.8
by Tim Penhey
Merge the two tables showing pending and completed reviews, and add nice colours everywhere. |
836 |
"""
|
7055.8.7
by Tim Penhey
Updates following review. |
837 |
# The user can request a review if the user has edit permissions, and
|
838 |
# the branch is not in a final state. We want to show the table as
|
|
839 |
# the menu link is now shown in the table itself.
|
|
7055.6.8
by Tim Penhey
Merge the two tables showing pending and completed reviews, and add nice colours everywhere. |
840 |
can_request_review = ( |
841 |
check_permission('launchpad.Edit', self.context) and |
|
842 |
self.context.isMergable()) |
|
843 |
||
7055.8.7
by Tim Penhey
Updates following review. |
844 |
# Show the table if there are review to show, or the user can review,
|
845 |
# or if the user can request a review.
|
|
9461.9.2
by Aaron Bentley
Remove obsolete show_user_review_link |
846 |
return (len(self.reviews) > 0 or can_request_review) |
7055.6.8
by Tim Penhey
Merge the two tables showing pending and completed reviews, and add nice colours everywhere. |
847 |
|
6438.2.3
by Tim Penhey
Add the tables for reviews done, and requested reviews. |
848 |
@cachedproperty
|
849 |
def reviews(self): |
|
850 |
"""Return the decorated votes for the proposal."""
|
|
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
851 |
users_vote = self.context.getUsersVoteReference(self.user) |
852 |
return [DecoratedCodeReviewVoteReference(vote, self.user, users_vote) |
|
14509.2.3
by Ian Booth
Allow private teams to review branches |
853 |
for vote in self.context.votes |
854 |
if check_permission('launchpad.LimitedView', vote.reviewer)] |
|
6438.2.3
by Tim Penhey
Add the tables for reviews done, and requested reviews. |
855 |
|
7055.6.8
by Tim Penhey
Merge the two tables showing pending and completed reviews, and add nice colours everywhere. |
856 |
@cachedproperty
|
6438.2.3
by Tim Penhey
Add the tables for reviews done, and requested reviews. |
857 |
def current_reviews(self): |
858 |
"""The current votes ordered by vote then date."""
|
|
859 |
# We want the reviews in a specific order.
|
|
860 |
# Disapprovals first, then approvals, then abstentions.
|
|
7055.6.12
by Tim Penhey
Add extra vote types, and format nicely the listing. |
861 |
reviews = [review for review in self.reviews |
862 |
if review.comment is not None] |
|
863 |
return sorted(reviews, key=operator.attrgetter('date_of_comment'), |
|
864 |
reverse=True) |
|
6438.2.3
by Tim Penhey
Add the tables for reviews done, and requested reviews. |
865 |
|
7055.6.8
by Tim Penhey
Merge the two tables showing pending and completed reviews, and add nice colours everywhere. |
866 |
@cachedproperty
|
6438.2.3
by Tim Penhey
Add the tables for reviews done, and requested reviews. |
867 |
def requested_reviews(self): |
868 |
"""Reviews requested but not yet done."""
|
|
869 |
reviews = [review for review in self.reviews |
|
870 |
if review.comment is None] |
|
871 |
# Now sort so the most recently created is first.
|
|
872 |
return sorted(reviews, key=operator.attrgetter('date_created'), |
|
873 |
reverse=True) |
|
874 |
||
7055.6.8
by Tim Penhey
Merge the two tables showing pending and completed reviews, and add nice colours everywhere. |
875 |
|
6438.3.1
by Aaron Bentley
Dirty implementation of mailing candidate reviewers |
876 |
class IReviewRequest(Interface): |
6438.3.15
by Aaron Bentley
Cleanup |
877 |
"""Schema for requesting a review."""
|
6438.3.1
by Aaron Bentley
Dirty implementation of mailing candidate reviewers |
878 |
|
7055.6.16
by Tim Penhey
vote tag and field name fixes. |
879 |
reviewer = copy_field(ICodeReviewVoteReference['reviewer']) |
6438.3.1
by Aaron Bentley
Dirty implementation of mailing candidate reviewers |
880 |
|
9656.1.6
by Nathan Handler
Make changes requested by Michael Hudson (mwhudson) |
881 |
review_type = copy_field( |
11019.3.1
by Tim Penhey
Extract the DecoratedBug and DecorateBranch out of the browser/branch module and into its own. Use a DecoratedBranch for the new revisions. |
882 |
ICodeReviewVoteReference['review_type'], |
9656.1.6
by Nathan Handler
Make changes requested by Michael Hudson (mwhudson) |
883 |
description=u'Lowercase keywords describing the type of review you ' |
884 |
'would like to be performed.') |
|
6438.3.1
by Aaron Bentley
Dirty implementation of mailing candidate reviewers |
885 |
|
886 |
||
5579.2.4
by Tim Penhey
UI works now. |
887 |
class BranchMergeProposalRequestReviewView(LaunchpadEditFormView): |
888 |
"""The view used to request a review of the merge proposal."""
|
|
889 |
||
6438.3.1
by Aaron Bentley
Dirty implementation of mailing candidate reviewers |
890 |
schema = IReviewRequest |
9129.1.11
by Tim Penhey
Oops, page_title not heading. |
891 |
page_title = label = "Request review" |
5579.2.4
by Tim Penhey
UI works now. |
892 |
|
893 |
@property
|
|
6438.3.1
by Aaron Bentley
Dirty implementation of mailing candidate reviewers |
894 |
def initial_values(self): |
6438.3.15
by Aaron Bentley
Cleanup |
895 |
"""Force the non-BMP values to None."""
|
7055.6.16
by Tim Penhey
vote tag and field name fixes. |
896 |
return {'reviewer': None, 'review_type': None} |
6438.3.1
by Aaron Bentley
Dirty implementation of mailing candidate reviewers |
897 |
|
898 |
@property
|
|
899 |
def adapters(self): |
|
6438.3.15
by Aaron Bentley
Cleanup |
900 |
"""Force IReviewRequest handling for BranchMergeProposal."""
|
6438.3.1
by Aaron Bentley
Dirty implementation of mailing candidate reviewers |
901 |
return {IReviewRequest: self.context} |
902 |
||
903 |
@property
|
|
6438.3.9
by Aaron Bentley
Support requesting additional reviewers |
904 |
def is_needs_review(self): |
6438.3.15
by Aaron Bentley
Cleanup |
905 |
"""Return True if queue status is NEEDS_REVIEW."""
|
6438.3.9
by Aaron Bentley
Support requesting additional reviewers |
906 |
return (self.context.queue_status == |
907 |
BranchMergeProposalStatus.NEEDS_REVIEW) |
|
908 |
||
909 |
@property
|
|
5579.2.4
by Tim Penhey
UI works now. |
910 |
def next_url(self): |
911 |
return canonical_url(self.context) |
|
912 |
||
6618.2.1
by Paul Hummer
Adds cancel_url, fixes tests |
913 |
cancel_url = next_url |
6438.3.24
by Aaron Bentley
Updates for LP2.0 |
914 |
|
6677.1.3
by Jonathan Lange
Only access IEmailAddress.email once. |
915 |
def requestReview(self, candidate, review_type): |
6677.1.4
by Jonathan Lange
Respond to review comments. |
916 |
"""Request a `review_type` review from `candidate` and email them."""
|
11019.3.1
by Tim Penhey
Extract the DecoratedBug and DecorateBranch out of the browser/branch module and into its own. Use a DecoratedBranch for the new revisions. |
917 |
self.context.nominateReviewer(candidate, self.user, review_type) |
6677.1.3
by Jonathan Lange
Only access IEmailAddress.email once. |
918 |
|
7055.6.16
by Tim Penhey
vote tag and field name fixes. |
919 |
@action('Request Review', name='review') |
6438.3.1
by Aaron Bentley
Dirty implementation of mailing candidate reviewers |
920 |
@notify
|
5579.2.4
by Tim Penhey
UI works now. |
921 |
def review_action(self, action, data): |
6438.3.15
by Aaron Bentley
Cleanup |
922 |
"""Set 'Needs review' status, nominate reviewers, send emails."""
|
5579.2.4
by Tim Penhey
UI works now. |
923 |
self.context.requestReview() |
7055.6.16
by Tim Penhey
vote tag and field name fixes. |
924 |
candidate = data.pop('reviewer', None) |
6438.3.1
by Aaron Bentley
Dirty implementation of mailing candidate reviewers |
925 |
review_type = data.pop('review_type', None) |
926 |
if candidate is not None: |
|
6677.1.3
by Jonathan Lange
Only access IEmailAddress.email once. |
927 |
self.requestReview(candidate, review_type) |
5579.2.4
by Tim Penhey
UI works now. |
928 |
|
929 |
def validate(self, data): |
|
930 |
"""Ensure that the proposal is in an appropriate state."""
|
|
7055.6.8
by Tim Penhey
Merge the two tables showing pending and completed reviews, and add nice colours everywhere. |
931 |
if not self.context.isMergable(): |
5579.2.4
by Tim Penhey
UI works now. |
932 |
self.addError("The merge proposal is not an a valid state to " |
933 |
"mark as 'Needs review'.") |
|
934 |
||
935 |
||
936 |
class ReviewForm(Interface): |
|
937 |
"""A simple interface to define the revision number field."""
|
|
938 |
||
939 |
revision_number = Int( |
|
940 |
title=_("Reviewed Revision"), required=True, |
|
941 |
description=_("The revision number on the source branch which " |
|
942 |
"has been reviewed.")) |
|
943 |
||
944 |
whiteboard = Whiteboard( |
|
945 |
title=_('Whiteboard'), required=False, |
|
946 |
description=_('Notes about the merge.')) |
|
947 |
||
948 |
||
949 |
class MergeProposalEditView(LaunchpadEditFormView, |
|
950 |
BranchMergeProposalRevisionIdMixin): |
|
951 |
"""A base class for merge proposal edit views."""
|
|
5280.4.3
by Tim Penhey
Workflow works nicely, resisting hard gold plating. |
952 |
|
6618.2.1
by Paul Hummer
Adds cancel_url, fixes tests |
953 |
def initialize(self): |
6618.2.4
by Paul Hummer
Adds merge conditional coding style change |
954 |
# Record next_url and cancel url now
|
6618.2.1
by Paul Hummer
Adds cancel_url, fixes tests |
955 |
self.next_url = canonical_url(self.context) |
956 |
self.cancel_url = self.next_url |
|
957 |
super(MergeProposalEditView, self).initialize() |
|
958 |
||
5763.1.6
by Tim Penhey
Some view refactoring. |
959 |
def _getRevisionId(self, data): |
960 |
"""Translate the revision number that was entered into a revision id.
|
|
961 |
||
962 |
If the branch is REMOTE we won't have any scanned revisions to compare
|
|
963 |
against, so store the raw integer revision number as the revision id.
|
|
5280.4.3
by Tim Penhey
Workflow works nicely, resisting hard gold plating. |
964 |
"""
|
965 |
source_branch = self.context.source_branch |
|
5763.1.6
by Tim Penhey
Some view refactoring. |
966 |
# Get the revision number out of the data.
|
5280.4.3
by Tim Penhey
Workflow works nicely, resisting hard gold plating. |
967 |
if source_branch.branch_type == BranchType.REMOTE: |
6623.1.1
by Tim Penhey
Stringify the revision number for remote branches. |
968 |
return str(data.pop('revision_number')) |
5280.4.3
by Tim Penhey
Workflow works nicely, resisting hard gold plating. |
969 |
else: |
5763.1.6
by Tim Penhey
Some view refactoring. |
970 |
branch_revision = source_branch.getBranchRevision( |
6736.3.5
by Tim Penhey
Clean up the Branch.getBranchRevision method. |
971 |
sequence=data.pop('revision_number')) |
5763.1.6
by Tim Penhey
Some view refactoring. |
972 |
return branch_revision.revision.revision_id |
973 |
||
5579.2.1
by Tim Penhey
Some queue management |
974 |
def _validateRevisionNumber(self, data, revision_name): |
975 |
"""Check to make sure that the revision number entered is valid."""
|
|
5763.1.6
by Tim Penhey
Some view refactoring. |
976 |
rev_no = data.get('revision_number') |
977 |
if rev_no is not None: |
|
978 |
try: |
|
979 |
rev_no = int(rev_no) |
|
980 |
except ValueError: |
|
981 |
self.setFieldError( |
|
982 |
'revision_number', |
|
5579.2.1
by Tim Penhey
Some queue management |
983 |
'The %s revision must be a positive number.' |
984 |
% revision_name) |
|
5280.4.3
by Tim Penhey
Workflow works nicely, resisting hard gold plating. |
985 |
else: |
5763.1.6
by Tim Penhey
Some view refactoring. |
986 |
if rev_no < 1: |
987 |
self.setFieldError( |
|
988 |
'revision_number', |
|
5579.2.1
by Tim Penhey
Some queue management |
989 |
'The %s revision must be a positive number.' |
990 |
% revision_name) |
|
5763.1.6
by Tim Penhey
Some view refactoring. |
991 |
# Accept any positive integer for a REMOTE branch.
|
992 |
source_branch = self.context.source_branch |
|
993 |
if (source_branch.branch_type != BranchType.REMOTE and |
|
994 |
rev_no > source_branch.revision_count): |
|
995 |
self.setFieldError( |
|
996 |
'revision_number', |
|
5579.2.1
by Tim Penhey
Some queue management |
997 |
'The %s revision cannot be larger than the ' |
998 |
'tip revision of the source branch.'
|
|
999 |
% revision_name) |
|
1000 |
||
1001 |
||
11812.2.3
by Aaron Bentley
Add break link option to resubmit. |
1002 |
class ResubmitSchema(IBranchMergeProposal): |
1003 |
||
1004 |
break_link = Bool( |
|
11812.2.11
by Aaron Bentley
Change text for breaking link. |
1005 |
title=u'Start afresh', |
1006 |
description=( |
|
1007 |
u'Do not show old conversation and do not link to superseded' |
|
1008 |
' proposal.'), |
|
11812.2.3
by Aaron Bentley
Add break link option to resubmit. |
1009 |
default=False,) |
1010 |
||
1011 |
||
11812.2.4
by Aaron Bentley
Switch to LaunchpadFormView to avoid overriding render_context. |
1012 |
class BranchMergeProposalResubmitView(LaunchpadFormView, |
5579.2.4
by Tim Penhey
UI works now. |
1013 |
UnmergedRevisionsMixin): |
1014 |
"""The view to resubmit a proposal to merge."""
|
|
1015 |
||
11812.2.3
by Aaron Bentley
Add break link option to resubmit. |
1016 |
schema = ResubmitSchema |
11812.2.2
by Aaron Bentley
Provide new resubmit UI. |
1017 |
for_input = True |
9129.1.11
by Tim Penhey
Oops, page_title not heading. |
1018 |
page_title = label = "Resubmit proposal to merge" |
11812.2.2
by Aaron Bentley
Provide new resubmit UI. |
1019 |
field_names = [ |
11812.2.10
by Aaron Bentley
Updates from review. |
1020 |
'source_branch', |
1021 |
'target_branch', |
|
1022 |
'prerequisite_branch', |
|
1023 |
'description', |
|
1024 |
'break_link', |
|
11812.2.2
by Aaron Bentley
Provide new resubmit UI. |
1025 |
]
|
11812.2.10
by Aaron Bentley
Updates from review. |
1026 |
|
1027 |
def initialize(self): |
|
1028 |
self.cancel_url = canonical_url(self.context) |
|
1029 |
super(BranchMergeProposalResubmitView, self).initialize() |
|
1030 |
||
11812.2.3
by Aaron Bentley
Add break link option to resubmit. |
1031 |
@property
|
1032 |
def initial_values(self): |
|
1033 |
UNSET = object() |
|
11812.2.10
by Aaron Bentley
Updates from review. |
1034 |
items = ((key, getattr(self.context, key, UNSET)) for key in |
11812.2.3
by Aaron Bentley
Add break link option to resubmit. |
1035 |
self.field_names if key != 'break_link') |
11812.2.10
by Aaron Bentley
Updates from review. |
1036 |
return dict(item for item in items if item[1] is not UNSET) |
5579.2.4
by Tim Penhey
UI works now. |
1037 |
|
1038 |
@action('Resubmit', name='resubmit') |
|
1039 |
def resubmit_action(self, action, data): |
|
1040 |
"""Resubmit this proposal."""
|
|
13278.2.4
by Aaron Bentley
Handle BranchMergeProposalExists as a user error. |
1041 |
try: |
1042 |
proposal = self.context.resubmit( |
|
1043 |
self.user, data['source_branch'], data['target_branch'], |
|
1044 |
data['prerequisite_branch'], data['description'], |
|
1045 |
data['break_link']) |
|
1046 |
except BranchMergeProposalExists as e: |
|
1047 |
message = structured( |
|
13278.2.7
by Aaron Bentley
Tweak error and test. |
1048 |
'Cannot resubmit because <a href="%(url)s">a similar merge' |
13278.2.4
by Aaron Bentley
Handle BranchMergeProposalExists as a user error. |
1049 |
' proposal</a> is already active.', |
1050 |
url=canonical_url(e.existing_proposal)) |
|
1051 |
self.request.response.addErrorNotification(message) |
|
1052 |
self.next_url = canonical_url(self.context) |
|
1053 |
return None |
|
13618.3.1
by Aaron Bentley
InvalidMergeProposal is handled as a user error. |
1054 |
except InvalidBranchMergeProposal as e: |
1055 |
self.addError(str(e)) |
|
1056 |
return None |
|
7055.6.17
by Tim Penhey
Fixed resubmit and link visibility. |
1057 |
self.next_url = canonical_url(proposal) |
11812.2.2
by Aaron Bentley
Provide new resubmit UI. |
1058 |
return proposal |
5579.2.4
by Tim Penhey
UI works now. |
1059 |
|
1060 |
||
5280.4.3
by Tim Penhey
Workflow works nicely, resisting hard gold plating. |
1061 |
class BranchMergeProposalEditView(MergeProposalEditView): |
5280.4.24
by Tim Penhey
First cut of changes following review. |
1062 |
"""The view to control the editing of merge proposals."""
|
4414.5.13
by Tim Penhey
Still work in progress |
1063 |
schema = IBranchMergeProposal |
9129.1.11
by Tim Penhey
Oops, page_title not heading. |
1064 |
page_title = label = "Edit branch merge proposal" |
6699.2.2
by Paul Hummer
Adds commit_message field |
1065 |
field_names = ["commit_message", "whiteboard"] |
4414.5.13
by Tim Penhey
Still work in progress |
1066 |
|
5280.4.24
by Tim Penhey
First cut of changes following review. |
1067 |
@action('Update', name='update') |
1068 |
def update_action(self, action, data): |
|
1069 |
"""Update the whiteboard and go back to the source branch."""
|
|
1070 |
self.updateContextFromData(data) |
|
1071 |
||
1072 |
||
7954.3.1
by Paul Hummer
Added BranchMergeProposalCommitMessageEditView |
1073 |
class BranchMergeProposalCommitMessageEditView(MergeProposalEditView): |
1074 |
"""The view to edit the commit message of merge proposals."""
|
|
1075 |
||
7954.3.2
by Paul Hummer
Added commit message editing view stubs |
1076 |
schema = IBranchMergeProposal |
1077 |
label = "Edit merge proposal commit message" |
|
9084.3.6
by Tim Penhey
Remove the commit message template in favour of generic-edit. |
1078 |
page_title = label |
7954.3.2
by Paul Hummer
Added commit message editing view stubs |
1079 |
field_names = ['commit_message'] |
1080 |
||
1081 |
@action('Update', name='update') |
|
1082 |
def update_action(self, action, data): |
|
1083 |
"""Update the commit message."""
|
|
7954.3.4
by Paul Hummer
Got an end-to-end working change for commit message |
1084 |
self.updateContextFromData(data) |
7954.3.2
by Paul Hummer
Added commit message editing view stubs |
1085 |
|
7954.3.1
by Paul Hummer
Added BranchMergeProposalCommitMessageEditView |
1086 |
|
7675.548.2
by Tim Penhey
Update for the description field. |
1087 |
class BranchMergeProposalDescriptionEditView(MergeProposalEditView): |
1088 |
"""The view to edit the description of merge proposals."""
|
|
1089 |
||
1090 |
schema = IBranchMergeProposal |
|
1091 |
label = "Edit merge proposal description" |
|
1092 |
page_title = label |
|
1093 |
field_names = ['description'] |
|
1094 |
||
1095 |
@action('Update', name='update') |
|
1096 |
def update_action(self, action, data): |
|
1097 |
"""Update the commit message."""
|
|
1098 |
self.updateContextFromData(data) |
|
1099 |
||
1100 |
||
5280.4.24
by Tim Penhey
First cut of changes following review. |
1101 |
class BranchMergeProposalDeleteView(MergeProposalEditView): |
1102 |
"""The view to control the deletion of merge proposals."""
|
|
1103 |
schema = IBranchMergeProposal |
|
1104 |
field_names = [] |
|
9129.1.11
by Tim Penhey
Oops, page_title not heading. |
1105 |
page_title = label = 'Delete proposal to merge branch' |
5280.4.24
by Tim Penhey
First cut of changes following review. |
1106 |
|
4414.5.13
by Tim Penhey
Still work in progress |
1107 |
def initialize(self): |
4414.5.14
by Tim Penhey
SOP and view work |
1108 |
# Store the source branch for `next_url` to make sure that
|
1109 |
# it is available in the situation where the merge proposal
|
|
1110 |
# is deleted.
|
|
4414.5.13
by Tim Penhey
Still work in progress |
1111 |
self.source_branch = self.context.source_branch |
5280.4.24
by Tim Penhey
First cut of changes following review. |
1112 |
super(BranchMergeProposalDeleteView, self).initialize() |
4414.5.13
by Tim Penhey
Still work in progress |
1113 |
|
5280.4.14
by Tim Penhey
More ui tweaks. |
1114 |
@action('Delete proposal', name='delete') |
4414.5.13
by Tim Penhey
Still work in progress |
1115 |
def delete_action(self, action, data): |
1116 |
"""Delete the merge proposal and go back to the source branch."""
|
|
5600.2.7
by Tim Penhey
Updated pagetest for resubmissions. |
1117 |
self.context.deleteProposal() |
5280.4.11
by Tim Penhey
Read only page is now the default view, edit pages hang off that. |
1118 |
# Override the next url to be the source branch.
|
6618.2.5
by Paul Hummer
Fixes tests |
1119 |
self.next_url = canonical_url(self.source_branch) |
4414.5.13
by Tim Penhey
Still work in progress |
1120 |
|
1121 |
||
1122 |
class BranchMergeProposalMergedView(LaunchpadEditFormView): |
|
4414.5.14
by Tim Penhey
SOP and view work |
1123 |
"""The view to mark a merge proposal as merged."""
|
4414.5.13
by Tim Penhey
Still work in progress |
1124 |
schema = IBranchMergeProposal |
9129.1.11
by Tim Penhey
Oops, page_title not heading. |
1125 |
page_title = label = "Edit branch merge proposal" |
4414.5.13
by Tim Penhey
Still work in progress |
1126 |
field_names = ["merged_revno"] |
7325.8.28
by Paul Hummer
Fixed webapp setting of merged_revno to use markAsMerged |
1127 |
for_input = True |
4414.5.13
by Tim Penhey
Still work in progress |
1128 |
|
5280.4.11
by Tim Penhey
Read only page is now the default view, edit pages hang off that. |
1129 |
@property
|
5280.4.24
by Tim Penhey
First cut of changes following review. |
1130 |
def initial_values(self): |
6669.1.2
by Jonathan Lange
Fix up the comment. |
1131 |
# Default to the tip of the target branch, on the assumption that the
|
1132 |
# source branch has just been merged into it.
|
|
7055.8.7
by Tim Penhey
Updates following review. |
1133 |
if self.context.merged_revno is not None: |
1134 |
revno = self.context.merged_revno |
|
1135 |
else: |
|
1136 |
revno = self.context.target_branch.revision_count |
|
1137 |
return {'merged_revno': revno} |
|
5280.4.24
by Tim Penhey
First cut of changes following review. |
1138 |
|
1139 |
@property
|
|
5280.4.11
by Tim Penhey
Read only page is now the default view, edit pages hang off that. |
1140 |
def next_url(self): |
1141 |
return canonical_url(self.context) |
|
1142 |
||
6618.2.1
by Paul Hummer
Adds cancel_url, fixes tests |
1143 |
cancel_url = next_url |
1144 |
||
4414.5.13
by Tim Penhey
Still work in progress |
1145 |
@action('Mark as Merged', name='mark_merged') |
6080.6.1
by Aaron Bentley
Refactor notify decorator out of update_and_notify |
1146 |
@notify
|
4414.5.13
by Tim Penhey
Still work in progress |
1147 |
def mark_merged_action(self, action, data): |
1148 |
"""Update the whiteboard and go back to the source branch."""
|
|
6853.1.4
by Paul Hummer
Added a way to edit the branch merge proposal's merged revno |
1149 |
revno = data['merged_revno'] |
6042.2.2
by Tim Penhey
Updates following review. |
1150 |
if self.context.queue_status == BranchMergeProposalStatus.MERGED: |
7325.8.28
by Paul Hummer
Fixed webapp setting of merged_revno to use markAsMerged |
1151 |
self.context.markAsMerged(merged_revno=revno) |
6853.1.4
by Paul Hummer
Added a way to edit the branch merge proposal's merged revno |
1152 |
self.request.response.addNotification( |
1153 |
'The proposal\'s merged revision has been updated.') |
|
6042.2.2
by Tim Penhey
Updates following review. |
1154 |
else: |
6080.6.1
by Aaron Bentley
Refactor notify decorator out of update_and_notify |
1155 |
self.context.markAsMerged(revno, merge_reporter=self.user) |
1156 |
self.request.response.addNotification( |
|
1157 |
'The proposal has now been marked as merged.') |
|
4414.5.13
by Tim Penhey
Still work in progress |
1158 |
|
1159 |
def validate(self, data): |
|
1160 |
# Ensure a positive integer value.
|
|
1161 |
revno = data.get('merged_revno') |
|
1162 |
if revno is not None: |
|
1163 |
if revno <= 0: |
|
1164 |
self.setFieldError( |
|
1165 |
'merged_revno', |
|
1166 |
'Revision numbers must be positive integers.') |
|
5579.2.1
by Tim Penhey
Some queue management |
1167 |
|
1168 |
||
1169 |
class EnqueueForm(Interface): |
|
1170 |
"""A simple interface to populate the form to enqueue a proposal."""
|
|
1171 |
||
1172 |
revision_number = Int( |
|
1173 |
title=_("Queue Revision"), required=True, |
|
5579.2.11
by Tim Penhey
Updates following review. |
1174 |
description=_("The revision number of the source branch " |
5579.2.1
by Tim Penhey
Some queue management |
1175 |
"which is to be merged into the target branch.")) |
1176 |
||
1177 |
commit_message = Summary( |
|
1178 |
title=_("Commit Message"), required=True, |
|
1179 |
description=_("The commit message to be used when merging " |
|
1180 |
"the source branch.")) |
|
1181 |
||
1182 |
whiteboard = Whiteboard( |
|
1183 |
title=_('Whiteboard'), required=False, |
|
1184 |
description=_('Notes about the merge.')) |
|
1185 |
||
1186 |
||
1187 |
class BranchMergeProposalEnqueueView(MergeProposalEditView, |
|
1188 |
UnmergedRevisionsMixin): |
|
5579.2.11
by Tim Penhey
Updates following review. |
1189 |
"""The view to submit a merge proposal for merging."""
|
1190 |
||
5579.2.1
by Tim Penhey
Some queue management |
1191 |
schema = EnqueueForm |
9129.1.11
by Tim Penhey
Oops, page_title not heading. |
1192 |
page_title = label = "Queue branch for merging" |
5579.2.1
by Tim Penhey
Some queue management |
1193 |
|
1194 |
@property
|
|
5579.2.7
by Tim Penhey
Update the existing pagetest for new actions. |
1195 |
def initial_values(self): |
1196 |
# If the user is a valid reviewer, then default the revision
|
|
1197 |
# number to be the tip.
|
|
9041.4.1
by Tim Penhey
Move isPersonTrustedReviewer to the IBranch interface. |
1198 |
if self.context.target_branch.isPersonTrustedReviewer(self.user): |
5579.2.7
by Tim Penhey
Update the existing pagetest for new actions. |
1199 |
revision_number = self.context.source_branch.revision_count |
1200 |
else: |
|
1201 |
revision_number = self._getRevisionNumberForRevisionId( |
|
1202 |
self.context.reviewed_revision_id) |
|
1203 |
||
1204 |
return {'revision_number': revision_number} |
|
1205 |
||
1206 |
@property
|
|
5579.2.1
by Tim Penhey
Some queue management |
1207 |
def adapters(self): |
5579.2.11
by Tim Penhey
Updates following review. |
1208 |
"""See `LaunchpadFormView`"""
|
5579.2.1
by Tim Penhey
Some queue management |
1209 |
return {EnqueueForm: self.context} |
1210 |
||
5579.2.7
by Tim Penhey
Update the existing pagetest for new actions. |
1211 |
def setUpFields(self): |
1212 |
super(BranchMergeProposalEnqueueView, self).setUpFields() |
|
1213 |
# If the user is not a valid reviewer for the target branch,
|
|
5579.2.11
by Tim Penhey
Updates following review. |
1214 |
# then the revision number should be read only, so an
|
1215 |
# untrusted user cannot land changes that have not bee reviewed.
|
|
9041.4.1
by Tim Penhey
Move isPersonTrustedReviewer to the IBranch interface. |
1216 |
if not self.context.target_branch.isPersonTrustedReviewer(self.user): |
5579.2.7
by Tim Penhey
Update the existing pagetest for new actions. |
1217 |
self.form_fields['revision_number'].for_display = True |
1218 |
||
5579.2.1
by Tim Penhey
Some queue management |
1219 |
@action('Enqueue', name='enqueue') |
6080.5.9
by Aaron Bentley
Ensure notifications show enqueing |
1220 |
@update_and_notify
|
5579.2.1
by Tim Penhey
Some queue management |
1221 |
def enqueue_action(self, action, data): |
5579.2.11
by Tim Penhey
Updates following review. |
1222 |
"""Update the whiteboard and enqueue the merge proposal."""
|
9041.4.1
by Tim Penhey
Move isPersonTrustedReviewer to the IBranch interface. |
1223 |
if self.context.target_branch.isPersonTrustedReviewer(self.user): |
5579.2.7
by Tim Penhey
Update the existing pagetest for new actions. |
1224 |
revision_id = self._getRevisionId(data) |
1225 |
else: |
|
1226 |
revision_id = self.context.reviewed_revision_id |
|
1227 |
self.context.enqueue(self.user, revision_id) |
|
5579.2.1
by Tim Penhey
Some queue management |
1228 |
|
1229 |
def validate(self, data): |
|
5579.2.11
by Tim Penhey
Updates following review. |
1230 |
"""Make sure that the proposal has been reviewed.
|
1231 |
||
1232 |
Or that the logged in user is able to review the branch as well.
|
|
1233 |
"""
|
|
5579.2.7
by Tim Penhey
Update the existing pagetest for new actions. |
1234 |
if not self.context.isValidTransition( |
1235 |
BranchMergeProposalStatus.QUEUED, self.user): |
|
1236 |
self.addError( |
|
5579.2.11
by Tim Penhey
Updates following review. |
1237 |
"The merge proposal is cannot be queued as it has not "
|
1238 |
"been reviewed.") |
|
5579.2.1
by Tim Penhey
Some queue management |
1239 |
|
1240 |
self._validateRevisionNumber(data, 'enqueued') |
|
1241 |
||
1242 |
||
1243 |
class BranchMergeProposalDequeueView(LaunchpadEditFormView): |
|
1244 |
"""The view to remove a merge proposal from the merge queue."""
|
|
1245 |
||
1246 |
schema = IBranchMergeProposal |
|
5579.2.4
by Tim Penhey
UI works now. |
1247 |
field_names = ["whiteboard"] |
9129.1.11
by Tim Penhey
Oops, page_title not heading. |
1248 |
page_title = label = "Dequeue branch" |
5579.2.1
by Tim Penhey
Some queue management |
1249 |
|
1250 |
@property
|
|
1251 |
def next_url(self): |
|
1252 |
return canonical_url(self.context) |
|
1253 |
||
6618.2.1
by Paul Hummer
Adds cancel_url, fixes tests |
1254 |
cancel_url = next_url |
1255 |
||
5579.2.4
by Tim Penhey
UI works now. |
1256 |
@action('Dequeue', name='dequeue') |
6080.5.17
by Aaron Bentley
Implement notification for the other dequeue |
1257 |
@update_and_notify
|
5579.2.4
by Tim Penhey
UI works now. |
1258 |
def dequeue_action(self, action, data): |
5579.2.11
by Tim Penhey
Updates following review. |
1259 |
"""Update the whiteboard and remove the proposal from the queue."""
|
5579.2.4
by Tim Penhey
UI works now. |
1260 |
self.context.dequeue() |
5579.2.1
by Tim Penhey
Some queue management |
1261 |
|
5579.2.4
by Tim Penhey
UI works now. |
1262 |
def validate(self, data): |
5579.2.11
by Tim Penhey
Updates following review. |
1263 |
"""Make sure the proposal is queued before removing."""
|
5579.2.4
by Tim Penhey
UI works now. |
1264 |
if self.context.queue_status != BranchMergeProposalStatus.QUEUED: |
1265 |
self.addError("The merge proposal is not queued.") |
|
1266 |
||
1267 |
||
1268 |
class BranchMergeProposalInlineDequeueView(LaunchpadEditFormView): |
|
1269 |
"""The view to provide a 'dequeue' button to the queue view."""
|
|
1270 |
||
1271 |
schema = IBranchMergeProposal |
|
1272 |
field_names = [] |
|
1273 |
||
1274 |
@property
|
|
1275 |
def next_url(self): |
|
1276 |
return canonical_url(self.context.target_branch) + '/+merge-queue' |
|
1277 |
||
6618.2.1
by Paul Hummer
Adds cancel_url, fixes tests |
1278 |
cancel_url = next_url |
1279 |
||
5579.2.4
by Tim Penhey
UI works now. |
1280 |
@action('Dequeue', name='dequeue') |
6080.5.16
by Aaron Bentley
Notification on dequeue |
1281 |
@notify
|
5579.2.4
by Tim Penhey
UI works now. |
1282 |
def dequeue_action(self, action, data): |
5579.2.11
by Tim Penhey
Updates following review. |
1283 |
"""Remove the proposal from the queue if queued."""
|
5579.2.4
by Tim Penhey
UI works now. |
1284 |
if self.context.queue_status == BranchMergeProposalStatus.QUEUED: |
1285 |
self.context.dequeue() |
|
1286 |
||
1287 |
@property
|
|
1288 |
def prefix(self): |
|
1289 |
return "field%s" % self.context.id |
|
1290 |
||
1291 |
@property
|
|
1292 |
def action_url(self): |
|
1293 |
return "%s/+dequeue-inline" % canonical_url(self.context) |
|
1294 |
||
1295 |
||
1296 |
class BranchMergeProposalJumpQueueView(LaunchpadEditFormView): |
|
1297 |
"""The view to provide a move the proposal to the front of the queue."""
|
|
1298 |
||
1299 |
schema = IBranchMergeProposal |
|
1300 |
field_names = [] |
|
1301 |
||
1302 |
@property
|
|
1303 |
def next_url(self): |
|
1304 |
return canonical_url(self.context.target_branch) + '/+merge-queue' |
|
1305 |
||
1306 |
@action('Move to front', name='move') |
|
6080.5.15
by Aaron Bentley
Notify on queue position changes |
1307 |
@notify
|
5579.2.4
by Tim Penhey
UI works now. |
1308 |
def move_action(self, action, data): |
5579.2.11
by Tim Penhey
Updates following review. |
1309 |
"""Move the proposal to the front of the queue (if queued)."""
|
5579.2.4
by Tim Penhey
UI works now. |
1310 |
if (self.context.queue_status == BranchMergeProposalStatus.QUEUED and |
1311 |
check_permission('launchpad.Edit', self.context.target_branch)): |
|
1312 |
self.context.moveToFrontOfQueue() |
|
1313 |
||
1314 |
@property
|
|
1315 |
def prefix(self): |
|
1316 |
return "field%s" % self.context.id |
|
1317 |
||
1318 |
@property
|
|
1319 |
def action_url(self): |
|
1320 |
return "%s/+jump-queue" % canonical_url(self.context) |
|
6699.2.1
by Paul Hummer
Modifies views for some of the subscription stuff |
1321 |
|
1322 |
||
1323 |
class BranchMergeProposalSubscribersView(LaunchpadView): |
|
1324 |
"""Used to show the pagelet subscribers on the main proposal page."""
|
|
1325 |
||
1326 |
def initialize(self): |
|
1327 |
"""See `LaunchpadView`."""
|
|
1328 |
# Get the subscribers and dump them into two sets.
|
|
1329 |
self._full_subscribers = set() |
|
1330 |
self._status_subscribers = set() |
|
1331 |
# Add subscribers from the source and target branches.
|
|
1332 |
self._add_subscribers_for_branch(self.context.source_branch) |
|
1333 |
self._add_subscribers_for_branch(self.context.target_branch) |
|
1334 |
# Remove all the people from the comment_subscribers from the
|
|
1335 |
# status_and_vote_subscribers as they recipients will get the email
|
|
1336 |
# only once, and for the most detailed subscription from the source
|
|
1337 |
# and target branches.
|
|
1338 |
self._status_subscribers = ( |
|
1339 |
self._status_subscribers - self._full_subscribers) |
|
1340 |
||
1341 |
def _add_subscribers_for_branch(self, branch): |
|
1342 |
"""Add the subscribers to the subscription sets for the branch."""
|
|
1343 |
for subscription in branch.subscriptions: |
|
1344 |
level = subscription.review_level |
|
1345 |
if level == CodeReviewNotificationLevel.FULL: |
|
1346 |
self._full_subscribers.add(subscription.person) |
|
1347 |
elif level == CodeReviewNotificationLevel.STATUS: |
|
1348 |
self._status_subscribers.add(subscription.person) |
|
1349 |
else: |
|
1350 |
# We don't do anything right now with people who say they
|
|
1351 |
# don't want to see anything.
|
|
1352 |
pass
|
|
1353 |
||
1354 |
@cachedproperty
|
|
1355 |
def full_subscribers(self): |
|
1356 |
"""A list of full subscribers ordered by displayname."""
|
|
1357 |
return sorted( |
|
1358 |
self._full_subscribers, key=operator.attrgetter('displayname')) |
|
1359 |
||
1360 |
@cachedproperty
|
|
1361 |
def status_subscribers(self): |
|
1362 |
"""A list of full subscribers ordered by displayname."""
|
|
1363 |
return sorted( |
|
1364 |
self._status_subscribers, key=operator.attrgetter('displayname')) |
|
1365 |
||
1366 |
@property
|
|
1367 |
def has_subscribers(self): |
|
1368 |
"""True if there are subscribers to the branch."""
|
|
1369 |
return len(self.full_subscribers) + len(self.status_subscribers) |
|
1370 |
||
7055.6.6
by Tim Penhey
Add an edit status view for merge proposals and remove the menu links. |
1371 |
|
9848.1.13
by Paul Hummer
Fixed the status vocabulary to be generated based on what's enabled. |
1372 |
class BranchMergeProposalChangeStatusView(MergeProposalEditView, |
1373 |
BranchMergeProposalStatusMixin): |
|
7055.6.6
by Tim Penhey
Add an edit status view for merge proposals and remove the menu links. |
1374 |
|
9129.1.11
by Tim Penhey
Oops, page_title not heading. |
1375 |
page_title = label = "Change merge proposal status" |
7055.6.6
by Tim Penhey
Add an edit status view for merge proposals and remove the menu links. |
1376 |
schema = IBranchMergeProposal |
1377 |
field_names = [] |
|
1378 |
||
7055.7.9
by Tim Penhey
Add test for +edit-status vocabulary options. |
1379 |
def setUpFields(self): |
1380 |
MergeProposalEditView.setUpFields(self) |
|
1381 |
# Add the custom restricted queue status widget.
|
|
1382 |
status_field = self.schema['queue_status'] |
|
7055.6.6
by Tim Penhey
Add an edit status view for merge proposals and remove the menu links. |
1383 |
|
1384 |
status_choice = Choice( |
|
1385 |
__name__='queue_status', title=status_field.title, |
|
7055.7.9
by Tim Penhey
Add test for +edit-status vocabulary options. |
1386 |
required=True, vocabulary=self._createStatusVocabulary()) |
7055.6.6
by Tim Penhey
Add an edit status view for merge proposals and remove the menu links. |
1387 |
status_field = form.Fields( |
1388 |
status_choice, render_context=self.render_context) |
|
1389 |
self.form_fields = status_field + self.form_fields |
|
1390 |
||
1391 |
@action('Change Status', name='update') |
|
7055.7.5
by Tim Penhey
Fire email notifications. |
1392 |
@notify
|
7055.6.6
by Tim Penhey
Add an edit status view for merge proposals and remove the menu links. |
1393 |
def update_action(self, action, data): |
1394 |
"""Update the status."""
|
|
1395 |
||
1396 |
curr_status = self.context.queue_status |
|
1397 |
# Assume for now that the queue_status in the data is a valid
|
|
1398 |
# transition from where we are.
|
|
1399 |
rev_id = self.request.form['revno'] |
|
1400 |
new_status = data['queue_status'] |
|
1401 |
# Don't do anything if the user hasn't changed the status.
|
|
1402 |
if new_status == curr_status: |
|
1403 |
return
|
|
1404 |
||
9327.2.2
by Aaron Bentley
Remove 'resubmit'/ superseded status setting. |
1405 |
assert new_status != BranchMergeProposalStatus.SUPERSEDED, ( |
1406 |
'Superseded is done via an action, not by setting status.') |
|
1407 |
self.context.setStatus(new_status, self.user, rev_id) |
|
7055.6.6
by Tim Penhey
Add an edit status view for merge proposals and remove the menu links. |
1408 |
|
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1409 |
|
1410 |
class IAddVote(Interface): |
|
1411 |
"""Interface for use as a schema for CodeReviewComment forms."""
|
|
1412 |
||
7055.6.16
by Tim Penhey
vote tag and field name fixes. |
1413 |
vote = copy_field(ICodeReviewComment['vote'], required=True) |
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1414 |
|
9656.1.6
by Nathan Handler
Make changes requested by Michael Hudson (mwhudson) |
1415 |
review_type = copy_field( |
11019.3.1
by Tim Penhey
Extract the DecoratedBug and DecorateBranch out of the browser/branch module and into its own. Use a DecoratedBranch for the new revisions. |
1416 |
ICodeReviewVoteReference['review_type'], |
9656.1.6
by Nathan Handler
Make changes requested by Michael Hudson (mwhudson) |
1417 |
description=u'Lowercase keywords describing the type of review you ' |
1418 |
'are performing.') |
|
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1419 |
|
1420 |
comment = Text(title=_('Comment'), required=False) |
|
1421 |
||
1422 |
||
1423 |
class BranchMergeProposalAddVoteView(LaunchpadFormView): |
|
1424 |
"""View for adding a CodeReviewComment."""
|
|
1425 |
||
1426 |
schema = IAddVote |
|
1427 |
field_names = ['vote', 'review_type', 'comment'] |
|
1428 |
||
7285.2.1
by Paul Hummer
Added class to the comment form in a reply |
1429 |
custom_widget('comment', TextAreaWidget, cssClass='codereviewcomment') |
1430 |
||
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1431 |
@cachedproperty
|
1432 |
def initial_values(self): |
|
7055.6.24
by Tim Penhey
More review updates. |
1433 |
"""The initial values are used to populate the form fields."""
|
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1434 |
# Look to see if there is a vote reference already for the user.
|
1435 |
if self.users_vote_ref is None: |
|
1436 |
# Look at the request to see if there is something there.
|
|
1437 |
review_type = self.request.form.get('review_type', '') |
|
1438 |
else: |
|
1439 |
review_type = self.users_vote_ref.review_type |
|
7055.6.24
by Tim Penhey
More review updates. |
1440 |
# We'll be positive here and default the vote to approve.
|
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1441 |
return {'vote': CodeReviewVote.APPROVE, |
1442 |
'review_type': review_type} |
|
1443 |
||
1444 |
def initialize(self): |
|
1445 |
"""Get the users existing vote reference."""
|
|
1446 |
self.users_vote_ref = self.context.getUsersVoteReference(self.user) |
|
1447 |
# If the user is not in the review team, nor in any team that has been
|
|
7055.6.24
by Tim Penhey
More review updates. |
1448 |
# requested to review and doesn't already have a vote reference, then
|
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1449 |
# error out as the user must have URL hacked to get here.
|
7055.6.12
by Tim Penhey
Add extra vote types, and format nicely the listing. |
1450 |
|
7055.9.2
by Tim Penhey
Review updates. |
1451 |
# XXX: Tim Penhey, 2008-10-02, bug=277000
|
1452 |
# Move valid_voter db class to expose for API.
|
|
7055.6.24
by Tim Penhey
More review updates. |
1453 |
|
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1454 |
if self.user is None: |
7055.6.24
by Tim Penhey
More review updates. |
1455 |
# Anonymous users are not valid voters.
|
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1456 |
raise AssertionError('Invalid voter') |
1457 |
LaunchpadFormView.initialize(self) |
|
1458 |
||
1459 |
def setUpFields(self): |
|
1460 |
LaunchpadFormView.setUpFields(self) |
|
1461 |
self.reviewer = self.user.name |
|
7055.6.30
by Paul Hummer
Added technical debt *sigh* |
1462 |
# claim_review is set in situations where a user is reviewing on
|
1463 |
# behalf of a team.
|
|
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1464 |
claim_review = self.request.form.get('claim') |
1465 |
if claim_review and self.users_vote_ref is None: |
|
1466 |
team = getUtility(IPersonSet).getByName(claim_review) |
|
1467 |
if team is not None and self.user.inTeam(team): |
|
7310.1.1
by Tim Penhey
Claiming a team review without a review type didn't work. |
1468 |
# If the review type is None, then don't show the field.
|
10147.3.1
by Tim Penhey
make the review claiming work for empty review types too |
1469 |
self.reviewer = team.name |
7310.1.1
by Tim Penhey
Claiming a team review without a review type didn't work. |
1470 |
if self.initial_values['review_type'] == '': |
1471 |
self.form_fields = self.form_fields.omit('review_type') |
|
1472 |
else: |
|
1473 |
# Disable the review_type field
|
|
1474 |
self.form_fields['review_type'].for_display = True |
|
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1475 |
|
1476 |
@property
|
|
1477 |
def label(self): |
|
1478 |
"""The pagetitle and heading."""
|
|
7055.6.16
by Tim Penhey
vote tag and field name fixes. |
1479 |
return "Review merge proposal for %s" % ( |
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1480 |
self.context.source_branch.bzr_identity) |
9129.1.11
by Tim Penhey
Oops, page_title not heading. |
1481 |
page_title = label |
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1482 |
|
7055.6.16
by Tim Penhey
vote tag and field name fixes. |
1483 |
@action('Save Review', name='vote') |
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1484 |
def vote_action(self, action, data): |
7055.6.23
by Tim Penhey
Updates following jml's review. |
1485 |
"""Create the comment."""
|
7055.6.24
by Tim Penhey
More review updates. |
1486 |
# Get the review type from the data dict. If the setUpFields set the
|
1487 |
# review_type field as for_display then 'review_type' will not be in
|
|
1488 |
# the data dict. If this is the case, get the review_type from the
|
|
1489 |
# hidden field that we so cunningly added to the form.
|
|
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1490 |
review_type = data.get( |
1491 |
'review_type', |
|
1492 |
self.request.form.get('review_type')) |
|
7310.1.1
by Tim Penhey
Claiming a team review without a review type didn't work. |
1493 |
# Translate the request parameter back into what our object model
|
1494 |
# needs.
|
|
1495 |
if review_type == '': |
|
1496 |
review_type = None |
|
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1497 |
# Get the reviewer from the hidden input.
|
1498 |
reviewer_name = self.request.form.get('reviewer') |
|
1499 |
reviewer = getUtility(IPersonSet).getByName(reviewer_name) |
|
1500 |
if (reviewer.is_team and self.user.inTeam(reviewer) and |
|
1501 |
self.users_vote_ref is None): |
|
1502 |
vote_ref = self.context.getUsersVoteReference( |
|
1503 |
reviewer, review_type) |
|
1504 |
if vote_ref is not None: |
|
7055.6.30
by Paul Hummer
Added technical debt *sigh* |
1505 |
# Claim this vote reference, i.e. say that the individual
|
1506 |
# self. user is doing this review ond behalf of the 'reviewer'
|
|
1507 |
# team.
|
|
10147.3.3
by Tim Penhey
Fix the team claiming reviews. |
1508 |
vote_ref.claimReview(self.user) |
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1509 |
|
11019.3.1
by Tim Penhey
Extract the DecoratedBug and DecorateBranch out of the browser/branch module and into its own. Use a DecoratedBranch for the new revisions. |
1510 |
self.context.createComment( |
7055.6.11
by Tim Penhey
Lots of changes to do with the request reviewer, voting and comment pages. |
1511 |
self.user, subject=None, content=data['comment'], |
1512 |
vote=data['vote'], review_type=review_type) |
|
1513 |
||
1514 |
@property
|
|
1515 |
def next_url(self): |
|
1516 |
"""Always take the user back to the merge proposal itself."""
|
|
1517 |
return canonical_url(self.context) |
|
1518 |
||
1519 |
cancel_url = next_url |
|
9737.2.5
by Tim Penhey
Make an xhtml renderer adapter for the commit_message. |
1520 |
|
1521 |
||
9691.6.10
by Tim Penhey
Make the diff load using the API rather than hitting the page. |
1522 |
class FormatPreviewDiffView(LaunchpadView, DiffRenderingMixin): |
1523 |
"""A simple view to render a diff formatted nicely."""
|
|
1524 |
||
1525 |
@property
|
|
1526 |
def preview_diff(self): |
|
1527 |
return self.context |
|
1528 |
||
1529 |
||
1530 |
class PreviewDiffHTMLRepresentation: |
|
1531 |
adapts(IPreviewDiff, IWebServiceClientRequest) |
|
1532 |
implements(Interface) |
|
1533 |
||
1534 |
def __init__(self, diff, request): |
|
1535 |
self.diff = diff |
|
1536 |
self.request = request |
|
1537 |
||
1538 |
def __call__(self): |
|
1539 |
"""Render `BugBranch` as XHTML using the webservice."""
|
|
1540 |
diff_view = getMultiAdapter( |
|
1541 |
(self.diff, self.request), name="+diff") |
|
1542 |
return diff_view() |