Merge lp:~jelmer/launchpad/bzr-code-imports-ui into lp:launchpad
- bzr-code-imports-ui
- Merge into devel
Status: | Merged | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Approved by: | Jelmer Vernooij | ||||||||||||||||
Approved revision: | no longer in the source branch. | ||||||||||||||||
Merged at revision: | 14112 | ||||||||||||||||
Proposed branch: | lp:~jelmer/launchpad/bzr-code-imports-ui | ||||||||||||||||
Merge into: | lp:launchpad | ||||||||||||||||
Prerequisite: | lp:~jelmer/launchpad/bzr-code-imports | ||||||||||||||||
Diff against target: |
1310 lines (+227/-479) 17 files modified
lib/lp/app/widgets/doc/launchpad-radio-widget.txt (+3/-3) lib/lp/code/browser/branch.py (+8/-50) lib/lp/code/browser/codeimport.py (+30/-10) lib/lp/code/browser/tests/test_branch.py (+3/-13) lib/lp/code/enums.py (+2/-2) lib/lp/code/stories/branches/xx-branch-deletion.txt (+0/-2) lib/lp/code/stories/branches/xx-branch-url-validation.txt (+0/-72) lib/lp/code/stories/branches/xx-creating-branches.txt (+0/-188) lib/lp/code/stories/branches/xx-junk-branches.txt (+2/-4) lib/lp/code/stories/codeimport/xx-create-codeimport.txt (+62/-16) lib/lp/code/templates/branch-form-macros.pt (+0/-42) lib/lp/code/templates/branch-import-details.pt (+28/-4) lib/lp/code/templates/codeimport-list.pt (+1/-0) lib/lp/code/templates/codeimport-new.pt (+16/-0) lib/lp/registry/browser/productseries.py (+35/-51) lib/lp/registry/browser/tests/productseries-setbranch-view.txt (+36/-21) 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 |
---|---|---|---|
Benji York (community) | code | Approve | |
Michael Hudson-Doyle | code | Pending | |
Brad Crittenden | Pending | ||
Ian Booth | code* | Pending | |
Review via email: mp+77961@code.launchpad.net |
This proposal supersedes a proposal from 2011-08-27.
Commit message
[r=benji][bug=352124,352131,
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 XML/RPC API used by the "bzr register-branch" command in bzr.
Michael Hudson-Doyle (mwhudson) wrote : Posted in a previous version of this proposal | # |
Brad Crittenden (bac) wrote : Posted in a previous version of this proposal | # |
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 : Posted in a previous version of this proposal | # |
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 : Posted in a previous version of this proposal | # |
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 : Posted in a previous version of this proposal | # |
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 : Posted in a previous version of this proposal | # |
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 : Posted in a previous version of this proposal | # |
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 : Posted in a previous version of this proposal | # |
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 : Posted in a previous version of this proposal | # |
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
Ian Booth (wallyworld) wrote : Posted in a previous version of this proposal | # |
I like UI simplification so this is a nice change.
A few issues to fix:
1. The conflict in sourcedeps.cache
2. There's an issue on the +new-import page. When first loaded, the bzr branch url field is enabled (and the url fields for the other vcs types are disabled) implying that bzr is the default choice. However, the bzr radio button is not selected by default. Given that this happens, there's a test that should be written. In xx-create-
3. Line 120, 121. The comment says "# Query makes no sense in Mercurial" but it should be bzr
4. Did you run lint? There's some lines > 78 characters plus other things like number of blank lines (some of it will be pre-existing but worth fixing as a drive-by). Normally we would like to see the lint output under the ==Lint == heading in the mp description.
5. In ProductSeriesSe
Dumb question 101 - this mp seems to kill the ability to create remote branches. I assume thats intended and such branches are no longer supported?
Jelmer Vernooij (jelmer) wrote : Posted in a previous version of this proposal | # |
Thanks Ian, much appreciated. I've finally found some time to update this MP and address the issues you raised.
xx-create-
I've fixed sourcedeps.cache and the comments about Mercurial and docstring in ProductSeriesSe
Removing remote branches was indeed intentional. There was an open bug about removing them, which I have linked to the branch.
"make lint" doesn't display any errors for me - how are you using it, does it need additional configuration?
Jelmer Vernooij (jelmer) wrote : Posted in a previous version of this proposal | # |
FWIW Bazaar code imports already work - they can be created through the API. There is a list of existing imports here:
Benji York (benji) wrote : Posted in a previous version of this proposal | # |
This branch looks good to me.
Regarding the lint that Ian mentioned, here's a lint report that shows the problems:
./lib/lp/
1: narrative uses a moin header.
38: narrative uses a moin header.
./lib/lp/
361: Line exceeds 78 characters.
270: E261 at least two spaces before inline comment
280: E261 at least two spaces before inline comment
361: E501 line too long (81 characters)
./lib/lp/
33: narrative exceeds 78 characters.
./lib/lp/
43: source exceeds 78 characters.
./lib/lp/
98: source exceeds 78 characters.
115: source exceeds 78 characters.
137: source exceeds 78 characters.
144: want exceeds 78 characters.
164: source exceeds 78 characters.
184: source exceeds 78 characters.
189: want exceeds 78 characters.
203: source exceeds 78 characters.
223: source exceeds 78 characters.
243: source exceeds 78 characters.
263: source exceeds 78 characters.
283: source exceeds 78 characters.
304: source exceeds 78 characters.
370: want exceeds 78 characters.
388: want exceeds 78 characters.
408: source exceeds 78 characters.
Benji York (benji) wrote : | # |
This branch looks good to me.
Regarding the lint that Ian mentioned, here's a lint report that shows
the problems:
./lib/lp/
1: narrative uses a moin header.
38: narrative uses a moin header.
./lib/lp/
361: Line exceeds 78 characters.
270: E261 at least two spaces before inline comment
280: E261 at least two spaces before inline comment
361: E501 line too long (81 characters)
./lib/lp/
33: narrative exceeds 78 characters.
./lib/lp/
43: source exceeds 78 characters.
./lib/lp/
98: source exceeds 78 characters.
115: source exceeds 78 characters.
137: source exceeds 78 characters.
144: want exceeds 78 characters.
164: source exceeds 78 characters.
184: source exceeds 78 characters.
189: want exceeds 78 characters.
203: source exceeds 78 characters.
223: source exceeds 78 characters.
243: source exceeds 78 characters.
263: source exceeds 78 characters.
283: source exceeds 78 characters.
304: source exceeds 78 characters.
370: want exceeds 78 characters.
388: want exceeds 78 characters.
408: source exceeds 78 characters.
Preview Diff
1 | === modified file 'lib/lp/app/widgets/doc/launchpad-radio-widget.txt' |
2 | --- lib/lp/app/widgets/doc/launchpad-radio-widget.txt 2011-04-28 02:59:45 +0000 |
3 | +++ lib/lp/app/widgets/doc/launchpad-radio-widget.txt 2011-10-04 14:34:53 +0000 |
4 | @@ -75,9 +75,9 @@ |
5 | <td><label for="field.branch_type.2">Imported</label></td> |
6 | </tr> |
7 | <tr> |
8 | - <td class="formHelp">Branches that have been converted from some |
9 | - other revision control system into bzr and are made available through |
10 | - Launchpad. </td> |
11 | + <td class="formHelp">Branches that have been imported from an |
12 | + externally hosted branch in bzr or another VCS and are made available |
13 | + through Launchpad. </td> |
14 | </tr> |
15 | <tr> |
16 | <td rowspan="2"><input class="radioType" id="field.branch_type.3" |
17 | |
18 | === modified file 'lib/lp/code/browser/branch.py' |
19 | --- lib/lp/code/browser/branch.py 2011-09-13 05:23:16 +0000 |
20 | +++ lib/lp/code/browser/branch.py 2011-10-04 14:34:53 +0000 |
21 | @@ -641,9 +641,10 @@ |
22 | (RevisionControlSystems.SVN, RevisionControlSystems.BZR_SVN) |
23 | |
24 | @property |
25 | - def svn_url_is_web(self): |
26 | - """True if an imported branch's SVN URL is HTTP or HTTPS.""" |
27 | - # You should only be calling this if it's an SVN code import |
28 | + def url_is_web(self): |
29 | + """True if an imported branch's URL is HTTP or HTTPS.""" |
30 | + # You should only be calling this if it's an SVN, BZR, GIT or HG code |
31 | + # import |
32 | assert self.context.code_import |
33 | url = self.context.code_import.url |
34 | assert url |
35 | @@ -1146,15 +1147,12 @@ |
36 | |
37 | class schema(Interface): |
38 | use_template( |
39 | - IBranch, include=['owner', 'name', 'url', 'lifecycle_status']) |
40 | - branch_type = copy_field( |
41 | - IBranch['branch_type'], vocabulary=UICreatableBranchType) |
42 | + IBranch, include=['owner', 'name', 'lifecycle_status']) |
43 | |
44 | for_input = True |
45 | - field_names = ['owner', 'name', 'branch_type', 'url', 'lifecycle_status'] |
46 | + field_names = ['owner', 'name', 'lifecycle_status'] |
47 | |
48 | branch = None |
49 | - custom_widget('branch_type', LaunchpadRadioWidgetWithDescription) |
50 | custom_widget('lifecycle_status', LaunchpadRadioWidgetWithDescription) |
51 | |
52 | initial_focus_widget = 'name' |
53 | @@ -1183,27 +1181,17 @@ |
54 | """ |
55 | return IPerson(self.context, self.user) |
56 | |
57 | - def showOptionalMarker(self, field_name): |
58 | - """Don't show the optional marker for url.""" |
59 | - if field_name == 'url': |
60 | - return False |
61 | - else: |
62 | - return LaunchpadFormView.showOptionalMarker(self, field_name) |
63 | - |
64 | @action('Register Branch', name='add') |
65 | def add_action(self, action, data): |
66 | """Handle a request to create a new branch for this product.""" |
67 | try: |
68 | - ui_branch_type = data['branch_type'] |
69 | namespace = self.target.getNamespace(data['owner']) |
70 | self.branch = namespace.createBranch( |
71 | - branch_type=BranchType.items[ui_branch_type.name], |
72 | + branch_type=BranchType.HOSTED, |
73 | name=data['name'], |
74 | registrant=self.user, |
75 | - url=data.get('url'), |
76 | + url=None, |
77 | lifecycle_status=data['lifecycle_status']) |
78 | - if self.branch.branch_type == BranchType.MIRRORED: |
79 | - self.branch.requestMirror() |
80 | except BranchCreationForbidden: |
81 | self.addError( |
82 | "You are not allowed to create branches in %s." % |
83 | @@ -1221,36 +1209,6 @@ |
84 | 'owner', |
85 | 'You are not a member of %s' % owner.displayname) |
86 | |
87 | - branch_type = data.get('branch_type') |
88 | - # If branch_type failed to validate, then the rest of the method |
89 | - # doesn't make any sense. |
90 | - if branch_type is None: |
91 | - return |
92 | - |
93 | - # If the branch is a MIRRORED branch, then the url |
94 | - # must be supplied, and if HOSTED the url must *not* |
95 | - # be supplied. |
96 | - url = data.get('url') |
97 | - if branch_type == UICreatableBranchType.MIRRORED: |
98 | - if url is None: |
99 | - # If the url is not set due to url validation errors, |
100 | - # there will be an error set for it. |
101 | - error = self.getFieldError('url') |
102 | - if not error: |
103 | - self.setFieldError( |
104 | - 'url', |
105 | - 'Branch URLs are required for Mirrored branches.') |
106 | - elif branch_type == UICreatableBranchType.HOSTED: |
107 | - if url is not None: |
108 | - self.setFieldError( |
109 | - 'url', |
110 | - 'Branch URLs cannot be set for Hosted branches.') |
111 | - elif branch_type == UICreatableBranchType.REMOTE: |
112 | - # A remote location can, but doesn't have to be set. |
113 | - pass |
114 | - else: |
115 | - raise AssertionError('Unknown branch type') |
116 | - |
117 | @property |
118 | def cancel_url(self): |
119 | return canonical_url(self.context) |
120 | |
121 | === modified file 'lib/lp/code/browser/codeimport.py' |
122 | --- lib/lp/code/browser/codeimport.py 2011-09-26 06:30:07 +0000 |
123 | +++ lib/lp/code/browser/codeimport.py 2011-10-04 14:34:53 +0000 |
124 | @@ -252,7 +252,7 @@ |
125 | "The URL of the git repository. The HEAD branch will be " |
126 | "imported."), |
127 | allowed_schemes=["git", "http", "https"], |
128 | - allow_userinfo=False, # Only anonymous access is supported. |
129 | + allow_userinfo=True, |
130 | allow_port=True, |
131 | allow_query=False, |
132 | allow_fragment=False, |
133 | @@ -264,12 +264,22 @@ |
134 | "The URL of the Mercurial repository. The tip branch will be " |
135 | "imported."), |
136 | allowed_schemes=["http", "https"], |
137 | - allow_userinfo=False, # Only anonymous access is supported. |
138 | + allow_userinfo=True, |
139 | allow_port=True, |
140 | - allow_query=False, # Query makes no sense in Mercurial. |
141 | - allow_fragment=False, # Fragment makes no sense in Mercurial. |
142 | + allow_query=False, # Query makes no sense in Bazaar. |
143 | + allow_fragment=False, # Fragment makes no sense in Bazaar. |
144 | trailing_slash=False) # See http://launchpad.net/bugs/56357. |
145 | |
146 | + bzr_branch_url = URIField( |
147 | + title=_("Branch URL"), required=False, |
148 | + description=_("The URL of the Bazaar branch."), |
149 | + allowed_schemes=["http", "https", "bzr"], |
150 | + allow_userinfo=True, |
151 | + allow_port=True, |
152 | + allow_query=False, # Query makes no sense in Bazaar |
153 | + allow_fragment=False, # Fragment makes no sense in Bazaar |
154 | + trailing_slash=False) |
155 | + |
156 | branch_name = copy_field( |
157 | IBranch['name'], |
158 | __name__='branch_name', |
159 | @@ -298,7 +308,7 @@ |
160 | def initial_values(self): |
161 | return { |
162 | 'owner': self.user, |
163 | - 'rcs_type': RevisionControlSystems.BZR_SVN, |
164 | + 'rcs_type': RevisionControlSystems.BZR, |
165 | 'branch_name': 'trunk', |
166 | } |
167 | |
168 | @@ -346,9 +356,11 @@ |
169 | # display them separately in the form. |
170 | soup = BeautifulSoup(self.widgets['rcs_type']()) |
171 | fields = soup.findAll('input') |
172 | - [cvs_button, svn_button, git_button, hg_button, empty_marker] = [ |
173 | - field for field in fields |
174 | - if field.get('value') in ['CVS', 'BZR_SVN', 'GIT', 'HG', '1']] |
175 | + [cvs_button, svn_button, git_button, hg_button, bzr_button, |
176 | + empty_marker] = [ |
177 | + field for field in fields |
178 | + if field.get('value') in [ |
179 | + 'CVS', 'BZR_SVN', 'GIT', 'HG', 'BZR', '1']] |
180 | cvs_button['onclick'] = 'updateWidgets()' |
181 | svn_button['onclick'] = 'updateWidgets()' |
182 | git_button['onclick'] = 'updateWidgets()' |
183 | @@ -358,6 +370,7 @@ |
184 | self.rcs_type_svn = str(svn_button) |
185 | self.rcs_type_git = str(git_button) |
186 | self.rcs_type_hg = str(hg_button) |
187 | + self.rcs_type_bzr = str(bzr_button) |
188 | self.rcs_type_emptymarker = str(empty_marker) |
189 | |
190 | def _getImportLocation(self, data): |
191 | @@ -371,6 +384,8 @@ |
192 | return None, None, data.get('git_repo_url') |
193 | elif rcs_type == RevisionControlSystems.HG: |
194 | return None, None, data.get('hg_repo_url') |
195 | + elif rcs_type == RevisionControlSystems.BZR: |
196 | + return None, None, data.get('bzr_branch_url') |
197 | else: |
198 | raise AssertionError( |
199 | 'Unexpected revision control type %r.' % rcs_type) |
200 | @@ -463,6 +478,9 @@ |
201 | elif rcs_type == RevisionControlSystems.HG: |
202 | self._validateURL( |
203 | data.get('hg_repo_url'), field_name='hg_repo_url') |
204 | + elif rcs_type == RevisionControlSystems.BZR: |
205 | + self._validateURL( |
206 | + data.get('bzr_branch_url'), field_name='bzr_branch_url') |
207 | else: |
208 | raise AssertionError( |
209 | 'Unexpected revision control type %r.' % rcs_type) |
210 | @@ -555,7 +573,8 @@ |
211 | elif self.code_import.rcs_type in (RevisionControlSystems.SVN, |
212 | RevisionControlSystems.BZR_SVN, |
213 | RevisionControlSystems.GIT, |
214 | - RevisionControlSystems.HG): |
215 | + RevisionControlSystems.HG, |
216 | + RevisionControlSystems.BZR): |
217 | self.form_fields = self.form_fields.omit( |
218 | 'cvs_root', 'cvs_module') |
219 | else: |
220 | @@ -590,7 +609,8 @@ |
221 | elif self.code_import.rcs_type in (RevisionControlSystems.SVN, |
222 | RevisionControlSystems.BZR_SVN, |
223 | RevisionControlSystems.GIT, |
224 | - RevisionControlSystems.HG): |
225 | + RevisionControlSystems.HG, |
226 | + RevisionControlSystems.BZR): |
227 | self._validateURL(data.get('url'), self.code_import) |
228 | else: |
229 | raise AssertionError('Unknown rcs_type for code import.') |
230 | |
231 | === modified file 'lib/lp/code/browser/tests/test_branch.py' |
232 | --- lib/lp/code/browser/tests/test_branch.py 2011-08-29 07:55:48 +0000 |
233 | +++ lib/lp/code/browser/tests/test_branch.py 2011-10-04 14:34:53 +0000 |
234 | @@ -191,8 +191,8 @@ |
235 | "This is a short error message.", |
236 | branch_view.mirror_status_message) |
237 | |
238 | - def testBranchAddRequestsMirror(self): |
239 | - """Registering a mirrored branch requests a mirror.""" |
240 | + def testBranchAddRequests(self): |
241 | + """Registering a branch that requests a mirror.""" |
242 | arbitrary_person = self.factory.makePerson() |
243 | arbitrary_product = self.factory.makeProduct() |
244 | login_person(arbitrary_person) |
245 | @@ -200,9 +200,8 @@ |
246 | add_view = BranchAddView(arbitrary_person, self.request) |
247 | add_view.initialize() |
248 | data = { |
249 | - 'branch_type': BranchType.MIRRORED, |
250 | + 'branch_type': BranchType.HOSTED, |
251 | 'name': 'some-branch', |
252 | - 'url': 'http://example.com', |
253 | 'title': 'Branch Title', |
254 | 'summary': '', |
255 | 'lifecycle_status': BranchLifecycleStatus.DEVELOPMENT, |
256 | @@ -212,15 +211,6 @@ |
257 | 'product': arbitrary_product, |
258 | } |
259 | add_view.add_action.success(data) |
260 | - # Make sure that next_mirror_time is a datetime, not an sqlbuilder |
261 | - # expression. |
262 | - removeSecurityProxy(add_view.branch).sync() |
263 | - now = datetime.now(pytz.timezone('UTC')) |
264 | - self.assertNotEqual(None, add_view.branch.next_mirror_time) |
265 | - self.assertTrue( |
266 | - add_view.branch.next_mirror_time < now, |
267 | - "next_mirror_time not set to UTC_NOW: %s < %s" |
268 | - % (add_view.branch.next_mirror_time, now)) |
269 | finally: |
270 | logout() |
271 | |
272 | |
273 | === modified file 'lib/lp/code/enums.py' |
274 | --- lib/lp/code/enums.py 2011-08-28 07:29:11 +0000 |
275 | +++ lib/lp/code/enums.py 2011-10-04 14:34:53 +0000 |
276 | @@ -99,8 +99,8 @@ |
277 | IMPORTED = DBItem(3, """ |
278 | Imported |
279 | |
280 | - Branches that have been converted from some other revision |
281 | - control system into bzr and are made available through Launchpad. |
282 | + Branches that have been imported from an externally hosted |
283 | + branch in bzr or another VCS and are made available through Launchpad. |
284 | """) |
285 | |
286 | REMOTE = DBItem(4, """ |
287 | |
288 | === modified file 'lib/lp/code/stories/branches/xx-branch-deletion.txt' |
289 | --- lib/lp/code/stories/branches/xx-branch-deletion.txt 2011-06-06 19:39:45 +0000 |
290 | +++ lib/lp/code/stories/branches/xx-branch-deletion.txt 2011-10-04 14:34:53 +0000 |
291 | @@ -22,7 +22,6 @@ |
292 | >>> browser = setupBrowser(auth="Basic alice@example.com:test") |
293 | >>> browser.open('http://code.launchpad.dev/earthlynx') |
294 | >>> browser.getLink("Register a branch").click() |
295 | - >>> browser.getControl('Branch URL').value = 'http://foo.bar.com/oops' |
296 | >>> browser.getControl('Name').value = 'to-delete' |
297 | >>> browser.getControl('Register Branch').click() |
298 | >>> print browser.title |
299 | @@ -60,7 +59,6 @@ |
300 | |
301 | >>> browser.open('http://code.launchpad.dev/~alice') |
302 | >>> browser.getLink("Register a branch").click() |
303 | - >>> browser.getControl('Hosted').click() |
304 | >>> browser.getControl('Name').value = 'to-delete' |
305 | >>> browser.getControl('Register Branch').click() |
306 | >>> browser.getLink('Delete branch').click() |
307 | |
308 | === removed file 'lib/lp/code/stories/branches/xx-branch-url-validation.txt' |
309 | --- lib/lp/code/stories/branches/xx-branch-url-validation.txt 2010-08-23 05:06:49 +0000 |
310 | +++ lib/lp/code/stories/branches/xx-branch-url-validation.txt 1970-01-01 00:00:00 +0000 |
311 | @@ -1,72 +0,0 @@ |
312 | -= Validating of branch URLs = |
313 | - |
314 | -First, let's define a helper to post to the Person +addbranch form. |
315 | - |
316 | - >>> def add_branch(url): |
317 | - ... user_browser.open( |
318 | - ... 'http://code.launchpad.dev/~lifeless/+addbranch') |
319 | - ... user_browser.getControl('Name').value = 'pyresources' |
320 | - ... user_browser.getControl('Branch URL').value = url |
321 | - ... user_browser.getControl('Register Branch').click() |
322 | - |
323 | -Try to create a branch with an invalid URL. |
324 | - |
325 | - >>> add_branch('example.com/~lifeless/pyresources/') |
326 | - >>> for message in get_feedback_messages(user_browser.contents): |
327 | - ... print message |
328 | - There is 1 error. |
329 | - "example.com/~lifeless/pyresources/" is not a valid URI |
330 | - |
331 | -Try to create branches with URLs in bazaar.launchpad.dev. |
332 | - |
333 | - >>> add_branch('http://bazaar.launchpad.dev') |
334 | - >>> for message in get_feedback_messages(user_browser.contents): |
335 | - ... print message |
336 | - There is 1 error. |
337 | - For Launchpad to mirror a branch, the original branch cannot be on |
338 | - launchpad.dev. |
339 | - |
340 | - >>> add_branch('http://bazaar.launchpad.dev/~me/that/this') |
341 | - >>> for message in get_feedback_messages(user_browser.contents): |
342 | - ... print message |
343 | - There is 1 error. |
344 | - For Launchpad to mirror a branch, the original branch cannot be on |
345 | - launchpad.dev. |
346 | - |
347 | - >>> add_branch('sftp://bazaar.launchpad.dev/~me/that/this') |
348 | - >>> for message in get_feedback_messages(user_browser.contents): |
349 | - ... print message |
350 | - There is 1 error. |
351 | - For Launchpad to mirror a branch, the original branch cannot be on |
352 | - launchpad.dev. |
353 | - |
354 | -Try to create a branch with a URL that is already registered. |
355 | - |
356 | - >>> add_branch('http://example.com/gnome-terminal/main/') |
357 | - >>> for message in get_feedback_messages(user_browser.contents): |
358 | - ... print message |
359 | - There is 1 error. |
360 | - The bzr branch lp://dev/~name12/gnome-terminal/main is already registered |
361 | - with this URL. |
362 | - |
363 | - |
364 | -Try to create a branch without URL |
365 | - |
366 | - >>> add_branch('') |
367 | - >>> for message in get_feedback_messages(user_browser.contents): |
368 | - ... print message |
369 | - There is 1 error. |
370 | - Branch URLs are required for Mirrored branches. |
371 | - |
372 | -Try to create a branch using the bzr+ssh URL scheme. |
373 | - |
374 | - >>> add_branch('bzr+ssh://example.com/code/branch') |
375 | - >>> print user_browser.url |
376 | - http://code.launchpad.dev/~no-priv/+junk/pyresources |
377 | - |
378 | - |
379 | -= The other forms = |
380 | - |
381 | -The +addbranch form of Product, and the +edit form of a branch all use the same |
382 | -validation logic that the previous form, since it is defined in the IBranch |
383 | -interface. No point in repeating the tests here. |
384 | |
385 | === modified file 'lib/lp/code/stories/branches/xx-creating-branches.txt' |
386 | --- lib/lp/code/stories/branches/xx-creating-branches.txt 2010-10-18 22:24:59 +0000 |
387 | +++ lib/lp/code/stories/branches/xx-creating-branches.txt 2011-10-04 14:34:53 +0000 |
388 | @@ -32,94 +32,8 @@ |
389 | >>> browser.open('http://code.launchpad.dev/redfish') |
390 | >>> browser.getLink("Register a branch").click() |
391 | |
392 | - >>> browser.getControl('Hosted').click() |
393 | >>> browser.getControl('Name').value = 'hosted-branch' |
394 | |
395 | -Branch URLs are not valid for hosted branches. |
396 | - |
397 | - >>> browser.getControl('Branch URL').value = ( |
398 | - ... 'http://example.com/hosted-branch') |
399 | - >>> browser.getControl('Register Branch').click() |
400 | - >>> for message in get_feedback_messages(browser.contents): |
401 | - ... print message |
402 | - There is 1 error. |
403 | - Branch URLs cannot be set for Hosted branches. |
404 | - |
405 | - >>> browser.getControl('Branch URL').value = '' |
406 | - >>> browser.getControl('Register Branch').click() |
407 | - |
408 | - >>> def print_branch_info(browser): |
409 | - ... branch_info = find_tag_by_id(browser.contents, 'branch-info') |
410 | - ... print extract_text(branch_info) |
411 | - >>> print_branch_info(browser) |
412 | - Branch information |
413 | - Owner: Sample Person |
414 | - Project: Redfish |
415 | - Status: Development |
416 | - |
417 | - |
418 | -Creating a mirrored branch |
419 | --------------------------- |
420 | - |
421 | -Mirrored branches are primarily hosted outside of Launchpad, and |
422 | -Launchpad mirrors the branch. |
423 | - |
424 | - >>> browser.open('http://code.launchpad.dev/redfish') |
425 | - >>> browser.getLink("Register a branch").click() |
426 | - |
427 | - >>> print_radio_button_field(browser.contents, 'branch_type') |
428 | - ( ) Hosted |
429 | - (*) Mirrored |
430 | - ( ) Remote |
431 | - |
432 | - >>> browser.getControl('Name').value = 'mirrored-branch' |
433 | - |
434 | -Branch URLs are required for mirrored branches. |
435 | - |
436 | - >>> browser.getControl('Register Branch').click() |
437 | - >>> for message in get_feedback_messages(browser.contents): |
438 | - ... print message |
439 | - There is 1 error. |
440 | - Branch URLs are required for Mirrored branches. |
441 | - |
442 | - >>> browser.getControl('Branch URL').value = ( |
443 | - ... 'http://example.com/mirrored-branch') |
444 | - >>> browser.getControl('Register Branch').click() |
445 | - |
446 | - >>> print_branch_info(browser) |
447 | - Branch information |
448 | - Owner: Sample Person |
449 | - Project: Redfish |
450 | - Status: Development |
451 | - Location: http://example.com/mirrored-branch |
452 | - Last mirrored: Not mirrored yet |
453 | - Next mirror: As soon as possible |
454 | - |
455 | - |
456 | -Creating a remote branch |
457 | ------------------------- |
458 | - |
459 | -The contents of Remote branches are not accessible through Launchpad. |
460 | - |
461 | - >>> browser.open('http://code.launchpad.dev/redfish') |
462 | - >>> browser.getLink("Register a branch").click() |
463 | - |
464 | - >>> browser.getControl('Remote').click() |
465 | - >>> browser.getControl('Name').value = 'remote-branch' |
466 | - |
467 | -A remote branch may have a URL, but doesn't have to. |
468 | - |
469 | - >>> browser.getControl('Branch URL').value = ( |
470 | - ... 'http://example.com/remote-branch') |
471 | - >>> browser.getControl('Register Branch').click() |
472 | - >>> print_branch_info(browser) |
473 | - Branch information |
474 | - Owner: Sample Person |
475 | - Project: Redfish |
476 | - Status: Development |
477 | - Location: http://example.com/remote-branch |
478 | - |
479 | - |
480 | Finding product/+addbranch |
481 | -------------------------- |
482 | |
483 | @@ -172,9 +86,6 @@ |
484 | The specified URL has a trailing slash. In the next test, we will check |
485 | that it has been stripped. |
486 | |
487 | - >>> user_browser.getControl('Branch URL').value = ( |
488 | - ... 'http://example.com/applets/main/') |
489 | - |
490 | >>> user_browser.getControl('Name').value = 'main' |
491 | >>> user_browser.getControl('Experimental').click() |
492 | >>> user_browser.getControl('Register Branch').click() |
493 | @@ -193,12 +104,6 @@ |
494 | >>> print extract_text(find_tag_by_id(content, 'privacy')) |
495 | This branch is public |
496 | |
497 | - >>> print extract_text(content.h1) |
498 | - lp://dev/~no-priv/applets/main |
499 | - |
500 | - >>> print extract_text(find_tag_by_id(content, 'mirror-location')) |
501 | - Location: http://example.com/applets/main |
502 | - |
503 | This page includes a link to other branches associated with that |
504 | product, and a link to other branches maintained by that person. |
505 | |
506 | @@ -209,34 +114,6 @@ |
507 | Other branches owned by No Privileges Person |
508 | |
509 | |
510 | -Adding a branch via a product series |
511 | ------------------------------------- |
512 | - |
513 | -A user can register a branch from the project series page using the |
514 | -'Submit code' link, or in the case of a series driver, by using the |
515 | -'registering a mirrored branch' link. |
516 | - |
517 | - >>> browser.open('http://launchpad.dev/gnome-terminal/trunk') |
518 | - >>> browser.getLink('registering a mirrored branch').click() |
519 | - >>> print browser.title |
520 | - Register a branch : Code : GNOME Terminal |
521 | - |
522 | -The user sees that he is registering a branch for the series' project. |
523 | - |
524 | - >>> print extract_text(find_main_content(browser.contents).h1) |
525 | - Register a branch on GNOME Terminal |
526 | - |
527 | -After posting the form, he sees the registered branch page. |
528 | - |
529 | - >>> browser.getControl('Branch URL').value = ( |
530 | - ... 'http://example.com/applets/master') |
531 | - >>> browser.getControl('Name').value = 'master' |
532 | - >>> browser.getControl('Experimental').click() |
533 | - >>> browser.getControl('Register Branch').click() |
534 | - >>> print browser.title |
535 | - master : Code : GNOME Terminal |
536 | - |
537 | - |
538 | Finding person/+addbranch |
539 | ------------------------- |
540 | |
541 | @@ -271,7 +148,6 @@ |
542 | Ubuntu Gnome Team (name18) |
543 | Warty Security Team (name20) |
544 | |
545 | - |
546 | Conflict on unique name |
547 | ----------------------- |
548 | |
549 | @@ -288,8 +164,6 @@ |
550 | Try a adding a conflicting branch from the product/+addbranch form. |
551 | |
552 | >>> browser.open('http://code.launchpad.dev/gnome-terminal/+addbranch') |
553 | - >>> browser.getControl('Branch URL').value = ( |
554 | - ... 'http://example.com/gnome-terminal/main-dup') |
555 | |
556 | Trying to post the form without filling a name at all should not cause |
557 | an oops! |
558 | @@ -321,7 +195,6 @@ |
559 | >>> browser.getControl('Owner').displayValue = [ |
560 | ... 'Landscape Developers'] |
561 | >>> browser.getControl('Name').value = 'main' |
562 | - >>> browser.getControl('Hosted').click() |
563 | >>> browser.getControl('Register Branch').click() |
564 | >>> print browser.url |
565 | http://code.launchpad.dev/~landscape-developers/gnome-terminal/main |
566 | @@ -335,7 +208,6 @@ |
567 | >>> browser.getControl('Owner').displayValue = [ |
568 | ... 'Landscape Developers'] |
569 | >>> browser.getControl('Name').value = 'main' |
570 | - >>> browser.getControl('Hosted').click() |
571 | >>> browser.getControl('Register Branch').click() |
572 | >>> for message in get_feedback_messages(browser.contents): |
573 | ... print extract_text(message) |
574 | @@ -343,65 +215,6 @@ |
575 | Landscape Developers already has a branch for GNOME Terminal called main. |
576 | |
577 | |
578 | -Checking URLs |
579 | -------------- |
580 | - |
581 | -URL validation should check that the entered URL is not the root of a |
582 | -site. |
583 | - |
584 | - >>> user_browser.open('http://code.launchpad.dev/applets') |
585 | - >>> user_browser.getLink("Register a branch").click() |
586 | - >>> user_browser.getControl('Branch URL').value = 'http://example.com' |
587 | - >>> user_browser.getControl('Name').value = 'unique-name' |
588 | - >>> user_browser.getControl('Register Branch').click() |
589 | - >>> messages = find_tags_by_class(user_browser.contents, 'message') |
590 | - >>> for element in messages: |
591 | - ... print element.renderContents() |
592 | - There is 1 error. |
593 | - URLs for branches cannot point to the root of a site. |
594 | - |
595 | -URL validation should check that the entered URL is not from Launchpad. |
596 | - |
597 | - >>> user_browser.open('http://code.launchpad.dev/applets') |
598 | - >>> user_browser.getLink("Register a branch").click() |
599 | - >>> user_browser.getControl('Branch URL').value = ( |
600 | - ... 'http://code.launchpad.dev/~testuser/') |
601 | - >>> user_browser.getControl('Name').value = 'unique-name' |
602 | - >>> user_browser.getControl('Register Branch').click() |
603 | - >>> for message in get_feedback_messages(user_browser.contents): |
604 | - ... print message |
605 | - There is 1 error. |
606 | - For Launchpad to mirror a branch, the original branch cannot be on |
607 | - launchpad.dev. |
608 | - |
609 | -As well as checking against the root site set in the config, a check is |
610 | -also done against the value stored as a database constraint. |
611 | - |
612 | - >>> user_browser.open('http://code.launchpad.dev/applets') |
613 | - >>> user_browser.getLink("Register a branch").click() |
614 | - >>> user_browser.getControl('Branch URL').value = ( |
615 | - ... 'http://bazaar.launchpad.net/foo/bar/') |
616 | - >>> user_browser.getControl('Name').value = 'unique-name' |
617 | - >>> user_browser.getControl('Register Branch').click() |
618 | - >>> for message in get_feedback_messages(user_browser.contents): |
619 | - ... print message |
620 | - There is 1 error. |
621 | - For Launchpad to mirror a branch, the original branch cannot be on |
622 | - http://bazaar.launchpad.net. |
623 | - |
624 | -Trailing slashes on URLs are removed. |
625 | - |
626 | - >>> user_browser.getControl('Branch URL').value = ( |
627 | - ... 'sftp://example.com/~lifeless/pyresources/') |
628 | - >>> user_browser.getControl('Register Branch').click() |
629 | - >>> print_tag_with_id(user_browser.contents, 'branch-info') |
630 | - Branch information |
631 | - Owner: ... |
632 | - ... |
633 | - Location: sftp://example.com/~lifeless/pyresources |
634 | - ... |
635 | - |
636 | - |
637 | Attempting to create a branch in a forbidden project |
638 | ---------------------------------------------------- |
639 | |
640 | @@ -423,7 +236,6 @@ |
641 | |
642 | >>> user_browser.open('http://code.launchpad.dev/landscape') |
643 | >>> user_browser.getLink("Register a branch").click() |
644 | - >>> user_browser.getControl('Branch URL').value = 'http://foo.com/bar' |
645 | >>> user_browser.getControl('Name').value = 'landscape1' |
646 | >>> user_browser.getControl('Register Branch').click() |
647 | >>> messages = find_tags_by_class(user_browser.contents, 'message') |
648 | |
649 | === modified file 'lib/lp/code/stories/branches/xx-junk-branches.txt' |
650 | --- lib/lp/code/stories/branches/xx-junk-branches.txt 2010-01-21 03:02:09 +0000 |
651 | +++ lib/lp/code/stories/branches/xx-junk-branches.txt 2011-10-04 14:34:53 +0000 |
652 | @@ -17,7 +17,6 @@ |
653 | >>> browser.open('http://code.launchpad.dev/~eric') |
654 | >>> browser.getLink("Register a branch").click() |
655 | >>> browser.getControl('Name').value = 'personal-junk' |
656 | - >>> browser.getControl('Hosted').click() |
657 | >>> browser.getControl('Register Branch').click() |
658 | |
659 | Posting the form should succeed and redirect to the page of the newly created |
660 | @@ -31,8 +30,8 @@ |
661 | Nearby |
662 | Other branches owned by Eric |
663 | |
664 | -Junk branches do not support merge proposals, so the "Branch Merges" section of |
665 | -the page should not be shown. |
666 | +Junk branches do not support merge proposals, so the "Branch Merges" section |
667 | +of the page should not be shown. |
668 | |
669 | >>> print find_tag_by_id(browser.contents, 'branch-merges') |
670 | None |
671 | @@ -46,7 +45,6 @@ |
672 | >>> browser.open('http://code.launchpad.dev/~vikings') |
673 | >>> browser.getLink("Register a branch").click() |
674 | >>> browser.getControl('Name').value = 'team-junk' |
675 | - >>> browser.getControl('Hosted').click() |
676 | >>> browser.getControl('Register Branch').click() |
677 | |
678 | >>> print browser.url |
679 | |
680 | === modified file 'lib/lp/code/stories/codeimport/xx-create-codeimport.txt' |
681 | --- lib/lp/code/stories/codeimport/xx-create-codeimport.txt 2011-08-15 11:21:26 +0000 |
682 | +++ lib/lp/code/stories/codeimport/xx-create-codeimport.txt 2011-10-04 14:34:53 +0000 |
683 | @@ -40,7 +40,8 @@ |
684 | >>> owner_browser.getLink('Configure code hosting').click() |
685 | >>> owner_browser.getControl( |
686 | ... 'Import a branch').click() |
687 | - >>> owner_browser.getControl('Branch URL').value = 'git://example.com/firefox' |
688 | + >>> owner_browser.getControl('Branch URL').value = ( |
689 | + ... 'git://example.com/firefox') |
690 | >>> owner_browser.getControl('Git').click() |
691 | >>> owner_browser.getControl('Branch name').value = 'trunk' |
692 | >>> owner_browser.getControl('Update').click() |
693 | @@ -50,22 +51,65 @@ |
694 | >>> browser.open('http://code.launchpad.dev/firefox') |
695 | >>> browser.getLink('Import a branch').click() |
696 | |
697 | -Requesting a Subversion import |
698 | -============================== |
699 | +Requesting a Bazaar import |
700 | +========================== |
701 | |
702 | -The default foreign VCS type is Subversion. |
703 | +The default VCS type is Bazaar. |
704 | |
705 | >>> print_radio_button_field(browser.contents, "rcs_type") |
706 | + (*) Bazaar |
707 | ( ) Git |
708 | ( ) Mercurial |
709 | - (*) Subversion |
710 | + ( ) Subversion |
711 | ( ) CVS |
712 | |
713 | The user is required to enter a project that the import is for, a name |
714 | -for the import branch, and a subversion branch location. |
715 | - |
716 | +for the import branch, and a Bazaar branch location. |
717 | + |
718 | + >>> browser.getControl('Branch Name').value = "mirrored" |
719 | + >>> browser.getControl('Branch URL', index=0).value = ( |
720 | + ... "http://bzr.example.com/firefox/trunk") |
721 | + >>> browser.getControl('Request Import').click() |
722 | + |
723 | +When the user clicks continue, the import branch is created |
724 | + |
725 | + >>> print extract_text(find_tag_by_id(browser.contents, "import-details")) |
726 | + Import Status: Reviewed |
727 | + This branch is an import of the Bazaar branch |
728 | + at http://bzr.example.com/firefox/trunk. |
729 | + The next import is scheduled to run |
730 | + as soon as possible. |
731 | + >>> browser.getLink("http://bzr.example.com/firefox/trunk") |
732 | + <Link text='http://bzr.example.com/firefox/trunk' |
733 | + url='http://bzr.example.com/firefox/trunk'> |
734 | + |
735 | +If the user wants, they can include a username and password in the |
736 | +URL. |
737 | + |
738 | + >>> browser.open("http://code.launchpad.dev/+code-imports/+new") |
739 | + >>> browser.getControl('Branch Name').value = "with-password" |
740 | + >>> browser.getControl('Branch URL', index=0).value = ( |
741 | + ... "http://user:password@bzr.example.com/firefox/trunk") |
742 | + >>> browser.getControl('Project').value = "firefox" |
743 | + >>> browser.getControl('Request Import').click() |
744 | + >>> print extract_text(find_tag_by_id(browser.contents, "import-details")) |
745 | + Import Status: Reviewed |
746 | + This branch is an import of the Bazaar branch |
747 | + at http://user:password@bzr.example.com/firefox/trunk. |
748 | + The next import is scheduled to run |
749 | + as soon as possible. |
750 | + |
751 | +Requesting a Subversion import |
752 | +============================== |
753 | + |
754 | +The user is required to enter a project that the import is for, |
755 | +a name for the import branch, and a subversion branch location. |
756 | + |
757 | + >>> browser.open("http://code.launchpad.dev/+code-imports/+new") |
758 | + >>> browser.getControl('Subversion').click() |
759 | + >>> browser.getControl('Project').value = "firefox" |
760 | >>> browser.getControl('Branch Name').value = "imported" |
761 | - >>> browser.getControl('Branch URL').value = ( |
762 | + >>> browser.getControl('Branch URL', index=1).value = ( |
763 | ... "http://svn.example.com/firefox/trunk") |
764 | >>> browser.getControl('Request Import').click() |
765 | |
766 | @@ -94,8 +138,9 @@ |
767 | URL. |
768 | |
769 | >>> browser.open("http://code.launchpad.dev/+code-imports/+new") |
770 | - >>> browser.getControl('Branch Name').value = "with-password" |
771 | - >>> browser.getControl('Branch URL').value = ( |
772 | + >>> browser.getControl('Subversion').click() |
773 | + >>> browser.getControl('Branch Name').value = "svn-with-password" |
774 | + >>> browser.getControl('Branch URL', index=1).value = ( |
775 | ... "http://user:password@svn.example.com/firefox/trunk") |
776 | >>> browser.getControl('Project').value = "firefox" |
777 | >>> browser.getControl('Request Import').click() |
778 | @@ -221,7 +266,7 @@ |
779 | the imported branch ~no-priv/firefox/import2. |
780 | |
781 | >>> browser.getControl('Subversion').click() |
782 | - >>> browser.getControl('Branch URL').value = ( |
783 | + >>> browser.getControl('Branch URL', index=1).value = ( |
784 | ... "http://svn.example.com/firefox/trunk") |
785 | >>> browser.getControl('Request Import').click() |
786 | |
787 | @@ -241,9 +286,10 @@ |
788 | one. |
789 | |
790 | >>> browser.open("http://code.launchpad.dev/+code-imports/+new") |
791 | + >>> browser.getControl('Subversion').click() |
792 | >>> browser.getControl('Project').value = "firefox" |
793 | >>> browser.getControl('Branch Name').value = "imported" |
794 | - >>> browser.getControl('Branch URL').value = ( |
795 | + >>> browser.getControl('Branch URL', index=1).value = ( |
796 | ... "http://svn.example.com/firefox/other") |
797 | >>> browser.getControl('Request Import').click() |
798 | >>> for message in get_feedback_messages(browser.contents): |
799 | @@ -261,7 +307,7 @@ |
800 | >>> browser.open("http://code.launchpad.dev/+code-imports/+new") |
801 | >>> browser.getControl('Project').value = "launchpad" |
802 | >>> browser.getControl('Branch Name').value = "imported" |
803 | - >>> browser.getControl('Branch URL').value = ( |
804 | + >>> browser.getControl('Branch URL', index=0).value = ( |
805 | ... "http://svn.example.com/launchpage/fake") |
806 | >>> browser.getControl('Request Import').click() |
807 | >>> for message in get_feedback_messages(browser.contents): |
808 | @@ -279,7 +325,7 @@ |
809 | >>> browser.open("http://code.launchpad.dev/+code-imports/+new") |
810 | >>> browser.getControl('Project').value = "no-such-product" |
811 | >>> browser.getControl('Branch Name').value = "imported" |
812 | - >>> browser.getControl('Branch URL').value = ( |
813 | + >>> browser.getControl('Branch URL', index=0).value = ( |
814 | ... "http://svn.example.com/launchpage/fake") |
815 | >>> browser.getControl('Request Import').click() |
816 | >>> for message in get_feedback_messages(browser.contents): |
817 | @@ -306,7 +352,7 @@ |
818 | >>> sample_browser.getControl('Owner').value = ['landscape-developers'] |
819 | >>> sample_browser.getControl('Owner').displayValue |
820 | ['Landscape Developers (landscape-developers)'] |
821 | - >>> sample_browser.getControl('Branch URL').value = ( |
822 | + >>> sample_browser.getControl('Branch URL', index=0).value = ( |
823 | ... "http://svn.example.com/firefox-beta/trunk") |
824 | >>> sample_browser.getControl('Request Import').click() |
825 | |
826 | @@ -320,7 +366,7 @@ |
827 | >>> admin_browser = setupBrowser(auth='Basic admin@canonical.com:test') |
828 | >>> admin_browser.open("http://code.launchpad.dev/firefox/+new-import") |
829 | >>> admin_browser.getControl('Owner').value = 'mark' |
830 | - >>> admin_browser.getControl('Branch URL').value = ( |
831 | + >>> admin_browser.getControl('Branch URL', index=0).value = ( |
832 | ... "http://svn.example.com/firefox-theta/trunk") |
833 | >>> admin_browser.getControl('Request Import').click() |
834 | |
835 | |
836 | === modified file 'lib/lp/code/templates/branch-form-macros.pt' |
837 | --- lib/lp/code/templates/branch-form-macros.pt 2009-10-02 15:02:23 +0000 |
838 | +++ lib/lp/code/templates/branch-form-macros.pt 2011-10-04 14:34:53 +0000 |
839 | @@ -17,20 +17,6 @@ |
840 | |
841 | <script type="text/javascript"> |
842 | //<![CDATA[ |
843 | -function update_branch_url() |
844 | -{ |
845 | - var branch_type_field = document.getElementsByName('field.branch_type') |
846 | - var form = branch_type_field[0].form; |
847 | - var branch_type = 'None'; |
848 | - for (var i = 0; i < branch_type_field.length; i++) { |
849 | - if (branch_type_field[i].checked) { |
850 | - branch_type = branch_type_field[i].value; |
851 | - break; |
852 | - } |
853 | - } |
854 | - updateField(form['field.url'], branch_type != 'HOSTED'); |
855 | -} |
856 | - |
857 | function update_branch_unique_name() |
858 | { |
859 | var unique_name = document.getElementById("branch-unique-name") |
860 | @@ -43,44 +29,16 @@ |
861 | unique_name.innerHTML = branch_name |
862 | } |
863 | |
864 | -function populate_branch_name_from_url() |
865 | -{ |
866 | - url_field = document.getElementById('field.url'); |
867 | - var url_text = trim(url_field.value); |
868 | - // strip of any trailing slashes |
869 | - url_text = url_text.replace(/\/+$/, '') |
870 | - if (url_text != url_field.value) { |
871 | - url_field.value = url_text; |
872 | - } |
873 | - var name_field = document.getElementById('field.name'); |
874 | - if (name_field.value == '') |
875 | - { |
876 | - // parse the value of the url field |
877 | - url_bits = url_text.split('/'); |
878 | - if (url_bits.length > 2) { |
879 | - // attempt at not barfing on something completely invalid |
880 | - last_bit = url_bits[url_bits.length - 1]; |
881 | - name_field.value = last_bit; |
882 | - } |
883 | - } |
884 | -} |
885 | - |
886 | function hookUpBranchFieldFunctions() |
887 | { |
888 | connect('field.owner', 'onkeyup', update_branch_unique_name); |
889 | connect('field.owner', 'onchange', update_branch_unique_name); |
890 | connect('field.name', 'onkeyup', update_branch_unique_name); |
891 | - connect('field.branch_type.0', 'onclick', update_branch_url); |
892 | - connect('field.branch_type.1', 'onclick', update_branch_url); |
893 | - connect('field.branch_type.2', 'onclick', update_branch_url); |
894 | update_branch_unique_name(); |
895 | - connect('field.url', 'onchange', populate_branch_name_from_url); |
896 | - connect('field.url', 'onblur', populate_branch_name_from_url); |
897 | document.getElementById("branch-unique-name-div").style.display = "block"; |
898 | } |
899 | |
900 | registerLaunchpadFunction(hookUpBranchFieldFunctions); |
901 | -registerLaunchpadFunction(update_branch_url); |
902 | |
903 | //]]> |
904 | </script> |
905 | |
906 | === modified file 'lib/lp/code/templates/branch-import-details.pt' |
907 | --- lib/lp/code/templates/branch-import-details.pt 2010-06-10 07:54:59 +0000 |
908 | +++ lib/lp/code/templates/branch-import-details.pt 2011-10-04 14:34:53 +0000 |
909 | @@ -41,26 +41,50 @@ |
910 | |
911 | <tal:git-import condition="code_import/rcs_type/enumvalue:GIT"> |
912 | <p>This branch is an import of the HEAD branch of the Git repository at |
913 | - <span tal:replace="code_import/url" />. |
914 | + <tal:is-web-url condition="view/url_is_web"> |
915 | + <a tal:attributes="href code_import/url" |
916 | + tal:content="code_import/url" />. |
917 | + </tal:is-web-url> |
918 | + <tal:not-web-url condition="not: view/url_is_web"> |
919 | + <span tal:replace="code_import/url" />. |
920 | + </tal:not-web-url> |
921 | </p> |
922 | </tal:git-import> |
923 | |
924 | <tal:hg-import condition="code_import/rcs_type/enumvalue:HG"> |
925 | <p>This branch is an import of the tip branch of the Mercurial repository at |
926 | - <span tal:replace="code_import/url" />. |
927 | + <tal:is-web-url condition="view/url_is_web"> |
928 | + <a tal:attributes="href code_import/url" |
929 | + tal:content="code_import/url" />. |
930 | + </tal:is-web-url> |
931 | + <tal:not-web-url condition="not: view/url_is_web"> |
932 | + <span tal:replace="code_import/url" />. |
933 | + </tal:not-web-url> |
934 | </p> |
935 | </tal:hg-import> |
936 | |
937 | + <tal:bzr-import condition="code_import/rcs_type/enumvalue:BZR"> |
938 | + <p>This branch is an import of the Bazaar branch at |
939 | + <tal:is-web-url condition="view/url_is_web"> |
940 | + <a tal:attributes="href code_import/url" |
941 | + tal:content="code_import/url" />. |
942 | + </tal:is-web-url> |
943 | + <tal:not-web-url condition="not: view/url_is_web"> |
944 | + <span tal:replace="code_import/url" />. |
945 | + </tal:not-web-url> |
946 | + </p> |
947 | + </tal:bzr-import> |
948 | + |
949 | <tal:svn-import condition="view/is_svn_import"> |
950 | <p id="svn-import-details"> |
951 | This branch is an import of the |
952 | <span tal:attributes="title code_import/rcs_type/title">Subversion</span> |
953 | branch from |
954 | - <tal:is-web-url condition="view/svn_url_is_web"> |
955 | + <tal:is-web-url condition="view/url_is_web"> |
956 | <a tal:attributes="href code_import/url" |
957 | tal:content="code_import/url" />. |
958 | </tal:is-web-url> |
959 | - <tal:not-web-url condition="not: view/svn_url_is_web"> |
960 | + <tal:not-web-url condition="not: view/url_is_web"> |
961 | <span tal:replace="code_import/url" />. |
962 | </tal:not-web-url> |
963 | </p> |
964 | |
965 | === modified file 'lib/lp/code/templates/codeimport-list.pt' |
966 | --- lib/lp/code/templates/codeimport-list.pt 2010-03-18 22:39:15 +0000 |
967 | +++ lib/lp/code/templates/codeimport-list.pt 2011-10-04 14:34:53 +0000 |
968 | @@ -21,6 +21,7 @@ |
969 | </select> |
970 | <select name="rcs_type" tal:replace="structure view/rcs_type_widget"> |
971 | <option label="">Any</option> |
972 | + <option label="BZR">Bazaar</option> |
973 | <option label="GIT">Git</option> |
974 | <option label="BZR_SVN">Subversion</option> |
975 | <option label="SVN">Subversion (legacy)</option> |
976 | |
977 | === modified file 'lib/lp/code/templates/codeimport-new.pt' |
978 | --- lib/lp/code/templates/codeimport-new.pt 2010-04-22 23:50:51 +0000 |
979 | +++ lib/lp/code/templates/codeimport-new.pt 2011-10-04 14:34:53 +0000 |
980 | @@ -53,6 +53,20 @@ |
981 | <tr> |
982 | <td> |
983 | <label> |
984 | + <input tal:replace="structure view/rcs_type_bzr" /> |
985 | + Bazaar |
986 | + </label> |
987 | + <table class="importdetails"> |
988 | + <tal:widget define="widget nocall:view/widgets/bzr_branch_url"> |
989 | + <metal:block use-macro="context/@@launchpad_form/widget_row" /> |
990 | + </tal:widget> |
991 | + </table> |
992 | + </td> |
993 | + </tr> |
994 | + |
995 | + <tr> |
996 | + <td> |
997 | + <label> |
998 | <input tal:replace="structure view/rcs_type_git" /> |
999 | Git |
1000 | </label> |
1001 | @@ -134,6 +148,8 @@ |
1002 | updateField(form['field.cvs_module'], rcs_type == 'CVS'); |
1003 | // SVN |
1004 | updateField(form['field.svn_branch_url'], rcs_type == 'BZR_SVN'); |
1005 | + // BZR |
1006 | + updateField(form['field.bzr_branch_url'], rcs_type == 'BZR'); |
1007 | } |
1008 | registerLaunchpadFunction(updateWidgets); |
1009 | //]]> |
1010 | |
1011 | === modified file 'lib/lp/registry/browser/productseries.py' |
1012 | --- lib/lp/registry/browser/productseries.py 2011-08-28 08:36:14 +0000 |
1013 | +++ lib/lp/registry/browser/productseries.py 2011-10-04 14:34:53 +0000 |
1014 | @@ -1089,8 +1089,7 @@ |
1015 | |
1016 | # Create a new branch. |
1017 | if branch_type == CREATE_NEW: |
1018 | - branch = self._createBzrBranch( |
1019 | - BranchType.HOSTED, branch_name, branch_owner) |
1020 | + branch = self._createBzrBranch(branch_name, branch_owner) |
1021 | if branch is not None: |
1022 | self.context.branch = branch |
1023 | self.request.response.addInfoNotification( |
1024 | @@ -1101,68 +1100,53 @@ |
1025 | # Either create an externally hosted bzr branch |
1026 | # (a.k.a. 'mirrored') or create a new code import. |
1027 | rcs_type = data.get('rcs_type') |
1028 | - if rcs_type == RevisionControlSystems.BZR: |
1029 | - branch = self._createBzrBranch( |
1030 | - BranchType.MIRRORED, branch_name, branch_owner, |
1031 | - data['repo_url']) |
1032 | - if branch is None: |
1033 | - return |
1034 | - |
1035 | - self.context.branch = branch |
1036 | - self.request.response.addInfoNotification( |
1037 | - 'Mirrored branch created and linked to ' |
1038 | - 'the series.') |
1039 | + # We need to create an import request. |
1040 | + if rcs_type == RevisionControlSystems.CVS: |
1041 | + cvs_root = data.get('repo_url') |
1042 | + cvs_module = data.get('cvs_module') |
1043 | + url = None |
1044 | else: |
1045 | - # We need to create an import request. |
1046 | - if rcs_type == RevisionControlSystems.CVS: |
1047 | - cvs_root = data.get('repo_url') |
1048 | - cvs_module = data.get('cvs_module') |
1049 | - url = None |
1050 | - else: |
1051 | - cvs_root = None |
1052 | - cvs_module = None |
1053 | - url = data.get('repo_url') |
1054 | - rcs_item = RevisionControlSystems.items[rcs_type.name] |
1055 | - try: |
1056 | - code_import = getUtility(ICodeImportSet).new( |
1057 | - registrant=branch_owner, |
1058 | - target=IBranchTarget(self.context.product), |
1059 | - branch_name=branch_name, |
1060 | - rcs_type=rcs_item, |
1061 | - url=url, |
1062 | - cvs_root=cvs_root, |
1063 | - cvs_module=cvs_module) |
1064 | - except BranchExists, e: |
1065 | - self._setBranchExists(e.existing_branch, |
1066 | - 'branch_name') |
1067 | - self.errors_in_action = True |
1068 | - # Abort transaction. This is normally handled |
1069 | - # by LaunchpadFormView, but we are already in |
1070 | - # the success handler. |
1071 | - self._abort() |
1072 | - return |
1073 | - self.context.branch = code_import.branch |
1074 | - self.request.response.addInfoNotification( |
1075 | - 'Code import created and branch linked to the ' |
1076 | - 'series.') |
1077 | + cvs_root = None |
1078 | + cvs_module = None |
1079 | + url = data.get('repo_url') |
1080 | + rcs_item = RevisionControlSystems.items[rcs_type.name] |
1081 | + try: |
1082 | + code_import = getUtility(ICodeImportSet).new( |
1083 | + registrant=branch_owner, |
1084 | + target=IBranchTarget(self.context.product), |
1085 | + branch_name=branch_name, |
1086 | + rcs_type=rcs_item, |
1087 | + url=url, |
1088 | + cvs_root=cvs_root, |
1089 | + cvs_module=cvs_module) |
1090 | + except BranchExists, e: |
1091 | + self._setBranchExists(e.existing_branch, |
1092 | + 'branch_name') |
1093 | + self.errors_in_action = True |
1094 | + # Abort transaction. This is normally handled |
1095 | + # by LaunchpadFormView, but we are already in |
1096 | + # the success handler. |
1097 | + self._abort() |
1098 | + return |
1099 | + self.context.branch = code_import.branch |
1100 | + self.request.response.addInfoNotification( |
1101 | + 'Code import created and branch linked to the ' |
1102 | + 'series.') |
1103 | else: |
1104 | raise UnexpectedFormData(branch_type) |
1105 | |
1106 | - def _createBzrBranch(self, branch_type, branch_name, |
1107 | - branch_owner, repo_url=None): |
1108 | - """Create a new Bazaar branch. It may be hosted or mirrored. |
1109 | + def _createBzrBranch(self, branch_name, branch_owner, repo_url=None): |
1110 | + """Create a new hosted Bazaar branch. |
1111 | |
1112 | Return the branch on success or None. |
1113 | """ |
1114 | branch = None |
1115 | try: |
1116 | namespace = self.target.getNamespace(branch_owner) |
1117 | - branch = namespace.createBranch(branch_type=branch_type, |
1118 | + branch = namespace.createBranch(branch_type=BranchType.HOSTED, |
1119 | name=branch_name, |
1120 | registrant=self.user, |
1121 | url=repo_url) |
1122 | - if branch_type == BranchType.MIRRORED: |
1123 | - branch.requestMirror() |
1124 | except BranchCreationForbidden: |
1125 | self.addError( |
1126 | "You are not allowed to create branches in %s." % |
1127 | |
1128 | === modified file 'lib/lp/registry/browser/tests/productseries-setbranch-view.txt' |
1129 | --- lib/lp/registry/browser/tests/productseries-setbranch-view.txt 2011-08-27 23:24:05 +0000 |
1130 | +++ lib/lp/registry/browser/tests/productseries-setbranch-view.txt 2011-10-04 14:34:53 +0000 |
1131 | @@ -95,7 +95,8 @@ |
1132 | ... 'field.branch_type': 'create-new', |
1133 | ... 'field.actions.update': 'Update', |
1134 | ... } |
1135 | - >>> view = create_initialized_view(series, name='+setbranch', principal=product.owner, form=form) |
1136 | + >>> view = create_initialized_view( |
1137 | + ... series, name='+setbranch', principal=product.owner, form=form) |
1138 | >>> for notification in view.request.response.notifications: |
1139 | ... print notification.message |
1140 | >>> for error in view.errors: |
1141 | @@ -112,7 +113,8 @@ |
1142 | ... 'field.actions.update': 'Update', |
1143 | ... } |
1144 | |
1145 | - >>> view = create_initialized_view(series, name='+setbranch', principal=product.owner, form=form) |
1146 | + >>> view = create_initialized_view( |
1147 | + ... series, name='+setbranch', principal=product.owner, form=form) |
1148 | >>> print view.errors_in_action |
1149 | False |
1150 | >>> print view.next_url |
1151 | @@ -134,7 +136,8 @@ |
1152 | ... 'field.actions.update': 'Update', |
1153 | ... } |
1154 | |
1155 | - >>> view = create_initialized_view(series, name='+setbranch', principal=product.owner, form=form) |
1156 | + >>> view = create_initialized_view( |
1157 | + ... series, name='+setbranch', principal=product.owner, form=form) |
1158 | >>> print view.errors_in_action |
1159 | True |
1160 | >>> print view.next_url |
1161 | @@ -161,7 +164,8 @@ |
1162 | ... 'field.branch_type': 'import-external', |
1163 | ... 'field.actions.update': 'Update', |
1164 | ... } |
1165 | - >>> view = create_initialized_view(series, name='+setbranch', principal=product.owner, form=form) |
1166 | + >>> view = create_initialized_view( |
1167 | + ... series, name='+setbranch', principal=product.owner, form=form) |
1168 | >>> for notification in view.request.response.notifications: |
1169 | ... print notification.message |
1170 | >>> for error in view.errors: |
1171 | @@ -181,13 +185,14 @@ |
1172 | ... 'field.repo_url': 'bzr+ssh://bzr.com/foo', |
1173 | ... 'field.actions.update': 'Update', |
1174 | ... } |
1175 | - >>> view = create_initialized_view(series, name='+setbranch', principal=product.owner, form=form) |
1176 | + >>> view = create_initialized_view( |
1177 | + ... series, name='+setbranch', principal=product.owner, form=form) |
1178 | >>> for notification in view.request.response.notifications: |
1179 | ... print notification.message |
1180 | >>> for error in view.errors: |
1181 | ... print error |
1182 | - ('repo_url'...The URI scheme "bzr+ssh" is not allowed. Only URIs with the following schemes may be |
1183 | - used: bzr, http, https')) |
1184 | + ('repo_url'...The URI scheme "bzr+ssh" is not allowed. Only URIs with |
1185 | + the following schemes may be used: bzr, http, https')) |
1186 | |
1187 | |
1188 | A correct URL is accepted. |
1189 | @@ -200,13 +205,14 @@ |
1190 | ... 'field.repo_url': 'http://bzr.com/foo', |
1191 | ... 'field.actions.update': 'Update', |
1192 | ... } |
1193 | - >>> view = create_initialized_view(series, name='+setbranch', principal=product.owner, form=form) |
1194 | + >>> view = create_initialized_view( |
1195 | + ... series, name='+setbranch', principal=product.owner, form=form) |
1196 | >>> transaction.commit() |
1197 | >>> for error in view.errors: |
1198 | ... print error |
1199 | >>> for notification in view.request.response.notifications: |
1200 | ... print notification.message |
1201 | - Mirrored branch created and linked to the series. |
1202 | + Code import created and branch linked to the series. |
1203 | >>> print series.branch.name |
1204 | blazer-branch |
1205 | |
1206 | @@ -220,7 +226,8 @@ |
1207 | ... 'field.repo_url': 'svn://svn.com/chevette', |
1208 | ... 'field.actions.update': 'Update', |
1209 | ... } |
1210 | - >>> view = create_initialized_view(series, name='+setbranch', principal=product.owner, form=form) |
1211 | + >>> view = create_initialized_view( |
1212 | + ... series, name='+setbranch', principal=product.owner, form=form) |
1213 | >>> for notification in view.request.response.notifications: |
1214 | ... print notification.message |
1215 | >>> for error in view.errors: |
1216 | @@ -240,7 +247,8 @@ |
1217 | ... 'field.repo_url': 'git://github.com/chevette', |
1218 | ... 'field.actions.update': 'Update', |
1219 | ... } |
1220 | - >>> view = create_initialized_view(series, name='+setbranch', principal=product.owner, form=form) |
1221 | + >>> view = create_initialized_view( |
1222 | + ... series, name='+setbranch', principal=product.owner, form=form) |
1223 | >>> transaction.commit() |
1224 | >>> for error in view.errors: |
1225 | ... print error |
1226 | @@ -260,7 +268,8 @@ |
1227 | ... 'field.repo_url': 'git://github.com/suburban', |
1228 | ... 'field.actions.update': 'Update', |
1229 | ... } |
1230 | - >>> view = create_initialized_view(series, name='+setbranch', principal=product.owner, form=form) |
1231 | + >>> view = create_initialized_view( |
1232 | + ... series, name='+setbranch', principal=product.owner, form=form) |
1233 | >>> for notification in view.request.response.notifications: |
1234 | ... print notification.message |
1235 | >>> for error in view.errors: |
1236 | @@ -280,7 +289,8 @@ |
1237 | ... 'field.repo_url': 'svn://svn.com/suburban', |
1238 | ... 'field.actions.update': 'Update', |
1239 | ... } |
1240 | - >>> view = create_initialized_view(series, name='+setbranch', principal=product.owner, form=form) |
1241 | + >>> view = create_initialized_view( |
1242 | + ... series, name='+setbranch', principal=product.owner, form=form) |
1243 | >>> for error in view.errors: |
1244 | ... print error |
1245 | >>> for notification in view.request.response.notifications: |
1246 | @@ -301,7 +311,8 @@ |
1247 | ... 'field.repo_url': 'https://mercurial.com/branch', |
1248 | ... 'field.actions.update': 'Update', |
1249 | ... } |
1250 | - >>> view = create_initialized_view(series, name='+setbranch', principal=product.owner, form=form) |
1251 | + >>> view = create_initialized_view( |
1252 | + ... series, name='+setbranch', principal=product.owner, form=form) |
1253 | >>> for error in view.errors: |
1254 | ... print error |
1255 | >>> for notification in view.request.response.notifications: |
1256 | @@ -367,8 +378,8 @@ |
1257 | ... print error |
1258 | <BLANKLINE> |
1259 | This foreign branch URL is already specified for |
1260 | - the imported branch <a href="http://code.launchpad.dev/~.../chevy/chevette-branch">~.../chevy/chevette-branch</a>. |
1261 | - |
1262 | + the imported branch |
1263 | + <a href="http://.../chevy/chevette-branch">~.../chevy/chevette-branch</a>. |
1264 | >>> for notification in view.request.response.notifications: |
1265 | ... print notification.message |
1266 | |
1267 | @@ -386,7 +397,8 @@ |
1268 | ... principal=product.owner, form=form) |
1269 | >>> for error in view.errors: |
1270 | ... print error |
1271 | - You already have a branch for <em>Chevy</em> called <em>chevette-branch</em>. |
1272 | + You already have a branch for |
1273 | + <em>Chevy</em> called <em>chevette-branch</em>. |
1274 | >>> print view.errors_in_action |
1275 | True |
1276 | >>> print view.next_url |
1277 | @@ -406,13 +418,16 @@ |
1278 | ... 'field.repo_url': 'http://bzr.com/foo', |
1279 | ... 'field.actions.update': 'Update', |
1280 | ... } |
1281 | - >>> view = create_initialized_view(series, name='+setbranch', principal=product.owner, form=form) |
1282 | + >>> view = create_initialized_view( |
1283 | + ... series, name='+setbranch', principal=product.owner, form=form) |
1284 | >>> for error in view.errors: |
1285 | ... print error |
1286 | - You already have a branch for <em>Chevy</em> called <em>blazer-branch</em>. |
1287 | + <BLANKLINE> |
1288 | + This foreign branch URL is already specified for the imported branch |
1289 | + <a href="http://.../blazer-branch">...</a>. |
1290 | >>> print view.errors_in_action |
1291 | - True |
1292 | + False |
1293 | >>> print view.next_url |
1294 | - None |
1295 | + http://launchpad.dev/chevy/corvair |
1296 | >>> for notification in view.request.response.notifications: |
1297 | ... print notification.message |
1298 | |
1299 | === modified file 'lib/lp/registry/templates/productseries-codesummary.pt' |
1300 | --- lib/lp/registry/templates/productseries-codesummary.pt 2011-05-16 20:55:08 +0000 |
1301 | +++ lib/lp/registry/templates/productseries-codesummary.pt 2011-10-04 14:34:53 +0000 |
1302 | @@ -54,7 +54,7 @@ |
1303 | </li> |
1304 | |
1305 | <li> |
1306 | - If the code is in Git, Mercurial, CVS or Subversion you can |
1307 | + If the code is in Git, Mercurial, CVS, Subversion or an external Bazaar branch you can |
1308 | <a tal:attributes="href view/request_import_link">request that the branch be imported to Bazaar</a>. |
1309 | </li> |
1310 | </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 :)