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

Proposed by Aaron Bentley
Status: Merged
Merged at revision: not available
Proposed branch: lp:~abentley/launchpad/reassign
Merge into: lp:launchpad
Diff against target: None lines
To merge this branch: bzr merge lp:~abentley/launchpad/reassign
Reviewer Review Type Date Requested Status
Paul Hummer (community) Approve
Review via email: mp+9791@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Aaron Bentley (abentley) wrote :

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

 reviewer rockstar

= Summary =
This is a follow-up to my claim-review branch. Now that reviews can be
claimed, it must be possible to "un-claim" them, and being able to
reassign reviews is useful for delegation as well.

== Proposed fix ==
Provide an edit icon next to the name of the review that, when clicked,
allows the user to assign the review to someone else. Only the
registrant and the reviewer can see this icon. (But anyone who can
claim the review can claim it and then reassign it.)

== Pre-implementation notes ==
Discussion with the Code team. ui approved by beuno:
https://code.edge.launchpad.net/~abentley/launchpad/reassign/+merge/9463

== Implementation details ==
Can't think of anything unusual.

== Tests ==
bin/test -t test_branchmergeproposal -t test_codereviewvote -t
xx-branch-merge-proposals.txt

== Demo and Q/A ==
Create a branch merge proposal. Request a review. Reassign the review.

= Launchpad lint =

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

Linting changed files:
  lib/lp/code/browser/configure.zcml
  lib/canonical/launchpad/pagetitles.py
  lib/lp/code/browser/tests/test_branchmergeproposal.py
  lib/lp/code/browser/codereviewvote.py
  lib/lp/code/stories/branches/xx-branch-merge-proposals.txt
  lib/lp/code/browser/tests/test_codereviewvote.py
  lib/lp/code/browser/branchmergeproposal.py
  lib/lp/code/templates/branchmergeproposal-votes.pt
  lib/lp/code/templates/reviewrequest-reassign.pt
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkp7Hi4ACgkQ0F+nu1YWqI2xSQCeL+UTWZs872RynfCXmieBAYU1
ab0An3LZo43n6ua1D/BAXO0Z1fjP1h/8
=axSL
-----END PGP SIGNATURE-----

Revision history for this message
Paul Hummer (rockstar) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/pagetitles.py'
2--- lib/canonical/launchpad/pagetitles.py 2009-07-29 02:38:44 +0000
3+++ lib/canonical/launchpad/pagetitles.py 2009-07-29 20:56:34 +0000
4@@ -1549,6 +1549,8 @@
5 translationgroup_reassignment = ContextTitle(smartquote(
6 'Change the owner of "%s" translation group'))
7
8+reviewrequest_reassign = 'Reassign review request'
9+
10 translationgroups_index = 'Launchpad translation groups'
11
12 translationimportqueueentry_index = 'Translation import queue entry'
13
14=== modified file 'lib/lp/code/browser/branchmergeproposal.py'
15--- lib/lp/code/browser/branchmergeproposal.py 2009-08-05 14:47:07 +0000
16+++ lib/lp/code/browser/branchmergeproposal.py 2009-08-06 18:09:19 +0000
17@@ -290,6 +290,18 @@
18
19 usedfor = IBranchMergeProposal
20
21+ @stepthrough('reviews')
22+ def traverse_review(self, id):
23+ """Navigate to a CodeReviewVoteReference through its BMP."""
24+ try:
25+ id = int(id)
26+ except ValueError:
27+ return None
28+ try:
29+ return self.context.getVoteReference(id)
30+ except WrongBranchMergeProposal:
31+ return None
32+
33 @stepthrough('comments')
34 def traverse_comment(self, id):
35 try:
36@@ -467,6 +479,10 @@
37 self.user_can_claim = False
38 else:
39 self.user_can_claim = self.user_can_review
40+ if user in (context.reviewer, context.registrant):
41+ self.user_can_reassign = True
42+ else:
43+ self.user_can_reassign = False
44
45 @property
46 def show_date_requested(self):
47
48=== added file 'lib/lp/code/browser/codereviewvote.py'
49--- lib/lp/code/browser/codereviewvote.py 1970-01-01 00:00:00 +0000
50+++ lib/lp/code/browser/codereviewvote.py 2009-08-06 18:09:19 +0000
51@@ -0,0 +1,36 @@
52+# Copyright 2009 Canonical Ltd. This software is licensed under the
53+# GNU Affero General Public License version 3 (see the file LICENSE).
54+
55+
56+"""Views, navigation and actions for CodeReviewVotes."""
57+
58+
59+__metaclass__ = type
60+
61+
62+from zope.interface import Interface
63+
64+from canonical.launchpad import _
65+from canonical.launchpad.fields import PublicPersonChoice
66+from canonical.launchpad.webapp import (
67+ action, canonical_url, LaunchpadFormView)
68+
69+
70+class ReassignSchema(Interface):
71+ """Schema to use when reassigning the reviewer for a requested review."""
72+
73+ reviewer = PublicPersonChoice( title=_('Reviewer'), required=True,
74+ description=_('A person who you want to review this.'),
75+ vocabulary='ValidPersonOrTeam')
76+
77+
78+class CodeReviewVoteReassign(LaunchpadFormView):
79+ """View for reassinging the reviewer for a requested review."""
80+
81+ schema = ReassignSchema
82+
83+ @action('Reassign', name='reassign')
84+ def reassign_action(self, action, data):
85+ """Use the form data to change the review request reviewer."""
86+ self.context.reviewer = data['reviewer']
87+ self.next_url = canonical_url(self.context.branch_merge_proposal)
88
89=== modified file 'lib/lp/code/browser/configure.zcml'
90--- lib/lp/code/browser/configure.zcml 2009-07-29 02:38:44 +0000
91+++ lib/lp/code/browser/configure.zcml 2009-08-06 14:28:41 +0000
92@@ -61,6 +61,13 @@
93 path_expression="string:+review/${id}"
94 attribute_to_parent="branch_merge_proposal"
95 rootsite="code"/>
96+ <browser:page
97+ for="lp.code.interfaces.codereviewvote.ICodeReviewVoteReference"
98+ name="+reassign"
99+ class="lp.code.browser.codereviewvote.CodeReviewVoteReassign"
100+ facet="branches"
101+ permission="launchpad.AnyPerson"
102+ template="../templates/reviewrequest-reassign.pt"/>
103 <facet
104 facet="branches">
105 <browser:url
106
107=== modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py'
108--- lib/lp/code/browser/tests/test_branchmergeproposal.py 2009-08-06 17:51:02 +0000
109+++ lib/lp/code/browser/tests/test_branchmergeproposal.py 2009-08-06 18:09:19 +0000
110@@ -180,6 +180,34 @@
111 view = BranchMergeProposalVoteView(self.bmp, LaunchpadTestRequest())
112 self.assertFalse(view.requested_reviews[0].user_can_claim)
113
114+ def makeReviewRequest(self, viewer=None, registrant=None):
115+ albert = self.factory.makePerson()
116+ if registrant is None:
117+ registrant = self.bmp.source_branch.owner
118+ self._nominateReviewer(albert, registrant)
119+ if viewer is None:
120+ viewer = albert
121+ login_person(viewer)
122+ view = BranchMergeProposalVoteView(self.bmp, LaunchpadTestRequest())
123+ return view.requested_reviews[0]
124+
125+ def test_user_can_reassign_assignee(self):
126+ """The user can reassign if they are the assignee."""
127+ review_request = self.makeReviewRequest()
128+ self.assertTrue(review_request.user_can_reassign)
129+
130+ def test_user_can_reassign_registrant(self):
131+ """The user can reassign if they are the registrant."""
132+ registrant = self.factory.makePerson()
133+ review_request = self.makeReviewRequest(registrant, registrant)
134+ self.assertTrue(review_request.user_can_reassign)
135+
136+ def test_user_cannot_reassign_random_person(self):
137+ """Random people cannot reassign reviews."""
138+ viewer = self.factory.makePerson()
139+ review_request = self.makeReviewRequest(viewer)
140+ self.assertFalse(review_request.user_can_reassign)
141+
142 def testCurrentReviewOrdering(self):
143 # Most recent first.
144 # Request three reviews.
145
146=== added file 'lib/lp/code/browser/tests/test_codereviewvote.py'
147--- lib/lp/code/browser/tests/test_codereviewvote.py 1970-01-01 00:00:00 +0000
148+++ lib/lp/code/browser/tests/test_codereviewvote.py 2009-08-06 18:09:19 +0000
149@@ -0,0 +1,40 @@
150+# Copyright 2009 Canonical Ltd. This software is licensed under the
151+# GNU Affero General Public License version 3 (see the file LICENSE).
152+
153+
154+"""Unit tests for CodeReviewVoteReferences."""
155+
156+
157+__metaclass__ = type
158+
159+
160+import unittest
161+
162+from canonical.launchpad.webapp.servers import LaunchpadTestRequest
163+from canonical.testing import DatabaseFunctionalLayer
164+from lp.testing import (
165+ login_person, TestCaseWithFactory)
166+from lp.code.browser.codereviewvote import CodeReviewVoteReassign
167+
168+
169+class TestReassignReviewer(TestCaseWithFactory):
170+ """Test functionality for changing the reviewer."""
171+
172+ layer = DatabaseFunctionalLayer
173+
174+ def test_reassign(self):
175+ """A reviewer can reassign their vote to someone else."""
176+ bmp = self.factory.makeBranchMergeProposal()
177+ reviewer = self.factory.makePerson()
178+ login_person(bmp.registrant)
179+ vote = bmp.nominateReviewer(
180+ reviewer=reviewer, registrant=bmp.registrant)
181+ new_reviewer = self.factory.makePerson()
182+ login_person(reviewer)
183+ view = CodeReviewVoteReassign(vote, LaunchpadTestRequest())
184+ view.reassign_action.success({'reviewer': new_reviewer})
185+ self.assertEqual(vote.reviewer, new_reviewer)
186+
187+
188+def test_suite():
189+ return unittest.TestLoader().loadTestsFromName(__name__)
190
191=== modified file 'lib/lp/code/stories/branches/xx-branch-merge-proposals.txt'
192--- lib/lp/code/stories/branches/xx-branch-merge-proposals.txt 2009-08-06 17:51:02 +0000
193+++ lib/lp/code/stories/branches/xx-branch-merge-proposals.txt 2009-08-06 17:53:03 +0000
194@@ -320,6 +320,22 @@
195 Reviewer Review Type Date Requested Status...
196 Foo Bar claimable ... ago Pending ...
197
198+The claimant can reassign the review to someone else.
199+
200+ >>> foobar_browser.getLink('Reassign').click()
201+ >>> foobar_browser.getControl('Reviewer').value = 'hwdb-team'
202+ >>> foobar_browser.getControl('Reassign').click()
203+ >>> foobar_browser.open('http://code.launchpad.dev/~name12/gnome-terminal'
204+ ... '/klingon/+merge/1')
205+ >>> pending = find_tag_by_id(
206+ ... foobar_browser.contents, 'code-review-votes')
207+
208+The review is now reassigned to the HWDB team.
209+
210+ >>> print extract_text(pending)
211+ Reviewer Review Type Date Requested Status...
212+ HWDB Team claimable ... ago Pending ...
213+
214
215 == Marking as merged ==
216
217
218=== modified file 'lib/lp/code/templates/branchmergeproposal-votes.pt'
219--- lib/lp/code/templates/branchmergeproposal-votes.pt 2009-08-05 14:47:07 +0000
220+++ lib/lp/code/templates/branchmergeproposal-votes.pt 2009-08-05 20:16:34 +0000
221@@ -44,7 +44,13 @@
222 <!-- Pending reviews -->
223 <tr tal:repeat="review view/requested_reviews"
224 tal:attributes="id string:review-${review/reviewer/name}">
225- <td tal:content="structure review/reviewer/fmt:link:mainsite" />
226+ <td>
227+ <tal:reviewer
228+ tal:replace="structure review/reviewer/fmt:link:mainsite" />
229+ <a tal:condition="review/user_can_reassign"
230+ tal:attributes="href string:reviews/${review/id}/+reassign"><img
231+ src="/@@/edit" title="Reassign reviewer" alt="Reassign" /></a>
232+ </td>
233 <td tal:content="review/review_type" />
234 <td>
235 <tal:date-requested condition="review/show_date_requested">
236
237=== added file 'lib/lp/code/templates/reviewrequest-reassign.pt'
238--- lib/lp/code/templates/reviewrequest-reassign.pt 1970-01-01 00:00:00 +0000
239+++ lib/lp/code/templates/reviewrequest-reassign.pt 2009-07-29 20:56:34 +0000
240@@ -0,0 +1,22 @@
241+<html
242+ xmlns="http://www.w3.org/1999/xhtml"
243+ xmlns:tal="http://xml.zope.org/namespaces/tal"
244+ xmlns:metal="http://xml.zope.org/namespaces/metal"
245+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
246+ xml:lang="en"
247+ lang="en"
248+ dir="ltr"
249+ metal:use-macro="view/macro:page/onecolumn"
250+ i18n:domain="launchpad"
251+>
252+<body>
253+<div metal:fill-slot="main"
254+ tal:define="context_menu context/menu:context">
255+
256+ <h1>Reassign review request</h1>
257+ <div metal:use-macro="context/@@launchpad_form/form">
258+ <div metal:fill-slot="extra_info" style="clear: both" />
259+ </div>
260+</div>
261+</body>
262+</html>