Merge lp:~stevenk/launchpad/branch-use-information_type into lp:launchpad

Proposed by Steve Kowalik
Status: Merged
Approved by: Steve Kowalik
Approved revision: no longer in the source branch.
Merged at revision: 15289
Proposed branch: lp:~stevenk/launchpad/branch-use-information_type
Merge into: lp:launchpad
Diff against target: 355 lines (+102/-34)
9 files modified
lib/lp/code/browser/tests/test_branch.py (+6/-3)
lib/lp/code/browser/tests/test_branchmergeproposal.py (+2/-1)
lib/lp/code/errors.py (+5/-0)
lib/lp/code/model/branch.py (+32/-11)
lib/lp/code/model/tests/test_branch.py (+28/-2)
lib/lp/code/model/tests/test_branchmergeproposal.py (+3/-2)
lib/lp/code/model/tests/test_branchvisibility.py (+4/-7)
lib/lp/code/xmlrpc/tests/test_branch.py (+4/-2)
lib/lp/testing/factory.py (+18/-6)
To merge this branch: bzr merge lp:~stevenk/launchpad/branch-use-information_type
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+106109@code.launchpad.net

Commit message

Switch Branch to using information_type by default.

Description of the change

Switch Branch to using information_type by default. I have also moved the code from setPrivate to transitionToInformationType and made setPrivate a wrapper around it. Changing the information_type of a branch that is stacked on a non-public branch is now forbidden. IBranch.branchChanged() now forces the branch that is being stacked on top of an existing branch will have its information_type set to the stacked on information_type if it's not public.

I have changed the factory method makeBranch to take an information_type argument, and have also made it call IBranch.branchChanged() if stacked_on is set, which more closely mirrors what happens in production.

This necessitated changing a fair number of tests, which naively just set explicitly_private by hand. I've converted them to setting information_type, but am willing to make use of IBranch.setPrivate() or IBranch.transistionToInformationType() instead.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) wrote :

32 +def convert_to_information_type(private):
33 + if private:
34 + return InformationType.USERDATA
35 + else:
36 + return InformationType.PUBLIC

I'd put this in model rather than adapters. It's not useful outside model.

101 +class BranchCannotChangeInformationType(Exception):
102 + """The branch cannot change its information type."""

Of course it can't -- a branch isn't an actor. Do you mean that its information type can't be changed?

116 +from lazr.restful.interface import copy_field

Unused?

159 + @property
160 def private(self):
161 - return self.transitively_private
162 + return self.information_type in PRIVATE_INFORMATION_TYPES

Doesn't this need to defer to transitively_private if information_type? Depending on the way information_type is populated later, we may even need to ignore information_type completely until the migration is done.

174 + if (
175 + self.stacked_on and self.stacked_on.information_type !=
176 + InformationType.PUBLIC and information_type !=
177 + self.stacked_on.information_type):

That is the worst line wrapping in the history of the universe.

211 + if (
212 + self.stacked_on and self.stacked_on.information_type !=
213 + InformationType.PUBLIC):
214 + self.information_type = self.stacked_on.information_type

This could do with one fewer line breaks, and possibly a comment.

327 + if information_type:
328 + removeSecurityProxy(branch).information_type = information_type
329 if private:
330 removeSecurityProxy(branch).explicitly_private = True
331 removeSecurityProxy(branch).transitively_private = True
332 + if not information_type:
333 + removeSecurityProxy(branch).information_type = (
334 + InformationType.USERDATA)

Should you perhaps merge the two information_type bits? And how close are we to eliminating makeBranch(private)?

review: Approve (code)
Revision history for this message
William Grant (wgrant) wrote :

121 + if (self.stacked_on and self.stacked_on.information_type in
122 + PRIVATE_INFORMATION_TYPES and information_type in
123 + PUBLIC_INFORMATION_TYPES):

This linebreaking is still a capital offence in several jurisdictions. One legal spelling is this:

if (self.stacked on
    and self.stacked_on.information_type in PRIVATE_INFORMATION TYPES
    and information_type in PUBLIC_INFORMATION TYPES):

157 + # If the branch we are stacking on is not public, and we are,
158 + # set our information_type to the stacked on's.

This comment should explain why.

159 + if (self.stacked_on and self.stacked_on.information_type not in
160 + PUBLIC_INFORMATION_TYPES and self.information_type in
161 + PUBLIC_INFORMATION_TYPES):

Another capital offence.

273 + branch = self.factory.makeBranch(
274 + name='branch_%s' % x, private=x > 2)

That linebreak is probably no longer required.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/code/browser/tests/test_branch.py'
--- lib/lp/code/browser/tests/test_branch.py 2012-05-02 05:25:11 +0000
+++ lib/lp/code/browser/tests/test_branch.py 2012-05-23 05:26:23 +0000
@@ -758,7 +758,8 @@
758 # If the target is private, the landing targets should not include it.758 # If the target is private, the landing targets should not include it.
759 bmp = self.factory.makeBranchMergeProposal()759 bmp = self.factory.makeBranchMergeProposal()
760 branch = bmp.source_branch760 branch = bmp.source_branch
761 removeSecurityProxy(bmp.target_branch).explicitly_private = True761 removeSecurityProxy(bmp.target_branch).information_type = (
762 InformationType.USERDATA)
762 view = BranchView(branch, LaunchpadTestRequest())763 view = BranchView(branch, LaunchpadTestRequest())
763 self.assertTrue(view.no_merges)764 self.assertTrue(view.no_merges)
764 self.assertEqual([], view.landing_targets)765 self.assertEqual([], view.landing_targets)
@@ -779,7 +780,8 @@
779 # it.780 # it.
780 bmp = self.factory.makeBranchMergeProposal()781 bmp = self.factory.makeBranchMergeProposal()
781 branch = bmp.target_branch782 branch = bmp.target_branch
782 removeSecurityProxy(bmp.source_branch).explicitly_private = True783 removeSecurityProxy(bmp.source_branch).information_type = (
784 InformationType.USERDATA)
783 view = BranchView(branch, LaunchpadTestRequest())785 view = BranchView(branch, LaunchpadTestRequest())
784 self.assertTrue(view.no_merges)786 self.assertTrue(view.no_merges)
785 self.assertEqual([], view.landing_candidates)787 self.assertEqual([], view.landing_candidates)
@@ -799,7 +801,8 @@
799 # the target is private, then the dependent_branches are not shown.801 # the target is private, then the dependent_branches are not shown.
800 branch = self.factory.makeProductBranch()802 branch = self.factory.makeProductBranch()
801 bmp = self.factory.makeBranchMergeProposal(prerequisite_branch=branch)803 bmp = self.factory.makeBranchMergeProposal(prerequisite_branch=branch)
802 removeSecurityProxy(bmp.source_branch).explicitly_private = True804 removeSecurityProxy(bmp.source_branch).information_type = (
805 InformationType.USERDATA)
803 view = BranchView(branch, LaunchpadTestRequest())806 view = BranchView(branch, LaunchpadTestRequest())
804 self.assertTrue(view.no_merges)807 self.assertTrue(view.no_merges)
805 self.assertEqual([], view.dependent_branches)808 self.assertEqual([], view.dependent_branches)
806809
=== modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py'
--- lib/lp/code/browser/tests/test_branchmergeproposal.py 2012-05-02 05:25:11 +0000
+++ lib/lp/code/browser/tests/test_branchmergeproposal.py 2012-05-23 05:26:23 +0000
@@ -1290,7 +1290,8 @@
1290 bmp2 = self.factory.makeBranchMergeProposal(1290 bmp2 = self.factory.makeBranchMergeProposal(
1291 date_created=(1291 date_created=(
1292 datetime(year=2008, month=10, day=10, tzinfo=pytz.UTC)))1292 datetime(year=2008, month=10, day=10, tzinfo=pytz.UTC)))
1293 removeSecurityProxy(bmp2.source_branch).explicitly_private = True1293 removeSecurityProxy(bmp2.source_branch).information_type = (
1294 InformationType.USERDATA)
1294 self.assertEqual(1295 self.assertEqual(
1295 [bmp1], latest_proposals_for_each_branch([bmp1, bmp2]))1296 [bmp1], latest_proposals_for_each_branch([bmp1, bmp2]))
12961297
12971298
=== modified file 'lib/lp/code/errors.py'
--- lib/lp/code/errors.py 2012-02-21 22:46:28 +0000
+++ lib/lp/code/errors.py 2012-05-23 05:26:23 +0000
@@ -10,6 +10,7 @@
10 'BadStateTransition',10 'BadStateTransition',
11 'BranchCannotBePrivate',11 'BranchCannotBePrivate',
12 'BranchCannotBePublic',12 'BranchCannotBePublic',
13 'BranchCannotChangeInformationType',
13 'BranchCreationException',14 'BranchCreationException',
14 'BranchCreationForbidden',15 'BranchCreationForbidden',
15 'BranchCreatorNotMemberOfOwnerTeam',16 'BranchCreatorNotMemberOfOwnerTeam',
@@ -155,6 +156,10 @@
155 """The branch cannot be made private."""156 """The branch cannot be made private."""
156157
157158
159class BranchCannotChangeInformationType(Exception):
160 """The information type of this branch cannot be changed."""
161
162
158class InvalidBranchException(Exception):163class InvalidBranchException(Exception):
159 """Base exception for an error resolving a branch for a component.164 """Base exception for an error resolving a branch for a component.
160165
161166
=== modified file 'lib/lp/code/model/branch.py'
--- lib/lp/code/model/branch.py 2012-05-04 04:52:24 +0000
+++ lib/lp/code/model/branch.py 2012-05-23 05:26:23 +0000
@@ -77,6 +77,7 @@
77 AlreadyLatestFormat,77 AlreadyLatestFormat,
78 BranchCannotBePrivate,78 BranchCannotBePrivate,
79 BranchCannotBePublic,79 BranchCannotBePublic,
80 BranchCannotChangeInformationType,
80 BranchMergeProposalExists,81 BranchMergeProposalExists,
81 BranchTargetError,82 BranchTargetError,
82 BranchTypeError,83 BranchTypeError,
@@ -128,7 +129,11 @@
128 )129 )
129from lp.code.model.seriessourcepackagebranch import SeriesSourcePackageBranch130from lp.code.model.seriessourcepackagebranch import SeriesSourcePackageBranch
130from lp.codehosting.safe_open import safe_open131from lp.codehosting.safe_open import safe_open
131from lp.registry.enums import InformationType132from lp.registry.enums import (
133 InformationType,
134 PRIVATE_INFORMATION_TYPES,
135 PUBLIC_INFORMATION_TYPES,
136 )
132from lp.registry.interfaces.person import (137from lp.registry.interfaces.person import (
133 validate_person,138 validate_person,
134 validate_public_person,139 validate_public_person,
@@ -187,33 +192,42 @@
187192
188 @property193 @property
189 def private(self):194 def private(self):
190 return self.transitively_private195 return self.information_type in PRIVATE_INFORMATION_TYPES
191196
192 def setPrivate(self, private, user):197 def setPrivate(self, private, user):
193 """See `IBranch`."""198 """See `IBranch`."""
194 if private == self.explicitly_private:199 if private:
200 information_type = InformationType.USERDATA
201 else:
202 information_type = InformationType.PUBLIC
203 return self.transitionToInformationType(information_type, user)
204
205 def transitionToInformationType(self, information_type, who):
206 """See `IBranch`."""
207 if self.information_type == information_type:
195 return208 return
209 if (self.stacked_on
210 and self.stacked_on.information_type in PRIVATE_INFORMATION_TYPES
211 and information_type in PUBLIC_INFORMATION_TYPES):
212 raise BranchCannotChangeInformationType()
213 private = information_type in PRIVATE_INFORMATION_TYPES
196 # Only check the privacy policy if the user is not special.214 # Only check the privacy policy if the user is not special.
197 if (not user_has_special_branch_access(user)):215 if (not user_has_special_branch_access(who)):
198 policy = IBranchNamespacePolicy(self.namespace)216 policy = IBranchNamespacePolicy(self.namespace)
199217
200 if private and not policy.canBranchesBePrivate():218 if private and not policy.canBranchesBePrivate():
201 raise BranchCannotBePrivate()219 raise BranchCannotBePrivate()
202 if not private and not policy.canBranchesBePublic():220 if not private and not policy.canBranchesBePublic():
203 raise BranchCannotBePublic()221 raise BranchCannotBePublic()
222 self.information_type = information_type
223 # Set the legacy values for now.
204 self.explicitly_private = private224 self.explicitly_private = private
205 # If this branch is private, then it is also transitively_private225 # If this branch is private, then it is also transitively_private
206 # otherwise we need to reload the value.226 # otherwise we need to reload the value.
207 if private:227 if private:
208 self.transitively_private = True228 self.transitively_private = True
209 self.information_type = InformationType.USERDATA
210 else:229 else:
211 self.transitively_private = AutoReload230 self.transitively_private = AutoReload
212 self.information_type = InformationType.PUBLIC
213
214 def transitionToInformationType(self, information_type, who):
215 """See `IBranch`."""
216 self.information_type = information_type
217231
218 registrant = ForeignKey(232 registrant = ForeignKey(
219 dbName='registrant', foreignKey='Person',233 dbName='registrant', foreignKey='Person',
@@ -1052,6 +1066,13 @@
1052 self.mirror_status_message = (1066 self.mirror_status_message = (
1053 'Invalid stacked on location: ' + stacked_on_url)1067 'Invalid stacked on location: ' + stacked_on_url)
1054 self.stacked_on = stacked_on_branch1068 self.stacked_on = stacked_on_branch
1069 # If the branch we are stacking on is not public, and we are,
1070 # set our information_type to the stacked on's, since having a
1071 # public branch stacked on a private branch does not make sense.
1072 if (self.stacked_on
1073 and self.stacked_on.information_type in PRIVATE_INFORMATION_TYPES
1074 and self.information_type in PUBLIC_INFORMATION_TYPES):
1075 self.information_type = self.stacked_on.information_type
1055 if self.branch_type == BranchType.HOSTED:1076 if self.branch_type == BranchType.HOSTED:
1056 self.last_mirrored = UTC_NOW1077 self.last_mirrored = UTC_NOW
1057 else:1078 else:
@@ -1207,7 +1228,7 @@
1207 This method doesn't check the stacked upon branch. That is handled by1228 This method doesn't check the stacked upon branch. That is handled by
1208 the `visibleByUser` method.1229 the `visibleByUser` method.
1209 """1230 """
1210 if not self.explicitly_private:1231 if self.information_type not in PRIVATE_INFORMATION_TYPES:
1211 return True1232 return True
1212 if user is None:1233 if user is None:
1213 return False1234 return False
12141235
=== modified file 'lib/lp/code/model/tests/test_branch.py'
--- lib/lp/code/model/tests/test_branch.py 2012-05-04 04:52:24 +0000
+++ lib/lp/code/model/tests/test_branch.py 2012-05-23 05:26:23 +0000
@@ -56,6 +56,7 @@
56 AlreadyLatestFormat,56 AlreadyLatestFormat,
57 BranchCannotBePrivate,57 BranchCannotBePrivate,
58 BranchCannotBePublic,58 BranchCannotBePublic,
59 BranchCannotChangeInformationType,
59 BranchCreatorNotMemberOfOwnerTeam,60 BranchCreatorNotMemberOfOwnerTeam,
60 BranchCreatorNotOwner,61 BranchCreatorNotOwner,
61 BranchTargetError,62 BranchTargetError,
@@ -2334,16 +2335,21 @@
2334 def test_public_stacked_on_private_is_private(self):2335 def test_public_stacked_on_private_is_private(self):
2335 # A public branch stacked on a private branch is private.2336 # A public branch stacked on a private branch is private.
2336 stacked_on = self.factory.makeBranch(private=True)2337 stacked_on = self.factory.makeBranch(private=True)
2337 branch = self.factory.makeBranch(stacked_on=stacked_on, private=False)2338 branch = self.factory.makeBranch(
2339 stacked_on=stacked_on, private=False)
2338 self.assertTrue(branch.private)2340 self.assertTrue(branch.private)
2341 self.assertEqual(
2342 stacked_on.information_type, branch.information_type)
2339 self.assertTrue(removeSecurityProxy(branch).transitively_private)2343 self.assertTrue(removeSecurityProxy(branch).transitively_private)
2340 self.assertFalse(branch.explicitly_private)2344 self.assertFalse(branch.explicitly_private)
23412345
2342 def test_private_stacked_on_public_is_private(self):2346 def test_private_stacked_on_public_is_private(self):
2343 # A public branch stacked on a private branch is private.2347 # A private branch stacked on a public branch is private.
2344 stacked_on = self.factory.makeBranch(private=False)2348 stacked_on = self.factory.makeBranch(private=False)
2345 branch = self.factory.makeBranch(stacked_on=stacked_on, private=True)2349 branch = self.factory.makeBranch(stacked_on=stacked_on, private=True)
2346 self.assertTrue(branch.private)2350 self.assertTrue(branch.private)
2351 self.assertNotEqual(
2352 stacked_on.information_type, branch.information_type)
2347 self.assertTrue(removeSecurityProxy(branch).transitively_private)2353 self.assertTrue(removeSecurityProxy(branch).transitively_private)
2348 self.assertTrue(branch.explicitly_private)2354 self.assertTrue(branch.explicitly_private)
23492355
@@ -2436,6 +2442,26 @@
2436 branch.setPrivate,2442 branch.setPrivate,
2437 False, branch.owner)2443 False, branch.owner)
24382444
2445 def test_cannot_transition_with_private_stacked_on(self):
2446 # If a public branch is stacked on a private branch, it can not
2447 # change its information_type to public.
2448 stacked_on = self.factory.makeBranch(private=True)
2449 branch = self.factory.makeBranch(stacked_on=stacked_on)
2450 self.assertRaises(
2451 BranchCannotChangeInformationType,
2452 branch.transitionToInformationType, InformationType.PUBLIC,
2453 branch.owner)
2454
2455 def test_can_transition_with_public_stacked_on(self):
2456 # If a private branch is stacked on a public branch, it can change
2457 # its information_type.
2458 stacked_on = self.factory.makeBranch()
2459 branch = self.factory.makeBranch(stacked_on=stacked_on, private=True)
2460 branch.transitionToInformationType(
2461 InformationType.UNEMBARGOEDSECURITY, branch.owner)
2462 self.assertEqual(
2463 InformationType.UNEMBARGOEDSECURITY, branch.information_type)
2464
24392465
2440class TestBranchCommitsForDays(TestCaseWithFactory):2466class TestBranchCommitsForDays(TestCaseWithFactory):
2441 """Tests for `Branch.commitsForDays`."""2467 """Tests for `Branch.commitsForDays`."""
24422468
=== modified file 'lib/lp/code/model/tests/test_branchmergeproposal.py'
--- lib/lp/code/model/tests/test_branchmergeproposal.py 2012-05-02 05:25:11 +0000
+++ lib/lp/code/model/tests/test_branchmergeproposal.py 2012-05-23 05:26:23 +0000
@@ -929,8 +929,9 @@
929 charlie, BranchSubscriptionNotificationLevel.NOEMAIL, None,929 charlie, BranchSubscriptionNotificationLevel.NOEMAIL, None,
930 CodeReviewNotificationLevel.FULL, charlie)930 CodeReviewNotificationLevel.FULL, charlie)
931 # Make both branches private.931 # Make both branches private.
932 removeSecurityProxy(bmp.source_branch).explicitly_private = True932 for branch in (bmp.source_branch, bmp.target_branch):
933 removeSecurityProxy(bmp.target_branch).explicitly_private = True933 removeSecurityProxy(branch).information_type = (
934 InformationType.USERDATA)
934 recipients = bmp.getNotificationRecipients(935 recipients = bmp.getNotificationRecipients(
935 CodeReviewNotificationLevel.FULL)936 CodeReviewNotificationLevel.FULL)
936 self.assertFalse(bob in recipients)937 self.assertFalse(bob in recipients)
937938
=== modified file 'lib/lp/code/model/tests/test_branchvisibility.py'
--- lib/lp/code/model/tests/test_branchvisibility.py 2012-01-15 17:43:05 +0000
+++ lib/lp/code/model/tests/test_branchvisibility.py 2012-05-23 05:26:23 +0000
@@ -1,4 +1,4 @@
1# Copyright 2011 Canonical Ltd. This software is licensed under the1# Copyright 2011-2012 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Tests for visibility of branches.4"""Tests for visibility of branches.
@@ -134,14 +134,11 @@
134 private_owner = self.factory.makePerson()134 private_owner = self.factory.makePerson()
135 test_branches = []135 test_branches = []
136 for x in range(5):136 for x in range(5):
137 # We want the first 3 public and the last 3 private137 # We want the first 3 public and the last 3 private.
138 branch = self.factory.makeBranch(name='branch_%s' % x)138 branch = self.factory.makeBranch(private=x > 2)
139 # The 3rd, 4th and 5th will be explicitly private.
140 branch.explicitly_private = x > 2
141 test_branches.append(branch)139 test_branches.append(branch)
142 test_branches.append(140 test_branches.append(
143 self.factory.makeBranch(141 self.factory.makeBranch(private=True, owner=private_owner))
144 name='branch_5', private=True, owner=private_owner))
145142
146 # Anonymous users see just the public branches.143 # Anonymous users see just the public branches.
147 branch_info = [(branch, branch.private)144 branch_info = [(branch, branch.private)
148145
=== modified file 'lib/lp/code/xmlrpc/tests/test_branch.py'
--- lib/lp/code/xmlrpc/tests/test_branch.py 2012-01-01 02:58:52 +0000
+++ lib/lp/code/xmlrpc/tests/test_branch.py 2012-05-23 05:26:23 +0000
@@ -1,4 +1,4 @@
1# Copyright 2009-2011 Canonical Ltd. This software is licensed under the1# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Unit tests for the public codehosting API."""4"""Unit tests for the public codehosting API."""
@@ -16,6 +16,7 @@
16from lp.code.interfaces.codehosting import BRANCH_ALIAS_PREFIX16from lp.code.interfaces.codehosting import BRANCH_ALIAS_PREFIX
17from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch17from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch
18from lp.code.xmlrpc.branch import PublicCodehostingAPI18from lp.code.xmlrpc.branch import PublicCodehostingAPI
19from lp.registry.enums import InformationType
19from lp.services.xmlrpc import LaunchpadFault20from lp.services.xmlrpc import LaunchpadFault
20from lp.testing import (21from lp.testing import (
21 person_logged_in,22 person_logged_in,
@@ -323,7 +324,8 @@
323 def test_private_branch_as_development_focus(self):324 def test_private_branch_as_development_focus(self):
324 # We resolve private linked branches using the writable alias.325 # We resolve private linked branches using the writable alias.
325 product, trunk = self.makeProdutWithTrunk()326 product, trunk = self.makeProdutWithTrunk()
326 removeSecurityProxy(trunk).explicitly_private = True327 removeSecurityProxy(trunk).information_type = (
328 InformationType.USERDATA)
327 self.assertOnlyWritableResolves(product.name)329 self.assertOnlyWritableResolves(product.name)
328330
329 def test_private_branch_as_user(self):331 def test_private_branch_as_user(self):
330332
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2012-05-04 14:52:44 +0000
+++ lib/lp/testing/factory.py 2012-05-23 05:26:23 +0000
@@ -140,6 +140,7 @@
140 DistroSeriesDifferenceStatus,140 DistroSeriesDifferenceStatus,
141 DistroSeriesDifferenceType,141 DistroSeriesDifferenceType,
142 InformationType,142 InformationType,
143 PRIVATE_INFORMATION_TYPES,
143 )144 )
144from lp.registry.interfaces.accesspolicy import (145from lp.registry.interfaces.accesspolicy import (
145 IAccessArtifactGrantSource,146 IAccessArtifactGrantSource,
@@ -1072,8 +1073,8 @@
10721073
1073 def makeBranch(self, branch_type=None, owner=None,1074 def makeBranch(self, branch_type=None, owner=None,
1074 name=None, product=_DEFAULT, url=_DEFAULT, registrant=None,1075 name=None, product=_DEFAULT, url=_DEFAULT, registrant=None,
1075 private=False, stacked_on=None, sourcepackage=None,1076 private=None, information_type=None, stacked_on=None,
1076 reviewer=None, **optional_branch_args):1077 sourcepackage=None, reviewer=None, **optional_branch_args):
1077 """Create and return a new, arbitrary Branch of the given type.1078 """Create and return a new, arbitrary Branch of the given type.
10781079
1079 Any parameters for `IBranchNamespace.createBranch` can be specified to1080 Any parameters for `IBranchNamespace.createBranch` can be specified to
@@ -1119,11 +1120,22 @@
1119 branch = namespace.createBranch(1120 branch = namespace.createBranch(
1120 branch_type=branch_type, name=name, registrant=registrant,1121 branch_type=branch_type, name=name, registrant=registrant,
1121 url=url, **optional_branch_args)1122 url=url, **optional_branch_args)
1122 if private:1123 assert information_type is None or private is None, (
1123 removeSecurityProxy(branch).explicitly_private = True1124 "Can not specify both information_type and private")
1124 removeSecurityProxy(branch).transitively_private = True1125 if information_type is not None or private is not None:
1126 if information_type:
1127 private = information_type in PRIVATE_INFORMATION_TYPES
1128 else:
1129 information_type = (
1130 InformationType.USERDATA if private else
1131 InformationType.PUBLIC)
1132 if private:
1133 removeSecurityProxy(branch).explicitly_private = True
1134 removeSecurityProxy(branch).transitively_private = True
1135 removeSecurityProxy(branch).information_type = information_type
1125 if stacked_on is not None:1136 if stacked_on is not None:
1126 removeSecurityProxy(branch).stacked_on = stacked_on1137 removeSecurityProxy(branch).branchChanged(
1138 stacked_on.unique_name, 'rev1', None, None, None)
1127 if reviewer is not None:1139 if reviewer is not None:
1128 removeSecurityProxy(branch).reviewer = reviewer1140 removeSecurityProxy(branch).reviewer = reviewer
1129 return branch1141 return branch