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

Proposed by Curtis Hovey
Status: Merged
Approved by: Curtis Hovey
Approved revision: no longer in the source branch.
Merged at revision: 14929
Proposed branch: lp:~sinzui/launchpad/remove-register-branch
Merge into: lp:launchpad
Diff against target: 1656 lines (+113/-845)
28 files modified
lib/lp/code/browser/branch.py (+0/-75)
lib/lp/code/browser/branchlisting.py (+1/-18)
lib/lp/code/browser/configure.zcml (+0/-23)
lib/lp/code/browser/tests/test_branch.py (+0/-56)
lib/lp/code/browser/tests/test_product.py (+7/-0)
lib/lp/code/javascript/tests/test_productseries-setbranch.html (+12/-24)
lib/lp/code/javascript/tests/test_productseries_setbranch.js (+1/-33)
lib/lp/code/stories/branches/xx-branch-deletion.txt (+9/-8)
lib/lp/code/stories/branches/xx-creating-branches.txt (+0/-247)
lib/lp/code/stories/branches/xx-junk-branches.txt (+0/-50)
lib/lp/code/stories/branches/xx-product-branches.txt (+16/-15)
lib/lp/code/stories/branches/xx-register-a-branch.txt (+0/-19)
lib/lp/code/templates/bazaar-index.pt (+0/-8)
lib/lp/code/templates/branch-add.pt (+0/-21)
lib/lp/code/templates/person-branches.pt (+0/-3)
lib/lp/code/templates/product-branch-summary.pt (+18/-3)
lib/lp/code/templates/product-branches.pt (+0/-7)
lib/lp/registry/browser/pillar.py (+1/-14)
lib/lp/registry/browser/product.py (+0/-6)
lib/lp/registry/browser/productseries.py (+3/-34)
lib/lp/registry/browser/tests/pillar-views.txt (+0/-2)
lib/lp/registry/browser/tests/productseries-setbranch-view.txt (+8/-68)
lib/lp/registry/browser/tests/productseries-views.txt (+0/-19)
lib/lp/registry/stories/productseries/xx-productseries-index.txt (+0/-10)
lib/lp/registry/stories/productseries/xx-productseries-set-branch.txt (+10/-35)
lib/lp/registry/templates/productseries-codesummary.pt (+11/-24)
lib/lp/registry/templates/productseries-linkbranch.pt (+3/-14)
lib/lp/registry/templates/productseries-setbranch.pt (+13/-9)
To merge this branch: bzr merge lp:~sinzui/launchpad/remove-register-branch
Reviewer Review Type Date Requested Status
j.c.sackett (community) Approve
Review via email: mp+96649@code.launchpad.net

Commit message

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

Description of the change

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

To post a comment you must log in.
Revision history for this message
j.c.sackett (jcsackett) wrote :

Curtis--

Wow, huge branch. Lots of cleanup though, lots of improvement to tests not killed, and a good job of removing the +addbranch stuff. I think this branch looks good.

Thanks.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/code/browser/branch.py'
2--- lib/lp/code/browser/branch.py 2012-02-14 03:49:35 +0000
3+++ lib/lp/code/browser/branch.py 2012-03-08 20:07:31 +0000
4@@ -6,7 +6,6 @@
5 __metaclass__ = type
6
7 __all__ = [
8- 'BranchAddView',
9 'BranchContextMenu',
10 'BranchDeletionView',
11 'BranchEditStatusView',
12@@ -103,7 +102,6 @@
13 CodeImportResultStatus,
14 CodeImportReviewStatus,
15 RevisionControlSystems,
16- UICreatableBranchType,
17 )
18 from lp.code.errors import (
19 BranchCreationForbidden,
20@@ -122,10 +120,8 @@
21 from lp.code.interfaces.branchcollection import IAllBranches
22 from lp.code.interfaces.branchmergeproposal import IBranchMergeProposal
23 from lp.code.interfaces.branchnamespace import IBranchNamespacePolicy
24-from lp.code.interfaces.branchtarget import IBranchTarget
25 from lp.code.interfaces.codereviewvote import ICodeReviewVoteReference
26 from lp.registry.interfaces.person import (
27- IPerson,
28 IPersonSet,
29 )
30 from lp.registry.interfaces.productseries import IProductSeries
31@@ -1154,77 +1150,6 @@
32 return {'reviewer': self.context.code_reviewer}
33
34
35-class BranchAddView(LaunchpadFormView, BranchNameValidationMixin):
36-
37- class schema(Interface):
38- use_template(
39- IBranch, include=['owner', 'name', 'lifecycle_status'])
40-
41- for_input = True
42- field_names = ['owner', 'name', 'lifecycle_status']
43-
44- branch = None
45- custom_widget('lifecycle_status', LaunchpadRadioWidgetWithDescription)
46-
47- initial_focus_widget = 'name'
48-
49- @property
50- def page_title(self):
51- return 'Register a branch'
52-
53- @property
54- def initial_values(self):
55- return {
56- 'owner': self.default_owner,
57- 'branch_type': UICreatableBranchType.MIRRORED}
58-
59- @property
60- def target(self):
61- """The branch target for the context."""
62- return IBranchTarget(self.context)
63-
64- @property
65- def default_owner(self):
66- """The default owner of branches in this context.
67-
68- If the context is a person, then it's the context. If the context is
69- not a person, then the default owner is the currently logged-in user.
70- """
71- return IPerson(self.context, self.user)
72-
73- @action('Register Branch', name='add')
74- def add_action(self, action, data):
75- """Handle a request to create a new branch for this product."""
76- try:
77- namespace = self.target.getNamespace(data['owner'])
78- self.branch = namespace.createBranch(
79- branch_type=BranchType.HOSTED,
80- name=data['name'],
81- registrant=self.user,
82- url=None,
83- lifecycle_status=data['lifecycle_status'])
84- except BranchCreationForbidden:
85- self.addError(
86- "You are not allowed to create branches in %s." %
87- self.context.displayname)
88- except BranchExists, e:
89- self._setBranchExists(e.existing_branch)
90- else:
91- self.next_url = canonical_url(self.branch)
92-
93- def validate(self, data):
94- owner = data['owner']
95-
96- if not self.user.inTeam(owner):
97- self.setFieldError(
98- 'owner',
99- 'You are not a member of %s' % owner.displayname)
100-
101- @property
102- def cancel_url(self):
103- return canonical_url(self.context)
104-
105-
106 class BranchSubscriptionsView(LaunchpadView):
107 """The view for the branch subscriptions portlet.
108
109
110=== modified file 'lib/lp/code/browser/branchlisting.py'
111--- lib/lp/code/browser/branchlisting.py 2012-02-21 12:11:11 +0000
112+++ lib/lp/code/browser/branchlisting.py 2012-03-08 20:07:31 +0000
113@@ -838,7 +838,7 @@
114
115 usedfor = IPerson
116 facet = 'branches'
117- links = ['registered', 'owned', 'subscribed', 'addbranch',
118+ links = ['registered', 'owned', 'subscribed',
119 'active_reviews', 'mergequeues', 'source_package_recipes',
120 'simplified_subscribed', 'simplified_registered',
121 'simplified_owned', 'simplified_active_reviews']
122@@ -980,17 +980,6 @@
123 'active reviews')
124 return Link('+activereviews', text)
125
126- def addbranch(self):
127- if self.user is None:
128- enabled = False
129- else:
130- enabled = self.user.inTeam(self.context)
131- text = 'Register a branch'
132- summary = 'Register a new Bazaar branch'
133- return Link(
134- '+addbranch', text, summary, icon='add', enabled=enabled,
135- site='code')
136-
137
138 class PersonProductBranchesMenu(PersonBranchesMenu):
139
140@@ -1150,7 +1139,6 @@
141 usedfor = IProduct
142 facet = 'branches'
143 links = [
144- 'branch_add',
145 'list_branches',
146 'active_reviews',
147 'code_import',
148@@ -1160,11 +1148,6 @@
149 'active_review_count',
150 ]
151
152- def branch_add(self):
153- text = 'Register a branch'
154- summary = 'Register a new Bazaar branch for this project'
155- return Link('+addbranch', text, summary, icon='add', site='code')
156-
157 def list_branches(self):
158 text = 'List branches'
159 summary = 'List the branches for this project'
160
161=== modified file 'lib/lp/code/browser/configure.zcml'
162--- lib/lp/code/browser/configure.zcml 2012-02-01 19:18:30 +0000
163+++ lib/lp/code/browser/configure.zcml 2012-03-08 20:07:31 +0000
164@@ -878,13 +878,6 @@
165 name="+activereviews"
166 template="../templates/active-reviews.pt"/>
167 <browser:page
168- name="+addbranch"
169- for="lp.registry.interfaces.person.IPerson"
170- layer="lp.code.publisher.CodeLayer"
171- class="lp.code.browser.branch.BranchAddView"
172- permission="launchpad.AnyPerson"
173- template="../templates/branch-add.pt"/>
174- <browser:page
175 for="lp.registry.interfaces.person.IPerson"
176 layer="lp.code.publisher.CodeLayer"
177 class="lp.code.browser.branchlisting.PersonTeamBranchesView"
178@@ -927,22 +920,6 @@
179 name="+count-summary"
180 template="../templates/branch-count-summary.pt"/>
181
182- <browser:page
183- name="+addbranch"
184- for="lp.registry.interfaces.product.IProduct"
185- layer="lp.code.publisher.CodeLayer"
186- class="lp.code.browser.branch.BranchAddView"
187- permission="launchpad.AnyPerson"
188- template="../templates/branch-add.pt"/>
189-
190- <browser:page
191- name="+addbranch"
192- for="lp.registry.interfaces.productseries.IProductSeries"
193- layer="lp.code.publisher.CodeLayer"
194- class="lp.code.browser.branch.BranchAddView"
195- permission="launchpad.AnyPerson"
196- template="../templates/branch-add.pt"/>
197-
198 <browser:menus
199 classes="ProductBranchesMenu"
200 module="lp.code.browser.branchlisting"/>
201
202=== modified file 'lib/lp/code/browser/tests/test_branch.py'
203--- lib/lp/code/browser/tests/test_branch.py 2012-01-20 03:30:06 +0000
204+++ lib/lp/code/browser/tests/test_branch.py 2012-03-08 20:07:31 +0000
205@@ -19,7 +19,6 @@
206 UNRESOLVED_BUGTASK_STATUSES,
207 )
208 from lp.code.browser.branch import (
209- BranchAddView,
210 BranchMirrorStatusView,
211 BranchReviewerEditView,
212 BranchView,
213@@ -31,11 +30,9 @@
214 RepositoryFormat,
215 )
216 from lp.code.enums import (
217- BranchLifecycleStatus,
218 BranchType,
219 BranchVisibilityRule,
220 )
221-from lp.code.interfaces.branchtarget import IBranchTarget
222 from lp.registry.interfaces.person import PersonVisibility
223 from lp.services.config import config
224 from lp.services.database.constants import UTC_NOW
225@@ -188,29 +185,6 @@
226 "This is a short error message.",
227 branch_view.mirror_status_message)
228
229- def testBranchAddRequests(self):
230- """Registering a branch that requests a mirror."""
231- arbitrary_person = self.factory.makePerson()
232- arbitrary_product = self.factory.makeProduct()
233- login_person(arbitrary_person)
234- try:
235- add_view = BranchAddView(arbitrary_person, self.request)
236- add_view.initialize()
237- data = {
238- 'branch_type': BranchType.HOSTED,
239- 'name': 'some-branch',
240- 'title': 'Branch Title',
241- 'summary': '',
242- 'lifecycle_status': BranchLifecycleStatus.DEVELOPMENT,
243- 'whiteboard': '',
244- 'owner': arbitrary_person,
245- 'author': arbitrary_person,
246- 'product': arbitrary_product,
247- }
248- add_view.add_action.success(data)
249- finally:
250- logout()
251-
252 def testShowMergeLinksOnManyBranchProject(self):
253 # The merge links are shown on projects that have multiple branches.
254 product = self.factory.makeProduct(name='super-awesome-project')
255@@ -672,36 +646,6 @@
256 self.assertIsNone(reviews_list.find('a', text='Privateteam'))
257
258
259-class TestBranchAddView(TestCaseWithFactory):
260- """Test the BranchAddView view."""
261-
262- layer = DatabaseFunctionalLayer
263-
264- def setUp(self):
265- super(TestBranchAddView, self).setUp()
266- self.person = self.factory.makePerson()
267- login_person(self.person)
268- self.request = LaunchpadTestRequest()
269-
270- def tearDown(self):
271- logout()
272- super(TestBranchAddView, self).tearDown()
273-
274- def get_view(self, context):
275- view = BranchAddView(context, self.request)
276- view.initialize()
277- return view
278-
279- def test_target_person(self):
280- add_view = self.get_view(self.person)
281- self.assertTrue(IBranchTarget.providedBy(add_view.target))
282-
283- def test_target_product(self):
284- product = self.factory.makeProduct()
285- add_view = self.get_view(product)
286- self.assertTrue(IBranchTarget.providedBy(add_view.target))
287-
288-
289 class TestBranchReviewerEditView(TestCaseWithFactory):
290 """Test the BranchReviewerEditView view."""
291
292
293=== modified file 'lib/lp/code/browser/tests/test_product.py'
294--- lib/lp/code/browser/tests/test_product.py 2012-01-01 02:58:52 +0000
295+++ lib/lp/code/browser/tests/test_product.py 2012-03-08 20:07:31 +0000
296@@ -185,6 +185,13 @@
297 commit_section = find_tag_by_id(view.render(), 'commits')
298 self.assertIs(None, commit_section)
299
300+ def test_initial_branches_contains_push_instructions(self):
301+ product, branch = self.makeProductAndDevelopmentFocusBranch()
302+ view = create_initialized_view(
303+ product, '+code-index', rootsite='code', principal=product.owner)
304+ content = view()
305+ self.assertIn('bzr push lp:~', content)
306+
307
308 class TestProductCodeIndexServiceUsages(ProductTestBase, BrowserTestCase):
309 """Tests for the product code page, especially the usage messasges."""
310
311=== modified file 'lib/lp/code/javascript/tests/test_productseries-setbranch.html'
312--- lib/lp/code/javascript/tests/test_productseries-setbranch.html 2012-02-13 14:15:36 +0000
313+++ lib/lp/code/javascript/tests/test_productseries-setbranch.html 2012-03-08 20:07:31 +0000
314@@ -62,7 +62,7 @@
315 <label>
316 <input class="radioType" checked="checked"
317 id="field.branch_type.0"
318- name="field.branch_type" type="radio" value="link-lp-bzr">
319+ name="field.branch_type" type="radio" value="link-lp-bzr" />
320 Link to a Bazaar branch already in Launchpad
321 </label>
322 <table>
323@@ -73,7 +73,7 @@
324 <span class="fieldRequired">(Optional)</span>
325 <div>
326 <input type="text" value="" id="field.branch_location"
327- name="field.branch_location" size="35">
328+ name="field.branch_location" size="35" />
329
330 </div>
331 <p class="formHelp">The Bazaar branch for this series in
332@@ -89,20 +89,8 @@
333 <td>
334 <label>
335 <input class="radioType" id="field.branch_type.1"
336- name="field.branch_type"
337- type="radio" value="create-new">
338- Create a new, empty branch in Launchpad and link
339- to this series
340- </label>
341- </td>
342- </tr>
343-
344- <tr>
345- <td>
346- <label>
347- <input class="radioType" id="field.branch_type.2"
348 name="field.branch_type" type="radio"
349- value="import-external">
350+ value="import-external" />
351 Import a branch hosted somewhere else
352 </label>
353 <table>
354@@ -114,7 +102,7 @@
355 <div>
356 <input class="urlTextType textType" id="field.repo_url"
357 name="field.repo_url" size="44" type="text"
358- value="" disabled="">
359+ value="" disabled="" />
360 </div>
361 </td>
362 </tr>
363@@ -124,7 +112,7 @@
364 <label>
365 <input class="radioType" id="field.rcs_type.6"
366 name="field.rcs_type" type="radio" value="BZR"
367- disabled="">
368+ disabled="" />
369 Bazaar, hosted externally
370 </label>
371 </td>
372@@ -135,7 +123,7 @@
373 <label>
374 <input class="radioType" id="field.rcs_type.4"
375 name="field.rcs_type" type="radio" value="GIT"
376- disabled="">
377+ disabled="" />
378 Git
379 </label>
380 </td>
381@@ -146,7 +134,7 @@
382 <label>
383 <input class="radioType" id="field.rcs_type.3"
384 name="field.rcs_type" type="radio"
385- value="BZR_SVN" disabled="">
386+ value="BZR_SVN" disabled="" />
387 SVN
388 </label>
389 </td>
390@@ -156,7 +144,7 @@
391 <td>
392 <label>
393 <input class="radioType" id="field.rcs_type.5"
394- name="field.rcs_type" type="radio" value="HG" disabled="">
395+ name="field.rcs_type" type="radio" value="HG" disabled="" />
396 Mercurial
397 </label>
398 </td>
399@@ -167,7 +155,7 @@
400 <label>
401 <input class="radioType" id="field.rcs_type.1"
402 name="field.rcs_type" type="radio" value="CVS"
403- disabled="">
404+ disabled="" />
405 CVS
406 </label>
407
408@@ -182,7 +170,7 @@
409 <input class="textType" id="field.cvs_module"
410 name="field.cvs_module" size="20"
411 type="text"
412- value="" disabled="">
413+ value="" disabled="" />
414 </div>
415 </td>
416 </tr>
417@@ -199,7 +187,7 @@
418 <td colspan="2">
419 <label for="field.branch_name">Branch name:</label>
420 <div>
421- <input class="textType" id="field.branch_name" name="field.branch_name" size="20" type="text" value="" />
422+ <input class="textType" id="field.branch_name" name="field.branch_name" size="20" type="text" value="" />
423 </div>
424 </td>
425 </tr>
426@@ -228,7 +216,7 @@
427 </tbody>
428 </table>
429 <input type="submit" id="field.actions.update"
430- name="field.actions.update" value="Update" class="button">
431+ name="field.actions.update" value="Update" class="button" />
432 or&nbsp;
433 <a href="https://launchpad.dev/zyc/trunk">Cancel</a>
434 </form>
435
436=== modified file 'lib/lp/code/javascript/tests/test_productseries_setbranch.js'
437--- lib/lp/code/javascript/tests/test_productseries_setbranch.js 2011-07-08 05:12:39 +0000
438+++ lib/lp/code/javascript/tests/test_productseries_setbranch.js 2012-03-08 20:07:31 +0000
439@@ -28,8 +28,7 @@
440
441 // Get the individual branch type radio buttons.
442 this.link_lp_bzr = Y.DOM.byId('field.branch_type.0');
443- this.create_new = Y.DOM.byId('field.branch_type.1');
444- this.import_external = Y.DOM.byId('field.branch_type.2');
445+ this.import_external = Y.DOM.byId('field.branch_type.1');
446
447 // Get the input widgets.
448 this.branch_location = Y.DOM.byId('field.branch_location');
449@@ -66,7 +65,6 @@
450 };
451
452 check_handler(this.link_lp_bzr, module.onclick_branch_type);
453- check_handler(this.create_new, module.onclick_branch_type);
454 check_handler(this.import_external, module.onclick_branch_type);
455
456 check_handler(this.cvs, module.onclick_rcs_type);
457@@ -106,36 +104,6 @@
458 'bzr button not disabled');
459 },
460
461- test_select_create_new: function() {
462- this.create_new.checked = true;
463- module.onclick_branch_type();
464- // The branch location is disabled.
465- Y.Assert.isTrue(this.branch_location.disabled,
466- 'branch_location not disabled');
467- module.onclick_rcs_type();
468- // The CVS module and repo url are disabled.
469- Y.Assert.isTrue(this.cvs_module.disabled,
470- 'cvs_module not disabled');
471- Y.Assert.isTrue(this.repo_url.disabled,
472- 'repo_url not disabled');
473- // The branch name and owner are enabled.
474- Y.Assert.isFalse(this.branch_name.disabled,
475- 'branch_name disabled');
476- Y.Assert.isFalse(this.branch_owner.disabled,
477- 'branch_owner disabled');
478- // All of the radio buttons are disabled.
479- Y.Assert.isTrue(this.cvs.disabled,
480- 'cvs button not disabled');
481- Y.Assert.isTrue(this.svn.disabled,
482- 'svn button not disabled');
483- Y.Assert.isTrue(this.git.disabled,
484- 'git button not disabled');
485- Y.Assert.isTrue(this.hg.disabled,
486- 'hg button not disabled');
487- Y.Assert.isTrue(this.bzr.disabled,
488- 'bzr button not disabled');
489- },
490-
491 test_select_import_external: function() {
492 this.import_external.checked = true;
493 module.onclick_branch_type();
494
495=== modified file 'lib/lp/code/stories/branches/xx-branch-deletion.txt'
496--- lib/lp/code/stories/branches/xx-branch-deletion.txt 2012-01-15 13:32:27 +0000
497+++ lib/lp/code/stories/branches/xx-branch-deletion.txt 2012-03-08 20:07:31 +0000
498@@ -16,13 +16,13 @@
499 ... product=product, branch=branch)
500 >>> login_person(alice)
501 >>> product.development_focus = productseries
502+ >>> delete_branch = factory.makeProductBranch(
503+ ... name='to-delete', owner=alice,
504+ ... product=product, branch_type=BranchType.HOSTED)
505 >>> logout()
506
507 >>> browser = setupBrowser(auth="Basic alice@example.com:test")
508- >>> browser.open('http://code.launchpad.dev/earthlynx')
509- >>> browser.getLink("Register a branch").click()
510- >>> browser.getControl('Name').value = 'to-delete'
511- >>> browser.getControl('Register Branch').click()
512+ >>> browser.open('http://code.launchpad.dev/~alice/earthlynx/to-delete')
513 >>> print browser.title
514 to-delete : Code : Earth Lynx
515
516@@ -56,10 +56,11 @@
517 If the branch is junk, then the user is taken back to the code listing for
518 the deleted branch's owner.
519
520- >>> browser.open('http://code.launchpad.dev/~alice')
521- >>> browser.getLink("Register a branch").click()
522- >>> browser.getControl('Name').value = 'to-delete'
523- >>> browser.getControl('Register Branch').click()
524+ >>> login_person(alice)
525+ >>> delete_branch = factory.makePersonalBranch(
526+ ... name='to-delete', owner=alice)
527+ >>> logout()
528+ >>> browser.open('http://code.launchpad.dev/~alice/+junk/to-delete')
529 >>> browser.getLink('Delete branch').click()
530 >>> browser.getControl('Delete').click()
531 >>> print browser.url
532
533=== removed file 'lib/lp/code/stories/branches/xx-creating-branches.txt'
534--- lib/lp/code/stories/branches/xx-creating-branches.txt 2011-08-29 16:37:46 +0000
535+++ lib/lp/code/stories/branches/xx-creating-branches.txt 1970-01-01 00:00:00 +0000
536@@ -1,247 +0,0 @@
537-Creating Branches
538-=================
539-
540-In the past, there were two very distinct ways of creating branches in
541-Launchpad. The first was to use the UI, and the other was to push the
542-branch to Launchpad. The first method only created MIRRORED branches,
543-and the second only HOSTED.
544-
545-Many users were confused with this, and tried to create HOSTED branches
546-using the user interface. Now they can.
547-
548-
549-Creating a hosted branch
550-------------------------
551-
552-Hosted branches use Launchpad as their primary location.
553-
554- >>> from zope.component import getUtility
555- >>> from lp.code.enums import BranchType
556- >>> from lp.registry.interfaces.product import IProductSet
557- >>> login(ANONYMOUS)
558- >>> redfish = getUtility(IProductSet).getByName('redfish')
559- >>> branch = factory.makeProductBranch(
560- ... product=redfish, branch_type=BranchType.HOSTED)
561- >>> productseries = factory.makeProductSeries(
562- ... product=redfish, branch=branch)
563- >>> login_person(redfish.owner)
564- >>> redfish.development_focus = productseries
565- >>> logout()
566-
567- >>> browser = setupBrowser(auth="Basic test@canonical.com:test")
568- >>> browser.open('http://code.launchpad.dev/redfish')
569- >>> browser.getLink("Register a branch").click()
570-
571- >>> browser.getControl('Name').value = 'hosted-branch'
572-
573-Finding product/+addbranch
574---------------------------
575-
576-We should be able to create a new branch from a product.
577-
578-First, check that the +addbranch link is visible on the product code
579-facet page.
580-
581- >>> user_browser.open('http://code.launchpad.dev/applets')
582- >>> print user_browser.url
583- http://code.launchpad.dev/applets
584-
585-Let's make sure we can load the branch creation form on a product.
586-
587- >>> user_browser.getLink("Register a branch").click()
588- Traceback (most recent call last):
589- ...
590- LinkNotFoundError
591-
592-The link is not there because the product has not been configured to
593-do code hosting yet. The development focus must be set with a branch first.
594-
595- >>> owner_browser = setupBrowser(auth="Basic foo.bar@canonical.com:test")
596- >>> owner_browser.open('http://code.launchpad.dev/applets')
597- >>> owner_browser.getLink('Configure code hosting').click()
598- >>> print owner_browser.url
599- http://code.launchpad.dev/applets/trunk/+setbranch
600-
601- >>> owner_browser.getControl(
602- ... 'Create a new, empty branch').click()
603- >>> owner_browser.getControl('Branch name').value = 'trunk'
604- >>> owner_browser.getControl('Update').click()
605-
606-Now that code hosting has been configured, a regular user will be able
607-to register a branch.
608-
609- >>> user_browser.open('http://code.launchpad.dev/applets')
610- >>> user_browser.getLink("Register a branch").click()
611- >>> print user_browser.url
612- http://code.launchpad.dev/applets/+addbranch
613-
614-
615-Adding a branch to a product
616-----------------------------
617-
618-Now, post the branch creation form for the product.
619-
620- >>> user_browser.open('http://code.launchpad.dev/applets/+addbranch')
621-
622-The specified URL has a trailing slash. In the next test, we will check
623-that it has been stripped.
624-
625- >>> user_browser.getControl('Name').value = 'main'
626- >>> user_browser.getControl('Experimental').click()
627- >>> user_browser.getControl('Register Branch').click()
628-
629-Posting the form should succeed and redirect to the page of the newly
630-registered branch. We check that the final slash of the URL was stripped
631-by matching for the angle brackets of an enclosing tag.
632-
633- >>> user_browser.url
634- 'http://code.launchpad.dev/~no-priv/applets/main'
635-
636- >>> content = find_tag_by_id(user_browser.contents, 'document')
637- >>> print extract_text(find_tag_by_id(content, 'registration'))
638- Created by No Privileges Person on ... and last modified on ...
639-
640- >>> print extract_text(find_tag_by_id(content, 'privacy'))
641- This branch is public
642-
643-This page includes a link to other branches associated with that
644-product, and a link to other branches maintained by that person.
645-
646- >>> print extract_text(find_tags_by_class(
647- ... user_browser.contents, 'related', only_first=True))
648- Nearby
649- Other Gnome Applets branches
650- Other branches owned by No Privileges Person
651-
652-
653-Finding person/+addbranch
654--------------------------
655-
656-The user is only able to register a branch where either they or a team
657-that they are a member of are the owner, so the 'Register branch' option
658-is only shown on the code pages for teams that the user is a member of,
659-and their own code page.
660-
661-Since no-priv is not a member of lifeless, the Register branch link is
662-not shown.
663-
664- >>> user_browser.open('http://code.launchpad.dev/~lifeless')
665- >>> user_browser.getLink("Register a branch")
666- Traceback (most recent call last):
667- ...
668- LinkNotFoundError
669-
670- >>> browser.open('http://code.launchpad.dev/~landscape-developers')
671- >>> browser.getLink("Register a branch").click()
672- >>> print browser.getControl('Owner').displayValue
673- ['Landscape Developers (landscape-developers)']
674-
675-The user is able to change the owner of the branch to any team that the
676-user is a member of, or to themselves.
677-
678- >>> for option in browser.getControl('Owner').displayOptions:
679- ... print option
680- Sample Person (name12)
681- HWDB Team (hwdb-team)
682- Landscape Developers (landscape-developers)
683- Launchpad Users (launchpad-users)
684- Ubuntu Gnome Team (name18)
685- Warty Security Team (name20)
686-
687-Conflict on unique name
688------------------------
689-
690-Trying to register a branch with a product and that matches an existing
691-branch owned by the user would cause a database integrity error, because
692-the triplet owner-product-name is unique for all branches.
693-
694-For this example, we will use ~name12/gnome-terminal/main. Check that it
695-already exists.
696-
697- >>> browser.open(
698- ... 'http://launchpad.dev/~name12/+branch/gnome-terminal/main')
699-
700-Try a adding a conflicting branch from the product/+addbranch form.
701-
702- >>> browser.open('http://code.launchpad.dev/gnome-terminal/+addbranch')
703-
704-Trying to post the form without filling a name at all should not cause
705-an oops!
706-
707- >>> browser.getControl('Register Branch').click()
708- >>> browser.url
709- 'http://code.launchpad.dev/gnome-terminal/+addbranch'
710-
711-Now, complete the form, but give a name that is alredy in use for that
712-owner and product.
713-
714- >>> browser.getControl('Name').value = 'main'
715- >>> browser.getControl('Register Branch').click()
716-
717-That should give us the form back with an error message.
718-
719- >>> browser.url
720- 'http://code.launchpad.dev/gnome-terminal/+addbranch'
721-
722- >>> for message in get_feedback_messages(browser.contents):
723- ... print extract_text(message)
724- There is 1 error.
725- You already have a branch for GNOME Terminal called main.
726-
727-If the user is trying to add a branch for a team that conflicts, then
728-the team name is given in the error message.
729-
730- >>> browser.open('http://code.launchpad.dev/gnome-terminal/+addbranch')
731- >>> browser.getControl('Owner').displayValue = [
732- ... 'Landscape Developers']
733- >>> browser.getControl('Name').value = 'main'
734- >>> browser.getControl('Register Branch').click()
735- >>> print browser.url
736- http://code.launchpad.dev/~landscape-developers/gnome-terminal/main
737-
738- >>> for message in get_feedback_messages(browser.contents):
739- ... print extract_text(message)
740-
741-Now registering again with the same name.
742-
743- >>> browser.open('http://code.launchpad.dev/gnome-terminal/+addbranch')
744- >>> browser.getControl('Owner').displayValue = [
745- ... 'Landscape Developers']
746- >>> browser.getControl('Name').value = 'main'
747- >>> browser.getControl('Register Branch').click()
748- >>> for message in get_feedback_messages(browser.contents):
749- ... print extract_text(message)
750- There is 1 error.
751- Landscape Developers already has a branch for GNOME Terminal called main.
752-
753-
754-Attempting to create a branch in a forbidden project
755-----------------------------------------------------
756-
757-The branch visibility policy for a product may specify that certain
758-groups of people cannot create branches. An example of this in the
759-sample data is the landscape project. Only landscape developers can
760-create branches for landscape.
761-
762-When registering a branch from the product pages, there is no product
763-widget, so errors are set at the page level.
764-
765- >>> owner_browser = setupBrowser(auth="Basic test@canonical.com:test")
766- >>> owner_browser.open('http://code.launchpad.dev/landscape')
767- >>> owner_browser.getLink('Configure code hosting').click()
768- >>> owner_browser.getControl(
769- ... 'Create a new, empty branch').click()
770- >>> owner_browser.getControl('Branch name').value = 'trunk'
771- >>> owner_browser.getControl('Update').click()
772-
773- >>> user_browser.open('http://code.launchpad.dev/landscape')
774- >>> user_browser.getLink("Register a branch").click()
775- >>> user_browser.getControl('Name').value = 'landscape1'
776- >>> user_browser.getControl('Register Branch').click()
777- >>> messages = find_tags_by_class(user_browser.contents, 'message')
778- >>> for element in messages:
779- ... print element.renderContents()
780- There is 1 error.
781- You are not allowed to create branches in The Landscape Project.
782-
783-
784
785=== removed file 'lib/lp/code/stories/branches/xx-junk-branches.txt'
786--- lib/lp/code/stories/branches/xx-junk-branches.txt 2012-01-15 13:32:27 +0000
787+++ lib/lp/code/stories/branches/xx-junk-branches.txt 1970-01-01 00:00:00 +0000
788@@ -1,50 +0,0 @@
789-Junk Branches
790-=============
791-
792-Create a person and team.
793-
794- >>> login(ANONYMOUS)
795- >>> eric = factory.makePerson(name='eric', email='eric@example.com')
796- >>> vikings = factory.makeTeam(name='vikings', owner=eric)
797- >>> logout()
798-
799-When creating a branch from a person, we have the option not to specify an
800-associated product. A branch with no associated product is called a "junk"
801-branch.
802-
803- >>> browser = setupBrowser(auth="Basic eric@example.com:test")
804- >>> browser.open('http://code.launchpad.dev/~eric')
805- >>> browser.getLink("Register a branch").click()
806- >>> browser.getControl('Name').value = 'personal-junk'
807- >>> browser.getControl('Register Branch').click()
808-
809-Posting the form should succeed and redirect to the page of the newly created
810-junk branch. Because it has no product, it has no link to other product
811-branches.
812-
813- >>> print browser.url
814- http://code.launchpad.dev/~eric/+junk/personal-junk
815- >>> print extract_text(find_tags_by_class(
816- ... browser.contents, 'related', only_first=True))
817- Nearby
818- Other branches owned by Eric
819-
820-Junk branches do not support merge proposals, so the "Branch Merges" section
821-of the page should not be shown.
822-
823- >>> print find_tag_by_id(browser.contents, 'branch-merges')
824- None
825-
826-
827-Team Junk Branches
828-==================
829-
830-Junk branches can also be associated with a team.
831-
832- >>> browser.open('http://code.launchpad.dev/~vikings')
833- >>> browser.getLink("Register a branch").click()
834- >>> browser.getControl('Name').value = 'team-junk'
835- >>> browser.getControl('Register Branch').click()
836-
837- >>> print browser.url
838- http://code.launchpad.dev/~vikings/+junk/team-junk
839
840=== modified file 'lib/lp/code/stories/branches/xx-product-branches.txt'
841--- lib/lp/code/stories/branches/xx-product-branches.txt 2010-10-18 13:04:16 +0000
842+++ lib/lp/code/stories/branches/xx-product-branches.txt 2012-03-08 20:07:31 +0000
843@@ -169,13 +169,16 @@
844 Involvement portlet
845 ===================
846
847-There are several links in the side portlet: 'Register a branch',
848+There are several links in the side portlet:
849 'Import a branch', 'Configure code hosting', and 'Define branch
850 visibility'. The links are only shown if the user has permission to
851 perform the task.
852
853 >>> from zope.component import getUtility
854 >>> from lp.registry.interfaces.product import IProductSet
855+ >>> from lp.testing import celebrity_logged_in
856+ >>> from lp.testing.factory import LaunchpadObjectFactory
857+ >>> factory = LaunchpadObjectFactory()
858 >>> login(ANONYMOUS)
859 >>> product = getUtility(IProductSet).getByName('firefox')
860 >>> old_branch = product.development_focus.branch
861@@ -191,12 +194,10 @@
862 ... print extract_text(link)
863
864 >>> def setup_code_hosting(productname):
865- ... admin_browser.open('http://code.launchpad.dev/%s' % productname)
866- ... admin_browser.getLink('Configure code hosting').click()
867- ... admin_browser.getControl(
868- ... 'Create a new, empty branch').click()
869- ... admin_browser.getControl('Branch name').value = 'trunk'
870- ... admin_browser.getControl('Update').click()
871+ ... with celebrity_logged_in('admin'):
872+ ... product = getUtility(IProductSet).getByName(productname)
873+ ... branch = factory.makeProductBranch(product=product)
874+ ... product.development_focus.branch = branch
875
876 The involvement portlet is not shown if the product does not have code
877 hosting configured or if it is not using Launchpad.
878@@ -212,7 +213,6 @@
879 LAUNCHPAD
880 >>> admin_browser.open('http://code.launchpad.dev/firefox')
881 >>> print_links(admin_browser)
882- Register a branch
883 Import a branch
884 Configure code hosting
885 Define branch visibility
886@@ -223,7 +223,6 @@
887 >>> owner_browser = setupBrowser(auth='Basic test@canonical.com:test')
888 >>> owner_browser.open('http://code.launchpad.dev/firefox')
889 >>> print_links(owner_browser)
890- Register a branch
891 Import a branch
892 Configure code hosting
893
894@@ -231,7 +230,6 @@
895
896 >>> user_browser.open('http://code.launchpad.dev/firefox')
897 >>> print_links(user_browser)
898- Register a branch
899 Import a branch
900
901 If the product specifies that it officially uses Launchpad code, then
902@@ -242,7 +240,6 @@
903 >>> logout()
904 >>> browser.open('http://code.launchpad.dev/firefox')
905 >>> print_links(browser)
906- Register a branch
907 Import a branch
908
909
910@@ -267,7 +264,8 @@
911
912 >>> setup_code_hosting('gnome-terminal')
913 >>> print_portlet('gnome-terminal')
914- GNOME Terminal has 9 active branches owned by 2 people and 2 teams. There were 0 commits in the last month.
915+ GNOME Terminal has 9 active branches owned by 2 people and 2 teams.
916+ There were 0 commits in the last month.
917
918 >>> from lp.testing import ANONYMOUS, login, logout
919 >>> login(ANONYMOUS)
920@@ -276,17 +274,20 @@
921 >>> logout()
922 >>> setup_code_hosting('fooix')
923 >>> print_portlet('fooix')
924- Fooix has 2 active branches owned by 2 people. There were 0 commits in the last month.
925+ Fooix has 2 active branches owned by 2 people.
926+ There were 0 commits in the last month.
927
928 >>> print_portlet('evolution')
929- Evolution has 3 active branches owned by 1 person and 1 team. There were 0 commits in the last month.
930+ Evolution has 3 active branches owned by 1 person and 1 team.
931+ There were 0 commits in the last month.
932
933 >>> login(ANONYMOUS)
934 >>> dinky = factory.makeProduct('dinky')
935 >>> logout()
936 >>> setup_code_hosting('dinky')
937 >>> print_portlet('dinky')
938- Dinky has 1 active branch owned by 1 person. There were 0 commits in the last month.
939+ Dinky has 1 active branch owned by 1 person. There were 0 commits in
940+ the last month.
941
942
943 Product has Branches, but none initially visible
944
945=== removed file 'lib/lp/code/stories/branches/xx-register-a-branch.txt'
946--- lib/lp/code/stories/branches/xx-register-a-branch.txt 2010-02-05 13:25:46 +0000
947+++ lib/lp/code/stories/branches/xx-register-a-branch.txt 1970-01-01 00:00:00 +0000
948@@ -1,19 +0,0 @@
949-From the Code homepage, register a branch.
950-
951-Clicking on the link as a logged-in user should take you directly to the branch
952-registration page.
953-
954- >>> browser = setupBrowser(auth='Basic test@canonical.com:test')
955- >>> browser.open('http://code.launchpad.dev/')
956- >>> browser.getLink('Register a branch').click()
957- >>> print browser.title
958- Register a branch...
959-
960-Clicking the link as an anonymous user should take you to a login page. Once
961-you've logged in, you will be redirected to the registration page.
962-
963- >>> anon_browser.open('http://code.launchpad.dev/')
964- >>> anon_browser.getLink('Register a branch').click()
965- Traceback (most recent call last):
966- ...
967- Unauthorized:...
968
969=== modified file 'lib/lp/code/templates/bazaar-index.pt'
970--- lib/lp/code/templates/bazaar-index.pt 2012-03-01 17:42:28 +0000
971+++ lib/lp/code/templates/bazaar-index.pt 2012-03-08 20:07:31 +0000
972@@ -20,14 +20,6 @@
973 </a>
974 </li>
975 <li>
976- <a href="/people/+me/+addbranch">
977- <img
978- alt="Register a branch"
979- src="/+icing/but-lrg-registerabranch.gif"
980- />
981- </a>
982- </li>
983- <li>
984 <a href="/+code-imports/+new" id="new-code-import">
985 <img alt="Import your project"
986 src="/+icing/but-lrg-importyourproject.gif"/>
987
988=== removed file 'lib/lp/code/templates/branch-add.pt'
989--- lib/lp/code/templates/branch-add.pt 2009-08-12 00:44:04 +0000
990+++ lib/lp/code/templates/branch-add.pt 1970-01-01 00:00:00 +0000
991@@ -1,21 +0,0 @@
992-<html
993- xmlns="http://www.w3.org/1999/xhtml"
994- xmlns:tal="http://xml.zope.org/namespaces/tal"
995- xmlns:metal="http://xml.zope.org/namespaces/metal"
996- xmlns:i18n="http://xml.zope.org/namespaces/i18n"
997- metal:use-macro="view/macro:page/main_only"
998- i18n:domain="launchpad">
999-
1000-<body>
1001-
1002- <h1 metal:fill-slot="heading">
1003- Register a branch on
1004- <tal:target-name tal:replace="view/target/displayname"/>
1005- </h1>
1006-
1007- <div metal:fill-slot="main">
1008- <metal:add-branch use-macro="context/@@branch-form-macros/add-branch-content"/>
1009- </div>
1010-
1011-</body>
1012-</html>
1013
1014=== modified file 'lib/lp/code/templates/person-branches.pt'
1015--- lib/lp/code/templates/person-branches.pt 2011-11-04 11:29:34 +0000
1016+++ lib/lp/code/templates/person-branches.pt 2012-03-08 20:07:31 +0000
1017@@ -13,9 +13,6 @@
1018 <div tal:define="menu context/menu:branches"
1019 tal:condition="view/show_action_menu"
1020 class="first portlet">
1021- <div tal:define="link menu/addbranch"
1022- tal:condition="link/enabled"
1023- tal:content="structure link/render" />
1024 </div>
1025
1026 <tal:summary replace="structure context/@@+codesummary"/>
1027
1028=== modified file 'lib/lp/code/templates/product-branch-summary.pt'
1029--- lib/lp/code/templates/product-branch-summary.pt 2011-12-29 05:29:36 +0000
1030+++ lib/lp/code/templates/product-branch-summary.pt 2012-03-08 20:07:31 +0000
1031@@ -48,7 +48,7 @@
1032 from it.
1033 </p>
1034 <p tal:condition="view/branch/branch_type/enumvalue:IMPORTED">
1035- Launchpad imports the master branch and you can create branches from
1036+ Launchpad imports the master branch and you can create branches from
1037 it.
1038 </p>
1039
1040@@ -59,7 +59,7 @@
1041
1042 <tal:no-branches condition="not: view/branch_count">
1043 There are no branches for <tal:project-name replace="context/displayname"/>
1044- in Launchpad.
1045+ in Launchpad.
1046 <tal:can-configure condition="view/can_configure_branches">
1047 You can change this by:
1048
1049@@ -95,9 +95,24 @@
1050 using the command:<br/>
1051 <tt style="padding-left:2em">bzr branch <tal:project-name replace="dev_focus/bzr_identity"/></tt>
1052 </div>
1053-
1054 </tal:has-branches>
1055
1056+ <tal:has-user condition="view/user">
1057+ <p id="push-instructions"
1058+ tal:condition="not: context/codehosting_usage/enumvalue:UNKNOWN">
1059+ You can push the branch directly to Launchpad with the command:<br />
1060+ <tt><strong>
1061+ bzr push lp:~<tal:user replace="view/user/name"/>/<tal:project replace="context/name"/>/<tal:series replace="context/name"/>
1062+ </strong></tt>
1063+ <tal:no-keys condition="not:view/user/sshkeys">
1064+ <br/>To authenticate with the Launchpad branch upload service,
1065+ you need to
1066+ <a tal:attributes="href string:${view/user/fmt:url}/+editsshkeys">
1067+ register a SSH key</a>.
1068+ </tal:no-keys>
1069+ </p>
1070+ </tal:has-user>
1071+
1072 <div tal:condition="context/codehosting_usage/enumvalue:UNKNOWN">
1073 <div
1074 tal:condition="not: context/codehosting_usage/enumvalue:LAUNCHPAD"
1075
1076=== modified file 'lib/lp/code/templates/product-branches.pt'
1077--- lib/lp/code/templates/product-branches.pt 2010-10-22 10:28:37 +0000
1078+++ lib/lp/code/templates/product-branches.pt 2012-03-08 20:07:31 +0000
1079@@ -36,13 +36,6 @@
1080
1081 <div id="involvement" class="portlet"
1082 tal:define="menu context/menu:branches">
1083- <ul class="involvement">
1084- <li style="border: none">
1085- <a href="+addbranch" class="menu-link-addbranch sprite code">
1086- Register a branch
1087- </a>
1088- </li>
1089- </ul>
1090 <p style="margin-top:10px;"
1091 tal:define="link menu/code_import"
1092 tal:condition="link/enabled"
1093
1094=== modified file 'lib/lp/registry/browser/pillar.py'
1095--- lib/lp/registry/browser/pillar.py 2012-03-07 07:37:00 +0000
1096+++ lib/lp/registry/browser/pillar.py 2012-03-08 20:07:31 +0000
1097@@ -67,8 +67,7 @@
1098 """The get involved menu."""
1099 usedfor = IInvolved
1100 links = [
1101- 'report_bug', 'ask_question', 'help_translate', 'submit_code',
1102- 'register_blueprint']
1103+ 'report_bug', 'ask_question', 'help_translate', 'register_blueprint']
1104
1105 @property
1106 def pillar(self):
1107@@ -89,18 +88,6 @@
1108 '', 'Help translate', site='translations', icon='translations',
1109 enabled=service_uses_launchpad(self.pillar.translations_usage))
1110
1111- def submit_code(self):
1112- if self.pillar.codehosting_usage in [
1113- ServiceUsage.LAUNCHPAD,
1114- ServiceUsage.EXTERNAL,
1115- ]:
1116- enabled = True
1117- else:
1118- enabled = False
1119- return Link(
1120- '+addbranch', 'Submit code', site='code', icon='code',
1121- enabled=enabled)
1122-
1123 def register_blueprint(self):
1124 return Link(
1125 '+addspec',
1126
1127=== modified file 'lib/lp/registry/browser/product.py'
1128--- lib/lp/registry/browser/product.py 2012-03-02 23:09:34 +0000
1129+++ lib/lp/registry/browser/product.py 2012-03-08 20:07:31 +0000
1130@@ -628,7 +628,6 @@
1131 'announcements',
1132 'administer',
1133 'review_license',
1134- 'branch_add',
1135 'branchvisibility',
1136 'rdf',
1137 'branding',
1138@@ -686,11 +685,6 @@
1139 text = 'Define branch visibility'
1140 return Link('+branchvisibility', text, icon='edit')
1141
1142- def branch_add(self):
1143- text = 'Register a branch'
1144- summary = "Register a new Bazaar branch for this project"
1145- return Link('+addbranch', text, summary, icon='add', site='code')
1146-
1147
1148 class ProductBugsMenu(PillarBugsMenu,
1149 ProductEditLinksMixin):
1150
1151=== modified file 'lib/lp/registry/browser/productseries.py'
1152--- lib/lp/registry/browser/productseries.py 2012-03-01 20:00:29 +0000
1153+++ lib/lp/registry/browser/productseries.py 2012-03-08 20:07:31 +0000
1154@@ -225,7 +225,7 @@
1155 """The get involved menu."""
1156 usedfor = IProductSeriesInvolved
1157 links = [
1158- 'report_bug', 'help_translate', 'submit_code', 'register_blueprint']
1159+ 'report_bug', 'help_translate', 'register_blueprint']
1160
1161 @property
1162 def view(self):
1163@@ -235,20 +235,12 @@
1164 def pillar(self):
1165 return self.view.context.product
1166
1167- def submit_code(self):
1168- target = canonical_url(
1169- self.pillar, view_name='+addbranch', rootsite='code')
1170- enabled = self.view.codehosting_usage == ServiceUsage.LAUNCHPAD
1171- return Link(
1172- target, 'Submit code', icon='code', enabled=enabled)
1173-
1174
1175 class ProductSeriesInvolvementView(PillarView):
1176 """Encourage configuration of involvement links for project series."""
1177
1178 implements(IProductSeriesInvolved)
1179 has_involvement = True
1180- visible_disabled_link_names = ['submit_code']
1181
1182 def __init__(self, context, request):
1183 super(ProductSeriesInvolvementView, self).__init__(context, request)
1184@@ -809,16 +801,12 @@
1185
1186
1187 LINK_LP_BZR = 'link-lp-bzr'
1188-CREATE_NEW = 'create-new'
1189 IMPORT_EXTERNAL = 'import-external'
1190
1191
1192 BRANCH_TYPE_VOCABULARY = SimpleVocabulary((
1193 SimpleTerm(LINK_LP_BZR, LINK_LP_BZR,
1194 _("Link to a Bazaar branch already on Launchpad")),
1195- SimpleTerm(CREATE_NEW, CREATE_NEW,
1196- _("Create a new, empty branch in Launchpad and "
1197- "link to this series")),
1198 SimpleTerm(IMPORT_EXTERNAL, IMPORT_EXTERNAL,
1199 _("Import a branch hosted somewhere else")),
1200 ))
1201@@ -934,10 +922,9 @@
1202 vocab = widget.vocabulary
1203
1204 (self.branch_type_link,
1205- self.branch_type_create,
1206 self.branch_type_import) = [
1207 render_radio_widget_part(widget, value, current_value)
1208- for value in (LINK_LP_BZR, CREATE_NEW, IMPORT_EXTERNAL)]
1209+ for value in (LINK_LP_BZR, IMPORT_EXTERNAL)]
1210
1211 def _validateLinkLpBzr(self, data):
1212 """Validate data for link-lp-bzr case."""
1213@@ -946,10 +933,6 @@
1214 'branch_location',
1215 'The branch location must be set.')
1216
1217- def _validateCreateNew(self, data):
1218- """Validate data for create new case."""
1219- self._validateBranch(data)
1220-
1221 def _validateImportExternal(self, data):
1222 """Validate data for import external case."""
1223 rcs_type = data.get('rcs_type')
1224@@ -1026,10 +1009,6 @@
1225 # Mark other widgets as non-required.
1226 self._setRequired(['rcs_type', 'repo_url', 'cvs_module',
1227 'branch_name', 'branch_owner'], False)
1228- elif branch_type == CREATE_NEW:
1229- self._setRequired(
1230- ['branch_location', 'repo_url', 'rcs_type', 'cvs_module'],
1231- False)
1232 elif branch_type == IMPORT_EXTERNAL:
1233 rcs_type = data.get('rcs_type')
1234
1235@@ -1057,8 +1036,6 @@
1236 self._validateImportExternal(data)
1237 elif branch_type == LINK_LP_BZR:
1238 self._validateLinkLpBzr(data)
1239- elif branch_type == CREATE_NEW:
1240- self._validateCreateNew(data)
1241 else:
1242 raise AssertionError("Unknown branch type %s" % branch_type)
1243
1244@@ -1085,16 +1062,8 @@
1245 branch_name = data.get('branch_name')
1246 branch_owner = data.get('branch_owner')
1247
1248- # Create a new branch.
1249- if branch_type == CREATE_NEW:
1250- branch = self._createBzrBranch(branch_name, branch_owner)
1251- if branch is not None:
1252- self.context.branch = branch
1253- self.request.response.addInfoNotification(
1254- 'New branch created and linked to the series.')
1255-
1256 # Import or mirror an external branch.
1257- elif branch_type == IMPORT_EXTERNAL:
1258+ if branch_type == IMPORT_EXTERNAL:
1259 # Either create an externally hosted bzr branch
1260 # (a.k.a. 'mirrored') or create a new code import.
1261 rcs_type = data.get('rcs_type')
1262
1263=== modified file 'lib/lp/registry/browser/tests/pillar-views.txt'
1264--- lib/lp/registry/browser/tests/pillar-views.txt 2011-12-22 05:09:10 +0000
1265+++ lib/lp/registry/browser/tests/pillar-views.txt 2012-03-08 20:07:31 +0000
1266@@ -84,7 +84,6 @@
1267 report_bug
1268 ask_question
1269 help_translate
1270- submit_code
1271
1272 >>> for link in view.configuration_links:
1273 ... print link['link'].name
1274@@ -268,7 +267,6 @@
1275 http://bugs.launchpad.dev/bread/+filebug
1276 http://answers.launchpad.dev/bread/+addquestion
1277 http://translations.launchpad.dev/bread
1278- http://code.launchpad.dev/bread/+addbranch
1279 http://blueprints.launchpad.dev/bread/+addspec
1280
1281 >>> from lp.registry.browser.pillar import InvolvedMenu
1282
1283=== modified file 'lib/lp/registry/browser/tests/productseries-setbranch-view.txt'
1284--- lib/lp/registry/browser/tests/productseries-setbranch-view.txt 2011-12-22 05:09:10 +0000
1285+++ lib/lp/registry/browser/tests/productseries-setbranch-view.txt 2012-03-08 20:07:31 +0000
1286@@ -13,14 +13,20 @@
1287 >>> login_person(product.owner)
1288 >>> view = create_initialized_view(series, name='+setbranch',
1289 ... principal=product.owner)
1290- >>> print find_tag_by_id(view.render(), 'maincontent')
1291+ >>> content = find_tag_by_id(view.render(), 'maincontent')
1292+ >>> print content
1293 <div...
1294 ...Link to a Bazaar branch already on Launchpad...
1295- ...Create a new, empty branch in Launchpad and link to this series...
1296 ...Import a branch hosted somewhere else...
1297 ...Branch name:...
1298 ...Branch owner:...
1299
1300+The user can see instructions to push a branch.
1301+
1302+ >>> instructions = find_tag_by_id(content, 'push-instructions')
1303+ >>> 'bzr push lp:~' in str(instructions)
1304+ True
1305+
1306
1307 Linking to an existing branch
1308 -----------------------------
1309@@ -83,72 +89,6 @@
1310 ~person.../chevy/impala-branch
1311
1312
1313-Creating a new branch
1314----------------------
1315-
1316-When creating a new branch the branch name and owner must be specified.
1317-
1318- >>> series = factory.makeProductSeries(name="camaro", product=product)
1319- >>> transaction.commit()
1320-
1321- >>> form = {
1322- ... 'field.branch_type': 'create-new',
1323- ... 'field.actions.update': 'Update',
1324- ... }
1325- >>> view = create_initialized_view(
1326- ... series, name='+setbranch', principal=product.owner, form=form)
1327- >>> for notification in view.request.response.notifications:
1328- ... print notification.message
1329- >>> for error in view.errors:
1330- ... print error
1331- The branch name must be set.
1332- The branch owner must be set.
1333-
1334- >>> from lp.registry.interfaces.person import IPersonSet
1335- >>> mark = getUtility(IPersonSet).getByEmail('mark@example.com')
1336- >>> form = {
1337- ... 'field.branch_type': 'create-new',
1338- ... 'field.branch_name': 'camaro-branch',
1339- ... 'field.branch_owner': product.owner.name,
1340- ... 'field.actions.update': 'Update',
1341- ... }
1342-
1343- >>> view = create_initialized_view(
1344- ... series, name='+setbranch', principal=product.owner, form=form)
1345- >>> print view.errors_in_action
1346- False
1347- >>> print view.next_url
1348- http://launchpad.dev/chevy/camaro
1349- >>> for error in view.errors:
1350- ... print error
1351- >>> for notification in view.request.response.notifications:
1352- ... print notification.message
1353- New branch created and linked to the series.
1354- >>> print series.branch.name
1355- camaro-branch
1356-
1357-Using a branch name that already exists results in an error.
1358-
1359- >>> form = {
1360- ... 'field.branch_type': 'create-new',
1361- ... 'field.branch_name': 'camaro-branch',
1362- ... 'field.branch_owner': product.owner.name,
1363- ... 'field.actions.update': 'Update',
1364- ... }
1365-
1366- >>> view = create_initialized_view(
1367- ... series, name='+setbranch', principal=product.owner, form=form)
1368- >>> print view.errors_in_action
1369- True
1370- >>> print view.next_url
1371- None
1372- >>> for error in view.errors:
1373- ... print error
1374- You already have a branch for <em>Chevy</em> called <em>camaro-branch</em>.
1375- >>> for notification in view.request.response.notifications:
1376- ... print notification.message
1377-
1378-
1379 Import a branch hosted elsewhere
1380 --------------------------------
1381
1382
1383=== modified file 'lib/lp/registry/browser/tests/productseries-views.txt'
1384--- lib/lp/registry/browser/tests/productseries-views.txt 2012-02-02 12:30:53 +0000
1385+++ lib/lp/registry/browser/tests/productseries-views.txt 2012-03-08 20:07:31 +0000
1386@@ -48,24 +48,6 @@
1387 http://bugs.launchpad.dev/app/simple/+filebug
1388 http://translations.launchpad.dev/app/simple
1389 http://blueprints.launchpad.dev/app/simple/+addspec
1390- >>> for link in view.visible_disabled_links:
1391- ... print link.url
1392- http://code.launchpad.dev/app/+addbranch
1393-
1394-Setting a branch for the series should enable the +addbranch link.
1395-
1396- >>> series.branch = factory.makeBranch()
1397- >>> view = create_view(series, '+get-involved')
1398- >>> print view.codehosting_usage.name
1399- LAUNCHPAD
1400- >>> for link in view.enabled_links:
1401- ... print link.url
1402- http://bugs.launchpad.dev/app/simple/+filebug
1403- http://translations.launchpad.dev/app/simple
1404- http://code.launchpad.dev/app/+addbranch
1405- http://blueprints.launchpad.dev/app/simple/+addspec
1406- >>> for link in view.visible_disabled_links:
1407- ... print link.url
1408
1409
1410 ProductSeries view
1411@@ -151,7 +133,6 @@
1412 None
1413
1414 >>> firefox = getUtility(IProductSet).getByName('firefox')
1415- >>> #login_person(firefox.owner)
1416 >>> series_with_downloads = firefox.getSeries('trunk')
1417 >>> view = create_initialized_view(series_with_downloads, name='+index')
1418 >>> print view.latest_release_with_download_files.version
1419
1420=== modified file 'lib/lp/registry/stories/productseries/xx-productseries-index.txt'
1421--- lib/lp/registry/stories/productseries/xx-productseries-index.txt 2011-06-16 13:50:58 +0000
1422+++ lib/lp/registry/stories/productseries/xx-productseries-index.txt 2012-03-08 20:07:31 +0000
1423@@ -145,13 +145,3 @@
1424 <Link ... url='http://launchpad.dev/firefox/+milestones'>
1425 >>> anon_browser.getLink('View downloads for the Mozilla Firefox project')
1426 <Link ... url='http://launchpad.dev/firefox/+download'>
1427-
1428-The involvement portlet has links to various actions, including
1429-submitting a new branch.
1430-
1431- >>> user_browser.open('http://launchpad.dev/evolution/trunk')
1432- >>> user_browser.getLink('Submit code')
1433- <Link ... url='http://code.launchpad.dev/evolution/+addbranch'>
1434- >>> user_browser.getLink('Submit code').click()
1435- >>> print user_browser.title
1436- Register a branch : Code : Evolution
1437
1438=== modified file 'lib/lp/registry/stories/productseries/xx-productseries-set-branch.txt'
1439--- lib/lp/registry/stories/productseries/xx-productseries-set-branch.txt 2010-04-05 18:02:00 +0000
1440+++ lib/lp/registry/stories/productseries/xx-productseries-set-branch.txt 2012-03-08 20:07:31 +0000
1441@@ -18,7 +18,6 @@
1442
1443 >>> print_radio_button_field(browser.contents, 'branch_type')
1444 (*) Link to a Bazaar branch already on Launchpad
1445- ( ) Create a new, empty branch in Launchpad and link to this series
1446 ( ) Import a branch hosted somewhere else
1447
1448
1449@@ -32,7 +31,8 @@
1450 >>> from lp.registry.interfaces.product import IProductSet
1451 >>> productset = getUtility(IProductSet)
1452 >>> firefox = productset.getByName('firefox')
1453- >>> branch = factory.makeBranch(name="firefox-hosted-branch", product=firefox)
1454+ >>> branch = factory.makeBranch(
1455+ ... name="firefox-hosted-branch", product=firefox)
1456 >>> branch_name = branch.unique_name
1457 >>> logout()
1458
1459@@ -45,35 +45,6 @@
1460 http://launchpad.dev/firefox/trunk
1461
1462
1463-Creating a new branch
1464----------------------
1465-
1466-A brand new, empty branch on Launchpad can be created and set as the
1467-series branch.
1468-
1469- >>> browser.open('http://launchpad.dev/firefox/trunk/+setbranch')
1470- >>> browser.getControl('Create a new, empty branch in Launchpad').click()
1471- >>> browser.getControl('Update').click()
1472- >>> for message in get_feedback_messages(browser.contents):
1473- ... print extract_text(message)
1474- There is 1 error.
1475- Required input is missing.
1476-
1477-However in order to create the branch the name and owner must be
1478-specified. The owner is a pre-populated dropdown list so the default
1479-can be used.
1480-
1481- >>> browser.open('http://launchpad.dev/firefox/trunk/+setbranch')
1482- >>> browser.getControl('Create a new, empty branch in Launchpad').click()
1483- >>> browser.getControl(name='field.branch_name').value = 'new-firefox-branch'
1484- >>> browser.getControl('Update').click()
1485- >>> for message in get_feedback_messages(browser.contents):
1486- ... print extract_text(message)
1487- New branch created and linked to the series.
1488- >>> print browser.url
1489- http://launchpad.dev/firefox/trunk
1490-
1491-
1492 Linking to an external branch
1493 -----------------------------
1494
1495@@ -87,7 +58,8 @@
1496 >>> browser.getControl('Import a branch hosted somewhere else').click()
1497 >>> browser.getControl('Branch name').value = 'bzr-firefox-branch'
1498 >>> browser.getControl('Bazaar', index=0).click()
1499- >>> browser.getControl('Branch URL').value = 'https://bzr.example.com/branch'
1500+ >>> browser.getControl('Branch URL').value = (
1501+ ... 'https://bzr.example.com/branch')
1502 >>> browser.getControl('Update').click()
1503 >>> for message in get_feedback_messages(browser.contents):
1504 ... print extract_text(message)
1505@@ -102,7 +74,8 @@
1506 >>> browser.getControl('Import a branch hosted somewhere else').click()
1507 >>> browser.getControl('Branch name').value = 'git-firefox-branch'
1508 >>> browser.getControl('Git').click()
1509- >>> browser.getControl('Branch URL').value = 'git://git.example.com/branch'
1510+ >>> browser.getControl('Branch URL').value = (
1511+ ... 'git://git.example.com/branch')
1512 >>> browser.getControl('Update').click()
1513 >>> for message in get_feedback_messages(browser.contents):
1514 ... print extract_text(message)
1515@@ -116,7 +89,8 @@
1516 >>> browser.getControl('Import a branch hosted somewhere else').click()
1517 >>> browser.getControl('Branch name').value = 'svn-firefox-branch'
1518 >>> browser.getControl('SVN').click()
1519- >>> browser.getControl('Branch URL').value = 'svn://svn.example.com/branch'
1520+ >>> browser.getControl('Branch URL').value = (
1521+ ... 'svn://svn.example.com/branch')
1522 >>> browser.getControl('Update').click()
1523 >>> for message in get_feedback_messages(browser.contents):
1524 ... print extract_text(message)
1525@@ -130,7 +104,8 @@
1526 >>> browser.getControl('Import a branch hosted somewhere else').click()
1527 >>> browser.getControl('Branch name').value = 'hg-firefox-branch'
1528 >>> browser.getControl('Mercurial').click()
1529- >>> browser.getControl('Branch URL').value = 'http://hg.example.com/branch'
1530+ >>> browser.getControl('Branch URL').value = (
1531+ ... 'http://hg.example.com/branch')
1532 >>> browser.getControl('Branch owner').value = ['hwdb-team']
1533 >>> browser.getControl('Update').click()
1534 >>> for message in get_feedback_messages(browser.contents):
1535
1536=== modified file 'lib/lp/registry/templates/productseries-codesummary.pt'
1537--- lib/lp/registry/templates/productseries-codesummary.pt 2011-08-25 10:35:17 +0000
1538+++ lib/lp/registry/templates/productseries-codesummary.pt 2012-03-08 20:07:31 +0000
1539@@ -27,30 +27,17 @@
1540 </li>
1541
1542 <li>
1543- <p>
1544- If the code is in a Bazaar branch not yet on Launchpad
1545- you can either:
1546- </p>
1547-
1548- <ul class="bulleted" style="margin-bottom: 0;">
1549- <li>
1550- Have the branch mirrored from a remote location by
1551- <a tal:attributes="href context/product/menu:overview/branch_add/fmt:url">
1552- registering a mirrored branch</a>
1553- </li>
1554- <li id="ssh-key-directions">
1555- Push the branch directly to Launchpad, e.g. with:<br />
1556- <tt><strong>
1557- bzr push lp:~<tal:user replace="view/user/name"/>/<tal:products replace="context/product/name"/>/<tal:series replace="context/name"/>
1558- </strong></tt>
1559- <tal:no-keys condition="not:view/user/sshkeys">
1560- <br/>To authenticate with the Launchpad branch upload service,
1561- you need to
1562- <a tal:attributes="href string:${view/user/fmt:url}/+editsshkeys">
1563- register a SSH key</a>.
1564- </tal:no-keys>
1565- </li>
1566- </ul>
1567+ If the code is in a Bazaar branch not yet on Launchpad
1568+ you can push the branch directly to Launchpad, e.g. with:<br />
1569+ <tt><strong>
1570+ bzr push lp:~<tal:user replace="view/user/name"/>/<tal:products replace="context/product/name"/>/<tal:series replace="context/name"/>
1571+ </strong></tt>
1572+ <tal:no-keys condition="not:view/user/sshkeys">
1573+ <br/>To authenticate with the Launchpad branch upload service,
1574+ you need to
1575+ <a tal:attributes="href string:${view/user/fmt:url}/+editsshkeys">
1576+ register a SSH key</a>.
1577+ </tal:no-keys>
1578 </li>
1579
1580 <li>
1581
1582=== modified file 'lib/lp/registry/templates/productseries-linkbranch.pt'
1583--- lib/lp/registry/templates/productseries-linkbranch.pt 2011-05-16 20:55:08 +0000
1584+++ lib/lp/registry/templates/productseries-linkbranch.pt 2012-03-08 20:07:31 +0000
1585@@ -14,19 +14,9 @@
1586 </li>
1587
1588 <li>
1589- <p>
1590+ <p id="ssh-key-directions">
1591 Otherwise, if the code is in a Bazaar branch not yet on Launchpad
1592- you can either:
1593- </p>
1594-
1595- <ul class="bulleted" style="margin-bottom: 0;">
1596- <li>
1597- Have the branch mirrored from a remote location by
1598- <a tal:attributes="href context/product/menu:overview/branch_add/fmt:url">
1599- registering a mirrored branch</a>
1600- </li>
1601- <li id="ssh-key-directions">
1602- Push the branch directly to Launchpad, e.g. with:<br />
1603+ you can push the branch directly to Launchpad, e.g. with:<br />
1604 <tt><strong>
1605 bzr push lp:~<tal:user replace="view/user/name"/>/<tal:project replace="context/product/name"/>/<tal:series replace="context/name"/>
1606 </strong></tt>
1607@@ -36,8 +26,7 @@
1608 <a tal:attributes="href string:${view/user/fmt:url}/+editsshkeys">
1609 register a SSH key</a>.
1610 </tal:no-keys>
1611- </li>
1612- </ul>
1613+ </p>
1614 </li>
1615
1616 <li id="external-code">
1617
1618=== modified file 'lib/lp/registry/templates/productseries-setbranch.pt'
1619--- lib/lp/registry/templates/productseries-setbranch.pt 2012-02-01 15:31:32 +0000
1620+++ lib/lp/registry/templates/productseries-setbranch.pt 2012-03-08 20:07:31 +0000
1621@@ -18,6 +18,19 @@
1622
1623 <div metal:fill-slot="main">
1624
1625+ <p id="push-instructions">
1626+ You can push the branch directly to Launchpad with the command:<br />
1627+ <tt><strong>
1628+ bzr push lp:~<tal:user replace="view/user/name"/>/<tal:project replace="context/product/name"/>/<tal:series replace="context/name"/>
1629+ </strong></tt>
1630+ <tal:no-keys condition="not:view/user/sshkeys">
1631+ <br/>To authenticate with the Launchpad branch upload service,
1632+ you need to
1633+ <a tal:attributes="href string:${view/user/fmt:url}/+editsshkeys">
1634+ register a SSH key</a>.
1635+ </tal:no-keys>
1636+ </p>
1637+
1638 <div metal:use-macro="context/@@launchpad_form/form">
1639
1640 <metal:formbody fill-slot="widgets">
1641@@ -39,15 +52,6 @@
1642
1643 <tr>
1644 <td>
1645- <label tal:replace="structure view/branch_type_create">
1646- Create a new, empty branch in Launchpad and link
1647- to this series
1648- </label>
1649- </td>
1650- </tr>
1651-
1652- <tr>
1653- <td>
1654 <label tal:replace="structure view/branch_type_import">
1655 Import a branch hosted somewhere else
1656 </label>