Merge lp:~stevenk/launchpad/branch-use-information_type-redux into lp:launchpad
- branch-use-information_type-redux
- Merge into devel
Proposed by
Steve Kowalik
on 2012-05-24
| Status: | Merged |
|---|---|
| Approved by: | Steve Kowalik on 2012-05-24 |
| 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 |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| William Grant | code | 2012-05-24 | Approve on 2012-05-24 |
|
Review via email:
|
|||
Commit Message
Switch Branch to using information_type to check privacy by default.
Description of the Change
Building on https:/
I have fixed the test failures, and have changed transitionToInf
To post a comment you must log in.
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): |
