← Back to team overview

launchpad-reviewers team mailing list archive

lp:~wallyworld/launchpad/branchcollection-filter-infotype-1001042 into lp:launchpad

 

Ian Booth has proposed merging lp:~wallyworld/launchpad/branchcollection-filter-infotype-1001042 into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #1001042 in Launchpad itself: "Update BranchCollection filtering to use branch information_type"
  https://bugs.launchpad.net/launchpad/+bug/1001042

For more details, see:
https://code.launchpad.net/~wallyworld/launchpad/branchcollection-filter-infotype-1001042/+merge/108886

== Implementation ==

This branch removes the uses of branch transitively_private and explicitly_private from model code. Those attributes are still defined on Branch, and set correctly when Branch is constructed and when information_type is changed. But the model code is ported to use information_type when doing branch queries etc.

Next steps will remove triggers which maintain transitively_private, remove the attributes from the model, delete the columns.

== Tests ==

Change tests to also use information_tyoe.

== Lint ==

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/code/model/branchcollection.py
  lib/lp/code/model/branchlookup.py
  lib/lp/code/model/branchmergeproposal.py
  lib/lp/code/model/revision.py
  lib/lp/code/model/tests/test_branch.py
  lib/lp/code/model/tests/test_branchcollection.py
  lib/lp/code/model/tests/test_branchmergeproposal.py
  lib/lp/code/model/tests/test_revision.py
  lib/lp/code/stories/webservice/xx-branch.txt
  lib/lp/code/stories/webservice/xx-branchmergeproposal.txt
  lib/lp/registry/model/distribution.py
-- 
https://code.launchpad.net/~wallyworld/launchpad/branchcollection-filter-infotype-1001042/+merge/108886
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wallyworld/launchpad/branchcollection-filter-infotype-1001042 into lp:launchpad.
=== modified file 'lib/lp/code/model/branchcollection.py'
--- lib/lp/code/model/branchcollection.py	2012-05-15 08:16:09 +0000
+++ lib/lp/code/model/branchcollection.py	2012-06-07 04:55:24 +0000
@@ -56,6 +56,10 @@
 from lp.code.model.codereviewcomment import CodeReviewComment
 from lp.code.model.codereviewvote import CodeReviewVoteReference
 from lp.code.model.seriessourcepackagebranch import SeriesSourcePackageBranch
+from lp.registry.enums import (
+    PRIVATE_INFORMATION_TYPES,
+    PUBLIC_INFORMATION_TYPES,
+    )
 from lp.registry.model.distribution import Distribution
 from lp.registry.model.distroseries import DistroSeries
 from lp.registry.model.person import (
@@ -71,7 +75,10 @@
     )
 from lp.services.database.decoratedresultset import DecoratedResultSet
 from lp.services.database.lpstorm import IStore
-from lp.services.database.sqlbase import quote
+from lp.services.database.sqlbase import (
+    quote,
+    sqlvalues,
+    )
 from lp.services.propertycache import get_property_cache
 from lp.services.searchbuilder import any
 from lp.services.webapp.interfaces import (
@@ -381,7 +388,7 @@
         scope_tables = [Branch] + self._tables.values()
         scope_expressions = self._branch_filter_expressions
         select = self.store.using(*scope_tables).find(
-            (Branch.id, Branch.transitively_private, Branch.ownerID),
+            (Branch.id, Branch.information_type, Branch.ownerID),
             *scope_expressions)
         branches_query = select._get_select()
         with_expr = [With("scope_branches", branches_query)
@@ -750,7 +757,8 @@
 
     def _getBranchVisibilityExpression(self, branch_class=Branch):
         """Return the where clauses for visibility."""
-        return [branch_class.transitively_private == False]
+        return [
+            branch_class.information_type.is_in(PUBLIC_INFORMATION_TYPES)]
 
     def _getCandidateBranchesWith(self):
         """Return WITH clauses defining candidate branches.
@@ -762,7 +770,8 @@
         return [
             With("candidate_branches",
                 SQL("""select id from scope_branches
-                    where not transitively_private"""))
+                    where information_type in %s"""
+                % sqlvalues(PUBLIC_INFORMATION_TYPES)))
             ]
 
 
@@ -842,7 +851,8 @@
             Select(Branch.id,
                    And(Branch.owner == TeamParticipation.teamID,
                        TeamParticipation.person == person,
-                       Branch.transitively_private == True)),
+                       Branch.information_type.is_in(
+                           PRIVATE_INFORMATION_TYPES))),
             # Private branches the person is subscribed to, either directly or
             # indirectly.
             Select(Branch.id,
@@ -850,7 +860,8 @@
                        BranchSubscription.person ==
                        TeamParticipation.teamID,
                        TeamParticipation.person == person,
-                       Branch.transitively_private == True)))
+                       Branch.information_type.is_in(
+                           PRIVATE_INFORMATION_TYPES))))
         return private_branches
 
     def _getBranchVisibilityExpression(self, branch_class=Branch):
@@ -859,7 +870,8 @@
         :param branch_class: The Branch class to use - permits using
             ClassAliases.
         """
-        public_branches = branch_class.transitively_private == False
+        public_branches = branch_class.information_type.is_in(
+            PUBLIC_INFORMATION_TYPES)
         if self._private_branch_ids is None:
             # Public only.
             return [public_branches]
@@ -880,24 +892,26 @@
             # Really an anonymous sitation
             return [
                 With("candidate_branches",
-                    SQL("""
-                        select id from scope_branches
-                        where not transitively_private"""))
+                    SQL("""select id from scope_branches
+                        where information_type in %s"""
+                    % sqlvalues(PUBLIC_INFORMATION_TYPES)))
                 ]
         return [
             With("teams", self.store.find(TeamParticipation.teamID,
                 TeamParticipation.personID == person.id)._get_select()),
             With("private_branches", SQL("""
                 SELECT scope_branches.id FROM scope_branches WHERE
-                scope_branches.transitively_private AND (
+                scope_branches.information_type in %s AND (
                     (scope_branches.owner in (select team from teams) OR
                      EXISTS(SELECT true from BranchSubscription, teams WHERE
                          branchsubscription.branch = scope_branches.id AND
-                         branchsubscription.person = teams.team)))""")),
+                         branchsubscription.person = teams.team)))"""
+                % sqlvalues(PRIVATE_INFORMATION_TYPES))),
             With("candidate_branches", SQL("""
                 (SELECT id FROM private_branches) UNION
                 (select id FROM scope_branches
-                WHERE not transitively_private)"""))
+                WHERE information_type in %s)"""
+                % sqlvalues(PUBLIC_INFORMATION_TYPES)))
             ]
 
     def visibleByUser(self, person):

=== modified file 'lib/lp/code/model/branchlookup.py'
--- lib/lp/code/model/branchlookup.py	2012-02-16 23:07:25 +0000
+++ lib/lp/code/model/branchlookup.py	2012-06-07 04:55:24 +0000
@@ -42,6 +42,7 @@
 from lp.code.interfaces.codehosting import BRANCH_ID_ALIAS_PREFIX
 from lp.code.interfaces.linkedbranch import get_linked_to_branch
 from lp.code.model.branch import Branch
+from lp.registry.enums import PUBLIC_INFORMATION_TYPES
 from lp.registry.errors import (
     NoSuchDistroSeries,
     NoSuchSourcePackageName,
@@ -303,7 +304,7 @@
         result = store.find(
             (Branch.id),
             Branch.id == branch_id,
-            Branch.transitively_private == False).one()
+            Branch.information_type.is_in(PUBLIC_INFORMATION_TYPES)).one()
         if result is None:
             return None, None
         else:
@@ -320,7 +321,7 @@
         result = store.find(
             (Branch.id, Branch.unique_name),
             Branch.unique_name.is_in(prefixes),
-            Branch.transitively_private == False).one()
+            Branch.information_type.is_in(PUBLIC_INFORMATION_TYPES)).one()
         if result is None:
             return None, None
         else:

=== modified file 'lib/lp/code/model/branchmergeproposal.py'
--- lib/lp/code/model/branchmergeproposal.py	2012-04-12 15:16:12 +0000
+++ lib/lp/code/model/branchmergeproposal.py	2012-06-07 04:55:24 +0000
@@ -76,6 +76,7 @@
     IncrementalDiff,
     PreviewDiff,
     )
+from lp.registry.enums import PRIVATE_INFORMATION_TYPES
 from lp.registry.interfaces.person import (
     IPerson,
     IPersonSet,
@@ -194,10 +195,13 @@
     @property
     def private(self):
         return (
-            self.source_branch.transitively_private or
-            self.target_branch.transitively_private or
+            (self.source_branch.information_type
+             in PRIVATE_INFORMATION_TYPES) or
+            (self.target_branch.information_type
+             in PRIVATE_INFORMATION_TYPES) or
             (self.prerequisite_branch is not None and
-             self.prerequisite_branch.transitively_private))
+             (self.prerequisite_branch.information_type in
+              PRIVATE_INFORMATION_TYPES)))
 
     reviewer = ForeignKey(
         dbName='reviewer', foreignKey='Person',

=== modified file 'lib/lp/code/model/revision.py'
--- lib/lp/code/model/revision.py	2012-02-24 22:00:41 +0000
+++ lib/lp/code/model/revision.py	2012-06-07 04:55:24 +0000
@@ -56,6 +56,7 @@
     IRevisionProperty,
     IRevisionSet,
     )
+from lp.registry.enums import PUBLIC_INFORMATION_TYPES
 from lp.registry.interfaces.person import validate_public_person
 from lp.registry.interfaces.product import IProduct
 from lp.registry.interfaces.projectgroup import IProjectGroup
@@ -159,7 +160,8 @@
             self.id == BranchRevision.revision_id,
             BranchRevision.branch_id == Branch.id)
         if not allow_private:
-            query = And(query, Not(Branch.transitively_private))
+            query = And(
+                query, Branch.information_type.is_in(PUBLIC_INFORMATION_TYPES))
         if not allow_junk:
             query = And(
                 query,
@@ -504,7 +506,7 @@
             Revision,
             And(revision_time_limit(day_limit),
                 person_condition,
-                Not(Branch.transitively_private)))
+                Branch.information_type.is_in(PUBLIC_INFORMATION_TYPES)))
         result_set.config(distinct=True)
         return result_set.order_by(Desc(Revision.revision_date))
 
@@ -522,8 +524,9 @@
             Join(Branch, BranchRevision.branch == Branch.id),
             ]
 
-        conditions = And(revision_time_limit(day_limit),
-                         Not(Branch.transitively_private))
+        conditions = And(
+            revision_time_limit(day_limit),
+            Branch.information_type.is_in(PUBLIC_INFORMATION_TYPES))
 
         if IProduct.providedBy(obj):
             conditions = And(conditions, Branch.product == obj)

=== modified file 'lib/lp/code/model/tests/test_branch.py'
--- lib/lp/code/model/tests/test_branch.py	2012-06-04 09:41:48 +0000
+++ lib/lp/code/model/tests/test_branch.py	2012-06-07 04:55:24 +0000
@@ -2350,19 +2350,9 @@
         self.assertTrue(branch.private)
         self.assertEqual(
             stacked_on.information_type, branch.information_type)
-        self.assertTrue(removeSecurityProxy(branch).transitively_private)
-        self.assertTrue(branch.explicitly_private)
-
-    def test_private_stacked_on_public_is_private(self):
-        # A private branch stacked on a public branch is private.
-        stacked_on = self.factory.makeBranch()
-        branch = self.factory.makeBranch(
-            stacked_on=stacked_on, information_type=InformationType.USERDATA)
-        self.assertTrue(branch.private)
-        self.assertNotEqual(
-            stacked_on.information_type, branch.information_type)
-        self.assertTrue(removeSecurityProxy(branch).transitively_private)
-        self.assertTrue(branch.explicitly_private)
+        self.assertEqual(
+            InformationType.USERDATA,
+            removeSecurityProxy(branch).information_type)
 
     def test_personal_branches_for_private_teams_are_private(self):
         team = self.factory.makeTeam(visibility=PersonVisibility.PRIVATE)
@@ -2406,8 +2396,7 @@
         self.assertFalse(branch.private)
         branch.setPrivate(False, branch.owner)
         self.assertFalse(branch.private)
-        self.assertFalse(removeSecurityProxy(branch).transitively_private)
-        self.assertFalse(branch.explicitly_private)
+        self.assertEqual(InformationType.PUBLIC, branch.information_type)
 
     def test_public_to_private_allowed(self):
         # If there is a privacy policy allowing the branch owner to have
@@ -2417,8 +2406,6 @@
             branch.owner, BranchVisibilityRule.PRIVATE)
         branch.setPrivate(True, branch.owner)
         self.assertTrue(branch.private)
-        self.assertTrue(removeSecurityProxy(branch).transitively_private)
-        self.assertTrue(branch.explicitly_private)
         self.assertEqual(InformationType.USERDATA, branch.information_type)
 
     def test_public_to_private_not_allowed(self):
@@ -2438,8 +2425,9 @@
         admins = getUtility(ILaunchpadCelebrities).admin
         branch.setPrivate(True, admins.teamowner)
         self.assertTrue(branch.private)
-        self.assertTrue(removeSecurityProxy(branch).transitively_private)
-        self.assertTrue(branch.explicitly_private)
+        self.assertEqual(
+            InformationType.USERDATA,
+            removeSecurityProxy(branch).information_type)
 
     def test_private_to_private(self):
         # Setting a private branch to be private is a no-op.
@@ -2448,8 +2436,9 @@
         self.assertTrue(branch.private)
         branch.setPrivate(True, branch.owner)
         self.assertTrue(branch.private)
-        self.assertTrue(removeSecurityProxy(branch).transitively_private)
-        self.assertTrue(branch.explicitly_private)
+        self.assertEqual(
+            InformationType.USERDATA,
+            removeSecurityProxy(branch).information_type)
 
     def test_private_to_public_allowed(self):
         # If the namespace policy allows public branches, then changing from
@@ -2458,8 +2447,6 @@
             information_type=InformationType.USERDATA)
         branch.setPrivate(False, branch.owner)
         self.assertFalse(branch.private)
-        self.assertFalse(removeSecurityProxy(branch).transitively_private)
-        self.assertFalse(branch.explicitly_private)
         self.assertEqual(InformationType.PUBLIC, branch.information_type)
 
     def test_private_to_public_not_allowed(self):

=== modified file 'lib/lp/code/model/tests/test_branchcollection.py'
--- lib/lp/code/model/tests/test_branchcollection.py	2012-05-31 03:54:13 +0000
+++ lib/lp/code/model/tests/test_branchcollection.py	2012-06-07 04:55:24 +0000
@@ -890,8 +890,10 @@
     def test_target_branch_private(self):
         # The target branch must be in the branch collection, as must the
         # source branch.
-        mp1 = self.factory.makeBranchMergeProposal()
-        removeSecurityProxy(mp1.target_branch).explicitly_private = True
+        registrant = self.factory.makePerson()
+        mp1 = self.factory.makeBranchMergeProposal(registrant=registrant)
+        removeSecurityProxy(mp1.target_branch).transitionToInformationType(
+            InformationType.USERDATA, registrant, verify_policy=False)
         collection = self.all_branches.visibleByUser(None)
         proposals = collection.getMergeProposals()
         self.assertEqual([], list(proposals))

=== modified file 'lib/lp/code/model/tests/test_branchmergeproposal.py'
--- lib/lp/code/model/tests/test_branchmergeproposal.py	2012-05-31 03:54:13 +0000
+++ lib/lp/code/model/tests/test_branchmergeproposal.py	2012-06-07 04:55:24 +0000
@@ -1160,7 +1160,9 @@
         # proposals that the logged in user is able to see.
         proposal = self._make_merge_proposal('albert', 'november', 'work')
         # Mark the source branch private.
-        removeSecurityProxy(proposal.source_branch).explicitly_private = True
+        proposal.source_branch.transitionToInformationType(
+            InformationType.USERDATA, proposal.source_branch.owner,
+            verify_policy=False)
         self._make_merge_proposal('albert', 'mike', 'work')
 
         albert = getUtility(IPersonSet).getByName('albert')
@@ -1198,10 +1200,10 @@
 
         proposal = self._make_merge_proposal(
             'xray', 'november', 'work', registrant=albert)
-        # Mark the source branch private by making it's stacked on branch
-        # private.
-        removeSecurityProxy(
-            proposal.source_branch.stacked_on).explicitly_private = True
+        # Mark the source branch private.
+        proposal.source_branch.transitionToInformationType(
+            InformationType.USERDATA, proposal.source_branch.owner,
+            verify_policy=False)
 
         november = getUtility(IProductSet).getByName('november')
         # The proposal is visible to charles.

=== modified file 'lib/lp/code/model/tests/test_revision.py'
--- lib/lp/code/model/tests/test_revision.py	2012-05-31 03:54:13 +0000
+++ lib/lp/code/model/tests/test_revision.py	2012-06-07 04:55:24 +0000
@@ -340,7 +340,8 @@
         # Only public branches are returned.
         b1 = self.makeBranchWithRevision(1)
         b2 = self.makeBranchWithRevision(1, owner=self.author)
-        removeSecurityProxy(b2).explicitly_private = True
+        removeSecurityProxy(b2).transitionToInformationType(
+            InformationType.USERDATA, b2.owner, verify_policy=False)
         self.assertEqual(b1, self.revision.getBranch())
 
     def testAllowPrivateReturnsPrivateBranch(self):
@@ -348,7 +349,8 @@
         # returned if they are the best match.
         self.makeBranchWithRevision(1)
         b2 = self.makeBranchWithRevision(1, owner=self.author)
-        removeSecurityProxy(b2).explicitly_private = True
+        removeSecurityProxy(b2).transitionToInformationType(
+            InformationType.USERDATA, b2.owner, verify_policy=False)
         self.assertEqual(b2, self.revision.getBranch(allow_private=True))
 
     def testAllowPrivateCanReturnPublic(self):
@@ -356,7 +358,8 @@
         # the branches.
         b1 = self.makeBranchWithRevision(1)
         b2 = self.makeBranchWithRevision(1, owner=self.author)
-        removeSecurityProxy(b1).explicitly_private = True
+        removeSecurityProxy(b1).transitionToInformationType(
+            InformationType.USERDATA, b1.owner, verify_policy=False)
         self.assertEqual(b2, self.revision.getBranch(allow_private=True))
 
     def testGetBranchNotJunk(self):
@@ -464,7 +467,9 @@
         rev1 = self._makeRevision()
         b = self._makeBranch()
         b.createBranchRevision(1, rev1)
-        removeSecurityProxy(b).explicitly_private = True
+
+        removeSecurityProxy(b).transitionToInformationType(
+            InformationType.USERDATA, b.owner, verify_policy=False)
         self.assertEqual([], self._getRevisions())
 
     def testRevisionDateRange(self):

=== modified file 'lib/lp/code/stories/webservice/xx-branch.txt'
--- lib/lp/code/stories/webservice/xx-branch.txt	2012-05-04 10:39:00 +0000
+++ lib/lp/code/stories/webservice/xx-branch.txt	2012-06-07 04:55:24 +0000
@@ -262,17 +262,14 @@
     >>> response = webservice.named_post(
     ...     branch_url, 'setPrivate', api_version='beta', private=True)
     >>> branch = webservice.get(branch_url).jsonBody()
-    >>> print branch['explicitly_private']
-    True
-    >>> print branch['private']
-    True
+    >>> print branch['information_type']
+    User Data
 
-In subsequent versions, 'setPrivate' is gone; you have to set the
-'explicitly_private' field directly.
+In subsequent versions, 'setPrivate' is gone; you have to use the
+'transitionToInformationType' method.
 
     >>> print webservice.named_post(
-    ...     branch_url, 'setPrivate', api_version='devel',
-    ...     explicitly_private=True)
+    ...     branch_url, 'setPrivate', api_version='devel', private=True)
     HTTP/1.1 400 Bad Request
     ...
     No such operation: setPrivate

=== modified file 'lib/lp/code/stories/webservice/xx-branchmergeproposal.txt'
--- lib/lp/code/stories/webservice/xx-branchmergeproposal.txt	2012-03-07 07:15:00 +0000
+++ lib/lp/code/stories/webservice/xx-branchmergeproposal.txt	2012-06-07 04:55:24 +0000
@@ -420,8 +420,11 @@
 
     >>> login('admin@xxxxxxxxxxxxx')
     >>> from zope.security.proxy import removeSecurityProxy
-    >>> removeSecurityProxy(fixit_proposal.source_branch).explicitly_private = True
+    >>> from lp.registry.enums import InformationType
     >>> branch_owner = fixit_proposal.source_branch.owner
+    >>> removeSecurityProxy(
+    ...     fixit_proposal.source_branch).transitionToInformationType(
+    ...     InformationType.USERDATA, branch_owner, verify_policy=False)
     >>> logout()
 
     >>> print_proposals(
@@ -439,7 +442,9 @@
     http://.../~source/fooix/fix-it/+merge/... - Approved
 
     >>> login('admin@xxxxxxxxxxxxx')
-    >>> removeSecurityProxy(fixit_proposal.source_branch).explicitly_private = False
+    >>> removeSecurityProxy(
+    ...     fixit_proposal.source_branch).transitionToInformationType(
+    ...     InformationType.PUBLIC, branch_owner)
     >>> logout()
 
 

=== modified file 'lib/lp/registry/model/distribution.py'
--- lib/lp/registry/model/distribution.py	2012-06-05 11:40:48 +0000
+++ lib/lp/registry/model/distribution.py	2012-06-07 04:55:24 +0000
@@ -98,6 +98,7 @@
     )
 from lp.registry.enums import (
     InformationType,
+    PRIVATE_INFORMATION_TYPES,
     PUBLIC_INFORMATION_TYPES,
     )
 from lp.registry.errors import NoSuchDistroSeries
@@ -639,7 +640,7 @@
                Branch.last_scanned_id,
                SPBDS.name AS distro_series_name,
                Branch.id,
-               Branch.transitively_private,
+               Branch.information_type,
                Branch.owner
         FROM Branch
         JOIN DistroSeries
@@ -659,7 +660,9 @@
             # Now we see just a touch of privacy concerns.
             # If the current user is anonymous, they cannot see any private
             # branches.
-            base_query += ('      AND NOT Branch.transitively_private\n')
+            base_query += (
+                '      AND Branch.information_type in %s\n'
+                % sqlvalues(PUBLIC_INFORMATION_TYPES))
         # We want to order the results, in part for easier grouping at the
         # end.
         base_query += 'ORDER BY unique_name, last_scanned_id'
@@ -693,7 +696,7 @@
                            id,
                            owner
                     FROM all_branches
-                    WHERE transitively_private
+                    WHERE information_type in %(private_branches)s
                 ), owned_branch_ids AS (
                     SELECT private_branches.id
                     FROM private_branches
@@ -708,10 +711,14 @@
                 )
             SELECT unique_name, last_scanned_id, distro_series_name
             FROM all_branches
-            WHERE NOT transitively_private OR
+            WHERE information_type in %(public_branches)s OR
                   id IN (SELECT id FROM owned_branch_ids) OR
                   id IN (SELECT id FROM subscribed_branch_ids)
-            """ % dict(base_query=base_query, user=quote(user.id))
+            """ % dict(
+                base_query=base_query,
+                user=quote(user.id),
+                private_branches=sqlvalues(PRIVATE_INFORMATION_TYPES),
+                public_branches=sqlvalues(PUBLIC_INFORMATION_TYPES))
 
         data = Store.of(self).execute(query + ';')
 


Follow ups