launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #18321
[Merge] lp:~cjwatson/launchpad/remove-branchmergequeue into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/remove-branchmergequeue into lp:launchpad.
Commit message:
Remove the incomplete "branch merge queue" feature.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #561157 in Launchpad itself: "'queued' merge proposals are unclear on +activereviews"
https://bugs.launchpad.net/launchpad/+bug/561157
Bug #564313 in Launchpad itself: "setStatus(queued, revid) doesn't report the revid via email"
https://bugs.launchpad.net/launchpad/+bug/564313
Bug #574120 in Launchpad itself: "unconflate 'proposal review' and 'proposal merging' functionality"
https://bugs.launchpad.net/launchpad/+bug/574120
Bug #574127 in Launchpad itself: "Ensure that only branch owners and reviewers can cause merge daemons to land code"
https://bugs.launchpad.net/launchpad/+bug/574127
Bug #574129 in Launchpad itself: "merge queue concept in Launchpad is incomplete"
https://bugs.launchpad.net/launchpad/+bug/574129
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/remove-branchmergequeue/+merge/256752
Remove the incomplete "branch merge queue" feature. It's disabled everywhere and has never been used properly. We can always resurrect it if we decide that it's the right direction to take in a future revamp of merge proposals.
There is one MP on production in the MERGE_FAILED state, and there are three in the QUEUED state. I've therefore kept just enough code to be able to render the relevant pages, with a few small changes to forbid transitions either to or from the now-obsolete states.
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/remove-branchmergequeue into lp:launchpad.
=== modified file 'database/schema/security.cfg'
--- database/schema/security.cfg 2015-04-15 17:16:26 +0000
+++ database/schema/security.cfg 2015-04-19 14:40:56 +0000
@@ -141,7 +141,6 @@
public.branchjob = SELECT, INSERT, UPDATE, DELETE
public.branchmergeproposal = SELECT, INSERT, UPDATE, DELETE
public.branchmergeproposaljob = SELECT, INSERT, UPDATE, DELETE
-public.branchmergequeue = SELECT, INSERT, UPDATE, DELETE
public.branchrevision = SELECT, INSERT, UPDATE, DELETE
public.branchsubscription = SELECT, INSERT, UPDATE, DELETE
public.bugaffectsperson = SELECT, INSERT, UPDATE, DELETE
@@ -2126,7 +2125,6 @@
public.binarypackagepublishinghistory = SELECT, UPDATE
public.branch = SELECT, UPDATE
public.branchmergeproposal = SELECT, UPDATE
-public.branchmergequeue = SELECT, UPDATE
public.branchsubscription = SELECT, UPDATE, DELETE
public.bug = SELECT, UPDATE
public.bugactivity = SELECT, UPDATE
=== modified file 'lib/lp/_schema_circular_imports.py'
--- lib/lp/_schema_circular_imports.py 2015-04-15 18:34:25 +0000
+++ lib/lp/_schema_circular_imports.py 2015-04-19 14:40:56 +0000
@@ -63,7 +63,6 @@
IBranchSet,
)
from lp.code.interfaces.branchmergeproposal import IBranchMergeProposal
-from lp.code.interfaces.branchmergequeue import IBranchMergeQueue
from lp.code.interfaces.branchsubscription import IBranchSubscription
from lp.code.interfaces.codeimport import ICodeImport
from lp.code.interfaces.codereviewcomment import ICodeReviewComment
@@ -792,11 +791,6 @@
IBranchMergeProposal, 'beta', "createComment", "getComment",
"nominateReviewer", "setStatus")
-# IBranchMergeQueue
-patch_entry_explicit_version(IBranchMergeQueue, 'beta')
-patch_operations_explicit_version(
- IBranchMergeQueue, 'beta', "setMergeQueueConfig")
-
# IBranchSubscription
patch_entry_explicit_version(IBranchSubscription, 'beta')
patch_operations_explicit_version(
=== modified file 'lib/lp/app/browser/tests/test_macro_view.py'
--- lib/lp/app/browser/tests/test_macro_view.py 2012-01-01 02:58:52 +0000
+++ lib/lp/app/browser/tests/test_macro_view.py 2015-04-19 14:40:56 +0000
@@ -38,7 +38,6 @@
'bugtask-macros-cve',
'+bmp-macros',
'branch-form-macros',
- '+bmq-macros',
'+announcement-macros',
'+person-macros',
'+milestone-macros',
=== modified file 'lib/lp/code/adapters/branch.py'
--- lib/lp/code/adapters/branch.py 2015-04-16 04:50:33 +0000
+++ lib/lp/code/adapters/branch.py 2015-04-19 14:40:56 +0000
@@ -84,7 +84,6 @@
'target_branch',
'prerequisite_branch',
'queue_status',
- 'queue_position',
)
new_values = (
'commit_message',
=== modified file 'lib/lp/code/browser/branch.py'
--- lib/lp/code/browser/branch.py 2014-12-06 03:47:44 +0000
+++ lib/lp/code/browser/branch.py 2015-04-19 14:40:56 +0000
@@ -14,7 +14,6 @@
'BranchEditWhiteboardView',
'BranchRequestImportView',
'BranchReviewerEditView',
- 'BranchMergeQueueView',
'BranchMirrorStatusView',
'BranchMirrorMixin',
'BranchNameValidationMixin',
@@ -279,7 +278,7 @@
'add_subscriber', 'browse_revisions', 'create_recipe', 'link_bug',
'link_blueprint', 'register_merge', 'source', 'subscription',
'edit_status', 'edit_import', 'upgrade_branch', 'view_recipes',
- 'create_queue', 'visibility']
+ 'visibility']
@enabled_with_permission('launchpad.Edit')
def edit_status(self):
@@ -367,10 +366,6 @@
text = 'Create packaging recipe'
return Link('+new-recipe', text, enabled=enabled, icon='add')
- @enabled_with_permission('launchpad.Edit')
- def create_queue(self):
- return Link('+create-queue', 'Create a new queue', icon='add')
-
class BranchMirrorMixin:
"""Provide mirror_location property.
@@ -1171,23 +1166,6 @@
return {'reviewer': self.context.code_reviewer}
-class BranchMergeQueueView(LaunchpadView):
- """The view used to render the merge queue for a branch."""
-
- @cachedproperty
- def merge_queue(self):
- """Get the merge queue and check visibility."""
- result = []
- for proposal in self.context.getMergeQueue():
- # If the logged in user cannot view the proposal then we
- # show a "place holder" in the queue position.
- if check_permission('launchpad.View', proposal):
- result.append(proposal)
- else:
- result.append(None)
- return result
-
-
class RegisterProposalStatus(EnumeratedType):
"""A restricted status enum for the register proposal form."""
=== modified file 'lib/lp/code/browser/branchlisting.py'
--- lib/lp/code/browser/branchlisting.py 2015-01-28 16:38:13 +0000
+++ lib/lp/code/browser/branchlisting.py 2015-04-19 14:40:56 +0000
@@ -69,7 +69,6 @@
from lp.bugs.interfaces.bugbranch import IBugBranchSet
from lp.code.browser.branch import BranchMirrorMixin
from lp.code.browser.branchmergeproposallisting import ActiveReviewsView
-from lp.code.browser.branchmergequeuelisting import HasMergeQueuesMenuMixin
from lp.code.browser.summary import BranchCountSummaryView
from lp.code.enums import (
BranchLifecycleStatus,
@@ -853,13 +852,11 @@
.scanned())
-class PersonBranchesMenu(ApplicationMenu, HasMergeQueuesMenuMixin):
+class PersonBranchesMenu(ApplicationMenu):
usedfor = IPerson
facet = 'branches'
- links = [
- 'branches', 'active_reviews', 'mergequeues', 'source_package_recipes']
- extra_attributes = ['mergequeue_count']
+ links = ['branches', 'active_reviews', 'source_package_recipes']
@property
def person(self):
=== modified file 'lib/lp/code/browser/branchmergeproposal.py'
--- lib/lp/code/browser/branchmergeproposal.py 2014-11-28 22:07:05 +0000
+++ lib/lp/code/browser/branchmergeproposal.py 2015-04-19 14:40:56 +0000
@@ -12,13 +12,9 @@
'BranchMergeProposalCommitMessageEditView',
'BranchMergeProposalContextMenu',
'BranchMergeProposalDeleteView',
- 'BranchMergeProposalDequeueView',
'BranchMergeProposalDescriptionEditView',
'BranchMergeProposalEditMenu',
'BranchMergeProposalEditView',
- 'BranchMergeProposalEnqueueView',
- 'BranchMergeProposalInlineDequeueView',
- 'BranchMergeProposalJumpQueueView',
'BranchMergeProposalNavigation',
'BranchMergeProposalMergedView',
'BranchMergeProposalRequestReviewView',
@@ -104,10 +100,7 @@
)
from lp.services.config import config
from lp.services.features import getFeatureFlag
-from lp.services.fields import (
- Summary,
- Whiteboard,
- )
+from lp.services.fields import Whiteboard
from lp.services.librarian.interfaces.client import LibrarianServerError
from lp.services.messages.interfaces.message import IMessageSet
from lp.services.propertycache import (
@@ -287,20 +280,6 @@
return Link('+merged', text)
@enabled_with_permission('launchpad.Edit')
- def enqueue(self):
- text = 'Queue for merging'
- enabled = self._enabledForStatus(
- BranchMergeProposalStatus.QUEUED)
- return Link('+enqueue', text, enabled=enabled)
-
- @enabled_with_permission('launchpad.Edit')
- def dequeue(self):
- text = 'Remove from queue'
- enabled = (self.context.queue_status ==
- BranchMergeProposalStatus.QUEUED)
- return Link('+dequeue', text, enabled=enabled)
-
- @enabled_with_permission('launchpad.Edit')
def resubmit(self):
text = 'Resubmit proposal'
enabled = self._enabledForStatus(
@@ -329,11 +308,9 @@
usedfor = IBranchMergeProposal
links = [
'add_comment',
- 'dequeue',
'set_commit_message',
'set_description',
'edit_status',
- 'enqueue',
'merge',
'request_review',
'resubmit',
@@ -416,12 +393,6 @@
return self._getRevisionNumberForRevisionId(
self.context.reviewed_revision_id)
- @cachedproperty
- def queued_revision_number(self):
- """Return the number of the queued revision."""
- return self._getRevisionNumberForRevisionId(
- self.context.queued_revision_id)
-
class BranchMergeProposalNavigation(Navigation):
"""Navigation from BranchMergeProposal to CodeReviewComment views."""
@@ -501,7 +472,6 @@
BranchMergeProposalStatus.NEEDS_REVIEW,
BranchMergeProposalStatus.CODE_APPROVED,
BranchMergeProposalStatus.REJECTED,
- # BranchMergeProposalStatus.QUEUED,
BranchMergeProposalStatus.MERGED,
)
terms = []
@@ -1201,160 +1171,6 @@
'Revision numbers must be positive integers.')
-class EnqueueForm(Interface):
- """A simple interface to populate the form to enqueue a proposal."""
-
- revision_number = Int(
- title=_("Queue Revision"), required=True,
- description=_("The revision number of the source branch "
- "which is to be merged into the target branch."))
-
- commit_message = Summary(
- title=_("Commit Message"), required=True,
- description=_("The commit message to be used when merging "
- "the source branch."))
-
- whiteboard = Whiteboard(
- title=_('Whiteboard'), required=False,
- description=_('Notes about the merge.'))
-
-
-class BranchMergeProposalEnqueueView(MergeProposalEditView,
- UnmergedRevisionsMixin):
- """The view to submit a merge proposal for merging."""
-
- schema = EnqueueForm
- page_title = label = "Queue branch for merging"
-
- @property
- def initial_values(self):
- # If the user is a valid reviewer, then default the revision
- # number to be the tip.
- if self.context.target_branch.isPersonTrustedReviewer(self.user):
- revision_number = self.context.source_branch.revision_count
- else:
- revision_number = self._getRevisionNumberForRevisionId(
- self.context.reviewed_revision_id)
-
- return {'revision_number': revision_number}
-
- @property
- def adapters(self):
- """See `LaunchpadFormView`"""
- return {EnqueueForm: self.context}
-
- def setUpFields(self):
- super(BranchMergeProposalEnqueueView, self).setUpFields()
- # If the user is not a valid reviewer for the target branch,
- # then the revision number should be read only, so an
- # untrusted user cannot land changes that have not bee reviewed.
- if not self.context.target_branch.isPersonTrustedReviewer(self.user):
- self.form_fields['revision_number'].for_display = True
-
- @action('Enqueue', name='enqueue')
- @update_and_notify
- def enqueue_action(self, action, data):
- """Update the whiteboard and enqueue the merge proposal."""
- if self.context.target_branch.isPersonTrustedReviewer(self.user):
- revision_id = self._getRevisionId(data)
- else:
- revision_id = self.context.reviewed_revision_id
- self.context.enqueue(self.user, revision_id)
-
- def validate(self, data):
- """Make sure that the proposal has been reviewed.
-
- Or that the logged in user is able to review the branch as well.
- """
- if not self.context.isValidTransition(
- BranchMergeProposalStatus.QUEUED, self.user):
- self.addError(
- "The merge proposal is cannot be queued as it has not "
- "been reviewed.")
-
- self._validateRevisionNumber(data, 'enqueued')
-
-
-class BranchMergeProposalDequeueView(LaunchpadEditFormView):
- """The view to remove a merge proposal from the merge queue."""
-
- schema = IBranchMergeProposal
- field_names = ["whiteboard"]
- page_title = label = "Dequeue branch"
-
- @property
- def next_url(self):
- return canonical_url(self.context)
-
- cancel_url = next_url
-
- @action('Dequeue', name='dequeue')
- @update_and_notify
- def dequeue_action(self, action, data):
- """Update the whiteboard and remove the proposal from the queue."""
- self.context.dequeue()
-
- def validate(self, data):
- """Make sure the proposal is queued before removing."""
- if self.context.queue_status != BranchMergeProposalStatus.QUEUED:
- self.addError("The merge proposal is not queued.")
-
-
-class BranchMergeProposalInlineDequeueView(LaunchpadEditFormView):
- """The view to provide a 'dequeue' button to the queue view."""
-
- schema = IBranchMergeProposal
- field_names = []
-
- @property
- def next_url(self):
- return canonical_url(self.context.target_branch) + '/+merge-queue'
-
- cancel_url = next_url
-
- @action('Dequeue', name='dequeue')
- @notify
- def dequeue_action(self, action, data):
- """Remove the proposal from the queue if queued."""
- if self.context.queue_status == BranchMergeProposalStatus.QUEUED:
- self.context.dequeue()
-
- @property
- def prefix(self):
- return "field%s" % self.context.id
-
- @property
- def action_url(self):
- return "%s/+dequeue-inline" % canonical_url(self.context)
-
-
-class BranchMergeProposalJumpQueueView(LaunchpadEditFormView):
- """The view to provide a move the proposal to the front of the queue."""
-
- schema = IBranchMergeProposal
- field_names = []
-
- @property
- def next_url(self):
- return canonical_url(self.context.target_branch) + '/+merge-queue'
-
- @action('Move to front', name='move')
- @notify
- def move_action(self, action, data):
- """Move the proposal to the front of the queue (if queued)."""
- if (self.context.queue_status == BranchMergeProposalStatus.QUEUED and
- check_permission('launchpad.Edit', self.context.target_branch)):
- self.context.moveToFrontOfQueue()
-
- @property
- def prefix(self):
- return "field%s" % self.context.id
-
- @property
- def action_url(self):
- return "%s/+jump-queue" % canonical_url(self.context)
-
-
class BranchMergeProposalSubscribersView(LaunchpadView):
"""Used to show the pagelet subscribers on the main proposal page."""
=== removed file 'lib/lp/code/browser/branchmergequeue.py'
--- lib/lp/code/browser/branchmergequeue.py 2012-01-01 02:58:52 +0000
+++ lib/lp/code/browser/branchmergequeue.py 1970-01-01 00:00:00 +0000
@@ -1,81 +0,0 @@
-# Copyright 2010 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""SourcePackageRecipe views."""
-
-__metaclass__ = type
-
-__all__ = [
- 'BranchMergeQueueContextMenu',
- 'BranchMergeQueueView',
- ]
-
-from lazr.restful.interface import copy_field
-from zope.component import getUtility
-from zope.interface import Interface
-
-from lp.app.browser.launchpadform import (
- action,
- LaunchpadFormView,
- )
-from lp.code.interfaces.branchmergequeue import (
- IBranchMergeQueue,
- IBranchMergeQueueSource,
- )
-from lp.services.webapp import (
- canonical_url,
- ContextMenu,
- LaunchpadView,
- )
-
-
-class BranchMergeQueueContextMenu(ContextMenu):
- """Context menu for sourcepackage recipes."""
-
- usedfor = IBranchMergeQueue
-
- facet = 'branches'
-
- links = ()
-
-
-class BranchMergeQueueView(LaunchpadView):
- """Default view of a SourcePackageRecipe."""
-
- @property
- def page_title(self):
- return "%(queue_name)s queue owned by %(name)s" % {
- 'name': self.context.owner.displayname,
- 'queue_name': self.context.name}
-
- label = page_title
-
-
-class BranchMergeQueueAddView(LaunchpadFormView):
-
- title = label = 'Create a new branch merge queue'
-
- class schema(Interface):
- name = copy_field(IBranchMergeQueue['name'], readonly=False)
- owner = copy_field(IBranchMergeQueue['owner'], readonly=False)
- description = copy_field(IBranchMergeQueue['description'],
- readonly=False)
-
- def initialize(self):
- super(BranchMergeQueueAddView, self).initialize()
-
- @property
- def initial_values(self):
- return {}
-
- @property
- def cancel_url(self):
- return canonical_url(self.context)
-
- @action('Create Queue', name='create')
- def request_action(self, action, data):
- merge_queue = getUtility(IBranchMergeQueueSource).new(
- data['name'], data['owner'], self.user, data['description'])
- self.context.addToQueue(merge_queue)
-
- self.next_url = canonical_url(merge_queue)
=== removed file 'lib/lp/code/browser/branchmergequeuelisting.py'
--- lib/lp/code/browser/branchmergequeuelisting.py 2012-01-01 02:58:52 +0000
+++ lib/lp/code/browser/branchmergequeuelisting.py 1970-01-01 00:00:00 +0000
@@ -1,105 +0,0 @@
-# Copyright 2010-2011 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Base class view for merge queue listings."""
-
-__metaclass__ = type
-
-__all__ = [
- 'MergeQueueListingView',
- 'HasMergeQueuesMenuMixin',
- 'PersonMergeQueueListingView',
- ]
-
-from zope.component import getUtility
-
-from lp.code.interfaces.branchmergequeuecollection import (
- IAllBranchMergeQueues,
- )
-from lp.services.browser_helpers import get_plural_text
-from lp.services.feeds.browser import FeedsMixin
-from lp.services.propertycache import cachedproperty
-from lp.services.webapp import (
- LaunchpadView,
- Link,
- )
-
-
-class HasMergeQueuesMenuMixin:
- """A context menus mixin for objects that can own merge queues."""
-
- def _getCollection(self):
- return getUtility(IAllBranchMergeQueues).visibleByUser(self.user)
-
- @property
- def person(self):
- """The `IPerson` for the context of the view.
-
- In simple cases this is the context itself, but in others, like the
- PersonProduct, it is an attribute of the context.
- """
- return self.context
-
- def mergequeues(self):
- return Link(
- '+merge-queues',
- get_plural_text(
- self.mergequeue_count,
- 'merge queue', 'merge queues'), site='code')
-
- @cachedproperty
- def mergequeue_count(self):
- return self._getCollection().ownedBy(self.person).count()
-
-
-class MergeQueueListingView(LaunchpadView, FeedsMixin):
-
- # No feeds initially
- feed_types = ()
-
- branch_enabled = True
- owner_enabled = True
-
- label_template = 'Merge Queues for %(displayname)s'
-
- @property
- def label(self):
- return self.label_template % {
- 'displayname': self.context.displayname,
- 'title': getattr(self.context, 'title', 'no-title')}
-
- # Provide a default page_title for distros and other things without
- # breadcrumbs..
- page_title = label
-
- def _getCollection(self):
- """Override this to say what queues will be in the listing."""
- raise NotImplementedError(self._getCollection)
-
- def getVisibleQueuesForUser(self):
- """Branch merge queues that are visible by the logged in user."""
- collection = self._getCollection().visibleByUser(self.user)
- return collection.getMergeQueues()
-
- @cachedproperty
- def mergequeues(self):
- return self.getVisibleQueuesForUser()
-
- @cachedproperty
- def mergequeue_count(self):
- """Return the number of merge queues that will be returned."""
- return self._getCollection().visibleByUser(self.user).count()
-
- @property
- def no_merge_queue_message(self):
- """Shown when there is no table to show."""
- return "%s has no merge queues." % self.context.displayname
-
-
-class PersonMergeQueueListingView(MergeQueueListingView):
-
- label_template = 'Merge Queues owned by %(displayname)s'
- owner_enabled = False
-
- def _getCollection(self):
- return getUtility(IAllBranchMergeQueues).ownedBy(self.context)
=== modified file 'lib/lp/code/browser/configure.zcml'
--- lib/lp/code/browser/configure.zcml 2015-03-19 17:04:22 +0000
+++ lib/lp/code/browser/configure.zcml 2015-04-19 14:40:56 +0000
@@ -221,30 +221,6 @@
permission="launchpad.Edit"
template="../templates/branchmergeproposal-resubmit.pt"/>
<browser:page
- name="+enqueue"
- for="lp.code.interfaces.branchmergeproposal.IBranchMergeProposal"
- class="lp.code.browser.branchmergeproposal.BranchMergeProposalEnqueueView"
- permission="launchpad.Edit"
- template="../templates/branchmergeproposal-enqueue.pt"/>
- <browser:page
- name="+dequeue"
- for="lp.code.interfaces.branchmergeproposal.IBranchMergeProposal"
- class="lp.code.browser.branchmergeproposal.BranchMergeProposalDequeueView"
- permission="launchpad.Edit"
- template="../../app/templates/generic-edit.pt"/>
- <browser:page
- name="+dequeue-inline"
- for="lp.code.interfaces.branchmergeproposal.IBranchMergeProposal"
- class="lp.code.browser.branchmergeproposal.BranchMergeProposalInlineDequeueView"
- permission="launchpad.Edit"
- template="../templates/inline-form-only-buttons.pt"/>
- <browser:page
- name="+jump-queue"
- for="lp.code.interfaces.branchmergeproposal.IBranchMergeProposal"
- class="lp.code.browser.branchmergeproposal.BranchMergeProposalJumpQueueView"
- permission="launchpad.Edit"
- template="../templates/inline-form-only-buttons.pt"/>
- <browser:page
name="+merged"
for="lp.code.interfaces.branchmergeproposal.IBranchMergeProposal"
class="lp.code.browser.branchmergeproposal.BranchMergeProposalMergedView"
@@ -1094,47 +1070,6 @@
factory="lp.code.browser.sourcepackagerecipe.SourcePackageRecipeBreadcrumb"
permission="zope.Public"/>
- <browser:page
- for="lp.registry.interfaces.person.IPerson"
- class="lp.code.browser.branchmergequeuelisting.PersonMergeQueueListingView"
- permission="zope.Public"
- name="+merge-queues"
- template="../templates/branchmergequeue-listing.pt"/>
-
- <browser:page
- for="*"
- name="+bmq-macros"
- permission="zope.Public"
- template="../templates/branchmergequeue-macros.pt"
- class="lp.app.browser.launchpad.Macro"/>
-
-
- <browser:url
- for="lp.code.interfaces.branchmergequeue.IBranchMergeQueue"
- attribute_to_parent="owner"
- path_expression="string:+merge-queues/${name}"
- rootsite="code" />
-
- <browser:menus
- classes="BranchMergeQueueContextMenu"
- module="lp.code.browser.branchmergequeue"/>
-
- <browser:defaultView
- for="lp.code.interfaces.branchmergequeue.IBranchMergeQueue"
- name="+index" />
- <browser:page
- for="lp.code.interfaces.branchmergequeue.IBranchMergeQueue"
- class="lp.code.browser.branchmergequeue.BranchMergeQueueView"
- name="+index"
- template="../templates/branchmergequeue-index.pt"
- permission="zope.Public" />
- <browser:page
- for="lp.code.interfaces.branch.IBranch"
- class="lp.code.browser.branchmergequeue.BranchMergeQueueAddView"
- name="+create-queue"
- template="../../app/templates/generic-edit.pt"
- permission="launchpad.Edit" />
-
</facet>
</configure>
=== modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py'
--- lib/lp/code/browser/tests/test_branchmergeproposal.py 2014-11-28 22:07:05 +0000
+++ lib/lp/code/browser/tests/test_branchmergeproposal.py 2015-04-19 14:40:56 +0000
@@ -1085,22 +1085,9 @@
self.proposal.target_branch.owner, 'some-revision')
self.assertAllStatusesAvailable(
user=self.proposal.source_branch.owner,
- except_for=['CODE_APPROVED', 'QUEUED'])
- self.assertAllStatusesAvailable(user=self.proposal.registrant,
- except_for=['CODE_APPROVED', 'QUEUED'])
- self.assertAllStatusesAvailable(
- user=self.proposal.target_branch.owner)
-
- def test_createStatusVocabulary_queued(self):
- # Queued proposals can go to any status, but only reviewers can set
- # them to REJECTED.
- self.proposal.enqueue(
- self.proposal.target_branch.owner, 'some-revision')
-
- self.assertAllStatusesAvailable(
- user=self.proposal.source_branch.owner, except_for=['REJECTED'])
- self.assertAllStatusesAvailable(user=self.proposal.registrant,
- except_for=['REJECTED'])
+ except_for=['CODE_APPROVED'])
+ self.assertAllStatusesAvailable(user=self.proposal.registrant,
+ except_for=['CODE_APPROVED'])
self.assertAllStatusesAvailable(
user=self.proposal.target_branch.owner)
=== removed file 'lib/lp/code/browser/tests/test_branchmergequeue.py'
--- lib/lp/code/browser/tests/test_branchmergequeue.py 2014-06-10 16:13:03 +0000
+++ lib/lp/code/browser/tests/test_branchmergequeue.py 1970-01-01 00:00:00 +0000
@@ -1,121 +0,0 @@
-# Copyright 2010-2014 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Tests for the branch merge queue view classes and templates."""
-
-from __future__ import with_statement
-
-__metaclass__ = type
-
-import re
-
-from mechanize import LinkNotFoundError
-import soupmatchers
-
-from lp.services.features.model import (
- FeatureFlag,
- getFeatureStore,
- )
-from lp.services.webapp import canonical_url
-from lp.testing import (
- ANONYMOUS,
- BrowserTestCase,
- person_logged_in,
- )
-from lp.testing.layers import DatabaseFunctionalLayer
-
-
-class TestBranchMergeQueue(BrowserTestCase):
- """Test the Branch Merge Queue index page."""
-
- layer = DatabaseFunctionalLayer
-
- def enable_queue_flag(self):
- getFeatureStore().add(FeatureFlag(
- scope=u'default', flag=u'code.branchmergequeue',
- value=u'on', priority=1))
-
- def test_index(self):
- """Test the index page of a branch merge queue."""
- with person_logged_in(ANONYMOUS):
- queue = self.factory.makeBranchMergeQueue()
-
- branch = self.factory.makeBranch()
- with person_logged_in(branch.owner):
- branch.addToQueue(queue)
-
- # XXX: rockstar - bug #666979 - The text argument should really ignore
- # whitespace, but it currently doesn't. Now I have two problems.
- queue_matcher = soupmatchers.HTMLContains(
- soupmatchers.Tag(
- 'Page title', 'h1',
- text=re.compile('\w*%s queue owned by %s\w*' % (
- queue.name, queue.owner.displayname))),
- soupmatchers.Tag(
- 'Description Label', 'dt',
- text=re.compile('\w*Description\w*')),
- soupmatchers.Tag(
- 'Description Value', 'dd',
- text=re.compile('\w*%s\w*' % queue.description)),
- soupmatchers.Tag(
- 'Branch link', 'a',
- text=re.compile('\w*%s\w*' % branch.bzr_identity)))
-
- browser = self.getUserBrowser(canonical_url(queue), user=queue.owner)
-
- self.assertThat(browser.contents, queue_matcher)
-
- def test_create(self):
- """Test that branch merge queues can be created from a branch."""
- self.enable_queue_flag()
- with person_logged_in(ANONYMOUS):
- rockstar = self.factory.makePerson(name='rockstar')
- branch = self.factory.makeBranch(owner=rockstar)
- self.factory.makeBranch(product=branch.product)
-
- browser = self.getUserBrowser(canonical_url(branch), user=rockstar)
-
- # There shouldn't be a merge queue linked here.
- noqueue_matcher = soupmatchers.HTMLContains(
- soupmatchers.Tag(
- 'Not managed', 'div',
- text=re.compile(
- '\w*This branch is not managed by a queue.\w*')))
- self.assertThat(browser.contents, noqueue_matcher)
-
- browser.getLink('Create a new queue').click()
-
- browser.getControl('Name').value = 'libbob-queue'
- browser.getControl('Description').value = (
- 'This is a queue for the libbob projects.')
- browser.getControl('Create Queue').click()
-
- self.assertEqual(
- 'http://code.launchpad.dev/~rockstar/+merge-queues/libbob-queue',
- browser.url)
-
- def test_create_unauthorized(self):
- """Test that queues can't be created by unauthorized users."""
- self.enable_queue_flag()
- with person_logged_in(ANONYMOUS):
- branch = self.factory.makeBranch()
- self.factory.makeBranch(product=branch.product)
-
- browser = self.getUserBrowser(canonical_url(branch))
- self.assertRaises(
- LinkNotFoundError,
- browser.getLink,
- 'Create a new queue')
-
- def test_create_featureflag(self):
- """Test that the feature flag hides the "create" link."""
- with person_logged_in(ANONYMOUS):
- rockstar = self.factory.makePerson(name='rockstar')
- branch = self.factory.makeBranch(owner=rockstar)
- self.factory.makeBranch(product=branch.product)
-
- browser = self.getUserBrowser(canonical_url(branch), user=rockstar)
- self.assertRaises(
- LinkNotFoundError,
- browser.getLink,
- 'Create a new queue')
=== removed file 'lib/lp/code/browser/tests/test_branchmergequeuelisting.py'
--- lib/lp/code/browser/tests/test_branchmergequeuelisting.py 2012-09-18 18:36:09 +0000
+++ lib/lp/code/browser/tests/test_branchmergequeuelisting.py 1970-01-01 00:00:00 +0000
@@ -1,229 +0,0 @@
-# Copyright 2010-2012 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Tests for branch listing."""
-
-__metaclass__ = type
-
-import re
-
-from mechanize import LinkNotFoundError
-import soupmatchers
-from zope.security.proxy import removeSecurityProxy
-
-from lp.app.enums import InformationType
-from lp.services.features.model import (
- FeatureFlag,
- getFeatureStore,
- )
-from lp.services.webapp import canonical_url
-from lp.testing import (
- BrowserTestCase,
- login_person,
- person_logged_in,
- TestCaseWithFactory,
- )
-from lp.testing.layers import DatabaseFunctionalLayer
-from lp.testing.pages import (
- extract_link_from_tag,
- extract_text,
- find_tag_by_id,
- )
-from lp.testing.views import create_initialized_view
-
-
-class MergeQueuesTestMixin:
-
- def setUp(self):
- self.branch_owner = self.factory.makePerson(name='eric')
-
- def enable_queue_flag(self):
- getFeatureStore().add(FeatureFlag(
- scope=u'default', flag=u'code.branchmergequeue',
- value=u'on', priority=1))
-
- def _makeMergeQueues(self, nr_queues=3, nr_with_private_branches=0):
- # We create nr_queues merge queues in total, and the first
- # nr_with_private_branches of them will have at least one private
- # branch in the queue.
- with person_logged_in(self.branch_owner):
- mergequeues = [
- self.factory.makeBranchMergeQueue(
- owner=self.branch_owner, branches=self._makeBranches())
- for i in range(nr_queues - nr_with_private_branches)]
- mergequeues_with_private_branches = [
- self.factory.makeBranchMergeQueue(
- owner=self.branch_owner,
- branches=self._makeBranches(nr_private=1))
- for i in range(nr_with_private_branches)]
-
- return mergequeues, mergequeues_with_private_branches
-
- def _makeBranches(self, nr_public=3, nr_private=0):
- branches = [
- self.factory.makeProductBranch(owner=self.branch_owner)
- for i in range(nr_public)]
-
- private_branches = [
- self.factory.makeProductBranch(
- owner=self.branch_owner,
- information_type=InformationType.USERDATA)
- for i in range(nr_private)]
-
- branches.extend(private_branches)
- return branches
-
-
-class TestPersonMergeQueuesView(TestCaseWithFactory, MergeQueuesTestMixin):
-
- layer = DatabaseFunctionalLayer
-
- def setUp(self):
- TestCaseWithFactory.setUp(self)
- MergeQueuesTestMixin.setUp(self)
- self.user = self.factory.makePerson()
-
- def test_mergequeues_with_all_public_branches(self):
- # Anyone can see mergequeues containing all public branches.
- mq, mq_with_private = self._makeMergeQueues()
- login_person(self.user)
- view = create_initialized_view(
- self.branch_owner, name="+merge-queues", rootsite='code')
- self.assertEqual(set(mq), set(view.mergequeues))
-
- def test_mergequeues_with_a_private_branch_for_owner(self):
- # Only users with access to private branches can see any queues
- # containing such branches.
- mq, mq_with_private = (
- self._makeMergeQueues(nr_with_private_branches=1))
- login_person(self.branch_owner)
- view = create_initialized_view(
- self.branch_owner, name="+merge-queues", rootsite='code')
- mq.extend(mq_with_private)
- self.assertEqual(set(mq), set(view.mergequeues))
-
- def test_mergequeues_with_a_private_branch_for_other_user(self):
- # Only users with access to private branches can see any queues
- # containing such branches.
- mq, mq_with_private = (
- self._makeMergeQueues(nr_with_private_branches=1))
- login_person(self.user)
- view = create_initialized_view(
- self.branch_owner, name="+merge-queues", rootsite='code')
- self.assertEqual(set(mq), set(view.mergequeues))
-
-
-class TestPersonCodePage(BrowserTestCase, MergeQueuesTestMixin):
- """Tests for the person code homepage.
-
- This is the default page shown for a person on the code subdomain.
- """
-
- layer = DatabaseFunctionalLayer
-
- def setUp(self):
- BrowserTestCase.setUp(self)
- MergeQueuesTestMixin.setUp(self)
- self._makeMergeQueues()
-
- def test_merge_queue_menu_link_without_feature_flag(self):
- login_person(self.branch_owner)
- browser = self.getUserBrowser(
- canonical_url(self.branch_owner, rootsite='code'),
- self.branch_owner)
- self.assertRaises(
- LinkNotFoundError,
- browser.getLink,
- url='+merge-queues')
-
- def test_merge_queue_menu_link(self):
- self.enable_queue_flag()
- login_person(self.branch_owner)
- browser = self.getUserBrowser(
- canonical_url(self.branch_owner, rootsite='code'),
- self.branch_owner)
- browser.getLink(url='+merge-queues').click()
- self.assertEqual(
- 'http://code.launchpad.dev/~eric/+merge-queues',
- browser.url)
-
-
-class TestPersonMergeQueuesListPage(BrowserTestCase, MergeQueuesTestMixin):
- """Tests for the person merge queue list page."""
-
- layer = DatabaseFunctionalLayer
-
- def setUp(self):
- BrowserTestCase.setUp(self)
- MergeQueuesTestMixin.setUp(self)
- mq, mq_with_private = self._makeMergeQueues()
- self.merge_queues = mq
- self.merge_queues.extend(mq_with_private)
-
- def test_merge_queue_list_contents_without_feature_flag(self):
- login_person(self.branch_owner)
- browser = self.getUserBrowser(
- canonical_url(self.branch_owner, rootsite='code',
- view_name='+merge-queues'), self.branch_owner)
- table = find_tag_by_id(browser.contents, 'mergequeuetable')
- self.assertIs(None, table)
- noqueue_matcher = soupmatchers.HTMLContains(
- soupmatchers.Tag(
- 'No merge queues', 'div',
- text=re.compile(
- '\w*No merge queues\w*')))
- self.assertThat(browser.contents, noqueue_matcher)
-
- def test_merge_queue_list_contents(self):
- self.enable_queue_flag()
- login_person(self.branch_owner)
- browser = self.getUserBrowser(
- canonical_url(self.branch_owner, rootsite='code',
- view_name='+merge-queues'), self.branch_owner)
-
- table = find_tag_by_id(browser.contents, 'mergequeuetable')
-
- merge_queue_info = {}
- for row in table.tbody.fetch('tr'):
- cells = row('td')
- row_info = {}
- queue_name = extract_text(cells[0])
- if not queue_name.startswith('queue'):
- continue
- qlink = extract_link_from_tag(cells[0].find('a'))
- row_info['queue_link'] = qlink
- queue_size = extract_text(cells[1])
- row_info['queue_size'] = queue_size
- queue_branches = cells[2]('a')
- branch_links = set()
- for branch_tag in queue_branches:
- branch_links.add(extract_link_from_tag(branch_tag))
- row_info['branch_links'] = branch_links
- merge_queue_info[queue_name] = row_info
-
- expected_queue_names = [queue.name for queue in self.merge_queues]
- self.assertEqual(
- set(expected_queue_names), set(merge_queue_info.keys()))
-
- #TODO: when IBranchMergeQueue API is available remove '4'
- expected_queue_sizes = dict(
- [(queue.name, '4') for queue in self.merge_queues])
- observed_queue_sizes = dict(
- [(queue.name, merge_queue_info[queue.name]['queue_size'])
- for queue in self.merge_queues])
- self.assertEqual(
- expected_queue_sizes, observed_queue_sizes)
-
- def branch_links(branches):
- return [canonical_url(removeSecurityProxy(branch),
- force_local_path=True)
- for branch in branches]
-
- expected_queue_branches = dict(
- [(queue.name, set(branch_links(queue.branches)))
- for queue in self.merge_queues])
- observed_queue_branches = dict(
- [(queue.name, merge_queue_info[queue.name]['branch_links'])
- for queue in self.merge_queues])
- self.assertEqual(
- expected_queue_branches, observed_queue_branches)
=== modified file 'lib/lp/code/configure.zcml'
--- lib/lp/code/configure.zcml 2015-04-16 14:35:17 +0000
+++ lib/lp/code/configure.zcml 2015-04-19 14:40:56 +0000
@@ -26,23 +26,6 @@
provides="lp.services.webapp.interfaces.IFacet"
name="branches" />
- <!-- Branch Merge Queues -->
- <securedutility
- component="lp.code.model.branchmergequeue.BranchMergeQueue"
- provides="lp.code.interfaces.branchmergequeue.IBranchMergeQueueSource">
- <allow interface="lp.code.interfaces.branchmergequeue.IBranchMergeQueueSource"/>
-
- </securedutility>
-
- <class class="lp.code.model.branchmergequeue.BranchMergeQueue">
- <require permission="zope.Public"
- attributes="registrant owner name description configuration
- date_created branches" />
- <require permission="launchpad.Edit"
- attributes="setMergeQueueConfig"
- set_attributes="owner name description configuration" />
- </class>
-
<class class="lp.code.model.codereviewvote.CodeReviewVoteReference">
<allow interface="lp.code.interfaces.codereviewvote.ICodeReviewVoteReferencePublic"/>
<require
@@ -98,12 +81,6 @@
<allow attributes="browserDefault
__call__"/>
</class>
- <class class="lp.code.model.branchmergequeuecollection.GenericBranchMergeQueueCollection">
- <allow interface="lp.code.interfaces.branchmergequeuecollection.IBranchMergeQueueCollection"/>
- </class>
- <class class="lp.code.model.branchmergequeuecollection.VisibleBranchMergeQueueCollection">
- <allow interface="lp.code.interfaces.branchmergequeuecollection.IBranchMergeQueueCollection"/>
- </class>
<class class="lp.code.model.branchcollection.GenericBranchCollection">
<allow interface="lp.code.interfaces.branchcollection.IBranchCollection"/>
</class>
@@ -162,11 +139,6 @@
provides="lp.code.interfaces.revisioncache.IRevisionCache">
<allow interface="lp.code.interfaces.revisioncache.IRevisionCache"/>
</securedutility>
- <securedutility
- class="lp.code.model.branchmergequeuecollection.GenericBranchMergeQueueCollection"
- provides="lp.code.interfaces.branchmergequeuecollection.IAllBranchMergeQueues">
- <allow interface="lp.code.interfaces.branchmergequeuecollection.IAllBranchMergeQueues"/>
- </securedutility>
<adapter
for="lp.registry.interfaces.person.IPerson"
provides="lp.code.interfaces.revisioncache.IRevisionCache"
@@ -392,8 +364,7 @@
lp.code.interfaces.branch.IBranchModerateAttributes
lp.code.interfaces.branch.IBranchEditableAttributes
lp.code.interfaces.branch.IBranchPublic
- lp.code.interfaces.branch.IBranchView"
- attributes="merge_queue merge_queue_config"/>
+ lp.code.interfaces.branch.IBranchView"/>
<require
permission="launchpad.Moderate"
interface="lp.code.interfaces.branch.IBranchModerate"
@@ -402,7 +373,7 @@
permission="launchpad.Edit"
interface="lp.code.interfaces.branch.IBranchEdit"
set_schema="lp.code.interfaces.branch.IBranchEditableAttributes"
- attributes="setPrivate addToQueue setMergeQueueConfig"
+ attributes="setPrivate"
set_attributes="branch_format control_format repository_format
branch_type
last_scanned last_scanned_id
=== modified file 'lib/lp/code/doc/branchmergeproposal.txt'
--- lib/lp/code/doc/branchmergeproposal.txt 2010-07-26 04:44:15 +0000
+++ lib/lp/code/doc/branchmergeproposal.txt 2015-04-19 14:40:56 +0000
@@ -85,16 +85,3 @@
Superseded
The intent of superseded proposals has changed somewhat over time, and needs
some rework (bugs 383352, 397444, 400030, 488544)
-
-
-There are also some other states that are not yet in general use:
-
-Queued
- The merge proposal is queued for merging. The proposal will be part of some
- merge queue which a person or script (like tarmac) will process and do the
- merges.
-
-Merge Failed
- A script tried to merge the branch but it either failed to merge cleanly
- (had conflicts) or failed some tests as defined by the script. There is the
- facility to add a log file containing the failures here.
=== modified file 'lib/lp/code/errors.py'
--- lib/lp/code/errors.py 2015-03-19 11:17:08 +0000
+++ lib/lp/code/errors.py 2015-04-19 14:40:56 +0000
@@ -39,7 +39,6 @@
'GitRepositoryScanFault',
'GitTargetError',
'InvalidBranchMergeProposal',
- 'InvalidMergeQueueConfig',
'InvalidNamespace',
'NoLinkedBranch',
'NoSuchBranch',
@@ -488,14 +487,5 @@
@error_status(httplib.BAD_REQUEST)
-class InvalidMergeQueueConfig(Exception):
- """The config specified is not a valid JSON string."""
-
- def __init__(self):
- message = ('The configuration specified is not a valid JSON string.')
- Exception.__init__(self, message)
-
-
-@error_status(httplib.BAD_REQUEST)
class DiffNotFound(Exception):
"""A `IPreviewDiff` with the timestamp was not found."""
=== modified file 'lib/lp/code/interfaces/branch.py'
--- lib/lp/code/interfaces/branch.py 2015-04-17 00:01:15 +0000
+++ lib/lp/code/interfaces/branch.py 2015-04-19 14:40:56 +0000
@@ -82,7 +82,6 @@
CodeReviewNotificationLevel,
)
from lp.code.interfaces.branchlookup import IBranchLookup
-from lp.code.interfaces.branchmergequeue import IBranchMergeQueue
from lp.code.interfaces.branchtarget import IHasBranchTarget
from lp.code.interfaces.hasbranches import IHasMergeProposals
from lp.code.interfaces.hasrecipes import IHasRecipes
@@ -1183,56 +1182,9 @@
"""
-class IMergeQueueable(Interface):
- """An interface for branches that can be queued."""
-
- merge_queue = exported(
- Reference(
- title=_('Branch Merge Queue'),
- schema=IBranchMergeQueue, required=False, readonly=True,
- description=_(
- "The branch merge queue that manages merges for this "
- "branch.")))
-
- merge_queue_config = exported(
- TextLine(
- title=_('Name'), required=True, readonly=True,
- description=_(
- "A JSON string of configuration values to send to a "
- "branch merge robot.")))
-
- @mutator_for(merge_queue)
- @operation_parameters(
- queue=Reference(title=_('Branch Merge Queue'),
- schema=IBranchMergeQueue))
- @export_write_operation()
- @operation_for_version('beta')
- def addToQueue(queue):
- """Add this branch to a specified queue.
-
- A branch's merges can be managed by a queue.
-
- :param queue: The branch merge queue that will manage the branch.
- """
-
- @mutator_for(merge_queue_config)
- @operation_parameters(
- config=TextLine(title=_("A JSON string of config values.")))
- @export_write_operation()
- @operation_for_version('beta')
- def setMergeQueueConfig(config):
- """Set the merge_queue_config property.
-
- A branch can store a JSON string of configuration data for a merge
- robot to retrieve.
-
- :param config: A JSON string of data.
- """
-
-
class IBranch(IBranchPublic, IBranchView, IBranchEdit,
IBranchEditableAttributes, IBranchModerate,
- IBranchModerateAttributes, IBranchAnyone, IMergeQueueable):
+ IBranchModerateAttributes, IBranchAnyone):
"""A Bazaar branch."""
# Mark branches as exported entries for the Launchpad API.
=== modified file 'lib/lp/code/interfaces/branchmergeproposal.py'
--- lib/lp/code/interfaces/branchmergeproposal.py 2015-04-16 04:00:33 +0000
+++ lib/lp/code/interfaces/branchmergeproposal.py 2015-04-19 14:40:56 +0000
@@ -6,6 +6,7 @@
__metaclass__ = type
__all__ = [
'BRANCH_MERGE_PROPOSAL_FINAL_STATES',
+ 'BRANCH_MERGE_PROPOSAL_OBSOLETE_STATES',
'IBranchMergeProposal',
'IBranchMergeProposalGetter',
'IBranchMergeProposalJob',
@@ -95,6 +96,12 @@
)
+BRANCH_MERGE_PROPOSAL_OBSOLETE_STATES = (
+ BranchMergeProposalStatus.MERGE_FAILED,
+ BranchMergeProposalStatus.QUEUED,
+ )
+
+
class IBranchMergeProposalPublic(IPrivacy):
id = Int(
@@ -210,25 +217,6 @@
"merging the source branch."),
strip_text=True))
- queue_position = exported(
- Int(
- title=_("Queue Position"), required=False, readonly=True,
- description=_("The position in the queue.")))
-
- queuer = exported(
- PublicPersonChoice(
- title=_('Queuer'), vocabulary='ValidPerson',
- required=False, readonly=True,
- description=_("The person that queued up the branch.")))
-
- queued_revision_id = exported(
- Text(
- title=_("Queued Revision ID"), readonly=True,
- required=False,
- description=_("The revision id that has been queued for "
- "landing.")),
- exported_as='queued_revid')
-
merged_revno = exported(
Int(
title=_("Merged Revision Number"), required=False,
@@ -276,9 +264,6 @@
date_reviewed = exported(
Datetime(
title=_('Date Reviewed'), required=False, readonly=True))
- date_queued = exported(
- Datetime(
- title=_('Date Queued'), required=False, readonly=True))
root_message_id = Text(
title=_('The email message id from the first message'),
required=False)
@@ -537,27 +522,6 @@
the current description).
"""
- def enqueue(queuer, revision_id):
- """Put the proposal into the merge queue for the target branch.
-
- If the proposal is not in the Approved state before this method
- is called, approveBranch is called with the reviewer and revision_id
- specified.
-
- If None is supplied as the revision_id, the proposals
- reviewed_revision_id is used.
- """
-
- def dequeue():
- """Take the proposal out of the merge queue of the target branch.
-
- :raises: BadStateTransition if the proposal is not in the queued
- state.
- """
-
- def moveToFrontOfQueue():
- """Move the queue proposal to the front of the queue."""
-
@operation_parameters(
reviewer=Reference(
title=_("A reviewer."), schema=IPerson),
=== removed file 'lib/lp/code/interfaces/branchmergequeue.py'
--- lib/lp/code/interfaces/branchmergequeue.py 2011-12-24 16:54:44 +0000
+++ lib/lp/code/interfaces/branchmergequeue.py 1970-01-01 00:00:00 +0000
@@ -1,129 +0,0 @@
-# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Branch merge queue interfaces."""
-
-__metaclass__ = type
-
-__all__ = [
- 'IBranchMergeQueue',
- 'IBranchMergeQueueSource',
- 'user_has_special_merge_queue_access',
- ]
-
-from lazr.restful.declarations import (
- export_as_webservice_entry,
- export_write_operation,
- exported,
- mutator_for,
- operation_parameters,
- )
-from lazr.restful.fields import (
- CollectionField,
- Reference,
- )
-from zope.component import getUtility
-from zope.interface import Interface
-from zope.schema import (
- Datetime,
- Int,
- Text,
- TextLine,
- )
-
-from lp import _
-from lp.app.interfaces.launchpad import ILaunchpadCelebrities
-from lp.services.fields import (
- PersonChoice,
- PublicPersonChoice,
- )
-
-
-class IBranchMergeQueue(Interface):
- """An interface for managing branch merges."""
-
- export_as_webservice_entry()
-
- id = Int(title=_('ID'), readonly=True, required=True)
-
- registrant = exported(
- PublicPersonChoice(
- title=_("The user that registered the branch."),
- required=True, readonly=True,
- vocabulary='ValidPersonOrTeam'))
-
- owner = exported(
- PersonChoice(
- title=_('Owner'),
- required=True, readonly=True,
- vocabulary='UserTeamsParticipationPlusSelf',
- description=_("The owner of the merge queue.")))
-
- name = exported(
- TextLine(
- title=_('Name'), required=True,
- description=_(
- "Keep very short, unique, and descriptive, because it will "
- "be used in URLs. "
- "Examples: main, devel, release-1.0, gnome-vfs.")))
-
- description = exported(
- Text(
- title=_('Description'), required=False,
- description=_(
- 'A short description of the purpose of this merge queue.')))
-
- configuration = exported(
- TextLine(
- title=_('Configuration'), required=False, readonly=True,
- description=_(
- "A JSON string of configuration values.")))
-
- date_created = exported(
- Datetime(
- title=_('Date Created'),
- required=True,
- readonly=True))
-
- branches = exported(
- CollectionField(
- title=_('Dependent Branches'),
- description=_(
- 'A collection of branches that this queue manages.'),
- readonly=True,
- value_type=Reference(Interface)))
-
- @mutator_for(configuration)
- @operation_parameters(
- config=TextLine(title=_("A JSON string of configuration values.")))
- @export_write_operation()
- def setMergeQueueConfig(config):
- """Set the JSON string configuration of the merge queue.
-
- :param config: A JSON string of configuration values.
- """
-
-
-class IBranchMergeQueueSource(Interface):
-
- def new(name, owner, registrant, description, configuration, branches):
- """Create a new IBranchMergeQueue object.
-
- :param name: The name of the branch merge queue.
- :param description: A description of queue.
- :param configuration: A JSON string of configuration values.
- :param owner: The owner of the queue.
- :param registrant: The registrant of the queue.
- :param branches: A list of branches to add to the queue.
- """
-
-
-def user_has_special_merge_queue_access(user):
- """Admins and bazaar experts have special access.
-
- :param user: A 'Person' or None.
- """
- if user is None:
- return False
- celebs = getUtility(ILaunchpadCelebrities)
- return user.inTeam(celebs.admin)
=== removed file 'lib/lp/code/interfaces/branchmergequeuecollection.py'
--- lib/lp/code/interfaces/branchmergequeuecollection.py 2013-01-07 02:40:55 +0000
+++ lib/lp/code/interfaces/branchmergequeuecollection.py 1970-01-01 00:00:00 +0000
@@ -1,62 +0,0 @@
-# Copyright 2010 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""A collection of branche merge queues.
-
-See `IBranchMergeQueueCollection` for more details.
-"""
-
-__metaclass__ = type
-__all__ = [
- 'IAllBranchMergeQueues',
- 'IBranchMergeQueueCollection',
- 'InvalidFilter',
- ]
-
-from zope.interface import Interface
-
-
-class InvalidFilter(Exception):
- """Raised when an `IBranchMergeQueueCollection` can't apply the filter."""
-
-
-class IBranchMergeQueueCollection(Interface):
- """A collection of branch merge queues.
-
- An `IBranchMergeQueueCollection` is an immutable collection of branch
- merge queues. It has two kinds of methods:
- filter methods and query methods.
-
- Query methods get information about the contents of collection. See
- `IBranchMergeQueueCollection.count` and
- `IBranchMergeQueueCollection.getMergeQueues`.
-
- Implementations of this interface are not 'content classes'. That is, they
- do not correspond to a particular row in the database.
-
- This interface is intended for use within Launchpad, not to be exported as
- a public API.
- """
-
- def count():
- """The number of merge queues in this collection."""
-
- def getMergeQueues():
- """Return a result set of all merge queues in this collection.
-
- The returned result set will also join across the specified tables as
- defined by the arguments to this function. These extra tables are
- joined specificly to allow the caller to sort on values not in the
- Branch table itself.
- """
-
- def ownedBy(person):
- """Restrict the collection to queues owned by 'person'."""
-
- def visibleByUser(person):
- """Restrict the collection to queues that 'person' is allowed to see.
- """
-
-
-class IAllBranchMergeQueues(IBranchMergeQueueCollection):
- """An `IBranchMergeQueueCollection` of all branch merge queues."""
=== modified file 'lib/lp/code/interfaces/webservice.py'
--- lib/lp/code/interfaces/webservice.py 2015-04-15 18:34:25 +0000
+++ lib/lp/code/interfaces/webservice.py 2015-04-19 14:40:56 +0000
@@ -53,7 +53,6 @@
IBranchSet,
)
from lp.code.interfaces.branchmergeproposal import IBranchMergeProposal
-from lp.code.interfaces.branchmergequeue import IBranchMergeQueue
from lp.code.interfaces.branchsubscription import IBranchSubscription
from lp.code.interfaces.codeimport import ICodeImport
from lp.code.interfaces.codereviewcomment import ICodeReviewComment
@@ -73,10 +72,7 @@
from lp.code.interfaces.sourcepackagerecipebuild import (
ISourcePackageRecipeBuild,
)
-from lp.services.webservice.apihelpers import patch_collection_property
-
-
-patch_collection_property(IBranchMergeQueue, 'branches', IBranch)
+
# XXX: JonathanLange 2010-11-09 bug=673083: Legacy work-around for circular
# import bugs. Break this up into a per-package thing.
=== modified file 'lib/lp/code/model/branch.py'
--- lib/lp/code/model/branch.py 2015-04-15 13:41:13 +0000
+++ lib/lp/code/model/branch.py 2015-04-19 14:40:56 +0000
@@ -14,7 +14,6 @@
from bzrlib import urlutils
from bzrlib.revision import NULL_REVISION
import pytz
-import simplejson
from sqlobject import (
ForeignKey,
IntCol,
@@ -35,11 +34,7 @@
Select,
SQL,
)
-from storm.locals import (
- AutoReload,
- Int,
- Reference,
- )
+from storm.locals import AutoReload
from storm.store import Store
from zope.component import getUtility
from zope.event import notify
@@ -97,7 +92,6 @@
CannotUpgradeBranch,
CannotUpgradeNonHosted,
InvalidBranchMergeProposal,
- InvalidMergeQueueConfig,
UpgradePending,
)
from lp.code.event.branchmergeproposal import (
@@ -1422,23 +1416,6 @@
hook = SourcePackageRecipe.preLoadDataForSourcePackageRecipes
return DecoratedResultSet(self._recipes, pre_iter_hook=hook)
- merge_queue_id = Int(name='merge_queue', allow_none=True)
- merge_queue = Reference(merge_queue_id, 'BranchMergeQueue.id')
-
- merge_queue_config = StringCol(dbName='merge_queue_config')
-
- def addToQueue(self, queue):
- """See `IBranchEdit`."""
- self.merge_queue = queue
-
- def setMergeQueueConfig(self, config):
- """See `IBranchEdit`."""
- try:
- simplejson.loads(config)
- self.merge_queue_config = config
- except ValueError: # The json string is invalid
- raise InvalidMergeQueueConfig
-
class DeletionOperation:
"""Represent an operation to perform as part of branch deletion."""
=== modified file 'lib/lp/code/model/branchmergeproposal.py'
--- lib/lp/code/model/branchmergeproposal.py 2015-04-17 00:01:15 +0000
+++ lib/lp/code/model/branchmergeproposal.py 2015-04-19 14:40:56 +0000
@@ -137,24 +137,22 @@
superseded,
] = BranchMergeProposalStatus.items
- # Transitioning to code approved, rejected, failed or queued from
- # work in progress, needs review or merge failed needs the
- # user to be a valid reviewer, other states are fine.
+ # Transitioning to code approved, rejected, or failed from work in
+ # progress or needs review needs the user to be a valid reviewer, other
+ # states are fine.
valid_reviewer = proposal.target_branch.isPersonTrustedReviewer(user)
- reviewed_ok_states = (code_approved, queued, merge_failed)
+ reviewed_ok_states = (code_approved, )
+ obsolete_states = (merge_failed, queued)
if not valid_reviewer:
- # Non reviewers cannot reject proposals [XXX: what about their own?]
+ # We cannot transition to obsolete states, and we no longer know how
+ # to transition away from them either.
+ if next_state in obsolete_states or from_state in obsolete_states:
+ return False
+ # Non-reviewers cannot reject proposals [XXX: what about their own?]
if next_state == rejected:
return False
- # Non-reviewers can toggle within the reviewed ok states
- # (approved/queued/failed): they can dequeue something they spot an
- # environmental issue with (queued or failed to approved). Retry
- # things that had an environmental issue (failed or approved to
- # queued) and note things as failing (approved and queued to failed).
- # This is perhaps more generous than needed, but its not clearly wrong
- # - a key concern is to prevent non reviewers putting things in the
- # queue that haven't been approved (and thus moved to approved or one
- # of the workflow states that approved leads to).
+ # Non-reviewers cannot approve proposals, but can otherwise move
+ # things around relatively freely.
elif (next_state in reviewed_ok_states and
from_state not in reviewed_ok_states):
return False
@@ -245,13 +243,6 @@
commit_message = StringCol(default=None)
- queue_position = IntCol(default=None)
-
- queuer = ForeignKey(
- dbName='queuer', foreignKey='Person', notNull=False,
- default=None)
- queued_revision_id = StringCol(default=None)
-
date_merged = UtcDateTimeCol(default=None)
merged_revno = IntCol(default=None)
@@ -336,8 +327,6 @@
def preview_diff(self):
return self._preview_diffs.last()
- date_queued = UtcDateTimeCol(notNull=False, default=None)
-
votes = SQLMultipleJoin(
'CodeReviewVoteReference', joinColumn='branch_merge_proposal')
@@ -422,9 +411,6 @@
# XXX - rockstar - 9 Oct 2008 - jml suggested in a review that this
# would be better as a dict mapping.
# See bug #281060.
- if (self.queue_status == BranchMergeProposalStatus.QUEUED and
- status != BranchMergeProposalStatus.QUEUED):
- self.dequeue()
if status == BranchMergeProposalStatus.WORK_IN_PROGRESS:
self.setAsWorkInProgress()
elif status == BranchMergeProposalStatus.NEEDS_REVIEW:
@@ -433,12 +419,8 @@
self.approveBranch(user, revision_id)
elif status == BranchMergeProposalStatus.REJECTED:
self.rejectBranch(user, revision_id)
- elif status == BranchMergeProposalStatus.QUEUED:
- self.enqueue(user, revision_id)
elif status == BranchMergeProposalStatus.MERGED:
self.markAsMerged(merge_reporter=user)
- elif status == BranchMergeProposalStatus.MERGE_FAILED:
- self._transitionToState(status, user=user)
else:
raise AssertionError('Unexpected queue status: %s' % status)
@@ -471,10 +453,8 @@
if self.queue_status != BranchMergeProposalStatus.NEEDS_REVIEW:
self._transitionToState(BranchMergeProposalStatus.NEEDS_REVIEW)
self.date_review_requested = _date_requested
- # Clear out any reviewed or queued values.
+ # Clear out any reviewed values.
self._mark_unreviewed()
- self.queuer = None
- self.queued_revision_id = None
def isMergable(self):
"""See `IBranchMergeProposal`."""
@@ -513,63 +493,6 @@
reviewer, BranchMergeProposalStatus.REJECTED, revision_id,
_date_reviewed)
- def enqueue(self, queuer, revision_id):
- """See `IBranchMergeProposal`."""
- if self.queue_status != BranchMergeProposalStatus.CODE_APPROVED:
- self.approveBranch(queuer, revision_id)
-
- last_entry = BranchMergeProposal.selectOne("""
- BranchMergeProposal.queue_position = (
- SELECT coalesce(MAX(queue_position), 0)
- FROM BranchMergeProposal)
- """)
-
- # The queue_position will wrap if we ever get to
- # two billion queue entries where the queue has
- # never become empty. Perhaps sometime in the future
- # we may want to (maybe) consider keeping track of
- # the maximum value here. I doubt that it'll ever be
- # a problem -- thumper.
- if last_entry is None:
- position = 1
- else:
- position = last_entry.queue_position + 1
-
- self.queue_status = BranchMergeProposalStatus.QUEUED
- self.queue_position = position
- self.queuer = queuer
- self.queued_revision_id = revision_id or self.reviewed_revision_id
- self.date_queued = UTC_NOW
- self.syncUpdate()
-
- def dequeue(self):
- """See `IBranchMergeProposal`."""
- if self.queue_status != BranchMergeProposalStatus.QUEUED:
- raise BadStateTransition(
- 'Invalid state transition for merge proposal: %s -> %s'
- % (self.queue_state.title,
- BranchMergeProposalStatus.QUEUED.title))
- self.queue_status = BranchMergeProposalStatus.CODE_APPROVED
- # Clear out the queued values.
- self.queuer = None
- self.queued_revision_id = None
- self.date_queued = None
- # Remove from the queue.
- self.queue_position = None
-
- def moveToFrontOfQueue(self):
- """See `IBranchMergeProposal`."""
- if self.queue_status != BranchMergeProposalStatus.QUEUED:
- return
- first_entry = BranchMergeProposal.selectOne("""
- BranchMergeProposal.queue_position = (
- SELECT MIN(queue_position)
- FROM BranchMergeProposal)
- """)
-
- self.queue_position = first_entry.queue_position - 1
- self.syncUpdate()
-
def markAsMerged(self, merged_revno=None, date_merged=None,
merge_reporter=None):
"""See `IBranchMergeProposal`."""
@@ -578,8 +501,6 @@
BranchMergeProposalStatus.MERGED, merge_reporter)
self.merged_revno = merged_revno
self.merge_reporter = merge_reporter
- # Remove from the queue.
- self.queue_position = None
# The reviewer of a merged proposal is assumed to have approved, if
# they rejected it remove the review metadata to avoid confusion.
=== removed file 'lib/lp/code/model/branchmergequeue.py'
--- lib/lp/code/model/branchmergequeue.py 2013-06-20 05:50:00 +0000
+++ lib/lp/code/model/branchmergequeue.py 1970-01-01 00:00:00 +0000
@@ -1,88 +0,0 @@
-# Copyright 2010 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Implementation classes for IBranchMergeQueue, etc."""
-
-__metaclass__ = type
-__all__ = ['BranchMergeQueue']
-
-import simplejson
-from storm.locals import (
- Int,
- Reference,
- Store,
- Storm,
- Unicode,
- )
-from zope.interface import (
- classProvides,
- implements,
- )
-
-from lp.code.errors import InvalidMergeQueueConfig
-from lp.code.interfaces.branchmergequeue import (
- IBranchMergeQueue,
- IBranchMergeQueueSource,
- )
-from lp.code.model.branch import Branch
-from lp.services.database.datetimecol import UtcDateTimeCol
-from lp.services.database.interfaces import IMasterStore
-
-
-class BranchMergeQueue(Storm):
- """See `IBranchMergeQueue`."""
-
- __storm_table__ = 'BranchMergeQueue'
- implements(IBranchMergeQueue)
- classProvides(IBranchMergeQueueSource)
-
- id = Int(primary=True)
-
- registrant_id = Int(name='registrant', allow_none=True)
- registrant = Reference(registrant_id, 'Person.id')
-
- owner_id = Int(name='owner', allow_none=True)
- owner = Reference(owner_id, 'Person.id')
-
- name = Unicode(allow_none=False)
- description = Unicode(allow_none=False)
- configuration = Unicode(allow_none=False)
-
- date_created = UtcDateTimeCol(notNull=True)
-
- @property
- def branches(self):
- """See `IBranchMergeQueue`."""
- return Store.of(self).find(
- Branch,
- Branch.merge_queue_id == self.id)
-
- def setMergeQueueConfig(self, config):
- """See `IBranchMergeQueue`."""
- try:
- simplejson.loads(config)
- self.configuration = config
- except ValueError: # The config string is not valid JSON
- raise InvalidMergeQueueConfig
-
- @classmethod
- def new(cls, name, owner, registrant, description=None,
- configuration=None, branches=None):
- """See `IBranchMergeQueueSource`."""
- store = IMasterStore(BranchMergeQueue)
-
- if configuration is None:
- configuration = unicode(simplejson.dumps({}))
-
- queue = cls()
- queue.name = name
- queue.owner = owner
- queue.registrant = registrant
- queue.description = description
- queue.configuration = configuration
- if branches is not None:
- for branch in branches:
- branch.addToQueue(queue)
-
- store.add(queue)
- return queue
=== removed file 'lib/lp/code/model/branchmergequeuecollection.py'
--- lib/lp/code/model/branchmergequeuecollection.py 2015-02-05 11:49:48 +0000
+++ lib/lp/code/model/branchmergequeuecollection.py 1970-01-01 00:00:00 +0000
@@ -1,158 +0,0 @@
-# Copyright 2010 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Implementations of `IBranchMergeQueueCollection`."""
-
-__metaclass__ = type
-__all__ = [
- 'GenericBranchMergeQueueCollection',
- ]
-
-from zope.interface import implements
-
-from lp.code.interfaces.branchmergequeue import (
- user_has_special_merge_queue_access,
- )
-from lp.code.interfaces.branchmergequeuecollection import (
- IBranchMergeQueueCollection,
- InvalidFilter,
- )
-from lp.code.interfaces.codehosting import LAUNCHPAD_SERVICES
-from lp.code.model.branchmergequeue import BranchMergeQueue
-from lp.services.database.interfaces import IMasterStore
-
-
-class GenericBranchMergeQueueCollection:
- """See `IBranchMergeQueueCollection`."""
-
- implements(IBranchMergeQueueCollection)
-
- def __init__(self, store=None, merge_queue_filter_expressions=None,
- tables=None):
- """Construct a `GenericBranchMergeQueueCollection`.
-
- :param store: The store to look in for merge queues. If not specified,
- use the default store.
- :param merge_queue_filter_expressions: A list of Storm expressions to
- restrict the queues in the collection. If unspecified, then
- there will be no restrictions on the result set. That is, all
- queues in the store will be in the collection.
- :param tables: A dict of Storm tables to the Join expression. If an
- expression in merge_queue_filter_expressions refers to a table,
- then that table *must* be in this list.
- """
- self._store = store
- if merge_queue_filter_expressions is None:
- merge_queue_filter_expressions = []
- self._merge_queue_filter_expressions = merge_queue_filter_expressions
- if tables is None:
- tables = {}
- self._tables = tables
-
- def count(self):
- return self._getCount()
-
- def _getCount(self):
- """See `IBranchMergeQueueCollection`."""
- return self._getMergeQueues().count()
-
- @property
- def store(self):
- if self._store is None:
- return IMasterStore(BranchMergeQueue)
- else:
- return self._store
-
- def _filterBy(self, expressions, table=None, join=None):
- """Return a subset of this collection, filtered by 'expressions'."""
- tables = self._tables.copy()
- if table is not None:
- if join is None:
- raise InvalidFilter("Cannot specify a table without a join.")
- tables[table] = join
- if expressions is None:
- expressions = []
- return self.__class__(
- self.store,
- self._merge_queue_filter_expressions + expressions,
- tables)
-
- def _getMergeQueueExpressions(self):
- """Return the where expressions for this collection."""
- return self._merge_queue_filter_expressions
-
- def getMergeQueues(self):
- return list(self._getMergeQueues())
-
- def _getMergeQueues(self):
- """See `IBranchMergeQueueCollection`."""
- tables = [BranchMergeQueue] + self._tables.values()
- expressions = self._getMergeQueueExpressions()
- return self.store.using(*tables).find(BranchMergeQueue, *expressions)
-
- def ownedBy(self, person):
- """See `IBranchMergeQueueCollection`."""
- return self._filterBy([BranchMergeQueue.owner == person])
-
- def visibleByUser(self, person):
- """See `IBranchMergeQueueCollection`."""
- if (person == LAUNCHPAD_SERVICES or
- user_has_special_merge_queue_access(person)):
- return self
- return VisibleBranchMergeQueueCollection(
- person, self._store, None, self._tables)
-
-
-class VisibleBranchMergeQueueCollection(GenericBranchMergeQueueCollection):
- """A mergequeue collection which provides queues visible by a user."""
-
- def __init__(self, person, store=None,
- merge_queue_filter_expressions=None, tables=None):
- super(VisibleBranchMergeQueueCollection, self).__init__(
- store=store,
- merge_queue_filter_expressions=merge_queue_filter_expressions,
- tables=tables)
- self._user = person
-
- def _filterBy(self, expressions, table=None, join=None):
- """Return a subset of this collection, filtered by 'expressions'."""
- tables = self._tables.copy()
- if table is not None:
- if join is None:
- raise InvalidFilter("Cannot specify a table without a join.")
- tables[table] = join
- if expressions is None:
- expressions = []
- return self.__class__(
- self._user,
- self.store,
- self._merge_queue_filter_expressions + expressions,
- tables)
-
- def visibleByUser(self, person):
- """See `IBranchMergeQueueCollection`."""
- if person == self._user:
- return self
- raise InvalidFilter(
- "Cannot filter for merge queues visible by user %r, already "
- "filtering for %r" % (person, self._user))
-
- def _getCount(self):
- """See `IBranchMergeQueueCollection`."""
- return len(self._getMergeQueues())
-
- def _getMergeQueues(self):
- """Return the queues visible by self._user.
-
- A queue is visible to a user if that user can see all the branches
- associated with the queue.
- """
-
- def allBranchesVisible(user, branches):
- return len([branch for branch in branches
- if branch.visibleByUser(user)]) == branches.count()
-
- queues = super(
- VisibleBranchMergeQueueCollection, self)._getMergeQueues()
- return [queue for queue in queues
- if allBranchesVisible(self._user, queue.branches)]
=== modified file 'lib/lp/code/model/tests/test_branch.py'
--- lib/lp/code/model/tests/test_branch.py 2014-08-19 04:56:39 +0000
+++ lib/lp/code/model/tests/test_branch.py 2015-04-19 14:40:56 +0000
@@ -64,7 +64,6 @@
CannotDeleteBranch,
CannotUpgradeNonHosted,
InvalidBranchMergeProposal,
- InvalidMergeQueueConfig,
UpgradePending,
)
from lp.code.interfaces.branch import (
@@ -3267,45 +3266,6 @@
self.assertRaises(BadUrl, db_stacked.getBzrBranch)
-class TestMergeQueue(TestCaseWithFactory):
- """Tests for branch merge queue functionality in branches."""
-
- layer = DatabaseFunctionalLayer
-
- def test_addToQueue(self):
- """Test Branch.addToQueue."""
- branch = self.factory.makeBranch()
- queue = self.factory.makeBranchMergeQueue()
- with person_logged_in(branch.owner):
- branch.addToQueue(queue)
-
- self.assertEqual(branch.merge_queue, queue)
-
- def test_setMergeQueueConfig(self):
- """Test Branch.setMergeQueueConfig."""
- branch = self.factory.makeBranch()
- config = json.dumps({
- 'path': '/',
- 'test': 'make test',
- })
-
- with person_logged_in(branch.owner):
- branch.setMergeQueueConfig(config)
-
- self.assertEqual(branch.merge_queue_config, config)
-
- def test_setMergeQueueConfig_invalid(self):
- """Test that invalid JSON strings aren't added to the database."""
- branch = self.factory.makeBranch()
- config = 'abc'
-
- with person_logged_in(branch.owner):
- self.assertRaises(
- InvalidMergeQueueConfig,
- branch.setMergeQueueConfig,
- config)
-
-
class TestBranchUnscan(TestCaseWithFactory):
layer = DatabaseFunctionalLayer
@@ -3377,24 +3337,6 @@
self.webservice = webservice_for_person(
self.branch_db.owner, permission=OAuthPermission.WRITE_PUBLIC)
- def test_set_merge_queue(self):
- """Test that the merge queue and config can be set properly."""
- with person_logged_in(ANONYMOUS):
- queue_db = self.factory.makeBranchMergeQueue()
- queue_url = api_url(queue_db)
-
- config = json.dumps({'test': 'make check'})
- self.webservice.patch(
- self.branch_url, "application/json",
- json.dumps({
- "merge_queue_link": queue_url,
- "merge_queue_config": config,
- }),
- api_version='devel')
- with person_logged_in(ANONYMOUS):
- self.assertEqual(self.branch_db.merge_queue, queue_db)
- self.assertEqual(self.branch_db.merge_queue_config, config)
-
def test_transitionToInformationType(self):
"""Test transitionToInformationType() API arguments."""
self.webservice.named_post(
=== modified file 'lib/lp/code/model/tests/test_branchmergeproposal.py'
--- lib/lp/code/model/tests/test_branchmergeproposal.py 2014-08-19 04:56:39 +0000
+++ lib/lp/code/model/tests/test_branchmergeproposal.py 2015-04-19 14:40:56 +0000
@@ -44,6 +44,7 @@
)
from lp.code.interfaces.branchmergeproposal import (
BRANCH_MERGE_PROPOSAL_FINAL_STATES as FINAL_STATES,
+ BRANCH_MERGE_PROPOSAL_OBSOLETE_STATES as OBSOLETE_STATES,
IBranchMergeProposal,
IBranchMergeProposalGetter,
notify_modified,
@@ -196,8 +197,6 @@
BranchMergeProposalStatus.CODE_APPROVED: 'approveBranch',
BranchMergeProposalStatus.REJECTED: 'rejectBranch',
BranchMergeProposalStatus.MERGED: 'markAsMerged',
- BranchMergeProposalStatus.MERGE_FAILED: 'setStatus',
- BranchMergeProposalStatus.QUEUED: 'enqueue',
BranchMergeProposalStatus.SUPERSEDED: 'resubmit',
}
@@ -217,15 +216,10 @@
kwargs = {}
method = getattr(proposal, self.transition_functions[to_state])
if to_state in (BranchMergeProposalStatus.CODE_APPROVED,
- BranchMergeProposalStatus.REJECTED,
- BranchMergeProposalStatus.QUEUED):
+ BranchMergeProposalStatus.REJECTED):
args = [proposal.target_branch.owner, 'some_revision_id']
elif to_state in (BranchMergeProposalStatus.SUPERSEDED, ):
args = [proposal.registrant]
- elif to_state in (BranchMergeProposalStatus.MERGE_FAILED, ):
- # transition via setStatus.
- args = [to_state]
- kwargs = dict(user=proposal.target_branch.owner)
else:
args = []
method(*args, **kwargs)
@@ -280,6 +274,9 @@
def assertAllTransitionsGood(self, from_state):
"""Assert that we can go from `from_state` to any state."""
for status in BranchMergeProposalStatus.items:
+ if status in OBSOLETE_STATES:
+ # We don't need to permit transitions to obsolete states.
+ continue
self.assertGoodTransition(from_state, status)
def test_transitions_from_wip(self):
@@ -311,6 +308,9 @@
"""
for from_status in FINAL_STATES:
for to_status in BranchMergeProposalStatus.items:
+ if to_status in OBSOLETE_STATES:
+ # We don't need to permit transitions to obsolete states.
+ continue
if to_status == BranchMergeProposalStatus.SUPERSEDED:
continue
if to_status in FINAL_STATES:
@@ -345,74 +345,6 @@
proposal, BranchMergeProposalStatus.REJECTED,
proposal.source_branch.owner)
- def test_transitions_from_merge_failed(self):
- """We can go from merge failed to any other state."""
- self.assertAllTransitionsGood(BranchMergeProposalStatus.MERGE_FAILED)
-
- def test_transition_from_merge_failed_to_queued_non_reviewer(self):
- # Contributors can requeue to retry after environmental issues fail a
- # merge.
- proposal = self.factory.makeBranchMergeProposal()
- self.assertFalse(proposal.target_branch.isPersonTrustedReviewer(
- proposal.source_branch.owner))
- self.assertValidTransitions(set([
- BranchMergeProposalStatus.MERGE_FAILED,
- BranchMergeProposalStatus.CODE_APPROVED,
- # It is always valid to go to the same state.
- BranchMergeProposalStatus.QUEUED]),
- proposal, BranchMergeProposalStatus.QUEUED,
- proposal.source_branch.owner)
-
- def test_transitions_from_queued_dequeue(self):
- # When a proposal is dequeued it is set to code approved, and the
- # queue position is reset.
- proposal = self.factory.makeBranchMergeProposal(
- target_branch=self.target_branch,
- set_state=BranchMergeProposalStatus.QUEUED)
- proposal.dequeue()
- self.assertProposalState(
- proposal, BranchMergeProposalStatus.CODE_APPROVED)
- self.assertIs(None, proposal.queue_position)
- self.assertIs(None, proposal.queuer)
- self.assertIs(None, proposal.queued_revision_id)
- self.assertIs(None, proposal.date_queued)
-
- def test_transitions_from_queued_to_merged(self):
- # When a proposal is marked as merged from queued, the queue_position
- # is reset.
- proposal = self.factory.makeBranchMergeProposal(
- target_branch=self.target_branch,
- set_state=BranchMergeProposalStatus.QUEUED)
- proposal.markAsMerged()
- self.assertProposalState(
- proposal, BranchMergeProposalStatus.MERGED)
- self.assertIs(None, proposal.queue_position)
-
- def test_transitions_from_queued_to_merge_failed(self):
- # When a proposal is marked as merged from queued, the queue_position
- # is reset.
- proposal = self.factory.makeBranchMergeProposal(
- target_branch=self.target_branch,
- set_state=BranchMergeProposalStatus.QUEUED)
- proposal.setStatus(BranchMergeProposalStatus.MERGE_FAILED)
- self.assertProposalState(
- proposal, BranchMergeProposalStatus.MERGE_FAILED)
- self.assertIs(None, proposal.queue_position)
-
- def test_transition_to_merge_failed_non_reviewer(self):
- # non reviewers cannot set merge-failed (target branch owners are
- # implicitly reviewers).
- proposal = self.factory.makeBranchMergeProposal()
- self.assertFalse(proposal.target_branch.isPersonTrustedReviewer(
- proposal.source_branch.owner))
- self.assertValidTransitions(set([
- # It is always valid to go to the same state.
- BranchMergeProposalStatus.MERGE_FAILED,
- BranchMergeProposalStatus.CODE_APPROVED,
- BranchMergeProposalStatus.QUEUED]),
- proposal, BranchMergeProposalStatus.MERGE_FAILED,
- proposal.source_branch.owner)
-
def test_transitions_to_wip_resets_reviewer(self):
# When a proposal was approved and is moved back into work in progress
# the reviewer, date reviewed, and reviewed revision are all reset.
@@ -452,19 +384,6 @@
self.target_branch = self.factory.makeProductBranch()
login_person(self.target_branch.owner)
- def test_set_status_approved_to_queued(self):
- # setState can change an approved merge proposal to Work In Progress,
- # which will set the revision id to the reviewed revision id if not
- # supplied.
- proposal = self.factory.makeBranchMergeProposal(
- target_branch=self.target_branch,
- set_state=BranchMergeProposalStatus.CODE_APPROVED)
- proposal.approveBranch(proposal.target_branch.owner, '250')
- proposal.setStatus(BranchMergeProposalStatus.QUEUED)
- self.assertEqual(proposal.queue_status,
- BranchMergeProposalStatus.QUEUED)
- self.assertEqual(proposal.queued_revision_id, '250')
-
def test_set_status_approved_to_work_in_progress(self):
# setState can change an approved merge proposal to Work In Progress.
proposal = self.factory.makeBranchMergeProposal(
@@ -474,18 +393,6 @@
self.assertEqual(proposal.queue_status,
BranchMergeProposalStatus.WORK_IN_PROGRESS)
- def test_set_status_queued_to_merge_failed(self):
- proposal = self.factory.makeBranchMergeProposal(
- target_branch=self.target_branch,
- set_state=BranchMergeProposalStatus.QUEUED)
- proposal.setStatus(BranchMergeProposalStatus.MERGE_FAILED)
- self.assertEqual(proposal.queue_status,
- BranchMergeProposalStatus.MERGE_FAILED)
- self.assertEqual(proposal.queuer, None)
- self.assertEqual(proposal.queued_revision_id, None)
- self.assertEqual(proposal.date_queued, None)
- self.assertEqual(proposal.queue_position, None)
-
def test_set_status_wip_to_needs_review(self):
# setState can change the merge proposal to Needs Review.
proposal = self.factory.makeBranchMergeProposal(
@@ -507,18 +414,6 @@
BranchMergeProposalStatus.CODE_APPROVED)
self.assertEqual(proposal.reviewed_revision_id, '500')
- def test_set_status_wip_to_queued(self):
- # setState can change the merge proposal to Queued, which will
- # also set the queued_revision_id to the specified revision id.
- proposal = self.factory.makeBranchMergeProposal(
- target_branch=self.target_branch,
- set_state=BranchMergeProposalStatus.WORK_IN_PROGRESS)
- proposal.setStatus(BranchMergeProposalStatus.QUEUED,
- user=self.target_branch.owner, revision_id='250')
- self.assertEqual(proposal.queue_status,
- BranchMergeProposalStatus.QUEUED)
- self.assertEqual(proposal.queued_revision_id, '250')
-
def test_set_status_wip_to_rejected(self):
# setState can change the merge proposal to Rejected, which also
# marks the reviewed_revision_id to the rejected revision id.
@@ -1086,6 +981,8 @@
def test_activeProposalsForBranches_different_states(self):
"""Only proposals for active states are returned."""
for state in BranchMergeProposalStatus.items:
+ if state in OBSOLETE_STATES:
+ continue
mp = self.factory.makeBranchMergeProposal(set_state=state)
active = BranchMergeProposalGetter.activeProposalsForBranches(
mp.source_branch, mp.target_branch)
@@ -1382,14 +1279,11 @@
"""
bmp = self.factory.makeBranchMergeProposal()
login_person(bmp.target_branch.owner)
- # Approve branch to prevent enqueue from approving it, which would
- # generate an undesired event.
- bmp.approveBranch(bmp.target_branch.owner, revision_id='abc')
self.assertNotifies(
- ObjectModifiedEvent, notify_modified, bmp, bmp.enqueue,
- bmp.target_branch.owner, revision_id='abc')
- self.assertEqual(BranchMergeProposalStatus.QUEUED, bmp.queue_status)
- self.assertEqual('abc', bmp.queued_revision_id)
+ ObjectModifiedEvent, notify_modified, bmp, bmp.markAsMerged,
+ merge_reporter=bmp.target_branch.owner)
+ self.assertEqual(BranchMergeProposalStatus.MERGED, bmp.queue_status)
+ self.assertEqual(bmp.target_branch.owner, bmp.merge_reporter)
class TestBranchMergeProposalNominateReviewer(TestCaseWithFactory):
=== removed file 'lib/lp/code/model/tests/test_branchmergequeue.py'
--- lib/lp/code/model/tests/test_branchmergequeue.py 2013-06-20 05:50:00 +0000
+++ lib/lp/code/model/tests/test_branchmergequeue.py 1970-01-01 00:00:00 +0000
@@ -1,155 +0,0 @@
-# Copyright 2010 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Unit tests for methods of BranchMergeQueue."""
-
-from __future__ import with_statement
-
-import simplejson
-
-from lp.code.errors import InvalidMergeQueueConfig
-from lp.code.interfaces.branchmergequeue import IBranchMergeQueue
-from lp.code.model.branchmergequeue import BranchMergeQueue
-from lp.services.database.interfaces import IStore
-from lp.testing import (
- ANONYMOUS,
- launchpadlib_for,
- person_logged_in,
- TestCaseWithFactory,
- verifyObject,
- ws_object,
- )
-from lp.testing.layers import (
- AppServerLayer,
- DatabaseFunctionalLayer,
- )
-
-
-class TestBranchMergeQueueInterface(TestCaseWithFactory):
- """Test IBranchMergeQueue interface."""
-
- layer = DatabaseFunctionalLayer
-
- def test_implements_interface(self):
- queue = self.factory.makeBranchMergeQueue()
- IStore(BranchMergeQueue).add(queue)
- verifyObject(IBranchMergeQueue, queue)
-
-
-class TestBranchMergeQueueSource(TestCaseWithFactory):
- """Test the methods of IBranchMergeQueueSource."""
-
- layer = DatabaseFunctionalLayer
-
- def test_new(self):
- owner = self.factory.makePerson()
- name = u'SooperQueue'
- description = u'This is Sooper Queue'
- config = unicode(simplejson.dumps({'test': 'make check'}))
-
- queue = BranchMergeQueue.new(
- name, owner, owner, description, config)
-
- self.assertEqual(queue.name, name)
- self.assertEqual(queue.owner, owner)
- self.assertEqual(queue.registrant, owner)
- self.assertEqual(queue.description, description)
- self.assertEqual(queue.configuration, config)
-
-
-class TestBranchMergeQueue(TestCaseWithFactory):
- """Test the functions of the BranchMergeQueue."""
-
- layer = DatabaseFunctionalLayer
-
- def test_branches(self):
- """Test that a merge queue can get all its managed branches."""
- store = IStore(BranchMergeQueue)
-
- queue = self.factory.makeBranchMergeQueue()
- store.add(queue)
-
- branch = self.factory.makeBranch()
- store.add(branch)
- with person_logged_in(branch.owner):
- branch.addToQueue(queue)
-
- self.assertEqual(
- list(queue.branches),
- [branch])
-
- def test_setMergeQueueConfig(self):
- """Test that the configuration is set properly."""
- queue = self.factory.makeBranchMergeQueue()
- config = unicode(simplejson.dumps({
- 'test': 'make test'}))
-
- with person_logged_in(queue.owner):
- queue.setMergeQueueConfig(config)
-
- self.assertEqual(queue.configuration, config)
-
- def test_setMergeQueueConfig_invalid_json(self):
- """Test that invalid json can't be set as the config."""
- queue = self.factory.makeBranchMergeQueue()
-
- with person_logged_in(queue.owner):
- self.assertRaises(
- InvalidMergeQueueConfig,
- queue.setMergeQueueConfig,
- 'abc')
-
-
-class TestWebservice(TestCaseWithFactory):
-
- layer = AppServerLayer
-
- def test_properties(self):
- """Test that the correct properties are exposed."""
- with person_logged_in(ANONYMOUS):
- name = u'teh-queue'
- description = u'Oh hai! I are a queues'
- configuration = unicode(simplejson.dumps({'test': 'make check'}))
-
- queuer = self.factory.makePerson()
- db_queue = self.factory.makeBranchMergeQueue(
- registrant=queuer, owner=queuer, name=name,
- description=description,
- configuration=configuration)
- branch1 = self.factory.makeBranch()
- with person_logged_in(branch1.owner):
- branch1.addToQueue(db_queue)
- branch2 = self.factory.makeBranch()
- with person_logged_in(branch2.owner):
- branch2.addToQueue(db_queue)
- launchpad = launchpadlib_for('test', db_queue.owner,
- service_root="http://api.launchpad.dev:8085")
-
- queuer = ws_object(launchpad, queuer)
- queue = ws_object(launchpad, db_queue)
- branch1 = ws_object(launchpad, branch1)
- branch2 = ws_object(launchpad, branch2)
-
- self.assertEqual(queue.registrant, queuer)
- self.assertEqual(queue.owner, queuer)
- self.assertEqual(queue.name, name)
- self.assertEqual(queue.description, description)
- self.assertEqual(queue.configuration, configuration)
- self.assertEqual(queue.date_created, db_queue.date_created)
- self.assertEqual(len(queue.branches), 2)
-
- def test_set_configuration(self):
- """Test the mutator for setting configuration."""
- with person_logged_in(ANONYMOUS):
- db_queue = self.factory.makeBranchMergeQueue()
- launchpad = launchpadlib_for('test', db_queue.owner,
- service_root="http://api.launchpad.dev:8085")
-
- configuration = simplejson.dumps({'test': 'make check'})
-
- queue = ws_object(launchpad, db_queue)
- queue.configuration = configuration
- queue.lp_save()
-
- queue2 = ws_object(launchpad, db_queue)
- self.assertEqual(queue2.configuration, configuration)
=== removed file 'lib/lp/code/model/tests/test_branchmergequeuecollection.py'
--- lib/lp/code/model/tests/test_branchmergequeuecollection.py 2013-06-20 05:50:00 +0000
+++ lib/lp/code/model/tests/test_branchmergequeuecollection.py 1970-01-01 00:00:00 +0000
@@ -1,194 +0,0 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Tests for branch merge queue collections."""
-
-__metaclass__ = type
-
-from zope.component import getUtility
-from zope.security.proxy import removeSecurityProxy
-
-from lp.app.enums import InformationType
-from lp.app.interfaces.launchpad import ILaunchpadCelebrities
-from lp.code.interfaces.branchmergequeuecollection import (
- IAllBranchMergeQueues,
- IBranchMergeQueueCollection,
- )
-from lp.code.interfaces.codehosting import LAUNCHPAD_SERVICES
-from lp.code.model.branchmergequeue import BranchMergeQueue
-from lp.code.model.branchmergequeuecollection import (
- GenericBranchMergeQueueCollection,
- )
-from lp.services.database.interfaces import IMasterStore
-from lp.testing import TestCaseWithFactory
-from lp.testing.layers import DatabaseFunctionalLayer
-
-
-class TestGenericBranchMergeQueueCollection(TestCaseWithFactory):
-
- layer = DatabaseFunctionalLayer
-
- def setUp(self):
- TestCaseWithFactory.setUp(self)
- self.store = IMasterStore(BranchMergeQueue)
-
- def test_provides_branchmergequeuecollection(self):
- # `GenericBranchMergeQueueCollection`
- # provides the `IBranchMergeQueueCollection` interface.
- self.assertProvides(
- GenericBranchMergeQueueCollection(self.store),
- IBranchMergeQueueCollection)
-
- def test_getMergeQueues_no_filter_no_queues(self):
- # If no filter is specified, then the collection is of all branches
- # merge queues. By default, there are no branch merge queues.
- collection = GenericBranchMergeQueueCollection(self.store)
- self.assertEqual([], list(collection.getMergeQueues()))
-
- def test_getMergeQueues_no_filter(self):
- # If no filter is specified, then the collection is of all branch
- # merge queues.
- collection = GenericBranchMergeQueueCollection(self.store)
- queue = self.factory.makeBranchMergeQueue()
- self.assertEqual([queue], list(collection.getMergeQueues()))
-
- def test_count(self):
- # The 'count' property of a collection is the number of elements in
- # the collection.
- collection = GenericBranchMergeQueueCollection(self.store)
- self.assertEqual(0, collection.count())
- for i in range(3):
- self.factory.makeBranchMergeQueue()
- self.assertEqual(3, collection.count())
-
- def test_count_respects_filter(self):
- # If a collection is a subset of all possible queues, then the count
- # will be the size of that subset. That is, 'count' respects any
- # filters that are applied.
- person = self.factory.makePerson()
- self.factory.makeBranchMergeQueue(owner=person)
- self.factory.makeAnyBranch()
- collection = GenericBranchMergeQueueCollection(
- self.store, [BranchMergeQueue.owner == person])
- self.assertEqual(1, collection.count())
-
-
-class TestBranchMergeQueueCollectionFilters(TestCaseWithFactory):
-
- layer = DatabaseFunctionalLayer
-
- def setUp(self):
- TestCaseWithFactory.setUp(self)
- self.all_queues = getUtility(IAllBranchMergeQueues)
-
- def test_count_respects_visibleByUser_filter(self):
- # IBranchMergeQueueCollection.count() returns the number of queues
- # that getMergeQueues() yields, even when the visibleByUser filter is
- # applied.
- branch = self.factory.makeAnyBranch(
- information_type=InformationType.USERDATA)
- naked_branch = removeSecurityProxy(branch)
- self.factory.makeBranchMergeQueue(branches=[naked_branch])
- branch2 = self.factory.makeAnyBranch(
- information_type=InformationType.USERDATA)
- naked_branch2 = removeSecurityProxy(branch2)
- self.factory.makeBranchMergeQueue(branches=[naked_branch2])
- collection = self.all_queues.visibleByUser(naked_branch.owner)
- self.assertEqual(1, len(collection.getMergeQueues()))
- self.assertEqual(1, collection.count())
-
- def test_ownedBy(self):
- # 'ownedBy' returns a new collection restricted to queues owned by
- # the given person.
- queue = self.factory.makeBranchMergeQueue()
- self.factory.makeBranchMergeQueue()
- collection = self.all_queues.ownedBy(queue.owner)
- self.assertEqual([queue], collection.getMergeQueues())
-
-
-class TestGenericBranchMergeQueueCollectionVisibleFilter(TestCaseWithFactory):
-
- layer = DatabaseFunctionalLayer
-
- def setUp(self):
- TestCaseWithFactory.setUp(self)
- public_branch = self.factory.makeAnyBranch(name='public')
- self.queue_with_public_branch = self.factory.makeBranchMergeQueue(
- branches=[removeSecurityProxy(public_branch)])
- private_branch1 = self.factory.makeAnyBranch(
- name='private1', information_type=InformationType.USERDATA)
- naked_private_branch1 = removeSecurityProxy(private_branch1)
- self.private_branch1_owner = naked_private_branch1.owner
- self.queue1_with_private_branch = self.factory.makeBranchMergeQueue(
- branches=[naked_private_branch1])
- private_branch2 = self.factory.makeAnyBranch(
- name='private2', information_type=InformationType.USERDATA)
- self.queue2_with_private_branch = self.factory.makeBranchMergeQueue(
- branches=[removeSecurityProxy(private_branch2)])
- self.all_queues = getUtility(IAllBranchMergeQueues)
-
- def test_all_queues(self):
- # Without the visibleByUser filter, all queues are in the
- # collection.
- self.assertEqual(
- sorted([self.queue_with_public_branch,
- self.queue1_with_private_branch,
- self.queue2_with_private_branch]),
- sorted(self.all_queues.getMergeQueues()))
-
- def test_anonymous_sees_only_public(self):
- # Anonymous users can see only queues with public branches.
- queues = self.all_queues.visibleByUser(None)
- self.assertEqual([self.queue_with_public_branch],
- list(queues.getMergeQueues()))
-
- def test_random_person_sees_only_public(self):
- # Logged in users with no special permissions can see only queues with
- # public branches.
- person = self.factory.makePerson()
- queues = self.all_queues.visibleByUser(person)
- self.assertEqual([self.queue_with_public_branch],
- list(queues.getMergeQueues()))
-
- def test_owner_sees_own_branches(self):
- # Users can always see the queues with branches that they own, as well
- # as queues with public branches.
- queues = self.all_queues.visibleByUser(self.private_branch1_owner)
- self.assertEqual(
- sorted([self.queue_with_public_branch,
- self.queue1_with_private_branch]),
- sorted(queues.getMergeQueues()))
-
- def test_owner_member_sees_own_queues(self):
- # Members of teams that own queues can see queues owned by those
- # teams, as well as public branches.
- team_owner = self.factory.makePerson()
- team = self.factory.makeTeam(team_owner)
- private_branch = self.factory.makeAnyBranch(
- owner=team, name='team',
- information_type=InformationType.USERDATA)
- queue_with_private_branch = self.factory.makeBranchMergeQueue(
- branches=[removeSecurityProxy(private_branch)])
- queues = self.all_queues.visibleByUser(team_owner)
- self.assertEqual(
- sorted([self.queue_with_public_branch,
- queue_with_private_branch]),
- sorted(queues.getMergeQueues()))
-
- def test_launchpad_services_sees_all(self):
- # The LAUNCHPAD_SERVICES special user sees *everything*.
- queues = self.all_queues.visibleByUser(LAUNCHPAD_SERVICES)
- self.assertEqual(
- sorted(self.all_queues.getMergeQueues()),
- sorted(queues.getMergeQueues()))
-
- def test_admins_see_all(self):
- # Launchpad administrators see *everything*.
- admin = self.factory.makePerson()
- admin_team = removeSecurityProxy(
- getUtility(ILaunchpadCelebrities).admin)
- admin_team.addMember(admin, admin_team.teamowner)
- queues = self.all_queues.visibleByUser(admin)
- self.assertEqual(
- sorted(self.all_queues.getMergeQueues()),
- sorted(queues.getMergeQueues()))
=== modified file 'lib/lp/code/stories/webservice/xx-branch.txt'
--- lib/lp/code/stories/webservice/xx-branch.txt 2015-01-29 16:28:30 +0000
+++ lib/lp/code/stories/webservice/xx-branch.txt 2015-04-19 14:40:56 +0000
@@ -125,8 +125,6 @@
last_scanned_id: None
lifecycle_status: u'Development'
linked_bugs_collection_link: u'http://.../~eric/fooix/trunk/linked_bugs'
- merge_queue_config: None
- merge_queue_link: None
mirror_status_message: None
name: u'trunk'
owner_link: u'.../~eric'
=== modified file 'lib/lp/code/stories/webservice/xx-branchmergeproposal.txt'
--- lib/lp/code/stories/webservice/xx-branchmergeproposal.txt 2015-01-29 16:28:30 +0000
+++ lib/lp/code/stories/webservice/xx-branchmergeproposal.txt 2015-04-19 14:40:56 +0000
@@ -50,7 +50,6 @@
commit_message: u'It was merged!\n'
date_created: u'...'
date_merged: None
- date_queued: None
date_review_requested: u'...'
date_reviewed: None
description: u'Merge\nit!'
@@ -60,10 +59,7 @@
preview_diff_link: None
preview_diffs_collection_link: u'http://.../preview_diffs'
private: False
- queue_position: None
queue_status: u'Needs review'
- queued_revid: None
- queuer_link: None
registrant_link: u'http://api.launchpad.dev/devel/~person-name...'
resource_type_link:
u'http://api.launchpad.dev/devel/#branch_merge_proposal'
@@ -149,7 +145,6 @@
commit_message: None
date_created: ...
date_merged: None
- date_queued: None
date_review_requested: None
date_reviewed: None
description: None
@@ -159,10 +154,7 @@
preview_diff_link: None
preview_diffs_collection_link: u'http://.../preview_diffs'
private: False
- queue_position: None
queue_status: u'Work in progress'
- queued_revid: None
- queuer_link: None
registrant_link: u'http://.../~person-name...'
resource_type_link: u'http://.../#branch_merge_proposal'
reviewed_revid: None
=== modified file 'lib/lp/code/templates/branch-pending-merges.pt'
--- lib/lp/code/templates/branch-pending-merges.pt 2010-10-28 03:24:26 +0000
+++ lib/lp/code/templates/branch-pending-merges.pt 2015-04-19 14:40:56 +0000
@@ -48,18 +48,6 @@
tal:condition="link/enabled"
tal:replace="structure link/render"
/>
-
- <div tal:condition="features/code.branchmergequeue">
- <div tal:condition="not: context/merge_queue">
- <h4>Merge Queue</h4>
- This branch is not managed by a queue.
- <div
- tal:define="link context_menu/create_queue"
- tal:condition="link/enabled"
- tal:content="structure link/render"
- />
- </div>
- </div>
</div>
</div>
=== modified file 'lib/lp/code/templates/branchmergeproposal-pagelet-summary.pt'
--- lib/lp/code/templates/branchmergeproposal-pagelet-summary.pt 2012-06-28 14:19:28 +0000
+++ lib/lp/code/templates/branchmergeproposal-pagelet-summary.pt 2015-04-19 14:40:56 +0000
@@ -77,24 +77,6 @@
</tr>
</tal:reviewed>
</tal:not-superseded>
- <tal:queued condition="context/queue_status/enumvalue:QUEUED">
- <tr id="summary-row-4-queued-by">
- <th>Queued by:</th>
- <td tal:content="structure context/queuer/fmt:link">Some User</td>
- </tr>
- <tr id="summary-row-5-queued-revision">
- <th>Queued revision:</th>
- <td>
- <tal:not-available condition="not: context/queued_revision_id">
- not available
- </tal:not-available>
- <tal:revision condition="context/queued_revision_id"
- content="view/queued_revision_number">
- 1234
- </tal:revision>
- </td>
- </tr>
- </tal:queued>
<tal:merged condition="context/queue_status/enumvalue:MERGED">
<tr id="summary-row-6-merge-reporter"
tal:condition="context/merge_reporter">
=== removed file 'lib/lp/code/templates/branchmergequeue-index.pt'
--- lib/lp/code/templates/branchmergequeue-index.pt 2010-10-26 02:28:39 +0000
+++ lib/lp/code/templates/branchmergequeue-index.pt 1970-01-01 00:00:00 +0000
@@ -1,39 +0,0 @@
-<html
- xmlns="http://www.w3.org/1999/xhtml"
- xmlns:tal="http://xml.zope.org/namespaces/tal"
- xmlns:metal="http://xml.zope.org/namespaces/metal"
- xmlns:i18n="http://xml.zope.org/namespaces/i18n"
- metal:use-macro="view/macro:page/main_side"
- i18n:domain="launchpad"
->
-
-<metal:side fill-slot="side">
- <div tal:replace="structure context/@@+global-actions" />
-</metal:side>
-
-<tal:registering metal:fill-slot="registering">
- Created by
- <tal:registrant replace="structure context/registrant/fmt:link" />
- on
- <tal:created-on replace="structure context/date_created/fmt:date" />
-</tal:registering>
-
-<div metal:fill-slot="main">
- <dl>
- <dt>
- Description
- </dt>
- <dd tal:content="context/description"></dd>
- </dl>
- <div tal:condition="context/branches">
- The following branches are managed by this queue:
- <ul>
- <tal:branches repeat="branch context/branches">
- <li>
- <a tal:content="structure branch/fmt:link" />
- </li>
- </tal:branches>
- </ul>
- </div>
-</div>
-</html>
=== removed file 'lib/lp/code/templates/branchmergequeue-listing.pt'
--- lib/lp/code/templates/branchmergequeue-listing.pt 2011-02-17 04:08:14 +0000
+++ lib/lp/code/templates/branchmergequeue-listing.pt 1970-01-01 00:00:00 +0000
@@ -1,68 +0,0 @@
-<html
- xmlns="http://www.w3.org/1999/xhtml"
- xmlns:tal="http://xml.zope.org/namespaces/tal"
- xmlns:metal="http://xml.zope.org/namespaces/metal"
- xmlns:i18n="http://xml.zope.org/namespaces/i18n"
- metal:use-macro="view/macro:page/main_only"
- i18n:domain="launchpad">
-
-<body>
-
- <div metal:fill-slot="main">
-
- <div tal:condition="not: request/features/code.branchmergequeue">
- <em>
- No merge queues
- </em>
- </div>
-
- <div tal:condition="request/features/code.branchmergequeue">
-
- <tal:has-queues condition="view/mergequeue_count">
-
- <table id="mergequeuetable" class="listing sortable">
- <thead>
- <tr>
- <th colspan="2">Name</th>
- <th tal:condition="view/owner_enabled">Owner</th>
- <th>Queue Size</th>
- <th>Associated Branches</th>
- </tr>
- </thead>
- <tbody>
- <tal:mergequeues repeat="mergeQueue view/mergequeues">
- <tr>
- <td colspan="2">
- <a tal:attributes="href mergeQueue/fmt:url"
- tal:content="mergeQueue/name">Merge queue name</a>
- </td>
- <td tal:condition="view/owner_enabled">
- <a tal:replace="structure mergeQueue/owner/fmt:link">
- Owner
- </a>
- </td>
- <td>4</td>
- <td>
- <metal:display-branches
- use-macro="context/@@+bmq-macros/merge_queue_branches"/>
- </td>
- </tr>
- </tal:mergequeues>
- </tbody>
- </table>
-
- </tal:has-queues>
-
- <em id="no-queues"
- tal:condition="not: view/mergequeue_count"
- tal:content="view/no_merge_queue_message">
- No merge queues
- </em>
-
- </div>
-
- </div>
-
-</body>
-</html>
-
=== removed file 'lib/lp/code/templates/branchmergequeue-macros.pt'
--- lib/lp/code/templates/branchmergequeue-macros.pt 2010-11-01 12:35:07 +0000
+++ lib/lp/code/templates/branchmergequeue-macros.pt 1970-01-01 00:00:00 +0000
@@ -1,20 +0,0 @@
- <tal:root
- xmlns:tal="http://xml.zope.org/namespaces/tal"
- xmlns:metal="http://xml.zope.org/namespaces/metal"
- omit-tag="">
-
-<metal:merge_queue_branches define-macro="merge_queue_branches">
- <table class="listing">
- <tbody>
- <tal:mergequeue-branches repeat="branch mergeQueue/branches">
- <tr>
- <td>
- <a tal:attributes="href branch/fmt:url"
- tal:content="branch/name">Branch name</a>
- </td>
- </tr>
- </tal:mergequeue-branches>
- </tbody>
- </table>
-</metal:merge_queue_branches>
-</tal:root>
\ No newline at end of file
=== modified file 'lib/lp/code/templates/person-codesummary.pt'
--- lib/lp/code/templates/person-codesummary.pt 2014-12-06 12:53:32 +0000
+++ lib/lp/code/templates/person-codesummary.pt 2015-04-19 14:40:56 +0000
@@ -14,11 +14,6 @@
tal:condition="menu/active_reviews/enabled">
<td tal:content="structure menu/active_reviews/render" />
</tr>
- <tr tal:condition="features/code.branchmergequeue" id="mergequeue-counts">
- <td class="code-count" tal:content="menu/mergequeue_count">5</td>
- <td tal:condition="menu"
- tal:content="structure menu/mergequeues/render" />
- </tr>
<tr class="code-links" tal:condition="menu/source_package_recipes/enabled">
<td tal:content="structure menu/source_package_recipes/render" />
</tr>
=== modified file 'lib/lp/registry/browser/person.py'
--- lib/lp/registry/browser/person.py 2015-03-30 14:47:22 +0000
+++ lib/lp/registry/browser/person.py 2015-04-19 14:40:56 +0000
@@ -584,11 +584,6 @@
"""Traverse to this person's recipes."""
return self.context.getRecipe(name)
- @stepthrough('+merge-queues')
- def traverse_merge_queue(self, name):
- """Traverse to this person's merge queues."""
- return self.context.getMergeQueue(name)
-
@stepthrough('+livefs')
def traverse_livefs(self, distribution_name):
"""Traverse to this person's live filesystem images."""
=== modified file 'lib/lp/registry/interfaces/person.py'
--- lib/lp/registry/interfaces/person.py 2015-03-10 11:38:21 +0000
+++ lib/lp/registry/interfaces/person.py 2015-04-19 14:40:56 +0000
@@ -1031,9 +1031,6 @@
def getRecipe(name):
"""Return the person's recipe with the given name."""
- def getMergeQueue(name):
- """Return the person's merge queue with the given name."""
-
@call_with(requester=REQUEST_USER)
@export_read_operation()
@operation_returns_collection_of(Interface) # Really IArchiveSubscriber
=== modified file 'lib/lp/registry/model/person.py'
--- lib/lp/registry/model/person.py 2015-04-15 18:34:25 +0000
+++ lib/lp/registry/model/person.py 2015-04-19 14:40:56 +0000
@@ -2964,13 +2964,6 @@
SourcePackageRecipe, SourcePackageRecipe.owner == self,
SourcePackageRecipe.name == name).one()
- def getMergeQueue(self, name):
- from lp.code.model.branchmergequeue import BranchMergeQueue
- return Store.of(self).find(
- BranchMergeQueue,
- BranchMergeQueue.owner == self,
- BranchMergeQueue.name == unicode(name)).one()
-
@cachedproperty
def is_ubuntu_coc_signer(self):
"""See `IPerson`."""
=== modified file 'lib/lp/registry/personmerge.py'
--- lib/lp/registry/personmerge.py 2015-04-16 22:56:36 +0000
+++ lib/lp/registry/personmerge.py 2015-04-19 14:40:56 +0000
@@ -147,12 +147,6 @@
removeSecurityProxy(branch).setOwner(to_person, to_person)
-def _mergeBranchMergeQueues(cur, from_id, to_id):
- cur.execute('''
- UPDATE BranchMergeQueue SET owner = %(to_id)s WHERE owner =
- %(from_id)s''', dict(to_id=to_id, from_id=from_id))
-
-
def _mergeGitRepositories(from_person, to_person):
# This shouldn't use removeSecurityProxy.
repositories = getUtility(IGitCollection).ownedBy(from_person)
@@ -717,6 +711,8 @@
('bugsummaryjournal', 'viewed_by'),
('latestpersonsourcepackagereleasecache', 'creator'),
('latestpersonsourcepackagereleasecache', 'maintainer'),
+ # Obsolete table.
+ ('branchmergequeue', 'owner'),
]
references = list(postgresql.listReferences(cur, 'person', 'id'))
@@ -764,9 +760,6 @@
_mergeBranches(from_person, to_person)
skip.append(('branch', 'owner'))
- _mergeBranchMergeQueues(cur, from_id, to_id)
- skip.append(('branchmergequeue', 'owner'))
-
# Update the GitRepositories that will not conflict, and fudge the names
# of ones that *do* conflict.
_mergeGitRepositories(from_person, to_person)
=== modified file 'lib/lp/security.py'
--- lib/lp/security.py 2015-03-17 13:14:36 +0000
+++ lib/lp/security.py 2015-04-19 14:40:56 +0000
@@ -70,7 +70,6 @@
IBranchCollection,
)
from lp.code.interfaces.branchmergeproposal import IBranchMergeProposal
-from lp.code.interfaces.branchmergequeue import IBranchMergeQueue
from lp.code.interfaces.codeimport import ICodeImport
from lp.code.interfaces.codeimportjob import (
ICodeImportJobSet,
@@ -1522,18 +1521,6 @@
return user.in_buildd_admin
-class EditBranchMergeQueue(AuthorizationBase):
- """Control who can edit a BranchMergeQueue.
-
- Access is granted only to the owner of the queue.
- """
- permission = 'launchpad.Edit'
- usedfor = IBranchMergeQueue
-
- def checkAuthenticated(self, user):
- return user.isOwner(self.obj)
-
-
class AdminDistributionTranslations(AuthorizationBase):
"""Class for deciding who can administer distribution translations.
=== modified file 'lib/lp/services/features/flags.py'
--- lib/lp/services/features/flags.py 2015-03-04 18:27:40 +0000
+++ lib/lp/services/features/flags.py 2015-04-19 14:40:56 +0000
@@ -88,12 +88,6 @@
'',
'',
''),
- ('code.branchmergequeue',
- 'boolean',
- 'Enables merge queue pages and lists them on branch pages.',
- '',
- '',
- ''),
('code.incremental_diffs.enabled',
'boolean',
'Shows incremental diffs on merge proposals.',
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2015-04-16 23:58:46 +0000
+++ lib/lp/testing/factory.py 2015-04-19 14:40:56 +0000
@@ -50,7 +50,6 @@
from lazr.jobrunner.jobrunner import SuspendJobException
import pytz
from pytz import UTC
-import simplejson
from twisted.python.util import mergeFunctionMetadata
from zope.component import (
ComponentLookupError,
@@ -112,7 +111,6 @@
RevisionControlSystems,
)
from lp.code.errors import UnknownBranchTypeError
-from lp.code.interfaces.branchmergequeue import IBranchMergeQueueSource
from lp.code.interfaces.branchnamespace import get_branch_namespace
from lp.code.interfaces.branchtarget import IBranchTarget
from lp.code.interfaces.codeimport import ICodeImportSet
@@ -1227,26 +1225,6 @@
namespace = target.getNamespace(owner)
return namespace.createBranch(branch_type, name, creator)
- def makeBranchMergeQueue(self, registrant=None, owner=None, name=None,
- description=None, configuration=None,
- branches=None):
- """Create a BranchMergeQueue."""
- if name is None:
- name = unicode(self.getUniqueString('queue'))
- if owner is None:
- owner = self.makePerson()
- if registrant is None:
- registrant = self.makePerson()
- if description is None:
- description = unicode(self.getUniqueString('queue-description'))
- if configuration is None:
- configuration = unicode(simplejson.dumps({
- self.getUniqueString('key'): self.getUniqueString('value')}))
-
- queue = getUtility(IBranchMergeQueueSource).new(
- name, owner, registrant, description, configuration, branches)
- return queue
-
def makeRelatedBranchesForSourcePackage(self, sourcepackage=None,
**kwargs):
"""Create some branches associated with a sourcepackage."""
@@ -1492,13 +1470,6 @@
proposal.target_branch.owner, 'some_revision')
elif set_state == BranchMergeProposalStatus.MERGED:
unsafe_proposal.markAsMerged()
- elif set_state == BranchMergeProposalStatus.MERGE_FAILED:
- unsafe_proposal.setStatus(set_state, proposal.target_branch.owner)
- elif set_state == BranchMergeProposalStatus.QUEUED:
- unsafe_proposal.commit_message = self.getUniqueString(
- 'commit message')
- unsafe_proposal.enqueue(
- proposal.target_branch.owner, 'some_revision')
elif set_state == BranchMergeProposalStatus.SUPERSEDED:
unsafe_proposal.resubmit(proposal.registrant)
else:
Follow ups