Merge lp:~thumper/launchpad/propose-merging-extra-options into lp:launchpad

Proposed by Tim Penhey on 2010-01-14
Status: Merged
Merged at revision: not available
Proposed branch: lp:~thumper/launchpad/propose-merging-extra-options
Merge into: lp:launchpad
Diff against target: 309 lines (+171/-18)
6 files modified
lib/canonical/launchpad/icing/style.css (+4/-2)
lib/lp/code/browser/branch.py (+13/-6)
lib/lp/code/browser/configure.zcml (+1/-1)
lib/lp/code/browser/tests/test_branchmergeproposal.py (+34/-9)
lib/lp/code/stories/branches/xx-propose-for-merging.txt (+59/-0)
lib/lp/code/templates/branch-register-merge.pt (+60/-0)
To merge this branch: bzr merge lp:~thumper/launchpad/propose-merging-extra-options
Reviewer Review Type Date Requested Status
Michael Nelson (community) ui 2010-01-15 Approve on 2010-01-15
Paul Hummer (community) code ui* 2010-01-14 Approve on 2010-01-15
Review via email: mp+17350@code.launchpad.net

Commit Message

Make prerequisite branch and reviewer fields extra options in the propose for merging page.

To post a comment you must log in.
Tim Penhey (thumper) wrote :

Makes prerequisite branch, reviewer and review type extra options when proposing a merge.

Also adds in commit message and needs review options.

Paul Hummer (rockstar) wrote :

Thanks for taking noodles and I through this branch's UI. The flow is more similar to the new bug UI as well now, so it looks good. Thanks for doing this.

review: Approve (code ui*)
review: Approve (ui)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/icing/style.css'
2--- lib/canonical/launchpad/icing/style.css 2010-01-06 14:14:35 +0000
3+++ lib/canonical/launchpad/icing/style.css 2010-01-17 06:03:17 +0000
4@@ -241,9 +241,11 @@
5 textarea {width: 90%; max-width: 60em;}
6
7 /* Many forms are laid out using tables, with appropriate spacing: */
8-table.form {margin: 1em 0; width: 100%;} /* http://launchpad.dev/firefox/+edit */
9+table.form, table.extra-options {margin: 1em 0; width: 100%;} /* http://launchpad.dev/firefox/+edit */
10 table.form th {font-weight: normal;}
11-table.form th, table.form td {padding-bottom: 1em;}
12+table.form th, table.form td,
13+table.form table.extra-options td,
14+table.form table.extra-options th {padding-bottom: 1em;}
15 table.form td td {padding-bottom: 0;}
16
17 /* === Tables === */
18
19=== modified file 'lib/lp/code/browser/branch.py'
20--- lib/lp/code/browser/branch.py 2010-01-07 05:03:46 +0000
21+++ lib/lp/code/browser/branch.py 2010-01-17 06:03:17 +0000
22@@ -41,7 +41,7 @@
23 from zope.formlib import form
24 from zope.interface import Interface, implements, providedBy
25 from zope.publisher.interfaces import NotFound
26-from zope.schema import Choice, Text
27+from zope.schema import Bool, Choice, Text
28 from lazr.delegates import delegates
29 from lazr.enum import EnumeratedType, Item
30 from lazr.lifecycle.event import ObjectModifiedEvent
31@@ -85,6 +85,7 @@
32 from lp.code.interfaces.branch import (
33 BranchCreationForbidden, BranchExists, IBranch,
34 user_has_special_branch_access)
35+from lp.code.interfaces.branchmergeproposal import IBranchMergeProposal
36 from lp.code.interfaces.branchtarget import IBranchTarget
37 from lp.code.interfaces.codeimportjob import ICodeImportJobWorkflow
38 from lp.code.interfaces.branchnamespace import IBranchNamespacePolicy
39@@ -1156,6 +1157,13 @@
40 description=u'Lowercase keywords describing the type of review you '
41 'would like to be performed.')
42
43+ commit_message = IBranchMergeProposal['commit_message']
44+
45+ needs_review = Bool(
46+ title=_("Needs review"), required=True, default=True,
47+ description=_(
48+ "Is the proposal ready for review now?"))
49+
50
51 class RegisterBranchMergeProposalView(LaunchpadFormView):
52 """The view to register new branch merge proposals."""
53@@ -1205,14 +1213,13 @@
54 review_requests.append((reviewer, data.get('review_type')))
55
56 try:
57- # Always default to needs review until we have the wonder of AJAX
58- # and an advanced expandable section.
59 proposal = source_branch.addLandingTarget(
60 registrant=registrant, target_branch=target_branch,
61- prerequisite_branch=prerequisite_branch, needs_review=True,
62+ prerequisite_branch=prerequisite_branch,
63+ needs_review=data['needs_review'],
64 initial_comment=data.get('comment'),
65- review_requests=review_requests)
66-
67+ review_requests=review_requests,
68+ commit_message=data.get('commit_message'))
69 self.next_url = canonical_url(proposal)
70 except InvalidBranchMergeProposal, error:
71 self.addError(str(error))
72
73=== modified file 'lib/lp/code/browser/configure.zcml'
74--- lib/lp/code/browser/configure.zcml 2010-01-14 01:48:19 +0000
75+++ lib/lp/code/browser/configure.zcml 2010-01-17 06:03:17 +0000
76@@ -519,7 +519,7 @@
77 class="lp.code.browser.branch.RegisterBranchMergeProposalView"
78 facet="branches"
79 permission="launchpad.AnyPerson"
80- template="../../app/templates/generic-edit.pt"/>
81+ template="../templates/branch-register-merge.pt"/>
82 <browser:page
83 name="+linkbug"
84 for="lp.code.interfaces.branch.IBranch"
85
86=== modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py'
87--- lib/lp/code/browser/tests/test_branchmergeproposal.py 2010-01-06 17:25:04 +0000
88+++ lib/lp/code/browser/tests/test_branchmergeproposal.py 2010-01-17 06:03:17 +0000
89@@ -351,14 +351,11 @@
90 return view
91
92 def _getSourceProposal(self):
93- # There will only be one proposal and it will be in needs review
94- # state.
95+ # There will only be one proposal.
96 landing_targets = list(self.source_branch.landing_targets)
97 self.assertEqual(1, len(landing_targets))
98 proposal = landing_targets[0]
99 self.assertEqual(self.target_branch, proposal.target_branch)
100- self.assertEqual(BranchMergeProposalStatus.NEEDS_REVIEW,
101- proposal.queue_status)
102 return proposal
103
104 def assertNoComments(self, proposal):
105@@ -393,18 +390,43 @@
106 # This simplest case is where the user only specifies the target
107 # branch, and not an initial comment or reviewer.
108 view = self._createView()
109- view.register_action.success({'target_branch': self.target_branch})
110+ view.register_action.success(
111+ {'target_branch': self.target_branch,
112+ 'needs_review': True})
113 proposal = self._getSourceProposal()
114 self.assertNoPendingReviews(proposal)
115 self.assertNoComments(proposal)
116
117+ def test_register_work_in_progress(self):
118+ # The needs review checkbox can be unchecked to create a work in
119+ # progress proposal.
120+ view = self._createView()
121+ view.register_action.success(
122+ {'target_branch': self.target_branch,
123+ 'needs_review': False})
124+ proposal = self._getSourceProposal()
125+ self.assertEqual(
126+ BranchMergeProposalStatus.WORK_IN_PROGRESS,
127+ proposal.queue_status)
128+
129+ def test_register_with_commit_message(self):
130+ # A commit message can also be set during the register process.
131+ view = self._createView()
132+ view.register_action.success(
133+ {'target_branch': self.target_branch,
134+ 'needs_review': True,
135+ 'commit_message': 'Fixed the bug!'})
136+ proposal = self._getSourceProposal()
137+ self.assertEqual('Fixed the bug!', proposal.commit_message)
138+
139 def test_register_initial_comment(self):
140 # If the user specifies an initial comment, this is added to the
141 # proposal.
142 view = self._createView()
143 view.register_action.success(
144 {'target_branch': self.target_branch,
145- 'comment': "This is the first comment."})
146+ 'comment': "This is the first comment.",
147+ 'needs_review': True})
148
149 proposal = self._getSourceProposal()
150 self.assertNoPendingReviews(proposal)
151@@ -417,7 +439,8 @@
152 view = self._createView()
153 view.register_action.success(
154 {'target_branch': self.target_branch,
155- 'reviewer': reviewer})
156+ 'reviewer': reviewer,
157+ 'needs_review': True})
158
159 proposal = self._getSourceProposal()
160 self.assertOnePendingReview(proposal, reviewer)
161@@ -431,7 +454,8 @@
162 view.register_action.success(
163 {'target_branch': self.target_branch,
164 'reviewer': reviewer,
165- 'review_type': 'god-like'})
166+ 'review_type': 'god-like',
167+ 'needs_review': True})
168
169 proposal = self._getSourceProposal()
170 self.assertOnePendingReview(proposal, reviewer, 'god-like')
171@@ -446,7 +470,8 @@
172 {'target_branch': self.target_branch,
173 'reviewer': reviewer,
174 'review_type': 'god-like',
175- 'comment': "This is the first comment."})
176+ 'comment': "This is the first comment.",
177+ 'needs_review': True})
178
179 proposal = self._getSourceProposal()
180 self.assertOnePendingReview(proposal, reviewer, 'god-like')
181
182=== added file 'lib/lp/code/stories/branches/xx-propose-for-merging.txt'
183--- lib/lp/code/stories/branches/xx-propose-for-merging.txt 1970-01-01 00:00:00 +0000
184+++ lib/lp/code/stories/branches/xx-propose-for-merging.txt 2010-01-17 06:03:17 +0000
185@@ -0,0 +1,59 @@
186+Propose a branch for merging
187+============================
188+
189+ >>> login(ANONYMOUS)
190+ >>> from lp.code.tests.helpers import make_erics_fooix_project
191+ >>> locals().update(make_erics_fooix_project(factory))
192+ >>> branch = factory.makeProductBranch(product=fooix)
193+ >>> url = canonical_url(branch)
194+ >>> logout()
195+
196+When proposing a branch for merging, the minimum that is needed is a target
197+branch.
198+
199+ >>> browser = setupBrowser(auth='Basic fred@example.com:test')
200+ >>> browser.open(url)
201+ >>> browser.getLink('Propose for merging').click()
202+
203+ >>> def print_radio_buttons(browser):
204+ ... main = find_main_content(browser.contents)
205+ ... for button in main.findAll('input', attrs={'type': 'radio'}):
206+ ... try:
207+ ... if button['checked']:
208+ ... checked = '(*)'
209+ ... else:
210+ ... checked = '( )'
211+ ... except KeyError:
212+ ... checked = '( )'
213+ ... print checked, button['value']
214+
215+ >>> print_radio_buttons(browser)
216+ (*) ~eric/fooix/trunk
217+ ( ) other
218+ >>> browser.getControl('Propose Merge').click()
219+ >>> print_tag_with_id(browser.contents, 'proposal-summary')
220+ Status: Needs review
221+ Proposed branch: ...
222+ Merge into: lp://dev/fooix
223+
224+
225+Work in progress
226+----------------
227+
228+Sometimes a proposal is wanted for the diff against the target, but the code
229+is not yet ready for review. In these situations the user can uncheck the
230+needs review checkbox in the extra options.
231+
232+ >>> login(ANONYMOUS)
233+ >>> branch = factory.makeProductBranch(product=fooix)
234+ >>> url = canonical_url(branch)
235+ >>> logout()
236+
237+ >>> browser.open(url)
238+ >>> browser.getLink('Propose for merging').click()
239+ >>> browser.getControl('Needs review').click()
240+ >>> browser.getControl('Propose Merge').click()
241+ >>> print_tag_with_id(browser.contents, 'proposal-summary')
242+ Status: Work in progress
243+ Proposed branch: ...
244+ Merge into: lp://dev/fooix
245
246=== added file 'lib/lp/code/templates/branch-register-merge.pt'
247--- lib/lp/code/templates/branch-register-merge.pt 1970-01-01 00:00:00 +0000
248+++ lib/lp/code/templates/branch-register-merge.pt 2010-01-17 06:03:17 +0000
249@@ -0,0 +1,60 @@
250+<html
251+ xmlns="http://www.w3.org/1999/xhtml"
252+ xmlns:tal="http://xml.zope.org/namespaces/tal"
253+ xmlns:metal="http://xml.zope.org/namespaces/metal"
254+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
255+ metal:use-macro="view/macro:page/main_only"
256+ i18n:domain="launchpad">
257+ <body>
258+ <div metal:fill-slot="main">
259+ <div metal:use-macro="context/@@launchpad_form/form">
260+
261+ <metal:formbody fill-slot="widgets">
262+ <table class="form">
263+
264+ <tal:widget define="widget nocall:view/widgets/target_branch">
265+ <metal:block use-macro="context/@@launchpad_form/widget_row" />
266+ </tal:widget>
267+
268+ <tal:widget define="widget nocall:view/widgets/comment">
269+ <metal:block use-macro="context/@@launchpad_form/widget_row" />
270+ </tal:widget>
271+
272+ <td colspan="2">
273+ <fieldset id="mergeproposal-extra-options"
274+ class="collapsible collapsed">
275+ <legend>Extra options</legend>
276+ <table class="extra-options">
277+
278+ <tal:widget define="widget nocall:view/widgets/commit_message">
279+ <metal:block use-macro="context/@@launchpad_form/widget_row" />
280+ </tal:widget>
281+
282+ <tal:widget define="widget nocall:view/widgets/reviewer">
283+ <metal:block use-macro="context/@@launchpad_form/widget_row" />
284+ </tal:widget>
285+
286+ <tal:widget define="widget nocall:view/widgets/review_type">
287+ <metal:block use-macro="context/@@launchpad_form/widget_row" />
288+ </tal:widget>
289+
290+ <tal:widget define="widget nocall:view/widgets/needs_review">
291+ <metal:block use-macro="context/@@launchpad_form/widget_row" />
292+ </tal:widget>
293+
294+ <tal:widget define="widget nocall:view/widgets/prerequisite_branch">
295+ <metal:block use-macro="context/@@launchpad_form/widget_row" />
296+ </tal:widget>
297+
298+
299+
300+ </table>
301+ </fieldset>
302+ </td>
303+
304+ </table>
305+ </metal:formbody>
306+ </div>
307+ </div>
308+ </body>
309+</html>