launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #07606
[Merge] lp:~stevenk/launchpad/branch-information_type-garbo into lp:launchpad
Steve Kowalik has proposed merging lp:~stevenk/launchpad/branch-information_type-garbo into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #933768 in Launchpad itself: "Update branch to use information_visibility_policy"
https://bugs.launchpad.net/launchpad/+bug/933768
For more details, see:
https://code.launchpad.net/~stevenk/launchpad/branch-information_type-garbo/+merge/104682
Add a garbo job to populate Branch.information_type. Be very sneaky and use an SQL CASE statement to set it for purely speed reasons.
--
https://code.launchpad.net/~stevenk/launchpad/branch-information_type-garbo/+merge/104682
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/branch-information_type-garbo into lp:launchpad.
=== modified file 'lib/lp/code/interfaces/branch.py'
--- lib/lp/code/interfaces/branch.py 2012-04-06 17:28:25 +0000
+++ lib/lp/code/interfaces/branch.py 2012-05-04 06:06:20 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
# pylint: disable-msg=E0211,E0213,F0401,W0611
@@ -90,6 +90,7 @@
from lp.code.interfaces.hasbranches import IHasMergeProposals
from lp.code.interfaces.hasrecipes import IHasRecipes
from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch
+from lp.registry.enums import InformationType
from lp.registry.interfaces.person import IPerson
from lp.registry.interfaces.pocket import PackagePublishingPocket
from lp.registry.interfaces.role import IHasOwner
@@ -247,11 +248,16 @@
title=_('Date Last Modified'),
required=True,
readonly=False))
-
explicitly_private = Bool(
title=_("Explicitly Private"),
description=_("This branch is explicitly marked private as opposed "
"to being private because it is stacked on a private branch."))
+ information_type = exported(
+ Choice(
+ title=_('Information Type'), vocabulary=InformationType,
+ required=True, readonly=True, default=InformationType.PUBLIC,
+ description=_(
+ 'The type of information contained in this branch.')))
class IBranchAnyone(Interface):
@@ -1114,6 +1120,13 @@
:raise: CannotDeleteBranch if the branch cannot be deleted.
"""
+ def transitionToInformationType(information_type, who):
+ """Set the information type for this branch.
+
+ :information_type: The `InformationType` to transition to.
+ :who: The `IPerson` who is making the change.
+ """
+
class IMergeQueueable(Interface):
"""An interface for branches that can be queued."""
=== modified file 'lib/lp/code/model/branch.py'
--- lib/lp/code/model/branch.py 2012-04-06 17:28:25 +0000
+++ lib/lp/code/model/branch.py 2012-05-04 06:06:20 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
# pylint: disable-msg=E0611,W0212,W0141,F0401
@@ -128,6 +128,7 @@
)
from lp.code.model.seriessourcepackagebranch import SeriesSourcePackageBranch
from lp.codehosting.safe_open import safe_open
+from lp.registry.enums import InformationType
from lp.registry.interfaces.person import (
validate_person,
validate_public_person,
@@ -181,6 +182,8 @@
# transitively private branch. The value of this attribute is maintained
# by a database trigger.
transitively_private = BoolCol(dbName='transitively_private')
+ information_type = EnumCol(
+ enum=InformationType, default=InformationType.PUBLIC)
@property
def private(self):
@@ -203,8 +206,14 @@
# otherwise we need to reload the value.
if private:
self.transitively_private = True
+ self.information_type = InformationType.USERDATA
else:
self.transitively_private = AutoReload
+ self.information_type = InformationType.PUBLIC
+
+ def transitionToInformationType(self, information_type, who):
+ """See `IBranch`."""
+ self.information_type = information_type
registrant = ForeignKey(
dbName='registrant', foreignKey='Person',
=== modified file 'lib/lp/code/model/branchnamespace.py'
--- lib/lp/code/model/branchnamespace.py 2011-12-30 06:14:56 +0000
+++ lib/lp/code/model/branchnamespace.py 2012-05-04 06:06:20 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Implementations of `IBranchNamespace`."""
@@ -44,6 +44,7 @@
)
from lp.code.interfaces.branchtarget import IBranchTarget
from lp.code.model.branch import Branch
+from lp.registry.enums import InformationType
from lp.registry.errors import (
NoSuchDistroSeries,
NoSuchSourcePackageName,
@@ -108,15 +109,19 @@
# If branches can be private, make them private initially.
private = self.areNewBranchesPrivate()
+ if private:
+ information_type = InformationType.USERDATA
+ else:
+ information_type = InformationType.PUBLIC
branch = Branch(
registrant=registrant,
name=name, owner=self.owner, product=product, url=url,
title=title, lifecycle_status=lifecycle_status, summary=summary,
whiteboard=whiteboard, explicitly_private=private,
- date_created=date_created, branch_type=branch_type,
- date_last_modified=date_created, branch_format=branch_format,
- repository_format=repository_format,
+ information_type=information_type, date_created=date_created,
+ branch_type=branch_type, date_last_modified=date_created,
+ branch_format=branch_format, repository_format=repository_format,
control_format=control_format, distroseries=distroseries,
sourcepackagename=sourcepackagename)
=== modified file 'lib/lp/code/model/tests/test_branch.py'
--- lib/lp/code/model/tests/test_branch.py 2012-04-13 18:31:35 +0000
+++ lib/lp/code/model/tests/test_branch.py 2012-05-04 06:06:20 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
# pylint: disable-msg=F0401,E1002
@@ -109,6 +109,7 @@
from lp.code.tests.helpers import add_revision_to_branch
from lp.codehosting.safe_open import BadUrl
from lp.codehosting.vfs.branchfs import get_real_branch_path
+from lp.registry.enums import InformationType
from lp.registry.interfaces.person import PersonVisibility
from lp.registry.interfaces.pocket import PackagePublishingPocket
from lp.registry.model.sourcepackage import SourcePackage
@@ -2350,6 +2351,7 @@
team = self.factory.makeTeam(visibility=PersonVisibility.PRIVATE)
branch = self.factory.makePersonalBranch(owner=team)
self.assertTrue(branch.private)
+ self.assertEqual(InformationType.USERDATA, branch.information_type)
class TestBranchSetPrivate(TestCaseWithFactory):
@@ -2380,6 +2382,7 @@
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):
# If there are no privacy policies allowing private branches, then
@@ -2418,6 +2421,7 @@
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):
# If the namespace policy does not allow public branches, attempting
=== modified file 'lib/lp/code/model/tests/test_branchnamespace.py'
--- lib/lp/code/model/tests/test_branchnamespace.py 2012-01-01 02:58:52 +0000
+++ lib/lp/code/model/tests/test_branchnamespace.py 2012-05-04 06:06:20 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Tests for `IBranchNamespace` implementations."""
@@ -35,6 +35,7 @@
PersonalNamespace,
ProductNamespace,
)
+from lp.registry.enums import InformationType
from lp.registry.errors import (
NoSuchDistroSeries,
NoSuchSourcePackageName,
@@ -79,6 +80,7 @@
BranchType.HOSTED, branch_name, registrant)
self.assertEqual(
expected_unique_name, branch.unique_name)
+ self.assertEqual(InformationType.PUBLIC, branch.information_type)
def test_createBranch_passes_through(self):
# createBranch takes all the arguments that the `Branch` constructor
@@ -373,6 +375,20 @@
team, BranchVisibilityRule.PRIVATE)
self.assertEqual(team, namespace.getPrivacySubscriber())
+ def test_information_type_private_team(self):
+ # Given a privacy policy for a namespace, branches are created with
+ # the correct information type.
+ person = self.factory.makePerson()
+ team = self.factory.makeTeam(owner=person)
+ product = self.factory.makeProduct()
+ namespace = ProductNamespace(team, product)
+ product.setBranchVisibilityTeamPolicy(
+ team, BranchVisibilityRule.PRIVATE)
+ branch = namespace.createBranch(
+ BranchType.HOSTED, self.factory.getUniqueString(),
+ namespace.owner)
+ self.assertEqual(InformationType.USERDATA, branch.information_type)
+
def test_subscriber_private_team_namespace(self):
# If there is a private policy for a namespace owner, then there is no
# privacy subscriber.
=== modified file 'lib/lp/scripts/garbo.py'
--- lib/lp/scripts/garbo.py 2012-04-25 14:10:24 +0000
+++ lib/lp/scripts/garbo.py 2012-05-04 06:06:20 +0000
@@ -51,6 +51,7 @@
MAX_SAMPLE_SIZE,
)
from lp.code.interfaces.revision import IRevisionSet
+from lp.code.model.branch import Branch
from lp.code.model.codeimportevent import CodeImportEvent
from lp.code.model.codeimportresult import CodeImportResult
from lp.code.model.revision import (
@@ -58,6 +59,7 @@
RevisionCache,
)
from lp.hardwaredb.model.hwdb import HWSubmission
+from lp.registry.enums import InformationType
from lp.registry.model.person import Person
from lp.services.config import config
from lp.services.database import postgresql
@@ -835,6 +837,30 @@
transaction.commit()
+class BranchInformationTypeMigrator(TunableLoop):
+ """A `TunableLoop` to populate information_type for all branches."""
+
+ maximum_chunk_size = 5000
+
+ def __init__(self, log, abort_time=None):
+ super(BranchInformationTypeMigrator, self).__init__(log, abort_time)
+ self.transaction = transaction
+ self.store = IMasterStore(Branch)
+
+ def findBranches(self):
+ return self.store.find(Branch, Branch.information_type == None)
+
+ def isDone(self):
+ return self.findBranches().is_empty()
+
+ def __call__(self, chunk_size):
+ self.findBranches()[:chunk_size].set(
+ information_type=SQL("CASE WHEN transitively_private THEN %s "
+ "ELSE %s END" % sqlvalues(
+ InformationType.USERDATA, InformationType.PUBLIC)))
+ self.transaction.commit()
+
+
class BugWatchActivityPruner(BulkPruner):
"""A TunableLoop to prune BugWatchActivity entries."""
target_table_class = BugWatchActivity
@@ -1382,6 +1408,7 @@
DuplicateSessionPruner,
BugHeatUpdater,
BugTaskFlattener,
+ BranchInformationTypeMigrator,
]
experimental_tunable_loops = []
=== modified file 'lib/lp/scripts/tests/test_garbo.py'
--- lib/lp/scripts/tests/test_garbo.py 2012-04-02 07:10:56 +0000
+++ lib/lp/scripts/tests/test_garbo.py 2012-05-04 06:06:20 +0000
@@ -55,6 +55,7 @@
)
from lp.code.model.codeimportevent import CodeImportEvent
from lp.code.model.codeimportresult import CodeImportResult
+from lp.registry.enums import InformationType
from lp.registry.interfaces.distribution import IDistributionSet
from lp.registry.interfaces.person import IPersonSet
from lp.scripts.garbo import (
@@ -1134,6 +1135,16 @@
'SELECT bugtask FROM BugTaskFlat WHERE bugtask = ?',
(task.id,)).get_one())
+ def test_BranchInformationTypeMigrator(self):
+ # A non-migrated branch will have information_type set correctly.
+ switch_dbuser('testadmin')
+ branch = self.factory.makeBranch(private=True)
+ # Since creating a branch will set information_type, unset it.
+ removeSecurityProxy(branch).information_type = None
+ transaction.commit()
+ self.runHourly()
+ self.assertEqual(InformationType.USERDATA, branch.information_type)
+
class TestGarboTasks(TestCaseWithFactory):
layer = LaunchpadZopelessLayer