Merge lp:~thumper/launchpad/bug-branch-proposal-view into lp:launchpad
- bug-branch-proposal-view
- Merge into devel
Proposed by
Tim Penhey
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~thumper/launchpad/bug-branch-proposal-view |
Merge into: | lp:launchpad |
Prerequisite: | lp:~thumper/launchpad/project-sourcecode |
Diff against target: |
640 lines (+233/-57) 10 files modified
lib/lp/code/browser/branchmergeproposal.py (+19/-1) lib/lp/code/browser/configure.zcml (+10/-5) lib/lp/code/browser/tests/test_branchmergeproposal.py (+55/-17) lib/lp/code/model/branchmergeproposal.py (+11/-6) lib/lp/code/stories/branches/xx-branch-merge-proposals.txt (+40/-27) lib/lp/code/templates/branch-index.pt (+4/-0) lib/lp/code/templates/branch-pending-merges.pt (+1/-0) lib/lp/code/templates/branchmergeproposal-link-summary.pt (+2/-1) lib/lp/code/templates/branchmergeproposal-vote-summary.pt (+49/-0) lib/lp/code/tests/helpers.py (+42/-0) |
To merge this branch: | bzr merge lp:~thumper/launchpad/bug-branch-proposal-view |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Barry Warsaw (community) | ui* | Approve | |
Paul Hummer (community) | ui code | Approve | |
Review via email: mp+14736@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Tim Penhey (thumper) wrote : | # |
Revision history for this message
Paul Hummer (rockstar) : | # |
review:
Approve
(ui code)
Revision history for this message
Barry Warsaw (barry) : | # |
review:
Approve
(ui*)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/lp/code/browser/branchmergeproposal.py' | |||
2 | --- lib/lp/code/browser/branchmergeproposal.py 2009-11-10 22:57:42 +0000 | |||
3 | +++ lib/lp/code/browser/branchmergeproposal.py 2009-11-18 00:28:15 +0000 | |||
4 | @@ -60,7 +60,8 @@ | |||
5 | 60 | from canonical.launchpad.webapp.breadcrumb import Breadcrumb | 60 | from canonical.launchpad.webapp.breadcrumb import Breadcrumb |
6 | 61 | from canonical.launchpad.webapp.interfaces import IPrimaryContext | 61 | from canonical.launchpad.webapp.interfaces import IPrimaryContext |
7 | 62 | from canonical.launchpad.webapp.menu import NavigationMenu | 62 | from canonical.launchpad.webapp.menu import NavigationMenu |
9 | 63 | from canonical.launchpad.webapp.tales import FormattersAPI | 63 | from canonical.launchpad.webapp.tales import ( |
10 | 64 | DateTimeFormatterAPI, FormattersAPI) | ||
11 | 64 | from canonical.widgets.lazrjs import ( | 65 | from canonical.widgets.lazrjs import ( |
12 | 65 | TextAreaEditorWidget, vocabulary_to_choice_edit_items) | 66 | TextAreaEditorWidget, vocabulary_to_choice_edit_items) |
13 | 66 | 67 | ||
14 | @@ -138,6 +139,23 @@ | |||
15 | 138 | } | 139 | } |
16 | 139 | return friendly_texts[self.context.queue_status] | 140 | return friendly_texts[self.context.queue_status] |
17 | 140 | 141 | ||
18 | 142 | @property | ||
19 | 143 | def status_title(self): | ||
20 | 144 | """The title for the status text. | ||
21 | 145 | |||
22 | 146 | Only set if the status is approved or rejected. | ||
23 | 147 | """ | ||
24 | 148 | result = '' | ||
25 | 149 | if self.context.queue_status in ( | ||
26 | 150 | BranchMergeProposalStatus.CODE_APPROVED, | ||
27 | 151 | BranchMergeProposalStatus.REJECTED | ||
28 | 152 | ): | ||
29 | 153 | formatter = DateTimeFormatterAPI(self.context.date_reviewed) | ||
30 | 154 | result = '%s %s' % ( | ||
31 | 155 | self.context.reviewer.displayname, | ||
32 | 156 | formatter.displaydate()) | ||
33 | 157 | return result | ||
34 | 158 | |||
35 | 141 | 159 | ||
36 | 142 | class BranchMergeProposalMenuMixin: | 160 | class BranchMergeProposalMenuMixin: |
37 | 143 | """Mixin class for merge proposal menus.""" | 161 | """Mixin class for merge proposal menus.""" |
38 | 144 | 162 | ||
39 | === modified file 'lib/lp/code/browser/configure.zcml' | |||
40 | --- lib/lp/code/browser/configure.zcml 2009-11-13 20:12:17 +0000 | |||
41 | +++ lib/lp/code/browser/configure.zcml 2009-11-18 00:28:15 +0000 | |||
42 | @@ -184,13 +184,18 @@ | |||
43 | 184 | name="+pagelet-summary" | 184 | name="+pagelet-summary" |
44 | 185 | template="../templates/branchmergeproposal-pagelet-summary.pt"/> | 185 | template="../templates/branchmergeproposal-pagelet-summary.pt"/> |
45 | 186 | </browser:pages> | 186 | </browser:pages> |
48 | 187 | <browser:page | 187 | <browser:pages |
47 | 188 | name="+votes" | ||
49 | 189 | for="lp.code.interfaces.branchmergeproposal.IBranchMergeProposal" | 188 | for="lp.code.interfaces.branchmergeproposal.IBranchMergeProposal" |
50 | 190 | class="lp.code.browser.branchmergeproposal.BranchMergeProposalVoteView" | 189 | class="lp.code.browser.branchmergeproposal.BranchMergeProposalVoteView" |
51 | 191 | facet="branches" | 190 | facet="branches" |
54 | 192 | permission="launchpad.View" | 191 | permission="launchpad.View"> |
55 | 193 | template="../templates/branchmergeproposal-votes.pt"/> | 192 | <browser:page |
56 | 193 | name="+votes" | ||
57 | 194 | template="../templates/branchmergeproposal-votes.pt"/> | ||
58 | 195 | <browser:page | ||
59 | 196 | name="+vote-summary" | ||
60 | 197 | template="../templates/branchmergeproposal-vote-summary.pt"/> | ||
61 | 198 | </browser:pages> | ||
62 | 194 | <browser:pages | 199 | <browser:pages |
63 | 195 | for="lp.code.interfaces.branchmergeproposal.IBranchMergeProposal" | 200 | for="lp.code.interfaces.branchmergeproposal.IBranchMergeProposal" |
64 | 196 | class="lp.code.browser.branchmergeproposal.BranchMergeProposalEditView" | 201 | class="lp.code.browser.branchmergeproposal.BranchMergeProposalEditView" |
65 | @@ -276,7 +281,7 @@ | |||
66 | 276 | class="lp.code.browser.branchmergeproposal.BranchMergeCandidateView" | 281 | class="lp.code.browser.branchmergeproposal.BranchMergeCandidateView" |
67 | 277 | facet="branches" | 282 | facet="branches" |
68 | 278 | permission="zope.Public" | 283 | permission="zope.Public" |
70 | 279 | template="../templates/branch-merge-link-summary.pt"/> | 284 | template="../templates/branchmergeproposal-link-summary.pt"/> |
71 | 280 | <browser:page | 285 | <browser:page |
72 | 281 | name="+pagelet-subscribers" | 286 | name="+pagelet-subscribers" |
73 | 282 | for="lp.code.interfaces.branchmergeproposal.IBranchMergeProposal" | 287 | for="lp.code.interfaces.branchmergeproposal.IBranchMergeProposal" |
74 | 283 | 288 | ||
75 | === modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py' | |||
76 | --- lib/lp/code/browser/tests/test_branchmergeproposal.py 2009-11-01 23:13:09 +0000 | |||
77 | +++ lib/lp/code/browser/tests/test_branchmergeproposal.py 2009-11-18 00:28:15 +0000 | |||
78 | @@ -7,10 +7,11 @@ | |||
79 | 7 | 7 | ||
80 | 8 | __metaclass__ = type | 8 | __metaclass__ = type |
81 | 9 | 9 | ||
83 | 10 | from datetime import timedelta | 10 | from datetime import datetime, timedelta |
84 | 11 | from difflib import unified_diff | 11 | from difflib import unified_diff |
85 | 12 | import unittest | 12 | import unittest |
86 | 13 | 13 | ||
87 | 14 | import pytz | ||
88 | 14 | import transaction | 15 | import transaction |
89 | 15 | from zope.component import getMultiAdapter | 16 | from zope.component import getMultiAdapter |
90 | 16 | from zope.security.interfaces import Unauthorized | 17 | from zope.security.interfaces import Unauthorized |
91 | @@ -66,6 +67,7 @@ | |||
92 | 66 | link = menu.add_comment() | 67 | link = menu.add_comment() |
93 | 67 | self.assertTrue(menu.add_comment().enabled) | 68 | self.assertTrue(menu.add_comment().enabled) |
94 | 68 | 69 | ||
95 | 70 | |||
96 | 69 | class TestDecoratedCodeReviewVoteReference(TestCaseWithFactory): | 71 | class TestDecoratedCodeReviewVoteReference(TestCaseWithFactory): |
97 | 70 | 72 | ||
98 | 71 | layer = DatabaseFunctionalLayer | 73 | layer = DatabaseFunctionalLayer |
99 | @@ -459,13 +461,6 @@ | |||
100 | 459 | self.bmp = self.factory.makeBranchMergeProposal(registrant=self.user) | 461 | self.bmp = self.factory.makeBranchMergeProposal(registrant=self.user) |
101 | 460 | login_person(self.user) | 462 | login_person(self.user) |
102 | 461 | 463 | ||
103 | 462 | def _createView(self): | ||
104 | 463 | # Construct the view and initialize it. | ||
105 | 464 | view = BranchMergeProposalView( | ||
106 | 465 | self.bmp, LaunchpadTestRequest()) | ||
107 | 466 | view.initialize() | ||
108 | 467 | return view | ||
109 | 468 | |||
110 | 469 | def makeTeamReview(self): | 464 | def makeTeamReview(self): |
111 | 470 | owner = self.bmp.source_branch.owner | 465 | owner = self.bmp.source_branch.owner |
112 | 471 | review_team = self.factory.makeTeam() | 466 | review_team = self.factory.makeTeam() |
113 | @@ -477,7 +472,7 @@ | |||
114 | 477 | albert = self.factory.makePerson() | 472 | albert = self.factory.makePerson() |
115 | 478 | albert.join(review.reviewer) | 473 | albert.join(review.reviewer) |
116 | 479 | login_person(albert) | 474 | login_person(albert) |
118 | 480 | view = self._createView() | 475 | view = create_initialized_view(self.bmp, '+index') |
119 | 481 | view.claim_action.success({'review_id': review.id}) | 476 | view.claim_action.success({'review_id': review.id}) |
120 | 482 | self.assertEqual(albert, review.reviewer) | 477 | self.assertEqual(albert, review.reviewer) |
121 | 483 | 478 | ||
122 | @@ -486,13 +481,13 @@ | |||
123 | 486 | review = self.makeTeamReview() | 481 | review = self.makeTeamReview() |
124 | 487 | albert = self.factory.makePerson() | 482 | albert = self.factory.makePerson() |
125 | 488 | login_person(albert) | 483 | login_person(albert) |
127 | 489 | view = self._createView() | 484 | view = create_initialized_view(self.bmp, '+index') |
128 | 490 | self.assertRaises(Unauthorized, view.claim_action.success, | 485 | self.assertRaises(Unauthorized, view.claim_action.success, |
129 | 491 | {'review_id': review.id}) | 486 | {'review_id': review.id}) |
130 | 492 | 487 | ||
131 | 493 | def test_preview_diff_text_with_no_diff(self): | 488 | def test_preview_diff_text_with_no_diff(self): |
132 | 494 | """review_diff should be None when there is no context.review_diff.""" | 489 | """review_diff should be None when there is no context.review_diff.""" |
134 | 495 | view = self._createView() | 490 | view = create_initialized_view(self.bmp, '+index') |
135 | 496 | self.assertIs(None, view.preview_diff_text) | 491 | self.assertIs(None, view.preview_diff_text) |
136 | 497 | 492 | ||
137 | 498 | def test_review_diff_utf8(self): | 493 | def test_review_diff_utf8(self): |
138 | @@ -502,8 +497,9 @@ | |||
139 | 502 | diff = StaticDiff.acquireFromText('x', 'y', diff_bytes) | 497 | diff = StaticDiff.acquireFromText('x', 'y', diff_bytes) |
140 | 503 | transaction.commit() | 498 | transaction.commit() |
141 | 504 | self.bmp.review_diff = diff | 499 | self.bmp.review_diff = diff |
142 | 500 | view = create_initialized_view(self.bmp, '+index') | ||
143 | 505 | self.assertEqual(diff_bytes.decode('utf-8'), | 501 | self.assertEqual(diff_bytes.decode('utf-8'), |
145 | 506 | self._createView().preview_diff_text) | 502 | view.preview_diff_text) |
146 | 507 | 503 | ||
147 | 508 | def test_review_diff_all_chars(self): | 504 | def test_review_diff_all_chars(self): |
148 | 509 | """review_diff should work on diffs containing all possible bytes.""" | 505 | """review_diff should work on diffs containing all possible bytes.""" |
149 | @@ -512,8 +508,9 @@ | |||
150 | 512 | diff = StaticDiff.acquireFromText('x', 'y', diff_bytes) | 508 | diff = StaticDiff.acquireFromText('x', 'y', diff_bytes) |
151 | 513 | transaction.commit() | 509 | transaction.commit() |
152 | 514 | self.bmp.review_diff = diff | 510 | self.bmp.review_diff = diff |
153 | 511 | view = create_initialized_view(self.bmp, '+index') | ||
154 | 515 | self.assertEqual(diff_bytes.decode('windows-1252', 'replace'), | 512 | self.assertEqual(diff_bytes.decode('windows-1252', 'replace'), |
156 | 516 | self._createView().preview_diff_text) | 513 | view.preview_diff_text) |
157 | 517 | 514 | ||
158 | 518 | def addReviewDiff(self): | 515 | def addReviewDiff(self): |
159 | 519 | review_diff_bytes = ''.join(unified_diff('', 'review')) | 516 | review_diff_bytes = ''.join(unified_diff('', 'review')) |
160 | @@ -532,27 +529,31 @@ | |||
161 | 532 | def test_preview_diff_prefers_preview_diff(self): | 529 | def test_preview_diff_prefers_preview_diff(self): |
162 | 533 | """The preview will be used for BMP with both a review and preview.""" | 530 | """The preview will be used for BMP with both a review and preview.""" |
163 | 534 | preview_diff = self.addBothDiffs() | 531 | preview_diff = self.addBothDiffs() |
165 | 535 | self.assertEqual(preview_diff, self._createView().preview_diff) | 532 | view = create_initialized_view(self.bmp, '+index') |
166 | 533 | self.assertEqual(preview_diff, view.preview_diff) | ||
167 | 536 | 534 | ||
168 | 537 | def test_preview_diff_uses_review_diff(self): | 535 | def test_preview_diff_uses_review_diff(self): |
169 | 538 | """The review diff will be used if there is no preview.""" | 536 | """The review diff will be used if there is no preview.""" |
170 | 539 | review_diff = self.addReviewDiff() | 537 | review_diff = self.addReviewDiff() |
171 | 538 | view = create_initialized_view(self.bmp, '+index') | ||
172 | 540 | self.assertEqual(review_diff.diff, | 539 | self.assertEqual(review_diff.diff, |
174 | 541 | self._createView().preview_diff) | 540 | view.preview_diff) |
175 | 542 | 541 | ||
176 | 543 | def test_review_diff_text_prefers_preview_diff(self): | 542 | def test_review_diff_text_prefers_preview_diff(self): |
177 | 544 | """The preview will be used for BMP with both a review and preview.""" | 543 | """The preview will be used for BMP with both a review and preview.""" |
178 | 545 | preview_diff = self.addBothDiffs() | 544 | preview_diff = self.addBothDiffs() |
179 | 546 | transaction.commit() | 545 | transaction.commit() |
180 | 546 | view = create_initialized_view(self.bmp, '+index') | ||
181 | 547 | self.assertEqual( | 547 | self.assertEqual( |
183 | 548 | preview_diff.text, self._createView().preview_diff_text) | 548 | preview_diff.text, view.preview_diff_text) |
184 | 549 | 549 | ||
185 | 550 | def test_linked_bugs_excludes_mutual_bugs(self): | 550 | def test_linked_bugs_excludes_mutual_bugs(self): |
186 | 551 | """List bugs that are linked to the source only.""" | 551 | """List bugs that are linked to the source only.""" |
187 | 552 | bug = self.factory.makeBug() | 552 | bug = self.factory.makeBug() |
188 | 553 | self.bmp.source_branch.linkBug(bug, self.bmp.registrant) | 553 | self.bmp.source_branch.linkBug(bug, self.bmp.registrant) |
189 | 554 | self.bmp.target_branch.linkBug(bug, self.bmp.registrant) | 554 | self.bmp.target_branch.linkBug(bug, self.bmp.registrant) |
191 | 555 | self.assertEqual([], self._createView().linked_bugs) | 555 | view = create_initialized_view(self.bmp, '+index') |
192 | 556 | self.assertEqual([], view.linked_bugs) | ||
193 | 556 | 557 | ||
194 | 557 | 558 | ||
195 | 558 | class TestBranchMergeProposalChangeStatusOptions(TestCaseWithFactory): | 559 | class TestBranchMergeProposalChangeStatusOptions(TestCaseWithFactory): |
196 | @@ -692,5 +693,42 @@ | |||
197 | 692 | self.assertEqual(u'\u2615', diff_attachment.diff_text) | 693 | self.assertEqual(u'\u2615', diff_attachment.diff_text) |
198 | 693 | 694 | ||
199 | 694 | 695 | ||
200 | 696 | class TestBranchMergeCandidateView(TestCaseWithFactory): | ||
201 | 697 | """Test the status title for the view.""" | ||
202 | 698 | |||
203 | 699 | layer = DatabaseFunctionalLayer | ||
204 | 700 | |||
205 | 701 | def test_needs_review_title(self): | ||
206 | 702 | # No title is set for a proposal needing review. | ||
207 | 703 | bmp = self.factory.makeBranchMergeProposal( | ||
208 | 704 | set_state=BranchMergeProposalStatus.NEEDS_REVIEW) | ||
209 | 705 | view = create_initialized_view(bmp, '+link-summary') | ||
210 | 706 | self.assertEqual('', view.status_title) | ||
211 | 707 | |||
212 | 708 | def test_approved_shows_reviewer(self): | ||
213 | 709 | # If the proposal is approved, the approver is shown in the title | ||
214 | 710 | # along with when they approved it. | ||
215 | 711 | bmp = self.factory.makeBranchMergeProposal() | ||
216 | 712 | owner = bmp.target_branch.owner | ||
217 | 713 | login_person(bmp.target_branch.owner) | ||
218 | 714 | owner.displayname = 'Eric' | ||
219 | 715 | bmp.approveBranch(owner, 'some-rev', datetime( | ||
220 | 716 | year=2008, month=9, day=10, tzinfo=pytz.UTC)) | ||
221 | 717 | view = create_initialized_view(bmp, '+link-summary') | ||
222 | 718 | self.assertEqual('Eric on 2008-09-10', view.status_title) | ||
223 | 719 | |||
224 | 720 | def test_rejected_shows_reviewer(self): | ||
225 | 721 | # If the proposal is rejected, the approver is shown in the title | ||
226 | 722 | # along with when they approved it. | ||
227 | 723 | bmp = self.factory.makeBranchMergeProposal() | ||
228 | 724 | owner = bmp.target_branch.owner | ||
229 | 725 | login_person(bmp.target_branch.owner) | ||
230 | 726 | owner.displayname = 'Eric' | ||
231 | 727 | bmp.rejectBranch(owner, 'some-rev', datetime( | ||
232 | 728 | year=2008, month=9, day=10, tzinfo=pytz.UTC)) | ||
233 | 729 | view = create_initialized_view(bmp, '+link-summary') | ||
234 | 730 | self.assertEqual('Eric on 2008-09-10', view.status_title) | ||
235 | 731 | |||
236 | 732 | |||
237 | 695 | def test_suite(): | 733 | def test_suite(): |
238 | 696 | return unittest.TestLoader().loadTestsFromName(__name__) | 734 | return unittest.TestLoader().loadTestsFromName(__name__) |
239 | 697 | 735 | ||
240 | === modified file 'lib/lp/code/model/branchmergeproposal.py' | |||
241 | --- lib/lp/code/model/branchmergeproposal.py 2009-10-05 14:17:48 +0000 | |||
242 | +++ lib/lp/code/model/branchmergeproposal.py 2009-11-18 00:28:15 +0000 | |||
243 | @@ -361,7 +361,8 @@ | |||
244 | 361 | # or superseded, then it is valid to be merged. | 361 | # or superseded, then it is valid to be merged. |
245 | 362 | return (self.queue_status not in FINAL_STATES) | 362 | return (self.queue_status not in FINAL_STATES) |
246 | 363 | 363 | ||
248 | 364 | def _reviewProposal(self, reviewer, next_state, revision_id): | 364 | def _reviewProposal(self, reviewer, next_state, revision_id, |
249 | 365 | _date_reviewed=None): | ||
250 | 365 | """Set the proposal to one of the two review statuses.""" | 366 | """Set the proposal to one of the two review statuses.""" |
251 | 366 | # Check the reviewer can review the code for the target branch. | 367 | # Check the reviewer can review the code for the target branch. |
252 | 367 | old_state = self.queue_status | 368 | old_state = self.queue_status |
253 | @@ -371,21 +372,25 @@ | |||
254 | 371 | self._transitionToState(next_state, reviewer) | 372 | self._transitionToState(next_state, reviewer) |
255 | 372 | # Record the reviewer | 373 | # Record the reviewer |
256 | 373 | self.reviewer = reviewer | 374 | self.reviewer = reviewer |
258 | 374 | self.date_reviewed = UTC_NOW | 375 | if _date_reviewed is None: |
259 | 376 | _date_reviewed = UTC_NOW | ||
260 | 377 | self.date_reviewed = _date_reviewed | ||
261 | 375 | # Record the reviewed revision id | 378 | # Record the reviewed revision id |
262 | 376 | self.reviewed_revision_id = revision_id | 379 | self.reviewed_revision_id = revision_id |
263 | 377 | notify(BranchMergeProposalStatusChangeEvent( | 380 | notify(BranchMergeProposalStatusChangeEvent( |
264 | 378 | self, reviewer, old_state, next_state)) | 381 | self, reviewer, old_state, next_state)) |
265 | 379 | 382 | ||
267 | 380 | def approveBranch(self, reviewer, revision_id): | 383 | def approveBranch(self, reviewer, revision_id, _date_reviewed=None): |
268 | 381 | """See `IBranchMergeProposal`.""" | 384 | """See `IBranchMergeProposal`.""" |
269 | 382 | self._reviewProposal( | 385 | self._reviewProposal( |
271 | 383 | reviewer, BranchMergeProposalStatus.CODE_APPROVED, revision_id) | 386 | reviewer, BranchMergeProposalStatus.CODE_APPROVED, revision_id, |
272 | 387 | _date_reviewed) | ||
273 | 384 | 388 | ||
275 | 385 | def rejectBranch(self, reviewer, revision_id): | 389 | def rejectBranch(self, reviewer, revision_id, _date_reviewed=None): |
276 | 386 | """See `IBranchMergeProposal`.""" | 390 | """See `IBranchMergeProposal`.""" |
277 | 387 | self._reviewProposal( | 391 | self._reviewProposal( |
279 | 388 | reviewer, BranchMergeProposalStatus.REJECTED, revision_id) | 392 | reviewer, BranchMergeProposalStatus.REJECTED, revision_id, |
280 | 393 | _date_reviewed) | ||
281 | 389 | 394 | ||
282 | 390 | def enqueue(self, queuer, revision_id): | 395 | def enqueue(self, queuer, revision_id): |
283 | 391 | """See `IBranchMergeProposal`.""" | 396 | """See `IBranchMergeProposal`.""" |
284 | 392 | 397 | ||
285 | === modified file 'lib/lp/code/stories/branches/xx-branch-merge-proposals.txt' | |||
286 | --- lib/lp/code/stories/branches/xx-branch-merge-proposals.txt 2009-10-28 19:31:47 +0000 | |||
287 | +++ lib/lp/code/stories/branches/xx-branch-merge-proposals.txt 2009-11-18 00:28:15 +0000 | |||
288 | @@ -29,6 +29,8 @@ | |||
289 | 29 | >>> _unused = branch.subscribe(subscriber, | 29 | >>> _unused = branch.subscribe(subscriber, |
290 | 30 | ... BranchSubscriptionNotificationLevel.NOEMAIL, None, | 30 | ... BranchSubscriptionNotificationLevel.NOEMAIL, None, |
291 | 31 | ... CodeReviewNotificationLevel.FULL) | 31 | ... CodeReviewNotificationLevel.FULL) |
292 | 32 | >>> from lp.code.tests.helpers import make_erics_fooix_project | ||
293 | 33 | >>> locals().update(make_erics_fooix_project(factory)) | ||
294 | 32 | >>> logout() | 34 | >>> logout() |
295 | 33 | 35 | ||
296 | 34 | Any logged in user can register a merge proposal. Registering | 36 | Any logged in user can register a merge proposal. Registering |
297 | @@ -68,7 +70,8 @@ | |||
298 | 68 | 70 | ||
299 | 69 | Registering the merge proposal takes the user to the new merge proposal. | 71 | Registering the merge proposal takes the user to the new merge proposal. |
300 | 70 | 72 | ||
302 | 71 | >>> print nopriv_browser.url | 73 | >>> klingon_proposal = nopriv_browser.url |
303 | 74 | >>> print klingon_proposal | ||
304 | 72 | http://code.launchpad.dev/~name12/gnome-terminal/klingon/+merge/... | 75 | http://code.launchpad.dev/~name12/gnome-terminal/klingon/+merge/... |
305 | 73 | 76 | ||
306 | 74 | The summary reflects the selected target and prerequisite. | 77 | The summary reflects the selected target and prerequisite. |
307 | @@ -97,9 +100,6 @@ | |||
308 | 97 | ... 'Add more <b>mojo</b>') | 100 | ... 'Add more <b>mojo</b>') |
309 | 98 | >>> nopriv_browser.getControl('Update').click() | 101 | >>> nopriv_browser.getControl('Update').click() |
310 | 99 | 102 | ||
311 | 100 | >>> print nopriv_browser.url | ||
312 | 101 | http://code.launchpad.dev/~name12/gnome-terminal/klingon/+merge/1 | ||
313 | 102 | |||
314 | 103 | >>> print_tag_with_id(nopriv_browser.contents, 'edit-description') | 103 | >>> print_tag_with_id(nopriv_browser.contents, 'edit-description') |
315 | 104 | Commit Message | 104 | Commit Message |
316 | 105 | Add more <b>mojo</b> | 105 | Add more <b>mojo</b> |
317 | @@ -113,7 +113,6 @@ | |||
318 | 113 | for the source_branch. | 113 | for the source_branch. |
319 | 114 | 114 | ||
320 | 115 | >>> login('foo.bar@canonical.com') | 115 | >>> login('foo.bar@canonical.com') |
321 | 116 | >>> eric = factory.makePerson(email="eric@example.com", password="test") | ||
322 | 117 | >>> bmp = factory.makeBranchMergeProposal(registrant=eric) | 116 | >>> bmp = factory.makeBranchMergeProposal(registrant=eric) |
323 | 118 | >>> bmp_url = canonical_url(bmp) | 117 | >>> bmp_url = canonical_url(bmp) |
324 | 119 | >>> branch_url = canonical_url(bmp.source_branch) | 118 | >>> branch_url = canonical_url(bmp.source_branch) |
325 | @@ -128,14 +127,13 @@ | |||
326 | 128 | 127 | ||
327 | 129 | >>> sample_browser = setupBrowser(auth="Basic test@canonical.com:test") | 128 | >>> sample_browser = setupBrowser(auth="Basic test@canonical.com:test") |
328 | 130 | 129 | ||
329 | 130 | |||
330 | 131 | Requesting reviews | 131 | Requesting reviews |
331 | 132 | ------------------ | 132 | ------------------ |
332 | 133 | 133 | ||
333 | 134 | You can request a review of a merge proposal. | 134 | You can request a review of a merge proposal. |
334 | 135 | 135 | ||
338 | 136 | >>> sample_browser.open( | 136 | >>> sample_browser.open(klingon_proposal) |
336 | 137 | ... 'http://code.launchpad.dev/~name12/gnome-terminal/klingon/+merge/1' | ||
337 | 138 | ... ) | ||
339 | 139 | >>> sample_browser.getLink('Request a review').click() | 137 | >>> sample_browser.getLink('Request a review').click() |
340 | 140 | >>> sample_browser.getControl('Reviewer').value = 'mark' | 138 | >>> sample_browser.getControl('Reviewer').value = 'mark' |
341 | 141 | >>> sample_browser.getControl('Review type').value = 'first' | 139 | >>> sample_browser.getControl('Review type').value = 'first' |
342 | @@ -169,7 +167,7 @@ | |||
343 | 169 | Reviewer Review Type Date Requested Status | 167 | Reviewer Review Type Date Requested Status |
344 | 170 | Sample Person Pending [Review] | 168 | Sample Person Pending [Review] |
345 | 171 | Mark Shuttleworth second ... ago Pending | 169 | Mark Shuttleworth second ... ago Pending |
347 | 172 | Review via email: mp+1@code.launchpad.dev | 170 | Review via email: mp+...@code.launchpad.dev |
348 | 173 | Request another review | 171 | Request another review |
349 | 174 | 172 | ||
350 | 175 | 173 | ||
351 | @@ -178,16 +176,14 @@ | |||
352 | 178 | 176 | ||
353 | 179 | People not logged in cannot perform reviews. | 177 | People not logged in cannot perform reviews. |
354 | 180 | 178 | ||
357 | 181 | >>> anon_browser.open('http://code.launchpad.dev/~name12/gnome-terminal' | 179 | >>> anon_browser.open(klingon_proposal) |
356 | 182 | ... '/klingon/+merge/1') | ||
358 | 183 | >>> link = anon_browser.getLink('[Review]') | 180 | >>> link = anon_browser.getLink('[Review]') |
359 | 184 | Traceback (most recent call last): | 181 | Traceback (most recent call last): |
360 | 185 | LinkNotFoundError | 182 | LinkNotFoundError |
361 | 186 | 183 | ||
362 | 187 | People who are logged in can perform reviews. | 184 | People who are logged in can perform reviews. |
363 | 188 | 185 | ||
366 | 189 | >>> nopriv_browser.open('http://code.launchpad.dev/~name12/gnome-terminal' | 186 | >>> nopriv_browser.open(klingon_proposal) |
365 | 190 | ... '/klingon/+merge/1') | ||
367 | 191 | >>> nopriv_browser.getLink('Add a review or comment').click() | 187 | >>> nopriv_browser.getLink('Add a review or comment').click() |
368 | 192 | >>> nopriv_browser.getControl(name='field.comment').value = "Don't like it" | 188 | >>> nopriv_browser.getControl(name='field.comment').value = "Don't like it" |
369 | 193 | >>> nopriv_browser.getControl(name='field.vote').getControl( | 189 | >>> nopriv_browser.getControl(name='field.vote').getControl( |
370 | @@ -201,8 +197,7 @@ | |||
371 | 201 | 197 | ||
372 | 202 | People can claim reviews for teams of which they are a member. | 198 | People can claim reviews for teams of which they are a member. |
373 | 203 | 199 | ||
376 | 204 | >>> sample_browser.open('http://code.launchpad.dev/~name12/gnome-terminal' | 200 | >>> sample_browser.open(klingon_proposal) |
375 | 205 | ... '/klingon/+merge/1') | ||
377 | 206 | >>> sample_browser.getLink('Request another review').click() | 201 | >>> sample_browser.getLink('Request another review').click() |
378 | 207 | >>> sample_browser.getControl('Reviewer').value = 'hwdb-team' | 202 | >>> sample_browser.getControl('Reviewer').value = 'hwdb-team' |
379 | 208 | >>> sample_browser.getControl('Review type').value = 'claimable' | 203 | >>> sample_browser.getControl('Review type').value = 'claimable' |
380 | @@ -213,8 +208,7 @@ | |||
381 | 213 | Reviewer Review Type Date Requested Status... | 208 | Reviewer Review Type Date Requested Status... |
382 | 214 | HWDB Team claimable ... ago Pending ... | 209 | HWDB Team claimable ... ago Pending ... |
383 | 215 | >>> foobar_browser = setupBrowser(auth="Basic foo.bar@canonical.com:test") | 210 | >>> foobar_browser = setupBrowser(auth="Basic foo.bar@canonical.com:test") |
386 | 216 | >>> foobar_browser.open('http://code.launchpad.dev/~name12/gnome-terminal' | 211 | >>> foobar_browser.open(klingon_proposal) |
385 | 217 | ... '/klingon/+merge/1') | ||
387 | 218 | >>> foobar_browser.getControl('Claim review').click() | 212 | >>> foobar_browser.getControl('Claim review').click() |
388 | 219 | >>> pending = find_tag_by_id( | 213 | >>> pending = find_tag_by_id( |
389 | 220 | ... foobar_browser.contents, 'code-review-votes') | 214 | ... foobar_browser.contents, 'code-review-votes') |
390 | @@ -230,8 +224,7 @@ | |||
391 | 230 | >>> foobar_browser.getLink('Reassign').click() | 224 | >>> foobar_browser.getLink('Reassign').click() |
392 | 231 | >>> foobar_browser.getControl('Reviewer').value = 'hwdb-team' | 225 | >>> foobar_browser.getControl('Reviewer').value = 'hwdb-team' |
393 | 232 | >>> foobar_browser.getControl('Reassign').click() | 226 | >>> foobar_browser.getControl('Reassign').click() |
396 | 233 | >>> foobar_browser.open('http://code.launchpad.dev/~name12/gnome-terminal' | 227 | >>> foobar_browser.open(klingon_proposal) |
395 | 234 | ... '/klingon/+merge/1') | ||
397 | 235 | >>> pending = find_tag_by_id( | 228 | >>> pending = find_tag_by_id( |
398 | 236 | ... foobar_browser.contents, 'code-review-votes') | 229 | ... foobar_browser.contents, 'code-review-votes') |
399 | 237 | 230 | ||
400 | @@ -248,8 +241,7 @@ | |||
401 | 248 | When a branch has been merged into the target branch, the proposal should | 241 | When a branch has been merged into the target branch, the proposal should |
402 | 249 | be marked as merged. | 242 | be marked as merged. |
403 | 250 | 243 | ||
406 | 251 | >>> nopriv_browser.open( | 244 | >>> nopriv_browser.open(klingon_proposal) |
405 | 252 | ... 'http://code.launchpad.dev/~name12/gnome-terminal/klingon/+merge/1') | ||
407 | 253 | 245 | ||
408 | 254 | The edit icon at the end of the status allows the user to edit the status. | 246 | The edit icon at the end of the status allows the user to edit the status. |
409 | 255 | 247 | ||
410 | @@ -264,8 +256,6 @@ | |||
411 | 264 | >>> nopriv_browser.getControl(name='field.queue_status').displayValue = ( | 256 | >>> nopriv_browser.getControl(name='field.queue_status').displayValue = ( |
412 | 265 | ... ['Merged']) | 257 | ... ['Merged']) |
413 | 266 | >>> nopriv_browser.getControl('Change Status').click() | 258 | >>> nopriv_browser.getControl('Change Status').click() |
414 | 267 | >>> print nopriv_browser.url | ||
415 | 268 | http://code.launchpad.dev/~name12/gnome-terminal/klingon/+merge/1 | ||
416 | 269 | 259 | ||
417 | 270 | The proposal is now shown as have being merged. | 260 | The proposal is now shown as have being merged. |
418 | 271 | 261 | ||
419 | @@ -282,6 +272,7 @@ | |||
420 | 282 | >>> print extract_text(find_tag_by_id( | 272 | >>> print extract_text(find_tag_by_id( |
421 | 283 | ... sample_browser.contents, 'landing-targets')) | 273 | ... sample_browser.contents, 'landing-targets')) |
422 | 284 | Merged into lp://dev/~name12/gnome-terminal/main | 274 | Merged into lp://dev/~name12/gnome-terminal/main |
423 | 275 | ... | ||
424 | 285 | >>> sample_browser.getLink('Merged').click() | 276 | >>> sample_browser.getLink('Merged').click() |
425 | 286 | >>> print_summary(sample_browser) | 277 | >>> print_summary(sample_browser) |
426 | 287 | Status: Merged | 278 | Status: Merged |
427 | @@ -303,6 +294,7 @@ | |||
428 | 303 | >>> print extract_text(find_tag_by_id( | 294 | >>> print extract_text(find_tag_by_id( |
429 | 304 | ... sample_browser.contents, 'landing-targets')) | 295 | ... sample_browser.contents, 'landing-targets')) |
430 | 305 | Merged into lp://dev/~name12/gnome-terminal/main at revision 42 | 296 | Merged into lp://dev/~name12/gnome-terminal/main at revision 42 |
431 | 297 | ... | ||
432 | 306 | 298 | ||
433 | 307 | 299 | ||
434 | 308 | Resubmitting proposals | 300 | Resubmitting proposals |
435 | @@ -315,9 +307,7 @@ | |||
436 | 315 | branches but with the state set to work-in-progress. | 307 | branches but with the state set to work-in-progress. |
437 | 316 | 308 | ||
438 | 317 | >>> login('foo.bar@canonical.com') | 309 | >>> login('foo.bar@canonical.com') |
442 | 318 | >>> fooix = factory.makeProduct(name='fooix') | 310 | >>> bmp = factory.makeBranchMergeProposal(target_branch=trunk) |
440 | 319 | >>> target = factory.makeProductBranch(product=fooix, owner=eric) | ||
441 | 320 | >>> bmp = factory.makeBranchMergeProposal(target_branch=target) | ||
443 | 321 | >>> bmp_url = canonical_url(bmp) | 311 | >>> bmp_url = canonical_url(bmp) |
444 | 322 | >>> logout() | 312 | >>> logout() |
445 | 323 | >>> eric_browser.open(bmp_url) | 313 | >>> eric_browser.open(bmp_url) |
446 | @@ -538,7 +528,6 @@ | |||
447 | 538 | Bug #...: Bug for linking (Undecided – New) | 528 | Bug #...: Bug for linking (Undecided – New) |
448 | 539 | 529 | ||
449 | 540 | 530 | ||
450 | 541 | |||
451 | 542 | Target branch edge cases | 531 | Target branch edge cases |
452 | 543 | ------------------------ | 532 | ------------------------ |
453 | 544 | 533 | ||
454 | @@ -626,3 +615,27 @@ | |||
455 | 626 | >>> print extract_text(get_review_diff()) | 615 | >>> print extract_text(get_review_diff()) |
456 | 627 | Preview Diff | 616 | Preview Diff |
457 | 628 | Empty | 617 | Empty |
458 | 618 | |||
459 | 619 | |||
460 | 620 | Merge proposal details shown on the branch page | ||
461 | 621 | ----------------------------------------------- | ||
462 | 622 | |||
463 | 623 | A branch that has a merge proposal, but no requested reviews shows this on the | ||
464 | 624 | branch page. | ||
465 | 625 | |||
466 | 626 | >>> nopriv_browser.open('http://code.launchpad.dev/~fred/fooix/feature') | ||
467 | 627 | >>> nopriv_browser.getLink('Propose for merging').click() | ||
468 | 628 | >>> nopriv_browser.getControl('Reviewer').value = '' | ||
469 | 629 | >>> nopriv_browser.getControl('Propose Merge').click() | ||
470 | 630 | >>> nopriv_browser.getLink('lp://dev/~fred/fooix/feature').click() | ||
471 | 631 | >>> print_tag_with_id(nopriv_browser.contents, 'landing-targets') | ||
472 | 632 | Ready for review for merging into lp://dev/fooix | ||
473 | 633 | No reviews requested | ||
474 | 634 | |||
475 | 635 | If there are reviews either pending or completed these are also shown. | ||
476 | 636 | |||
477 | 637 | >>> nopriv_browser.open('http://code.launchpad.dev/~fred/fooix/proposed') | ||
478 | 638 | >>> print_tag_with_id(nopriv_browser.contents, 'landing-targets') | ||
479 | 639 | Ready for review for merging into lp://dev/fooix | ||
480 | 640 | Eric the Viking: Pending (code) requested ... ago | ||
481 | 641 | Diff: 47 lines | ||
482 | 629 | 642 | ||
483 | === modified file 'lib/lp/code/templates/branch-index.pt' | |||
484 | --- lib/lp/code/templates/branch-index.pt 2009-10-11 02:33:30 +0000 | |||
485 | +++ lib/lp/code/templates/branch-index.pt 2009-11-18 00:28:15 +0000 | |||
486 | @@ -25,6 +25,10 @@ | |||
487 | 25 | #download-url dd span.branch-url, #upload-url dd span.branch-url { | 25 | #download-url dd span.branch-url, #upload-url dd span.branch-url { |
488 | 26 | font-weight: normal; | 26 | font-weight: normal; |
489 | 27 | } | 27 | } |
490 | 28 | dl.reviews dd { | ||
491 | 29 | padding-left: 2em; | ||
492 | 30 | margin-bottom: 0; | ||
493 | 31 | } | ||
494 | 28 | 32 | ||
495 | 29 | </style> | 33 | </style> |
496 | 30 | <script type="text/javascript" | 34 | <script type="text/javascript" |
497 | 31 | 35 | ||
498 | === modified file 'lib/lp/code/templates/branch-pending-merges.pt' | |||
499 | --- lib/lp/code/templates/branch-pending-merges.pt 2009-09-18 21:20:42 +0000 | |||
500 | +++ lib/lp/code/templates/branch-pending-merges.pt 2009-11-18 00:28:15 +0000 | |||
501 | @@ -36,6 +36,7 @@ | |||
502 | 36 | <div> | 36 | <div> |
503 | 37 | <tal:merge-fragment tal:replace="structure mergeproposal/@@+link-summary" /> | 37 | <tal:merge-fragment tal:replace="structure mergeproposal/@@+link-summary" /> |
504 | 38 | </div> | 38 | </div> |
505 | 39 | <tal:merge-fragment tal:replace="structure mergeproposal/@@+vote-summary" /> | ||
506 | 39 | </tal:landing-candidates> | 40 | </tal:landing-candidates> |
507 | 40 | </div> | 41 | </div> |
508 | 41 | 42 | ||
509 | 42 | 43 | ||
510 | === renamed file 'lib/lp/code/templates/branch-merge-link-summary.pt' => 'lib/lp/code/templates/branchmergeproposal-link-summary.pt' | |||
511 | --- lib/lp/code/templates/branch-merge-link-summary.pt 2009-09-22 16:31:42 +0000 | |||
512 | +++ lib/lp/code/templates/branchmergeproposal-link-summary.pt 2009-11-18 00:28:15 +0000 | |||
513 | @@ -4,7 +4,8 @@ | |||
514 | 4 | xmlns:i18n="http://xml.zope.org/namespaces/i18n"> | 4 | xmlns:i18n="http://xml.zope.org/namespaces/i18n"> |
515 | 5 | 5 | ||
516 | 6 | <img src="/@@/merge-proposal-icon" /> | 6 | <img src="/@@/merge-proposal-icon" /> |
518 | 7 | <a tal:attributes="href context/fmt:url" | 7 | <a tal:attributes="href context/fmt:url; |
519 | 8 | title view/status_title" | ||
520 | 8 | tal:content="view/friendly_text">Approved</a> | 9 | tal:content="view/friendly_text">Approved</a> |
521 | 9 | <tal:for-merging condition="not: context/queue_status/enumvalue:MERGED"> | 10 | <tal:for-merging condition="not: context/queue_status/enumvalue:MERGED"> |
522 | 10 | for merging | 11 | for merging |
523 | 11 | 12 | ||
524 | === added file 'lib/lp/code/templates/branchmergeproposal-vote-summary.pt' | |||
525 | --- lib/lp/code/templates/branchmergeproposal-vote-summary.pt 1970-01-01 00:00:00 +0000 | |||
526 | +++ lib/lp/code/templates/branchmergeproposal-vote-summary.pt 2009-11-18 00:28:15 +0000 | |||
527 | @@ -0,0 +1,49 @@ | |||
528 | 1 | <tal:root | ||
529 | 2 | xmlns:tal="http://xml.zope.org/namespaces/tal" | ||
530 | 3 | xmlns:metal="http://xml.zope.org/namespaces/metal" | ||
531 | 4 | xmlns:i18n="http://xml.zope.org/namespaces/i18n"> | ||
532 | 5 | |||
533 | 6 | <tal:comment condition="nothing"> | ||
534 | 7 | <!-- | ||
535 | 8 | Yet again we are bitten by white space issues, so some tags in this | ||
536 | 9 | template have closing brackets on following lines, and not breaks | ||
537 | 10 | between some tags. | ||
538 | 11 | --> | ||
539 | 12 | </tal:comment> | ||
540 | 13 | |||
541 | 14 | <dl class="reviews"> | ||
542 | 15 | <dd tal:condition="not: view/reviews"> | ||
543 | 16 | No reviews requested | ||
544 | 17 | </dd> | ||
545 | 18 | <dd tal:repeat="review view/current_reviews"> | ||
546 | 19 | <tal:reviewer replace="structure review/reviewer/fmt:link:mainsite"> | ||
547 | 20 | Eric the Reviewer</tal:reviewer | ||
548 | 21 | ><tal:community condition="not: review/trusted"> | ||
549 | 22 | (community)</tal:community>: | ||
550 | 23 | <span tal:attributes="class string:vote${review/comment/vote/name}" | ||
551 | 24 | tal:content="review/status_text"> | ||
552 | 25 | Approved | ||
553 | 26 | </span> | ||
554 | 27 | <tal:vote-tags condition="review/review_type_str"> | ||
555 | 28 | (<tal:tag replace="review/review_type_str"/>) | ||
556 | 29 | </tal:vote-tags> | ||
557 | 30 | <tal:date replace="review/date_of_comment/fmt:displaydate" /> | ||
558 | 31 | </dd> | ||
559 | 32 | <dd tal:repeat="review view/requested_reviews" | ||
560 | 33 | tal:attributes="id string:review-${review/reviewer/name}"> | ||
561 | 34 | <tal:reviewer | ||
562 | 35 | tal:replace="structure review/reviewer/fmt:link:mainsite" />: | ||
563 | 36 | |||
564 | 37 | <span class="votePENDING">Pending</span> | ||
565 | 38 | <tal:vote-tags condition="review/review_type_str"> | ||
566 | 39 | (<tal:tag replace="review/review_type_str"/>) | ||
567 | 40 | </tal:vote-tags> | ||
568 | 41 | requested | ||
569 | 42 | <tal:date replace="review/date_requested/fmt:approximatedate"/> | ||
570 | 43 | </dd> | ||
571 | 44 | <dd tal:condition="context/preview_diff"> | ||
572 | 45 | Diff: <tal:diff replace="structure context/preview_diff/fmt:link"/> | ||
573 | 46 | </dd> | ||
574 | 47 | |||
575 | 48 | </dl> | ||
576 | 49 | </tal:root> | ||
577 | 0 | 50 | ||
578 | === modified file 'lib/lp/code/tests/helpers.py' | |||
579 | --- lib/lp/code/tests/helpers.py 2009-10-26 18:40:04 +0000 | |||
580 | +++ lib/lp/code/tests/helpers.py 2009-11-18 00:28:15 +0000 | |||
581 | @@ -6,10 +6,12 @@ | |||
582 | 6 | __metaclass__ = type | 6 | __metaclass__ = type |
583 | 7 | __all__ = [ | 7 | __all__ = [ |
584 | 8 | 'make_linked_package_branch', | 8 | 'make_linked_package_branch', |
585 | 9 | 'make_erics_fooix_project', | ||
586 | 9 | ] | 10 | ] |
587 | 10 | 11 | ||
588 | 11 | 12 | ||
589 | 12 | from datetime import timedelta | 13 | from datetime import timedelta |
590 | 14 | from difflib import unified_diff | ||
591 | 13 | from itertools import count | 15 | from itertools import count |
592 | 14 | 16 | ||
593 | 15 | from zope.component import getUtility | 17 | from zope.component import getUtility |
594 | @@ -23,6 +25,46 @@ | |||
595 | 23 | from lp.testing import time_counter | 25 | from lp.testing import time_counter |
596 | 24 | 26 | ||
597 | 25 | 27 | ||
598 | 28 | def make_erics_fooix_project(factory): | ||
599 | 29 | """Make Eric, the Fooix project, and some branches. | ||
600 | 30 | |||
601 | 31 | :return: a dict of objects to put into local scope. | ||
602 | 32 | """ | ||
603 | 33 | result = {} | ||
604 | 34 | eric = factory.makePerson( | ||
605 | 35 | name='eric', displayname='Eric the Viking', | ||
606 | 36 | email='eric@example.com', password='test') | ||
607 | 37 | fooix = factory.makeProduct( | ||
608 | 38 | name='fooix', displayname='Fooix', owner=eric) | ||
609 | 39 | trunk = factory.makeProductBranch( | ||
610 | 40 | owner=eric, product=fooix, name='trunk') | ||
611 | 41 | removeSecurityProxy(fooix.development_focus).branch = trunk | ||
612 | 42 | # Development is done by Fred. | ||
613 | 43 | fred = factory.makePerson( | ||
614 | 44 | name='fred', displayname='Fred Flintstone', | ||
615 | 45 | email='fred@example.com', password='test') | ||
616 | 46 | feature = factory.makeProductBranch( | ||
617 | 47 | owner=fred, product=fooix, name='feature') | ||
618 | 48 | proposed = factory.makeProductBranch( | ||
619 | 49 | owner=fred, product=fooix, name='proposed') | ||
620 | 50 | bmp = proposed.addLandingTarget( | ||
621 | 51 | registrant=fred, target_branch=trunk, needs_review=True, | ||
622 | 52 | review_requests=[(eric, 'code')]) | ||
623 | 53 | # And fake a diff. | ||
624 | 54 | naked_bmp = removeSecurityProxy(bmp) | ||
625 | 55 | preview = removeSecurityProxy(bmp.updatePreviewDiff( | ||
626 | 56 | ''.join(unified_diff('', 'random content')), u'rev-a', u'rev-b')) | ||
627 | 57 | naked_bmp.source_branch.last_scanned_id = preview.source_revision_id | ||
628 | 58 | naked_bmp.target_branch.last_scanned_id = preview.target_revision_id | ||
629 | 59 | preview.diff_lines_count = 47 | ||
630 | 60 | preview.added_lines_count = 7 | ||
631 | 61 | preview.remvoed_lines_count = 13 | ||
632 | 62 | preview.diffstat = {'file1': (3, 8), 'file2': (4, 5)} | ||
633 | 63 | return { | ||
634 | 64 | 'eric': eric, 'fooix': fooix, 'trunk':trunk, 'feature': feature, | ||
635 | 65 | 'proposed': proposed, 'fred': fred} | ||
636 | 66 | |||
637 | 67 | |||
638 | 26 | def make_linked_package_branch(factory, distribution=None, | 68 | def make_linked_package_branch(factory, distribution=None, |
639 | 27 | sourcepackagename=None): | 69 | sourcepackagename=None): |
640 | 28 | """Make a new package branch and make it official.""" | 70 | """Make a new package branch and make it official.""" |
Trying the prerequisite branch bit.
This branch shows more merge proposal details on the branch page.
browser/branch.py | 1
Drive by pep-8 cleanup
browser/ branchmergeprop osal.py | 20 ++++++
Define a title for the status link based on the approver/rejecter.
browser/ configure. zcml | 15 +++--
New view, and renamed an old one to be more consistent.
browser/ tests/test_ branchmergeprop osal.py | 72 +++++++ +++++++ +++++-- ----
Cleaned up a test before I realised it was the wrong one.
Added a test for the status title in the view above.
model/ branchmergeprop osal.py | 17 +++--
This change is just adding the ability to pass the review date through to the function for better testing.
stories/ branches/ xx-branch- merge-proposals .txt | 67 +++++++ ++++++- ------- --
Move some object creation out into a helper function.
Change the explicit BMP urls to use a recorded value.
Add a section at the end to show how merge proposals look on branch pages.
templates/ branch- index.pt | 4 +
Some page based styles.
templates/ branch- pending- merges. pt | 1
Add in the vote summary.
templates/ branchmergeprop osal-link- summary. pt | 3 -
Add the title to the status anchor.
templates/ branchmergeprop osal-vote- summary. pt | 49 +++++++++++++++++
Render the details.
tests/helpers.py | 42 ++++++++++++++
Create some standard people/projects for the tests.
11 files changed, 234 insertions(+), 57 deletions(-)
This branch only has the change on the branch page, but I'm expecting to have it on the bug page as well in a follow on branch.