← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~sinzui/launchpad/code-review-affiliation into lp:launchpad

 

Curtis Hovey has proposed merging lp:~sinzui/launchpad/code-review-affiliation into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #828826 in Launchpad itself: "OOPS using person picker when reassigning merge proposal review slot"
  https://bugs.launchpad.net/launchpad/+bug/828826

For more details, see:
https://code.launchpad.net/~sinzui/launchpad/code-review-affiliation/+merge/72106

IHasAffiliation is not required to use the person picker.

    Launchpad bug: https://bugs.launchpad.net/bugs/828826
    Pre-implementation: jcsackett

OOPS-2056DQ44 was caused when CodeReviewVoteReference could not be
adapted to IHasAffiliation to lookup badges. badge are not required;
PersonPickerEntrySourceAdapter must not assume that every possibly
target has affiliation.

--------------------------------------------------------------------

RULES

    * Update PersonPickerEntrySourceAdapter to only lookup badges if
      the context can adapted to IHasAffiliation.
    * Add an IHasAffiliation adapter for ICodeReviewVoteReference
      because the user probably wants to choose a person affiliated with
      the pillar that owns the target branch.
    * ADDENDUM Update BranchPillarAffiliation to show that trusted reviewers
      are also affiliated.


QA

    * locate a merge proposal that has not been reviewed yet.
    * Choose to reassign (+reassign) the review.
    * Use the Choose link and search for julian
    * Verify the picker displays choices.
    * Verify that Julian is affiliated and a trusted reviewer.


LINT

    lib/lp/app/browser/vocabulary.py
    lib/lp/app/browser/tests/test_vocabulary.py
    lib/lp/registry/configure.zcml
    lib/lp/registry/model/pillaraffiliation.py
    lib/lp/registry/tests/test_pillaraffiliation.py


TEST

    ./bin/test -vv \
        -t PersonPickerEntrySourceAdapterTestCase \
        -t TestBranchPillarAffiliation \
        -t CodeReviewVotePillarAffiliationTestCase


IMPLEMENTATION

Updated PersonPickerEntrySourceAdapter to only attempt to get the badges
for the context if it can be adapted it IHasAffiliation.
    lib/lp/app/browser/vocabulary.py
    lib/lp/app/browser/tests/test_vocabulary.py

Update BranchPillarAffiliation to include the branch trusted reviewers as
affiliated users.
    lib/lp/registry/model/pillaraffiliation.py
    lib/lp/registry/tests/test_pillaraffiliation.py

Added CodeReviewVotePillarAffiliation to show code reviewers that are
affiliated with the pillar or branch.
    lib/lp/registry/configure.zcml
    lib/lp/registry/model/pillaraffiliation.py
    lib/lp/registry/tests/test_pillaraffiliation.py
-- 
https://code.launchpad.net/~sinzui/launchpad/code-review-affiliation/+merge/72106
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~sinzui/launchpad/code-review-affiliation into lp:launchpad.
=== modified file 'lib/lp/app/browser/tests/test_vocabulary.py'
--- lib/lp/app/browser/tests/test_vocabulary.py	2011-08-11 00:34:33 +0000
+++ lib/lp/app/browser/tests/test_vocabulary.py	2011-08-18 21:05:53 +0000
@@ -137,6 +137,17 @@
         self.assertEqual('/@@/product-badge', entry.badges[2]['url'])
         self.assertEqual('Fnord bug supervisor', entry.badges[2]['alt'])
 
+    def test_PersonPickerEntryAdapter_badges_without_IHasAffiliation(self):
+        # The enhanced person picker handles objects that do not support
+        # IHasAffilliation.
+        person = self.factory.makePerson(email='snarf@xxxxxx', name='snarf')
+        thing = object()
+        [entry] = IPickerEntrySource(person).getPickerEntries(
+            [person], thing, enhanced_picker_enabled=True,
+            picker_expander_enabled=True,
+            personpicker_affiliation_enabled=True)
+        self.assertEqual(None, None)
+
 
 class TestPersonVocabulary:
     implements(IHugeVocabulary)

=== modified file 'lib/lp/app/browser/vocabulary.py'
--- lib/lp/app/browser/vocabulary.py	2011-08-11 00:34:33 +0000
+++ lib/lp/app/browser/vocabulary.py	2011-08-18 21:05:53 +0000
@@ -146,11 +146,12 @@
 
         personpicker_affiliation_enabled = kwarg.get(
                                     'personpicker_affiliation_enabled', False)
-        if personpicker_affiliation_enabled:
+        affiliated_context = IHasAffiliation(context_object, None)
+        if (affiliated_context is not None
+            and personpicker_affiliation_enabled):
             # If a person is affiliated with the associated_object then we
             # can display a badge.
-            badges = IHasAffiliation(
-                context_object).getAffiliationBadges(term_values)
+            badges = affiliated_context.getAffiliationBadges(term_values)
             for picker_entry, badges in izip(picker_entries, badges):
                 picker_entry.badges = []
                 for badge_info in badges:

=== modified file 'lib/lp/registry/configure.zcml'
--- lib/lp/registry/configure.zcml	2011-08-09 04:09:33 +0000
+++ lib/lp/registry/configure.zcml	2011-08-18 21:05:53 +0000
@@ -915,7 +915,10 @@
             for="lp.registry.interfaces.productseries.IProductSeries"
             factory="lp.registry.model.pillaraffiliation.ProductSeriesPillarAffiliation"
             />
-
+        <adapter
+            for="lp.code.interfaces.codereviewvote.ICodeReviewVoteReference"
+            factory="lp.registry.model.pillaraffiliation.CodeReviewVotePillarAffiliation"
+            />
         <!-- Using
 
     permission="Public" here causes some tests to fail

=== modified file 'lib/lp/registry/model/pillaraffiliation.py'
--- lib/lp/registry/model/pillaraffiliation.py	2011-08-11 00:34:33 +0000
+++ lib/lp/registry/model/pillaraffiliation.py	2011-08-18 21:05:53 +0000
@@ -139,9 +139,32 @@
 
 class BranchPillarAffiliation(BugTaskPillarAffiliation):
     """An affiliation adapter for branches."""
+
     def getPillar(self):
         return self.context.product or self.context.distribution
 
+    def getBranch(self):
+        return self.context
+
+    def _getAffiliationDetails(self, person, pillar):
+        super_instance = super(BranchPillarAffiliation, self)
+        result = super_instance._getAffiliationDetails(person, pillar)
+        if self.getBranch().isPersonTrustedReviewer(person):
+            result.append((pillar.displayname, 'trusted reviewer'))
+        return result
+
+
+class CodeReviewVotePillarAffiliation(BranchPillarAffiliation):
+    """An affiliation adapter for CodeReviewVotes."""
+
+    def getPillar(self):
+        """Return the target branch'pillar."""
+        branch = self.getBranch()
+        return branch.product or branch.distribution
+
+    def getBranch(self):
+        return self.context.branch_merge_proposal.target_branch
+
 
 class DistroSeriesPillarAffiliation(PillarAffiliation):
     """An affiliation adapter for distroseries."""

=== modified file 'lib/lp/registry/tests/test_pillaraffiliation.py'
--- lib/lp/registry/tests/test_pillaraffiliation.py	2011-08-11 00:34:33 +0000
+++ lib/lp/registry/tests/test_pillaraffiliation.py	2011-08-18 21:05:53 +0000
@@ -246,17 +246,77 @@
         adapter = IHasAffiliation(branch)
         self.assertEqual(branch.product, adapter.getPillar())
 
-    def _check_affiliated_with_distro(self, person, target, role):
-        distroseries = self.factory.makeDistroSeries(distribution=target)
-        sp = self.factory.makeSourcePackage(distroseries=distroseries)
-        branch = self.factory.makeBranch(sourcepackage=sp)
-        [badges] = IHasAffiliation(branch).getAffiliationBadges([person])
-        self.assertEqual(
-            ("/@@/distribution-badge", "Pting %s" % role), badges[0])
-
-    def _check_affiliated_with_product(self, person, target, role):
-        branch = self.factory.makeBranch(product=target)
-        [badges] = IHasAffiliation(branch).getAffiliationBadges([person])
+    def test_getBranch(self):
+        # The branch is the context.
+        branch = self.factory.makeBranch()
+        adapter = IHasAffiliation(branch)
+        self.assertEqual(branch, adapter.getBranch())
+
+    def test_branch_trusted_reviewer_affiliation(self):
+        # A person who is the branch's trusted reviewer is affiliated.
+        person = self.factory.makePerson()
+        product = self.factory.makeProduct(name='pting')
+        self._check_affiliated_with_product(
+            person, product, 'trusted reviewer')
+
+    def _check_affiliated_with_distro(self, person, target, role):
+        distroseries = self.factory.makeDistroSeries(distribution=target)
+        sp = self.factory.makeSourcePackage(distroseries=distroseries)
+        branch = self.factory.makeBranch(sourcepackage=sp)
+        [badges] = IHasAffiliation(branch).getAffiliationBadges([person])
+        self.assertEqual(
+            ("/@@/distribution-badge", "Pting %s" % role), badges[0])
+
+    def _check_affiliated_with_product(self, person, target, role):
+        branch = self.factory.makeBranch(product=target)
+        with person_logged_in(branch.owner):
+            branch.reviewer = person
+        [badges] = IHasAffiliation(branch).getAffiliationBadges([person])
+        self.assertEqual(
+            ("/@@/product-badge", "Pting %s" % role), badges[0])
+
+
+class CodeReviewVotePillarAffiliationTestCase(TestBranchPillarAffiliation):
+
+    layer = DatabaseFunctionalLayer
+
+    def makeCodeReviewVote(self, branch):
+        merge_proposal = self.factory.makeBranchMergeProposal(
+            target_branch=branch)
+        reviewer = self.factory.makePerson()
+        with person_logged_in(merge_proposal.registrant):
+            vote = merge_proposal.nominateReviewer(
+                reviewer, merge_proposal.registrant)
+        return vote
+
+    def test_correct_pillar_is_used(self):
+        branch = self.factory.makeBranch()
+        vote = self.makeCodeReviewVote(branch)
+        adapter = IHasAffiliation(vote)
+        self.assertEqual(branch.product, adapter.getPillar())
+
+    def test_getBranch(self):
+        # The code review vote's target branch is the branch.
+        branch = self.factory.makeBranch()
+        vote = self.makeCodeReviewVote(branch)
+        adapter = IHasAffiliation(vote)
+        self.assertEqual(branch, adapter.getBranch())
+
+    def _check_affiliated_with_distro(self, person, target, role):
+        distroseries = self.factory.makeDistroSeries(distribution=target)
+        sp = self.factory.makeSourcePackage(distroseries=distroseries)
+        branch = self.factory.makeBranch(sourcepackage=sp)
+        vote = self.makeCodeReviewVote(branch)
+        [badges] = IHasAffiliation(vote).getAffiliationBadges([person])
+        self.assertEqual(
+            ("/@@/distribution-badge", "Pting %s" % role), badges[0])
+
+    def _check_affiliated_with_product(self, person, target, role):
+        branch = self.factory.makeBranch(product=target)
+        with person_logged_in(branch.owner):
+            branch.reviewer = person
+        vote = self.makeCodeReviewVote(branch)
+        [badges] = IHasAffiliation(vote).getAffiliationBadges([person])
         self.assertEqual(
             ("/@@/product-badge", "Pting %s" % role), badges[0])
 
@@ -279,7 +339,8 @@
             owner=owner, driver=driver, name='pting')
         distroseries = self.factory.makeDistroSeries(
             registrant=driver, distribution=distribution)
-        [badges] = IHasAffiliation(distroseries).getAffiliationBadges([driver])
+        [badges] = IHasAffiliation(
+            distroseries).getAffiliationBadges([driver])
         self.assertEqual(
             ("/@@/distribution-badge", "Pting driver"), badges[0])
 
@@ -292,7 +353,8 @@
             owner=owner, driver=driver, name='pting')
         distroseries = self.factory.makeDistroSeries(
             registrant=owner, distribution=distribution)
-        [badges] = IHasAffiliation(distroseries).getAffiliationBadges([driver])
+        [badges] = IHasAffiliation(
+            distroseries).getAffiliationBadges([driver])
         self.assertEqual(
             ("/@@/distribution-badge", "Pting driver"), badges[0])