Merge lp:~sinzui/launchpad/series-branch-target into lp:launchpad
- series-branch-target
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Aaron Bentley |
Approved revision: | no longer in the source branch. |
Merged at revision: | not available |
Proposed branch: | lp:~sinzui/launchpad/series-branch-target |
Merge into: | lp:launchpad |
Diff against target: |
616 lines (+142/-153) 14 files modified
lib/lp/code/browser/tests/test_branch.py (+0/-6) lib/lp/code/configure.zcml (+0/-4) lib/lp/code/model/branchtarget.py (+0/-18) lib/lp/code/model/tests/test_branchtarget.py (+1/-26) lib/lp/code/stories/branches/xx-creating-branches.txt (+1/-1) lib/lp/registry/browser/configure.zcml (+26/-14) lib/lp/registry/browser/pillar.py (+1/-55) lib/lp/registry/browser/product.py (+34/-1) lib/lp/registry/browser/productseries.py (+48/-11) lib/lp/registry/browser/tests/pillar-views.txt (+0/-10) lib/lp/registry/browser/tests/productseries-views.txt (+28/-5) lib/lp/registry/model/distribution.py (+1/-0) lib/lp/registry/templates/productseries-codesummary.pt (+1/-1) lib/lp/registry/templates/productseries-linkbranch.pt (+1/-1) |
To merge this branch: | bzr merge lp:~sinzui/launchpad/series-branch-target |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Curtis Hovey (community) | Abstain | ||
Aaron Bentley (community) | Approve | ||
Tim Penhey (community) | Approve | ||
Review via email: mp+23056@code.launchpad.net |
Commit message
Description of the change
See the revised merge summary below
Curtis Hovey (sinzui) wrote : | # |
Hi Tim.
There was a single test failure that showed that this change toppled all the facet/navigation links for product series. Both classes of link reply on IPrimaryContext. This change made all productseries application and involvement links go to the product.
I am reimplementing this by removing the IBranchTarget adapter. My fix is to subclass the the InvolvementMenu and view for IProductSeries. This is not as simple as it seems. Edwin did this recently and discovered that we could not import anything from browser.pillar without causing insane adaptions; he had to place product related classes in the pillar modile. My implementaiton solves this by removing the inline python providesAdapter() and using ZCML--damn it, ZCML is useful :(
Since Edwin's branch is landing, I will wait for his branch to be merged, and I will fix his classes. I will seek a re-review on Monday I think.
Curtis Hovey (sinzui) wrote : | # |
This is my branch to remove ProductSeriesBr
lp:~sinzui/launchpad/series-branch-target
Diff size: 500
Launchpad bug: https:/
Test command: ./bin/test -vv \
-t test_branchtarget \
-t pillar-views \
-t productseries-views
Pre-
Target release: 10.04
Remove ProductSeriesBr
-------
Thumper says that ProductSeriesBr
follow the BranchTarget model and leads to confusion, and wasted effort
trying to understand it.
The suggested change of using a function to return ProductBranchTarget
broke the facet menus (Application/tab menus) because the IPrimaryContext
for IProductSeries was wrongly changed to IProduct.
The correct fix is to remove the branch adaption and fixing the link in an
adaption InvolvedMenu. This requires fixing the adaption insanity that
happens when lp.registry.
Rules
-----
* Remove the ProductBranchTarget subclass with a function that returns
ProductBr
* Subclass the InvolvedMenu to provide the correct link for ProductSeries.
* Fix the adaption issues caused by importing browser.pillar.
* Moved the Product and ProductSeries views in pillar to their proper
modules.
QA
--
* Visit https:/
* Choose Submit code from the Involvement menu
* Verify that you see the Register a branch on Gedit Developer Plugins
page (not an oops.)
Lint
----
Linting changed files:
* lib/lp/
* lib/lp/
* lib/lp/
* lib/lp/
* lib/lp/
* lib/lp/
* lib/lp/
* lib/lp/
* lib/lp/
Test
----
* lib/lp/
* Removed test for removed code.
* lib/lp/
* Removed product series test because there is a better test.
* lib/lp/
* Added a test to verify all the productseries links are to the
correct host and target.
Implementation
--------------
* lib/lp/
* Unregistered removed code.
* lib/lp/
* Removed the adapter.
* lib/lp/
* Moved the InvolvedMenu provideAdapter registration into the zcml to
insanity when pillar is imported.
* Moved the Product and ProductSeries registrations to their proper
location in the ZCML file.
* Registered a new adapter for ProductSeriesIn
* lib/lp/
* Removed the provideAdapter call that causes alternate registrations
when browser.pillar is imported. Used ZCML to do the registration.
* Moved the Product and ProductSeries views to their proper modules.
* lib/...
Aaron Bentley (abentley) : | # |
Curtis Hovey (sinzui) : | # |
Preview Diff
1 | === modified file 'lib/lp/code/browser/tests/test_branch.py' |
2 | --- lib/lp/code/browser/tests/test_branch.py 2010-02-22 01:13:15 +0000 |
3 | +++ lib/lp/code/browser/tests/test_branch.py 2010-04-13 04:18:28 +0000 |
4 | @@ -291,12 +291,6 @@ |
5 | add_view = self.get_view(product) |
6 | self.assertTrue(IBranchTarget.providedBy(add_view.target)) |
7 | |
8 | - def test_target_productseries(self): |
9 | - product = self.factory.makeProduct() |
10 | - series = self.factory.makeProductSeries(product=product) |
11 | - add_view = self.get_view(series) |
12 | - self.assertTrue(IBranchTarget.providedBy(add_view.target)) |
13 | - |
14 | |
15 | class TestBranchReviewerEditView(TestCaseWithFactory): |
16 | """Test the BranchReviewerEditView view.""" |
17 | |
18 | === modified file 'lib/lp/code/configure.zcml' |
19 | --- lib/lp/code/configure.zcml 2010-04-09 02:08:39 +0000 |
20 | +++ lib/lp/code/configure.zcml 2010-04-13 04:18:28 +0000 |
21 | @@ -674,10 +674,6 @@ |
22 | provides="lp.code.interfaces.branchtarget.IBranchTarget" |
23 | factory="lp.code.model.branchtarget.ProductBranchTarget"/> |
24 | <adapter |
25 | - for="lp.registry.interfaces.product.IProductSeries" |
26 | - provides="lp.code.interfaces.branchtarget.IBranchTarget" |
27 | - factory="lp.code.model.branchtarget.ProductSeriesBranchTarget"/> |
28 | - <adapter |
29 | for="lp.code.interfaces.branchtarget.IBranchTarget" |
30 | provides="canonical.launchpad.webapp.interfaces.ICanonicalUrlData" |
31 | factory="lp.code.model.branchtarget.get_canonical_url_data_for_target"/> |
32 | |
33 | === modified file 'lib/lp/code/model/branchtarget.py' |
34 | --- lib/lp/code/model/branchtarget.py 2010-04-09 02:08:39 +0000 |
35 | +++ lib/lp/code/model/branchtarget.py 2010-04-13 04:18:28 +0000 |
36 | @@ -9,7 +9,6 @@ |
37 | 'PackageBranchTarget', |
38 | 'PersonBranchTarget', |
39 | 'ProductBranchTarget', |
40 | - 'ProductSeriesBranchTarget', |
41 | ] |
42 | |
43 | from zope.component import getUtility |
44 | @@ -337,23 +336,6 @@ |
45 | branch.sourcepackagename = None |
46 | |
47 | |
48 | -class ProductSeriesBranchTarget(ProductBranchTarget): |
49 | - |
50 | - def __init__(self, productseries): |
51 | - self.productseries = productseries |
52 | - self.product = productseries.product |
53 | - |
54 | - @property |
55 | - def context(self): |
56 | - """See `IBranchTarget`.""" |
57 | - return self.productseries |
58 | - |
59 | - @property |
60 | - def supports_code_imports(self): |
61 | - """See `IBranchTarget`.""" |
62 | - return False |
63 | - |
64 | - |
65 | def get_canonical_url_data_for_target(branch_target): |
66 | """Return the `ICanonicalUrlData` for an `IBranchTarget`.""" |
67 | return ICanonicalUrlData(branch_target.context) |
68 | |
69 | === modified file 'lib/lp/code/model/tests/test_branchtarget.py' |
70 | --- lib/lp/code/model/tests/test_branchtarget.py 2010-04-09 02:08:39 +0000 |
71 | +++ lib/lp/code/model/tests/test_branchtarget.py 2010-04-13 04:18:28 +0000 |
72 | @@ -12,8 +12,7 @@ |
73 | |
74 | from lp.code.model.branchtarget import ( |
75 | check_default_stacked_on, |
76 | - PackageBranchTarget, PersonBranchTarget, ProductBranchTarget, |
77 | - ProductSeriesBranchTarget) |
78 | + PackageBranchTarget, PersonBranchTarget, ProductBranchTarget) |
79 | from lp.code.enums import BranchType, RevisionControlSystems |
80 | from lp.code.interfaces.branchtarget import IBranchTarget |
81 | from lp.code.interfaces.codeimport import ICodeImport |
82 | @@ -415,30 +414,6 @@ |
83 | self.assertEqual(self.target, code_import.branch.target) |
84 | |
85 | |
86 | -class TestProductSeriesBranchTarget(TestCaseWithFactory): |
87 | - |
88 | - layer = DatabaseFunctionalLayer |
89 | - |
90 | - def setUp(self): |
91 | - TestCaseWithFactory.setUp(self) |
92 | - self.original = self.factory.makeProductSeries() |
93 | - self.target = ProductSeriesBranchTarget(self.original) |
94 | - |
95 | - def test_adapter(self): |
96 | - target = IBranchTarget(self.original) |
97 | - self.assertIsInstance(target, ProductSeriesBranchTarget) |
98 | - |
99 | - def test_doesnt_support_code_imports(self): |
100 | - self.assertFalse(self.target.supports_code_imports) |
101 | - |
102 | - def test_creating_code_import_fails(self): |
103 | - self.assertRaises( |
104 | - AssertionError, self.target.newCodeImport, |
105 | - self.factory.makePerson(), |
106 | - self.factory.getUniqueString("name-"), |
107 | - RevisionControlSystems.GIT, url=self.factory.getUniqueURL()) |
108 | - |
109 | - |
110 | class TestCheckDefaultStackedOnBranch(TestCaseWithFactory): |
111 | """Only certain branches are allowed to be default stacked-on branches.""" |
112 | |
113 | |
114 | === modified file 'lib/lp/code/stories/branches/xx-creating-branches.txt' |
115 | --- lib/lp/code/stories/branches/xx-creating-branches.txt 2009-11-13 21:28:28 +0000 |
116 | +++ lib/lp/code/stories/branches/xx-creating-branches.txt 2010-04-13 04:18:28 +0000 |
117 | @@ -175,7 +175,7 @@ |
118 | >>> browser.open('http://launchpad.dev/gnome-terminal/trunk') |
119 | >>> browser.getLink('registering a mirrored branch').click() |
120 | >>> print browser.title |
121 | - Register a branch : Series trunk : GNOME Terminal |
122 | + Register a branch : GNOME Terminal |
123 | |
124 | The user sees that he is registering a branch for the series' project. |
125 | |
126 | |
127 | === modified file 'lib/lp/registry/browser/configure.zcml' |
128 | --- lib/lp/registry/browser/configure.zcml 2010-04-08 19:19:13 +0000 |
129 | +++ lib/lp/registry/browser/configure.zcml 2010-04-13 04:18:28 +0000 |
130 | @@ -483,6 +483,12 @@ |
131 | for="lp.registry.interfaces.pillar.IPillarNameSet" |
132 | path_expression="string:pillars" |
133 | parent_utility="canonical.launchpad.interfaces.ILaunchpadRoot"/> |
134 | + <adapter |
135 | + provides="canonical.launchpad.webapp.interfaces.INavigationMenu" |
136 | + for="lp.registry.browser.pillar.IInvolved" |
137 | + factory="lp.registry.browser.pillar.InvolvedMenu" |
138 | + name="overview" |
139 | + permission="zope.Public"/> |
140 | <browser:page |
141 | for="lp.registry.interfaces.pillar.IPillar" |
142 | name="+listing-simple" |
143 | @@ -495,20 +501,6 @@ |
144 | facet="overview" |
145 | permission="zope.Public" |
146 | template="../templates/pillar-involvement-portlet.pt"/> |
147 | - <browser:page |
148 | - name="+get-involved" |
149 | - for="lp.registry.interfaces.product.IProduct" |
150 | - class="lp.registry.browser.pillar.ProductInvolvementView" |
151 | - facet="overview" |
152 | - permission="zope.Public" |
153 | - template="../templates/pillar-involvement-portlet.pt"/> |
154 | - <browser:page |
155 | - name="+get-involved" |
156 | - for="lp.registry.interfaces.product.IProductSeries" |
157 | - class="lp.registry.browser.pillar.ProductSeriesInvolvementView" |
158 | - facet="overview" |
159 | - permission="zope.Public" |
160 | - template="../templates/pillar-involvement-portlet.pt"/> |
161 | <facet |
162 | facet="overview"> |
163 | <browser:url |
164 | @@ -1384,6 +1376,13 @@ |
165 | path_expression="name" |
166 | parent_utility="canonical.launchpad.interfaces.ILaunchpadRoot"/> |
167 | <browser:page |
168 | + name="+get-involved" |
169 | + for="lp.registry.interfaces.product.IProduct" |
170 | + class="lp.registry.browser.product.ProductInvolvementView" |
171 | + facet="overview" |
172 | + permission="zope.Public" |
173 | + template="../templates/pillar-involvement-portlet.pt"/> |
174 | + <browser:page |
175 | for="lp.registry.interfaces.product.IProduct" |
176 | name="+download" |
177 | class="lp.registry.browser.product.ProductDownloadFilesView" |
178 | @@ -1600,6 +1599,12 @@ |
179 | for="lp.registry.interfaces.productseries.IProductSeries" |
180 | path_expression="name" |
181 | attribute_to_parent="product"/> |
182 | + <adapter |
183 | + provides="canonical.launchpad.webapp.interfaces.INavigationMenu" |
184 | + for="lp.registry.browser.productseries.IProductSeriesInvolved" |
185 | + factory="lp.registry.browser.productseries.ProductSeriesInvolvedMenu" |
186 | + name="overview" |
187 | + permission="zope.Public"/> |
188 | <browser:defaultView |
189 | for="lp.registry.interfaces.productseries.IProductSeries" |
190 | name="+index"/> |
191 | @@ -1611,6 +1616,13 @@ |
192 | for="lp.registry.interfaces.productseries.IProductSeries" |
193 | layer="canonical.launchpad.layers.BugsLayer" |
194 | name="+bugs-index"/> |
195 | + <browser:page |
196 | + name="+get-involved" |
197 | + for="lp.registry.interfaces.productseries.IProductSeries" |
198 | + class="lp.registry.browser.productseries.ProductSeriesInvolvementView" |
199 | + facet="overview" |
200 | + permission="zope.Public" |
201 | + template="../templates/pillar-involvement-portlet.pt"/> |
202 | <browser:pages |
203 | for="lp.registry.interfaces.productseries.IProductSeries" |
204 | facet="overview" |
205 | |
206 | === modified file 'lib/lp/registry/browser/pillar.py' |
207 | --- lib/lp/registry/browser/pillar.py 2010-04-09 18:19:54 +0000 |
208 | +++ lib/lp/registry/browser/pillar.py 2010-04-13 04:18:28 +0000 |
209 | @@ -6,17 +6,16 @@ |
210 | __metaclass__ = type |
211 | |
212 | __all__ = [ |
213 | + 'InvolvedMenu', |
214 | 'PillarView', |
215 | ] |
216 | |
217 | |
218 | from operator import attrgetter |
219 | |
220 | -from zope.component.globalregistry import provideAdapter |
221 | from zope.interface import implements, Interface |
222 | |
223 | from canonical.cachedproperty import cachedproperty |
224 | -from canonical.launchpad.webapp.interfaces import INavigationMenu |
225 | from canonical.launchpad.webapp.menu import Link, NavigationMenu |
226 | from canonical.launchpad.webapp.publisher import LaunchpadView, nearest |
227 | from canonical.launchpad.webapp.tales import MenuAPI |
228 | @@ -146,56 +145,3 @@ |
229 | return sorted([ |
230 | link for link in important_links if not link.enabled], |
231 | key=attrgetter('sort_key')) |
232 | - |
233 | - |
234 | -provideAdapter( |
235 | - InvolvedMenu, [IInvolved], INavigationMenu, name="overview") |
236 | - |
237 | - |
238 | -# This class can't be moved into the browser/product.py file, since |
239 | -# the pillar-views.txt test will fail due to the MenuAPI adapter |
240 | -# for PillarView.enabled_links not working. |
241 | -class ProductInvolvementView(PillarView): |
242 | - """Encourage configuration of involvement links for projects.""" |
243 | - |
244 | - has_involvement = True |
245 | - visible_disabled_link_names = ['submit_code'] |
246 | - |
247 | - @property |
248 | - def configuration_links(self): |
249 | - """The enabled involvement links.""" |
250 | - overview_menu = MenuAPI(self.context).overview |
251 | - series_menu = MenuAPI(self.context.development_focus).overview |
252 | - configuration_names = [ |
253 | - 'configure_answers', |
254 | - 'configure_bugtracker', |
255 | - 'configure_translations', |
256 | - ] |
257 | - configuration_links = [ |
258 | - overview_menu[name] for name in configuration_names] |
259 | - set_branch = series_menu['set_branch'] |
260 | - set_branch.text = 'Configure project branch' |
261 | - configuration_links.append(set_branch) |
262 | - return sorted([ |
263 | - link for link in configuration_links if link.enabled], |
264 | - key=attrgetter('sort_key')) |
265 | - |
266 | - |
267 | -class ProductSeriesInvolvementView(PillarView): |
268 | - """Encourage configuration of involvement links for project series.""" |
269 | - |
270 | - has_involvement = True |
271 | - visible_disabled_link_names = ['submit_code'] |
272 | - |
273 | - def __init__(self, context, request): |
274 | - super(ProductSeriesInvolvementView, self).__init__(context, request) |
275 | - self.official_codehosting = self.context.branch is not None |
276 | - self.official_answers = False |
277 | - |
278 | - @property |
279 | - def configuration_links(self): |
280 | - """The enabled involvement links.""" |
281 | - series_menu = MenuAPI(self.context).overview |
282 | - set_branch = series_menu['set_branch'] |
283 | - set_branch.text = 'Configure series branch' |
284 | - return [set_branch] |
285 | |
286 | === modified file 'lib/lp/registry/browser/product.py' |
287 | --- lib/lp/registry/browser/product.py 2010-04-08 19:19:13 +0000 |
288 | +++ lib/lp/registry/browser/product.py 2010-04-13 04:18:28 +0000 |
289 | @@ -14,7 +14,6 @@ |
290 | 'ProductBugsMenu', |
291 | 'ProductConfigureAnswersView', |
292 | 'ProductConfigureBlueprintsView', |
293 | - 'ProductConfigureBranchesView', |
294 | 'ProductConfigureBugTrackerView', |
295 | 'ProductConfigureTranslationsView', |
296 | 'ProductDownloadFileMixin', |
297 | @@ -94,6 +93,7 @@ |
298 | IRegistryCollectionNavigationMenu, RegistryCollectionActionMenuBase) |
299 | from lp.answers.browser.faqtarget import FAQTargetNavigationMixin |
300 | from canonical.launchpad.browser.feeds import FeedsMixin |
301 | +from lp.registry.browser.pillar import PillarView |
302 | from lp.registry.browser.productseries import get_series_branch_error |
303 | from lp.translations.browser.customlanguagecode import ( |
304 | HasCustomLanguageCodesTraversalMixin) |
305 | @@ -115,6 +115,7 @@ |
306 | action, custom_widget, LaunchpadEditFormView, LaunchpadFormView, |
307 | ReturnToReferrerMixin) |
308 | from canonical.launchpad.webapp.menu import NavigationMenu |
309 | +from canonical.launchpad.webapp.tales import MenuAPI |
310 | from canonical.widgets.popup import PersonPickerWidget |
311 | from canonical.widgets.date import DateWidget |
312 | from canonical.widgets.itemswidgets import ( |
313 | @@ -299,6 +300,32 @@ |
314 | return Link('', text, summary) |
315 | |
316 | |
317 | +class ProductInvolvementView(PillarView): |
318 | + """Encourage configuration of involvement links for projects.""" |
319 | + |
320 | + has_involvement = True |
321 | + visible_disabled_link_names = ['submit_code'] |
322 | + |
323 | + @property |
324 | + def configuration_links(self): |
325 | + """The enabled involvement links.""" |
326 | + overview_menu = MenuAPI(self.context).overview |
327 | + series_menu = MenuAPI(self.context.development_focus).overview |
328 | + configuration_names = [ |
329 | + 'configure_answers', |
330 | + 'configure_bugtracker', |
331 | + 'configure_translations', |
332 | + ] |
333 | + configuration_links = [ |
334 | + overview_menu[name] for name in configuration_names] |
335 | + set_branch = series_menu['set_branch'] |
336 | + set_branch.text = 'Configure project branch' |
337 | + configuration_links.append(set_branch) |
338 | + return sorted([ |
339 | + link for link in configuration_links if link.enabled], |
340 | + key=attrgetter('sort_key')) |
341 | + |
342 | + |
343 | class ProductNavigationMenu(NavigationMenu): |
344 | |
345 | usedfor = IProduct |
346 | @@ -420,6 +447,7 @@ |
347 | 'announcements', |
348 | 'administer', |
349 | 'review_license', |
350 | + 'branch_add', |
351 | 'branchvisibility', |
352 | 'rdf', |
353 | 'branding', |
354 | @@ -476,6 +504,11 @@ |
355 | text = 'Branch Visibility Policy' |
356 | return Link('+branchvisibility', text, icon='edit') |
357 | |
358 | + def branch_add(self): |
359 | + text = 'Register a branch' |
360 | + summary = "Register a new Bazaar branch for this project" |
361 | + return Link('+addbranch', text, summary, icon='add') |
362 | + |
363 | |
364 | class ProductBugsMenu(ApplicationMenu, StructuralSubscriptionMenuMixin): |
365 | |
366 | |
367 | === modified file 'lib/lp/registry/browser/productseries.py' |
368 | --- lib/lp/registry/browser/productseries.py 2010-04-09 02:25:21 +0000 |
369 | +++ lib/lp/registry/browser/productseries.py 2010-04-13 04:18:28 +0000 |
370 | @@ -13,6 +13,7 @@ |
371 | 'ProductSeriesEditView', |
372 | 'ProductSeriesFacets', |
373 | 'ProductSeriesFileBugRedirect', |
374 | + 'ProductSeriesInvolvementView', |
375 | 'ProductSeriesLinkBranchView', |
376 | 'ProductSeriesLinkBranchFromCodeView', |
377 | 'ProductSeriesNavigation', |
378 | @@ -34,7 +35,7 @@ |
379 | from zope.component import getUtility |
380 | from zope.app.form.browser import TextAreaWidget, TextWidget |
381 | from zope.formlib import form |
382 | -from zope.interface import Interface |
383 | +from zope.interface import implements, Interface |
384 | from zope.schema import Choice |
385 | from zope.schema.vocabulary import SimpleTerm, SimpleVocabulary |
386 | |
387 | @@ -84,11 +85,13 @@ |
388 | action, custom_widget, LaunchpadEditFormView, LaunchpadFormView, |
389 | ReturnToReferrerMixin) |
390 | from canonical.launchpad.webapp.menu import structured |
391 | +from canonical.launchpad.webapp.tales import MenuAPI |
392 | from canonical.widgets.itemswidgets import LaunchpadRadioWidget |
393 | from canonical.widgets.textwidgets import StrippedTextWidget |
394 | |
395 | from lp.registry.browser import ( |
396 | MilestoneOverlayMixin, RegistryDeleteViewMixin) |
397 | +from lp.registry.browser.pillar import InvolvedMenu, PillarView |
398 | from lp.registry.interfaces.series import SeriesStatus |
399 | from lp.registry.interfaces.productseries import IProductSeries |
400 | |
401 | @@ -168,13 +171,53 @@ |
402 | return Link(link, text, summary=summary) |
403 | |
404 | |
405 | +class IProductSeriesInvolved(Interface): |
406 | + """A marker interface for getting involved.""" |
407 | + |
408 | + |
409 | +class ProductSeriesInvolvedMenu(InvolvedMenu): |
410 | + """The get involved menu.""" |
411 | + usedfor = IProductSeriesInvolved |
412 | + links = [ |
413 | + 'report_bug', 'help_translate', 'submit_code', 'register_blueprint'] |
414 | + |
415 | + def submit_code(self): |
416 | + product = self.context.context.product |
417 | + target = canonical_url( |
418 | + product, view_name='+addbranch', rootsite='code') |
419 | + enabled = product.official_codehosting |
420 | + return Link( |
421 | + target, 'Submit code', icon='code', enabled=enabled) |
422 | + |
423 | + |
424 | +class ProductSeriesInvolvementView(PillarView): |
425 | + """Encourage configuration of involvement links for project series.""" |
426 | + |
427 | + implements(IProductSeriesInvolved) |
428 | + has_involvement = True |
429 | + visible_disabled_link_names = ['submit_code'] |
430 | + |
431 | + def __init__(self, context, request): |
432 | + super(ProductSeriesInvolvementView, self).__init__(context, request) |
433 | + self.official_codehosting = self.context.branch is not None |
434 | + self.official_answers = False |
435 | + |
436 | + @property |
437 | + def configuration_links(self): |
438 | + """The enabled involvement links.""" |
439 | + series_menu = MenuAPI(self.context).overview |
440 | + set_branch = series_menu['set_branch'] |
441 | + set_branch.text = 'Configure series branch' |
442 | + return [set_branch] |
443 | + |
444 | + |
445 | class ProductSeriesOverviewMenu( |
446 | ApplicationMenu, StructuralSubscriptionMenuMixin): |
447 | """The overview menu.""" |
448 | usedfor = IProductSeries |
449 | facet = 'overview' |
450 | links = [ |
451 | - 'edit', 'delete', 'driver', 'link_branch', 'branch_add', 'ubuntupkg', |
452 | + 'edit', 'delete', 'driver', 'link_branch', 'ubuntupkg', |
453 | 'create_milestone', 'create_release', 'rdf', 'subscribe', |
454 | 'set_branch', |
455 | ] |
456 | @@ -228,11 +271,6 @@ |
457 | summary = 'Change the branch for this series' |
458 | return Link('+setbranch', text, summary, icon=icon) |
459 | |
460 | - def branch_add(self): |
461 | - text = 'Register a branch' |
462 | - summary = "Register a new Bazaar branch for this series' project" |
463 | - return Link('+addbranch', text, summary, icon='add') |
464 | - |
465 | @enabled_with_permission('launchpad.AnyPerson') |
466 | def ubuntupkg(self): |
467 | """Return a link to link this series to an ubuntu sourcepackage.""" |
468 | @@ -507,7 +545,6 @@ |
469 | # to this series, or any other series. |
470 | pass |
471 | |
472 | - |
473 | @action('Update', name='continue') |
474 | def continue_action(self, action, data): |
475 | # set the packaging record for this productseries in the current |
476 | @@ -879,8 +916,8 @@ |
477 | # Extend the allowed schemes for the repository URL based on |
478 | # rcs_type. |
479 | extra_schemes = { |
480 | - RevisionControlSystemsExtended.BZR_SVN:['svn'], |
481 | - RevisionControlSystemsExtended.GIT:['git'], |
482 | + RevisionControlSystemsExtended.BZR_SVN: ['svn'], |
483 | + RevisionControlSystemsExtended.GIT: ['git'], |
484 | } |
485 | schemes.update(extra_schemes.get(rcs_type, [])) |
486 | return schemes |
487 | @@ -933,7 +970,7 @@ |
488 | @property |
489 | def target(self): |
490 | """The branch target for the context.""" |
491 | - return IBranchTarget(self.context) |
492 | + return IBranchTarget(self.context.product) |
493 | |
494 | @action(_('Update'), name='update') |
495 | def update_action(self, action, data): |
496 | |
497 | === modified file 'lib/lp/registry/browser/tests/pillar-views.txt' |
498 | --- lib/lp/registry/browser/tests/pillar-views.txt 2010-04-09 02:25:21 +0000 |
499 | +++ lib/lp/registry/browser/tests/pillar-views.txt 2010-04-13 04:18:28 +0000 |
500 | @@ -132,16 +132,6 @@ |
501 | ... print link.name |
502 | report_bug |
503 | |
504 | -ProductSeries can use this view. The product is used to set the links, |
505 | -but the answers link will be disbaled. |
506 | - |
507 | - >>> series = factory.makeProductSeries(product=product) |
508 | - >>> product.official_answers = True |
509 | - >>> view = create_view(series, '+get-involved') |
510 | - >>> for link in view.enabled_links: |
511 | - ... print link.name |
512 | - register_blueprint |
513 | - |
514 | DistributionSourcePackages can use this view. The distribution is used to |
515 | set the links. Despite the fact that the distribution uses blueprints, |
516 | and translations those links are not enabled for DistributionSourcePackages. |
517 | |
518 | === modified file 'lib/lp/registry/browser/tests/productseries-views.txt' |
519 | --- lib/lp/registry/browser/tests/productseries-views.txt 2010-04-02 14:08:22 +0000 |
520 | +++ lib/lp/registry/browser/tests/productseries-views.txt 2010-04-13 04:18:28 +0000 |
521 | @@ -1,7 +1,7 @@ |
522 | ProductSeries Views |
523 | =================== |
524 | |
525 | -Productseries menus |
526 | +ProductSeries menus |
527 | ------------------- |
528 | |
529 | The ProductSeriesOverviewMenu provides the links to the common ProductSeries |
530 | @@ -11,11 +11,37 @@ |
531 | ... ProductSeriesOverviewMenu) |
532 | >>> from lp.testing.menu import check_menu_links |
533 | |
534 | - >>> series = factory.makeSeries() |
535 | + >>> product = factory.makeProduct(name='app') |
536 | + >>> series = factory.makeSeries(name='simple', product=product) |
537 | >>> check_menu_links(ProductSeriesOverviewMenu(series)) |
538 | True |
539 | |
540 | |
541 | +ProductSeries Involvement links |
542 | +............................... |
543 | + |
544 | +The ProductSeries involvement view uses the ProductSeriesInvolvedMenu when |
545 | +rendering links: |
546 | + |
547 | + >>> from operator import attrgetter |
548 | + >>> from canonical.launchpad.webapp.tales import MenuAPI |
549 | + |
550 | + >>> login_person(product.owner) |
551 | + >>> product.official_answers = True |
552 | + >>> product.official_blueprints = True |
553 | + >>> product.official_malone = True |
554 | + >>> product.official_rosetta = True |
555 | + >>> view = create_view(series, '+get-involved') |
556 | + >>> menuapi = MenuAPI(view) |
557 | + >>> for link in sorted( |
558 | + ... menuapi.navigation.values(), key=attrgetter('sort_key')): |
559 | + ... print link.url |
560 | + http://bugs.launchpad.dev/app/simple/+filebug |
561 | + http://translations.launchpad.dev/app/simple |
562 | + http://code.launchpad.dev/app/+addbranch |
563 | + http://blueprints.launchpad.dev/app/simple/+addspec |
564 | + |
565 | + |
566 | ProductSeries view |
567 | ------------------ |
568 | |
569 | @@ -26,9 +52,6 @@ |
570 | >>> from canonical.launchpad.testing.pages import find_tag_by_id |
571 | |
572 | >>> login('foo.bar@canonical.com') |
573 | - |
574 | - >>> product = factory.makeProduct(name='app') |
575 | - >>> series = factory.makeSeries(name='simple', product=product) |
576 | >>> view = create_view(series, '+index', principal=product.owner) |
577 | >>> script = find_tag_by_id(view.render(), 'milestone-script') |
578 | >>> print script |
579 | |
580 | === modified file 'lib/lp/registry/model/distribution.py' |
581 | --- lib/lp/registry/model/distribution.py 2010-04-10 09:24:41 +0000 |
582 | +++ lib/lp/registry/model/distribution.py 2010-04-13 04:18:28 +0000 |
583 | @@ -21,6 +21,7 @@ |
584 | from lp.archivepublisher.debversion import Version |
585 | from canonical.cachedproperty import cachedproperty |
586 | from canonical.database.constants import UTC_NOW |
587 | + |
588 | from canonical.database.datetimecol import UtcDateTimeCol |
589 | from canonical.database.enumcol import EnumCol |
590 | from canonical.database.sqlbase import ( |
591 | |
592 | === modified file 'lib/lp/registry/templates/productseries-codesummary.pt' |
593 | --- lib/lp/registry/templates/productseries-codesummary.pt 2010-03-11 15:32:22 +0000 |
594 | +++ lib/lp/registry/templates/productseries-codesummary.pt 2010-04-13 04:18:28 +0000 |
595 | @@ -35,7 +35,7 @@ |
596 | <ul class="bulleted" style="margin-bottom: 0;"> |
597 | <li> |
598 | Have the branch mirrored from a remote location by |
599 | - <a tal:attributes="href context/menu:overview/branch_add/fmt:url"> |
600 | + <a tal:attributes="href context/product/menu:overview/branch_add/fmt:url"> |
601 | registering a mirrored branch</a> |
602 | </li> |
603 | <li id="ssh-key-directions"> |
604 | |
605 | === modified file 'lib/lp/registry/templates/productseries-linkbranch.pt' |
606 | --- lib/lp/registry/templates/productseries-linkbranch.pt 2010-03-11 15:26:46 +0000 |
607 | +++ lib/lp/registry/templates/productseries-linkbranch.pt 2010-04-13 04:18:28 +0000 |
608 | @@ -22,7 +22,7 @@ |
609 | <ul class="bulleted" style="margin-bottom: 0;"> |
610 | <li> |
611 | Have the branch mirrored from a remote location by |
612 | - <a tal:attributes="href context/menu:overview/branch_add/fmt:url"> |
613 | + <a tal:attributes="href context/product/menu:overview/branch_add/fmt:url"> |
614 | registering a mirrored branch</a> |
615 | </li> |
616 | <li id="ssh-key-directions"> |
Looks good