← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~abentley/launchpad/remove-create-merge-proposal-job into lp:launchpad

 

Aaron Bentley has proposed merging lp:~abentley/launchpad/remove-create-merge-proposal-job into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #989831 in Launchpad itself: "CreateMergeProposalJobs are dead code"
  https://bugs.launchpad.net/launchpad/+bug/989831

For more details, see:
https://code.launchpad.net/~abentley/launchpad/remove-create-merge-proposal-job/+merge/103929

= Summary =
Fix bug #989831: CreateMergeProposalJobs are dead code

== Proposed fix ==
Remove CreateMergeProposalJobs

== Pre-implementation notes ==
Discussed with deryck.  We determined that this feature has not been used at all in 2012, and less than 100 times in 2011.

== LOC Rationale ==
Reduces LOC

== Implementation details ==
Deletion.  Lots and lots of deletion.  (And mostly my own hard work, too!)

== Tests ==
bin/test -v test_codehandler

== Demo and Q/A ==
Send an email to merge@code.*.launchpad.net.  You should get an email back saying merge directives are no longer supported.


= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/code/configure.zcml
  lib/lp/services/config/schema-lazr.conf
  lib/lp/code/interfaces/branchmergeproposal.py
  lib/lp/code/mail/codehandler.py
  lib/lp/code/model/tests/test_branchmergeproposal.py
  lib/lp/code/mail/tests/test_codehandler.py
  lib/lp/services/messages/model/message.py
  lib/lp/services/mail/errortemplates/mergedirectivenotsupported.txt
  lib/lp/testing/factory.py
  lib/lp/services/messages/interfaces/message.py
  lib/lp/code/model/branchmergeproposaljob.py
  configs/testrunner/launchpad-lazr.conf
  lib/lp/services/messages/tests/test_message.py

./lib/lp/services/config/schema-lazr.conf
     489: Line exceeds 80 characters.
    1100: Line exceeds 80 characters.
    1107: Line exceeds 80 characters.
    1699: Line exceeds 80 characters.
./lib/lp/services/mail/errortemplates/mergedirectivenotsupported.txt
       1: Line exceeds 80 characters.
       3: Line exceeds 80 characters.
./configs/testrunner/launchpad-lazr.conf
     126: Line exceeds 80 characters.
-- 
https://code.launchpad.net/~abentley/launchpad/remove-create-merge-proposal-job/+merge/103929
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~abentley/launchpad/remove-create-merge-proposal-job into lp:launchpad.
=== modified file 'configs/testrunner/launchpad-lazr.conf'
--- configs/testrunner/launchpad-lazr.conf	2012-01-18 01:46:02 +0000
+++ configs/testrunner/launchpad-lazr.conf	2012-04-27 19:10:25 +0000
@@ -30,10 +30,6 @@
 access_log: /tmp/test-codehosting-access.log
 internal_branch_by_id_root: file:///var/tmp/bazaar.launchpad.dev/mirrors
 
-[create_merge_proposals]
-oops_prefix: TMPCJ
-error_dir: /var/tmp/codehosting.test
-
 [database]
 rw_main_master: dbname=launchpad_ftest host=localhost
 rw_main_slave:  dbname=launchpad_ftest host=localhost

=== removed file 'cronscripts/create_merge_proposals.py'
--- cronscripts/create_merge_proposals.py	2012-01-01 03:14:54 +0000
+++ cronscripts/create_merge_proposals.py	1970-01-01 00:00:00 +0000
@@ -1,40 +0,0 @@
-#!/usr/bin/python -S
-#
-# Copyright 2009 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-# pylint: disable-msg=W0403
-
-"""Create BranchMergeProposals from email."""
-
-__metaclass__ = type
-
-import _pythonpath
-
-from zope.component import getUtility
-
-from lp.code.interfaces.branchmergeproposal import (
-    ICreateMergeProposalJobSource,
-    )
-from lp.services.config import config
-from lp.services.job.runner import JobRunner
-from lp.services.scripts.base import LaunchpadCronScript
-from lp.services.webapp.errorlog import globalErrorUtility
-
-
-class RunCreateMergeProposalJobs(LaunchpadCronScript):
-    """Run create merge proposal jobs."""
-
-    def main(self):
-        globalErrorUtility.configure('create_merge_proposals')
-        job_source = getUtility(ICreateMergeProposalJobSource)
-        runner = JobRunner.fromReady(job_source, self.logger)
-        runner.runAll()
-        self.logger.info(
-            'Ran %d CreateMergeProposalJobs.' % len(runner.completed_jobs))
-
-
-if __name__ == '__main__':
-    script = RunCreateMergeProposalJobs(
-        'create_merge_proposals', config.create_merge_proposals.dbuser)
-    script.lock_and_run()

=== modified file 'lib/lp/code/configure.zcml'
--- lib/lp/code/configure.zcml	2012-04-24 06:00:11 +0000
+++ lib/lp/code/configure.zcml	2012-04-27 19:10:25 +0000
@@ -289,16 +289,6 @@
 
   <!-- Branch Merge Proposal Jobs -->
 
-  <class class="lp.code.model.branchmergeproposaljob.CreateMergeProposalJob">
-    <allow interface="lp.services.messages.interfaces.message.IMessageJob"/>
-    <allow interface="lp.code.interfaces.branchmergeproposal.ICreateMergeProposalJob"/>
-  </class>
-  <securedutility
-      component="lp.code.model.branchmergeproposaljob.CreateMergeProposalJob"
-      provides="lp.code.interfaces.branchmergeproposal.ICreateMergeProposalJobSource">
-    <allow interface="lp.code.interfaces.branchmergeproposal.ICreateMergeProposalJobSource"/>
-  </securedutility>
-
   <class class="lp.code.model.branchmergeproposaljob.MergeProposalNeedsReviewEmailJob">
     <allow interface="lp.code.interfaces.branchmergeproposal.IBranchMergeProposalJob"/>
     <allow interface="lp.code.interfaces.branchmergeproposal.IMergeProposalNeedsReviewEmailJob"/>

=== modified file 'lib/lp/code/interfaces/branchmergeproposal.py'
--- lib/lp/code/interfaces/branchmergeproposal.py	2011-12-30 06:14:56 +0000
+++ lib/lp/code/interfaces/branchmergeproposal.py	2012-04-27 19:10:25 +0000
@@ -15,8 +15,6 @@
     'IBranchMergeProposalListingBatchNavigator',
     'ICodeReviewCommentEmailJob',
     'ICodeReviewCommentEmailJobSource',
-    'ICreateMergeProposalJob',
-    'ICreateMergeProposalJobSource',
     'IGenerateIncrementalDiffJob',
     'IGenerateIncrementalDiffJobSource',
     'IMergeProposalNeedsReviewEmailJob',
@@ -641,20 +639,6 @@
     IBranchMergeProposal[name].schema = IBranchMergeProposal
 
 
-class ICreateMergeProposalJob(IRunnableJob):
-    """A Job that creates a branch merge proposal.
-
-    It uses a Message, which must contain a merge directive.
-    """
-
-
-class ICreateMergeProposalJobSource(IJobSource):
-    """Acquire MergeProposalJobs."""
-
-    def create(message_bytes):
-        """Return a CreateMergeProposalJob for this message."""
-
-
 class IMergeProposalNeedsReviewEmailJob(IRunnableJob):
     """Email about a merge proposal needing a review.."""
 

=== modified file 'lib/lp/code/mail/codehandler.py'
--- lib/lp/code/mail/codehandler.py	2012-01-01 02:58:52 +0000
+++ lib/lp/code/mail/codehandler.py	2012-04-27 19:10:25 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2012 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 __metaclass__ = type
@@ -8,44 +8,22 @@
 import os
 import re
 
-from bzrlib.branch import Branch
-from bzrlib.errors import (
-    NotAMergeDirective,
-    NotBranchError,
-    NotStacked,
-    )
-from bzrlib.merge_directive import MergeDirective
-from bzrlib.transport import get_transport
-from bzrlib.urlutils import join as urljoin
-from lazr.uri import URI
 from sqlobject import SQLObjectNotFound
 import transaction
 from zope.component import getUtility
 from zope.interface import implements
 from zope.security.interfaces import Unauthorized
 
-from lp.code.bzr import get_branch_formats
 from lp.code.enums import (
-    BranchType,
     CodeReviewVote,
     )
 from lp.code.errors import (
-    BranchCreationException,
-    BranchMergeProposalExists,
     UserNotBranchReviewer,
     )
-from lp.code.interfaces.branchlookup import IBranchLookup
 from lp.code.interfaces.branchmergeproposal import (
     IBranchMergeProposalGetter,
-    ICreateMergeProposalJobSource,
-    )
-from lp.code.interfaces.branchnamespace import (
-    lookup_branch_namespace,
-    split_unique_name,
-    )
-from lp.code.interfaces.branchtarget import check_default_stacked_on
-from lp.codehosting.bzrutils import is_branch_stackable
-from lp.codehosting.vfs import get_lp_server
+    )
+from lp.services.config import config
 from lp.services.mail.commands import (
     EmailCommand,
     EmailCommandCollection,
@@ -65,8 +43,6 @@
 from lp.services.mail.notification import send_process_error_notification
 from lp.services.mail.sendmail import simple_sendmail
 from lp.services.messages.interfaces.message import IMessageSet
-from lp.services.webapp import urlparse
-from lp.services.webapp.errorlog import globalErrorUtility
 from lp.services.webapp.interfaces import ILaunchBag
 
 
@@ -89,14 +65,6 @@
     """The user-supplied vote is not an acceptable value."""
 
 
-class NonLaunchpadTarget(Exception):
-    """Target branch is not registered with Launchpad."""
-
-
-class MissingMergeDirective(Exception):
-    """Emailed merge proposal lacks a merge directive"""
-
-
 class CodeReviewEmailCommandExecutionContext:
     """Passed as the only parameter to each code review email command.
 
@@ -283,7 +251,10 @@
         deferred to jobs to create BranchMergeProposals.
         """
         if email_addr.startswith('merge@'):
-            return self.createMergeProposalJob(mail, email_addr, file_alias)
+            body = get_error_message('mergedirectivenotsupported.txt')
+            simple_sendmail(
+                config.canonical.noreply_from_address, [mail.get('from')],
+                'Merge directive not supported.', body)
         else:
             try:
                 return self.processComment(mail, email_addr, file_alias)
@@ -294,23 +265,6 @@
                     'Error Creating Merge Proposal', body)
                 return True
 
-    def createMergeProposalJob(self, mail, email_addr, file_alias):
-        """Check that the message is signed and create the job."""
-        try:
-            ensure_not_weakly_authenticated(
-                mail, email_addr, 'not-signed-md.txt',
-                'key-not-registered-md.txt', error_templates)
-        except IncomingEmailError, error:
-            user = getUtility(ILaunchBag).user
-            send_process_error_notification(
-                str(user.preferredemail.email),
-                'Submit Request Failure',
-                error.message, mail, error.failing_command)
-            transaction.abort()
-        else:
-            getUtility(ICreateMergeProposalJobSource).create(file_alias)
-        return True
-
     def processCommands(self, context, commands):
         """Process the various merge proposal commands against the context."""
         processing_errors = []
@@ -401,292 +355,3 @@
             return getter.get(merge_proposal_id)
         except SQLObjectNotFound:
             raise NonExistantBranchMergeProposalAddress(email_addr)
-
-    def _acquireBranchesForProposal(self, md, submitter):
-        """Find or create DB Branches from a MergeDirective.
-
-        If the target is not a Launchpad branch, NonLaunchpadTarget will be
-        raised.  If the source is not a Launchpad branch, a REMOTE branch will
-        be created implicitly, with submitter as its owner/registrant.
-
-        :param md: The `MergeDirective` to get branch URLs from.
-        :param submitter: The `Person` who requested that the merge be
-            performed.
-        :return: source_branch, target_branch
-        """
-        mp_target = getUtility(IBranchLookup).getByUrl(md.target_branch)
-        if mp_target is None:
-            raise NonLaunchpadTarget()
-        # If the target branch cannot be stacked upon, then don't try to stack
-        # upon it or get revisions form it.
-        if md.bundle is None or check_default_stacked_on(mp_target) is None:
-            mp_source = self._getSourceNoBundle(
-                md, mp_target, submitter)
-        else:
-            mp_source = self._getSourceWithBundle(
-                md, mp_target, submitter)
-        return mp_source, mp_target
-
-    @staticmethod
-    def _getNewBranchInfo(url, target_branch, submitter):
-        """Return the namespace and basename for a branch.
-
-        If an LP URL is provided, the namespace and basename will match the
-        LP URL.
-
-        Otherwise, the target is used to determine the namespace, and the base
-        depends on what was supplied.
-
-        If a URL is supplied, its base is used.
-
-        If no URL is supplied, 'merge' is used as the base.
-
-        :param url: The public URL of the source branch, if any.
-        :param target_branch: The target branch.
-        :param submitter: The person submitting the merge proposal.
-        """
-        if url is not None:
-            url = url.rstrip('/')
-            branches = getUtility(IBranchLookup)
-            unique_name = branches.uriToUniqueName(URI(url))
-            if unique_name is not None:
-                namespace_name, base = split_unique_name(unique_name)
-                return lookup_branch_namespace(namespace_name), base
-        if url is None:
-            basename = 'merge'
-        else:
-            basename = urlparse(url)[2].split('/')[-1]
-        namespace = target_branch.target.getNamespace(submitter)
-        return namespace, basename
-
-    def _getNewBranch(self, branch_type, url, target, submitter):
-        """Return a new database branch.
-
-        :param branch_type: The type of branch to create.
-        :param url: The public location of the branch to create.
-        :param product: The product associated with the branch to create.
-        :param submitter: The person who requested the merge.
-        """
-        namespace, basename = self._getNewBranchInfo(url, target, submitter)
-        if branch_type == BranchType.REMOTE:
-            db_url = url
-        else:
-            db_url = None
-        return namespace.createBranchWithPrefix(
-            branch_type, basename, submitter, url=db_url)
-
-    def _getSourceNoBundle(self, md, target, submitter):
-        """Get a source branch for a merge directive with no bundle."""
-        source_db_branch = getUtility(IBranchLookup).getByUrl(
-            md.source_branch)
-        if source_db_branch is None:
-            source_db_branch = self._getNewBranch(
-                BranchType.REMOTE, md.source_branch, target, submitter)
-        return source_db_branch
-
-    def _getOrCreateDBBranch(self, md, db_target, submitter):
-        """Return the source branch, creating a new branch if necessary."""
-        db_source = None
-        if md.source_branch is not None:
-            db_source = getUtility(IBranchLookup).getByUrl(md.source_branch)
-        if db_source is None:
-            db_source = self._getNewBranch(
-                BranchType.HOSTED, md.source_branch, db_target, submitter)
-            # Commit the transaction to make sure the new source branch is
-            # visible to the XMLRPC server which provides the virtual file
-            # system information.
-            transaction.commit()
-        return db_source
-
-    def _openSourceBzrBranch(self, source_url, target_url, stacked_url):
-        """Open the source bzr branch, creating a new branch if necessary."""
-        try:
-            return Branch.open(source_url)
-        except NotBranchError:
-            bzr_target = Branch.open(target_url)
-            transport = get_transport(
-                source_url,
-                possible_transports=[bzr_target.bzrdir.root_transport])
-            bzrdir = bzr_target.bzrdir.sprout(
-                transport.base, bzr_target.last_revision(),
-                force_new_repo=True, stacked=True, create_tree_if_local=False,
-                possible_transports=[transport], source_branch=bzr_target)
-            bzr_branch = bzrdir.open_branch()
-            # Set the stacked url to be the relative url for the target.
-            bzr_branch.set_stacked_on_url(stacked_url)
-            return bzr_branch
-
-    def _getSourceWithBundle(self, md, db_target, submitter):
-        """Get a source branch for a merge directive with a bundle."""
-        db_source = self._getOrCreateDBBranch(md, db_target, submitter)
-        # Make sure that the target branch is stackable so that we only
-        # install the revisions unique to the source branch. If the target
-        # branch is not stackable, return the existing branch or a new hosted
-        # source branch - one that has *no* Bazaar data.  Together these
-        # prevent users from using Launchpad disk space at a rate that is
-        # disproportionately greater than data uploaded.
-        mirrored_bzr_target = db_target.getBzrBranch()
-        if not is_branch_stackable(mirrored_bzr_target):
-            return db_source
-        assert db_source.branch_type == BranchType.HOSTED, (
-            "Source branch is not hosted.")
-
-        # Create the LP server as if the submitter was pushing a branch to LP.
-        lp_server = get_lp_server(submitter.id)
-        lp_server.start_server()
-        try:
-            source_url = urljoin(lp_server.get_url(), db_source.unique_name)
-            target_url = urljoin(lp_server.get_url(), db_target.unique_name)
-            stacked_url = '/' + db_target.unique_name
-            bzr_source = self._openSourceBzrBranch(
-                source_url, target_url, stacked_url)
-            if is_branch_stackable(bzr_source):
-                # Set the stacked on URL if not set.
-                try:
-                    bzr_source.get_stacked_on_url()
-                except NotStacked:
-                    # We don't currently support pulling in the revisions if
-                    # the source branch exists and isn't stacked.
-                    # XXX Tim Penhey 2010-07-27 bug 610292
-                    # We should fail here and return an oops email to the
-                    # user.
-                    return db_source
-                self._pullRevisionsFromMergeDirectiveIntoSourceBranch(
-                    md, target_url, bzr_source)
-                # Get the puller to pull the branch into the mirrored area.
-                formats = get_branch_formats(bzr_source)
-                db_source.branchChanged(
-                    stacked_url, bzr_source.last_revision(), *formats)
-            return db_source
-        finally:
-            lp_server.stop_server()
-
-    def _pullRevisionsFromMergeDirectiveIntoSourceBranch(self, md,
-                                                         target_url,
-                                                         bzr_branch):
-        """Pull the revisions from the merge directive into the branch.
-
-        :param md: The merge directive
-        :param target_url: The URL of the branch that the merge directive is
-            targetting using the user's LP transport.
-        :param bzr_branch: The bazaar branch entity for the branch that the
-            revisions from the merge directive are being pulled into.
-        """
-        # Tell the merge directive to use the user's LP transport URL to get
-        # access to any needed but not supplied revisions.
-        md.target_branch = target_url
-        md.install_revisions(bzr_branch.repository)
-        bzr_branch.lock_write()
-        try:
-            bzr_branch.pull(bzr_branch, stop_revision=md.revision_id,
-                            overwrite=True)
-        finally:
-            bzr_branch.unlock()
-
-    def findMergeDirectiveAndComment(self, message):
-        """Extract the comment and Merge Directive from a SignedMessage."""
-        body = None
-        md = None
-        for part in message.walk():
-            if part.is_multipart():
-                continue
-            payload = part.get_payload(decode=True)
-            content_type = part.get('Content-type', 'text/plain').lower()
-            if content_type.startswith('text/plain'):
-                body = payload
-                charset = part.get_param('charset')
-                if charset is not None:
-                    body = body.decode(charset)
-            try:
-                md = MergeDirective.from_lines(payload.splitlines(True))
-            except NotAMergeDirective:
-                pass
-            if None not in (body, md):
-                return body, md
-        else:
-            raise MissingMergeDirective()
-
-    def processMergeProposal(self, message):
-        """Generate a merge proposal (and comment) from an email message.
-
-        The message is expected to contain a merge directive in one of its
-        parts.  Its values are used to generate a BranchMergeProposal.
-        If the message has a non-empty body, it is turned into a
-        CodeReviewComment.
-        """
-        submitter = getUtility(ILaunchBag).user
-        try:
-            email_body_text, md = self.findMergeDirectiveAndComment(message)
-        except MissingMergeDirective:
-            body = get_error_message(
-                'missingmergedirective.txt',
-                error_templates=error_templates)
-            simple_sendmail('merge@xxxxxxxxxxxxxxxxxx',
-                [message.get('from')],
-                'Error Creating Merge Proposal', body)
-            return
-        oops_message = (
-            'target: %r source: %r' %
-            (md.target_branch, md.source_branch))
-        with globalErrorUtility.oopsMessage(oops_message):
-            try:
-                source, target = self._acquireBranchesForProposal(
-                    md, submitter)
-            except NonLaunchpadTarget:
-                body = get_error_message('nonlaunchpadtarget.txt',
-                    error_templates=error_templates,
-                    target_branch=md.target_branch)
-                simple_sendmail('merge@xxxxxxxxxxxxxxxxxx',
-                    [message.get('from')],
-                    'Error Creating Merge Proposal', body)
-                return
-            except BranchCreationException, e:
-                body = get_error_message(
-                        'branch-creation-exception.txt',
-                        error_templates=error_templates,
-                        reason=e)
-                simple_sendmail('merge@xxxxxxxxxxxxxxxxxx',
-                    [message.get('from')],
-                    'Error Creating Merge Proposal', body)
-                return
-        with globalErrorUtility.oopsMessage(
-            'target: %r source: %r' % (target, source)):
-            try:
-                # When creating a merge proposal, we need to gather all
-                # necessary arguments to addLandingTarget(). So from the email
-                # body we need to extract: reviewer, review type, description.
-                description = None
-                review_requests = []
-                email_body_text = email_body_text.strip()
-                if email_body_text != '':
-                    description = email_body_text
-                    review_args = parse_commands(
-                        email_body_text, ['reviewer'])
-                    if len(review_args) > 0:
-                        cmd, args = review_args[0]
-                        review_request = (
-                            CodeEmailCommands.parseReviewRequest(cmd, args))
-                        review_requests.append(review_request)
-
-                bmp = source.addLandingTarget(submitter, target,
-                                              needs_review=True,
-                                              description=description,
-                                              review_requests=review_requests)
-                return bmp
-
-            except BranchMergeProposalExists:
-                body = get_error_message(
-                    'branchmergeproposal-exists.txt',
-                    error_templates=error_templates,
-                    source_branch=source.bzr_identity,
-                    target_branch=target.bzr_identity)
-                simple_sendmail('merge@xxxxxxxxxxxxxxxxxx',
-                    [message.get('from')],
-                    'Error Creating Merge Proposal', body)
-                transaction.abort()
-            except IncomingEmailError, error:
-                send_process_error_notification(
-                    str(submitter.preferredemail.email),
-                    'Submit Request Failure',
-                    error.message, email_body_text, error.failing_command)
-                transaction.abort()

=== removed file 'lib/lp/code/mail/errortemplates/branch-creation-exception.txt'
--- lib/lp/code/mail/errortemplates/branch-creation-exception.txt	2011-08-11 22:18:34 +0000
+++ lib/lp/code/mail/errortemplates/branch-creation-exception.txt	1970-01-01 00:00:00 +0000
@@ -1,2 +0,0 @@
-Launchpad cannot create the branch requested by your merge directive:
-%(reason)s

=== removed file 'lib/lp/code/mail/errortemplates/missingmergedirective.txt'
--- lib/lp/code/mail/errortemplates/missingmergedirective.txt	2011-08-11 22:18:34 +0000
+++ lib/lp/code/mail/errortemplates/missingmergedirective.txt	1970-01-01 00:00:00 +0000
@@ -1,2 +0,0 @@
-Your email did not contain a merge directive. Please resend your email with
-the merge directive attached.

=== modified file 'lib/lp/code/mail/tests/test_codehandler.py'
--- lib/lp/code/mail/tests/test_codehandler.py	2012-01-20 15:42:44 +0000
+++ lib/lp/code/mail/tests/test_codehandler.py	2012-04-27 19:10:25 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2012 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Testing the CodeHandler."""
@@ -8,64 +8,38 @@
 from difflib import unified_diff
 from textwrap import dedent
 
-from bzrlib.branch import Branch
-from bzrlib.urlutils import join as urljoin
-from bzrlib.workingtree import WorkingTree
 from storm.store import Store
 import transaction
-from zope.component import getUtility
-from zope.interface import (
-    directlyProvidedBy,
-    directlyProvides,
-    )
 from zope.security.management import setSecurityPolicy
-from zope.security.proxy import removeSecurityProxy
 
 from lp.code.enums import (
     BranchMergeProposalStatus,
     BranchSubscriptionNotificationLevel,
-    BranchType,
-    BranchVisibilityRule,
     CodeReviewNotificationLevel,
     CodeReviewVote,
     )
-from lp.code.interfaces.branchlookup import IBranchLookup
 from lp.code.mail.codehandler import (
     AddReviewerEmailCommand,
     CodeEmailCommands,
     CodeHandler,
     CodeReviewEmailCommandExecutionContext,
     InvalidBranchMergeProposalAddress,
-    MissingMergeDirective,
-    NonLaunchpadTarget,
     UpdateStatusEmailCommand,
     VoteEmailCommand,
     )
 from lp.code.model.branchmergeproposaljob import (
     BranchMergeProposalJob,
     BranchMergeProposalJobType,
-    CreateMergeProposalJob,
-    MergeProposalNeedsReviewEmailJob,
     )
 from lp.code.model.diff import PreviewDiff
 from lp.code.tests.helpers import make_merge_proposal_without_reviewers
-from lp.codehosting.vfs import get_lp_server
-from lp.registry.interfaces.person import IPersonSet
 from lp.services.config import config
-from lp.services.job.runner import JobRunner
 from lp.services.mail.handlers import mail_handlers
 from lp.services.mail.interfaces import (
     EmailProcessingError,
-    IWeaklyAuthenticatedPrincipal,
     )
 from lp.services.messages.model.message import MessageSet
-from lp.services.osutils import override_environ
 from lp.services.webapp.authorization import LaunchpadSecurityPolicy
-from lp.services.webapp.interaction import (
-    get_current_principal,
-    setupInteraction,
-    )
-from lp.services.webapp.interfaces import IPlacelessAuthUtility
 from lp.testing import (
     login,
     login_person,
@@ -249,7 +223,7 @@
             review needs-fixing
 
 
-        -- 
+        --\x20
         For more information about using Launchpad by e-mail, see
         https://help.launchpad.net/EmailInterface
         or send an email to help@xxxxxxxxxxxxx"""),
@@ -394,286 +368,18 @@
         self.assertRaises(InvalidBranchMergeProposalAddress,
                           self.code_handler.getBranchMergeProposal, 'mp+abc@')
 
-    def test_acquireBranchesForProposal(self):
-        """Ensure CodeHandler._acquireBranchesForProposal works."""
-        target_branch = self.factory.makeAnyBranch()
-        source_branch = self.factory.makeAnyBranch()
-        md = self.factory.makeMergeDirective(source_branch, target_branch)
-        submitter = self.factory.makePerson()
-        switch_dbuser(config.processmail.dbuser)
-        mp_source, mp_target = self.code_handler._acquireBranchesForProposal(
-            md, submitter)
-        self.assertEqual(mp_source, source_branch)
-        self.assertEqual(mp_target, target_branch)
-        transaction.commit()
-
-    def test_acquireBranchesForProposalRemoteTarget(self):
-        """CodeHandler._acquireBranchesForProposal fails on remote targets."""
-        source_branch = self.factory.makeAnyBranch()
-        md = self.factory.makeMergeDirective(
-            source_branch, target_branch_url='http://example.com')
-        submitter = self.factory.makePerson()
-        switch_dbuser(config.create_merge_proposals.dbuser)
-        self.assertRaises(
-            NonLaunchpadTarget, self.code_handler._acquireBranchesForProposal,
-            md, submitter)
-        transaction.commit()
-
-    def test_acquireBranchesForProposalRemoteSource(self):
-        """CodeHandler._acquireBranchesForProposal allows remote sources.
-
-        If there's no existing remote branch, it creates one, using
-        the suffix of the url as a branch name seed.
-        """
-        target_branch = self.factory.makeProductBranch()
-        source_branch_url = 'http://example.com/suffix'
-        md = self.factory.makeMergeDirective(
-            source_branch_url=source_branch_url, target_branch=target_branch)
-        branches = getUtility(IBranchLookup)
-        self.assertIs(None, branches.getByUrl(source_branch_url))
-        submitter = self.factory.makePerson()
-        switch_dbuser(config.create_merge_proposals.dbuser)
-        mp_source, mp_target = self.code_handler._acquireBranchesForProposal(
-            md, submitter)
-        self.assertEqual(mp_target, target_branch)
-        self.assertIsNot(None, mp_source)
-        self.assertEqual(mp_source, branches.getByUrl(source_branch_url))
-        self.assertEqual(BranchType.REMOTE, mp_source.branch_type)
-        self.assertEqual(mp_target.product, mp_source.product)
-        self.assertEqual('suffix', mp_source.name)
-        transaction.commit()
-
-    def test_acquireBranchesForProposalRemoteSourceDupeName(self):
-        """CodeHandler._acquireBranchesForProposal creates names safely.
-
-        When creating a new branch, it uses the suffix of the url as a branch
-        name seed.  If there is already a branch with that name, it appends
-        a numeric suffix.
-        """
-        target_branch = self.factory.makeProductBranch()
-        source_branch_url = 'http://example.com/suffix'
-        md = self.factory.makeMergeDirective(
-            source_branch_url=source_branch_url, target_branch=target_branch)
-        submitter = self.factory.makePerson()
-        self.factory.makeProductBranch(
-            product=target_branch.product, name='suffix', owner=submitter)
-        switch_dbuser(config.create_merge_proposals.dbuser)
-        mp_source, mp_target = self.code_handler._acquireBranchesForProposal(
-            md, submitter)
-        self.assertEqual('suffix-1', mp_source.name)
-        transaction.commit()
-
-    def test_findMergeDirectiveAndComment(self):
-        """findMergeDirectiveAndComment works."""
-        md = self.factory.makeMergeDirective()
-        message = self.factory.makeSignedMessage(
-            body='Hi!\n', attachment_contents=''.join(md.to_lines()),
-            force_transfer_encoding=True)
-        code_handler = CodeHandler()
-        switch_dbuser(config.processmail.dbuser)
-        comment, md2 = code_handler.findMergeDirectiveAndComment(message)
-        self.assertEqual('Hi!\n', comment)
-        self.assertEqual(md.revision_id, md2.revision_id)
-        self.assertEqual(md.target_branch, md2.target_branch)
-        transaction.commit()
-
-    def test_findMergeDirectiveAndCommentEmptyBody(self):
-        """findMergeDirectiveAndComment handles empty message bodies.
-
-        Empty message bodies are returned verbatim.
-        """
-        md = self.factory.makeMergeDirective()
-        message = self.factory.makeSignedMessage(
-            body='', attachment_contents=''.join(md.to_lines()))
-        switch_dbuser(config.processmail.dbuser)
-        code_handler = CodeHandler()
-        comment, md2 = code_handler.findMergeDirectiveAndComment(message)
-        self.assertEqual('', comment)
-        transaction.commit()
-
-    def test_findMergeDirectiveAndComment_no_content_type(self):
-        """Parts with no content-type are treated as text/plain."""
-        md = self.factory.makeMergeDirective()
-        message = self.factory.makeSignedMessage(
-            body='', attachment_contents=''.join(md.to_lines()))
-        body = message.get_payload()[0]
-        del body['Content-type']
-        body.set_payload('body')
-        switch_dbuser(config.processmail.dbuser)
-        code_handler = CodeHandler()
-        comment, md2 = code_handler.findMergeDirectiveAndComment(message)
-        self.assertEqual('body', comment)
-
-    def test_findMergeDirectiveAndComment_case_insensitive(self):
-        """findMergeDirectiveAndComment uses case-insensitive content-type."""
-        md = self.factory.makeMergeDirective()
-        message = self.factory.makeSignedMessage(
-            body='', attachment_contents=''.join(md.to_lines()))
-        body = message.get_payload()[0]
-        # Unlike dicts, messages append when you assign to a key.  So
-        # we must delete the first Content-type before adding another.
-        del body['Content-type']
-        body['Content-type'] = 'Text/Plain'
-        body.set_payload('body')
-        switch_dbuser(config.processmail.dbuser)
-        code_handler = CodeHandler()
-        comment, md2 = code_handler.findMergeDirectiveAndComment(message)
-        self.assertEqual('body', comment)
-
-    def test_findMergeDirectiveAndCommentUnicodeBody(self):
-        """findMergeDirectiveAndComment returns unicode comments."""
-        md = self.factory.makeMergeDirective()
-        message = self.factory.makeSignedMessage(
-            body=u'\u1234', attachment_contents=''.join(md.to_lines()))
-        switch_dbuser(config.processmail.dbuser)
-        code_handler = CodeHandler()
-        comment, md2 = code_handler.findMergeDirectiveAndComment(message)
-        self.assertEqual(u'\u1234', comment)
-        transaction.commit()
-
-    def test_findMergeDirectiveAndCommentNoMergeDirective(self):
-        """findMergeDirectiveAndComment handles missing merge directives.
-
-        MissingMergeDirective is raised when no merge directive is present.
-        """
-        message = self.factory.makeSignedMessage(body='Hi!\n')
-        switch_dbuser(config.processmail.dbuser)
-        code_handler = CodeHandler()
-        self.assertRaises(MissingMergeDirective,
-            code_handler.findMergeDirectiveAndComment, message)
-        transaction.commit()
-
-    def test_processMergeProposal(self):
-        """processMergeProposal creates a merge proposal and comment."""
-        message, file_alias, source, target = (
-            self.factory.makeMergeDirectiveEmail())
-        # Add some revisions so the proposal is ready.
-        self.factory.makeRevisionsForBranch(source, count=1)
-        switch_dbuser(config.create_merge_proposals.dbuser)
-        code_handler = CodeHandler()
-        pop_notifications()
-        bmp = code_handler.processMergeProposal(message)
-        self.assertEqual(source, bmp.source_branch)
-        self.assertEqual(target, bmp.target_branch)
-        self.assertEqual('Hi!', bmp.description)
-        # No emails are sent.
-        messages = pop_notifications()
-        self.assertEqual(0, len(messages))
-        # Only a job created.
-        runner = JobRunner.fromReady(MergeProposalNeedsReviewEmailJob)
-        self.assertEqual(1, len(list(runner.jobs)))
-        transaction.commit()
-
-    def test_processMergeProposalEmptyMessage(self):
-        """processMergeProposal handles empty message bodies.
-
-        Messages with empty bodies produce merge proposals only, not
-        comments.
-        """
-        message, file_alias, source_branch, target_branch = (
-            self.factory.makeMergeDirectiveEmail(body=' '))
-        switch_dbuser(config.create_merge_proposals.dbuser)
-        code_handler = CodeHandler()
-        bmp = code_handler.processMergeProposal(message)
-        self.assertEqual(source_branch, bmp.source_branch)
-        self.assertEqual(target_branch, bmp.target_branch)
-        self.assertIs(None, bmp.description)
-        self.assertEqual(0, bmp.all_comments.count())
-        transaction.commit()
-
-    def test_processMergeDirectiveEmailNeedsGPG(self):
-        """process creates a merge proposal from a merge directive email."""
-        message, file_alias, source, target = (
-            self.factory.makeMergeDirectiveEmail())
-        # Ensure the message is stored in the librarian.
-        # mail.incoming.handleMail also explicitly does this.
-        switch_dbuser(config.create_merge_proposals.dbuser)
-        code_handler = CodeHandler()
-        # In order to fake a non-gpg signed email, we say that the current
-        # principal direcly provides IWeaklyAuthenticatePrincipal, which is
-        # what the surrounding code does.
-        cur_principal = get_current_principal()
-        directlyProvides(
-            cur_principal, directlyProvidedBy(cur_principal),
-            IWeaklyAuthenticatedPrincipal)
-        code_handler.process(message, 'merge@xxxxxxxxxxxxxxxxxx', file_alias)
-
-        notification = pop_notifications()[0]
-        self.assertEqual('Submit Request Failure', notification['subject'])
-        # The returned message is a multipart message, the first part is
-        # the message, and the second is the original message.
-        message, original = notification.get_payload()
-        self.assertEqual(dedent("""\
-        An error occurred while processing a mail you sent to Launchpad's email
-        interface.
-
-
-        Error message:
-
-        All emails to merge@xxxxxxxxxxxxxxxxxx must be signed with your OpenPGP
-        key.
-
-
-        -- 
-        For more information about using Launchpad by e-mail, see
-        https://help.launchpad.net/EmailInterface
-        or send an email to help@xxxxxxxxxxxxx"""),
-                                message.get_payload(decode=True))
-
     def test_processWithMergeDirectiveEmail(self):
-        """process creates a merge proposal from a merge directive email."""
-        message, file_alias, source, target = (
-            self.factory.makeMergeDirectiveEmail())
-        # Ensure the message is stored in the librarian.
-        # mail.incoming.handleMail also explicitly does this.
-        switch_dbuser(config.processmail.dbuser)
-        code_handler = CodeHandler()
-        self.assertEqual(0, source.landing_targets.count())
-        code_handler.process(message, 'merge@xxxxxxxxxxxxxxxxxx', file_alias)
-        switch_dbuser(config.create_merge_proposals.dbuser)
-        JobRunner.fromReady(CreateMergeProposalJob).runAll()
-        self.assertEqual(target, source.landing_targets[0].target_branch)
-        # Ensure the DB operations violate no constraints.
-        Store.of(source).flush()
-
-    def test_processWithUnicodeMergeDirectiveEmail(self):
-        """process creates a comment from a unicode message body."""
-        message, file_alias, source, target = (
-            self.factory.makeMergeDirectiveEmail(body=u'\u1234'))
-        # Ensure the message is stored in the librarian.
-        # mail.incoming.handleMail also explicitly does this.
-        switch_dbuser(config.processmail.dbuser)
-        code_handler = CodeHandler()
-        self.assertEqual(0, source.landing_targets.count())
-        code_handler.process(message, 'merge@xxxxxxxxxxxxxxxxxx', file_alias)
-        switch_dbuser(config.create_merge_proposals.dbuser)
-        JobRunner.fromReady(CreateMergeProposalJob).runAll()
-        proposal = source.landing_targets[0]
-        self.assertEqual(u'\u1234', proposal.description)
-        # Ensure the DB operations violate no constraints.
-        Store.of(proposal).flush()
-
-    def test_processMergeProposalReviewerRequested(self):
-        # The commands in the merge proposal are parsed.
-        eric = self.factory.makePerson(name="eric")
-        message, file_alias, source_branch, target_branch = (
-            self.factory.makeMergeDirectiveEmail(body=dedent("""\
-                This is the comment.
-
-                  reviewer eric
-                """)))
-        switch_dbuser(config.create_merge_proposals.dbuser)
-        code_handler = CodeHandler()
-        pop_notifications()
-        bmp = code_handler.processMergeProposal(message)
-        pending_reviews = list(bmp.votes)
-        self.assertEqual(1, len(pending_reviews))
-        self.assertEqual(eric, pending_reviews[0].reviewer)
-        # No emails are sent.
-        messages = pop_notifications()
-        self.assertEqual(0, len(messages))
-        # Ensure the DB operations violate no constraints.
-        Store.of(bmp).flush()
+        """process errors if merge@ address used."""
+        message = self.factory.makeSignedMessage()
+        file_alias = self.factory.makeLibraryFileAlias(
+            content=message.as_string())
+        # mail.incoming.handleMail also explicitly does this.
+        switch_dbuser(config.processmail.dbuser)
+        code_handler = CodeHandler()
+        code_handler.process(message, 'merge@xxxxxxxxxxxxxxxxxx', file_alias)
+        notification = pop_notifications()[0]
+        self.assertEqual(
+            'Merge directive not supported.', notification['Subject'])
 
     def test_reviewer_with_diff(self):
         """Requesting a review with a diff works."""
@@ -695,161 +401,6 @@
         [vote] = bmp.votes
         self.assertEqual(eric, vote.reviewer)
 
-    def test_processMergeProposalDefaultReviewer(self):
-        # If no reviewer was requested in the comment body, then the default
-        # reviewer of the target branch is used.
-        message, file_alias, source_branch, target_branch = (
-            self.factory.makeMergeDirectiveEmail(body=dedent("""\
-                This is the comment.
-                """)))
-        switch_dbuser(config.create_merge_proposals.dbuser)
-        code_handler = CodeHandler()
-        pop_notifications()
-        bmp = code_handler.processMergeProposal(message)
-        # If no reviewer is specified, then the default reviewer of the target
-        # branch is requested to review.
-        pending_reviews = list(bmp.votes)
-        self.assertEqual(1, len(pending_reviews))
-        self.assertEqual(
-            target_branch.code_reviewer,
-            pending_reviews[0].reviewer)
-        # No emails are sent.
-        messages = pop_notifications()
-        self.assertEqual(0, len(messages))
-        # Ensure the DB operations violate no constraints.
-        Store.of(target_branch).flush()
-
-    def test_processMergeProposalExists(self):
-        """processMergeProposal raises BranchMergeProposalExists
-
-        If there is already a merge proposal with the same target and source
-        branches of the merge directive, an email is sent to the user.
-        """
-        message, file_alias, source, target = (
-            self.factory.makeMergeDirectiveEmail())
-        switch_dbuser(config.create_merge_proposals.dbuser)
-        code_handler = CodeHandler()
-        code_handler.processMergeProposal(message)
-        pop_notifications()
-        transaction.commit()
-        code_handler.processMergeProposal(message)
-        [notification] = pop_notifications()
-        self.assertEqual(
-            notification['Subject'], 'Error Creating Merge Proposal')
-        self.assertEqual(
-            notification.get_payload(decode=True),
-            'The branch %s is already proposed for merging into %s.\n\n'
-            % (source.bzr_identity, target.bzr_identity))
-        self.assertEqual(notification['to'], message['from'])
-
-    def test_processMissingMergeDirective(self):
-        """process sends an email if the original email lacks an attachment.
-        """
-        message = self.factory.makeSignedMessage(body='A body',
-            subject='A subject', attachment_contents='')
-        switch_dbuser(config.create_merge_proposals.dbuser)
-        code_handler = CodeHandler()
-        code_handler.processMergeProposal(message)
-        transaction.commit()
-        [notification] = pop_notifications()
-
-        self.assertEqual(
-            notification['Subject'], 'Error Creating Merge Proposal')
-        self.assertEqual(
-            notification.get_payload(),
-            'Your email did not contain a merge directive. Please resend '
-            'your email with\nthe merge directive attached.\n')
-        self.assertEqual(notification['to'],
-            message['from'])
-
-    def makeTargetBranch(self):
-        """Helper for getNewBranchInfo tests."""
-        owner = self.factory.makePerson(name='target-owner')
-        product = self.factory.makeProduct(name='target-product')
-        return self.factory.makeProductBranch(product=product, owner=owner)
-
-    def test_getNewBranchInfoNoURL(self):
-        """If no URL, target namespace is used, with 'merge' basename."""
-        submitter = self.factory.makePerson(name='merge-submitter')
-        target = self.makeTargetBranch()
-        code_handler = CodeHandler()
-        namespace, base = code_handler._getNewBranchInfo(
-            None, target, submitter)
-        self.assertEqual('~merge-submitter/target-product', namespace.name)
-        self.assertEqual('merge', base)
-
-    def test_getNewBranchInfoRemoteURL(self):
-        """If a URL is provided, its base is used, with target namespace."""
-        submitter = self.factory.makePerson(name='merge-submitter')
-        target = self.makeTargetBranch()
-        code_handler = CodeHandler()
-        namespace, base = code_handler._getNewBranchInfo(
-                'http://foo/bar', target, submitter)
-        self.assertEqual('~merge-submitter/target-product', namespace.name)
-        self.assertEqual('bar', base)
-
-    def test_getNewBranchInfoRemoteURLTrailingSlash(self):
-        """Trailing slashes are ignored when determining base."""
-        submitter = self.factory.makePerson(name='merge-submitter')
-        target = self.makeTargetBranch()
-        code_handler = CodeHandler()
-        namespace, base = code_handler._getNewBranchInfo(
-                'http://foo/bar/', target, submitter)
-        self.assertEqual('~merge-submitter/target-product', namespace.name)
-        self.assertEqual('bar', base)
-
-    def test_getNewBranchInfoLPURL(self):
-        """If an LP URL is provided, we attempt to reproduce it exactly."""
-        submitter = self.factory.makePerson(name='merge-submitter')
-        target = self.makeTargetBranch()
-        self.factory.makeProduct('uproduct')
-        self.factory.makePerson(name='uuser')
-        code_handler = CodeHandler()
-        namespace, base = code_handler._getNewBranchInfo(
-            config.codehosting.supermirror_root + '~uuser/uproduct/bar',
-            target, submitter)
-        self.assertEqual('~uuser/uproduct', namespace.name)
-        self.assertEqual('bar', base)
-
-    def test_getNewBranchInfoLPURLTrailingSlash(self):
-        """Trailing slashes are permitted in LP URLs."""
-        submitter = self.factory.makePerson(name='merge-submitter')
-        target = self.makeTargetBranch()
-        self.factory.makeProduct('uproduct')
-        self.factory.makePerson(name='uuser')
-        code_handler = CodeHandler()
-        namespace, base = code_handler._getNewBranchInfo(
-            config.codehosting.supermirror_root + '~uuser/uproduct/bar/',
-            target, submitter)
-        self.assertEqual('~uuser/uproduct', namespace.name)
-        self.assertEqual('bar', base)
-
-    def test_processNonLaunchpadTarget(self):
-        """When target branch is unknown to Launchpad, the user is notified.
-        """
-        directive = self.factory.makeMergeDirective(
-            target_branch_url='http://www.example.com')
-        message = self.factory.makeSignedMessage(body='body',
-            subject='This is gonna fail', attachment_contents=''.join(
-                directive.to_lines()))
-
-        switch_dbuser(config.create_merge_proposals.dbuser)
-        code_handler = CodeHandler()
-        code_handler.processMergeProposal(message)
-        transaction.commit()
-        [notification] = pop_notifications()
-
-        self.assertEqual(
-            notification['Subject'], 'Error Creating Merge Proposal')
-        self.assertEqual(
-            notification.get_payload(decode=True),
-            'The target branch at %s is not known to Launchpad.  It\'s\n'
-            'possible that your submit branch is not set correctly, or that '
-            'your submit\nbranch has not yet been pushed to Launchpad.\n\n'
-            % ('http://www.example.com'))
-        self.assertEqual(notification['to'],
-            message['from'])
-
     def test_processMissingSubject(self):
         """If the subject is missing, the user is warned by email."""
         mail = self.factory.makeSignedMessage(
@@ -874,267 +425,6 @@
         self.assertEqual(0, bmp.all_comments.count())
 
 
-class TestCodeHandlerProcessMergeDirective(TestCaseWithFactory):
-    """Test the merge directive processing parts of the code email hander."""
-
-    layer = ZopelessAppServerLayer
-
-    def setUp(self):
-        TestCaseWithFactory.setUp(self, user='test@xxxxxxxxxxxxx')
-        self.code_handler = CodeHandler()
-        self._old_policy = setSecurityPolicy(LaunchpadSecurityPolicy)
-
-    def tearDown(self):
-        setSecurityPolicy(self._old_policy)
-        TestCaseWithFactory.tearDown(self)
-
-    def _createTargetSourceAndBundle(self, format=None):
-        """Create a merge directive with a bundle and associated branches.
-
-        The target branch is created in the specified format, or the default
-        format if the format is None.
-
-        :return: A tuple containing the db_branch relating to the target
-            branch, a bzr_branch of the source branch, and the merge directive
-            containing the revisions in the source branch that aren't in the
-            target branch.
-        """
-        db_target_branch, target_tree = self.create_branch_and_tree(
-            tree_location='.', format=format)
-        target_tree.branch.set_public_branch(db_target_branch.bzr_identity)
-        # XXX: AaronBentley 2010-08-06 bug=614404: a bzr username is
-        # required to generate the revision-id.
-        with override_environ(BZR_EMAIL='me@xxxxxxxxxxx'):
-            target_tree.commit('rev1')
-            # Make sure that the created branch has been mirrored.
-            removeSecurityProxy(db_target_branch).branchChanged(
-                '', 'rev1', None, None, None)
-            sprout_bzrdir = target_tree.bzrdir.sprout('source')
-            source_tree = sprout_bzrdir.open_workingtree()
-            source_tree.commit('rev2')
-        message = self.factory.makeBundleMergeDirectiveEmail(
-            source_tree.branch, db_target_branch)
-        return db_target_branch, source_tree.branch, message
-
-    def _openBazaarBranchAsClient(self, db_branch):
-        """Open the Bazaar branch relating to db_branch as if a client was.
-
-        The client has write access to the branch.
-        """
-        lp_server = get_lp_server(db_branch.owner.id)
-        lp_server.start_server()
-        self.addCleanup(lp_server.stop_server)
-        branch_url = urljoin(lp_server.get_url(), db_branch.unique_name)
-        return Branch.open(branch_url)
-
-    def _processMergeDirective(self, message):
-        """Process the merge directive email."""
-        switch_dbuser(config.create_merge_proposals.dbuser)
-        code_handler = CodeHandler()
-        # Do the authentication dance as we do in the processing script.
-        authutil = getUtility(IPlacelessAuthUtility)
-        email_addr = message['from']
-        principal = authutil.getPrincipalByLogin(email_addr)
-        if principal is None:
-            raise AssertionError('No principal found for %s' % email_addr)
-        setupInteraction(principal, email_addr)
-        return code_handler.processMergeProposal(message)
-
-    def test_nonstackable_target(self):
-        # If the target branch is in a non-stackable format, then the source
-        # branch that is created is an empty hosted branch.  The new branch
-        # will not have a mirror requested as there are no revisions, and
-        # there is no branch created in the hosted area.
-
-        # XXX Tim Penhey 2010-07-27 bug 610292
-        # We should fail here and return an oops email to the user.
-        self.useBzrBranches()
-        branch, source, message = self._createTargetSourceAndBundle(
-            format="pack-0.92")
-        bmp = self._processMergeDirective(message)
-        self.assertEqual(BranchType.HOSTED, bmp.source_branch.branch_type)
-        self.assertIs(None, bmp.source_branch.next_mirror_time)
-
-    def test_stackable_unmirrored_target(self):
-        # If the target branch is in a stackable format but has not been
-        # mirrored, the source branch that is created is an empty hosted
-        # branch.  The new branch will not have a mirror requested as there
-        # are no revisions, and there is no branch created in the hosted area.
-        self.useBzrBranches()
-        branch, source, message = self._createTargetSourceAndBundle(
-            format="1.9")
-        # Mark the target branch as "unmirrored", at least as far as the db is
-        # concerned.
-        branch.last_mirrored = None
-        branch.last_mirrored_id = None
-        bmp = self._processMergeDirective(message)
-        self.assertEqual(BranchType.REMOTE, bmp.source_branch.branch_type)
-
-    def test_stackable_target(self):
-        # If the target branch is in a stackable format, then the source
-        # branch that is created is a hosted branch stacked on the target
-        # branch. The source branch will have the revisions from the bundle,
-        # and a mirror will have been triggered.
-        self.useBzrBranches()
-        branch, source, message = self._createTargetSourceAndBundle(
-            format="1.9")
-        bmp = self._processMergeDirective(message)
-        source_bzr_branch = self._openBazaarBranchAsClient(bmp.source_branch)
-        self.assertEqual(BranchType.HOSTED, bmp.source_branch.branch_type)
-        self.assertTrue(bmp.source_branch.pending_writes)
-        self.assertEqual(
-            source.last_revision(), source_bzr_branch.last_revision())
-
-    def test_branch_stacked(self):
-        # When a branch is created for a merge directive, it is created
-        # stacked on the target branch.
-        self.useBzrBranches()
-        branch, source, message = self._createTargetSourceAndBundle(
-            format="1.9")
-        bmp = self._processMergeDirective(message)
-        # The source branch is stacked on the target.
-        source_bzr_branch = self._openBazaarBranchAsClient(bmp.source_branch)
-        self.assertEqual(
-            '/' + bmp.target_branch.unique_name,
-            source_bzr_branch.get_stacked_on_url())
-        # Make sure that the source branch doesn't have all the revisions.
-        source_branch_revisions = (
-            source_bzr_branch.bzrdir.open_repository().all_revision_ids())
-        # The only revision is the tip revision, as the other revisions are
-        # from the target branch.
-        tip_revision = source_bzr_branch.last_revision()
-        self.assertEqual([tip_revision], source_branch_revisions)
-
-    def test_source_not_newer(self):
-        # The source branch is created correctly when the source is not newer
-        # than the target, instead of raising DivergedBranches.
-        self.useBzrBranches()
-        branch, source, message = self._createTargetSourceAndBundle(
-            format="1.9")
-        target_tree = WorkingTree.open('.')
-        # XXX: AaronBentley 2010-08-06 bug=614404: a bzr username is
-        # required to generate the revision-id.
-        with override_environ(BZR_EMAIL='me@xxxxxxxxxxx'):
-            target_tree.commit('rev2b')
-        bmp = self._processMergeDirective(message)
-        lp_branch = self._openBazaarBranchAsClient(bmp.source_branch)
-        self.assertEqual(source.last_revision(), lp_branch.last_revision())
-
-    def _createPreexistingSourceAndMessage(self, target_format,
-                                           source_format, set_stacked=False):
-        """Create the source and target branches and the merge directive."""
-        db_target_branch, target_tree = self.create_branch_and_tree(
-            'target', format=target_format)
-        target_tree.branch.set_public_branch(db_target_branch.bzr_identity)
-        # XXX: AaronBentley 2010-08-06 bug=614404: a bzr username is
-        # required to generate the revision-id.
-        with override_environ(BZR_EMAIL='me@xxxxxxxxxxx'):
-            revid = target_tree.commit('rev1')
-            removeSecurityProxy(db_target_branch).branchChanged(
-                '', revid, None, None, None)
-
-            db_source_branch, source_tree = self.create_branch_and_tree(
-                'lpsource', db_target_branch.product, format=source_format)
-            # The branch is not scheduled to be mirrorred.
-            self.assertIs(db_source_branch.next_mirror_time, None)
-            source_tree.pull(target_tree.branch)
-            source_tree.commit('rev2', rev_id='rev2')
-            # bundle_tree is effectively behaving like a local copy of
-            # db_source_branch, and is used to create the merge directive.
-            sprout_bzrdir = source_tree.bzrdir.sprout('source')
-            bundle_tree = sprout_bzrdir.open_workingtree()
-            bundle_tree.commit('rev3', rev_id='rev3')
-        bundle_tree.branch.set_public_branch(db_source_branch.bzr_identity)
-        message = self.factory.makeBundleMergeDirectiveEmail(
-            bundle_tree.branch, db_target_branch,
-            sender=db_source_branch.owner)
-        # Tell the source branch that it is stacked on the target.
-        if set_stacked:
-            stacked_url = '/' + db_target_branch.unique_name
-            branch = self._openBazaarBranchAsClient(db_source_branch)
-            branch.set_stacked_on_url(stacked_url)
-        return db_source_branch, message
-
-    def test_existing_stacked_branch(self):
-        # A bundle can update an existing branch if they are both stackable,
-        # and the source branch is stacked.
-        self.useBzrBranches()
-        lp_source, message = self._createPreexistingSourceAndMessage(
-            target_format="1.9", source_format="1.9", set_stacked=True)
-        bmp = self._processMergeDirective(message)
-        # The branch merge proposal should use the existing db branch.
-        self.assertEqual(lp_source, bmp.source_branch)
-        bzr_branch = self._openBazaarBranchAsClient(bmp.source_branch)
-        # The branch has been updated.
-        self.assertEqual('rev3', bzr_branch.last_revision())
-
-    def test_existing_unstacked_branch(self):
-        # Even if the source and target are stackable, if the source is not
-        # stacked, we don't support stacking something that wasn't stacked
-        # before (yet).
-        self.useBzrBranches()
-        lp_source, message = self._createPreexistingSourceAndMessage(
-            target_format="1.9", source_format="1.9")
-        bmp = self._processMergeDirective(message)
-        # The branch merge proposal should use the existing db branch.
-        self.assertEqual(lp_source, bmp.source_branch)
-        bzr_branch = self._openBazaarBranchAsClient(bmp.source_branch)
-        # The hosted copy of the branch has not been updated.
-        self.assertEqual('rev2', bzr_branch.last_revision())
-
-    def test_existing_branch_nonstackable_target(self):
-        # If the target branch is not stackable, then we don't pull any
-        # revisions.
-        self.useBzrBranches()
-        lp_source, message = self._createPreexistingSourceAndMessage(
-            target_format="pack-0.92", source_format="1.9")
-        bmp = self._processMergeDirective(message)
-        # The branch merge proposal should use the existing db branch.
-        self.assertEqual(lp_source, bmp.source_branch)
-        # Now the branch is not scheduled to be mirrorred.
-        self.assertIs(None, lp_source.next_mirror_time)
-        hosted = self._openBazaarBranchAsClient(bmp.source_branch)
-        # The hosted copy has not been updated.
-        self.assertEqual('rev2', hosted.last_revision())
-
-    def test_existing_branch_nonstackable_source(self):
-        # If the source branch is not stackable, then we don't pull any
-        # revisions.
-        self.useBzrBranches()
-        lp_source, message = self._createPreexistingSourceAndMessage(
-            target_format="1.9", source_format="pack-0.92")
-        bmp = self._processMergeDirective(message)
-        # The branch merge proposal should use the existing db branch.
-        self.assertEqual(lp_source, bmp.source_branch)
-        # Now the branch is not scheduled to be mirrorred.
-        self.assertIs(None, lp_source.next_mirror_time)
-        hosted = self._openBazaarBranchAsClient(bmp.source_branch)
-        # The hosted copy has not been updated.
-        self.assertEqual('rev2', hosted.last_revision())
-
-    def test_forbidden_target(self):
-        """Specifying a branch in a forbidden target generates email."""
-        self.useBzrBranches()
-        branch, source, message = self._createTargetSourceAndBundle(
-            format="pack-0.92")
-        branch.product.setBranchVisibilityTeamPolicy(
-            None, BranchVisibilityRule.FORBIDDEN)
-        result = self._processMergeDirective(message)
-        self.assertIs(None, result)
-        notifications = pop_notifications()
-        self.assertEqual(1, len(notifications))
-        self.assertEqual(
-            'Error Creating Merge Proposal', notifications[0]['subject'])
-        body = notifications[0].get_payload(decode=True)
-        sender = getUtility(IPersonSet).getByEmail(message['from'])
-        expected = (
-            'Launchpad cannot create the branch requested by'
-            ' your merge directive:\n'
-            'You cannot create branches in "~%s/%s"\n' %
-            (sender.name, branch.product.name))
-        self.assertEqual(expected, body)
-
-
 class TestVoteEmailCommand(TestCase):
     """Test the vote and tag processing of the VoteEmailCommand."""
 

=== modified file 'lib/lp/code/model/branchmergeproposaljob.py'
--- lib/lp/code/model/branchmergeproposaljob.py	2012-04-13 19:20:03 +0000
+++ lib/lp/code/model/branchmergeproposaljob.py	2012-04-27 19:10:25 +0000
@@ -17,7 +17,6 @@
     'BranchMergeProposalJobSource',
     'BranchMergeProposalJobType',
     'CodeReviewCommentEmailJob',
-    'CreateMergeProposalJob',
     'GenerateIncrementalDiffJob',
     'MergeProposalNeedsReviewEmailJob',
     'MergeProposalUpdatedEmailJob',
@@ -30,7 +29,6 @@
     datetime,
     timedelta,
     )
-from email.utils import parseaddr
 
 from lazr.delegates import delegates
 from lazr.enum import (
@@ -69,8 +67,6 @@
     IBranchMergeProposalJobSource,
     ICodeReviewCommentEmailJob,
     ICodeReviewCommentEmailJobSource,
-    ICreateMergeProposalJob,
-    ICreateMergeProposalJobSource,
     IGenerateIncrementalDiffJob,
     IGenerateIncrementalDiffJobSource,
     IMergeProposalNeedsReviewEmailJob,
@@ -91,7 +87,6 @@
 from lp.codehosting.bzrutils import server
 from lp.codehosting.vfs import (
     get_ro_server,
-    get_rw_server,
     )
 from lp.registry.interfaces.person import IPersonSet
 from lp.services.config import config
@@ -107,16 +102,9 @@
     BaseRunnableJobSource,
     )
 from lp.services.mail.sendmail import format_address_for_person
-from lp.services.messages.interfaces.message import IMessageJob
-from lp.services.messages.model.message import (
-    MessageJob,
-    MessageJobAction,
-    )
 from lp.services.webapp import errorlog
-from lp.services.webapp.interaction import setupInteraction
 from lp.services.webapp.interfaces import (
     DEFAULT_FLAVOR,
-    IPlacelessAuthUtility,
     IStoreSelector,
     MAIN_STORE,
     MASTER_FLAVOR,
@@ -403,83 +391,6 @@
         return format_address_for_person(registrant)
 
 
-class CreateMergeProposalJob(BaseRunnableJob):
-    """See `ICreateMergeProposalJob` and `ICreateMergeProposalJobSource`."""
-
-    classProvides(ICreateMergeProposalJobSource)
-
-    delegates(IMessageJob)
-
-    class_action = MessageJobAction.CREATE_MERGE_PROPOSAL
-
-    implements(ICreateMergeProposalJob)
-
-    def __init__(self, context):
-        """Create an instance of CreateMergeProposalJob.
-
-        :param context: a MessageJob.
-        """
-        self.context = context
-
-    def __eq__(self, other):
-        return (self.__class__ == other.__class__ and
-                self.context == other.context)
-
-    @classmethod
-    def create(klass, message_bytes):
-        """See `ICreateMergeProposalJobSource`."""
-        context = MessageJob(
-            message_bytes, MessageJobAction.CREATE_MERGE_PROPOSAL)
-        return klass(context)
-
-    @classmethod
-    def iterReady(klass):
-        """Iterate through all ready BranchMergeProposalJobs."""
-        store = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR)
-        jobs = store.find(
-            (MessageJob),
-            And(MessageJob.action == klass.class_action,
-                MessageJob.job == Job.id,
-                Job.id.is_in(Job.ready_jobs)))
-        return (klass(job) for job in jobs)
-
-    def run(self):
-        """See `ICreateMergeProposalJob`."""
-        # Avoid circular import
-        from lp.code.mail.codehandler import CodeHandler
-        url = self.context.message_bytes.getURL()
-        with errorlog.globalErrorUtility.oopsMessage('Mail url: %r' % url):
-            message = self.getMessage()
-            # Since the message was checked as signed before it was saved in
-            # the Librarian, just create the principal from the sender and set
-            # up the interaction.
-            name, email_addr = parseaddr(message['From'])
-            authutil = getUtility(IPlacelessAuthUtility)
-            principal = authutil.getPrincipalByLogin(email_addr)
-            if principal is None:
-                raise AssertionError('No principal found for %s' % email_addr)
-            setupInteraction(principal, email_addr)
-
-            server = get_rw_server()
-            server.start_server()
-            try:
-                return CodeHandler().processMergeProposal(message)
-            finally:
-                server.stop_server()
-
-    def getOopsRecipients(self):
-        message = self.getMessage()
-        from_ = message['From']
-        if from_ is None:
-            return []
-        return [from_]
-
-    def getOperationDescription(self):
-        message = self.getMessage()
-        return ('creating a merge proposal from message with subject %s' %
-                message['Subject'])
-
-
 class CodeReviewCommentEmailJob(BranchMergeProposalJobDerived):
     """A job to send a code review comment.
 

=== modified file 'lib/lp/code/model/tests/test_branchmergeproposal.py'
--- lib/lp/code/model/tests/test_branchmergeproposal.py	2012-02-27 00:49:48 +0000
+++ lib/lp/code/model/tests/test_branchmergeproposal.py	2012-04-27 19:10:25 +0000
@@ -47,8 +47,6 @@
     BRANCH_MERGE_PROPOSAL_FINAL_STATES as FINAL_STATES,
     IBranchMergeProposal,
     IBranchMergeProposalGetter,
-    ICreateMergeProposalJob,
-    ICreateMergeProposalJobSource,
     notify_modified,
     )
 from lp.code.model.branchmergeproposal import (
@@ -57,7 +55,6 @@
     )
 from lp.code.model.branchmergeproposaljob import (
     BranchMergeProposalJob,
-    CreateMergeProposalJob,
     MergeProposalNeedsReviewEmailJob,
     UpdatePreviewDiffJob,
     )
@@ -68,7 +65,6 @@
 from lp.registry.interfaces.person import IPersonSet
 from lp.registry.interfaces.product import IProductSet
 from lp.services.database.constants import UTC_NOW
-from lp.services.messages.interfaces.message import IMessageJob
 from lp.services.webapp import canonical_url
 from lp.services.webapp.testing import verifyObject
 from lp.testing import (
@@ -82,14 +78,11 @@
     ws_object,
     )
 from lp.testing.factory import (
-    GPGSigningContext,
     LaunchpadObjectFactory,
     )
-from lp.testing.gpgkeys import import_secret_test_key
 from lp.testing.layers import (
     DatabaseFunctionalLayer,
     LaunchpadFunctionalLayer,
-    LaunchpadZopelessLayer,
     )
 
 
@@ -1749,66 +1742,6 @@
                 BranchMergeProposalStatus.REJECTED, first_mp.queue_status)
 
 
-class TestCreateMergeProposalJob(TestCaseWithFactory):
-    """Tests for CreateMergeProposalJob."""
-
-    layer = LaunchpadZopelessLayer
-
-    def setUp(self):
-        TestCaseWithFactory.setUp(self, user='test@xxxxxxxxxxxxx')
-
-    def test_providesInterface(self):
-        """The class and instances correctly implement their interfaces."""
-        verifyObject(ICreateMergeProposalJobSource, CreateMergeProposalJob)
-        file_alias = self.factory.makeMergeDirectiveEmail()[1]
-        job = CreateMergeProposalJob.create(file_alias)
-        job.context.sync()
-        verifyObject(IMessageJob, job)
-        verifyObject(ICreateMergeProposalJob, job)
-
-    def test_run_creates_proposal(self):
-        """CreateMergeProposalJob.run should create a merge proposal."""
-        key = import_secret_test_key()
-        signing_context = GPGSigningContext(key.fingerprint, password='test')
-        message, file_alias, source, target = (
-            self.factory.makeMergeDirectiveEmail(
-                signing_context=signing_context))
-        job = CreateMergeProposalJob.create(file_alias)
-        transaction.commit()
-        proposal = job.run()
-        self.assertEqual(proposal.source_branch, source)
-        self.assertEqual(proposal.target_branch, target)
-
-    def test_getOopsMailController(self):
-        """The sender is notified when creating a bmp from email fails."""
-        key = import_secret_test_key()
-        signing_context = GPGSigningContext(key.fingerprint, password='test')
-        message, file_alias, source, target = (
-            self.factory.makeMergeDirectiveEmail(
-                signing_context=signing_context))
-        job = CreateMergeProposalJob.create(file_alias)
-        transaction.commit()
-        ctrl = job.getOopsMailController('1234')
-        self.assertEqual([message['From']], ctrl.to_addrs)
-        desc = ('creating a merge proposal from message with subject %s' %
-                message['Subject'])
-        self.assertIn(desc, ctrl.body)
-
-    def test_iterReady_includes_ready_jobs(self):
-        """Ready jobs should be listed."""
-        file_alias = self.factory.makeMergeDirectiveEmail()[1]
-        job = CreateMergeProposalJob.create(file_alias)
-        self.assertEqual([job], list(CreateMergeProposalJob.iterReady()))
-
-    def test_iterReady_excludes_unready_jobs(self):
-        """Unready jobs should not be listed."""
-        file_alias = self.factory.makeMergeDirectiveEmail()[1]
-        job = CreateMergeProposalJob.create(file_alias)
-        job.job.start()
-        job.job.complete()
-        self.assertEqual([], list(CreateMergeProposalJob.iterReady()))
-
-
 class TestUpdatePreviewDiff(TestCaseWithFactory):
     """Test the updateMergeDiff method of BranchMergeProposal."""
 

=== removed file 'lib/lp/code/scripts/tests/test_create_merge_proposals.py'
--- lib/lp/code/scripts/tests/test_create_merge_proposals.py	2012-03-28 11:36:07 +0000
+++ lib/lp/code/scripts/tests/test_create_merge_proposals.py	1970-01-01 00:00:00 +0000
@@ -1,107 +0,0 @@
-#! /usr/bin/python
-#
-# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Test the create_merge_proposals script"""
-
-from cStringIO import StringIO
-
-import transaction
-from zope.component import getUtility
-
-from lp.code.model.branchmergeproposaljob import CreateMergeProposalJob
-from lp.services.librarian.interfaces import ILibraryFileAliasSet
-from lp.services.scripts.tests import run_script
-from lp.testing import TestCaseWithFactory
-from lp.testing.factory import GPGSigningContext
-from lp.testing.gpgkeys import import_secret_test_key
-from lp.testing.layers import ZopelessAppServerLayer
-
-
-class TestCreateMergeProposals(TestCaseWithFactory):
-
-    layer = ZopelessAppServerLayer
-
-    def test_create_merge_proposals(self):
-        """Ensure create_merge_proposals runs and creates proposals."""
-        key = import_secret_test_key()
-        signing_context = GPGSigningContext(key.fingerprint, password='test')
-        email, file_alias, source, target = (
-            self.factory.makeMergeDirectiveEmail(
-                signing_context=signing_context))
-        job = CreateMergeProposalJob.create(file_alias)
-        self.assertEqual(0, source.landing_targets.count())
-        transaction.commit()
-        retcode, stdout, stderr = run_script(
-            'cronscripts/create_merge_proposals.py', [])
-        self.assertEqual(0, retcode)
-        self.assertTextMatchesExpressionIgnoreWhitespace(
-            "INFO    Creating lockfile: "
-            "/var/lock/launchpad-create_merge_proposals.lock\n"
-            "INFO    Running <.*CreateMergeProposalJob object at .*?> "
-            "\(ID %s\) in status Waiting\n"
-            "INFO    Ran 1 CreateMergeProposalJobs.\n" % job.job.id, stderr)
-        self.assertEqual('', stdout)
-        self.assertEqual(1, source.landing_targets.count())
-
-    def createJob(self, branch, tree):
-        """Create merge directive job from this branch."""
-        tree.branch.set_public_branch(branch.bzr_identity)
-        tree.commit('rev1')
-        source = tree.bzrdir.sprout('source').open_workingtree()
-        source.commit('rev2')
-        message = self.factory.makeBundleMergeDirectiveEmail(
-            source.branch, branch)
-        message_str = message.as_string()
-        library_file_aliases = getUtility(ILibraryFileAliasSet)
-        file_alias = library_file_aliases.create(
-            '*', len(message_str), StringIO(message_str), '*')
-        CreateMergeProposalJob.create(file_alias)
-        return source
-
-    def jobOutputCheck(self, branch, source):
-        """Run the job and check the output."""
-        transaction.commit()
-        retcode, stdout, stderr = run_script(
-            'cronscripts/create_merge_proposals.py', [])
-        self.assertEqual(0, retcode)
-        self.assertEqual(
-            "INFO    Creating lockfile: "
-            "/var/lock/launchpad-create_merge_proposals.lock\n"
-            "INFO    Ran 1 CreateMergeProposalJobs.\n", stderr)
-        self.assertEqual('', stdout)
-        bmp = branch.landing_candidates[0]
-        local_source = bmp.source_branch.getBzrBranch()
-        # The branch has the correct last revision.
-        self.assertEqual(
-            source.branch.last_revision(), local_source.last_revision())
-
-    def disabled_test_merge_directive_with_bundle(self):
-        """Merge directives with bundles generate branches."""
-        # XXX TimPenhey 2009-04-01 bug 352800
-        self.useBzrBranches()
-        branch, tree = self.create_branch_and_tree()
-        source = self.createJob(branch, tree)
-        self.jobOutputCheck(branch, source)
-
-    def disabled_test_merge_directive_with_project(self):
-        """Bundles are handled when the target branch has a project."""
-        # XXX TimPenhey 2009-04-01 bug 352800
-        self.useBzrBranches()
-        product = self.factory.makeProduct(project=self.factory.makeProject())
-        branch, tree = self.create_branch_and_tree(product=product)
-        source = self.createJob(branch, tree)
-        self.jobOutputCheck(branch, source)
-
-    def test_oops(self):
-        """A bogus request should cause an oops, not an exception."""
-        file_alias = self.factory.makeLibraryFileAlias(content='bogus')
-        CreateMergeProposalJob.create(file_alias)
-        transaction.commit()
-        retcode, stdout, stderr = run_script(
-            'cronscripts/create_merge_proposals.py', [])
-        self.assertIn('INFO    Creating lockfile:', stderr)
-        self.assertIn('INFO    Job resulted in OOPS:', stderr)
-        self.assertIn('INFO    Ran 0 CreateMergeProposalJobs.\n', stderr)
-        self.assertEqual('', stdout)

=== modified file 'lib/lp/services/config/schema-lazr.conf'
--- lib/lp/services/config/schema-lazr.conf	2012-04-18 16:23:23 +0000
+++ lib/lp/services/config/schema-lazr.conf	2012-04-27 19:10:25 +0000
@@ -481,18 +481,6 @@
 # datatype: string; a url
 licensing_policy_url: https://help.launchpad.net/Legal/ProjectLicensing
 
-
-[create_merge_proposals]
-# The database user which will be used by this process.
-# datatype: string
-dbuser: create-merge-proposals
-
-# See [error_reports].
-error_dir: none
-
-# See [error_reports].
-oops_prefix: none
-
 [packaging_translations]
 # The database user which will be used by this process.
 # datatype: string

=== added file 'lib/lp/services/mail/errortemplates/mergedirectivenotsupported.txt'
--- lib/lp/services/mail/errortemplates/mergedirectivenotsupported.txt	1970-01-01 00:00:00 +0000
+++ lib/lp/services/mail/errortemplates/mergedirectivenotsupported.txt	2012-04-27 19:10:25 +0000
@@ -0,0 +1,3 @@
+Launchpad no longer accepts merge directives, because this functionality was not being used.  We apologise for the inconvenience.  See https://bugs.launchpad.net/launchpad/+bug/989831 for details.
+
+To create merge proposals from the commandline, consider using "bzr lp-propose-merge".  This command is from the launchpad plugin which usually ships with Bazaar.  Of course, you can also use the Launchpad web site to create merge proposals.

=== modified file 'lib/lp/services/messages/interfaces/message.py'
--- lib/lp/services/messages/interfaces/message.py	2012-01-06 19:48:06 +0000
+++ lib/lp/services/messages/interfaces/message.py	2012-04-27 19:10:25 +0000
@@ -11,7 +11,6 @@
     'IIndexedMessage',
     'IMessage',
     'IMessageChunk',
-    'IMessageJob',
     'IMessageSet',
     'IUserToUserEmail',
     'IndexedMessage',
@@ -47,7 +46,6 @@
 
 from lp import _
 from lp.app.errors import NotFoundError
-from lp.services.job.interfaces.job import IJob
 from lp.services.librarian.interfaces import ILibraryFileAlias
 
 
@@ -287,22 +285,6 @@
         """
 
 
-class IMessageJob(Interface):
-    """Interface for jobs triggered by messages."""
-
-    job = Object(schema=IJob, required=True)
-
-    message_bytes = Object(
-        title=_('Full MIME content of Email.'), required=True,
-        schema=ILibraryFileAlias)
-
-    def getMessage():
-        """Return an email.Message representing this job's message."""
-
-    def destroySelf():
-        """Remove this object (and its job) from the database."""
-
-
 class UnknownSender(NotFoundError):
     """Raised if we cannot lookup an email message's sender in the database"""
 

=== modified file 'lib/lp/services/messages/model/message.py'
--- lib/lp/services/messages/model/message.py	2012-04-13 07:19:14 +0000
+++ lib/lp/services/messages/model/message.py	2012-04-27 19:10:25 +0000
@@ -8,8 +8,6 @@
     'DirectEmailAuthorization',
     'Message',
     'MessageChunk',
-    'MessageJob',
-    'MessageJobAction',
     'MessageSet',
     'UserToUserEmail',
     ]
@@ -32,10 +30,6 @@
 import os.path
 
 from lazr.config import as_timedelta
-from lazr.enum import (
-    DBEnumeratedType,
-    DBItem,
-    )
 import pytz
 from sqlobject import (
     BoolCol,
@@ -67,17 +61,13 @@
 from lp.services.config import config
 from lp.services.database.constants import UTC_NOW
 from lp.services.database.datetimecol import UtcDateTimeCol
-from lp.services.database.enumcol import EnumCol
 from lp.services.database.sqlbase import SQLBase
 from lp.services.encoding import guess as ensure_unicode
-from lp.services.job.model.job import Job
 from lp.services.librarian.interfaces import ILibraryFileAliasSet
-from lp.services.mail.signedmessage import signed_message_from_string
 from lp.services.messages.interfaces.message import (
     IDirectEmailAuthorization,
     IMessage,
     IMessageChunk,
-    IMessageJob,
     IMessageSet,
     InvalidEmailMessage,
     IUserToUserEmail,
@@ -637,59 +627,6 @@
         Store.of(sender).add(self)
 
 
-class MessageJobAction(DBEnumeratedType):
-    """MessageJob action
-
-    The action that a job should perform.
-    """
-
-    CREATE_MERGE_PROPOSAL = DBItem(1, """
-        Create a merge proposal.
-
-        Create a merge proposal from a message which must contain a merge
-        directive.
-        """)
-
-
-class MessageJob(Storm):
-    """A job for processing messages."""
-
-    implements(IMessageJob)
-    # XXX: AaronBentley 2009-02-05 bug=325883: This table is poorly named.
-    __storm_table__ = 'MergeDirectiveJob'
-
-    id = Int(primary=True)
-
-    jobID = Int('job', allow_none=False)
-    job = Reference(jobID, Job.id)
-
-    message_bytesID = Int('merge_directive', allow_none=False)
-    message_bytes = Reference(message_bytesID, 'LibraryFileAlias.id')
-
-    action = EnumCol(enum=MessageJobAction)
-
-    def __init__(self, message_bytes, action):
-        Storm.__init__(self)
-        self.job = Job()
-        self.message_bytes = message_bytes
-        self.action = action
-
-    def destroySelf(self):
-        """See `IMessageJob`."""
-        self.job.destroySelf()
-        Store.of(self).remove(self)
-
-    def sync(self):
-        """Update the database with all changes for this object."""
-        store = Store.of(self)
-        store.flush()
-        store.autoreload(self)
-
-    def getMessage(self):
-        """See `IMessageJob`."""
-        return signed_message_from_string(self.message_bytes.read())
-
-
 class DirectEmailAuthorization:
     """See `IDirectEmailAuthorization`."""
 

=== modified file 'lib/lp/services/messages/tests/test_message.py'
--- lib/lp/services/messages/tests/test_message.py	2012-01-01 02:58:52 +0000
+++ lib/lp/services/messages/tests/test_message.py	2012-04-27 19:10:25 +0000
@@ -3,7 +3,6 @@
 
 __metaclass__ = type
 
-from cStringIO import StringIO
 from email.header import Header
 from email.message import Message
 from email.mime.multipart import MIMEMultipart
@@ -13,24 +12,14 @@
     make_msgid,
     )
 
-from sqlobject import SQLObjectNotFound
 import transaction
-from zope.component import getUtility
 
-from lp.services.job.model.job import Job
-from lp.services.librarian.interfaces import ILibraryFileAliasSet
-from lp.services.mail.sendmail import MailController
-from lp.services.messages.interfaces.message import IMessageJob
 from lp.services.messages.model.message import (
-    MessageJob,
-    MessageJobAction,
     MessageSet,
     )
-from lp.services.webapp.testing import verifyObject
 from lp.testing import (
     login,
     TestCase,
-    TestCaseWithFactory,
     )
 from lp.testing.factory import LaunchpadObjectFactory
 from lp.testing.layers import LaunchpadFunctionalLayer
@@ -200,41 +189,3 @@
             'Treating unknown encoding "booga" as latin-1.'):
             result = MessageSet.decode(self.high_characters, 'booga')
         self.assertEqual(self.high_characters.decode('latin-1'), result)
-
-
-class TestMessageJob(TestCaseWithFactory):
-    """Tests for MessageJob."""
-
-    layer = LaunchpadFunctionalLayer
-
-    def test_providesInterface(self):
-        """Ensure that BranchJob implements IBranchJob."""
-        # Ensure database constraints are satisfied.
-        file_alias = self.factory.makeMergeDirectiveEmail()[1]
-        job = MessageJob(file_alias, MessageJobAction.CREATE_MERGE_PROPOSAL)
-        job.sync()
-        verifyObject(IMessageJob, job)
-
-    def test_destroySelf_destroys_job(self):
-        """Ensure that MessageJob.destroySelf destroys the Job as well."""
-        file_alias = self.factory.makeMergeDirectiveEmail()[1]
-        message_job = MessageJob(
-            file_alias, MessageJobAction.CREATE_MERGE_PROPOSAL)
-        job_id = message_job.job.id
-        message_job.destroySelf()
-        self.assertRaises(SQLObjectNotFound, Job.get, job_id)
-
-    def test_getMessage(self):
-        """getMessage should return a Message with appropriate values."""
-        ctrl = MailController(
-            'from@xxxxxxxxxxx', ['to@xxxxxxxxxxx'], 'subject', 'body')
-        content = ctrl.makeMessage().as_string()
-        lfa = getUtility(ILibraryFileAliasSet).create(
-            'message', len(content), StringIO(content), 'text/x-diff')
-        message_job = MessageJob(lfa, MessageJobAction.CREATE_MERGE_PROPOSAL)
-        transaction.commit()
-        message = message_job.getMessage()
-        self.assertEqual('from@xxxxxxxxxxx', message['From'])
-        self.assertEqual('to@xxxxxxxxxxx', message['To'])
-        self.assertEqual('subject', message['Subject'])
-        self.assertEqual('body', message.get_payload())

=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py	2012-04-23 20:27:38 +0000
+++ lib/lp/testing/factory.py	2012-04-27 19:10:25 +0000
@@ -45,7 +45,6 @@
 from types import InstanceType
 import warnings
 
-from bzrlib.merge_directive import MergeDirective2
 from bzrlib.plugins.builder.recipe import BaseRecipeBranch
 from bzrlib.revision import Revision as BzrRevision
 from lazr.jobrunner.jobrunner import SuspendJobException
@@ -4100,87 +4099,6 @@
                 msg.attach(attachment)
         return msg
 
-    def makeBundleMergeDirectiveEmail(self, source_branch, target_branch,
-                                      signing_context=None, sender=None):
-        """Create a merge directive email from two bzr branches.
-
-        :param source_branch: The source branch for the merge directive.
-        :param target_branch: The target branch for the merge directive.
-        :param signing_context: A GPGSigningContext instance containing the
-            gpg key to sign with.  If None, the message is unsigned.  The
-            context also contains the password and gpg signing mode.
-        :param sender: The `Person` that is sending the email.
-        """
-        md = MergeDirective2.from_objects(
-            source_branch.repository, source_branch.last_revision(),
-            public_branch=source_branch.get_public_branch(),
-            target_branch=target_branch.getInternalBzrUrl(),
-            local_target_branch=target_branch.getInternalBzrUrl(), time=0,
-            timezone=0)
-        email = None
-        if sender is not None:
-            email = removeSecurityProxy(sender).preferredemail.email
-        return self.makeSignedMessage(
-            body='My body', subject='My subject',
-            attachment_contents=''.join(md.to_lines()),
-            signing_context=signing_context, email_address=email)
-
-    def makeMergeDirective(self, source_branch=None, target_branch=None,
-        source_branch_url=None, target_branch_url=None):
-        """Return a bzr merge directive object.
-
-        :param source_branch: The source database branch in the merge
-            directive.
-        :param target_branch: The target database branch in the merge
-            directive.
-        :param source_branch_url: The URL of the source for the merge
-            directive.  Overrides source_branch.
-        :param target_branch_url: The URL of the target for the merge
-            directive.  Overrides target_branch.
-        """
-        from bzrlib.merge_directive import MergeDirective2
-        if source_branch_url is not None:
-            assert source_branch is None
-        else:
-            if source_branch is None:
-                source_branch = self.makeAnyBranch()
-            source_branch_url = (
-                config.codehosting.supermirror_root +
-                source_branch.unique_name)
-        if target_branch_url is not None:
-            assert target_branch is None
-        else:
-            if target_branch is None:
-                target_branch = self.makeAnyBranch()
-            target_branch_url = (
-                config.codehosting.supermirror_root +
-                target_branch.unique_name)
-        return MergeDirective2(
-            'revid', 'sha', 0, 0, target_branch_url,
-            source_branch=source_branch_url, base_revision_id='base-revid',
-            patch='')
-
-    def makeMergeDirectiveEmail(self, body='Hi!\n', signing_context=None):
-        """Create an email with a merge directive attached.
-
-        :param body: The message body to use for the email.
-        :param signing_context: A GPGSigningContext instance containing the
-            gpg key to sign with.  If None, the message is unsigned.  The
-            context also contains the password and gpg signing mode.
-        :return: message, file_alias, source_branch, target_branch
-        """
-        target_branch = self.makeProductBranch()
-        source_branch = self.makeProductBranch(
-            product=target_branch.product)
-        md = self.makeMergeDirective(source_branch, target_branch)
-        message = self.makeSignedMessage(body=body,
-            subject='My subject', attachment_contents=''.join(md.to_lines()),
-            signing_context=signing_context)
-        message_string = message.as_string()
-        file_alias = getUtility(ILibraryFileAliasSet).create(
-            '*', len(message_string), StringIO(message_string), '*')
-        return message, file_alias, source_branch, target_branch
-
     def makeHWSubmission(self, date_created=None, submission_key=None,
                          emailaddress=u'test@xxxxxxxxxxxxx',
                          distroarchseries=None, private=False,
@@ -4446,7 +4364,6 @@
         BaseRecipeBranch,
         DSCFile,
         InstanceType,
-        MergeDirective2,
         Message,
         datetime,
         int,


Follow ups