Merge lp:~jelmer/launchpad/bzr-code-imports-ui into lp:launchpad/db-devel
- bzr-code-imports-ui
- Merge into db-devel
Status: | Superseded | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Proposed branch: | lp:~jelmer/launchpad/bzr-code-imports-ui | ||||||||||||||||
Merge into: | lp:launchpad/db-devel | ||||||||||||||||
Prerequisite: | lp:~jelmer/launchpad/bzr-code-imports | ||||||||||||||||
Diff against target: |
720 lines (+88/-339) 11 files modified
lib/lp/code/browser/branch.py (+4/-47) lib/lp/code/browser/codeimport.py (+23/-5) lib/lp/code/browser/tests/test_branch.py (+3/-13) lib/lp/code/enums.py (+2/-2) lib/lp/code/stories/branches/xx-creating-branches.txt (+0/-179) lib/lp/code/stories/codeimport/xx-create-codeimport.txt (+1/-0) lib/lp/code/templates/branch-form-macros.pt (+0/-42) lib/lp/code/templates/branch-import-details.pt (+6/-0) lib/lp/code/templates/codeimport-new.pt (+14/-0) lib/lp/registry/browser/productseries.py (+34/-50) lib/lp/registry/templates/productseries-codesummary.pt (+1/-1) |
||||||||||||||||
To merge this branch: | bzr merge lp:~jelmer/launchpad/bzr-code-imports-ui | ||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Brad Crittenden (community) | Approve | ||
Michael Hudson-Doyle | code | Pending | |
Review via email: mp+65684@code.launchpad.net |
This proposal has been superseded by a proposal from 2011-08-27.
Commit message
Remove the ability to register mirrored branches; instead, make it possible to register bzr code imports in the UI.
Description of the change
Make it possible to create new Bazaar code imports in the code import UI, disable the ability to create mirror branches.
This removes the user-visible distinction in the web UI between code imports (syncing from remote non-bzr branches) and mirrors (syncing from remote bzr branches), which should make the UI a bit easier to comprehend.
This doesn't migrate any of the existing mirror branches to be code imports, but that would be the next logical step.
It also doesn't remove the ability to create old-style mirrors via the API.
Michael Hudson-Doyle (mwhudson) wrote : | # |
Brad Crittenden (bac) wrote : | # |
Hi Jelmer,
Thanks for trying to clean up this UI. It has always been a bit of a mess. I think your simplifications are good.
Twice in browser/
@@ -576,7 +592,8 @@
151 elif self.code_
152 RevisionControl
153 RevisionControl
154 - RevisionControl
155 + RevisionControl
156 + RevisionControl
As with all UI changes, screenshot of before and after as well as clear instructions on how to exercise the changes makes for speedier review.
Michael Hudson-Doyle (mwhudson) wrote : | # |
Another direction the UI could go of course would be to not overly
distinguish between the various import types and just let the foreign
branch plugins figure it all out. This feels like it would make for a
simpler user experience, but it would also certainly be a big change. I
wonder if it might seem a bit too magical?
Cheers,
mwh
Jelmer Vernooij (jelmer) wrote : | # |
On 26/06/11 23:26, Michael Hudson-Doyle wrote:
> Another direction the UI could go of course would be to not overly
> distinguish between the various import types and just let the foreign
> branch plugins figure it all out. This feels like it would make for a
> simpler user experience, but it would also certainly be a big change. I
> wonder if it might seem a bit too magical?
That's an interesting idea. "bzr branch" has that magic to figure out
what format the source branch is in too, and it seems to work fine
there. One way to do this would be to add a "AUTO" value to
RevisionControl
of the CodeImportWorkers. That would (I think) be a minimal amount of
work, though it would of course only work for those importers that
actually have probers (BZR, BZR_SVN, GIT, HG).
CVS would still need to be special, but I guess there's no way around
that anyway, as it requires a root and a module to be specified.
Cheers,
Jelmer
Robert Collins (lifeless) wrote : | # |
On Mon, Jun 27, 2011 at 11:04 AM, Jelmer Vernooij <email address hidden> wrote:
> CVS would still need to be special, but I guess there's no way around
> that anyway, as it requires a root and a module to be specified.
see config-manager for a url format for cvs that includes the root and module.
Michael Hudson-Doyle (mwhudson) wrote : | # |
On Mon, 27 Jun 2011 00:01:14 +0200, Jelmer Vernooij <email address hidden> wrote:
> On 26/06/11 23:26, Michael Hudson-Doyle wrote:
> > Another direction the UI could go of course would be to not overly
> > distinguish between the various import types and just let the foreign
> > branch plugins figure it all out. This feels like it would make for a
> > simpler user experience, but it would also certainly be a big change. I
> > wonder if it might seem a bit too magical?
> That's an interesting idea. "bzr branch" has that magic to figure out
> what format the source branch is in too, and it seems to work fine
> there. One way to do this would be to add a "AUTO" value to
> RevisionControl
> of the CodeImportWorkers. That would (I think) be a minimal amount of
> work, though it would of course only work for those importers that
> actually have probers (BZR, BZR_SVN, GIT, HG).
Yeah, that would be pretty neat, although presenting bzr/svn/git/hg/auto
to the user wouldn't really be progress :)
> CVS would still need to be special, but I guess there's no way around
> that anyway, as it requires a root and a module to be specified.
Apparently config-manager defines a URL format for CVS we could borrow.
But that would be more useful for cleaning up the internals, I don't
think we could get away with expecting the user to know about it.
Cheers,
mwh
Jelmer Vernooij (jelmer) wrote : | # |
Hi Brad,
On 24/06/11 20:15, Brad Crittenden wrote:
> Thanks for trying to clean up this UI. It has always been a bit of a mess. I think your simplifications are good.
>
> Twice in browser/
>
> @@ -576,7 +592,8 @@
> 151 elif self.code_
> 152 RevisionControl
> 153 RevisionControl
> 154 - RevisionControl
> 155 + RevisionControl
> 156 + RevisionControl
Updated to use a single list.
>
>
> As with all UI changes, screenshot of before and after as well as clear instructions on how to exercise the changes makes for speedier review.
Thanks for the review! I'll make sure to include screenshots next time.
Cheers,
Jelmer
Jelmer Vernooij (jelmer) wrote : | # |
On Sun, 2011-06-26 at 23:19 +0000, Robert Collins wrote:
> On Mon, Jun 27, 2011 at 11:04 AM, Jelmer Vernooij <email address hidden> wrote:
> > CVS would still need to be special, but I guess there's no way around
> > that anyway, as it requires a root and a module to be specified.
> see config-manager for a url format for cvs that includes the root and module.
Even if we do that, do we want users to have to know about that
particular format?
Cheers,
Jelmer
Michael Hudson-Doyle (mwhudson) wrote : | # |
On Mon, 25 Jul 2011 13:21:44 -0000, Jelmer Vernooij <email address hidden> wrote:
> On Sun, 2011-06-26 at 23:19 +0000, Robert Collins wrote:
> > On Mon, Jun 27, 2011 at 11:04 AM, Jelmer Vernooij <email address hidden> wrote:
> > > CVS would still need to be special, but I guess there's no way around
> > > that anyway, as it requires a root and a module to be specified.
> > see config-manager for a url format for cvs that includes the root and module.
> Even if we do that, do we want users to have to know about that
> particular format?
No.
Cheers,
mwh
Preview Diff
1 | === modified file 'lib/lp/code/browser/branch.py' |
2 | --- lib/lp/code/browser/branch.py 2011-08-24 11:52:43 +0000 |
3 | +++ lib/lp/code/browser/branch.py 2011-08-25 10:47:30 +0000 |
4 | @@ -1120,15 +1120,12 @@ |
5 | |
6 | class schema(Interface): |
7 | use_template( |
8 | - IBranch, include=['owner', 'name', 'url', 'lifecycle_status']) |
9 | - branch_type = copy_field( |
10 | - IBranch['branch_type'], vocabulary=UICreatableBranchType) |
11 | + IBranch, include=['owner', 'name', 'lifecycle_status']) |
12 | |
13 | for_input = True |
14 | - field_names = ['owner', 'name', 'branch_type', 'url', 'lifecycle_status'] |
15 | + field_names = ['owner', 'name', 'lifecycle_status'] |
16 | |
17 | branch = None |
18 | - custom_widget('branch_type', LaunchpadRadioWidgetWithDescription) |
19 | custom_widget('lifecycle_status', LaunchpadRadioWidgetWithDescription) |
20 | |
21 | initial_focus_widget = 'name' |
22 | @@ -1157,27 +1154,17 @@ |
23 | """ |
24 | return IPerson(self.context, self.user) |
25 | |
26 | - def showOptionalMarker(self, field_name): |
27 | - """Don't show the optional marker for url.""" |
28 | - if field_name == 'url': |
29 | - return False |
30 | - else: |
31 | - return LaunchpadFormView.showOptionalMarker(self, field_name) |
32 | - |
33 | @action('Register Branch', name='add') |
34 | def add_action(self, action, data): |
35 | """Handle a request to create a new branch for this product.""" |
36 | try: |
37 | - ui_branch_type = data['branch_type'] |
38 | namespace = self.target.getNamespace(data['owner']) |
39 | self.branch = namespace.createBranch( |
40 | - branch_type=BranchType.items[ui_branch_type.name], |
41 | + branch_type=BranchType.HOSTED, |
42 | name=data['name'], |
43 | registrant=self.user, |
44 | - url=data.get('url'), |
45 | + url=None, |
46 | lifecycle_status=data['lifecycle_status']) |
47 | - if self.branch.branch_type == BranchType.MIRRORED: |
48 | - self.branch.requestMirror() |
49 | except BranchCreationForbidden: |
50 | self.addError( |
51 | "You are not allowed to create branches in %s." % |
52 | @@ -1195,36 +1182,6 @@ |
53 | 'owner', |
54 | 'You are not a member of %s' % owner.displayname) |
55 | |
56 | - branch_type = data.get('branch_type') |
57 | - # If branch_type failed to validate, then the rest of the method |
58 | - # doesn't make any sense. |
59 | - if branch_type is None: |
60 | - return |
61 | - |
62 | - # If the branch is a MIRRORED branch, then the url |
63 | - # must be supplied, and if HOSTED the url must *not* |
64 | - # be supplied. |
65 | - url = data.get('url') |
66 | - if branch_type == UICreatableBranchType.MIRRORED: |
67 | - if url is None: |
68 | - # If the url is not set due to url validation errors, |
69 | - # there will be an error set for it. |
70 | - error = self.getFieldError('url') |
71 | - if not error: |
72 | - self.setFieldError( |
73 | - 'url', |
74 | - 'Branch URLs are required for Mirrored branches.') |
75 | - elif branch_type == UICreatableBranchType.HOSTED: |
76 | - if url is not None: |
77 | - self.setFieldError( |
78 | - 'url', |
79 | - 'Branch URLs cannot be set for Hosted branches.') |
80 | - elif branch_type == UICreatableBranchType.REMOTE: |
81 | - # A remote location can, but doesn't have to be set. |
82 | - pass |
83 | - else: |
84 | - raise AssertionError('Unknown branch type') |
85 | - |
86 | @property |
87 | def cancel_url(self): |
88 | return canonical_url(self.context) |
89 | |
90 | === modified file 'lib/lp/code/browser/codeimport.py' |
91 | --- lib/lp/code/browser/codeimport.py 2011-05-27 21:12:25 +0000 |
92 | +++ lib/lp/code/browser/codeimport.py 2011-08-25 10:47:30 +0000 |
93 | @@ -271,6 +271,16 @@ |
94 | allow_fragment=False, # Fragment makes no sense in Mercurial |
95 | trailing_slash=False) # See http://launchpad.net/bugs/56357. |
96 | |
97 | + bzr_branch_url = URIField( |
98 | + title=_("Bazaar branch URL"), required=False, |
99 | + description=_("The URL of the Bazaar branch."), |
100 | + allowed_schemes=["http", "https", "bzr"], |
101 | + allow_userinfo=False, # Only anonymous access is supported. |
102 | + allow_port=True, |
103 | + allow_query=False, # Query makes no sense in Mercurial |
104 | + allow_fragment=False, # Fragment makes no sense in Mercurial |
105 | + trailing_slash=False) |
106 | + |
107 | branch_name = copy_field( |
108 | IBranch['name'], |
109 | __name__='branch_name', |
110 | @@ -346,9 +356,9 @@ |
111 | # display them separately in the form. |
112 | soup = BeautifulSoup(self.widgets['rcs_type']()) |
113 | fields = soup.findAll('input') |
114 | - [cvs_button, svn_button, git_button, hg_button, empty_marker] = [ |
115 | - field for field in fields |
116 | - if field.get('value') in ['CVS', 'BZR_SVN', 'GIT', 'HG', '1']] |
117 | + [cvs_button, svn_button, git_button, hg_button, bzr_button, |
118 | + empty_marker] = [field for field in fields |
119 | + if field.get('value') in ['CVS', 'BZR_SVN', 'GIT', 'HG', 'BZR', '1']] |
120 | cvs_button['onclick'] = 'updateWidgets()' |
121 | svn_button['onclick'] = 'updateWidgets()' |
122 | git_button['onclick'] = 'updateWidgets()' |
123 | @@ -358,6 +368,7 @@ |
124 | self.rcs_type_svn = str(svn_button) |
125 | self.rcs_type_git = str(git_button) |
126 | self.rcs_type_hg = str(hg_button) |
127 | + self.rcs_type_bzr = str(bzr_button) |
128 | self.rcs_type_emptymarker = str(empty_marker) |
129 | |
130 | def _getImportLocation(self, data): |
131 | @@ -371,6 +382,8 @@ |
132 | return None, None, data.get('git_repo_url') |
133 | elif rcs_type == RevisionControlSystems.HG: |
134 | return None, None, data.get('hg_repo_url') |
135 | + elif rcs_type == RevisionControlSystems.BZR: |
136 | + return None, None, data.get('bzr_branch_url') |
137 | else: |
138 | raise AssertionError( |
139 | 'Unexpected revision control type %r.' % rcs_type) |
140 | @@ -485,6 +498,9 @@ |
141 | elif rcs_type == RevisionControlSystems.HG: |
142 | self._validateURL( |
143 | data.get('hg_repo_url'), field_name='hg_repo_url') |
144 | + elif rcs_type == RevisionControlSystems.BZR: |
145 | + self._validateURL( |
146 | + data.get('bzr_branch_url'), field_name='bzr_branch_url') |
147 | else: |
148 | raise AssertionError( |
149 | 'Unexpected revision control type %r.' % rcs_type) |
150 | @@ -576,7 +592,8 @@ |
151 | elif self.code_import.rcs_type in (RevisionControlSystems.SVN, |
152 | RevisionControlSystems.BZR_SVN, |
153 | RevisionControlSystems.GIT, |
154 | - RevisionControlSystems.HG): |
155 | + RevisionControlSystems.HG, |
156 | + RevisionControlSystems.BZR): |
157 | self.form_fields = self.form_fields.omit( |
158 | 'cvs_root', 'cvs_module') |
159 | else: |
160 | @@ -611,7 +628,8 @@ |
161 | elif self.code_import.rcs_type in (RevisionControlSystems.SVN, |
162 | RevisionControlSystems.BZR_SVN, |
163 | RevisionControlSystems.GIT, |
164 | - RevisionControlSystems.HG): |
165 | + RevisionControlSystems.HG, |
166 | + RevisionControlSystems.BZR): |
167 | self._validateURL(data.get('url'), self.code_import) |
168 | else: |
169 | raise AssertionError('Unknown rcs_type for code import.') |
170 | |
171 | === modified file 'lib/lp/code/browser/tests/test_branch.py' |
172 | --- lib/lp/code/browser/tests/test_branch.py 2011-08-22 18:10:47 +0000 |
173 | +++ lib/lp/code/browser/tests/test_branch.py 2011-08-25 10:47:30 +0000 |
174 | @@ -191,8 +191,8 @@ |
175 | "This is a short error message.", |
176 | branch_view.mirror_status_message) |
177 | |
178 | - def testBranchAddRequestsMirror(self): |
179 | - """Registering a mirrored branch requests a mirror.""" |
180 | + def testBranchAddRequests(self): |
181 | + """Registering a branch that requests a mirror.""" |
182 | arbitrary_person = self.factory.makePerson() |
183 | arbitrary_product = self.factory.makeProduct() |
184 | login_person(arbitrary_person) |
185 | @@ -200,9 +200,8 @@ |
186 | add_view = BranchAddView(arbitrary_person, self.request) |
187 | add_view.initialize() |
188 | data = { |
189 | - 'branch_type': BranchType.MIRRORED, |
190 | + 'branch_type': BranchType.HOSTED, |
191 | 'name': 'some-branch', |
192 | - 'url': 'http://example.com', |
193 | 'title': 'Branch Title', |
194 | 'summary': '', |
195 | 'lifecycle_status': BranchLifecycleStatus.DEVELOPMENT, |
196 | @@ -212,15 +211,6 @@ |
197 | 'product': arbitrary_product, |
198 | } |
199 | add_view.add_action.success(data) |
200 | - # Make sure that next_mirror_time is a datetime, not an sqlbuilder |
201 | - # expression. |
202 | - removeSecurityProxy(add_view.branch).sync() |
203 | - now = datetime.now(pytz.timezone('UTC')) |
204 | - self.assertNotEqual(None, add_view.branch.next_mirror_time) |
205 | - self.assertTrue( |
206 | - add_view.branch.next_mirror_time < now, |
207 | - "next_mirror_time not set to UTC_NOW: %s < %s" |
208 | - % (add_view.branch.next_mirror_time, now)) |
209 | finally: |
210 | logout() |
211 | |
212 | |
213 | === modified file 'lib/lp/code/enums.py' |
214 | --- lib/lp/code/enums.py 2011-08-25 10:47:05 +0000 |
215 | +++ lib/lp/code/enums.py 2011-08-25 10:47:30 +0000 |
216 | @@ -99,8 +99,8 @@ |
217 | IMPORTED = DBItem(3, """ |
218 | Imported |
219 | |
220 | - Branches that have been converted from some other revision |
221 | - control system into bzr and are made available through Launchpad. |
222 | + Branches that have been imported from an externally hosted |
223 | + branch in bzr or another VCS and are made available through Launchpad. |
224 | """) |
225 | |
226 | REMOTE = DBItem(4, """ |
227 | |
228 | === modified file 'lib/lp/code/stories/branches/xx-creating-branches.txt' |
229 | --- lib/lp/code/stories/branches/xx-creating-branches.txt 2010-10-18 22:24:59 +0000 |
230 | +++ lib/lp/code/stories/branches/xx-creating-branches.txt 2011-08-25 10:47:30 +0000 |
231 | @@ -32,94 +32,8 @@ |
232 | >>> browser.open('http://code.launchpad.dev/redfish') |
233 | >>> browser.getLink("Register a branch").click() |
234 | |
235 | - >>> browser.getControl('Hosted').click() |
236 | >>> browser.getControl('Name').value = 'hosted-branch' |
237 | |
238 | -Branch URLs are not valid for hosted branches. |
239 | - |
240 | - >>> browser.getControl('Branch URL').value = ( |
241 | - ... 'http://example.com/hosted-branch') |
242 | - >>> browser.getControl('Register Branch').click() |
243 | - >>> for message in get_feedback_messages(browser.contents): |
244 | - ... print message |
245 | - There is 1 error. |
246 | - Branch URLs cannot be set for Hosted branches. |
247 | - |
248 | - >>> browser.getControl('Branch URL').value = '' |
249 | - >>> browser.getControl('Register Branch').click() |
250 | - |
251 | - >>> def print_branch_info(browser): |
252 | - ... branch_info = find_tag_by_id(browser.contents, 'branch-info') |
253 | - ... print extract_text(branch_info) |
254 | - >>> print_branch_info(browser) |
255 | - Branch information |
256 | - Owner: Sample Person |
257 | - Project: Redfish |
258 | - Status: Development |
259 | - |
260 | - |
261 | -Creating a mirrored branch |
262 | --------------------------- |
263 | - |
264 | -Mirrored branches are primarily hosted outside of Launchpad, and |
265 | -Launchpad mirrors the branch. |
266 | - |
267 | - >>> browser.open('http://code.launchpad.dev/redfish') |
268 | - >>> browser.getLink("Register a branch").click() |
269 | - |
270 | - >>> print_radio_button_field(browser.contents, 'branch_type') |
271 | - ( ) Hosted |
272 | - (*) Mirrored |
273 | - ( ) Remote |
274 | - |
275 | - >>> browser.getControl('Name').value = 'mirrored-branch' |
276 | - |
277 | -Branch URLs are required for mirrored branches. |
278 | - |
279 | - >>> browser.getControl('Register Branch').click() |
280 | - >>> for message in get_feedback_messages(browser.contents): |
281 | - ... print message |
282 | - There is 1 error. |
283 | - Branch URLs are required for Mirrored branches. |
284 | - |
285 | - >>> browser.getControl('Branch URL').value = ( |
286 | - ... 'http://example.com/mirrored-branch') |
287 | - >>> browser.getControl('Register Branch').click() |
288 | - |
289 | - >>> print_branch_info(browser) |
290 | - Branch information |
291 | - Owner: Sample Person |
292 | - Project: Redfish |
293 | - Status: Development |
294 | - Location: http://example.com/mirrored-branch |
295 | - Last mirrored: Not mirrored yet |
296 | - Next mirror: As soon as possible |
297 | - |
298 | - |
299 | -Creating a remote branch |
300 | ------------------------- |
301 | - |
302 | -The contents of Remote branches are not accessible through Launchpad. |
303 | - |
304 | - >>> browser.open('http://code.launchpad.dev/redfish') |
305 | - >>> browser.getLink("Register a branch").click() |
306 | - |
307 | - >>> browser.getControl('Remote').click() |
308 | - >>> browser.getControl('Name').value = 'remote-branch' |
309 | - |
310 | -A remote branch may have a URL, but doesn't have to. |
311 | - |
312 | - >>> browser.getControl('Branch URL').value = ( |
313 | - ... 'http://example.com/remote-branch') |
314 | - >>> browser.getControl('Register Branch').click() |
315 | - >>> print_branch_info(browser) |
316 | - Branch information |
317 | - Owner: Sample Person |
318 | - Project: Redfish |
319 | - Status: Development |
320 | - Location: http://example.com/remote-branch |
321 | - |
322 | - |
323 | Finding product/+addbranch |
324 | -------------------------- |
325 | |
326 | @@ -209,34 +123,6 @@ |
327 | Other branches owned by No Privileges Person |
328 | |
329 | |
330 | -Adding a branch via a product series |
331 | ------------------------------------- |
332 | - |
333 | -A user can register a branch from the project series page using the |
334 | -'Submit code' link, or in the case of a series driver, by using the |
335 | -'registering a mirrored branch' link. |
336 | - |
337 | - >>> browser.open('http://launchpad.dev/gnome-terminal/trunk') |
338 | - >>> browser.getLink('registering a mirrored branch').click() |
339 | - >>> print browser.title |
340 | - Register a branch : Code : GNOME Terminal |
341 | - |
342 | -The user sees that he is registering a branch for the series' project. |
343 | - |
344 | - >>> print extract_text(find_main_content(browser.contents).h1) |
345 | - Register a branch on GNOME Terminal |
346 | - |
347 | -After posting the form, he sees the registered branch page. |
348 | - |
349 | - >>> browser.getControl('Branch URL').value = ( |
350 | - ... 'http://example.com/applets/master') |
351 | - >>> browser.getControl('Name').value = 'master' |
352 | - >>> browser.getControl('Experimental').click() |
353 | - >>> browser.getControl('Register Branch').click() |
354 | - >>> print browser.title |
355 | - master : Code : GNOME Terminal |
356 | - |
357 | - |
358 | Finding person/+addbranch |
359 | ------------------------- |
360 | |
361 | @@ -271,7 +157,6 @@ |
362 | Ubuntu Gnome Team (name18) |
363 | Warty Security Team (name20) |
364 | |
365 | - |
366 | Conflict on unique name |
367 | ----------------------- |
368 | |
369 | @@ -288,8 +173,6 @@ |
370 | Try a adding a conflicting branch from the product/+addbranch form. |
371 | |
372 | >>> browser.open('http://code.launchpad.dev/gnome-terminal/+addbranch') |
373 | - >>> browser.getControl('Branch URL').value = ( |
374 | - ... 'http://example.com/gnome-terminal/main-dup') |
375 | |
376 | Trying to post the form without filling a name at all should not cause |
377 | an oops! |
378 | @@ -321,7 +204,6 @@ |
379 | >>> browser.getControl('Owner').displayValue = [ |
380 | ... 'Landscape Developers'] |
381 | >>> browser.getControl('Name').value = 'main' |
382 | - >>> browser.getControl('Hosted').click() |
383 | >>> browser.getControl('Register Branch').click() |
384 | >>> print browser.url |
385 | http://code.launchpad.dev/~landscape-developers/gnome-terminal/main |
386 | @@ -335,7 +217,6 @@ |
387 | >>> browser.getControl('Owner').displayValue = [ |
388 | ... 'Landscape Developers'] |
389 | >>> browser.getControl('Name').value = 'main' |
390 | - >>> browser.getControl('Hosted').click() |
391 | >>> browser.getControl('Register Branch').click() |
392 | >>> for message in get_feedback_messages(browser.contents): |
393 | ... print extract_text(message) |
394 | @@ -343,65 +224,6 @@ |
395 | Landscape Developers already has a branch for GNOME Terminal called main. |
396 | |
397 | |
398 | -Checking URLs |
399 | -------------- |
400 | - |
401 | -URL validation should check that the entered URL is not the root of a |
402 | -site. |
403 | - |
404 | - >>> user_browser.open('http://code.launchpad.dev/applets') |
405 | - >>> user_browser.getLink("Register a branch").click() |
406 | - >>> user_browser.getControl('Branch URL').value = 'http://example.com' |
407 | - >>> user_browser.getControl('Name').value = 'unique-name' |
408 | - >>> user_browser.getControl('Register Branch').click() |
409 | - >>> messages = find_tags_by_class(user_browser.contents, 'message') |
410 | - >>> for element in messages: |
411 | - ... print element.renderContents() |
412 | - There is 1 error. |
413 | - URLs for branches cannot point to the root of a site. |
414 | - |
415 | -URL validation should check that the entered URL is not from Launchpad. |
416 | - |
417 | - >>> user_browser.open('http://code.launchpad.dev/applets') |
418 | - >>> user_browser.getLink("Register a branch").click() |
419 | - >>> user_browser.getControl('Branch URL').value = ( |
420 | - ... 'http://code.launchpad.dev/~testuser/') |
421 | - >>> user_browser.getControl('Name').value = 'unique-name' |
422 | - >>> user_browser.getControl('Register Branch').click() |
423 | - >>> for message in get_feedback_messages(user_browser.contents): |
424 | - ... print message |
425 | - There is 1 error. |
426 | - For Launchpad to mirror a branch, the original branch cannot be on |
427 | - launchpad.dev. |
428 | - |
429 | -As well as checking against the root site set in the config, a check is |
430 | -also done against the value stored as a database constraint. |
431 | - |
432 | - >>> user_browser.open('http://code.launchpad.dev/applets') |
433 | - >>> user_browser.getLink("Register a branch").click() |
434 | - >>> user_browser.getControl('Branch URL').value = ( |
435 | - ... 'http://bazaar.launchpad.net/foo/bar/') |
436 | - >>> user_browser.getControl('Name').value = 'unique-name' |
437 | - >>> user_browser.getControl('Register Branch').click() |
438 | - >>> for message in get_feedback_messages(user_browser.contents): |
439 | - ... print message |
440 | - There is 1 error. |
441 | - For Launchpad to mirror a branch, the original branch cannot be on |
442 | - http://bazaar.launchpad.net. |
443 | - |
444 | -Trailing slashes on URLs are removed. |
445 | - |
446 | - >>> user_browser.getControl('Branch URL').value = ( |
447 | - ... 'sftp://example.com/~lifeless/pyresources/') |
448 | - >>> user_browser.getControl('Register Branch').click() |
449 | - >>> print_tag_with_id(user_browser.contents, 'branch-info') |
450 | - Branch information |
451 | - Owner: ... |
452 | - ... |
453 | - Location: sftp://example.com/~lifeless/pyresources |
454 | - ... |
455 | - |
456 | - |
457 | Attempting to create a branch in a forbidden project |
458 | ---------------------------------------------------- |
459 | |
460 | @@ -423,7 +245,6 @@ |
461 | |
462 | >>> user_browser.open('http://code.launchpad.dev/landscape') |
463 | >>> user_browser.getLink("Register a branch").click() |
464 | - >>> user_browser.getControl('Branch URL').value = 'http://foo.com/bar' |
465 | >>> user_browser.getControl('Name').value = 'landscape1' |
466 | >>> user_browser.getControl('Register Branch').click() |
467 | >>> messages = find_tags_by_class(user_browser.contents, 'message') |
468 | |
469 | === modified file 'lib/lp/code/stories/codeimport/xx-create-codeimport.txt' |
470 | --- lib/lp/code/stories/codeimport/xx-create-codeimport.txt 2010-09-28 19:25:54 +0000 |
471 | +++ lib/lp/code/stories/codeimport/xx-create-codeimport.txt 2011-08-25 10:47:30 +0000 |
472 | @@ -56,6 +56,7 @@ |
473 | The default foreign VCS type is Subversion. |
474 | |
475 | >>> print_radio_button_field(browser.contents, "rcs_type") |
476 | + ( ) Bazaar |
477 | ( ) Git |
478 | ( ) Mercurial |
479 | (*) Subversion |
480 | |
481 | === modified file 'lib/lp/code/templates/branch-form-macros.pt' |
482 | --- lib/lp/code/templates/branch-form-macros.pt 2009-10-02 15:02:23 +0000 |
483 | +++ lib/lp/code/templates/branch-form-macros.pt 2011-08-25 10:47:30 +0000 |
484 | @@ -17,20 +17,6 @@ |
485 | |
486 | <script type="text/javascript"> |
487 | //<![CDATA[ |
488 | -function update_branch_url() |
489 | -{ |
490 | - var branch_type_field = document.getElementsByName('field.branch_type') |
491 | - var form = branch_type_field[0].form; |
492 | - var branch_type = 'None'; |
493 | - for (var i = 0; i < branch_type_field.length; i++) { |
494 | - if (branch_type_field[i].checked) { |
495 | - branch_type = branch_type_field[i].value; |
496 | - break; |
497 | - } |
498 | - } |
499 | - updateField(form['field.url'], branch_type != 'HOSTED'); |
500 | -} |
501 | - |
502 | function update_branch_unique_name() |
503 | { |
504 | var unique_name = document.getElementById("branch-unique-name") |
505 | @@ -43,44 +29,16 @@ |
506 | unique_name.innerHTML = branch_name |
507 | } |
508 | |
509 | -function populate_branch_name_from_url() |
510 | -{ |
511 | - url_field = document.getElementById('field.url'); |
512 | - var url_text = trim(url_field.value); |
513 | - // strip of any trailing slashes |
514 | - url_text = url_text.replace(/\/+$/, '') |
515 | - if (url_text != url_field.value) { |
516 | - url_field.value = url_text; |
517 | - } |
518 | - var name_field = document.getElementById('field.name'); |
519 | - if (name_field.value == '') |
520 | - { |
521 | - // parse the value of the url field |
522 | - url_bits = url_text.split('/'); |
523 | - if (url_bits.length > 2) { |
524 | - // attempt at not barfing on something completely invalid |
525 | - last_bit = url_bits[url_bits.length - 1]; |
526 | - name_field.value = last_bit; |
527 | - } |
528 | - } |
529 | -} |
530 | - |
531 | function hookUpBranchFieldFunctions() |
532 | { |
533 | connect('field.owner', 'onkeyup', update_branch_unique_name); |
534 | connect('field.owner', 'onchange', update_branch_unique_name); |
535 | connect('field.name', 'onkeyup', update_branch_unique_name); |
536 | - connect('field.branch_type.0', 'onclick', update_branch_url); |
537 | - connect('field.branch_type.1', 'onclick', update_branch_url); |
538 | - connect('field.branch_type.2', 'onclick', update_branch_url); |
539 | update_branch_unique_name(); |
540 | - connect('field.url', 'onchange', populate_branch_name_from_url); |
541 | - connect('field.url', 'onblur', populate_branch_name_from_url); |
542 | document.getElementById("branch-unique-name-div").style.display = "block"; |
543 | } |
544 | |
545 | registerLaunchpadFunction(hookUpBranchFieldFunctions); |
546 | -registerLaunchpadFunction(update_branch_url); |
547 | |
548 | //]]> |
549 | </script> |
550 | |
551 | === modified file 'lib/lp/code/templates/branch-import-details.pt' |
552 | --- lib/lp/code/templates/branch-import-details.pt 2010-06-10 07:54:59 +0000 |
553 | +++ lib/lp/code/templates/branch-import-details.pt 2011-08-25 10:47:30 +0000 |
554 | @@ -51,6 +51,12 @@ |
555 | </p> |
556 | </tal:hg-import> |
557 | |
558 | + <tal:bzr-import condition="code_import/rcs_type/enumvalue:BZR"> |
559 | + <p>This branch is an import of the Bazaar branch at |
560 | + <span tal:replace="code_import/url" />. |
561 | + </p> |
562 | + </tal:bzr-import> |
563 | + |
564 | <tal:svn-import condition="view/is_svn_import"> |
565 | <p id="svn-import-details"> |
566 | This branch is an import of the |
567 | |
568 | === modified file 'lib/lp/code/templates/codeimport-new.pt' |
569 | --- lib/lp/code/templates/codeimport-new.pt 2010-04-22 23:50:51 +0000 |
570 | +++ lib/lp/code/templates/codeimport-new.pt 2011-08-25 10:47:30 +0000 |
571 | @@ -53,6 +53,20 @@ |
572 | <tr> |
573 | <td> |
574 | <label> |
575 | + <input tal:replace="structure view/rcs_type_bzr" /> |
576 | + Bazaar |
577 | + </label> |
578 | + <table class="importdetails"> |
579 | + <tal:widget define="widget nocall:view/widgets/bzr_branch_url"> |
580 | + <metal:block use-macro="context/@@launchpad_form/widget_row" /> |
581 | + </tal:widget> |
582 | + </table> |
583 | + </td> |
584 | + </tr> |
585 | + |
586 | + <tr> |
587 | + <td> |
588 | + <label> |
589 | <input tal:replace="structure view/rcs_type_git" /> |
590 | Git |
591 | </label> |
592 | |
593 | === modified file 'lib/lp/registry/browser/productseries.py' |
594 | --- lib/lp/registry/browser/productseries.py 2011-08-25 10:47:05 +0000 |
595 | +++ lib/lp/registry/browser/productseries.py 2011-08-25 10:47:30 +0000 |
596 | @@ -1090,8 +1090,7 @@ |
597 | |
598 | # Create a new branch. |
599 | if branch_type == CREATE_NEW: |
600 | - branch = self._createBzrBranch( |
601 | - BranchType.HOSTED, branch_name, branch_owner) |
602 | + branch = self._createBzrBranch(branch_name, branch_owner) |
603 | if branch is not None: |
604 | self.context.branch = branch |
605 | self.request.response.addInfoNotification( |
606 | @@ -1102,55 +1101,42 @@ |
607 | # Either create an externally hosted bzr branch |
608 | # (a.k.a. 'mirrored') or create a new code import. |
609 | rcs_type = data.get('rcs_type') |
610 | - if rcs_type == RevisionControlSystems.BZR: |
611 | - branch = self._createBzrBranch( |
612 | - BranchType.MIRRORED, branch_name, branch_owner, |
613 | - data['repo_url']) |
614 | - if branch is None: |
615 | - return |
616 | - |
617 | - self.context.branch = branch |
618 | - self.request.response.addInfoNotification( |
619 | - 'Mirrored branch created and linked to ' |
620 | - 'the series.') |
621 | + # We need to create an import request. |
622 | + if rcs_type == RevisionControlSystems.CVS: |
623 | + cvs_root = data.get('repo_url') |
624 | + cvs_module = data.get('cvs_module') |
625 | + url = None |
626 | else: |
627 | - # We need to create an import request. |
628 | - if rcs_type == RevisionControlSystems.CVS: |
629 | - cvs_root = data.get('repo_url') |
630 | - cvs_module = data.get('cvs_module') |
631 | - url = None |
632 | - else: |
633 | - cvs_root = None |
634 | - cvs_module = None |
635 | - url = data.get('repo_url') |
636 | - rcs_item = RevisionControlSystems.items[rcs_type.name] |
637 | - try: |
638 | - code_import = getUtility(ICodeImportSet).new( |
639 | - registrant=branch_owner, |
640 | - target=IBranchTarget(self.context.product), |
641 | - branch_name=branch_name, |
642 | - rcs_type=rcs_item, |
643 | - url=url, |
644 | - cvs_root=cvs_root, |
645 | - cvs_module=cvs_module) |
646 | - except BranchExists, e: |
647 | - self._setBranchExists(e.existing_branch, |
648 | - 'branch_name') |
649 | - self.errors_in_action = True |
650 | - # Abort transaction. This is normally handled |
651 | - # by LaunchpadFormView, but we are already in |
652 | - # the success handler. |
653 | - self._abort() |
654 | - return |
655 | - self.context.branch = code_import.branch |
656 | - self.request.response.addInfoNotification( |
657 | - 'Code import created and branch linked to the ' |
658 | - 'series.') |
659 | + cvs_root = None |
660 | + cvs_module = None |
661 | + url = data.get('repo_url') |
662 | + rcs_item = RevisionControlSystems.items[rcs_type.name] |
663 | + try: |
664 | + code_import = getUtility(ICodeImportSet).new( |
665 | + registrant=branch_owner, |
666 | + target=IBranchTarget(self.context.product), |
667 | + branch_name=branch_name, |
668 | + rcs_type=rcs_item, |
669 | + url=url, |
670 | + cvs_root=cvs_root, |
671 | + cvs_module=cvs_module) |
672 | + except BranchExists, e: |
673 | + self._setBranchExists(e.existing_branch, |
674 | + 'branch_name') |
675 | + self.errors_in_action = True |
676 | + # Abort transaction. This is normally handled |
677 | + # by LaunchpadFormView, but we are already in |
678 | + # the success handler. |
679 | + self._abort() |
680 | + return |
681 | + self.context.branch = code_import.branch |
682 | + self.request.response.addInfoNotification( |
683 | + 'Code import created and branch linked to the ' |
684 | + 'series.') |
685 | else: |
686 | raise UnexpectedFormData(branch_type) |
687 | |
688 | - def _createBzrBranch(self, branch_type, branch_name, |
689 | - branch_owner, repo_url=None): |
690 | + def _createBzrBranch(self, branch_name, branch_owner, repo_url=None): |
691 | """Create a new Bazaar branch. It may be hosted or mirrored. |
692 | |
693 | Return the branch on success or None. |
694 | @@ -1158,12 +1144,10 @@ |
695 | branch = None |
696 | try: |
697 | namespace = self.target.getNamespace(branch_owner) |
698 | - branch = namespace.createBranch(branch_type=branch_type, |
699 | + branch = namespace.createBranch(branch_type=BranchType.HOSTED, |
700 | name=branch_name, |
701 | registrant=self.user, |
702 | url=repo_url) |
703 | - if branch_type == BranchType.MIRRORED: |
704 | - branch.requestMirror() |
705 | except BranchCreationForbidden: |
706 | self.addError( |
707 | "You are not allowed to create branches in %s." % |
708 | |
709 | === modified file 'lib/lp/registry/templates/productseries-codesummary.pt' |
710 | --- lib/lp/registry/templates/productseries-codesummary.pt 2011-05-16 20:55:08 +0000 |
711 | +++ lib/lp/registry/templates/productseries-codesummary.pt 2011-08-25 10:47:30 +0000 |
712 | @@ -54,7 +54,7 @@ |
713 | </li> |
714 | |
715 | <li> |
716 | - If the code is in Git, Mercurial, CVS or Subversion you can |
717 | + If the code is in Git, Mercurial, CVS, Subversion or an external Bazaar branch you can |
718 | <a tal:attributes="href view/request_import_link">request that the branch be imported to Bazaar</a>. |
719 | </li> |
720 | </ul> |
+ bzr_branch_url = URIField(
...
+ allow_query=False, # Query makes no sense in Mercurial
:-)
Otherwise, well it looks fine. It's great to see so much code being deleted. I don't have the time to do a line by line review, and I don't have the Launchpad dev environment set up on my new laptop so I can't play around with it. I worry that there are probably more places that implicitly assume import branches are foreign in some way, but maybe not (also approximately noone uses mirror branches any more aiui).
It would be SO GREAT if we could get rid of the puller after this. I think this requires having some kind of token mechanism that grants the holder of the token the ability to read and write to a particular branch (and read any stacked on branches I guess) via the usual codehosting access. But that can wait :)