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

Proposed by Steve Kowalik
Status: Merged
Approved by: Steve Kowalik
Approved revision: no longer in the source branch.
Merged at revision: 15307
Proposed branch: lp:~stevenk/launchpad/branch-use-information_type-redux
Merge into: lp:launchpad
Diff against target: 603 lines (+135/-100)
18 files modified
lib/lp/app/browser/tests/test_launchpad.py (+6/-3)
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/interfaces/branch.py (+7/-4)
lib/lp/code/model/branch.py (+35/-12)
lib/lp/code/model/tests/test_branch.py (+29/-3)
lib/lp/code/model/tests/test_branchlookup.py (+2/-1)
lib/lp/code/model/tests/test_branchmergeproposal.py (+4/-3)
lib/lp/code/model/tests/test_branchvisibility.py (+4/-7)
lib/lp/code/model/tests/test_sourcepackagerecipe.py (+3/-1)
lib/lp/code/model/tests/test_sourcepackagerecipebuild.py (+4/-2)
lib/lp/code/stories/branches/xx-branch-edit-privacy.txt (+0/-33)
lib/lp/code/stories/branches/xx-branch-index.txt (+0/-15)
lib/lp/code/xmlrpc/tests/test_branch.py (+4/-2)
lib/lp/registry/stories/product/xx-product-development-focus.txt (+6/-2)
lib/lp/testing/factory.py (+14/-6)
lib/lp/translations/tests/test_translationtemplatesbuildjob.py (+4/-2)
To merge this branch: bzr merge lp:~stevenk/launchpad/branch-use-information_type-redux
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+107150@code.launchpad.net

Commit message

Switch Branch to using information_type to check privacy by default.

Description of the change

Building on https://code.launchpad.net/~stevenk/launchpad/branch-use-information_type/+merge/106109 which got reverted due to test failures.

I have fixed the test failures, and have changed transitionToInformationType so it will change the information_type of branches stacked on the branch which information_type is being changed.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/app/browser/tests/test_launchpad.py'
2--- lib/lp/app/browser/tests/test_launchpad.py 2012-02-23 23:44:00 +0000
3+++ lib/lp/app/browser/tests/test_launchpad.py 2012-05-25 01:57:19 +0000
4@@ -1,4 +1,4 @@
5-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
6+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
7 # GNU Affero General Public License version 3 (see the file LICENSE).
8
9 """Tests for traversal from the root branch object."""
10@@ -20,6 +20,7 @@
11 from lp.app.errors import GoneError
12 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
13 from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch
14+from lp.registry.enums import InformationType
15 from lp.registry.interfaces.person import (
16 IPersonSet,
17 PersonVisibility,
18@@ -192,7 +193,8 @@
19 branch = self.factory.makeProductBranch()
20 naked_product = removeSecurityProxy(branch.product)
21 ICanHasLinkedBranch(naked_product).setBranch(branch)
22- removeSecurityProxy(branch).explicitly_private = True
23+ removeSecurityProxy(branch).information_type = (
24+ InformationType.USERDATA)
25 login(ANONYMOUS)
26 requiredMessage = (
27 u"The target %s does not have a linked branch." %
28@@ -218,7 +220,8 @@
29 branch = self.factory.makeProductBranch()
30 naked_product = removeSecurityProxy(branch.product)
31 ICanHasLinkedBranch(naked_product).setBranch(branch)
32- removeSecurityProxy(branch).explicitly_private = True
33+ removeSecurityProxy(branch).information_type = (
34+ InformationType.USERDATA)
35 login(ANONYMOUS)
36 self.assertNotFound(naked_product.name, use_default_referer=False)
37
38
39=== modified file 'lib/lp/code/browser/tests/test_branch.py'
40--- lib/lp/code/browser/tests/test_branch.py 2012-05-23 22:27:56 +0000
41+++ lib/lp/code/browser/tests/test_branch.py 2012-05-25 01:57:19 +0000
42@@ -758,7 +758,8 @@
43 # If the target is private, the landing targets should not include it.
44 bmp = self.factory.makeBranchMergeProposal()
45 branch = bmp.source_branch
46- removeSecurityProxy(bmp.target_branch).explicitly_private = True
47+ removeSecurityProxy(bmp.target_branch).information_type = (
48+ InformationType.USERDATA)
49 view = BranchView(branch, LaunchpadTestRequest())
50 self.assertTrue(view.no_merges)
51 self.assertEqual([], view.landing_targets)
52@@ -779,7 +780,8 @@
53 # it.
54 bmp = self.factory.makeBranchMergeProposal()
55 branch = bmp.target_branch
56- removeSecurityProxy(bmp.source_branch).explicitly_private = True
57+ removeSecurityProxy(bmp.source_branch).information_type = (
58+ InformationType.USERDATA)
59 view = BranchView(branch, LaunchpadTestRequest())
60 self.assertTrue(view.no_merges)
61 self.assertEqual([], view.landing_candidates)
62@@ -799,7 +801,8 @@
63 # the target is private, then the dependent_branches are not shown.
64 branch = self.factory.makeProductBranch()
65 bmp = self.factory.makeBranchMergeProposal(prerequisite_branch=branch)
66- removeSecurityProxy(bmp.source_branch).explicitly_private = True
67+ removeSecurityProxy(bmp.source_branch).information_type = (
68+ InformationType.USERDATA)
69 view = BranchView(branch, LaunchpadTestRequest())
70 self.assertTrue(view.no_merges)
71 self.assertEqual([], view.dependent_branches)
72
73=== modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py'
74--- lib/lp/code/browser/tests/test_branchmergeproposal.py 2012-05-23 22:27:56 +0000
75+++ lib/lp/code/browser/tests/test_branchmergeproposal.py 2012-05-25 01:57:19 +0000
76@@ -1290,7 +1290,8 @@
77 bmp2 = self.factory.makeBranchMergeProposal(
78 date_created=(
79 datetime(year=2008, month=10, day=10, tzinfo=pytz.UTC)))
80- removeSecurityProxy(bmp2.source_branch).explicitly_private = True
81+ removeSecurityProxy(bmp2.source_branch).information_type = (
82+ InformationType.USERDATA)
83 self.assertEqual(
84 [bmp1], latest_proposals_for_each_branch([bmp1, bmp2]))
85
86
87=== modified file 'lib/lp/code/errors.py'
88--- lib/lp/code/errors.py 2012-05-23 22:27:56 +0000
89+++ lib/lp/code/errors.py 2012-05-25 01:57:19 +0000
90@@ -10,6 +10,7 @@
91 'BadStateTransition',
92 'BranchCannotBePrivate',
93 'BranchCannotBePublic',
94+ 'BranchCannotChangeInformationType',
95 'BranchCreationException',
96 'BranchCreationForbidden',
97 'BranchCreatorNotMemberOfOwnerTeam',
98@@ -155,6 +156,10 @@
99 """The branch cannot be made private."""
100
101
102+class BranchCannotChangeInformationType(Exception):
103+ """The information type of this branch cannot be changed."""
104+
105+
106 class InvalidBranchException(Exception):
107 """Base exception for an error resolving a branch for a component.
108
109
110=== modified file 'lib/lp/code/interfaces/branch.py'
111--- lib/lp/code/interfaces/branch.py 2012-05-18 04:14:08 +0000
112+++ lib/lp/code/interfaces/branch.py 2012-05-25 01:57:19 +0000
113@@ -1120,11 +1120,14 @@
114 :raise: CannotDeleteBranch if the branch cannot be deleted.
115 """
116
117- def transitionToInformationType(information_type, who):
118- """Set the information type for this branch.
119+ def transitionToInformationType(information_type, who,
120+ verify_policy=True):
121+ """Set the information type for this branch.
122
123- :information_type: The `InformationType` to transition to.
124- :who: The `IPerson` who is making the change.
125+ :param information_type: The `InformationType` to transition to.
126+ :param who: The `IPerson` who is making the change.
127+ :param verify_policy: Check if the new information type complies
128+ with the `IBranchNamespacePolicy`.
129 """
130
131
132
133=== modified file 'lib/lp/code/model/branch.py'
134--- lib/lp/code/model/branch.py 2012-05-23 22:27:56 +0000
135+++ lib/lp/code/model/branch.py 2012-05-25 01:57:19 +0000
136@@ -77,6 +77,7 @@
137 AlreadyLatestFormat,
138 BranchCannotBePrivate,
139 BranchCannotBePublic,
140+ BranchCannotChangeInformationType,
141 BranchMergeProposalExists,
142 BranchTargetError,
143 BranchTypeError,
144@@ -128,7 +129,11 @@
145 )
146 from lp.code.model.seriessourcepackagebranch import SeriesSourcePackageBranch
147 from lp.codehosting.safe_open import safe_open
148-from lp.registry.enums import InformationType
149+from lp.registry.enums import (
150+ InformationType,
151+ PRIVATE_INFORMATION_TYPES,
152+ PUBLIC_INFORMATION_TYPES,
153+ )
154 from lp.registry.interfaces.person import (
155 validate_person,
156 validate_public_person,
157@@ -187,33 +192,42 @@
158
159 @property
160 def private(self):
161- return self.transitively_private
162+ return self.information_type in PRIVATE_INFORMATION_TYPES
163
164 def setPrivate(self, private, user):
165 """See `IBranch`."""
166- if private == self.explicitly_private:
167+ if private:
168+ information_type = InformationType.USERDATA
169+ else:
170+ information_type = InformationType.PUBLIC
171+ return self.transitionToInformationType(information_type, user)
172+
173+ def transitionToInformationType(self, information_type, who,
174+ verify_policy=True):
175+ """See `IBranch`."""
176+ if self.information_type == information_type:
177 return
178+ if (self.stacked_on
179+ and self.stacked_on.information_type in PRIVATE_INFORMATION_TYPES
180+ and information_type in PUBLIC_INFORMATION_TYPES):
181+ raise BranchCannotChangeInformationType()
182+ private = information_type in PRIVATE_INFORMATION_TYPES
183 # Only check the privacy policy if the user is not special.
184- if (not user_has_special_branch_access(user)):
185+ if verify_policy and not user_has_special_branch_access(who):
186 policy = IBranchNamespacePolicy(self.namespace)
187-
188 if private and not policy.canBranchesBePrivate():
189 raise BranchCannotBePrivate()
190 if not private and not policy.canBranchesBePublic():
191 raise BranchCannotBePublic()
192+ self.information_type = information_type
193+ # Set the legacy values for now.
194 self.explicitly_private = private
195 # If this branch is private, then it is also transitively_private
196 # otherwise we need to reload the value.
197 if private:
198 self.transitively_private = True
199- self.information_type = InformationType.USERDATA
200 else:
201 self.transitively_private = AutoReload
202- self.information_type = InformationType.PUBLIC
203-
204- def transitionToInformationType(self, information_type, who):
205- """See `IBranch`."""
206- self.information_type = information_type
207
208 registrant = ForeignKey(
209 dbName='registrant', foreignKey='Person',
210@@ -1052,6 +1066,15 @@
211 self.mirror_status_message = (
212 'Invalid stacked on location: ' + stacked_on_url)
213 self.stacked_on = stacked_on_branch
214+ # If the branch we are stacking on is not public, and we are,
215+ # set our information_type to the stacked on's, since having a
216+ # public branch stacked on a private branch does not make sense.
217+ if (self.stacked_on
218+ and self.stacked_on.information_type in PRIVATE_INFORMATION_TYPES
219+ and self.information_type in PUBLIC_INFORMATION_TYPES):
220+ self.transitionToInformationType(
221+ self.stacked_on.information_type, self.owner,
222+ verify_policy=False)
223 if self.branch_type == BranchType.HOSTED:
224 self.last_mirrored = UTC_NOW
225 else:
226@@ -1207,7 +1230,7 @@
227 This method doesn't check the stacked upon branch. That is handled by
228 the `visibleByUser` method.
229 """
230- if not self.explicitly_private:
231+ if self.information_type in PUBLIC_INFORMATION_TYPES:
232 return True
233 if user is None:
234 return False
235
236=== modified file 'lib/lp/code/model/tests/test_branch.py'
237--- lib/lp/code/model/tests/test_branch.py 2012-05-23 22:27:56 +0000
238+++ lib/lp/code/model/tests/test_branch.py 2012-05-25 01:57:19 +0000
239@@ -56,6 +56,7 @@
240 AlreadyLatestFormat,
241 BranchCannotBePrivate,
242 BranchCannotBePublic,
243+ BranchCannotChangeInformationType,
244 BranchCreatorNotMemberOfOwnerTeam,
245 BranchCreatorNotOwner,
246 BranchTargetError,
247@@ -2334,16 +2335,21 @@
248 def test_public_stacked_on_private_is_private(self):
249 # A public branch stacked on a private branch is private.
250 stacked_on = self.factory.makeBranch(private=True)
251- branch = self.factory.makeBranch(stacked_on=stacked_on, private=False)
252+ branch = self.factory.makeBranch(
253+ stacked_on=stacked_on, private=False)
254 self.assertTrue(branch.private)
255+ self.assertEqual(
256+ stacked_on.information_type, branch.information_type)
257 self.assertTrue(removeSecurityProxy(branch).transitively_private)
258- self.assertFalse(branch.explicitly_private)
259+ self.assertTrue(branch.explicitly_private)
260
261 def test_private_stacked_on_public_is_private(self):
262- # A public branch stacked on a private branch is private.
263+ # A private branch stacked on a public branch is private.
264 stacked_on = self.factory.makeBranch(private=False)
265 branch = self.factory.makeBranch(stacked_on=stacked_on, private=True)
266 self.assertTrue(branch.private)
267+ self.assertNotEqual(
268+ stacked_on.information_type, branch.information_type)
269 self.assertTrue(removeSecurityProxy(branch).transitively_private)
270 self.assertTrue(branch.explicitly_private)
271
272@@ -2436,6 +2442,26 @@
273 branch.setPrivate,
274 False, branch.owner)
275
276+ def test_cannot_transition_with_private_stacked_on(self):
277+ # If a public branch is stacked on a private branch, it can not
278+ # change its information_type to public.
279+ stacked_on = self.factory.makeBranch(private=True)
280+ branch = self.factory.makeBranch(stacked_on=stacked_on)
281+ self.assertRaises(
282+ BranchCannotChangeInformationType,
283+ branch.transitionToInformationType, InformationType.PUBLIC,
284+ branch.owner)
285+
286+ def test_can_transition_with_public_stacked_on(self):
287+ # If a private branch is stacked on a public branch, it can change
288+ # its information_type.
289+ stacked_on = self.factory.makeBranch()
290+ branch = self.factory.makeBranch(stacked_on=stacked_on, private=True)
291+ branch.transitionToInformationType(
292+ InformationType.UNEMBARGOEDSECURITY, branch.owner)
293+ self.assertEqual(
294+ InformationType.UNEMBARGOEDSECURITY, branch.information_type)
295+
296
297 class TestBranchCommitsForDays(TestCaseWithFactory):
298 """Tests for `Branch.commitsForDays`."""
299
300=== modified file 'lib/lp/code/model/tests/test_branchlookup.py'
301--- lib/lp/code/model/tests/test_branchlookup.py 2012-01-01 02:58:52 +0000
302+++ lib/lp/code/model/tests/test_branchlookup.py 2012-05-25 01:57:19 +0000
303@@ -147,7 +147,8 @@
304 owner = self.factory.makePerson()
305 private_branch = self.factory.makeAnyBranch(
306 owner=owner, private=True)
307- branch = self.factory.makeAnyBranch(stacked_on=private_branch)
308+ branch = self.factory.makeAnyBranch(
309+ stacked_on=private_branch, owner=owner)
310 with person_logged_in(owner):
311 path = branch_id_alias(branch)
312 result = self.branch_set.getIdAndTrailingPath(path)
313
314=== modified file 'lib/lp/code/model/tests/test_branchmergeproposal.py'
315--- lib/lp/code/model/tests/test_branchmergeproposal.py 2012-05-23 22:27:56 +0000
316+++ lib/lp/code/model/tests/test_branchmergeproposal.py 2012-05-25 01:57:19 +0000
317@@ -929,8 +929,9 @@
318 charlie, BranchSubscriptionNotificationLevel.NOEMAIL, None,
319 CodeReviewNotificationLevel.FULL, charlie)
320 # Make both branches private.
321- removeSecurityProxy(bmp.source_branch).explicitly_private = True
322- removeSecurityProxy(bmp.target_branch).explicitly_private = True
323+ for branch in (bmp.source_branch, bmp.target_branch):
324+ removeSecurityProxy(branch).information_type = (
325+ InformationType.USERDATA)
326 recipients = bmp.getNotificationRecipients(
327 CodeReviewNotificationLevel.FULL)
328 self.assertFalse(bob in recipients)
329@@ -1505,7 +1506,7 @@
330 base_branch = self.factory.makeBranch(
331 owner=owner, private=True, product=product)
332 source_branch = self.factory.makeBranch(
333- stacked_on=base_branch, product=product)
334+ stacked_on=base_branch, product=product, owner=owner)
335 target_branch = self.factory.makeBranch(owner=owner, product=product)
336 target_branch.product.setBranchVisibilityTeamPolicy(
337 owner, BranchVisibilityRule.PRIVATE)
338
339=== modified file 'lib/lp/code/model/tests/test_branchvisibility.py'
340--- lib/lp/code/model/tests/test_branchvisibility.py 2012-05-23 22:27:56 +0000
341+++ lib/lp/code/model/tests/test_branchvisibility.py 2012-05-25 01:57:19 +0000
342@@ -1,4 +1,4 @@
343-# Copyright 2011 Canonical Ltd. This software is licensed under the
344+# Copyright 2011-2012 Canonical Ltd. This software is licensed under the
345 # GNU Affero General Public License version 3 (see the file LICENSE).
346
347 """Tests for visibility of branches.
348@@ -134,14 +134,11 @@
349 private_owner = self.factory.makePerson()
350 test_branches = []
351 for x in range(5):
352- # We want the first 3 public and the last 3 private
353- branch = self.factory.makeBranch(name='branch_%s' % x)
354- # The 3rd, 4th and 5th will be explicitly private.
355- branch.explicitly_private = x > 2
356+ # We want the first 3 public and the last 3 private.
357+ branch = self.factory.makeBranch(private=x > 2)
358 test_branches.append(branch)
359 test_branches.append(
360- self.factory.makeBranch(
361- name='branch_5', private=True, owner=private_owner))
362+ self.factory.makeBranch(private=True, owner=private_owner))
363
364 # Anonymous users see just the public branches.
365 branch_info = [(branch, branch.private)
366
367=== modified file 'lib/lp/code/model/tests/test_sourcepackagerecipe.py'
368--- lib/lp/code/model/tests/test_sourcepackagerecipe.py 2012-02-28 11:14:44 +0000
369+++ lib/lp/code/model/tests/test_sourcepackagerecipe.py 2012-05-25 01:57:19 +0000
370@@ -50,6 +50,7 @@
371 )
372 from lp.code.model.sourcepackagerecipedata import SourcePackageRecipeData
373 from lp.code.tests.helpers import recipe_parser_newest_version
374+from lp.registry.enums import InformationType
375 from lp.registry.interfaces.pocket import PackagePublishingPocket
376 from lp.services.database.bulk import load_referencing
377 from lp.services.database.constants import UTC_NOW
378@@ -529,7 +530,8 @@
379 with person_logged_in(owner):
380 recipe = self.factory.makeSourcePackageRecipe(branches=[branch])
381 self.assertTrue(check_permission('launchpad.View', recipe))
382- removeSecurityProxy(branch).explicitly_private = True
383+ removeSecurityProxy(branch).information_type = (
384+ InformationType.USERDATA)
385 with person_logged_in(self.factory.makePerson()):
386 self.assertFalse(check_permission('launchpad.View', recipe))
387 self.assertFalse(check_permission('launchpad.View', recipe))
388
389=== modified file 'lib/lp/code/model/tests/test_sourcepackagerecipebuild.py'
390--- lib/lp/code/model/tests/test_sourcepackagerecipebuild.py 2012-04-24 06:44:30 +0000
391+++ lib/lp/code/model/tests/test_sourcepackagerecipebuild.py 2012-05-25 01:57:19 +0000
392@@ -1,4 +1,4 @@
393-# Copyright 2010-2011 Canonical Ltd. This software is licensed under the
394+# Copyright 2010-2012 Canonical Ltd. This software is licensed under the
395 # GNU Affero General Public License version 3 (see the file LICENSE).
396
397 """Tests for source package builds."""
398@@ -38,6 +38,7 @@
399 SourcePackageRecipeBuildMailer,
400 )
401 from lp.code.model.sourcepackagerecipebuild import SourcePackageRecipeBuild
402+from lp.registry.enums import InformationType
403 from lp.registry.interfaces.pocket import PackagePublishingPocket
404 from lp.registry.interfaces.series import SeriesStatus
405 from lp.services.database.lpstorm import IStore
406@@ -176,7 +177,8 @@
407 job = build.makeJob()
408 self.assertTrue(check_permission('launchpad.View', build))
409 self.assertTrue(check_permission('launchpad.View', job))
410- removeSecurityProxy(branch).explicitly_private = True
411+ removeSecurityProxy(branch).information_type = (
412+ InformationType.USERDATA)
413 with person_logged_in(self.factory.makePerson()):
414 self.assertFalse(check_permission('launchpad.View', build))
415 self.assertFalse(check_permission('launchpad.View', job))
416
417=== modified file 'lib/lp/code/stories/branches/xx-branch-edit-privacy.txt'
418--- lib/lp/code/stories/branches/xx-branch-edit-privacy.txt 2012-01-15 13:32:27 +0000
419+++ lib/lp/code/stories/branches/xx-branch-edit-privacy.txt 2012-05-25 01:57:19 +0000
420@@ -129,36 +129,3 @@
421 Traceback (most recent call last):
422 ...
423 LookupError: label 'Keep branch confidential'
424-
425-
426-Branches stacked on private branches
427-------------------------------------
428-
429-A public branch is private if it is stacked on a private branch. When the
430-branch is edited, it is shown as private but the checkbox widget is disabled
431-and the title and hint text is updated to inform the user.
432-
433- >>> login('admin@canonical.com')
434- >>> stacked_on_branch = factory.makeAnyBranch(private=True)
435- >>> stacked_branch = factory.makeAnyBranch(stacked_on=stacked_on_branch)
436- >>> url = canonical_url(stacked_branch)
437- >>> logout()
438-
439- >>> admin_browser.open(url)
440- >>> admin_browser.getLink('Change branch details').click()
441- >>> privacy_checkbox = admin_browser.getControl('Branch is confidential')
442- >>> print privacy_checkbox.selected
443- True
444- >>> print privacy_checkbox.disabled
445- True
446- >>> ('branch is confidential because it is stacked on a private branch'
447- ... in admin_browser.contents)
448- True
449-
450-If the branch is edited and saved, there is no user message displayed since
451-the transitive privacy status hasn't changed.
452-
453- >>> admin_browser.getControl('Description').value = "New changes"
454- >>> admin_browser.getControl('Change Branch').click()
455- >>> print_feedback_messages(browser.contents)
456- ...
457
458=== modified file 'lib/lp/code/stories/branches/xx-branch-index.txt'
459--- lib/lp/code/stories/branches/xx-branch-index.txt 2012-02-22 21:51:33 +0000
460+++ lib/lp/code/stories/branches/xx-branch-index.txt 2012-05-25 01:57:19 +0000
461@@ -409,21 +409,6 @@
462 >>> print extract_text(find_tag_by_id(content, 'privacy'))
463 This branch is public
464
465-We mark the stacked-on branch as private:
466-
467- >>> admin_browser.open(stacked_on_url)
468- >>> admin_browser.getLink('Change branch details').click()
469- >>> admin_browser.getControl('Keep branch confidential').selected = True
470- >>> admin_browser.getControl('Change Branch').click()
471-
472-Now the stacked branch is private:
473-
474- >>> admin_browser.open(url)
475- >>> content = find_tag_by_id(admin_browser.contents, 'document')
476- >>> print extract_text(find_tag_by_id(content, 'privacy'))
477- This branch is private because it is stacked on a private branch.
478-
479-
480 Navigation Context
481 ..................
482
483
484=== modified file 'lib/lp/code/xmlrpc/tests/test_branch.py'
485--- lib/lp/code/xmlrpc/tests/test_branch.py 2012-05-23 22:27:56 +0000
486+++ lib/lp/code/xmlrpc/tests/test_branch.py 2012-05-25 01:57:19 +0000
487@@ -1,4 +1,4 @@
488-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
489+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
490 # GNU Affero General Public License version 3 (see the file LICENSE).
491
492 """Unit tests for the public codehosting API."""
493@@ -16,6 +16,7 @@
494 from lp.code.interfaces.codehosting import BRANCH_ALIAS_PREFIX
495 from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch
496 from lp.code.xmlrpc.branch import PublicCodehostingAPI
497+from lp.registry.enums import InformationType
498 from lp.services.xmlrpc import LaunchpadFault
499 from lp.testing import (
500 person_logged_in,
501@@ -323,7 +324,8 @@
502 def test_private_branch_as_development_focus(self):
503 # We resolve private linked branches using the writable alias.
504 product, trunk = self.makeProdutWithTrunk()
505- removeSecurityProxy(trunk).explicitly_private = True
506+ removeSecurityProxy(trunk).information_type = (
507+ InformationType.USERDATA)
508 self.assertOnlyWritableResolves(product.name)
509
510 def test_private_branch_as_user(self):
511
512=== modified file 'lib/lp/registry/stories/product/xx-product-development-focus.txt'
513--- lib/lp/registry/stories/product/xx-product-development-focus.txt 2012-01-15 13:32:27 +0000
514+++ lib/lp/registry/stories/product/xx-product-development-focus.txt 2012-05-25 01:57:19 +0000
515@@ -14,7 +14,9 @@
516 >>> eric = factory.makePerson(name='eric', email='eric@example.com')
517 >>> fooix = factory.makeProduct(name='fooix', owner=eric)
518 >>> branch = factory.makeBranch(owner=eric, product=fooix, name='trunk')
519- >>> # Make revisions for the branch so it has a codebrowse link.
520+
521+Make revisions for the branch so it has a codebrowse link.
522+
523 >>> factory.makeRevisionsForBranch(branch)
524 >>> logout()
525
526@@ -145,7 +147,9 @@
527
528 >>> login('admin@canonical.com')
529 >>> from zope.security.proxy import removeSecurityProxy
530- >>> removeSecurityProxy(branch).explicitly_private = True
531+ >>> from lp.registry.enums import InformationType
532+ >>> removeSecurityProxy(branch).information_type = (
533+ ... InformationType.USERDATA)
534 >>> logout()
535
536 >>> anon_browser.open('http://launchpad.dev/fooix')
537
538=== modified file 'lib/lp/testing/factory.py'
539--- lib/lp/testing/factory.py 2012-05-23 22:27:56 +0000
540+++ lib/lp/testing/factory.py 2012-05-25 01:57:19 +0000
541@@ -1072,8 +1072,8 @@
542
543 def makeBranch(self, branch_type=None, owner=None,
544 name=None, product=_DEFAULT, url=_DEFAULT, registrant=None,
545- private=False, stacked_on=None, sourcepackage=None,
546- reviewer=None, **optional_branch_args):
547+ private=None, information_type=None, stacked_on=None,
548+ sourcepackage=None, reviewer=None, **optional_branch_args):
549 """Create and return a new, arbitrary Branch of the given type.
550
551 Any parameters for `IBranchNamespace.createBranch` can be specified to
552@@ -1119,11 +1119,19 @@
553 branch = namespace.createBranch(
554 branch_type=branch_type, name=name, registrant=registrant,
555 url=url, **optional_branch_args)
556- if private:
557- removeSecurityProxy(branch).explicitly_private = True
558- removeSecurityProxy(branch).transitively_private = True
559+ assert information_type is None or private is None, (
560+ "Can not specify both information_type and private")
561+ if private is not None:
562+ information_type = (
563+ InformationType.USERDATA if private else
564+ InformationType.PUBLIC)
565+ if information_type is not None:
566+ removeSecurityProxy(branch).transitionToInformationType(
567+ information_type, registrant, verify_policy=False)
568 if stacked_on is not None:
569- removeSecurityProxy(branch).stacked_on = stacked_on
570+ removeSecurityProxy(branch).branchChanged(
571+ removeSecurityProxy(stacked_on).unique_name, 'rev1', None,
572+ None, None)
573 if reviewer is not None:
574 removeSecurityProxy(branch).reviewer = reviewer
575 return branch
576
577=== modified file 'lib/lp/translations/tests/test_translationtemplatesbuildjob.py'
578--- lib/lp/translations/tests/test_translationtemplatesbuildjob.py 2012-01-01 02:58:52 +0000
579+++ lib/lp/translations/tests/test_translationtemplatesbuildjob.py 2012-05-25 01:57:19 +0000
580@@ -1,4 +1,4 @@
581-# Copyright 2010 Canonical Ltd. This software is licensed under the
582+# Copyright 2010-2012 Canonical Ltd. This software is licensed under the
583 # GNU Affero General Public License version 3 (see the file LICENSE).
584
585 __metaclass__ = type
586@@ -17,6 +17,7 @@
587 from lp.code.model.branchjob import BranchJob
588 from lp.code.model.directbranchcommit import DirectBranchCommit
589 from lp.codehosting.scanner import events
590+from lp.registry.enums import InformationType
591 from lp.services.job.model.job import Job
592 from lp.services.webapp.interfaces import (
593 DEFAULT_FLAVOR,
594@@ -249,7 +250,8 @@
595 def test_private_branch(self):
596 # We don't generate templates for private branches.
597 branch = self._makeTranslationBranch(fake_pottery_compatible=True)
598- removeSecurityProxy(branch).explicitly_private = True
599+ removeSecurityProxy(branch).information_type = (
600+ InformationType.USERDATA)
601 self.assertFalse(self.jobsource.generatesTemplates(branch))
602
603 def test_scheduleTranslationTemplatesBuild_subscribed(self):