← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~cjwatson/launchpad/remove-branch-set-api into lp:launchpad

 

Colin Watson has proposed merging lp:~cjwatson/launchpad/remove-branch-set-api into lp:launchpad.

Commit message:
Remove BranchSetAPI.  Since the calling code in bzr relies on password authentication, it can't have worked since at least 2012.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/remove-branch-set-api/+merge/324474

https://code.launchpad.net/~cjwatson/bzr/remove-register-branch/+merge/324472 removes the bzr side.  Ordinarily we'd probably need to go through a deprecation cycle or something, but since this API has been unusable for years we've effectively done so already, albeit by accident.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/remove-branch-set-api into lp:launchpad.
=== modified file 'lib/lp/code/configure.zcml'
--- lib/lp/code/configure.zcml	2017-05-04 16:02:40 +0000
+++ lib/lp/code/configure.zcml	2017-05-23 12:56:33 +0000
@@ -182,11 +182,6 @@
 
   <xmlrpc:view
       for="lp.code.interfaces.codehosting.IBazaarApplication"
-      interface="lp.code.xmlrpc.branch.IBranchSetAPI"
-      class="lp.code.xmlrpc.branch.BranchSetAPI"
-      permission="launchpad.AnyPerson"/>
-  <xmlrpc:view
-      for="lp.code.interfaces.codehosting.IBazaarApplication"
       interface="lp.code.xmlrpc.branch.IPublicCodehostingAPI"
       class="lp.code.xmlrpc.branch.PublicCodehostingAPI"
       permission="zope.Public"/>

=== modified file 'lib/lp/code/doc/branch-xmlrpc.txt'
--- lib/lp/code/doc/branch-xmlrpc.txt	2016-02-04 04:59:12 +0000
+++ lib/lp/code/doc/branch-xmlrpc.txt	2017-05-23 12:56:33 +0000
@@ -1,310 +1,8 @@
-IBranchSetAPI
-=============
+IPublicCodehostingAPI
+=====================
 
-    >>> from zope.security.proxy import removeSecurityProxy
-    >>> from datetime import datetime
-    >>> import pytz
     >>> import xmlrpclib
     >>> from lp.testing.xmlrpc import XMLRPCTestTransport
-    >>> branchset_api = xmlrpclib.ServerProxy(
-    ...     'http://foo.bar@xxxxxxxxxxxxx:test@xxxxxxxxxxxxxxxxxxxx/bazaar/',
-    ...     transport=XMLRPCTestTransport())
-
-
-register_branch
-===============
-
-register_branch(branch_url, branch_name, branch_title,
-                branch_description, author_email, product_name,
-                owner_name='')
-
-Let's register a branch using register_branch(). First we make sure that
-there is no branch with the URL we are going to register.
-
-    >>> from lp.code.interfaces.branchlookup import IBranchLookup
-    >>> branch_url = 'http://foo.com/branch'
-    >>> getUtility(IBranchLookup).getByUrl(branch_url) is None
-    True
-
-The only thing that we have to supply is the branch url. The rest is
-optional, so we pass '' for the rest of the parameters. The reason we
-pass '' is that XMLRPC doesn't allow optional parameters, and None is an
-extension to XMLRPC which we don't want to rely on. We use the currently
-authenticated user as the owner of the branch.
-
-    >>> branchset_api.register_branch(
-    ...      'http://foo.com/branch', '', '', '', '', '')
-    'http://code.launchpad.dev/~name16/+junk/branch'
-
-Now we can see that a branch got registered:
-
-    >>> new_branch = getUtility(IBranchLookup).getByUrl(branch_url)
-
-The author_email is now ignored as the author attribute has been
-removed from the branch object.
-
-    >>> print new_branch.owner.displayname
-    Foo Bar
-
-The name got set to the last component of the URL since it wasn't
-specified:
-
-    >>> print new_branch.name
-    branch
-
-Since we didn't specify product, title or description, they are None:
-
-    >>> new_branch.product is None
-    True
-
-Also, Launchpad is scheduled to mirror this branch on its next mirror run:
-
-    >>> removeSecurityProxy(new_branch).sync()
-    >>> print new_branch.next_mirror_time is not None
-    True
-    >>> print new_branch.next_mirror_time < datetime.now(pytz.timezone('UTC'))
-    True
-
-(We remove the security proxy in order to ensure that next_mirror_time has a
-real object in it, rather than an expression builder.)
-
-Let's register a branch specifying the name, description and product as
-well:
-
-    >>> other_branch_url = 'http://foo.com/other_branch'
-    >>> branchset_api.register_branch(
-    ...      other_branch_url, 'branch_name', 'branch_title',
-    ...      'branch description', 'test@xxxxxxxxxxxxx', 'evolution')
-    'http://code.launchpad.dev/~name16/evolution/branch_name'
-
-    >>> new_branch = getUtility(IBranchLookup).getByUrl(other_branch_url)
-    >>> print new_branch.owner.displayname
-    Foo Bar
-
-    >>> print new_branch.name
-    branch_name
-    >>> print new_branch.product.displayname
-    Evolution
-
-If we try to register a branch with a branch name that is already used:
-
-    >>> yet_another_branch_url = 'http://foo.com/yet_another_branch'
-    >>> branchset_api.register_branch(
-    ...      yet_another_branch_url, 'branch_name', 'branch_title',
-    ...      'branch description', 'test@xxxxxxxxxxxxx', 'evolution')
-    Traceback (most recent call last):
-    ...
-    Fault: <Fault 220: 'Branch name already in use:
-      A branch with the name "branch_name" already exists
-      for name16 in evolution.'>
-
-However a branch can be registered with a name used by a different user.
-
-    >>> evo_main_url = 'http://foo.example.com/evo/main'
-    >>> branchset_api.register_branch(
-    ...      evo_main_url, 'main', 'branch_title',
-    ...      'branch description', 'test@xxxxxxxxxxxxx', 'evolution')
-    'http://code.launchpad.dev/~name16/evolution/main'
-
-This check must also detect branch name conflict for +junk branches:
-
-    >>> branchset_api.register_branch(
-    ...      yet_another_branch_url, 'branch', '', '', '', '')
-    Traceback (most recent call last):
-    ...
-    Fault: <Fault 220: 'Branch name already in use:
-      A junk branch with the name "branch" already exists for name16.'>
-
-If we give a product name that doesn't exist, we get an error:
-
-    >>> new_branch_url = 'http://foo.com/new_branch'
-    >>> branchset_api.register_branch(
-    ...      new_branch_url, 'branch_name', 'branch_title',
-    ...      'branch description', 'test@xxxxxxxxxxxxx', 'non-existing')
-    Traceback (most recent call last):
-    ...
-    Fault: <Fault 10: 'No such project: non-existing'>
-
-If we try to register a branch with an invalid URI:
-
-    >>> invalid_uri = '.'
-    >>> branchset_api.register_branch(
-    ...     invalid_uri, 'branch_name', 'branch title', 'branch description',
-    ...     'test@xxxxxxxxxxxxx', 'evolution')
-    Traceback (most recent call last):
-    ...
-    Fault: <Fault 120: 'Invalid URL: .\n&quot;.&quot; is not a valid URI'>
-
-If we try to register a URL with a unsupported scheme:
-
-    >>> bad_scheme = 'svn://chinstrap.ubuntu.com/foo/bar/baz'
-    >>> branchset_api.register_branch(
-    ...     bad_scheme, 'branch_name', 'branch title', 'branch description',
-    ...     'test@xxxxxxxxxxxxx', 'evolution')
-    Traceback (most recent call last):
-    ...
-    Fault: <Fault 120: 'Invalid URL:
-    svn://chinstrap.ubuntu.com/foo/bar/baz\nThe URI scheme
-    &quot;svn&quot; is not allowed.  Only URIs with the following
-    schemes may be used: bzr+ssh, ftp, http, https, sftp'>
-
-If we try to register a root URL:
-
-    >>> root_url = 'http://example.com/'
-    >>> branchset_api.register_branch(
-    ...     root_url, 'branch_name', 'branch title', 'branch description',
-    ...     'test@xxxxxxxxxxxxx', 'evolution')
-    Traceback (most recent call last):
-    ...
-    Fault: <Fault 120: 'Invalid URL: http://example.com\nURLs for branches
-    cannot point to the root of a site.'>
-
-If we try to register a URL in launchpad.net (actually, launchpad.dev because
-we are in the testing environment):
-
-    >>> launchpad_url = 'https://blueprints.launchpad.dev/foo/bar/baz'
-    >>> branchset_api.register_branch(
-    ...     launchpad_url, 'branch_name', 'branch title',
-    ...     'branch description', 'test@xxxxxxxxxxxxx', 'evolution')
-    Traceback (most recent call last):
-    ...
-    Fault: <Fault 120:
-    'Invalid URL: https://blueprints.launchpad.dev/foo/bar/baz\nFor
-    Launchpad to mirror a branch, the original branch cannot be on
-    <code>launchpad.dev</code>.'>
-
-Registering a branch name that ends in a slash works, but the slash
-gets removed from the stored URL:
-
-    >>> branchset_api.register_branch(
-    ...     new_branch_url + '/', 'new_branch', 'branch_title',
-    ...     'branch_description', 'test@xxxxxxxxxxxxx', 'evolution')
-    'http://code.launchpad.dev/~name16/evolution/new_branch'
-
-    >>> new_branch = getUtility(IBranchLookup).getByUrl(new_branch_url)
-    >>> print new_branch.url
-    http://foo.com/new_branch
-    >>> print new_branch.owner.name
-    name16
-    >>> print new_branch.product.name
-    evolution
-    >>> print new_branch.name
-    new_branch
-
-
-If we try to register a branch which is already registered in Launchpad:
-
-    >>> getUtility(IBranchLookup).getByUrl(other_branch_url) is not None
-    True
-    >>> branchset_api.register_branch(
-    ...      other_branch_url, 'branch_name', 'branch_title',
-    ...      'branch description', 'test@xxxxxxxxxxxxx', 'evolution')
-    Traceback (most recent call last):
-    ...
-    Fault: <Fault 50: 'http://foo.com/other_branch is already registered.'>
-
-
-We get the same error if we try to register the branch with a slash appended:
-    >>> branchset_api.register_branch(
-    ...      other_branch_url + '/', 'branch_name', 'branch_title',
-    ...      'branch description', 'test@xxxxxxxxxxxxx', 'evolution')
-    Traceback (most recent call last):
-    ...
-    Fault: <Fault 50: 'http://foo.com/other_branch is already registered.'>
-
-Attempting to register a branch for a product where the branch visibility
-policy is forbidden will cause a fault result.
-
-    >>> test_user_api = xmlrpclib.ServerProxy(
-    ...     'http://no-priv@xxxxxxxxxxxxx:test@xxxxxxxxxxxxxxxxxxxx/bazaar/',
-    ...     transport=XMLRPCTestTransport())
-    >>> test_user_api.register_branch(
-    ...     'http://foo.com/bar', 'branch_name', 'branch_title',
-    ...     'branch description', 'no-priv@xxxxxxxxxxxxx', 'landscape')
-    Traceback (most recent call last):
-    ...
-    Fault: <Fault 110: 'You are not allowed to create a branch for project:
-    The Landscape Project'>
-
-We can register a branch as being owned by a team, rather than just an
-individual:
-
-    >>> branchset_api.register_branch(
-    ...     'http://example.com/unregistered-as-yet', 'team-branch',
-    ...     'new-title', 'new-description', 'test@xxxxxxxxxxxxx',
-    ...     'evolution', 'name18')
-    'http://code.launchpad.dev/~name18/evolution/team-branch'
-
-If the team doesn't exist, we raise a Fault that says so:
-
-    >>> branchset_api.register_branch(
-    ...     'http://example.com/team-dont-exist', 'team-dont-exist',
-    ...     'title', 'description', 'test@xxxxxxxxxxxxx', 'evolution',
-    ...     'no-existy-teamo')
-    Traceback (most recent call last):
-    ...
-    Fault: <Fault 200: 'No such person or team: no-existy-teamo'>
-
-We can only register branches as belonging to a team that we are a
-member of. Doing otherwise raises a Fault:
-
-    >>> branchset_api.register_branch(
-    ...     'http://example.com/invalid-team', 'invalid-team', 'title',
-    ...     'description', 'test@xxxxxxxxxxxxx', 'evolution',
-    ...     'landscape-developers')
-    Traceback (most recent call last):
-    ...
-    Fault: <Fault 250: 'name16 is not a member of landscape-developers.'>
-
-Trying to register a branch with an invalid name will fail with a fault that
-explains the problem:
-
-    >>> branchset_api.register_branch(
-    ...     'http://example.com/invalid-branch-name', '.bzr', 'title', 'desc',
-    ...     'test@xxxxxxxxxxxxx', 'evolution')
-    Traceback (most recent call last):
-    ...
-    Fault: <Fault 260: 'Invalid branch name &#x27;.bzr&#x27;. Branch names must ...
-
-Crazy unicode characters are also invalid:
-
-    >>> branchset_api.register_branch(
-    ...     'http://example.com/invalid-branch-name',
-    ...      u'\N{latin small letter e with acute}', 'title', 'desc',
-    ...     'test@xxxxxxxxxxxxx', 'evolution')
-    Traceback (most recent call last):
-    ...
-    Fault: <Fault 260: u'Invalid branch name &#x27;\xe9&#x27;. Branch names must ...
-
-
-link_branch_to_bug(branch_url, bug_id)
-======================================
-
-link_branch_to_bug() associates a branch with a bug. Let's associate
-the branch we registered with bug 1. If the link is successful, the bug
-URL is returned.
-
-    >>> branchset_api.link_branch_to_bug(other_branch_url, '1')
-    'http://bugs.launchpad.dev/bugs/1'
-
-Let's take a look to see that the branch actually got linked to the bug:
-
-    >>> from lp.bugs.interfaces.bug import IBugSet
-    >>> bug_one = getUtility(IBugSet).get(1)
-    >>> for branch in bug_one.linked_branches:
-    ...     print branch.url
-    http://foo.com/other_branch
-
-We get an error if we try to specify a non-existant branch or bug:
-
-    >>> branchset_api.link_branch_to_bug('http://foo.com/unknown', '1')
-    Traceback (most recent call last):
-    ...
-    Fault: <Fault 30: 'No such branch: http://foo.com/unknown'>
-    >>> branchset_api.link_branch_to_bug(branch_url, '99')
-    Traceback (most recent call last):
-    ...
-    Fault: <Fault 40: 'No such bug: 99'>
 
 
 resolve_lp_path
@@ -319,9 +17,7 @@
 This API is deprecated, and will eventually be replaced with an
 equivalent method in the new Launchpad API infrastructure.
 
-Note that authentication is not required to use this method.
-
-    >>> branchset_api = xmlrpclib.ServerProxy(
+    >>> public_codehosting_api = xmlrpclib.ServerProxy(
     ...     'http://xmlrpc.launchpad.dev/bazaar/',
     ...     transport=XMLRPCTestTransport())
 
@@ -329,7 +25,8 @@
 On success, resolve_lp_path returns a dict containing a single key,
 'urls':
 
-    >>> results = branchset_api.resolve_lp_path('~vcs-imports/evolution/main')
+    >>> results = public_codehosting_api.resolve_lp_path(
+    ...     '~vcs-imports/evolution/main')
     >>> print results.keys()
     ['urls']
 
@@ -337,7 +34,8 @@
 The value of a key is a list of URLs from which the branch can be
 accessed:
 
-    >>> results = branchset_api.resolve_lp_path('~vcs-imports/evolution/main')
+    >>> results = public_codehosting_api.resolve_lp_path(
+    ...     '~vcs-imports/evolution/main')
     >>> for url in results['urls']:
     ...     print url
     bzr+ssh://bazaar.launchpad.dev/~vcs-imports/evolution/main

=== modified file 'lib/lp/code/model/branchnamespace.py'
--- lib/lp/code/model/branchnamespace.py	2015-10-09 15:49:14 +0000
+++ lib/lp/code/model/branchnamespace.py	2017-05-23 12:56:33 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2015 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Implementations of `IBranchNamespace`."""
@@ -199,10 +199,10 @@
             raise BranchExists(existing_branch)
 
         # Not all code paths that lead to branch creation go via a
-        # schema-validated form (e.g. the register_branch XML-RPC call or
-        # pushing a new branch to codehosting), so we validate the branch name
-        # here to give a nicer error message than 'ERROR: new row for relation
-        # "branch" violates check constraint "valid_name"...'.
+        # schema-validated form (e.g. pushing a new branch to codehosting),
+        # so we validate the branch name here to give a nicer error message
+        # than 'ERROR: new row for relation "branch" violates check
+        # constraint "valid_name"...'.
         IBranch['name'].validate(unicode(name))
 
     def validateMove(self, branch, mover, name=None):

=== modified file 'lib/lp/code/xmlrpc/branch.py'
--- lib/lp/code/xmlrpc/branch.py	2015-09-28 17:38:45 +0000
+++ lib/lp/code/xmlrpc/branch.py	2017-05-23 12:56:33 +0000
@@ -1,12 +1,10 @@
-# Copyright 2009-2012 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Branch XMLRPC API."""
 
 __metaclass__ = type
 __all__ = [
-    'BranchSetAPI',
-    'IBranchSetAPI',
     'IPublicCodehostingAPI',
     'PublicCodehostingAPI',
     ]
@@ -21,21 +19,14 @@
     Interface,
     )
 
-from lp.app.errors import NotFoundError
-from lp.app.validators import LaunchpadValidationError
-from lp.bugs.interfaces.bug import IBugSet
 from lp.code.enums import BranchType
 from lp.code.errors import (
-    BranchCreationException,
-    BranchCreationForbidden,
     CannotHaveLinkedBranch,
     InvalidNamespace,
     NoLinkedBranch,
     NoSuchBranch,
     )
-from lp.code.interfaces.branch import IBranch
 from lp.code.interfaces.branchlookup import IBranchLookup
-from lp.code.interfaces.branchnamespace import get_branch_namespace
 from lp.code.interfaces.codehosting import (
     BRANCH_ALIAS_PREFIX,
     compose_public_url,
@@ -45,134 +36,18 @@
     NoSuchDistroSeries,
     NoSuchSourcePackageName,
     )
-from lp.registry.interfaces.person import (
-    IPersonSet,
-    NoSuchPerson,
-    )
+from lp.registry.interfaces.person import NoSuchPerson
 from lp.registry.interfaces.product import (
     InvalidProductName,
-    IProductSet,
     NoSuchProduct,
     )
 from lp.registry.interfaces.productseries import NoSuchProductSeries
 from lp.services.config import config
-from lp.services.webapp import (
-    canonical_url,
-    LaunchpadXMLRPCView,
-    )
-from lp.services.webapp.interfaces import ILaunchBag
+from lp.services.webapp import LaunchpadXMLRPCView
 from lp.xmlrpc import faults
 from lp.xmlrpc.helpers import return_fault
 
 
-class IBranchSetAPI(Interface):
-    """An XMLRPC interface for dealing with branches.
-
-    This XML-RPC interface was introduced to support Bazaar 0.8-2, which is
-    included in Ubuntu 6.06. This interface cannot be removed until Ubuntu
-    6.06 is end-of-lifed.
-    """
-
-    def register_branch(branch_url, branch_name, branch_title,
-                        branch_description, author_email, product_name,
-                        owner_name=''):
-        """Register a new branch in Launchpad."""
-
-    def link_branch_to_bug(branch_url, bug_id):
-        """Link the branch to the bug."""
-
-
-@implementer(IBranchSetAPI)
-class BranchSetAPI(LaunchpadXMLRPCView):
-
-    def register_branch(self, branch_url, branch_name, branch_title,
-                        branch_description, author_email, product_name,
-                        owner_name=''):
-        """See IBranchSetAPI."""
-        registrant = getUtility(ILaunchBag).user
-        assert registrant is not None, (
-            "register_branch shouldn't be accessible to unauthenicated"
-            " requests.")
-
-        person_set = getUtility(IPersonSet)
-        if owner_name:
-            owner = person_set.getByName(owner_name)
-            if owner is None:
-                return faults.NoSuchPersonWithName(owner_name)
-            if not registrant.inTeam(owner):
-                return faults.NotInTeam(registrant.name, owner_name)
-        else:
-            owner = registrant
-
-        if product_name:
-            product = getUtility(IProductSet).getByName(product_name)
-            if product is None:
-                return faults.NoSuchProduct(product_name)
-        else:
-            product = None
-
-        # Branch URLs in Launchpad do not end in a slash, so strip any
-        # slashes from the end of the URL.
-        branch_url = branch_url.rstrip('/')
-
-        branch_lookup = getUtility(IBranchLookup)
-        existing_branch = branch_lookup.getByUrl(branch_url)
-        if existing_branch is not None:
-            return faults.BranchAlreadyRegistered(branch_url)
-
-        try:
-            unicode_branch_url = branch_url.decode('utf-8')
-            IBranch['url'].validate(unicode_branch_url)
-        except LaunchpadValidationError as exc:
-            return faults.InvalidBranchUrl(branch_url, exc)
-
-        # We want it to be None in the database, not ''.
-        if not branch_description:
-            branch_description = None
-        if not branch_title:
-            branch_title = None
-
-        if not branch_name:
-            branch_name = unicode_branch_url.split('/')[-1]
-
-        try:
-            if branch_url:
-                branch_type = BranchType.MIRRORED
-            else:
-                branch_type = BranchType.HOSTED
-            namespace = get_branch_namespace(owner, product)
-            branch = namespace.createBranch(
-                branch_type=branch_type,
-                name=branch_name, registrant=registrant,
-                url=branch_url, title=branch_title,
-                summary=branch_description)
-            if branch_type == BranchType.MIRRORED:
-                branch.requestMirror()
-        except BranchCreationForbidden:
-            return faults.BranchCreationForbidden(product.displayname)
-        except BranchCreationException as err:
-            return faults.BranchNameInUse(err)
-        except LaunchpadValidationError as err:
-            return faults.InvalidBranchName(err)
-
-        return canonical_url(branch)
-
-    def link_branch_to_bug(self, branch_url, bug_id):
-        """See IBranchSetAPI."""
-        branch = getUtility(IBranchLookup).getByUrl(url=branch_url)
-        if branch is None:
-            return faults.NoSuchBranch(branch_url)
-        try:
-            bug = getUtility(IBugSet).get(bug_id)
-        except NotFoundError:
-            return faults.NoSuchBug(bug_id)
-        # Since this API is controlled using launchpad.AnyPerson there must be
-        # an authenticated person, so use this person as the registrant.
-        registrant = getUtility(ILaunchBag).user
-        bug.linkBranch(branch, registrant=registrant)
-        return canonical_url(bug)
-
-
 class IPublicCodehostingAPI(Interface):
     """The public codehosting API."""
 


Follow ups