Merge lp:~thumper/launchpad/ibranch-interface-smashing into lp:launchpad

Proposed by Tim Penhey
Status: Merged
Approved by: Robert Collins
Approved revision: no longer in the source branch.
Merged at revision: 11203
Proposed branch: lp:~thumper/launchpad/ibranch-interface-smashing
Merge into: lp:launchpad
Diff against target: 750 lines (+259/-335)
3 files modified
lib/lp/code/configure.zcml (+17/-117)
lib/lp/code/interfaces/branch.py (+239/-216)
lib/lp/code/model/branch.py (+3/-2)
To merge this branch: bzr merge lp:~thumper/launchpad/ibranch-interface-smashing
Reviewer Review Type Date Requested Status
Paul Hummer (community) code Approve
Review via email: mp+29969@code.launchpad.net

Commit message

Move the attributes and methods of IBranch to other interfaces based on permissions.

Description of the change

Break the IBranch interface into other interfaces based on the required permissions.

There should be no other changes necessary.

There are two slight oddities with the resulting code.

I changed the IPrivacy inheritance in IBranch to be something that Branch directly provides. This is due to the fact that we were reimplmenting (or overriding) the private attribute defined by IPrivacy in the IBranch interface.

Secondly we are using an api mutator decorator on "private" which doesn't work when the private attibute isn't available in the same interface, so for now, I've left both private and setPrivate on IBranch.

To post a comment you must log in.
Revision history for this message
Paul Hummer (rockstar) wrote :

boring

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/configure.zcml'
--- lib/lp/code/configure.zcml 2010-07-22 01:48:51 +0000
+++ lib/lp/code/configure.zcml 2010-07-22 09:28:53 +0000
@@ -439,129 +439,29 @@
439 <class class="lp.code.model.branch.Branch">439 <class class="lp.code.model.branch.Branch">
440 <require440 <require
441 permission="launchpad.View"441 permission="launchpad.View"
442 attributes="id442 interface="canonical.launchpad.interfaces.launchpad.IPrivacy
443 branch_type443 lp.code.interfaces.branch.IBranchAnyone
444 name444 lp.code.interfaces.branch.IBranchEditableAttributes
445 url445 lp.code.interfaces.branch.IBranchPublic
446 composePublicURL446 lp.code.interfaces.branch.IBranchView
447 whiteboard447 "/>
448 target
449 mirror_status_message
450 private
451 registrant
452 owner
453 description
454 author
455 reviewer
456 code_reviewer
457 isPersonTrustedReviewer
458 product
459 unique_name
460 displayname
461 sort_key
462 lifecycle_status
463 last_mirrored
464 last_mirrored_id
465 last_mirror_attempt
466 mirror_failures
467 pull_disabled
468 next_mirror_time
469 last_scanned
470 last_scanned_id
471 revision_count
472 bug_branches
473 linked_bugs
474 getLinkedBugsAndTasks
475 linkBug
476 unlinkBug
477 spec_links
478 linkSpecification
479 unlinkSpecification
480 revision_history
481 subscriptions
482 subscribers
483 date_created
484 date_last_modified
485 latest_revisions
486 landing_targets
487 landing_candidates
488 dependent_branches
489 _createMergeProposal
490 addLandingTarget
491 scheduleDiffUpdates
492 getMergeQueue
493 getRevisionsSince
494 code_is_browseable
495 browse_source_url
496 code_import
497 bzr_identity
498 canBeDeleted
499 deletionRequirements
500 associatedProductSeries
501 getProductSeriesPushingTranslations
502 associatedSuiteSourcePackages
503 branchIdentities
504 branchLinks
505 subscribe
506 getSubscription
507 hasSubscription
508 unsubscribe
509 getSubscriptionsByLevel
510 getBranchRevision
511 getMainlineBranchRevisions
512 getMergeProposals
513 getStackedBranches
514 createBranchRevision
515 getTipRevision
516 updateScannedDetails
517 getNotificationRecipients
518 getScannerData
519 getPullURL
520 getInternalBzrUrl
521 getBzrBranch
522 requestMirror
523 startMirroring
524 mirrorFailed
525 branch_format
526 repository_format
527 control_format
528 stacked_on
529 createBranchRevisionFromIDs
530 distroseries
531 sourcepackagename
532 addToLaunchBag
533 distribution
534 sourcepackage
535 codebrowse_url
536 merge_queue
537 namespace
538 pending_writes
539 commitsForDays
540 needs_upgrading
541 upgrade_pending
542 getUpgradeFormat
543 isBranchMergeable
544 visibleByUser
545 getRecipes
546 "/>
547 <require448 <require
548 permission="launchpad.Edit"449 permission="launchpad.Edit"
549 attributes="destroySelf destroySelfBreakReferences setPrivate450 interface="lp.code.interfaces.branch.IBranchEdit"
550 setOwner setTarget requestUpgrade branchChanged"451 set_schema="lp.code.interfaces.branch.IBranchEditableAttributes"
551 set_attributes="name url mirror_status_message452 attributes="setPrivate"
552 description lifecycle_status453 set_attributes="branch_format control_format repository_format
553 last_mirrored last_mirrored_id last_mirror_attempt454 branch_type
554 mirror_failures pull_disabled next_mirror_time455 last_scanned last_scanned_id
555 last_scanned last_scanned_id revision_count branch_type456 last_mirrored last_mirrored_id next_mirror_time
556 reviewer branch_format repository_format457 revision_count merge_queue mirror_failures
557 control_format stacked_on merge_queue458 stacked_on mirror_status_message"/>
558 merge_control_status"/>
559 <require459 <require
560 permission="launchpad.AnyPerson"460 permission="launchpad.AnyPerson"
561 set_attributes="whiteboard"/>461 set_schema="lp.code.interfaces.branch.IBranchAnyone"/>
562 <require462 <require
563 permission="zope.Public"463 permission="zope.Public"
564 set_attributes="date_last_modified"/>464 set_schema="lp.code.interfaces.branch.IBranchPublic"/>
565 </class>465 </class>
566 <adapter466 <adapter
567 for="lp.code.interfaces.branch.IBranch"467 for="lp.code.interfaces.branch.IBranch"
568468
=== modified file 'lib/lp/code/interfaces/branch.py'
--- lib/lp/code/interfaces/branch.py 2010-07-09 10:22:32 +0000
+++ lib/lp/code/interfaces/branch.py 2010-07-22 09:28:53 +0000
@@ -57,12 +57,17 @@
57from canonical.launchpad import _57from canonical.launchpad import _
58from canonical.launchpad.fields import (58from canonical.launchpad.fields import (
59 ParticipatingPersonChoice, PublicPersonChoice, URIField, Whiteboard)59 ParticipatingPersonChoice, PublicPersonChoice, URIField, Whiteboard)
60from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
60from canonical.launchpad.validators import LaunchpadValidationError61from canonical.launchpad.validators import LaunchpadValidationError
62from canonical.launchpad.webapp.interfaces import (
63 ITableBatchNavigator, NameLookupFailed)
64from canonical.launchpad.webapp.menu import structured
61from lp.code.bzr import BranchFormat, ControlFormat, RepositoryFormat65from lp.code.bzr import BranchFormat, ControlFormat, RepositoryFormat
62from lp.code.enums import (66from lp.code.enums import (
63 BranchLifecycleStatus,67 BranchLifecycleStatus,
64 BranchMergeControlStatus,68 BranchMergeControlStatus,
65 BranchSubscriptionNotificationLevel, BranchSubscriptionDiffSize,69 BranchSubscriptionDiffSize,
70 BranchSubscriptionNotificationLevel,
66 CodeReviewNotificationLevel,71 CodeReviewNotificationLevel,
67 UICreatableBranchType,72 UICreatableBranchType,
68 )73 )
@@ -71,14 +76,9 @@
71from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch76from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch
72from lp.code.interfaces.hasbranches import IHasMergeProposals77from lp.code.interfaces.hasbranches import IHasMergeProposals
73from lp.code.interfaces.hasrecipes import IHasRecipes78from lp.code.interfaces.hasrecipes import IHasRecipes
74from canonical.launchpad.interfaces.launchpad import (
75 ILaunchpadCelebrities, IPrivacy)
76from lp.registry.interfaces.role import IHasOwner79from lp.registry.interfaces.role import IHasOwner
77from lp.registry.interfaces.person import IPerson80from lp.registry.interfaces.person import IPerson
78from lp.registry.interfaces.pocket import PackagePublishingPocket81from lp.registry.interfaces.pocket import PackagePublishingPocket
79from canonical.launchpad.webapp.interfaces import (
80 ITableBatchNavigator, NameLookupFailed)
81from canonical.launchpad.webapp.menu import structured
8282
8383
84DEFAULT_BRANCH_STATUS_IN_LISTING = (84DEFAULT_BRANCH_STATUS_IN_LISTING = (
@@ -317,50 +317,31 @@
317 """A marker interface to indicate the need to show the branch menu."""317 """A marker interface to indicate the need to show the branch menu."""
318318
319319
320class IBranch(IHasOwner, IPrivacy, IHasBranchTarget, IHasMergeProposals,320class IBranchPublic(Interface):
321 IHasRecipes):321 """Public attributes for a branch."""
322 """A Bazaar branch."""322
323323 date_last_modified = exported(
324 # Mark branches as exported entries for the Launchpad API.324 Datetime(
325 export_as_webservice_entry(plural_name='branches')325 title=_('Date Last Modified'),
326 required=True,
327 readonly=False))
328
329
330class IBranchAnyone(Interface):
331 """Attributes of IBranch that can be changed by launchpad.AnyPerson."""
332
333 whiteboard = exported(
334 Whiteboard(
335 title=_('Whiteboard'), required=False,
336 description=_('Notes on the current status of the branch.')))
337
338
339class IBranchView(IHasOwner, IHasBranchTarget, IHasMergeProposals,
340 IHasRecipes):
341 """IBranch attributes that require launchpad.View permission."""
326342
327 id = Int(title=_('ID'), readonly=True, required=True)343 id = Int(title=_('ID'), readonly=True, required=True)
328344
329 # XXX: TimPenhey 2007-08-31
330 # The vocabulary set for branch_type is only used for the creation
331 # of branches through the automatically generated forms, and doesn't
332 # actually represent the complete range of real values that branch_type
333 # may actually hold. Import branches are not created in the same
334 # way as Hosted, Mirrored or Remote branches.
335 # There are two option:
336 # 1) define a separate schema to use in the UI (sledgehammer solution)
337 # 2) work out some way to specify a restricted vocabulary in the view
338 # Personally I'd like a LAZR way to do number 2.
339 branch_type = exported(
340 Choice(
341 title=_("Branch Type"), required=True, readonly=True,
342 vocabulary=UICreatableBranchType))
343
344 name = exported(
345 TextLine(
346 title=_('Name'), required=True, constraint=branch_name_validator,
347 description=_(
348 "Keep very short, unique, and descriptive, because it will "
349 "be used in URLs. "
350 "Examples: main, devel, release-1.0, gnome-vfs.")))
351
352 url = exported(
353 BranchURIField(
354 title=_('Branch URL'), required=False,
355 allowed_schemes=['http', 'https', 'ftp', 'sftp', 'bzr+ssh'],
356 allow_userinfo=False,
357 allow_query=False,
358 allow_fragment=False,
359 trailing_slash=False,
360 description=_(
361 "This is the external location where the Bazaar "
362 "branch is hosted.")))
363
364 @operation_parameters(345 @operation_parameters(
365 scheme=TextLine(title=_("URL scheme"), default=u'http'))346 scheme=TextLine(title=_("URL scheme"), default=u'http'))
366 @export_read_operation()347 @export_read_operation()
@@ -372,57 +353,6 @@
372 accepted).353 accepted).
373 """354 """
374355
375 description = exported(
376 Text(
377 title=_('Description'), required=False,
378 description=_(
379 'A short description of the changes in this branch.')))
380
381 branch_format = exported(
382 Choice(
383 title=_("Branch Format"),
384 required=False, readonly=True,
385 vocabulary=BranchFormat))
386
387 repository_format = exported(
388 Choice(
389 title=_("Repository Format"),
390 required=False, readonly=True,
391 vocabulary=RepositoryFormat))
392
393 control_format = exported(
394 Choice(
395 title=_("Control Directory"),
396 required=False, readonly=True,
397 vocabulary=ControlFormat))
398
399 whiteboard = exported(
400 Whiteboard(
401 title=_('Whiteboard'), required=False,
402 description=_('Notes on the current status of the branch.')))
403
404 mirror_status_message = exported(
405 Text(
406 title=_('The last message we got when mirroring this branch.'),
407 required=False, readonly=True))
408
409 # This is redefined from IPrivacy.private because the attribute is
410 # read-only. The value is guarded by setPrivate().
411 private = exported(
412 Bool(
413 title=_("Keep branch confidential"), required=False,
414 readonly=True, default=False,
415 description=_(
416 "Make this branch visible only to its subscribers.")))
417
418 @mutator_for(private)
419 @call_with(user=REQUEST_USER)
420 @operation_parameters(
421 private=Bool(title=_("Keep branch confidential")))
422 @export_write_operation()
423 def setPrivate(private, user):
424 """Set the branch privacy for this branch."""
425
426 # People attributes356 # People attributes
427 registrant = exported(357 registrant = exported(
428 PublicPersonChoice(358 PublicPersonChoice(
@@ -438,44 +368,6 @@
438 description=_("Either yourself or a team you are a member of. "368 description=_("Either yourself or a team you are a member of. "
439 "This controls who can modify the branch.")))369 "This controls who can modify the branch.")))
440370
441 @call_with(user=REQUEST_USER)
442 @operation_parameters(
443 new_owner=Reference(
444 title=_("The new owner of the branch."),
445 schema=IPerson))
446 @export_write_operation()
447 def setOwner(new_owner, user):
448 """Set the owner of the branch to be `new_owner`."""
449
450 @call_with(user=REQUEST_USER)
451 @operation_parameters(
452 project=Reference(
453 title=_("The project the branch belongs to."),
454 schema=Interface, required=False), # Really IProduct
455 source_package=Reference(
456 title=_("The source package the branch belongs to."),
457 schema=Interface, required=False)) # Really ISourcePackage
458 @export_write_operation()
459 def setTarget(user, project=None, source_package=None):
460 """Set the target of the branch to be `project` or `source_package`.
461
462 Only one of `project` or `source_package` can be set, and if neither
463 is set, the branch gets moved into the junk namespace of the branch
464 owner.
465
466 :raise: `BranchTargetError` if both project and source_package are set,
467 or if either the project or source_package fail to be adapted to an
468 IBranchTarget.
469 """
470
471 reviewer = exported(
472 PublicPersonChoice(
473 title=_('Review Team'),
474 required=False,
475 vocabulary='ValidPersonOrTeam',
476 description=_("The reviewer of a branch is the person or team "
477 "that is responsible for reviewing proposals and "
478 "merging into this branch.")))
479371
480 # Distroseries and sourcepackagename are exported together as372 # Distroseries and sourcepackagename are exported together as
481 # the sourcepackage.373 # the sourcepackage.
@@ -505,22 +397,6 @@
505 "None if not a package branch."),397 "None if not a package branch."),
506 schema=Interface, required=False, readonly=True))398 schema=Interface, required=False, readonly=True))
507399
508 code_reviewer = Attribute(
509 "The reviewer if set, otherwise the owner of the branch.")
510
511 @operation_parameters(
512 reviewer=Reference(
513 title=_("A person for which the reviewer status is in question."),
514 schema=IPerson))
515 @export_read_operation()
516 def isPersonTrustedReviewer(reviewer):
517 """Return true if the `reviewer` is a trusted reviewer.
518
519 The reviewer is trusted if they are either own the branch, or are in
520 the team that owns the branch, or they are in the review team for the
521 branch.
522 """
523
524 namespace = Attribute(400 namespace = Attribute(
525 "The namespace of this branch, as an `IBranchNamespace`.")401 "The namespace of this branch, as an `IBranchNamespace`.")
526402
@@ -549,29 +425,38 @@
549 "The branch unique_name.")),425 "The branch unique_name.")),
550 exported_as='display_name')426 exported_as='display_name')
551427
552 # Stats and status attributes428 code_reviewer = Attribute(
553 lifecycle_status = exported(429 "The reviewer if set, otherwise the owner of the branch.")
554 Choice(430
555 title=_('Status'), vocabulary=BranchLifecycleStatus,431 @operation_parameters(
556 default=BranchLifecycleStatus.DEVELOPMENT))432 reviewer=Reference(
557433 title=_("A person for which the reviewer status is in question."),
558 # Mirroring attributes. For more information about how these all relate to434 schema=IPerson))
559 # each other, look at435 @export_read_operation()
560 # 'lib/canonical/launchpad/doc/puller-state-table.ods'.436 def isPersonTrustedReviewer(reviewer):
437 """Return true if the `reviewer` is a trusted reviewer.
438
439 The reviewer is trusted if they are either own the branch, or are in
440 the team that owns the branch, or they are in the review team for the
441 branch.
442 """
443
561 last_mirrored = exported(444 last_mirrored = exported(
562 Datetime(445 Datetime(
563 title=_("Last time this branch was successfully mirrored."),446 title=_("Last time this branch was successfully mirrored."),
564 required=False, readonly=True))447 required=False, readonly=True))
565 last_mirrored_id = Text(448 last_mirrored_id = Text(
566 title=_("Last mirrored revision ID"), required=False,449 title=_("Last mirrored revision ID"), required=False, readonly=True,
567 description=_("The head revision ID of the branch when last "450 description=_("The head revision ID of the branch when last "
568 "successfully mirrored."))451 "successfully mirrored."))
569 last_mirror_attempt = exported(452 last_mirror_attempt = exported(
570 Datetime(453 Datetime(
571 title=_("Last time a mirror of this branch was attempted."),454 title=_("Last time a mirror of this branch was attempted."),
572 required=False, readonly=True))455 required=False, readonly=True))
456
573 mirror_failures = Attribute(457 mirror_failures = Attribute(
574 "Number of failed mirror attempts since the last successful mirror.")458 "Number of failed mirror attempts since the last successful mirror.")
459
575 next_mirror_time = Datetime(460 next_mirror_time = Datetime(
576 title=_("If this value is more recent than the last mirror attempt, "461 title=_("If this value is more recent than the last mirror attempt, "
577 "then the branch will be mirrored on the next mirror run."),462 "then the branch will be mirrored on the next mirror run."),
@@ -596,6 +481,9 @@
596481
597 stacked_on = Attribute('Stacked-on branch')482 stacked_on = Attribute('Stacked-on branch')
598483
484 merge_queue = Attribute(
485 "The queue that contains the QUEUED proposals for this branch.")
486
599 # Bug attributes487 # Bug attributes
600 bug_branches = CollectionField(488 bug_branches = CollectionField(
601 title=_("The bug-branch link objects that link this branch "489 title=_("The bug-branch link objects that link this branch "
@@ -663,9 +551,6 @@
663 :param user: IPerson unlinking the spec.551 :param user: IPerson unlinking the spec.
664 """552 """
665553
666 pending_writes = Attribute(
667 "Whether there is new Bazaar data for this branch.")
668
669 # Joins554 # Joins
670 revision_history = Attribute(555 revision_history = Attribute(
671 """The sequence of BranchRevision for the mainline of that branch.556 """The sequence of BranchRevision for the mainline of that branch.
@@ -693,30 +578,8 @@
693 required=True,578 required=True,
694 readonly=True))579 readonly=True))
695580
696 date_last_modified = exported(581 pending_writes = Attribute(
697 Datetime(582 "Whether there is new Bazaar data for this branch.")
698 title=_('Date Last Modified'),
699 required=True,
700 readonly=False))
701
702 @export_destructor_operation()
703 def destroySelfBreakReferences():
704 """Delete the specified branch.
705
706 BranchRevisions associated with this branch will also be deleted as
707 well as any items with mandatory references.
708 """
709
710 def destroySelf(break_references=False):
711 """Delete the specified branch.
712
713 BranchRevisions associated with this branch will also be deleted.
714
715 :param break_references: If supplied, break any references to this
716 branch by deleting items with mandatory references and
717 NULLing other references.
718 :raise: CannotDeleteBranch if the branch cannot be deleted.
719 """
720583
721 def latest_revisions(quantity=10):584 def latest_revisions(quantity=10):
722 """A specific number of the latest revisions in that branch."""585 """A specific number of the latest revisions in that branch."""
@@ -815,14 +678,6 @@
815 def getStackedBranches():678 def getStackedBranches():
816 """The branches that are stacked on this one."""679 """The branches that are stacked on this one."""
817680
818 merge_queue = Attribute(
819 "The queue that contains the QUEUED proposals for this branch.")
820
821 merge_control_status = Choice(
822 title=_('Merge Control Status'), required=True,
823 vocabulary=BranchMergeControlStatus,
824 default=BranchMergeControlStatus.NO_QUEUE)
825
826 def getMergeQueue():681 def getMergeQueue():
827 """The proposals that are QUEUED to land on this branch."""682 """The proposals that are QUEUED to land on this branch."""
828683
@@ -1111,23 +966,6 @@
1111 def startMirroring():966 def startMirroring():
1112 """Signal that this branch is being mirrored."""967 """Signal that this branch is being mirrored."""
1113968
1114 def branchChanged(stacked_on_url, last_revision_id, control_format,
1115 branch_format, repository_format):
1116 """Record that a branch has been changed.
1117
1118 This method records the stacked on branch tip revision id and format
1119 or the branch and creates a scan job if the tip revision id has
1120 changed.
1121
1122 :param stacked_on_url: The unique name of the branch this branch is
1123 stacked on, or '' if this branch is not stacked.
1124 :param last_revision_id: The tip revision ID of the branch.
1125 :param control_format: The entry from ControlFormat for the branch.
1126 :param branch_format: The entry from BranchFormat for the branch.
1127 :param repository_format: The entry from RepositoryFormat for the
1128 branch.
1129 """
1130
1131 def mirrorFailed(reason):969 def mirrorFailed(reason):
1132 """Signal that a mirror attempt failed.970 """Signal that a mirror attempt failed.
1133971
@@ -1148,11 +986,196 @@
1148 upgrade_pending = Attribute(986 upgrade_pending = Attribute(
1149 "Whether a branch has had an upgrade requested.")987 "Whether a branch has had an upgrade requested.")
1150988
989 def visibleByUser(user):
990 """Can the specified user see this branch?"""
991
992
993class IBranchEditableAttributes(Interface):
994 """IBranch attributes that can be edited.
995
996 These attributes need launchpad.View to see, and launchpad.Edit to change.
997 """
998
999 name = exported(
1000 TextLine(
1001 title=_('Name'), required=True, constraint=branch_name_validator,
1002 description=_(
1003 "Keep very short, unique, and descriptive, because it will "
1004 "be used in URLs. "
1005 "Examples: main, devel, release-1.0, gnome-vfs.")))
1006
1007 reviewer = exported(
1008 PublicPersonChoice(
1009 title=_('Review Team'),
1010 required=False,
1011 vocabulary='ValidPersonOrTeam',
1012 description=_("The reviewer of a branch is the person or team "
1013 "that is responsible for reviewing proposals and "
1014 "merging into this branch.")))
1015
1016 url = exported(
1017 BranchURIField(
1018 title=_('Branch URL'), required=False,
1019 allowed_schemes=['http', 'https', 'ftp', 'sftp', 'bzr+ssh'],
1020 allow_userinfo=False,
1021 allow_query=False,
1022 allow_fragment=False,
1023 trailing_slash=False,
1024 description=_(
1025 "This is the external location where the Bazaar "
1026 "branch is hosted.")))
1027
1028 mirror_status_message = exported(
1029 Text(
1030 title=_('The last message we got when mirroring this branch.'),
1031 required=False, readonly=True))
1032
1033 # XXX: TimPenhey 2007-08-31
1034 # The vocabulary set for branch_type is only used for the creation
1035 # of branches through the automatically generated forms, and doesn't
1036 # actually represent the complete range of real values that branch_type
1037 # may actually hold. Import branches are not created in the same
1038 # way as Hosted, Mirrored or Remote branches.
1039 # There are two option:
1040 # 1) define a separate schema to use in the UI (sledgehammer solution)
1041 # 2) work out some way to specify a restricted vocabulary in the view
1042 # Personally I'd like a LAZR way to do number 2.
1043 branch_type = exported(
1044 Choice(
1045 title=_("Branch Type"), required=True, readonly=True,
1046 vocabulary=UICreatableBranchType))
1047
1048 description = exported(
1049 Text(
1050 title=_('Description'), required=False,
1051 description=_(
1052 'A short description of the changes in this branch.')))
1053
1054 lifecycle_status = exported(
1055 Choice(
1056 title=_('Status'), vocabulary=BranchLifecycleStatus,
1057 default=BranchLifecycleStatus.DEVELOPMENT))
1058
1059 branch_format = exported(
1060 Choice(
1061 title=_("Branch Format"),
1062 required=False, readonly=True,
1063 vocabulary=BranchFormat))
1064
1065 repository_format = exported(
1066 Choice(
1067 title=_("Repository Format"),
1068 required=False, readonly=True,
1069 vocabulary=RepositoryFormat))
1070
1071 control_format = exported(
1072 Choice(
1073 title=_("Control Directory"),
1074 required=False, readonly=True,
1075 vocabulary=ControlFormat))
1076
1077 merge_control_status = Choice(
1078 title=_('Merge Control Status'), required=True,
1079 vocabulary=BranchMergeControlStatus,
1080 default=BranchMergeControlStatus.NO_QUEUE)
1081
1082
1083class IBranchEdit(Interface):
1084 """IBranch attributes that require launchpad.Edit permission."""
1085
1086 @call_with(user=REQUEST_USER)
1087 @operation_parameters(
1088 new_owner=Reference(
1089 title=_("The new owner of the branch."),
1090 schema=IPerson))
1091 @export_write_operation()
1092 def setOwner(new_owner, user):
1093 """Set the owner of the branch to be `new_owner`."""
1094
1095 @call_with(user=REQUEST_USER)
1096 @operation_parameters(
1097 project=Reference(
1098 title=_("The project the branch belongs to."),
1099 schema=Interface, required=False), # Really IProduct
1100 source_package=Reference(
1101 title=_("The source package the branch belongs to."),
1102 schema=Interface, required=False)) # Really ISourcePackage
1103 @export_write_operation()
1104 def setTarget(user, project=None, source_package=None):
1105 """Set the target of the branch to be `project` or `source_package`.
1106
1107 Only one of `project` or `source_package` can be set, and if neither
1108 is set, the branch gets moved into the junk namespace of the branch
1109 owner.
1110
1111 :raise: `BranchTargetError` if both project and source_package are set,
1112 or if either the project or source_package fail to be adapted to an
1113 IBranchTarget.
1114 """
1115
1151 def requestUpgrade():1116 def requestUpgrade():
1152 """Create an IBranchUpgradeJob to upgrade this branch."""1117 """Create an IBranchUpgradeJob to upgrade this branch."""
11531118
1154 def visibleByUser(user):1119 def branchChanged(stacked_on_url, last_revision_id, control_format,
1155 """Can the specified user see this branch?"""1120 branch_format, repository_format):
1121 """Record that a branch has been changed.
1122
1123 This method records the stacked on branch tip revision id and format
1124 or the branch and creates a scan job if the tip revision id has
1125 changed.
1126
1127 :param stacked_on_url: The unique name of the branch this branch is
1128 stacked on, or '' if this branch is not stacked.
1129 :param last_revision_id: The tip revision ID of the branch.
1130 :param control_format: The entry from ControlFormat for the branch.
1131 :param branch_format: The entry from BranchFormat for the branch.
1132 :param repository_format: The entry from RepositoryFormat for the
1133 branch.
1134 """
1135
1136 @export_destructor_operation()
1137 def destroySelfBreakReferences():
1138 """Delete the specified branch.
1139
1140 BranchRevisions associated with this branch will also be deleted as
1141 well as any items with mandatory references.
1142 """
1143
1144 def destroySelf(break_references=False):
1145 """Delete the specified branch.
1146
1147 BranchRevisions associated with this branch will also be deleted.
1148
1149 :param break_references: If supplied, break any references to this
1150 branch by deleting items with mandatory references and
1151 NULLing other references.
1152 :raise: CannotDeleteBranch if the branch cannot be deleted.
1153 """
1154
1155
1156class IBranch(IBranchPublic, IBranchView, IBranchEdit,
1157 IBranchEditableAttributes, IBranchAnyone):
1158 """A Bazaar branch."""
1159
1160 # Mark branches as exported entries for the Launchpad API.
1161 export_as_webservice_entry(plural_name='branches')
1162
1163 # This is redefined from IPrivacy.private because the attribute is
1164 # read-only. The value is guarded by setPrivate().
1165 private = exported(
1166 Bool(
1167 title=_("Keep branch confidential"), required=False,
1168 readonly=True, default=False,
1169 description=_(
1170 "Make this branch visible only to its subscribers.")))
1171
1172 @mutator_for(private)
1173 @call_with(user=REQUEST_USER)
1174 @operation_parameters(
1175 private=Bool(title=_("Keep branch confidential")))
1176 @export_write_operation()
1177 def setPrivate(private, user):
1178 """Set the branch privacy for this branch."""
11561179
11571180
1158class IBranchSet(Interface):1181class IBranchSet(Interface):
11591182
=== modified file 'lib/lp/code/model/branch.py'
--- lib/lp/code/model/branch.py 2010-07-17 22:49:11 +0000
+++ lib/lp/code/model/branch.py 2010-07-22 09:28:53 +0000
@@ -40,7 +40,8 @@
4040
41from canonical.launchpad import _41from canonical.launchpad import _
42from lp.services.job.model.job import Job42from lp.services.job.model.job import Job
43from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities43from canonical.launchpad.interfaces.launchpad import (
44 ILaunchpadCelebrities, IPrivacy)
44from canonical.launchpad.webapp import urlappend45from canonical.launchpad.webapp import urlappend
45from canonical.launchpad.webapp.interfaces import (46from canonical.launchpad.webapp.interfaces import (
46 IStoreSelector, MAIN_STORE, SLAVE_FLAVOR)47 IStoreSelector, MAIN_STORE, SLAVE_FLAVOR)
@@ -88,7 +89,7 @@
88class Branch(SQLBase, BzrIdentityMixin):89class Branch(SQLBase, BzrIdentityMixin):
89 """A sequence of ordered revisions in Bazaar."""90 """A sequence of ordered revisions in Bazaar."""
9091
91 implements(IBranch, IBranchNavigationMenu)92 implements(IBranch, IBranchNavigationMenu, IPrivacy)
92 _table = 'Branch'93 _table = 'Branch'
9394
94 branch_type = EnumCol(enum=BranchType, notNull=True)95 branch_type = EnumCol(enum=BranchType, notNull=True)