← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~sinzui/launchpad/remove-register-branch into lp:launchpad

 

Curtis Hovey has proposed merging lp:~sinzui/launchpad/remove-register-branch into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #115965 in Launchpad itself: "people use the "Register branch" form to request code imports"
  https://bugs.launchpad.net/launchpad/+bug/115965
  Bug #288645 in Launchpad itself: ""Register a branch" on hosted branches is confusing"
  https://bugs.launchpad.net/launchpad/+bug/288645
  Bug #527794 in Launchpad itself: "Put a "Register branch" under "Get involved" on projects' main page"
  https://bugs.launchpad.net/launchpad/+bug/527794
  Bug #836088 in Launchpad itself: ""submit code" link leads to confusing page"
  https://bugs.launchpad.net/launchpad/+bug/836088

For more details, see:
https://code.launchpad.net/~sinzui/launchpad/remove-register-branch/+merge/96649

Remove the register/add/set an empty branch action.

    Pre-implementation: no one

Launchpad should not encourage users to create an empty hosted branches.
This action does not help users associate code with a project. It is
often a false step. There are many links to the +addbranch page that can
be deleted. Pages need to explain how to push a branch. +setbranch should
not list creating an empty branch as an options.

This work is undertaken as a preliminary step to update the code
configuration pages to work with sharing.

My apologies for the size of this diff. The branch only adds a few lines
the instruct users to push a branch. Most of this branch is deletions.
--------------------------------------------------------------------

RULES

    * Remove the option create an empty branch from forms.
    * Ensure users are directed to instruction to push a branch to Lp.


QA

    * Visit https://code.qastaging.launchpad.net/gdp
    * Verify the page explains how to push a branch to the series.
      bzr push lp:~me/gdp/BRANCHNAME

    * Visit https://qastaging.launchpad.net/gdp/0.5.x
    * Verify the page does not have a Submit code link.

    * Visit https://qstaging.launchpad.net/gdp/0.5.x/+setbranch
    * Verify there are two options to link to an existing branch or
      import a branch. This option is *not* present:
      Create a new, empty branch in Launchpad and link to this series
    * Verify the page explains how to push a branch to the series.
      bzr push lp:~me/gdp/BRANCHNAME

    * Visit https://code.qastaging.launchpad.net/~me
    * Verify there is not a link Register a branch.
    * Verify the page instructs you how to push your branch:
      bzr push lp:~me/+junk/BRANCHNAME


LINT

    lib/lp/code/browser/branch.py
    lib/lp/code/browser/branchlisting.py
    lib/lp/code/browser/configure.zcml
    lib/lp/code/browser/tests/test_branch.py
    lib/lp/code/browser/tests/test_product.py
    lib/lp/code/javascript/tests/test_productseries-setbranch.html
    lib/lp/code/javascript/tests/test_productseries_setbranch.js
    lib/lp/code/stories/branches/xx-branch-deletion.txt
    lib/lp/code/stories/branches/xx-product-branches.txt
    lib/lp/code/templates/bazaar-index.pt
    lib/lp/code/templates/person-branches.pt
    lib/lp/code/templates/product-branch-summary.pt
    lib/lp/code/templates/product-branches.pt
    lib/lp/registry/browser/pillar.py
    lib/lp/registry/browser/product.py
    lib/lp/registry/browser/productseries.py
    lib/lp/registry/browser/tests/pillar-views.txt
    lib/lp/registry/browser/tests/productseries-setbranch-view.txt
    lib/lp/registry/browser/tests/productseries-views.txt
    lib/lp/registry/stories/productseries/xx-productseries-index.txt
    lib/lp/registry/stories/productseries/xx-productseries-set-branch.txt
    lib/lp/registry/templates/productseries-codesummary.pt
    lib/lp/registry/templates/productseries-linkbranch.pt
    lib/lp/registry/templates/productseries-setbranch.pt



TEST

    ./bin/test -vv -t xx-product-branches -t productseries-setbranch-views lp

    ./bin/test -vv lp.code.browser.tests.test_branch
    ./bin/test -vv lp.code.tests.test_yui
    ./bin/test -vv -t xx-branch-deletion lp.code.tests.test_doc
    ./bin/test -vv -t pillar-views -t productseries-views lp.registry.browser
    ./bin/test -vv -t xx-productseries lp.registry.tests.test_doc


IMPLEMENTATION

Add push instructions to the branch listing page template and set project
branch template.
    lib/lp/code/stories/branches/xx-product-branches.txt
    lib/lp/code/browser/tests/test_product.py
    lib/lp/registry/templates/productseries-setbranch.pt
    lib/lp/registry/browser/tests/productseries-setbranch-view.txt

Removed widgets, views, templates, and tests that encouraged users to
register an empty branch that no one could user. A few bad stories were
using the +addbranch to setup conditions; I change the stories to use
the factory.
    lib/lp/code/browser/branch.py
    lib/lp/code/browser/branchlisting.py
    lib/lp/code/browser/configure.zcml
    lib/lp/code/browser/tests/test_branch.py
    lib/lp/code/javascript/tests/test_productseries-setbranch.html
    lib/lp/code/javascript/tests/test_productseries_setbranch.js
    lib/lp/code/stories/branches/xx-branch-deletion.txt
    lib/lp/code/templates/bazaar-index.pt
    lib/lp/code/templates/person-branches.pt
    lib/lp/code/templates/product-branch-summary.pt
    lib/lp/code/templates/product-branches.pt
    lib/lp/registry/browser/pillar.py
    lib/lp/registry/browser/product.py
    lib/lp/registry/browser/productseries.py
    lib/lp/registry/browser/tests/pillar-views.txt
    lib/lp/registry/browser/tests/productseries-views.txt
    lib/lp/registry/stories/productseries/xx-productseries-index.txt
    lib/lp/registry/stories/productseries/xx-productseries-set-branch.txt
    lib/lp/registry/templates/productseries-codesummary.pt
    lib/lp/registry/templates/productseries-linkbranch.pt
-- 
https://code.launchpad.net/~sinzui/launchpad/remove-register-branch/+merge/96649
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~sinzui/launchpad/remove-register-branch into lp:launchpad.
=== modified file 'lib/lp/code/browser/branch.py'
--- lib/lp/code/browser/branch.py	2012-02-14 03:49:35 +0000
+++ lib/lp/code/browser/branch.py	2012-03-08 20:07:31 +0000
@@ -6,7 +6,6 @@
 __metaclass__ = type
 
 __all__ = [
-    'BranchAddView',
     'BranchContextMenu',
     'BranchDeletionView',
     'BranchEditStatusView',
@@ -103,7 +102,6 @@
     CodeImportResultStatus,
     CodeImportReviewStatus,
     RevisionControlSystems,
-    UICreatableBranchType,
     )
 from lp.code.errors import (
     BranchCreationForbidden,
@@ -122,10 +120,8 @@
 from lp.code.interfaces.branchcollection import IAllBranches
 from lp.code.interfaces.branchmergeproposal import IBranchMergeProposal
 from lp.code.interfaces.branchnamespace import IBranchNamespacePolicy
-from lp.code.interfaces.branchtarget import IBranchTarget
 from lp.code.interfaces.codereviewvote import ICodeReviewVoteReference
 from lp.registry.interfaces.person import (
-    IPerson,
     IPersonSet,
     )
 from lp.registry.interfaces.productseries import IProductSeries
@@ -1154,77 +1150,6 @@
         return {'reviewer': self.context.code_reviewer}
 
 
-class BranchAddView(LaunchpadFormView, BranchNameValidationMixin):
-
-    class schema(Interface):
-        use_template(
-            IBranch, include=['owner', 'name', 'lifecycle_status'])
-
-    for_input = True
-    field_names = ['owner', 'name', 'lifecycle_status']
-
-    branch = None
-    custom_widget('lifecycle_status', LaunchpadRadioWidgetWithDescription)
-
-    initial_focus_widget = 'name'
-
-    @property
-    def page_title(self):
-        return 'Register a branch'
-
-    @property
-    def initial_values(self):
-        return {
-            'owner': self.default_owner,
-            'branch_type': UICreatableBranchType.MIRRORED}
-
-    @property
-    def target(self):
-        """The branch target for the context."""
-        return IBranchTarget(self.context)
-
-    @property
-    def default_owner(self):
-        """The default owner of branches in this context.
-
-        If the context is a person, then it's the context. If the context is
-        not a person, then the default owner is the currently logged-in user.
-        """
-        return IPerson(self.context, self.user)
-
-    @action('Register Branch', name='add')
-    def add_action(self, action, data):
-        """Handle a request to create a new branch for this product."""
-        try:
-            namespace = self.target.getNamespace(data['owner'])
-            self.branch = namespace.createBranch(
-                branch_type=BranchType.HOSTED,
-                name=data['name'],
-                registrant=self.user,
-                url=None,
-                lifecycle_status=data['lifecycle_status'])
-        except BranchCreationForbidden:
-            self.addError(
-                "You are not allowed to create branches in %s." %
-                self.context.displayname)
-        except BranchExists, e:
-            self._setBranchExists(e.existing_branch)
-        else:
-            self.next_url = canonical_url(self.branch)
-
-    def validate(self, data):
-        owner = data['owner']
-
-        if not self.user.inTeam(owner):
-            self.setFieldError(
-                'owner',
-                'You are not a member of %s' % owner.displayname)
-
-    @property
-    def cancel_url(self):
-        return canonical_url(self.context)
-
-
 class BranchSubscriptionsView(LaunchpadView):
     """The view for the branch subscriptions portlet.
 

=== modified file 'lib/lp/code/browser/branchlisting.py'
--- lib/lp/code/browser/branchlisting.py	2012-02-21 12:11:11 +0000
+++ lib/lp/code/browser/branchlisting.py	2012-03-08 20:07:31 +0000
@@ -838,7 +838,7 @@
 
     usedfor = IPerson
     facet = 'branches'
-    links = ['registered', 'owned', 'subscribed', 'addbranch',
+    links = ['registered', 'owned', 'subscribed',
              'active_reviews', 'mergequeues', 'source_package_recipes',
              'simplified_subscribed', 'simplified_registered',
              'simplified_owned', 'simplified_active_reviews']
@@ -980,17 +980,6 @@
             'active reviews')
         return Link('+activereviews', text)
 
-    def addbranch(self):
-        if self.user is None:
-            enabled = False
-        else:
-            enabled = self.user.inTeam(self.context)
-        text = 'Register a branch'
-        summary = 'Register a new Bazaar branch'
-        return Link(
-            '+addbranch', text, summary, icon='add', enabled=enabled,
-            site='code')
-
 
 class PersonProductBranchesMenu(PersonBranchesMenu):
 
@@ -1150,7 +1139,6 @@
     usedfor = IProduct
     facet = 'branches'
     links = [
-        'branch_add',
         'list_branches',
         'active_reviews',
         'code_import',
@@ -1160,11 +1148,6 @@
         'active_review_count',
         ]
 
-    def branch_add(self):
-        text = 'Register a branch'
-        summary = 'Register a new Bazaar branch for this project'
-        return Link('+addbranch', text, summary, icon='add', site='code')
-
     def list_branches(self):
         text = 'List branches'
         summary = 'List the branches for this project'

=== modified file 'lib/lp/code/browser/configure.zcml'
--- lib/lp/code/browser/configure.zcml	2012-02-01 19:18:30 +0000
+++ lib/lp/code/browser/configure.zcml	2012-03-08 20:07:31 +0000
@@ -878,13 +878,6 @@
             name="+activereviews"
             template="../templates/active-reviews.pt"/>
         <browser:page
-            name="+addbranch"
-            for="lp.registry.interfaces.person.IPerson"
-            layer="lp.code.publisher.CodeLayer"
-            class="lp.code.browser.branch.BranchAddView"
-            permission="launchpad.AnyPerson"
-            template="../templates/branch-add.pt"/>
-        <browser:page
             for="lp.registry.interfaces.person.IPerson"
             layer="lp.code.publisher.CodeLayer"
             class="lp.code.browser.branchlisting.PersonTeamBranchesView"
@@ -927,22 +920,6 @@
         name="+count-summary"
         template="../templates/branch-count-summary.pt"/>
 
-    <browser:page
-        name="+addbranch"
-        for="lp.registry.interfaces.product.IProduct"
-        layer="lp.code.publisher.CodeLayer"
-        class="lp.code.browser.branch.BranchAddView"
-        permission="launchpad.AnyPerson"
-        template="../templates/branch-add.pt"/>
-
-    <browser:page
-        name="+addbranch"
-        for="lp.registry.interfaces.productseries.IProductSeries"
-        layer="lp.code.publisher.CodeLayer"
-        class="lp.code.browser.branch.BranchAddView"
-        permission="launchpad.AnyPerson"
-        template="../templates/branch-add.pt"/>
-
     <browser:menus
         classes="ProductBranchesMenu"
         module="lp.code.browser.branchlisting"/>

=== modified file 'lib/lp/code/browser/tests/test_branch.py'
--- lib/lp/code/browser/tests/test_branch.py	2012-01-20 03:30:06 +0000
+++ lib/lp/code/browser/tests/test_branch.py	2012-03-08 20:07:31 +0000
@@ -19,7 +19,6 @@
     UNRESOLVED_BUGTASK_STATUSES,
     )
 from lp.code.browser.branch import (
-    BranchAddView,
     BranchMirrorStatusView,
     BranchReviewerEditView,
     BranchView,
@@ -31,11 +30,9 @@
     RepositoryFormat,
     )
 from lp.code.enums import (
-    BranchLifecycleStatus,
     BranchType,
     BranchVisibilityRule,
     )
-from lp.code.interfaces.branchtarget import IBranchTarget
 from lp.registry.interfaces.person import PersonVisibility
 from lp.services.config import config
 from lp.services.database.constants import UTC_NOW
@@ -188,29 +185,6 @@
             "This is a short error message.",
             branch_view.mirror_status_message)
 
-    def testBranchAddRequests(self):
-        """Registering a branch that requests a mirror."""
-        arbitrary_person = self.factory.makePerson()
-        arbitrary_product = self.factory.makeProduct()
-        login_person(arbitrary_person)
-        try:
-            add_view = BranchAddView(arbitrary_person, self.request)
-            add_view.initialize()
-            data = {
-                'branch_type': BranchType.HOSTED,
-                'name': 'some-branch',
-                'title': 'Branch Title',
-                'summary': '',
-                'lifecycle_status': BranchLifecycleStatus.DEVELOPMENT,
-                'whiteboard': '',
-                'owner': arbitrary_person,
-                'author': arbitrary_person,
-                'product': arbitrary_product,
-                }
-            add_view.add_action.success(data)
-        finally:
-            logout()
-
     def testShowMergeLinksOnManyBranchProject(self):
         # The merge links are shown on projects that have multiple branches.
         product = self.factory.makeProduct(name='super-awesome-project')
@@ -672,36 +646,6 @@
         self.assertIsNone(reviews_list.find('a', text='Privateteam'))
 
 
-class TestBranchAddView(TestCaseWithFactory):
-    """Test the BranchAddView view."""
-
-    layer = DatabaseFunctionalLayer
-
-    def setUp(self):
-        super(TestBranchAddView, self).setUp()
-        self.person = self.factory.makePerson()
-        login_person(self.person)
-        self.request = LaunchpadTestRequest()
-
-    def tearDown(self):
-        logout()
-        super(TestBranchAddView, self).tearDown()
-
-    def get_view(self, context):
-        view = BranchAddView(context, self.request)
-        view.initialize()
-        return view
-
-    def test_target_person(self):
-        add_view = self.get_view(self.person)
-        self.assertTrue(IBranchTarget.providedBy(add_view.target))
-
-    def test_target_product(self):
-        product = self.factory.makeProduct()
-        add_view = self.get_view(product)
-        self.assertTrue(IBranchTarget.providedBy(add_view.target))
-
-
 class TestBranchReviewerEditView(TestCaseWithFactory):
     """Test the BranchReviewerEditView view."""
 

=== modified file 'lib/lp/code/browser/tests/test_product.py'
--- lib/lp/code/browser/tests/test_product.py	2012-01-01 02:58:52 +0000
+++ lib/lp/code/browser/tests/test_product.py	2012-03-08 20:07:31 +0000
@@ -185,6 +185,13 @@
         commit_section = find_tag_by_id(view.render(), 'commits')
         self.assertIs(None, commit_section)
 
+    def test_initial_branches_contains_push_instructions(self):
+        product, branch = self.makeProductAndDevelopmentFocusBranch()
+        view = create_initialized_view(
+            product, '+code-index', rootsite='code', principal=product.owner)
+        content = view()
+        self.assertIn('bzr push lp:~', content)
+
 
 class TestProductCodeIndexServiceUsages(ProductTestBase, BrowserTestCase):
     """Tests for the product code page, especially the usage messasges."""

=== modified file 'lib/lp/code/javascript/tests/test_productseries-setbranch.html'
--- lib/lp/code/javascript/tests/test_productseries-setbranch.html	2012-02-13 14:15:36 +0000
+++ lib/lp/code/javascript/tests/test_productseries-setbranch.html	2012-03-08 20:07:31 +0000
@@ -62,7 +62,7 @@
                   <label>
                     <input class="radioType" checked="checked"
                            id="field.branch_type.0"
-                           name="field.branch_type" type="radio" value="link-lp-bzr">
+                           name="field.branch_type" type="radio" value="link-lp-bzr" />
                     Link to a Bazaar branch already in Launchpad
                   </label>
                     <table>
@@ -73,7 +73,7 @@
                             <span class="fieldRequired">(Optional)</span>
                             <div>
                               <input type="text" value="" id="field.branch_location"
-                                     name="field.branch_location" size="35">
+                                     name="field.branch_location" size="35" />
 
                             </div>
                             <p class="formHelp">The Bazaar branch for this series in
@@ -89,20 +89,8 @@
                 <td>
                   <label>
                     <input class="radioType" id="field.branch_type.1"
-                           name="field.branch_type"
-                           type="radio" value="create-new">
-                    Create a new, empty branch in Launchpad and link
-                    to this series
-                  </label>
-                </td>
-              </tr>
-
-              <tr>
-                <td>
-                  <label>
-                    <input class="radioType" id="field.branch_type.2"
                            name="field.branch_type" type="radio"
-                           value="import-external">
+                           value="import-external" />
                     Import a branch hosted somewhere else
                   </label>
                   <table>
@@ -114,7 +102,7 @@
                           <div>
                             <input class="urlTextType textType" id="field.repo_url"
                                    name="field.repo_url" size="44" type="text"
-                                   value="" disabled="">
+                                   value="" disabled="" />
                           </div>
                         </td>
                       </tr>
@@ -124,7 +112,7 @@
                           <label>
                             <input class="radioType" id="field.rcs_type.6"
                                    name="field.rcs_type" type="radio" value="BZR"
-                                   disabled="">
+                                   disabled="" />
                             Bazaar, hosted externally
                           </label>
                         </td>
@@ -135,7 +123,7 @@
                           <label>
                             <input class="radioType" id="field.rcs_type.4"
                                    name="field.rcs_type" type="radio" value="GIT"
-                                   disabled="">
+                                   disabled="" />
                             Git
                           </label>
                         </td>
@@ -146,7 +134,7 @@
                           <label>
                             <input class="radioType" id="field.rcs_type.3"
                                    name="field.rcs_type" type="radio"
-                                   value="BZR_SVN" disabled="">
+                                   value="BZR_SVN" disabled="" />
                             SVN
                           </label>
                         </td>
@@ -156,7 +144,7 @@
                         <td>
                           <label>
                             <input class="radioType" id="field.rcs_type.5"
-                                   name="field.rcs_type" type="radio" value="HG" disabled="">
+                                   name="field.rcs_type" type="radio" value="HG" disabled="" />
                             Mercurial
                           </label>
                         </td>
@@ -167,7 +155,7 @@
                           <label>
                             <input class="radioType" id="field.rcs_type.1"
                                    name="field.rcs_type" type="radio" value="CVS"
-                                   disabled="">
+                                   disabled="" />
                             CVS
                           </label>
 
@@ -182,7 +170,7 @@
                                     <input class="textType" id="field.cvs_module"
                                            name="field.cvs_module" size="20"
                                            type="text"
-                                           value="" disabled="">
+                                           value="" disabled="" />
                                   </div>
                                 </td>
                               </tr>
@@ -199,7 +187,7 @@
                 <td colspan="2">
                   <label for="field.branch_name">Branch name:</label>
                   <div>
-                    <input class="textType" id="field.branch_name" name="field.branch_name" size="20" type="text" value=""  />
+                    <input class="textType" id="field.branch_name" name="field.branch_name" size="20" type="text" value="" />
                   </div>
                 </td>
               </tr>
@@ -228,7 +216,7 @@
             </tbody>
           </table>
           <input type="submit" id="field.actions.update"
-                 name="field.actions.update" value="Update" class="button">
+                 name="field.actions.update" value="Update" class="button" />
           or&nbsp;
           <a href="https://launchpad.dev/zyc/trunk";>Cancel</a>
         </form>

=== modified file 'lib/lp/code/javascript/tests/test_productseries_setbranch.js'
--- lib/lp/code/javascript/tests/test_productseries_setbranch.js	2011-07-08 05:12:39 +0000
+++ lib/lp/code/javascript/tests/test_productseries_setbranch.js	2012-03-08 20:07:31 +0000
@@ -28,8 +28,7 @@
 
            // Get the individual branch type radio buttons.
            this.link_lp_bzr = Y.DOM.byId('field.branch_type.0');
-           this.create_new = Y.DOM.byId('field.branch_type.1');
-           this.import_external = Y.DOM.byId('field.branch_type.2');
+           this.import_external = Y.DOM.byId('field.branch_type.1');
 
            // Get the input widgets.
            this.branch_location = Y.DOM.byId('field.branch_location');
@@ -66,7 +65,6 @@
            };
 
            check_handler(this.link_lp_bzr, module.onclick_branch_type);
-           check_handler(this.create_new, module.onclick_branch_type);
            check_handler(this.import_external, module.onclick_branch_type);
 
            check_handler(this.cvs, module.onclick_rcs_type);
@@ -106,36 +104,6 @@
                            'bzr button not disabled');
         },
 
-        test_select_create_new: function() {
-           this.create_new.checked = true;
-           module.onclick_branch_type();
-           // The branch location is disabled.
-           Y.Assert.isTrue(this.branch_location.disabled,
-                           'branch_location not disabled');
-           module.onclick_rcs_type();
-           // The CVS module and repo url are disabled.
-           Y.Assert.isTrue(this.cvs_module.disabled,
-                           'cvs_module not disabled');
-           Y.Assert.isTrue(this.repo_url.disabled,
-                           'repo_url not disabled');
-           // The branch name and owner are enabled.
-           Y.Assert.isFalse(this.branch_name.disabled,
-                           'branch_name disabled');
-           Y.Assert.isFalse(this.branch_owner.disabled,
-                           'branch_owner disabled');
-           // All of the radio buttons are disabled.
-           Y.Assert.isTrue(this.cvs.disabled,
-                           'cvs button not disabled');
-           Y.Assert.isTrue(this.svn.disabled,
-                           'svn button not disabled');
-           Y.Assert.isTrue(this.git.disabled,
-                           'git button not disabled');
-           Y.Assert.isTrue(this.hg.disabled,
-                           'hg button not disabled');
-           Y.Assert.isTrue(this.bzr.disabled,
-                           'bzr button not disabled');
-        },
-
         test_select_import_external: function() {
            this.import_external.checked = true;
            module.onclick_branch_type();

=== modified file 'lib/lp/code/stories/branches/xx-branch-deletion.txt'
--- lib/lp/code/stories/branches/xx-branch-deletion.txt	2012-01-15 13:32:27 +0000
+++ lib/lp/code/stories/branches/xx-branch-deletion.txt	2012-03-08 20:07:31 +0000
@@ -16,13 +16,13 @@
     ...     product=product, branch=branch)
     >>> login_person(alice)
     >>> product.development_focus = productseries
+    >>> delete_branch = factory.makeProductBranch(
+    ...     name='to-delete', owner=alice,
+    ...     product=product, branch_type=BranchType.HOSTED)
     >>> logout()
 
     >>> browser = setupBrowser(auth="Basic alice@xxxxxxxxxxx:test")
-    >>> browser.open('http://code.launchpad.dev/earthlynx')
-    >>> browser.getLink("Register a branch").click()
-    >>> browser.getControl('Name').value = 'to-delete'
-    >>> browser.getControl('Register Branch').click()
+    >>> browser.open('http://code.launchpad.dev/~alice/earthlynx/to-delete')
     >>> print browser.title
     to-delete : Code : Earth Lynx
 
@@ -56,10 +56,11 @@
 If the branch is junk, then the user is taken back to the code listing for
 the deleted branch's owner.
 
-    >>> browser.open('http://code.launchpad.dev/~alice')
-    >>> browser.getLink("Register a branch").click()
-    >>> browser.getControl('Name').value = 'to-delete'
-    >>> browser.getControl('Register Branch').click()
+    >>> login_person(alice)
+    >>> delete_branch = factory.makePersonalBranch(
+    ...     name='to-delete', owner=alice)
+    >>> logout()
+    >>> browser.open('http://code.launchpad.dev/~alice/+junk/to-delete')
     >>> browser.getLink('Delete branch').click()
     >>> browser.getControl('Delete').click()
     >>> print browser.url

=== removed file 'lib/lp/code/stories/branches/xx-creating-branches.txt'
--- lib/lp/code/stories/branches/xx-creating-branches.txt	2011-08-29 16:37:46 +0000
+++ lib/lp/code/stories/branches/xx-creating-branches.txt	1970-01-01 00:00:00 +0000
@@ -1,247 +0,0 @@
-Creating Branches
-=================
-
-In the past, there were two very distinct ways of creating branches in
-Launchpad.  The first was to use the UI, and the other was to push the
-branch to Launchpad.  The first method only created MIRRORED branches,
-and the second only HOSTED.
-
-Many users were confused with this, and tried to create HOSTED branches
-using the user interface.  Now they can.
-
-
-Creating a hosted branch
-------------------------
-
-Hosted branches use Launchpad as their primary location.
-
-    >>> from zope.component import getUtility
-    >>> from lp.code.enums import BranchType
-    >>> from lp.registry.interfaces.product import IProductSet
-    >>> login(ANONYMOUS)
-    >>> redfish = getUtility(IProductSet).getByName('redfish')
-    >>> branch = factory.makeProductBranch(
-    ...     product=redfish, branch_type=BranchType.HOSTED)
-    >>> productseries = factory.makeProductSeries(
-    ...     product=redfish, branch=branch)
-    >>> login_person(redfish.owner)
-    >>> redfish.development_focus = productseries
-    >>> logout()
-
-    >>> browser = setupBrowser(auth="Basic test@xxxxxxxxxxxxx:test")
-    >>> browser.open('http://code.launchpad.dev/redfish')
-    >>> browser.getLink("Register a branch").click()
-
-    >>> browser.getControl('Name').value = 'hosted-branch'
-
-Finding product/+addbranch
---------------------------
-
-We should be able to create a new branch from a product.
-
-First, check that the +addbranch link is visible on the product code
-facet page.
-
-    >>> user_browser.open('http://code.launchpad.dev/applets')
-    >>> print user_browser.url
-    http://code.launchpad.dev/applets
-
-Let's make sure we can load the branch creation form on a product.
-
-    >>> user_browser.getLink("Register a branch").click()
-    Traceback (most recent call last):
-    ...
-    LinkNotFoundError
-
-The link is not there because the product has not been configured to
-do code hosting yet.  The development focus must be set with a branch first.
-
-    >>> owner_browser = setupBrowser(auth="Basic foo.bar@xxxxxxxxxxxxx:test")
-    >>> owner_browser.open('http://code.launchpad.dev/applets')
-    >>> owner_browser.getLink('Configure code hosting').click()
-    >>> print owner_browser.url
-    http://code.launchpad.dev/applets/trunk/+setbranch
-
-    >>> owner_browser.getControl(
-    ...     'Create a new, empty branch').click()
-    >>> owner_browser.getControl('Branch name').value = 'trunk'
-    >>> owner_browser.getControl('Update').click()
-
-Now that code hosting has been configured, a regular user will be able
-to register a branch.
-
-    >>> user_browser.open('http://code.launchpad.dev/applets')
-    >>> user_browser.getLink("Register a branch").click()
-    >>> print user_browser.url
-    http://code.launchpad.dev/applets/+addbranch
-
-
-Adding a branch to a product
-----------------------------
-
-Now, post the branch creation form for the product.
-
-    >>> user_browser.open('http://code.launchpad.dev/applets/+addbranch')
-
-The specified URL has a trailing slash. In the next test, we will check
-that it has been stripped.
-
-    >>> user_browser.getControl('Name').value = 'main'
-    >>> user_browser.getControl('Experimental').click()
-    >>> user_browser.getControl('Register Branch').click()
-
-Posting the form should succeed and redirect to the page of the newly
-registered branch. We check that the final slash of the URL was stripped
-by matching for the angle brackets of an enclosing tag.
-
-    >>> user_browser.url
-    'http://code.launchpad.dev/~no-priv/applets/main'
-
-    >>> content = find_tag_by_id(user_browser.contents, 'document')
-    >>> print extract_text(find_tag_by_id(content, 'registration'))
-    Created by No Privileges Person on ... and last modified on ...
-
-    >>> print extract_text(find_tag_by_id(content, 'privacy'))
-    This branch is public
-
-This page includes a link to other branches associated with that
-product, and a link to other branches maintained by that person.
-
-    >>> print extract_text(find_tags_by_class(
-    ...     user_browser.contents, 'related', only_first=True))
-    Nearby
-    Other Gnome Applets branches
-    Other branches owned by No Privileges Person
-
-
-Finding person/+addbranch
--------------------------
-
-The user is only able to register a branch where either they or a team
-that they are a member of are the owner, so the 'Register branch' option
-is only shown on the code pages for teams that the user is a member of,
-and their own code page.
-
-Since no-priv is not a member of lifeless, the Register branch link is
-not shown.
-
-    >>> user_browser.open('http://code.launchpad.dev/~lifeless')
-    >>> user_browser.getLink("Register a branch")
-    Traceback (most recent call last):
-    ...
-    LinkNotFoundError
-
-    >>> browser.open('http://code.launchpad.dev/~landscape-developers')
-    >>> browser.getLink("Register a branch").click()
-    >>> print browser.getControl('Owner').displayValue
-    ['Landscape Developers (landscape-developers)']
-
-The user is able to change the owner of the branch to any team that the
-user is a member of, or to themselves.
-
-    >>> for option in browser.getControl('Owner').displayOptions:
-    ...     print option
-    Sample Person (name12)
-    HWDB Team (hwdb-team)
-    Landscape Developers (landscape-developers)
-    Launchpad Users (launchpad-users)
-    Ubuntu Gnome Team (name18)
-    Warty Security Team (name20)
-
-Conflict on unique name
------------------------
-
-Trying to register a branch with a product and that matches an existing
-branch owned by the user would cause a database integrity error, because
-the triplet owner-product-name is unique for all branches.
-
-For this example, we will use ~name12/gnome-terminal/main. Check that it
-already exists.
-
-    >>> browser.open(
-    ...     'http://launchpad.dev/~name12/+branch/gnome-terminal/main')
-
-Try a adding a conflicting branch from the product/+addbranch form.
-
-    >>> browser.open('http://code.launchpad.dev/gnome-terminal/+addbranch')
-
-Trying to post the form without filling a name at all should not cause
-an oops!
-
-    >>> browser.getControl('Register Branch').click()
-    >>> browser.url
-    'http://code.launchpad.dev/gnome-terminal/+addbranch'
-
-Now, complete the form, but give a name that is alredy in use for that
-owner and product.
-
-    >>> browser.getControl('Name').value = 'main'
-    >>> browser.getControl('Register Branch').click()
-
-That should give us the form back with an error message.
-
-    >>> browser.url
-    'http://code.launchpad.dev/gnome-terminal/+addbranch'
-
-    >>> for message in get_feedback_messages(browser.contents):
-    ...     print extract_text(message)
-    There is 1 error.
-    You already have a branch for GNOME Terminal called main.
-
-If the user is trying to add a branch for a team that conflicts, then
-the team name is given in the error message.
-
-    >>> browser.open('http://code.launchpad.dev/gnome-terminal/+addbranch')
-    >>> browser.getControl('Owner').displayValue = [
-    ...     'Landscape Developers']
-    >>> browser.getControl('Name').value = 'main'
-    >>> browser.getControl('Register Branch').click()
-    >>> print browser.url
-    http://code.launchpad.dev/~landscape-developers/gnome-terminal/main
-
-    >>> for message in get_feedback_messages(browser.contents):
-    ...     print extract_text(message)
-
-Now registering again with the same name.
-
-    >>> browser.open('http://code.launchpad.dev/gnome-terminal/+addbranch')
-    >>> browser.getControl('Owner').displayValue = [
-    ...     'Landscape Developers']
-    >>> browser.getControl('Name').value = 'main'
-    >>> browser.getControl('Register Branch').click()
-    >>> for message in get_feedback_messages(browser.contents):
-    ...     print extract_text(message)
-    There is 1 error.
-    Landscape Developers already has a branch for GNOME Terminal called main.
-
-
-Attempting to create a branch in a forbidden project
-----------------------------------------------------
-
-The branch visibility policy for a product may specify that certain
-groups of people cannot create branches.  An example of this in the
-sample data is the landscape project.  Only landscape developers can
-create branches for landscape.
-
-When registering a branch from the product pages, there is no product
-widget, so errors are set at the page level.
-
-    >>> owner_browser = setupBrowser(auth="Basic test@xxxxxxxxxxxxx:test")
-    >>> owner_browser.open('http://code.launchpad.dev/landscape')
-    >>> owner_browser.getLink('Configure code hosting').click()
-    >>> owner_browser.getControl(
-    ...     'Create a new, empty branch').click()
-    >>> owner_browser.getControl('Branch name').value = 'trunk'
-    >>> owner_browser.getControl('Update').click()
-
-    >>> user_browser.open('http://code.launchpad.dev/landscape')
-    >>> user_browser.getLink("Register a branch").click()
-    >>> user_browser.getControl('Name').value = 'landscape1'
-    >>> user_browser.getControl('Register Branch').click()
-    >>> messages = find_tags_by_class(user_browser.contents, 'message')
-    >>> for element in messages:
-    ...     print element.renderContents()
-    There is 1 error.
-    You are not allowed to create branches in The Landscape Project.
-
-

=== removed file 'lib/lp/code/stories/branches/xx-junk-branches.txt'
--- lib/lp/code/stories/branches/xx-junk-branches.txt	2012-01-15 13:32:27 +0000
+++ lib/lp/code/stories/branches/xx-junk-branches.txt	1970-01-01 00:00:00 +0000
@@ -1,50 +0,0 @@
-Junk Branches
-=============
-
-Create a person and team.
-
-    >>> login(ANONYMOUS)
-    >>> eric = factory.makePerson(name='eric', email='eric@xxxxxxxxxxx')
-    >>> vikings = factory.makeTeam(name='vikings', owner=eric)
-    >>> logout()
-
-When creating a branch from a person, we have the option not to specify an
-associated product. A branch with no associated product is called a "junk"
-branch.
-
-    >>> browser = setupBrowser(auth="Basic eric@xxxxxxxxxxx:test")
-    >>> browser.open('http://code.launchpad.dev/~eric')
-    >>> browser.getLink("Register a branch").click()
-    >>> browser.getControl('Name').value = 'personal-junk'
-    >>> browser.getControl('Register Branch').click()
-
-Posting the form should succeed and redirect to the page of the newly created
-junk branch. Because it has no product, it has no link to other product
-branches.
-
-    >>> print browser.url
-    http://code.launchpad.dev/~eric/+junk/personal-junk
-    >>> print extract_text(find_tags_by_class(
-    ...     browser.contents, 'related', only_first=True))
-    Nearby
-    Other branches owned by Eric
-
-Junk branches do not support merge proposals, so the "Branch Merges" section
-of the page should not be shown.
-
-    >>> print find_tag_by_id(browser.contents, 'branch-merges')
-    None
-
-
-Team Junk Branches
-==================
-
-Junk branches can also be associated with a team.
-
-    >>> browser.open('http://code.launchpad.dev/~vikings')
-    >>> browser.getLink("Register a branch").click()
-    >>> browser.getControl('Name').value = 'team-junk'
-    >>> browser.getControl('Register Branch').click()
-
-    >>> print browser.url
-    http://code.launchpad.dev/~vikings/+junk/team-junk

=== modified file 'lib/lp/code/stories/branches/xx-product-branches.txt'
--- lib/lp/code/stories/branches/xx-product-branches.txt	2010-10-18 13:04:16 +0000
+++ lib/lp/code/stories/branches/xx-product-branches.txt	2012-03-08 20:07:31 +0000
@@ -169,13 +169,16 @@
 Involvement portlet
 ===================
 
-There are several links in the side portlet:  'Register a branch',
+There are several links in the side portlet:
 'Import a branch', 'Configure code hosting', and 'Define branch
 visibility'.  The links are only shown if the user has permission to
 perform the task.
 
     >>> from zope.component import getUtility
     >>> from lp.registry.interfaces.product import IProductSet
+    >>> from lp.testing import celebrity_logged_in
+    >>> from lp.testing.factory import LaunchpadObjectFactory
+    >>> factory = LaunchpadObjectFactory()
     >>> login(ANONYMOUS)
     >>> product = getUtility(IProductSet).getByName('firefox')
     >>> old_branch = product.development_focus.branch
@@ -191,12 +194,10 @@
     ...         print extract_text(link)
 
     >>> def setup_code_hosting(productname):
-    ...     admin_browser.open('http://code.launchpad.dev/%s' % productname)
-    ...     admin_browser.getLink('Configure code hosting').click()
-    ...     admin_browser.getControl(
-    ...         'Create a new, empty branch').click()
-    ...     admin_browser.getControl('Branch name').value = 'trunk'
-    ...     admin_browser.getControl('Update').click()
+    ...     with celebrity_logged_in('admin'):
+    ...         product = getUtility(IProductSet).getByName(productname)
+    ...         branch = factory.makeProductBranch(product=product)
+    ...         product.development_focus.branch = branch
 
 The involvement portlet is not shown if the product does not have code
 hosting configured or if it is not using Launchpad.
@@ -212,7 +213,6 @@
     LAUNCHPAD
     >>> admin_browser.open('http://code.launchpad.dev/firefox')
     >>> print_links(admin_browser)
-    Register a branch
     Import a branch
     Configure code hosting
     Define branch visibility
@@ -223,7 +223,6 @@
     >>> owner_browser = setupBrowser(auth='Basic test@xxxxxxxxxxxxx:test')
     >>> owner_browser.open('http://code.launchpad.dev/firefox')
     >>> print_links(owner_browser)
-    Register a branch
     Import a branch
     Configure code hosting
 
@@ -231,7 +230,6 @@
 
     >>> user_browser.open('http://code.launchpad.dev/firefox')
     >>> print_links(user_browser)
-    Register a branch
     Import a branch
 
 If the product specifies that it officially uses Launchpad code, then
@@ -242,7 +240,6 @@
     >>> logout()
     >>> browser.open('http://code.launchpad.dev/firefox')
     >>> print_links(browser)
-    Register a branch
     Import a branch
 
 
@@ -267,7 +264,8 @@
 
     >>> setup_code_hosting('gnome-terminal')
     >>> print_portlet('gnome-terminal')
-    GNOME Terminal has 9 active branches owned by 2 people and 2 teams. There were 0 commits in the last month.
+    GNOME Terminal has 9 active branches owned by 2 people and 2 teams.
+    There were 0 commits in the last month.
 
     >>> from lp.testing import ANONYMOUS, login, logout
     >>> login(ANONYMOUS)
@@ -276,17 +274,20 @@
     >>> logout()
     >>> setup_code_hosting('fooix')
     >>> print_portlet('fooix')
-    Fooix has 2 active branches owned by 2 people. There were 0 commits in the last month.
+    Fooix has 2 active branches owned by 2 people.
+    There were 0 commits in the last month.
 
     >>> print_portlet('evolution')
-    Evolution has 3 active branches owned by 1 person and 1 team. There were 0 commits in the last month.
+    Evolution has 3 active branches owned by 1 person and 1 team.
+    There were 0 commits in the last month.
 
     >>> login(ANONYMOUS)
     >>> dinky = factory.makeProduct('dinky')
     >>> logout()
     >>> setup_code_hosting('dinky')
     >>> print_portlet('dinky')
-    Dinky has 1 active branch owned by 1 person. There were 0 commits in the last month.
+    Dinky has 1 active branch owned by 1 person. There were 0 commits in
+    the last month.
 
 
 Product has Branches, but none initially visible

=== removed file 'lib/lp/code/stories/branches/xx-register-a-branch.txt'
--- lib/lp/code/stories/branches/xx-register-a-branch.txt	2010-02-05 13:25:46 +0000
+++ lib/lp/code/stories/branches/xx-register-a-branch.txt	1970-01-01 00:00:00 +0000
@@ -1,19 +0,0 @@
-From the Code homepage, register a branch.
-
-Clicking on the link as a logged-in user should take you directly to the branch
-registration page.
-
-    >>> browser = setupBrowser(auth='Basic test@xxxxxxxxxxxxx:test')
-    >>> browser.open('http://code.launchpad.dev/')
-    >>> browser.getLink('Register a branch').click()
-    >>> print browser.title
-    Register a branch...
-
-Clicking the link as an anonymous user should take you to a login page. Once
-you've logged in, you will be redirected to the registration page.
-
-    >>> anon_browser.open('http://code.launchpad.dev/')
-    >>> anon_browser.getLink('Register a branch').click()
-    Traceback (most recent call last):
-    ...
-    Unauthorized:...

=== modified file 'lib/lp/code/templates/bazaar-index.pt'
--- lib/lp/code/templates/bazaar-index.pt	2012-03-01 17:42:28 +0000
+++ lib/lp/code/templates/bazaar-index.pt	2012-03-08 20:07:31 +0000
@@ -20,14 +20,6 @@
           </a>
         </li>
         <li>
-          <a href="/people/+me/+addbranch">
-            <img
-               alt="Register a branch"
-               src="/+icing/but-lrg-registerabranch.gif"
-               />
-          </a>
-        </li>
-        <li>
           <a href="/+code-imports/+new" id="new-code-import">
             <img alt="Import your project"
                  src="/+icing/but-lrg-importyourproject.gif"/>

=== removed file 'lib/lp/code/templates/branch-add.pt'
--- lib/lp/code/templates/branch-add.pt	2009-08-12 00:44:04 +0000
+++ lib/lp/code/templates/branch-add.pt	1970-01-01 00:00:00 +0000
@@ -1,21 +0,0 @@
-<html
-  xmlns="http://www.w3.org/1999/xhtml";
-  xmlns:tal="http://xml.zope.org/namespaces/tal";
-  xmlns:metal="http://xml.zope.org/namespaces/metal";
-  xmlns:i18n="http://xml.zope.org/namespaces/i18n";
-  metal:use-macro="view/macro:page/main_only"
-  i18n:domain="launchpad">
-
-<body>
-
-  <h1 metal:fill-slot="heading">
-    Register a branch on
-    <tal:target-name tal:replace="view/target/displayname"/>
-  </h1>
-
-  <div metal:fill-slot="main">
-    <metal:add-branch use-macro="context/@@branch-form-macros/add-branch-content"/>
-  </div>
-
-</body>
-</html>

=== modified file 'lib/lp/code/templates/person-branches.pt'
--- lib/lp/code/templates/person-branches.pt	2011-11-04 11:29:34 +0000
+++ lib/lp/code/templates/person-branches.pt	2012-03-08 20:07:31 +0000
@@ -13,9 +13,6 @@
   <div tal:define="menu context/menu:branches"
        tal:condition="view/show_action_menu"
        class="first portlet">
-    <div tal:define="link menu/addbranch"
-         tal:condition="link/enabled"
-         tal:content="structure link/render" />
   </div>
 
   <tal:summary replace="structure context/@@+codesummary"/>

=== modified file 'lib/lp/code/templates/product-branch-summary.pt'
--- lib/lp/code/templates/product-branch-summary.pt	2011-12-29 05:29:36 +0000
+++ lib/lp/code/templates/product-branch-summary.pt	2012-03-08 20:07:31 +0000
@@ -48,7 +48,7 @@
       from it.
     </p>
     <p tal:condition="view/branch/branch_type/enumvalue:IMPORTED">
-      Launchpad imports the master branch and you can create branches from 
+      Launchpad imports the master branch and you can create branches from
       it.
     </p>
 
@@ -59,7 +59,7 @@
 
   <tal:no-branches condition="not: view/branch_count">
     There are no branches for <tal:project-name replace="context/displayname"/>
-    in Launchpad. 
+    in Launchpad.
     <tal:can-configure condition="view/can_configure_branches">
       You can change this by:
 
@@ -95,9 +95,24 @@
        using the command:<br/>
       <tt style="padding-left:2em">bzr branch <tal:project-name replace="dev_focus/bzr_identity"/></tt>
     </div>
-
   </tal:has-branches>
 
+  <tal:has-user condition="view/user">
+    <p id="push-instructions"
+      tal:condition="not: context/codehosting_usage/enumvalue:UNKNOWN">
+      You can push the branch directly to Launchpad with the command:<br />
+      <tt><strong>
+        bzr push lp:~<tal:user replace="view/user/name"/>/<tal:project replace="context/name"/>/<tal:series replace="context/name"/>
+      </strong></tt>
+      <tal:no-keys condition="not:view/user/sshkeys">
+        <br/>To authenticate with the Launchpad branch upload service,
+        you need to
+        <a tal:attributes="href string:${view/user/fmt:url}/+editsshkeys">
+          register a SSH key</a>.
+      </tal:no-keys>
+    </p>
+  </tal:has-user>
+
   <div tal:condition="context/codehosting_usage/enumvalue:UNKNOWN">
     <div
        tal:condition="not: context/codehosting_usage/enumvalue:LAUNCHPAD"

=== modified file 'lib/lp/code/templates/product-branches.pt'
--- lib/lp/code/templates/product-branches.pt	2010-10-22 10:28:37 +0000
+++ lib/lp/code/templates/product-branches.pt	2012-03-08 20:07:31 +0000
@@ -36,13 +36,6 @@
 
       <div id="involvement" class="portlet"
            tal:define="menu context/menu:branches">
-        <ul class="involvement">
-            <li style="border: none">
-              <a href="+addbranch" class="menu-link-addbranch sprite code">
-                Register a branch
-              </a>
-            </li>
-        </ul>
         <p style="margin-top:10px;"
            tal:define="link menu/code_import"
            tal:condition="link/enabled"

=== modified file 'lib/lp/registry/browser/pillar.py'
--- lib/lp/registry/browser/pillar.py	2012-03-07 07:37:00 +0000
+++ lib/lp/registry/browser/pillar.py	2012-03-08 20:07:31 +0000
@@ -67,8 +67,7 @@
     """The get involved menu."""
     usedfor = IInvolved
     links = [
-        'report_bug', 'ask_question', 'help_translate', 'submit_code',
-        'register_blueprint']
+        'report_bug', 'ask_question', 'help_translate', 'register_blueprint']
 
     @property
     def pillar(self):
@@ -89,18 +88,6 @@
             '', 'Help translate', site='translations', icon='translations',
             enabled=service_uses_launchpad(self.pillar.translations_usage))
 
-    def submit_code(self):
-        if self.pillar.codehosting_usage in [
-                ServiceUsage.LAUNCHPAD,
-                ServiceUsage.EXTERNAL,
-                ]:
-            enabled = True
-        else:
-            enabled = False
-        return Link(
-            '+addbranch', 'Submit code', site='code', icon='code',
-            enabled=enabled)
-
     def register_blueprint(self):
         return Link(
             '+addspec',

=== modified file 'lib/lp/registry/browser/product.py'
--- lib/lp/registry/browser/product.py	2012-03-02 23:09:34 +0000
+++ lib/lp/registry/browser/product.py	2012-03-08 20:07:31 +0000
@@ -628,7 +628,6 @@
         'announcements',
         'administer',
         'review_license',
-        'branch_add',
         'branchvisibility',
         'rdf',
         'branding',
@@ -686,11 +685,6 @@
         text = 'Define branch visibility'
         return Link('+branchvisibility', text, icon='edit')
 
-    def branch_add(self):
-        text = 'Register a branch'
-        summary = "Register a new Bazaar branch for this project"
-        return Link('+addbranch', text, summary, icon='add', site='code')
-
 
 class ProductBugsMenu(PillarBugsMenu,
                       ProductEditLinksMixin):

=== modified file 'lib/lp/registry/browser/productseries.py'
--- lib/lp/registry/browser/productseries.py	2012-03-01 20:00:29 +0000
+++ lib/lp/registry/browser/productseries.py	2012-03-08 20:07:31 +0000
@@ -225,7 +225,7 @@
     """The get involved menu."""
     usedfor = IProductSeriesInvolved
     links = [
-        'report_bug', 'help_translate', 'submit_code', 'register_blueprint']
+        'report_bug', 'help_translate', 'register_blueprint']
 
     @property
     def view(self):
@@ -235,20 +235,12 @@
     def pillar(self):
         return self.view.context.product
 
-    def submit_code(self):
-        target = canonical_url(
-            self.pillar, view_name='+addbranch', rootsite='code')
-        enabled = self.view.codehosting_usage == ServiceUsage.LAUNCHPAD
-        return Link(
-            target, 'Submit code', icon='code', enabled=enabled)
-
 
 class ProductSeriesInvolvementView(PillarView):
     """Encourage configuration of involvement links for project series."""
 
     implements(IProductSeriesInvolved)
     has_involvement = True
-    visible_disabled_link_names = ['submit_code']
 
     def __init__(self, context, request):
         super(ProductSeriesInvolvementView, self).__init__(context, request)
@@ -809,16 +801,12 @@
 
 
 LINK_LP_BZR = 'link-lp-bzr'
-CREATE_NEW = 'create-new'
 IMPORT_EXTERNAL = 'import-external'
 
 
 BRANCH_TYPE_VOCABULARY = SimpleVocabulary((
     SimpleTerm(LINK_LP_BZR, LINK_LP_BZR,
                _("Link to a Bazaar branch already on Launchpad")),
-    SimpleTerm(CREATE_NEW, CREATE_NEW,
-               _("Create a new, empty branch in Launchpad and "
-                 "link to this series")),
     SimpleTerm(IMPORT_EXTERNAL, IMPORT_EXTERNAL,
                _("Import a branch hosted somewhere else")),
     ))
@@ -934,10 +922,9 @@
         vocab = widget.vocabulary
 
         (self.branch_type_link,
-         self.branch_type_create,
          self.branch_type_import) = [
             render_radio_widget_part(widget, value, current_value)
-            for value in (LINK_LP_BZR, CREATE_NEW, IMPORT_EXTERNAL)]
+            for value in (LINK_LP_BZR, IMPORT_EXTERNAL)]
 
     def _validateLinkLpBzr(self, data):
         """Validate data for link-lp-bzr case."""
@@ -946,10 +933,6 @@
                 'branch_location',
                 'The branch location must be set.')
 
-    def _validateCreateNew(self, data):
-        """Validate data for create new case."""
-        self._validateBranch(data)
-
     def _validateImportExternal(self, data):
         """Validate data for import external case."""
         rcs_type = data.get('rcs_type')
@@ -1026,10 +1009,6 @@
             # Mark other widgets as non-required.
             self._setRequired(['rcs_type', 'repo_url', 'cvs_module',
                                'branch_name', 'branch_owner'], False)
-        elif branch_type == CREATE_NEW:
-            self._setRequired(
-                ['branch_location', 'repo_url', 'rcs_type', 'cvs_module'],
-                False)
         elif branch_type == IMPORT_EXTERNAL:
             rcs_type = data.get('rcs_type')
 
@@ -1057,8 +1036,6 @@
             self._validateImportExternal(data)
         elif branch_type == LINK_LP_BZR:
             self._validateLinkLpBzr(data)
-        elif branch_type == CREATE_NEW:
-            self._validateCreateNew(data)
         else:
             raise AssertionError("Unknown branch type %s" % branch_type)
 
@@ -1085,16 +1062,8 @@
             branch_name = data.get('branch_name')
             branch_owner = data.get('branch_owner')
 
-            # Create a new branch.
-            if branch_type == CREATE_NEW:
-                branch = self._createBzrBranch(branch_name, branch_owner)
-                if branch is not None:
-                    self.context.branch = branch
-                    self.request.response.addInfoNotification(
-                        'New branch created and linked to the series.')
-
             # Import or mirror an external branch.
-            elif branch_type == IMPORT_EXTERNAL:
+            if branch_type == IMPORT_EXTERNAL:
                 # Either create an externally hosted bzr branch
                 # (a.k.a. 'mirrored') or create a new code import.
                 rcs_type = data.get('rcs_type')

=== modified file 'lib/lp/registry/browser/tests/pillar-views.txt'
--- lib/lp/registry/browser/tests/pillar-views.txt	2011-12-22 05:09:10 +0000
+++ lib/lp/registry/browser/tests/pillar-views.txt	2012-03-08 20:07:31 +0000
@@ -84,7 +84,6 @@
     report_bug
     ask_question
     help_translate
-    submit_code
 
     >>> for link in view.configuration_links:
     ...     print link['link'].name
@@ -268,7 +267,6 @@
     http://bugs.launchpad.dev/bread/+filebug
     http://answers.launchpad.dev/bread/+addquestion
     http://translations.launchpad.dev/bread
-    http://code.launchpad.dev/bread/+addbranch
     http://blueprints.launchpad.dev/bread/+addspec
 
     >>> from lp.registry.browser.pillar import InvolvedMenu

=== modified file 'lib/lp/registry/browser/tests/productseries-setbranch-view.txt'
--- lib/lp/registry/browser/tests/productseries-setbranch-view.txt	2011-12-22 05:09:10 +0000
+++ lib/lp/registry/browser/tests/productseries-setbranch-view.txt	2012-03-08 20:07:31 +0000
@@ -13,14 +13,20 @@
     >>> login_person(product.owner)
     >>> view = create_initialized_view(series, name='+setbranch',
     ...                                principal=product.owner)
-    >>> print find_tag_by_id(view.render(), 'maincontent')
+    >>> content = find_tag_by_id(view.render(), 'maincontent')
+    >>> print content
     <div...
     ...Link to a Bazaar branch already on Launchpad...
-    ...Create a new, empty branch in Launchpad and link to this series...
     ...Import a branch hosted somewhere else...
     ...Branch name:...
     ...Branch owner:...
 
+The user can see instructions to push a branch.
+
+    >>> instructions = find_tag_by_id(content, 'push-instructions')
+    >>> 'bzr push lp:~' in str(instructions)
+    True
+
 
 Linking to an existing branch
 -----------------------------
@@ -83,72 +89,6 @@
     ~person.../chevy/impala-branch
 
 
-Creating a new branch
----------------------
-
-When creating a new branch the branch name and owner must be specified.
-
-    >>> series = factory.makeProductSeries(name="camaro", product=product)
-    >>> transaction.commit()
-
-    >>> form = {
-    ...     'field.branch_type': 'create-new',
-    ...     'field.actions.update': 'Update',
-    ...     }
-    >>> view = create_initialized_view(
-    ...     series, name='+setbranch', principal=product.owner, form=form)
-    >>> for notification in view.request.response.notifications:
-    ...     print notification.message
-    >>> for error in view.errors:
-    ...     print error
-    The branch name must be set.
-    The branch owner must be set.
-
-    >>> from lp.registry.interfaces.person import IPersonSet
-    >>> mark = getUtility(IPersonSet).getByEmail('mark@xxxxxxxxxxx')
-    >>> form = {
-    ...     'field.branch_type': 'create-new',
-    ...     'field.branch_name': 'camaro-branch',
-    ...     'field.branch_owner': product.owner.name,
-    ...     'field.actions.update': 'Update',
-    ...     }
-
-    >>> view = create_initialized_view(
-    ...     series, name='+setbranch', principal=product.owner, form=form)
-    >>> print view.errors_in_action
-    False
-    >>> print view.next_url
-    http://launchpad.dev/chevy/camaro
-    >>> for error in view.errors:
-    ...     print error
-    >>> for notification in view.request.response.notifications:
-    ...     print notification.message
-    New branch created and linked to the series.
-    >>> print series.branch.name
-    camaro-branch
-
-Using a branch name that already exists results in an error.
-
-    >>> form = {
-    ...     'field.branch_type': 'create-new',
-    ...     'field.branch_name': 'camaro-branch',
-    ...     'field.branch_owner': product.owner.name,
-    ...     'field.actions.update': 'Update',
-    ...     }
-
-    >>> view = create_initialized_view(
-    ...     series, name='+setbranch', principal=product.owner, form=form)
-    >>> print view.errors_in_action
-    True
-    >>> print view.next_url
-    None
-    >>> for error in view.errors:
-    ...     print error
-    You already have a branch for <em>Chevy</em> called <em>camaro-branch</em>.
-    >>> for notification in view.request.response.notifications:
-    ...     print notification.message
-
-
 Import a branch hosted elsewhere
 --------------------------------
 

=== modified file 'lib/lp/registry/browser/tests/productseries-views.txt'
--- lib/lp/registry/browser/tests/productseries-views.txt	2012-02-02 12:30:53 +0000
+++ lib/lp/registry/browser/tests/productseries-views.txt	2012-03-08 20:07:31 +0000
@@ -48,24 +48,6 @@
     http://bugs.launchpad.dev/app/simple/+filebug
     http://translations.launchpad.dev/app/simple
     http://blueprints.launchpad.dev/app/simple/+addspec
-    >>> for link in view.visible_disabled_links:
-    ...     print link.url
-    http://code.launchpad.dev/app/+addbranch
-
-Setting a branch for the series should enable the +addbranch link.
-
-    >>> series.branch = factory.makeBranch()
-    >>> view = create_view(series, '+get-involved')
-    >>> print view.codehosting_usage.name
-    LAUNCHPAD
-    >>> for link in view.enabled_links:
-    ...     print link.url
-    http://bugs.launchpad.dev/app/simple/+filebug
-    http://translations.launchpad.dev/app/simple
-    http://code.launchpad.dev/app/+addbranch
-    http://blueprints.launchpad.dev/app/simple/+addspec
-    >>> for link in view.visible_disabled_links:
-    ...     print link.url
 
 
 ProductSeries view
@@ -151,7 +133,6 @@
     None
 
     >>> firefox = getUtility(IProductSet).getByName('firefox')
-    >>> #login_person(firefox.owner)
     >>> series_with_downloads = firefox.getSeries('trunk')
     >>> view = create_initialized_view(series_with_downloads, name='+index')
     >>> print view.latest_release_with_download_files.version

=== modified file 'lib/lp/registry/stories/productseries/xx-productseries-index.txt'
--- lib/lp/registry/stories/productseries/xx-productseries-index.txt	2011-06-16 13:50:58 +0000
+++ lib/lp/registry/stories/productseries/xx-productseries-index.txt	2012-03-08 20:07:31 +0000
@@ -145,13 +145,3 @@
     <Link ... url='http://launchpad.dev/firefox/+milestones'>
     >>> anon_browser.getLink('View downloads for the Mozilla Firefox project')
     <Link ... url='http://launchpad.dev/firefox/+download'>
-
-The involvement portlet has links to various actions, including
-submitting a new branch.
-
-    >>> user_browser.open('http://launchpad.dev/evolution/trunk')
-    >>> user_browser.getLink('Submit code')
-    <Link ... url='http://code.launchpad.dev/evolution/+addbranch'>
-    >>> user_browser.getLink('Submit code').click()
-    >>> print user_browser.title
-    Register a branch : Code : Evolution

=== modified file 'lib/lp/registry/stories/productseries/xx-productseries-set-branch.txt'
--- lib/lp/registry/stories/productseries/xx-productseries-set-branch.txt	2010-04-05 18:02:00 +0000
+++ lib/lp/registry/stories/productseries/xx-productseries-set-branch.txt	2012-03-08 20:07:31 +0000
@@ -18,7 +18,6 @@
 
     >>> print_radio_button_field(browser.contents, 'branch_type')
     (*) Link to a Bazaar branch already on Launchpad
-    ( ) Create a new, empty branch in Launchpad and link to this series
     ( ) Import a branch hosted somewhere else
 
 
@@ -32,7 +31,8 @@
     >>> from lp.registry.interfaces.product import IProductSet
     >>> productset = getUtility(IProductSet)
     >>> firefox = productset.getByName('firefox')
-    >>> branch = factory.makeBranch(name="firefox-hosted-branch", product=firefox)
+    >>> branch = factory.makeBranch(
+    ...     name="firefox-hosted-branch", product=firefox)
     >>> branch_name = branch.unique_name
     >>> logout()
 
@@ -45,35 +45,6 @@
     http://launchpad.dev/firefox/trunk
 
 
-Creating a new branch
----------------------
-
-A brand new, empty branch on Launchpad can be created and set as the
-series branch.
-
-    >>> browser.open('http://launchpad.dev/firefox/trunk/+setbranch')
-    >>> browser.getControl('Create a new, empty branch in Launchpad').click()
-    >>> browser.getControl('Update').click()
-    >>> for message in get_feedback_messages(browser.contents):
-    ...     print extract_text(message)
-    There is 1 error.
-    Required input is missing.
-
-However in order to create the branch the name and owner must be
-specified.  The owner is a pre-populated dropdown list so the default
-can be used.
-
-    >>> browser.open('http://launchpad.dev/firefox/trunk/+setbranch')
-    >>> browser.getControl('Create a new, empty branch in Launchpad').click()
-    >>> browser.getControl(name='field.branch_name').value = 'new-firefox-branch'
-    >>> browser.getControl('Update').click()
-    >>> for message in get_feedback_messages(browser.contents):
-    ...     print extract_text(message)
-    New branch created and linked to the series.
-    >>> print browser.url
-    http://launchpad.dev/firefox/trunk
-
-
 Linking to an external branch
 -----------------------------
 
@@ -87,7 +58,8 @@
     >>> browser.getControl('Import a branch hosted somewhere else').click()
     >>> browser.getControl('Branch name').value = 'bzr-firefox-branch'
     >>> browser.getControl('Bazaar', index=0).click()
-    >>> browser.getControl('Branch URL').value = 'https://bzr.example.com/branch'
+    >>> browser.getControl('Branch URL').value = (
+    ...     'https://bzr.example.com/branch')
     >>> browser.getControl('Update').click()
     >>> for message in get_feedback_messages(browser.contents):
     ...     print extract_text(message)
@@ -102,7 +74,8 @@
     >>> browser.getControl('Import a branch hosted somewhere else').click()
     >>> browser.getControl('Branch name').value = 'git-firefox-branch'
     >>> browser.getControl('Git').click()
-    >>> browser.getControl('Branch URL').value = 'git://git.example.com/branch'
+    >>> browser.getControl('Branch URL').value = (
+    ...     'git://git.example.com/branch')
     >>> browser.getControl('Update').click()
     >>> for message in get_feedback_messages(browser.contents):
     ...     print extract_text(message)
@@ -116,7 +89,8 @@
     >>> browser.getControl('Import a branch hosted somewhere else').click()
     >>> browser.getControl('Branch name').value = 'svn-firefox-branch'
     >>> browser.getControl('SVN').click()
-    >>> browser.getControl('Branch URL').value = 'svn://svn.example.com/branch'
+    >>> browser.getControl('Branch URL').value = (
+    ...     'svn://svn.example.com/branch')
     >>> browser.getControl('Update').click()
     >>> for message in get_feedback_messages(browser.contents):
     ...     print extract_text(message)
@@ -130,7 +104,8 @@
     >>> browser.getControl('Import a branch hosted somewhere else').click()
     >>> browser.getControl('Branch name').value = 'hg-firefox-branch'
     >>> browser.getControl('Mercurial').click()
-    >>> browser.getControl('Branch URL').value = 'http://hg.example.com/branch'
+    >>> browser.getControl('Branch URL').value = (
+    ...     'http://hg.example.com/branch')
     >>> browser.getControl('Branch owner').value = ['hwdb-team']
     >>> browser.getControl('Update').click()
     >>> for message in get_feedback_messages(browser.contents):

=== modified file 'lib/lp/registry/templates/productseries-codesummary.pt'
--- lib/lp/registry/templates/productseries-codesummary.pt	2011-08-25 10:35:17 +0000
+++ lib/lp/registry/templates/productseries-codesummary.pt	2012-03-08 20:07:31 +0000
@@ -27,30 +27,17 @@
         </li>
 
         <li>
-          <p>
-            If the code is in a Bazaar branch not yet on Launchpad
-            you can either:
-          </p>
-
-          <ul class="bulleted" style="margin-bottom: 0;">
-            <li>
-              Have the branch mirrored from a remote location by
-               <a tal:attributes="href context/product/menu:overview/branch_add/fmt:url">
-              registering a mirrored branch</a>
-            </li>
-            <li id="ssh-key-directions">
-              Push the branch directly to Launchpad, e.g. with:<br />
-              <tt><strong>
-                bzr push lp:~<tal:user replace="view/user/name"/>/<tal:products replace="context/product/name"/>/<tal:series replace="context/name"/>
-              </strong></tt>
-              <tal:no-keys condition="not:view/user/sshkeys">
-                <br/>To authenticate with the Launchpad branch upload service,
-                you need to
-                <a tal:attributes="href string:${view/user/fmt:url}/+editsshkeys">
-                  register a SSH key</a>.
-              </tal:no-keys>
-            </li>
-          </ul>
+          If the code is in a Bazaar branch not yet on Launchpad
+          you can push the branch directly to Launchpad, e.g. with:<br />
+            <tt><strong>
+              bzr push lp:~<tal:user replace="view/user/name"/>/<tal:products replace="context/product/name"/>/<tal:series replace="context/name"/>
+            </strong></tt>
+            <tal:no-keys condition="not:view/user/sshkeys">
+              <br/>To authenticate with the Launchpad branch upload service,
+              you need to
+              <a tal:attributes="href string:${view/user/fmt:url}/+editsshkeys">
+                register a SSH key</a>.
+            </tal:no-keys>
         </li>
 
         <li>

=== modified file 'lib/lp/registry/templates/productseries-linkbranch.pt'
--- lib/lp/registry/templates/productseries-linkbranch.pt	2011-05-16 20:55:08 +0000
+++ lib/lp/registry/templates/productseries-linkbranch.pt	2012-03-08 20:07:31 +0000
@@ -14,19 +14,9 @@
         </li>
 
         <li>
-          <p>
+          <p id="ssh-key-directions">
             Otherwise, if the code is in a Bazaar branch not yet on Launchpad
-            you can either:
-          </p>
-
-          <ul class="bulleted" style="margin-bottom: 0;">
-            <li>
-              Have the branch mirrored from a remote location by
-               <a tal:attributes="href context/product/menu:overview/branch_add/fmt:url">
-              registering a mirrored branch</a>
-            </li>
-            <li id="ssh-key-directions">
-              Push the branch directly to Launchpad, e.g. with:<br />
+            you can push the branch directly to Launchpad, e.g. with:<br />
               <tt><strong>
                 bzr push lp:~<tal:user replace="view/user/name"/>/<tal:project replace="context/product/name"/>/<tal:series replace="context/name"/>
               </strong></tt>
@@ -36,8 +26,7 @@
                 <a tal:attributes="href string:${view/user/fmt:url}/+editsshkeys">
                   register a SSH key</a>.
               </tal:no-keys>
-            </li>
-          </ul>
+          </p>
         </li>
 
         <li id="external-code">

=== modified file 'lib/lp/registry/templates/productseries-setbranch.pt'
--- lib/lp/registry/templates/productseries-setbranch.pt	2012-02-01 15:31:32 +0000
+++ lib/lp/registry/templates/productseries-setbranch.pt	2012-03-08 20:07:31 +0000
@@ -18,6 +18,19 @@
 
 <div metal:fill-slot="main">
 
+  <p id="push-instructions">
+    You can push the branch directly to Launchpad with the command:<br />
+    <tt><strong>
+      bzr push lp:~<tal:user replace="view/user/name"/>/<tal:project replace="context/product/name"/>/<tal:series replace="context/name"/>
+    </strong></tt>
+    <tal:no-keys condition="not:view/user/sshkeys">
+      <br/>To authenticate with the Launchpad branch upload service,
+      you need to
+      <a tal:attributes="href string:${view/user/fmt:url}/+editsshkeys">
+        register a SSH key</a>.
+    </tal:no-keys>
+  </p>
+
   <div metal:use-macro="context/@@launchpad_form/form">
 
     <metal:formbody fill-slot="widgets">
@@ -39,15 +52,6 @@
 
         <tr>
           <td>
-            <label tal:replace="structure view/branch_type_create">
-              Create a new, empty branch in Launchpad and link
-              to this series
-            </label>
-          </td>
-        </tr>
-
-        <tr>
-          <td>
             <label tal:replace="structure view/branch_type_import">
               Import a branch hosted somewhere else
             </label>