Merge lp:~jml/launchpad/free-code-imports into lp:launchpad
- free-code-imports
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Michael Hudson-Doyle |
Approved revision: | no longer in the source branch. |
Merged at revision: | not available |
Proposed branch: | lp:~jml/launchpad/free-code-imports |
Merge into: | lp:launchpad |
Diff against target: |
1017 lines (+432/-243) 13 files modified
lib/canonical/launchpad/security.py (+19/-3) lib/lp/code/browser/branch.py (+4/-2) lib/lp/code/doc/codeimport.txt (+30/-7) lib/lp/code/mail/codeimport.py (+3/-2) lib/lp/code/model/branch.py (+6/-2) lib/lp/code/model/codeimport.py (+2/-4) lib/lp/code/stories/codeimport/xx-admin-codeimport.txt (+277/-0) lib/lp/code/stories/codeimport/xx-codeimport-machines.txt (+7/-7) lib/lp/code/stories/codeimport/xx-create-codeimport.txt (+2/-2) lib/lp/code/stories/codeimport/xx-edit-codeimport.txt (+42/-208) lib/lp/code/stories/codeimport/xx-failing-codeimport.txt (+4/-3) lib/lp/code/tests/test_branch.py (+33/-1) lib/lp/testing/factory.py (+3/-2) |
To merge this branch: | bzr merge lp:~jml/launchpad/free-code-imports |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Hudson-Doyle | Approve | ||
Review via email: mp+12832@code.launchpad.net |
Commit message
New code imports will be owned by the person who registered them, rather than the vcs-imports special team.
Description of the change
Jonathan Lange (jml) wrote : | # |
Michael Hudson-Doyle (mwhudson) wrote : | # |
Hi, this is simple enough and a good idea. I think you'll need to run the page tests and at least look at the browser code for creating code imports before this can land though.
Jonathan Lange (jml) wrote : | # |
> Hi, this is simple enough and a good idea. I think you'll need to run the
> page tests and at least look at the browser code for creating code imports
> before this can land though.
For those following at home, here's what's happening.
I've changed my branch so that it passes _almost_ all the tests. The only one it doesn't pass is the "edit" page test. The reason is that the way that code import permissions work now is a little bit confusing.
I'll address these as soon as I have a spare moment.
Jonathan Lange (jml) wrote : | # |
> > Hi, this is simple enough and a good idea. I think you'll need to run the
> > page tests and at least look at the browser code for creating code imports
> > before this can land though.
>
> For those following at home, here's what's happening.
>
> I've changed my branch so that it passes _almost_ all the tests. The only one
> it doesn't pass is the "edit" page test. The reason is that the way that code
> import permissions work now is a little bit confusing.
>
> I'll address these as soon as I have a spare moment.
Addressed!
Now, if you register the code import, you are the owner of the branch, rather than vcs-imports. I've also tweaked things so that even if the branch is owned by vcs-imports, you can edit the branch.
We actually *don't* want to give people edit permissions on the CodeImport object itself, since we use 'launchpad.Edit' permissions to mean "you are allowed to administer code imports".
jml
Michael Hudson-Doyle (mwhudson) wrote : | # |
I have a couple of questions I'd like you to answer. The page tests are somewhat icky and you've added a little duplication. Remove that and I reckon you should land this.
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -177,6 +177,7 @@
> if proposal.id == id:
> return proposal
>
> +
> class BranchEditMenu(
> """Edit menu for IBranch."""
>
> @@ -206,10 +207,14 @@
> return Link(
> '+whiteboard', text, icon='edit', enabled=enabled)
>
> - @enabled_
> + # XXX: Rewrite the page test to be smarter about who is actually logged
> + # in, handling cases of branch owner and vcs-imports member separately.
This is fair enough but I don't see why the comment is here!
> def edit_import(self):
> text = 'Edit import source or review import'
> - enabled = self.branch_
> + enabled = (
> + self.branch_
> + check_permissio
> return Link(
> '+edit-import', text, icon='edit', enabled=enabled)
>
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -94,7 +94,7 @@
> Operator @vcs-imports
> >>> print message.
> A new code import has been requested by No Privileges Person:
> - http://
> + http://
> -- =
> You are getting this email because you are a member of the vcs-imports team.
>
> @@ -207,6 +207,24 @@
> ... nopriv)
> >>> print_emails(
> From: No Privileges Person <email address hidden>
> + To: <email address hidden>, ...
> + Subject: Code import product.../name... status: Reviewed
> + <BLANKLINE>
> + The import has been approved and an import will start shortly.
> + <BLANKLINE>
> + ... is now being imported from:
> + http://
> + instead of:
> + http://
> + <BLANKLINE>
> + -- =
> + <BLANKLINE>
> + http://
> + You are getting this email because you are a member of the vcs-imports
> + team.
> + <BLANKLINE>
> + -------
This is a bit bizarre. Oh, I think the rules for subscriptions to
code import branches are a bit unusual, maybe? I guess it would be
good to understand why this is happening before landing.
> + From: No Privileges Person <email address hidden>
> To: <email address hidden>
> Subject: Code import product.../name... status: Reviewed
> <BLANKLINE>
> @@ -218,10 +236,11 @@
> http://
> <BLANKLINE>
> -- =
> - http://
> + <BLANKLINE>
> + http://
Jonathan Lange (jml) wrote : | # |
I've fixed everything you've pointed out, but haven't done anything about the two open questions:
1. Why do I need to do the Unauthenticated
2. What's going on with email?
In answer to the first, I don't know why I had to make the change, other than that the tests made me do it. Perhaps Gary or Bjorn would know why.
As for the second, we should look into it at the sprint tomorrow.
Michael Hudson-Doyle (mwhudson) wrote : | # |
I answered my own questions in the end, I think the behaviour in this branch is better than trunk in fact.
Preview Diff
1 | === modified file 'lib/canonical/launchpad/security.py' |
2 | --- lib/canonical/launchpad/security.py 2009-10-20 13:21:44 +0000 |
3 | +++ lib/canonical/launchpad/security.py 2009-11-11 09:00:39 +0000 |
4 | @@ -1591,9 +1591,25 @@ |
5 | usedfor = IBranch |
6 | |
7 | def checkAuthenticated(self, user): |
8 | - return (user.inTeam(self.obj.owner) or |
9 | - user_has_special_branch_access(user) or |
10 | - can_upload_linked_package(user, self.obj)) |
11 | + can_edit = ( |
12 | + user.inTeam(self.obj.owner) or |
13 | + user_has_special_branch_access(user) or |
14 | + can_upload_linked_package(user, self.obj)) |
15 | + if can_edit: |
16 | + return True |
17 | + # It used to be the case that all import branches were owned by the |
18 | + # special, restricted team ~vcs-imports. For these legacy code import |
19 | + # branches, we still want the code import registrant to be able to |
20 | + # edit them. Similarly, we still want vcs-imports members to be able |
21 | + # to edit those branches. |
22 | + code_import = self.obj.code_import |
23 | + if code_import is None: |
24 | + return False |
25 | + vcs_imports = getUtility(ILaunchpadCelebrities).vcs_imports |
26 | + return ( |
27 | + user.inTeam(vcs_imports) |
28 | + or (self.obj.owner == vcs_imports |
29 | + and user.inTeam(code_import.registrant))) |
30 | |
31 | |
32 | def can_upload_linked_package(person, branch): |
33 | |
34 | === modified file 'lib/lp/code/browser/branch.py' |
35 | --- lib/lp/code/browser/branch.py 2009-10-29 16:54:10 +0000 |
36 | +++ lib/lp/code/browser/branch.py 2009-11-11 09:00:39 +0000 |
37 | @@ -177,6 +177,7 @@ |
38 | if proposal.id == id: |
39 | return proposal |
40 | |
41 | + |
42 | class BranchEditMenu(NavigationMenu): |
43 | """Edit menu for IBranch.""" |
44 | |
45 | @@ -206,10 +207,11 @@ |
46 | return Link( |
47 | '+whiteboard', text, icon='edit', enabled=enabled) |
48 | |
49 | - @enabled_with_permission('launchpad.Edit') |
50 | def edit_import(self): |
51 | text = 'Edit import source or review import' |
52 | - enabled = self.branch_is_import() |
53 | + enabled = ( |
54 | + self.branch_is_import() and |
55 | + check_permission('launchpad.Edit', self.context.code_import)) |
56 | return Link( |
57 | '+edit-import', text, icon='edit', enabled=enabled) |
58 | |
59 | |
60 | === modified file 'lib/lp/code/doc/codeimport.txt' |
61 | --- lib/lp/code/doc/codeimport.txt 2009-07-01 13:16:44 +0000 |
62 | +++ lib/lp/code/doc/codeimport.txt 2009-11-11 09:00:39 +0000 |
63 | @@ -94,7 +94,7 @@ |
64 | Operator @vcs-imports |
65 | >>> print message.get_payload() |
66 | A new code import has been requested by No Privileges Person: |
67 | - http://code.launchpad.dev/~vcs-imports/firefox/trunk-cvs |
68 | + http://code.launchpad.dev/~no-priv/firefox/trunk-cvs |
69 | -- = |
70 | You are getting this email because you are a member of the vcs-imports team. |
71 | |
72 | @@ -207,6 +207,24 @@ |
73 | ... nopriv) |
74 | >>> print_emails(group_similar=True) |
75 | From: No Privileges Person <no-priv@canonical.com> |
76 | + To: david.allouche@canonical.com, ... |
77 | + Subject: Code import product.../name... status: Reviewed |
78 | + <BLANKLINE> |
79 | + The import has been approved and an import will start shortly. |
80 | + <BLANKLINE> |
81 | + ... is now being imported from: |
82 | + http://svn.example.com/project/trunk |
83 | + instead of: |
84 | + http://svn.example.com/project |
85 | + <BLANKLINE> |
86 | + -- = |
87 | + <BLANKLINE> |
88 | + http://code.launchpad.dev/~person.../product.../name... |
89 | + You are getting this email because you are a member of the vcs-imports |
90 | + team. |
91 | + <BLANKLINE> |
92 | + ---------------------------------------- |
93 | + From: No Privileges Person <no-priv@canonical.com> |
94 | To: no-priv@canonical.com |
95 | Subject: Code import product.../name... status: Reviewed |
96 | <BLANKLINE> |
97 | @@ -218,10 +236,11 @@ |
98 | http://svn.example.com/project |
99 | <BLANKLINE> |
100 | -- = |
101 | - http://code.launchpad.dev/~vcs-imports/product.../name... |
102 | + <BLANKLINE> |
103 | + http://code.launchpad.dev/~person.../product.../name... |
104 | You are receiving this email as you are subscribed to the branch. |
105 | - To unsubscribe from this branch go to http://code.launchpad.dev/~vcs-import= |
106 | - s/product.../name.../+edit-subscription. |
107 | + To unsubscribe from this branch go to .../+edit-subscription. |
108 | + <BLANKLINE> |
109 | ---------------------------------------- |
110 | |
111 | updateFromData is smart enough to not send an email if no changes were |
112 | @@ -239,6 +258,10 @@ |
113 | ... None) |
114 | >>> print_emails(group_similar=True) |
115 | From: noreply@launchpad.net |
116 | + To: david.allouche@canonical.com, ... |
117 | + Subject: Code import product.../name... status: Reviewed |
118 | + ... |
119 | + From: noreply@launchpad.net |
120 | To: no-priv@canonical.com |
121 | Subject: Code import product.../name... status: Reviewed |
122 | ... |
123 | @@ -351,7 +374,7 @@ |
124 | and are not traversable in themselves. |
125 | |
126 | >>> print canonical_url(svn_import.branch) |
127 | - http://code.launchpad.dev/~vcs-imports/firefox/trunk-svn |
128 | + http://code.launchpad.dev/~no-priv/firefox/trunk-svn |
129 | >>> print canonical_url(svn_import) |
130 | Traceback (most recent call last): |
131 | NoCanonicalUrl: ... |
132 | @@ -410,7 +433,7 @@ |
133 | >>> modify_event = cvs_import.updateFromData(data, nopriv) |
134 | >>> print make_email_body_for_code_import_update( |
135 | ... cvs_import, modify_event, None) |
136 | - ~vcs-imports/firefox/trunk-cvs is now being imported from: |
137 | + ~no-priv/firefox/trunk-cvs is now being imported from: |
138 | hello from :pserver:anoncvs@cvs.example.com:/var/cvsroot |
139 | instead of: |
140 | hello from :pserver:anonymous@cvs.example.com:/cvsroot |
141 | @@ -421,7 +444,7 @@ |
142 | >>> modify_event = git_import.updateFromData(data, nopriv) |
143 | >>> print make_email_body_for_code_import_update( |
144 | ... git_import, modify_event, None) |
145 | - ~vcs-imports/firefox/trunk-git is now being imported from: |
146 | + ~no-priv/firefox/trunk-git is now being imported from: |
147 | git://git.example.com/goodbye.git |
148 | instead of: |
149 | git://git.example.com/hello.git |
150 | |
151 | === modified file 'lib/lp/code/mail/codeimport.py' |
152 | --- lib/lp/code/mail/codeimport.py 2009-07-17 00:26:05 +0000 |
153 | +++ lib/lp/code/mail/codeimport.py 2009-11-11 09:00:39 +0000 |
154 | @@ -8,6 +8,7 @@ |
155 | import textwrap |
156 | |
157 | from zope.component import getUtility |
158 | +from zope.app.security.interfaces import IUnauthenticatedPrincipal |
159 | |
160 | from canonical.config import config |
161 | from canonical.launchpad.helpers import ( |
162 | @@ -23,11 +24,11 @@ |
163 | |
164 | def new_import(code_import, event): |
165 | """Email the vcs-imports team about a new code import.""" |
166 | - if event.user is None: |
167 | + if (event.user is None |
168 | + or IUnauthenticatedPrincipal.providedBy(event.user)): |
169 | # If there is no logged in user, then we are most likely in a |
170 | # test. |
171 | return |
172 | - |
173 | user = IPerson(event.user) |
174 | subject = 'New code import: %s/%s' % ( |
175 | code_import.product.name, code_import.branch.name) |
176 | |
177 | === modified file 'lib/lp/code/model/branch.py' |
178 | --- lib/lp/code/model/branch.py 2009-10-30 22:56:45 +0000 |
179 | +++ lib/lp/code/model/branch.py 2009-11-11 09:00:39 +0000 |
180 | @@ -591,8 +591,6 @@ |
181 | series_set = getUtility(IFindOfficialBranchLinks) |
182 | alteration_operations.extend( |
183 | map(ClearOfficialPackageBranch, series_set.findForBranch(self))) |
184 | - if self.code_import is not None: |
185 | - deletion_operations.append(DeleteCodeImport(self.code_import)) |
186 | return (alteration_operations, deletion_operations) |
187 | |
188 | def deletionRequirements(self): |
189 | @@ -623,6 +621,12 @@ |
190 | operation() |
191 | for operation in deletion_operations: |
192 | operation() |
193 | + # Special-case code import, since users don't have lp.Edit on them, |
194 | + # since if you can delete a branch you should be able to delete the |
195 | + # code import and since deleting the code import object itself isn't |
196 | + # actually a very interesting thing to tell the user about. |
197 | + if self.code_import is not None: |
198 | + DeleteCodeImport(self.code_import)() |
199 | |
200 | def associatedProductSeries(self): |
201 | """See `IBranch`.""" |
202 | |
203 | === modified file 'lib/lp/code/model/codeimport.py' |
204 | --- lib/lp/code/model/codeimport.py 2009-08-31 09:52:42 +0000 |
205 | +++ lib/lp/code/model/codeimport.py 2009-11-11 09:00:39 +0000 |
206 | @@ -33,7 +33,6 @@ |
207 | from canonical.database.sqlbase import SQLBase, quote, sqlvalues |
208 | from lp.code.model.codeimportjob import CodeImportJobWorkflow |
209 | from lp.registry.model.productseries import ProductSeries |
210 | -from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities |
211 | from canonical.launchpad.webapp.interfaces import NotFoundError |
212 | from lp.code.enums import ( |
213 | BranchType, CodeImportResultStatus, CodeImportReviewStatus, |
214 | @@ -238,11 +237,10 @@ |
215 | else: |
216 | review_status = CodeImportReviewStatus.NEW |
217 | # Create the branch for the CodeImport. |
218 | - vcs_imports = getUtility(ILaunchpadCelebrities).vcs_imports |
219 | - namespace = get_branch_namespace(vcs_imports, product) |
220 | + namespace = get_branch_namespace(registrant, product) |
221 | import_branch = namespace.createBranch( |
222 | branch_type=BranchType.IMPORTED, name=branch_name, |
223 | - registrant=vcs_imports) |
224 | + registrant=registrant) |
225 | |
226 | code_import = CodeImport( |
227 | registrant=registrant, owner=registrant, branch=import_branch, |
228 | |
229 | === added file 'lib/lp/code/stories/codeimport/xx-admin-codeimport.txt' |
230 | --- lib/lp/code/stories/codeimport/xx-admin-codeimport.txt 1970-01-01 00:00:00 +0000 |
231 | +++ lib/lp/code/stories/codeimport/xx-admin-codeimport.txt 2009-11-11 09:00:39 +0000 |
232 | @@ -0,0 +1,277 @@ |
233 | += Administrating code imports = |
234 | + |
235 | +The code import details are displayed on the main branch page for |
236 | +imported branches. If the logged in user is an import operator |
237 | +(member of VCS imports or Launchpad admin) then they can see a link |
238 | +to edit the details. |
239 | + |
240 | + >>> from canonical.launchpad.ftests import ANONYMOUS, login, logout |
241 | + >>> login('test@canonical.com') |
242 | + |
243 | + >>> svn_import = factory.makeCodeImport( |
244 | + ... svn_branch_url='svn://svn.example.com/fooix/trunk') |
245 | + >>> from canonical.launchpad.webapp import canonical_url |
246 | + >>> svn_import_location = str(canonical_url(svn_import.branch)) |
247 | + >>> svn_import_branch_unique_name = svn_import.branch.unique_name |
248 | + |
249 | + >>> cvs_import = factory.makeCodeImport( |
250 | + ... cvs_root=":pserver:anonymous@cvs.example.com:/fooix", |
251 | + ... cvs_module="fooix") |
252 | + >>> cvs_import_location = str(canonical_url(cvs_import.branch)) |
253 | + >>> cvs_import_branch_unique_name = cvs_import.branch.unique_name |
254 | + |
255 | + >>> git_import = factory.makeCodeImport( |
256 | + ... git_repo_url="git://git.example.org/fooix") |
257 | + >>> git_import_location = str(canonical_url(git_import.branch)) |
258 | + >>> git_import_branch_unique_name = git_import.branch.unique_name |
259 | + |
260 | + >>> import_browser = setupBrowser( |
261 | + ... auth='Basic david.allouche@canonical.com:test') |
262 | + |
263 | + |
264 | +== Editing the import == |
265 | + |
266 | +Both VCS Imports members and Launchpad administrators can edit the |
267 | +import: |
268 | + |
269 | + >>> import_browser.open(svn_import_location) |
270 | + >>> print_import_details(import_browser) |
271 | + Import Status: Pending Review |
272 | + This branch is an import of the Subversion branch |
273 | + from svn://svn.example.com/fooix/trunk. |
274 | + |
275 | + |
276 | +== Editing details == |
277 | + |
278 | +There are a number of buttons shown on the editing page for |
279 | +import operators. |
280 | + |
281 | + >>> import_browser.getLink('Edit import source or review import').click() |
282 | + >>> print_submit_buttons(import_browser.contents) |
283 | + Update |
284 | + Approve |
285 | + Mark Invalid |
286 | + Suspend |
287 | + Mark Failing |
288 | + |
289 | +A cancel link is also shown next to the buttons, that takes the user |
290 | +back to the main branch details page. |
291 | + |
292 | + >>> import_browser.getLink('Cancel').url == svn_import_location |
293 | + True |
294 | + |
295 | +Only the fields that are relevant to the type of import are shown |
296 | +in the form. |
297 | + |
298 | + >>> def print_form_fields(browser): |
299 | + ... tags = find_tags_by_class(browser.contents, 'textType') |
300 | + ... for tag in tags: |
301 | + ... print '%s: %s' % (tag['name'], tag['value']) |
302 | + |
303 | + >>> print_form_fields(import_browser) |
304 | + field.svn_branch_url: svn://svn.example.com/fooix/trunk |
305 | + |
306 | + >>> import_browser.open(cvs_import_location) |
307 | + >>> import_browser.getLink('Edit import source or review import').click() |
308 | + >>> print_form_fields(import_browser) |
309 | + field.cvs_root: :pserver:anonymous@cvs.example.com:/fooix |
310 | + field.cvs_module: fooix |
311 | + |
312 | + >>> import_browser.open(git_import_location) |
313 | + >>> import_browser.getLink('Edit import source or review import').click() |
314 | + >>> print_form_fields(import_browser) |
315 | + field.git_repo_url: git://git.example.org/fooix |
316 | + |
317 | +=== Editing the import location === |
318 | + |
319 | +The +edit-import page allows the import operator to edit the location |
320 | +an import is from. |
321 | + |
322 | +This is true for Subversion imports, |
323 | + |
324 | + >>> import_browser.open(svn_import_location + '/+edit-import') |
325 | + >>> import_browser.getControl('Branch URL').value = \ |
326 | + ... 'svn://svn-new.example.com/fooix/trunk' |
327 | + >>> import_browser.getControl('Update').click() |
328 | + >>> for message in get_feedback_messages(import_browser.contents): |
329 | + ... print extract_text(message) |
330 | + The code import has been updated. |
331 | + |
332 | +CVS imports, |
333 | + |
334 | + >>> import_browser.open(cvs_import_location + '/+edit-import') |
335 | + >>> import_browser.getControl('Repository').value = \ |
336 | + ... ':pserver:anonymous@cvs-new.example.com:/fooix' |
337 | + >>> import_browser.getControl('Module').value = \ |
338 | + ... 'fooix2' |
339 | + >>> import_browser.getControl('Update').click() |
340 | + >>> for message in get_feedback_messages(import_browser.contents): |
341 | + ... print extract_text(message) |
342 | + The code import has been updated. |
343 | + |
344 | +and Git imports. |
345 | + |
346 | + >>> import_browser.open(git_import_location + '/+edit-import') |
347 | + >>> import_browser.getControl('Repo URL').value = \ |
348 | + ... 'git://git-new.example.org/fooix' |
349 | + >>> import_browser.getControl('Update').click() |
350 | + >>> for message in get_feedback_messages(import_browser.contents): |
351 | + ... print extract_text(message) |
352 | + The code import has been updated. |
353 | + |
354 | + |
355 | +=== Approving an import === |
356 | + |
357 | +When a code import is approved, a pending job is created for it. |
358 | + |
359 | + >>> import_browser.open(svn_import_location + '/+edit-import') |
360 | + >>> import_browser.getControl('Approve').click() |
361 | + >>> print_import_details(import_browser) |
362 | + Import Status: Reviewed |
363 | + ... |
364 | + The next import is scheduled to run as soon as possible. |
365 | + |
366 | + >>> for message in get_feedback_messages(import_browser.contents): |
367 | + ... print extract_text(message) |
368 | + The code import has been approved. |
369 | + |
370 | + |
371 | +=== Invalidating an import === |
372 | + |
373 | + >>> import_browser.getLink('Edit import source or review import').click() |
374 | + >>> import_browser.getControl('Mark Invalid').click() |
375 | + >>> print_import_details(import_browser) |
376 | + Import Status: Invalid |
377 | + ... |
378 | + >>> for message in get_feedback_messages(import_browser.contents): |
379 | + ... print extract_text(message) |
380 | + The code import has been set as invalid. |
381 | + |
382 | + |
383 | +=== Suspending an import === |
384 | + |
385 | + >>> import_browser.getLink('Edit import source or review import').click() |
386 | + >>> import_browser.getControl('Suspend').click() |
387 | + >>> print_import_details(import_browser) |
388 | + Import Status: Suspended |
389 | + ... |
390 | + >>> for message in get_feedback_messages(import_browser.contents): |
391 | + ... print extract_text(message) |
392 | + The code import has been suspended. |
393 | + |
394 | + |
395 | +=== Marking an import as failing === |
396 | + |
397 | + >>> import_browser.getLink('Edit import source or review import').click() |
398 | + >>> import_browser.getControl('Mark Failing').click() |
399 | + >>> print_import_details(import_browser) |
400 | + Import Status: Failed |
401 | + ... |
402 | + >>> for message in get_feedback_messages(import_browser.contents): |
403 | + ... print extract_text(message) |
404 | + The code import has been marked as failing. |
405 | + |
406 | + |
407 | +== Import details for a running job == |
408 | + |
409 | +If the job for an approved import is running, then the import details |
410 | +says how long ago since it started. |
411 | + |
412 | + >>> import_browser.getLink('Edit import source or review import').click() |
413 | + >>> import_browser.getControl('Approve').click() |
414 | + >>> print_import_details(import_browser) |
415 | + Import Status: Reviewed |
416 | + ... |
417 | + The next import is scheduled to run as soon as possible. |
418 | + |
419 | +Now set the job as running. |
420 | + |
421 | + >>> login('david.allouche@canonical.com') |
422 | + >>> from canonical.launchpad.testing.codeimporthelpers import ( |
423 | + ... get_import_for_branch_name, make_running_import) |
424 | + >>> code_import = get_import_for_branch_name( |
425 | + ... svn_import_branch_unique_name) |
426 | + |
427 | +Set the started time to 2h 20m ago, and the approximate datetime |
428 | +should show this as 2 hours. |
429 | + |
430 | + >>> from datetime import datetime, timedelta |
431 | + >>> import pytz |
432 | + >>> date_started = datetime.now(pytz.UTC) - timedelta(hours=2, minutes=20) |
433 | + >>> code_import = make_running_import( |
434 | + ... code_import, date_started=date_started, factory=factory, |
435 | + ... logtail="Changeset 1\nChangeset 2") |
436 | + >>> logout() |
437 | + |
438 | + >>> import_browser.open(svn_import_location) |
439 | + >>> print_import_details(import_browser) |
440 | + Import Status: Reviewed |
441 | + ... |
442 | + An import is currently running on machine-..., and was started 2 hours |
443 | + ago. The last few lines of the job's output were: |
444 | + Changeset 1 |
445 | + Changeset 2 |
446 | + |
447 | + |
448 | +== Import details for a import that has been imported successfully == |
449 | + |
450 | +If a branch has been successfully imported in the past, then the date |
451 | +that it was last successful is shown, as well as when the next import |
452 | +will be run -- which is, by default for Subversion, six hours after the |
453 | +last import completed, and so in this case in about three hours. |
454 | + |
455 | + >>> login('david.allouche@canonical.com') |
456 | + >>> from canonical.launchpad.testing.codeimporthelpers import ( |
457 | + ... make_finished_import) |
458 | + >>> date_finished = datetime(2007,9,10,12, tzinfo=pytz.UTC) |
459 | + >>> code_import = get_import_for_branch_name( |
460 | + ... svn_import_branch_unique_name) |
461 | + >>> code_import = make_finished_import(code_import, factory=factory, |
462 | + ... date_finished=date_finished) |
463 | + >>> logout() |
464 | + |
465 | + >>> import_browser.open(svn_import_location) |
466 | + >>> print_import_details(import_browser) |
467 | + Import Status: Reviewed |
468 | + This branch is an import of the Subversion branch from |
469 | + svn://svn-new.example.com/fooix/trunk. |
470 | + The next import is scheduled to run in 3 hours. |
471 | + Last successful import was on 2007-09-10. |
472 | + ... |
473 | + |
474 | + |
475 | +== Requesting an import == |
476 | + |
477 | +If an import is waiting for its next update, any logged in user can |
478 | +click a button to request an immediate import. |
479 | + |
480 | + >>> sample_person_browser = setupBrowser( |
481 | + ... auth='Basic test@canonical.com:test') |
482 | + >>> sample_person_browser.open(import_browser.url) |
483 | + >>> sample_person_browser.getControl('Import Now') |
484 | + <SubmitControl ...> |
485 | + |
486 | +Anonymous users cannot see this button. |
487 | + |
488 | + >>> anon_browser.open(import_browser.url) |
489 | + >>> anon_browser.getControl('Import Now') |
490 | + Traceback (most recent call last): |
491 | + ... |
492 | + LookupError: label 'Import Now' |
493 | + |
494 | +If the logged in user clicks this button, the import will be scheduled |
495 | +to run ASAP and the fact that the import has been requested is |
496 | +displayed. |
497 | + |
498 | + >>> sample_person_browser.getControl('Import Now').click() |
499 | + >>> for msg in get_feedback_messages(sample_person_browser.contents): |
500 | + ... print msg |
501 | + Import will run as soon as possible. |
502 | + >>> print_import_details(sample_person_browser) |
503 | + Import Status: Reviewed |
504 | + This branch is an import of the Subversion branch from |
505 | + svn://svn-new.example.com/fooix/trunk. |
506 | + The next import is scheduled to run as soon as possible (requested |
507 | + by Sample Person). |
508 | + Last successful import was on 2007-09-10. |
509 | + ... |
510 | |
511 | === modified file 'lib/lp/code/stories/codeimport/xx-codeimport-machines.txt' |
512 | --- lib/lp/code/stories/codeimport/xx-codeimport-machines.txt 2009-06-02 08:20:49 +0000 |
513 | +++ lib/lp/code/stories/codeimport/xx-codeimport-machines.txt 2009-11-11 09:00:39 +0000 |
514 | @@ -50,13 +50,13 @@ |
515 | >>> print_table(browser) |
516 | Machine Status |
517 | apollo (2 jobs running) Online |
518 | - lp://dev/~vcs-imports/.../... |
519 | + lp://dev/~.../.../... |
520 | Started: ... ago Last heartbeat: ... ago |
521 | - lp://dev/~vcs-imports/.../... |
522 | + lp://dev/~.../.../... |
523 | Started: ... ago Last heartbeat: ... ago |
524 | bazaar-importer (0 jobs running) Online |
525 | odin (1 job running) Online |
526 | - lp://dev/~vcs-imports/.../... |
527 | + lp://dev/~.../.../... |
528 | Started: ... ago Last heartbeat: ... ago |
529 | saturn Offline |
530 | |
531 | @@ -79,10 +79,10 @@ |
532 | |
533 | >>> print extract_text(find_tag_by_id(browser.contents, 'current-jobs')) |
534 | Current jobs |
535 | - lp://dev/~vcs-imports/.../... Started: ... ago Last heartbeat: ... ago |
536 | + lp://dev/~.../.../... Started: ... ago Last heartbeat: ... ago |
537 | Creating changeset 1 |
538 | Creating changeset 2 |
539 | - lp://dev/~vcs-imports/.../... Started: ... ago Last heartbeat: ... ago |
540 | + lp://dev/~.../.../... Started: ... ago Last heartbeat: ... ago |
541 | |
542 | And also shows the most recent ten events for the machine, with the most |
543 | recent event first. |
544 | @@ -92,8 +92,8 @@ |
545 | ... print extract_text(recent_events) |
546 | >>> print_events(browser) |
547 | Related events |
548 | - ...: Job Started lp://dev/~vcs-imports/.../... |
549 | - ...: Job Started lp://dev/~vcs-imports/.../... |
550 | + ...: Job Started lp://dev/~.../.../... |
551 | + ...: Job Started lp://dev/~.../.../... |
552 | ...: Machine Online |
553 | |
554 | |
555 | |
556 | === modified file 'lib/lp/code/stories/codeimport/xx-create-codeimport.txt' |
557 | --- lib/lp/code/stories/codeimport/xx-create-codeimport.txt 2009-10-19 17:31:15 +0000 |
558 | +++ lib/lp/code/stories/codeimport/xx-create-codeimport.txt 2009-11-11 09:00:39 +0000 |
559 | @@ -149,7 +149,7 @@ |
560 | ... print extract_text(message) |
561 | There is 1 error. |
562 | Those CVS details are already specified for |
563 | - the imported branch ~vcs-imports/firefox/import2. |
564 | + the imported branch ~no-priv/firefox/import2. |
565 | |
566 | >>> browser.getControl('Subversion').click() |
567 | >>> browser.getControl('Branch URL').value = ( |
568 | @@ -160,7 +160,7 @@ |
569 | ... print extract_text(message) |
570 | There is 1 error. |
571 | This Subversion branch URL is already specified for |
572 | - the imported branch ~vcs-imports/firefox/imported. |
573 | + the imported branch ~no-priv/firefox/imported. |
574 | |
575 | |
576 | Requesting an import whose name would clash |
577 | |
578 | === modified file 'lib/lp/code/stories/codeimport/xx-edit-codeimport.txt' |
579 | --- lib/lp/code/stories/codeimport/xx-edit-codeimport.txt 2009-09-18 05:49:48 +0000 |
580 | +++ lib/lp/code/stories/codeimport/xx-edit-codeimport.txt 2009-11-11 09:00:39 +0000 |
581 | @@ -1,32 +1,29 @@ |
582 | = Editing code import details = |
583 | |
584 | -The code import details are displayed on the main branch page for |
585 | -imported branches. If the logged in user is an import operator |
586 | -(member of VCS imports or Launchpad admin) then they can see a link |
587 | -to edit the details. |
588 | +Not everyone can edit code import details, these stories show what it's like |
589 | +to edit a code import if you are the owner of the code import branch. |
590 | + |
591 | +The code import details are displayed on the main branch page for imported |
592 | +branches. If the logged-in user is allowed to edit the code import then they |
593 | +can see a link to edit the details. |
594 | |
595 | >>> from canonical.launchpad.ftests import ANONYMOUS, login, logout |
596 | - >>> login('test@canonical.com') |
597 | + >>> from canonical.launchpad.webapp import canonical_url |
598 | + |
599 | + >>> login(ANONYMOUS) |
600 | + >>> registrant = factory.makePerson(password='test') |
601 | >>> svn_import = factory.makeCodeImport( |
602 | - ... svn_branch_url='svn://svn.example.com/fooix/trunk') |
603 | - >>> from canonical.launchpad.webapp import canonical_url |
604 | + ... svn_branch_url='svn://svn.example.com/fooix/trunk', |
605 | + ... registrant=registrant) |
606 | >>> svn_import_location = str(canonical_url(svn_import.branch)) |
607 | >>> svn_import_branch_unique_name = svn_import.branch.unique_name |
608 | - >>> cvs_import = factory.makeCodeImport( |
609 | - ... cvs_root=":pserver:anonymous@cvs.example.com:/fooix", |
610 | - ... cvs_module="fooix") |
611 | - >>> cvs_import_location = str(canonical_url(cvs_import.branch)) |
612 | - >>> cvs_import_branch_unique_name = cvs_import.branch.unique_name |
613 | - >>> git_import = factory.makeCodeImport( |
614 | - ... git_repo_url="git://git.example.org/fooix") |
615 | - >>> git_import_location = str(canonical_url(git_import.branch)) |
616 | - >>> git_import_branch_unique_name = git_import.branch.unique_name |
617 | + |
618 | >>> hosted_branch = factory.makeAnyBranch() |
619 | >>> hosted_branch_location = str(canonical_url(hosted_branch)) |
620 | >>> logout() |
621 | |
622 | >>> import_browser = setupBrowser( |
623 | - ... auth='Basic david.allouche@canonical.com:test') |
624 | + ... auth='Basic %s:test' % str(registrant.preferredemail.email)) |
625 | |
626 | |
627 | == Import details on the branch page == |
628 | @@ -42,34 +39,19 @@ |
629 | ... div = find_tag_by_id( |
630 | ... browser.contents, 'branch-import-details').div.div |
631 | ... print extract_text(div) |
632 | - >>> browser.open(svn_import_location) |
633 | - >>> print_import_details(browser) |
634 | + >>> anon_browser.open(svn_import_location) |
635 | + >>> print_import_details(anon_browser) |
636 | Import Status: Pending Review |
637 | This branch is an import of the Subversion branch |
638 | from svn://svn.example.com/fooix/trunk. |
639 | |
640 | Because it's an svn:// URL, it doesn't get linkified: |
641 | |
642 | - >>> browser.getLink("svn://svn.example.com/fooix/trunk") |
643 | + >>> anon_browser.getLink("svn://svn.example.com/fooix/trunk") |
644 | Traceback (most recent call last): |
645 | ... |
646 | LinkNotFoundError |
647 | |
648 | -Both VCS Imports members and Launchpad administrators can edit the |
649 | -import, though: |
650 | - |
651 | - >>> import_browser.open(svn_import_location) |
652 | - >>> print_import_details(import_browser) |
653 | - Import Status: Pending Review |
654 | - This branch is an import of the Subversion branch |
655 | - from svn://svn.example.com/fooix/trunk. |
656 | - |
657 | - >>> admin_browser.open(svn_import_location) |
658 | - >>> print_import_details(admin_browser) |
659 | - Import Status: Pending Review |
660 | - This branch is an import of the Subversion branch |
661 | - from svn://svn.example.com/fooix/trunk. |
662 | - |
663 | |
664 | == Not authorized versus 404 == |
665 | |
666 | @@ -77,7 +59,7 @@ |
667 | they will get a not authorised page if the branch has a code import, |
668 | and a 404 if the branch doesn't have an import. |
669 | |
670 | - >>> browser.open(svn_import_location + '/+edit-import') |
671 | + >>> anon_browser.open(svn_import_location + '/+edit-import') |
672 | Traceback (most recent call last): |
673 | Unauthorized: (... 'launchpad.Edit') |
674 | |
675 | @@ -88,174 +70,10 @@ |
676 | |
677 | == Editing details == |
678 | |
679 | -There are a number of buttons shown on the editing page for |
680 | -import operators. |
681 | - |
682 | - >>> import_browser.getLink('Edit import source or review import').click() |
683 | - >>> print_submit_buttons(import_browser.contents) |
684 | - Update |
685 | - Approve |
686 | - Mark Invalid |
687 | - Suspend |
688 | - Mark Failing |
689 | - |
690 | -A cancel link is also shown next to the buttons, that takes the user |
691 | -back to the main branch details page. |
692 | - |
693 | - >>> import_browser.getLink('Cancel').url == svn_import_location |
694 | - True |
695 | - |
696 | -Only the fields that are relevant to the type of import are shown |
697 | -in the form. |
698 | - |
699 | - >>> def print_form_fields(browser): |
700 | - ... tags = find_tags_by_class(browser.contents, 'textType') |
701 | - ... for tag in tags: |
702 | - ... print '%s: %s' % (tag['name'], tag['value']) |
703 | - |
704 | - >>> print_form_fields(import_browser) |
705 | - field.svn_branch_url: svn://svn.example.com/fooix/trunk |
706 | - |
707 | - >>> admin_browser.open(cvs_import_location) |
708 | - >>> admin_browser.getLink('Edit import source or review import').click() |
709 | - >>> print_form_fields(admin_browser) |
710 | - field.cvs_root: :pserver:anonymous@cvs.example.com:/fooix |
711 | - field.cvs_module: fooix |
712 | - |
713 | - >>> admin_browser.open(git_import_location) |
714 | - >>> admin_browser.getLink('Edit import source or review import').click() |
715 | - >>> print_form_fields(admin_browser) |
716 | - field.git_repo_url: git://git.example.org/fooix |
717 | - |
718 | -=== Editing the import location === |
719 | - |
720 | -The +edit-import page allows the import operator to edit the location |
721 | -an import is from. |
722 | - |
723 | -This is true for Subversion imports, |
724 | - |
725 | - >>> import_browser.open(svn_import_location + '/+edit-import') |
726 | - >>> import_browser.getControl('Branch URL').value = \ |
727 | - ... 'svn://svn-new.example.com/fooix/trunk' |
728 | - >>> import_browser.getControl('Update').click() |
729 | - >>> for message in get_feedback_messages(import_browser.contents): |
730 | - ... print extract_text(message) |
731 | - The code import has been updated. |
732 | - |
733 | -CVS imports, |
734 | - |
735 | - >>> import_browser.open(cvs_import_location + '/+edit-import') |
736 | - >>> import_browser.getControl('Repository').value = \ |
737 | - ... ':pserver:anonymous@cvs-new.example.com:/fooix' |
738 | - >>> import_browser.getControl('Module').value = \ |
739 | - ... 'fooix2' |
740 | - >>> import_browser.getControl('Update').click() |
741 | - >>> for message in get_feedback_messages(import_browser.contents): |
742 | - ... print extract_text(message) |
743 | - The code import has been updated. |
744 | - |
745 | -and Git imports. |
746 | - |
747 | - >>> import_browser.open(git_import_location + '/+edit-import') |
748 | - >>> import_browser.getControl('Repo URL').value = \ |
749 | - ... 'git://git-new.example.org/fooix' |
750 | - >>> import_browser.getControl('Update').click() |
751 | - >>> for message in get_feedback_messages(import_browser.contents): |
752 | - ... print extract_text(message) |
753 | - The code import has been updated. |
754 | - |
755 | - |
756 | -=== Approving an import === |
757 | - |
758 | -When a code import is approved, a pending job is created for it. |
759 | - |
760 | - >>> import_browser.open(svn_import_location + '/+edit-import') |
761 | - >>> import_browser.getControl('Approve').click() |
762 | - >>> print_import_details(import_browser) |
763 | - Import Status: Reviewed |
764 | - ... |
765 | - The next import is scheduled to run as soon as possible. |
766 | - |
767 | - >>> for message in get_feedback_messages(import_browser.contents): |
768 | - ... print extract_text(message) |
769 | - The code import has been approved. |
770 | - |
771 | - |
772 | -=== Invalidating an import === |
773 | - |
774 | - >>> import_browser.getLink('Edit import source or review import').click() |
775 | - >>> import_browser.getControl('Mark Invalid').click() |
776 | - >>> print_import_details(import_browser) |
777 | - Import Status: Invalid |
778 | - ... |
779 | - >>> for message in get_feedback_messages(import_browser.contents): |
780 | - ... print extract_text(message) |
781 | - The code import has been set as invalid. |
782 | - |
783 | - |
784 | -=== Suspending an import === |
785 | - |
786 | - >>> import_browser.getLink('Edit import source or review import').click() |
787 | - >>> import_browser.getControl('Suspend').click() |
788 | - >>> print_import_details(import_browser) |
789 | - Import Status: Suspended |
790 | - ... |
791 | - >>> for message in get_feedback_messages(import_browser.contents): |
792 | - ... print extract_text(message) |
793 | - The code import has been suspended. |
794 | - |
795 | - |
796 | -=== Marking an import as failing === |
797 | - |
798 | - >>> import_browser.getLink('Edit import source or review import').click() |
799 | - >>> import_browser.getControl('Mark Failing').click() |
800 | - >>> print_import_details(import_browser) |
801 | - Import Status: Failed |
802 | - ... |
803 | - >>> for message in get_feedback_messages(import_browser.contents): |
804 | - ... print extract_text(message) |
805 | - The code import has been marked as failing. |
806 | - |
807 | - |
808 | -== Import details for a running job == |
809 | - |
810 | -If the job for an approved import is running, then the import details |
811 | -says how long ago since it started. |
812 | - |
813 | - >>> import_browser.getLink('Edit import source or review import').click() |
814 | - >>> import_browser.getControl('Approve').click() |
815 | - >>> print_import_details(import_browser) |
816 | - Import Status: Reviewed |
817 | - ... |
818 | - The next import is scheduled to run as soon as possible. |
819 | - |
820 | -Now set the job as running. |
821 | - |
822 | - >>> login('david.allouche@canonical.com') |
823 | - >>> from canonical.launchpad.testing.codeimporthelpers import ( |
824 | - ... get_import_for_branch_name, make_running_import) |
825 | - >>> code_import = get_import_for_branch_name( |
826 | - ... svn_import_branch_unique_name) |
827 | - |
828 | -Set the started time to 2h 20m ago, and the approximate datetime |
829 | -should show this as 2 hours. |
830 | - |
831 | - >>> from datetime import datetime, timedelta |
832 | - >>> import pytz |
833 | - >>> date_started = datetime.now(pytz.UTC) - timedelta(hours=2, minutes=20) |
834 | - >>> code_import = make_running_import( |
835 | - ... code_import, date_started=date_started, factory=factory, |
836 | - ... logtail="Changeset 1\nChangeset 2") |
837 | - >>> logout() |
838 | - |
839 | >>> import_browser.open(svn_import_location) |
840 | - >>> print_import_details(import_browser) |
841 | - Import Status: Reviewed |
842 | - ... |
843 | - An import is currently running on machine-..., and was started 2 hours |
844 | - ago. The last few lines of the job's output were: |
845 | - Changeset 1 |
846 | - Changeset 2 |
847 | + >>> import_browser.getLink('Edit import source or review import') |
848 | + Traceback (most recent call last): |
849 | + LinkNotFoundError |
850 | |
851 | |
852 | == Import details for a import that has been imported successfully == |
853 | @@ -265,10 +83,16 @@ |
854 | will be run -- which is, by default for Subversion, six hours after the |
855 | last import completed, and so in this case in about three hours. |
856 | |
857 | +We log in as "david.allouche" since he has super-user privileges for code |
858 | +imports. |
859 | + |
860 | >>> login('david.allouche@canonical.com') |
861 | >>> from canonical.launchpad.testing.codeimporthelpers import ( |
862 | - ... make_finished_import) |
863 | - >>> date_finished = datetime(2007,9,10,12, tzinfo=pytz.UTC) |
864 | + ... make_finished_import, get_import_for_branch_name, |
865 | + ... make_running_import) |
866 | + >>> from datetime import datetime |
867 | + >>> import pytz |
868 | + >>> date_finished = datetime(2007, 9, 10, 12, tzinfo=pytz.UTC) |
869 | >>> code_import = get_import_for_branch_name( |
870 | ... svn_import_branch_unique_name) |
871 | >>> code_import = make_finished_import(code_import, factory=factory, |
872 | @@ -279,8 +103,8 @@ |
873 | >>> print_import_details(import_browser) |
874 | Import Status: Reviewed |
875 | This branch is an import of the Subversion branch from |
876 | - svn://svn-new.example.com/fooix/trunk. |
877 | - The next import is scheduled to run in 3 hours. |
878 | + svn://svn.example.com/fooix/trunk. |
879 | + The next import is scheduled to run in 5 hours. |
880 | Last successful import was on 2007-09-10. |
881 | ... |
882 | |
883 | @@ -315,8 +139,18 @@ |
884 | >>> print_import_details(sample_person_browser) |
885 | Import Status: Reviewed |
886 | This branch is an import of the Subversion branch from |
887 | - svn://svn-new.example.com/fooix/trunk. |
888 | + svn://svn.example.com/fooix/trunk. |
889 | The next import is scheduled to run as soon as possible (requested |
890 | by Sample Person). |
891 | Last successful import was on 2007-09-10. |
892 | ... |
893 | + |
894 | + |
895 | +== Deleting an import == |
896 | + |
897 | +If you own the branch that has the code import, you can delete the branch. |
898 | + |
899 | + >>> import_browser.getLink('Delete branch').click() |
900 | + >>> import_browser.getControl('Delete').click() |
901 | + >>> print_feedback_messages(import_browser.contents) |
902 | + Branch ... deleted. |
903 | |
904 | === modified file 'lib/lp/code/stories/codeimport/xx-failing-codeimport.txt' |
905 | --- lib/lp/code/stories/codeimport/xx-failing-codeimport.txt 2009-05-13 03:41:09 +0000 |
906 | +++ lib/lp/code/stories/codeimport/xx-failing-codeimport.txt 2009-11-11 09:00:39 +0000 |
907 | @@ -9,8 +9,9 @@ |
908 | >>> from lp.code.interfaces.codeimportresult import CodeImportResultStatus |
909 | >>> from canonical.config import config |
910 | >>> product = factory.makeProduct(name='imported') |
911 | + >>> owner = factory.makePerson(name='import-owner') |
912 | >>> code_import = factory.makeCodeImport( |
913 | - ... product=product, branch_name='trunk') |
914 | + ... product=product, branch_name='trunk', registrant=owner) |
915 | >>> for i in range(config.codeimport.consecutive_failure_limit): |
916 | ... dummy = make_finished_import( |
917 | ... code_import, CodeImportResultStatus.FAILURE, |
918 | @@ -20,7 +21,7 @@ |
919 | This is shown on the branch index page: |
920 | |
921 | >>> user_browser.open( |
922 | - ... 'http://code.launchpad.dev/~vcs-imports/imported/trunk') |
923 | + ... 'http://code.launchpad.dev/~import-owner/imported/trunk') |
924 | >>> print extract_text(find_tag_by_id(user_browser.contents, 'failing-try-again')) |
925 | The import has been suspended because it failed 5 or more times in succession. |
926 | |
927 | @@ -33,7 +34,7 @@ |
928 | Anonymous users do not see this button, however. |
929 | |
930 | >>> anon_browser.open( |
931 | - ... 'http://code.launchpad.dev/~vcs-imports/imported/trunk') |
932 | + ... 'http://code.launchpad.dev/~import-owner/imported/trunk') |
933 | >>> anon_browser.getControl('Try Again') |
934 | Traceback (most recent call last): |
935 | ... |
936 | |
937 | === modified file 'lib/lp/code/tests/test_branch.py' |
938 | --- lib/lp/code/tests/test_branch.py 2009-10-20 07:47:54 +0000 |
939 | +++ lib/lp/code/tests/test_branch.py 2009-11-11 09:00:39 +0000 |
940 | @@ -15,7 +15,7 @@ |
941 | from lp.archiveuploader.permission import verify_upload |
942 | from lp.code.enums import ( |
943 | BranchSubscriptionDiffSize, BranchSubscriptionNotificationLevel, |
944 | - CodeReviewNotificationLevel) |
945 | + BranchType, CodeReviewNotificationLevel) |
946 | from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch |
947 | from lp.registry.interfaces.distroseries import DistroSeriesStatus |
948 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
949 | @@ -231,6 +231,16 @@ |
950 | branch = self.factory.makeAnyBranch(owner=team) |
951 | self.assertCanEdit(person, branch) |
952 | |
953 | + def test_vcs_imports_members_can_edit_import_branch(self): |
954 | + # Even if a branch isn't owned by vcs-imports, vcs-imports members can |
955 | + # edit it if it has a code import associated with it. |
956 | + person = self.factory.makePerson() |
957 | + branch = self.factory.makeCodeImport().branch |
958 | + vcs_imports = getUtility(ILaunchpadCelebrities).vcs_imports |
959 | + removeSecurityProxy(vcs_imports).addMember( |
960 | + person, vcs_imports.teamowner) |
961 | + self.assertCanEdit(person, branch) |
962 | + |
963 | def makeOfficialPackageBranch(self): |
964 | """Make a branch linked to the pocket of a source package.""" |
965 | branch = self.factory.makePackageBranch() |
966 | @@ -307,6 +317,28 @@ |
967 | # permissions granted above. |
968 | self.assertCanEdit(person, branch) |
969 | |
970 | + def test_arbitrary_person_cannot_edit(self): |
971 | + # Arbitrary people cannot edit branches, you have to be someone |
972 | + # special. |
973 | + branch = self.factory.makeAnyBranch() |
974 | + person = self.factory.makePerson() |
975 | + self.assertCannotEdit(person, branch) |
976 | + |
977 | + def test_code_import_registrant_can_edit(self): |
978 | + # It used to be the case that all import branches were owned by the |
979 | + # special, restricted team ~vcs-imports. This made a lot of work for |
980 | + # the Launchpad development team, since they needed to delete and |
981 | + # rename import branches whenever people wanted it. To reduce this |
982 | + # work a little, whoever registered of a code import branch is allowed |
983 | + # to edit the branch, even if they aren't one of the owners. |
984 | + registrant = self.factory.makePerson() |
985 | + code_import = self.factory.makeCodeImport(registrant=registrant) |
986 | + branch = code_import.branch |
987 | + removeSecurityProxy(branch).setOwner( |
988 | + getUtility(ILaunchpadCelebrities).vcs_imports, |
989 | + getUtility(ILaunchpadCelebrities).vcs_imports) |
990 | + self.assertCanEdit(registrant, branch) |
991 | + |
992 | |
993 | def test_suite(): |
994 | return unittest.TestLoader().loadTestsFromName(__name__) |
995 | |
996 | === modified file 'lib/lp/testing/factory.py' |
997 | --- lib/lp/testing/factory.py 2009-10-30 17:32:39 +0000 |
998 | +++ lib/lp/testing/factory.py 2009-11-11 09:00:39 +0000 |
999 | @@ -1193,7 +1193,7 @@ |
1000 | |
1001 | def makeCodeImport(self, svn_branch_url=None, cvs_root=None, |
1002 | cvs_module=None, product=None, branch_name=None, |
1003 | - git_repo_url=None): |
1004 | + git_repo_url=None, registrant=None): |
1005 | """Create and return a new, arbitrary code import. |
1006 | |
1007 | The type of code import will be inferred from the source details |
1008 | @@ -1207,7 +1207,8 @@ |
1009 | product = self.makeProduct() |
1010 | if branch_name is None: |
1011 | branch_name = self.getUniqueString('name') |
1012 | - registrant = self.makePerson() |
1013 | + if registrant is None: |
1014 | + registrant = self.makePerson() |
1015 | |
1016 | code_import_set = getUtility(ICodeImportSet) |
1017 | if svn_branch_url is not None: |
Hi Michael,
In this branch, I have tried to fix bug 387110 by setting the owner of a code import branch to be the registrant of the branch, rather than ~vcs-imports.
Doing this changed the email that gets sent. I'm not entirely sure what's going on here, but hope I've done the right thing.
jml