← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~stevenk/launchpad/less-public-bmp into lp:launchpad

 

Steve Kowalik has proposed merging lp:~stevenk/launchpad/less-public-bmp into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~stevenk/launchpad/less-public-bmp/+merge/150731

Split IBranchMergeProposal into four classes -- IBranchMergeProposal{Public,View,Edit,AnyPerson}, and these are used in the ZCML rather than listing attributes.
-- 
https://code.launchpad.net/~stevenk/launchpad/less-public-bmp/+merge/150731
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/less-public-bmp into lp:launchpad.
=== modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py'
--- lib/lp/code/browser/tests/test_branchmergeproposal.py	2013-01-07 02:40:55 +0000
+++ lib/lp/code/browser/tests/test_branchmergeproposal.py	2013-02-27 07:42:24 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 
@@ -224,19 +224,6 @@
 
         return private_team1, public_person1
 
-    def testPrivateVotesNotVisibleIfBranchNotVisible(self):
-        # User can't see votes for private teams if they can't see the branch.
-        private_team1, public_person1 = self._createPrivateVotes(False)
-        login_person(self.factory.makePerson())
-        view = BranchMergeProposalVoteView(self.bmp, LaunchpadTestRequest())
-
-        # Check the requested reviews.
-        requested_reviews = view.requested_reviews
-        self.assertEqual(1, len(requested_reviews))
-        self.assertContentEqual(
-            [public_person1],
-            [review.reviewer for review in requested_reviews])
-
     def testPrivateVotesVisibleIfBranchVisible(self):
         # User can see votes for private teams if they can see the branch.
         private_team1, public_person1 = self._createPrivateVotes()
@@ -805,7 +792,8 @@
         browser = self.getViewBrowser(bmp, '+resubmit')
         browser.getControl('Description').value = 'flibble'
         browser.getControl('Resubmit').click()
-        self.assertEqual('flibble', bmp.superseded_by.description)
+        with person_logged_in(self.user):
+            self.assertEqual('flibble', bmp.superseded_by.description)
 
 
 class TestBranchMergeProposalView(TestCaseWithFactory):

=== modified file 'lib/lp/code/configure.zcml'
--- lib/lp/code/configure.zcml	2013-02-25 05:23:12 +0000
+++ lib/lp/code/configure.zcml	2013-02-27 07:42:24 +0000
@@ -218,75 +218,23 @@
   <!-- Branch Merge Proposal -->
 
   <class class="lp.code.model.branchmergeproposal.BranchMergeProposal">
-    <allow attributes="
-                    address
-                    id
-                    registrant
-                    source_branch
-                    source_branchID
-                    target_branch
-                    prerequisite_branch
-                    prerequisite_branchID
-                    description
-                    whiteboard
-                    queue_status
-                    private
-                    reviewer
-                    reviewed_revision_id
-                    queuer
-                    queue_position
-                    queued_revision_id
-                    commit_message
-                    date_queued
-                    merged_revno
-                    date_merged
-                    merge_reporter
-                    supersedes
-                    superseded_by
-                    title
-                    date_created
-                    date_review_requested
-                    date_reviewed
-                    next_preview_diff_job
-                    preview_diff
+    <allow
+        interface="lp.code.interfaces.branchmergeproposal.IBranchMergeProposalPublic"
+        attributes="generateIncrementalDiff
                     getIncrementalDiffs
-                    votes
-                    all_comments
-                    getRelatedBugTasks
-                    revision_end_date
-                    isMergable
-                    getComment
-                    getRevisionsSinceReviewStart
-                    getNotificationRecipients
-                    getVoteReference
-                    isValidTransition
-                    getUnlandedSourceBranchRevisions
-                    root_message_id
-                    getUsersVoteReference
-                    generateIncrementalDiff"/>
+                    revision_end_date"/>
     <allow interface="lp.code.interfaces.branchtarget.IHasBranchTarget"/>
     <require
+        permission="launchpad.View"
+        interface="lp.code.interfaces.branchmergeproposal.IBranchMergeProposalView"/>
+    <require
         permission="launchpad.Edit"
+        interface="lp.code.interfaces.branchmergeproposal.IBranchMergeProposalEdit"
         set_attributes="description whiteboard merged_revno commit_message
-                        root_message_id prerequisite_branch"
-        attributes="
-                    deleteProposal
-                    setStatus
-                    setAsWorkInProgress
-                    requestReview
-                    approveBranch
-                    rejectBranch
-                    markAsMerged
-                    resubmit
-                    enqueue
-                    dequeue
-                    moveToFrontOfQueue
-                    nominateReviewer
-                    updatePreviewDiff"/>
+                        root_message_id prerequisite_branch"/>
     <require
         permission="launchpad.AnyPerson"
-        attributes="createComment
-                    createCommentFromMessage"/>
+        interface="lp.code.interfaces.branchmergeproposal.IBranchMergeProposalAnyPerson"/>
   </class>
 
   <!-- Branch Merge Proposal Jobs -->

=== modified file 'lib/lp/code/interfaces/branchmergeproposal.py'
--- lib/lp/code/interfaces/branchmergeproposal.py	2013-02-05 22:56:33 +0000
+++ lib/lp/code/interfaces/branchmergeproposal.py	2013-02-27 07:42:24 +0000
@@ -94,20 +94,24 @@
     )
 
 
-class IBranchMergeProposal(IPrivacy):
-    """Branch merge proposals show intent of landing one branch on another."""
-
-    export_as_webservice_entry()
+class IBranchMergeProposalPublic(IPrivacy):
 
     id = Int(
         title=_('DB ID'), required=True, readonly=True,
         description=_("The tracking number for this merge proposal."))
+    source_branchID = Int(
+        title=_('Source branch ID'), required=True, readonly=True)
+    prerequisite_branchID = Int(
+        title=_('Prerequisite branch ID'), required=True, readonly=True)
 
-    registrant = exported(
-        PublicPersonChoice(
-            title=_('Person'), required=True,
-            vocabulary='ValidPersonOrTeam', readonly=True,
-            description=_('The person who registered the merge proposal.')))
+    # This is redefined from IPrivacy.private because the attribute is
+    # read-only. The value is determined by the involved branches.
+    private = exported(
+        Bool(
+            title=_("Proposal is confidential"), required=False,
+            readonly=True, default=False,
+            description=_(
+                "If True, this proposal is visible only to subscribers.")))
 
     source_branch = exported(
         ReferenceChoice(
@@ -131,14 +135,14 @@
                 "If this branch is the same as the target branch, then "
                 "leave this field blank.")))
 
-    # This is redefined from IPrivacy.private because the attribute is
-    # read-only. The value is determined by the involved branches.
-    private = exported(
-        Bool(
-            title=_("Proposal is confidential"), required=False,
-            readonly=True, default=False,
-            description=_(
-                "If True, this proposal is visible only to subscribers.")))
+
+class IBranchMergeProposalView(Interface):
+
+    registrant = exported(
+        PublicPersonChoice(
+            title=_('Person'), required=True,
+            vocabulary='ValidPersonOrTeam', readonly=True,
+            description=_('The person who registered the merge proposal.')))
 
     description = exported(
         Text(title=_('Description'), required=False,
@@ -312,19 +316,63 @@
             notified.
         """
 
-    # Cannot specify value type without creating a circular dependency
     votes = exported(
         CollectionField(
             title=_('The votes cast or expected for this proposal'),
             # Really ICodeReviewVoteReference.
             value_type=Reference(schema=Interface),
-            readonly=True,
-            )
-        )
+            readonly=True))
 
     def isValidTransition(next_state, user=None):
         """True if it is valid for user update the proposal to next_state."""
 
+    def isMergable():
+        """Is the proposal in a state that allows it to being merged?
+
+        As long as the proposal isn't in one of the end states, it is valid
+        to be merged.
+        """
+
+    def getUnlandedSourceBranchRevisions():
+        """Return a sequence of `BranchRevision` objects.
+
+        Returns up to 10 revisions that are in the revision history for the
+        source branch that are not in the revision history of the target
+        branch.  These are the revisions that have been committed to the
+        source branch since it branched off the target branch.
+        """
+
+    def getUsersVoteReference(user):
+        """Get the existing vote reference for the given user.
+
+        :return: A `CodeReviewVoteReference` or None.
+        """
+
+
+class IBranchMergeProposalEdit(Interface):
+
+    def deleteProposal():
+        """Delete the proposal to merge."""
+
+    def updatePreviewDiff(diff_content, source_revision_id,
+                          target_revision_id, prerequisite_revision_id=None,
+                          conflicts=None):
+        """Update the preview diff for this proposal.
+
+        If there is not an existing preview diff, one will be created.
+
+        :param diff_content: The raw bytes of the diff content to be put in
+            the librarian.
+        :param diff_stat: Text describing the files added, remove or modified.
+        :param source_revision_id: The revision id that was used from the
+            source branch.
+        :param target_revision_id: The revision id that was used from the
+            target branch.
+        :param prerequisite_revision_id: The revision id that was used from
+            the prerequisite branch.
+        :param conflicts: Text describing the conflicts if any.
+        """
+
     @call_with(user=REQUEST_USER)
     @rename_parameters_as(revision_id='revid')
     @operation_parameters(
@@ -385,27 +433,6 @@
                  the branch reviewer for the target branch.
         """
 
-    def enqueue(queuer, revision_id):
-        """Put the proposal into the merge queue for the target branch.
-
-        If the proposal is not in the Approved state before this method
-        is called, approveBranch is called with the reviewer and revision_id
-        specified.
-
-        If None is supplied as the revision_id, the proposals
-        reviewed_revision_id is used.
-        """
-
-    def dequeue():
-        """Take the proposal out of the merge queue of the target branch.
-
-        :raises: BadStateTransition if the proposal is not in the queued
-                 state.
-        """
-
-    def moveToFrontOfQueue():
-        """Move the queue proposal to the front of the queue."""
-
     def markAsMerged(merged_revno=None, date_merged=None,
                      merge_reporter=None):
         """Mark the branch merge proposal as merged.
@@ -451,21 +478,26 @@
             the current description).
         """
 
-    def isMergable():
-        """Is the proposal in a state that allows it to being merged?
-
-        As long as the proposal isn't in one of the end states, it is valid
-        to be merged.
-        """
-
-    def getUnlandedSourceBranchRevisions():
-        """Return a sequence of `BranchRevision` objects.
-
-        Returns up to 10 revisions that are in the revision history for the
-        source branch that are not in the revision history of the target
-        branch.  These are the revisions that have been committed to the
-        source branch since it branched off the target branch.
-        """
+    def enqueue(queuer, revision_id):
+        """Put the proposal into the merge queue for the target branch.
+
+        If the proposal is not in the Approved state before this method
+        is called, approveBranch is called with the reviewer and revision_id
+        specified.
+
+        If None is supplied as the revision_id, the proposals
+        reviewed_revision_id is used.
+        """
+
+    def dequeue():
+        """Take the proposal out of the merge queue of the target branch.
+
+        :raises: BadStateTransition if the proposal is not in the queued
+                 state.
+        """
+
+    def moveToFrontOfQueue():
+        """Move the queue proposal to the front of the queue."""
 
     @operation_parameters(
         reviewer=Reference(
@@ -482,11 +514,8 @@
         the details are updated.
         """
 
-    def getUsersVoteReference(user):
-        """Get the existing vote reference for the given user.
 
-        :return: A `CodeReviewVoteReference` or None.
-        """
+class IBranchMergeProposalAnyPerson(Interface):
 
     @operation_parameters(
         subject=Text(), content=Text(),
@@ -517,27 +546,13 @@
         :param original_email: Original email message.
         """
 
-    def deleteProposal():
-        """Delete the proposal to merge."""
-
-    def updatePreviewDiff(diff_content, source_revision_id,
-                          target_revision_id, prerequisite_revision_id=None,
-                          conflicts=None):
-        """Update the preview diff for this proposal.
-
-        If there is not an existing preview diff, one will be created.
-
-        :param diff_content: The raw bytes of the diff content to be put in
-            the librarian.
-        :param diff_stat: Text describing the files added, remove or modified.
-        :param source_revision_id: The revision id that was used from the
-            source branch.
-        :param target_revision_id: The revision id that was used from the
-            target branch.
-        :param prerequisite_revision_id: The revision id that was used from
-            the prerequisite branch.
-        :param conflicts: Text describing the conflicts if any.
-        """
+
+class IBranchMergeProposal(IBranchMergeProposalPublic,
+                           IBranchMergeProposalView, IBranchMergeProposalEdit,
+                           IBranchMergeProposalAnyPerson):
+    """Branch merge proposals show intent of landing one branch on another."""
+
+    export_as_webservice_entry()
 
 
 class IBranchMergeProposalJob(Interface):

=== modified file 'lib/lp/code/model/tests/test_branchmergeproposal.py'
--- lib/lp/code/model/tests/test_branchmergeproposal.py	2013-01-04 05:42:01 +0000
+++ lib/lp/code/model/tests/test_branchmergeproposal.py	2013-02-27 07:42:24 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Tests for BranchMergeProposals."""
@@ -953,31 +953,37 @@
     def test_getNotificationRecipients_privacy(self):
         # If a user can see only one of the source and target branches, then
         # they do not get email about the proposal.
-        bmp = self.factory.makeBranchMergeProposal()
+        owner = self.factory.makePerson()
+        product = self.factory.makeProduct()
+        source = self.factory.makeBranch(owner=owner, product=product)
+        target = self.factory.makeBranch(owner=owner, product=product)
+        bmp = self.factory.makeBranchMergeProposal(
+            source_branch=source, target_branch=target)
         # Subscribe eric to the source branch only.
         eric = self.factory.makePerson()
-        bmp.source_branch.subscribe(
+        source.subscribe(
             eric, BranchSubscriptionNotificationLevel.NOEMAIL, None,
             CodeReviewNotificationLevel.FULL, eric)
         # Subscribe bob to the target branch only.
         bob = self.factory.makePerson()
-        bmp.target_branch.subscribe(
+        target.subscribe(
             bob, BranchSubscriptionNotificationLevel.NOEMAIL, None,
             CodeReviewNotificationLevel.FULL, bob)
         # Subscribe charlie to both.
         charlie = self.factory.makePerson()
-        bmp.source_branch.subscribe(
+        source.subscribe(
             charlie, BranchSubscriptionNotificationLevel.NOEMAIL, None,
             CodeReviewNotificationLevel.FULL, charlie)
-        bmp.target_branch.subscribe(
+        target.subscribe(
             charlie, BranchSubscriptionNotificationLevel.NOEMAIL, None,
             CodeReviewNotificationLevel.FULL, charlie)
         # Make both branches private.
-        for branch in (bmp.source_branch, bmp.target_branch):
+        for branch in (source, target):
             removeSecurityProxy(branch).transitionToInformationType(
                 InformationType.USERDATA, branch.owner, verify_policy=False)
-        recipients = bmp.getNotificationRecipients(
-            CodeReviewNotificationLevel.FULL)
+        with person_logged_in(owner):
+            recipients = bmp.getNotificationRecipients(
+                CodeReviewNotificationLevel.FULL)
         self.assertNotIn(bob, recipients)
         self.assertNotIn(eric, recipients)
         self.assertIn(charlie, recipients)
@@ -2038,12 +2044,13 @@
 
     def test_getMergeProposals_with_merged_revnos(self):
         """Specifying merged revnos selects the correct merge proposal."""
-        mp = self.factory.makeBranchMergeProposal()
+        registrant = self.factory.makePerson()
+        mp = self.factory.makeBranchMergeProposal(registrant=registrant)
         launchpad = launchpadlib_for(
-            'test', mp.registrant,
+            'test', registrant,
             service_root=self.layer.appserver_root_url('api'))
 
-        with person_logged_in(mp.registrant):
+        with person_logged_in(registrant):
             mp.markAsMerged(merged_revno=123)
             transaction.commit()
             target = ws_object(launchpad, mp.target_branch)

=== modified file 'lib/lp/code/stories/branches/xx-branchmergeproposals.txt'
--- lib/lp/code/stories/branches/xx-branchmergeproposals.txt	2012-12-10 13:43:47 +0000
+++ lib/lp/code/stories/branches/xx-branchmergeproposals.txt	2013-02-27 07:42:24 +0000
@@ -667,8 +667,9 @@
     Updating diff...
     An updated diff will be available in a few minutes.  Reload to see the
     changes.
-    >>> bmp.next_preview_diff_job.start()
-    >>> bmp.next_preview_diff_job.complete()
+    >>> job = removeSecurityProxy(bmp).next_preview_diff_job
+    >>> job.start()
+    >>> job.complete()
     >>> transaction.commit()
     >>> nopriv_browser.open(url)
     >>> print find_tag_by_id(nopriv_browser.contents, 'diff-pending-update')