Merge lp:~bac/launchpad/bug-512408 into lp:launchpad
- bug-512408
- 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:~bac/launchpad/bug-512408 |
Merge into: | lp:launchpad |
Diff against target: |
655 lines (+429/-47) 11 files modified
lib/canonical/launchpad/testing/pages.py (+1/-12) lib/canonical/launchpad/testing/systemdocs.py (+13/-0) lib/lp/registry/browser/configure.zcml (+7/-4) lib/lp/registry/browser/product.py (+55/-0) lib/lp/registry/browser/tests/product-portlet-packages-view.txt (+174/-0) lib/lp/registry/browser/tests/product-views.txt (+75/-0) lib/lp/registry/model/distributionsourcepackage.py (+2/-1) lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt (+3/-3) lib/lp/registry/stories/product/xx-product-index.txt (+33/-0) lib/lp/registry/templates/product-portlet-packages.pt (+65/-26) lib/lp/registry/tests/test_doc_product.py (+1/-1) |
To merge this branch: | bzr merge lp:~bac/launchpad/bug-512408 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Curtis Hovey (community) | code + ui | Approve | |
Aaron Bentley (community) | Approve | ||
Review via email: mp+20379@code.launchpad.net |
Commit message
Project index page packaging portlet suggests which Ubuntu package it may be associated.
Description of the change
Brad Crittenden (bac) wrote : | # |
Aaron Bentley (abentley) : | # |
Curtis Hovey (sinzui) wrote : | # |
Hi Brad.
The UI looks and behaves well and I think it is good to land, but there is an implementation issue.
As we saw on IRC, The UI prompts me to create duplicate packaging links. The list of candiates is not filtering the packages that have packaging links. My test case was to create a link to lucid pmount from applets. When I registered pmount, I was prompted to link it to lucid pmount--which leads to a db constraint violation in db-devel and a NotOneError in devel when I vistit lucid pmount.
Brad Crittenden (bac) wrote : | # |
Curtis I made the change you requested.
In the process of writing the tests I needed to use Barry's 'stop()' command but it was only available to page tests, not doc tests, so I did a quick drive-by to move it over.
Curtis Hovey (sinzui) wrote : | # |
All this is lovely, unlike merge reviews which just ate my UI approve because I wanted to give you my code approve.
Preview Diff
1 | === modified file 'lib/canonical/launchpad/testing/pages.py' | |||
2 | --- lib/canonical/launchpad/testing/pages.py 2010-02-24 23:18:40 +0000 | |||
3 | +++ lib/canonical/launchpad/testing/pages.py 2010-03-06 12:18:33 +0000 | |||
4 | @@ -14,7 +14,6 @@ | |||
5 | 14 | import pprint | 14 | import pprint |
6 | 15 | import re | 15 | import re |
7 | 16 | import transaction | 16 | import transaction |
8 | 17 | import sys | ||
9 | 18 | import unittest | 17 | import unittest |
10 | 19 | 18 | ||
11 | 20 | from BeautifulSoup import ( | 19 | from BeautifulSoup import ( |
12 | @@ -34,7 +33,7 @@ | |||
13 | 34 | IOAuthConsumerSet, OAUTH_REALM, ILaunchpadCelebrities, | 33 | IOAuthConsumerSet, OAUTH_REALM, ILaunchpadCelebrities, |
14 | 35 | TeamMembershipStatus) | 34 | TeamMembershipStatus) |
15 | 36 | from canonical.launchpad.testing.systemdocs import ( | 35 | from canonical.launchpad.testing.systemdocs import ( |
17 | 37 | LayeredDocFileSuite, SpecialOutputChecker, strip_prefix) | 36 | LayeredDocFileSuite, SpecialOutputChecker, stop, strip_prefix) |
18 | 38 | from canonical.launchpad.webapp import canonical_url | 37 | from canonical.launchpad.webapp import canonical_url |
19 | 39 | from canonical.launchpad.webapp.interfaces import OAuthPermission | 38 | from canonical.launchpad.webapp.interfaces import OAuthPermission |
20 | 40 | from canonical.launchpad.webapp.url import urlsplit | 39 | from canonical.launchpad.webapp.url import urlsplit |
21 | @@ -715,16 +714,6 @@ | |||
22 | 715 | return setupBrowser(auth='Basic re@ex.com:test') | 714 | return setupBrowser(auth='Basic re@ex.com:test') |
23 | 716 | 715 | ||
24 | 717 | 716 | ||
25 | 718 | def stop(): | ||
26 | 719 | # Temporarily restore the real stdout. | ||
27 | 720 | old_stdout = sys.stdout | ||
28 | 721 | sys.stdout = sys.__stdout__ | ||
29 | 722 | try: | ||
30 | 723 | pdb.set_trace() | ||
31 | 724 | finally: | ||
32 | 725 | sys.stdout = old_stdout | ||
33 | 726 | |||
34 | 727 | |||
35 | 728 | def setUpGlobs(test): | 717 | def setUpGlobs(test): |
36 | 729 | test.globs['transaction'] = transaction | 718 | test.globs['transaction'] = transaction |
37 | 730 | test.globs['http'] = UnstickyCookieHTTPCaller() | 719 | test.globs['http'] = UnstickyCookieHTTPCaller() |
38 | 731 | 720 | ||
39 | === modified file 'lib/canonical/launchpad/testing/systemdocs.py' | |||
40 | --- lib/canonical/launchpad/testing/systemdocs.py 2009-10-15 11:47:32 +0000 | |||
41 | +++ lib/canonical/launchpad/testing/systemdocs.py 2010-03-06 12:18:33 +0000 | |||
42 | @@ -10,12 +10,14 @@ | |||
43 | 10 | 'SpecialOutputChecker', | 10 | 'SpecialOutputChecker', |
44 | 11 | 'setUp', | 11 | 'setUp', |
45 | 12 | 'setGlobs', | 12 | 'setGlobs', |
46 | 13 | 'stop', | ||
47 | 13 | 'strip_prefix', | 14 | 'strip_prefix', |
48 | 14 | 'tearDown', | 15 | 'tearDown', |
49 | 15 | ] | 16 | ] |
50 | 16 | 17 | ||
51 | 17 | import logging | 18 | import logging |
52 | 18 | import os | 19 | import os |
53 | 20 | import pdb | ||
54 | 19 | import pprint | 21 | import pprint |
55 | 20 | import sys | 22 | import sys |
56 | 21 | 23 | ||
57 | @@ -170,6 +172,16 @@ | |||
58 | 170 | "%r: %r" % (key, value) for key, value in sorted(dict.items())) | 172 | "%r: %r" % (key, value) for key, value in sorted(dict.items())) |
59 | 171 | 173 | ||
60 | 172 | 174 | ||
61 | 175 | def stop(): | ||
62 | 176 | # Temporarily restore the real stdout. | ||
63 | 177 | old_stdout = sys.stdout | ||
64 | 178 | sys.stdout = sys.__stdout__ | ||
65 | 179 | try: | ||
66 | 180 | pdb.set_trace() | ||
67 | 181 | finally: | ||
68 | 182 | sys.stdout = old_stdout | ||
69 | 183 | |||
70 | 184 | |||
71 | 173 | def setGlobs(test): | 185 | def setGlobs(test): |
72 | 174 | """Add the common globals for testing system documentation.""" | 186 | """Add the common globals for testing system documentation.""" |
73 | 175 | test.globs['ANONYMOUS'] = ANONYMOUS | 187 | test.globs['ANONYMOUS'] = ANONYMOUS |
74 | @@ -186,6 +198,7 @@ | |||
75 | 186 | test.globs['ordered_dict_as_string'] = ordered_dict_as_string | 198 | test.globs['ordered_dict_as_string'] = ordered_dict_as_string |
76 | 187 | test.globs['verifyObject'] = verifyObject | 199 | test.globs['verifyObject'] = verifyObject |
77 | 188 | test.globs['pretty'] = pprint.PrettyPrinter(width=1).pformat | 200 | test.globs['pretty'] = pprint.PrettyPrinter(width=1).pformat |
78 | 201 | test.globs['stop'] = stop | ||
79 | 189 | 202 | ||
80 | 190 | 203 | ||
81 | 191 | def setUp(test): | 204 | def setUp(test): |
82 | 192 | 205 | ||
83 | === modified file 'lib/lp/registry/browser/configure.zcml' | |||
84 | --- lib/lp/registry/browser/configure.zcml 2010-03-05 14:18:18 +0000 | |||
85 | +++ lib/lp/registry/browser/configure.zcml 2010-03-06 12:18:33 +0000 | |||
86 | @@ -1412,15 +1412,18 @@ | |||
87 | 1412 | facet="overview" | 1412 | facet="overview" |
88 | 1413 | template="../templates/product-portlet-license-missing.pt"/> | 1413 | template="../templates/product-portlet-license-missing.pt"/> |
89 | 1414 | <browser:page | 1414 | <browser:page |
90 | 1415 | name="+portlet-packages" | ||
91 | 1416 | facet="overview" | ||
92 | 1417 | template="../templates/product-portlet-packages.pt"/> | ||
93 | 1418 | <browser:page | ||
94 | 1419 | name="+purchase-subscription" | 1415 | name="+purchase-subscription" |
95 | 1420 | template="../templates/product-purchase-subscription.pt"/> | 1416 | template="../templates/product-purchase-subscription.pt"/> |
96 | 1421 | </browser:pages> | 1417 | </browser:pages> |
97 | 1422 | <browser:page | 1418 | <browser:page |
98 | 1423 | for="lp.registry.interfaces.product.IProduct" | 1419 | for="lp.registry.interfaces.product.IProduct" |
99 | 1420 | permission="zope.Public" | ||
100 | 1421 | name="+portlet-packages" | ||
101 | 1422 | facet="overview" | ||
102 | 1423 | class="lp.registry.browser.product.ProductPackagesPortletView" | ||
103 | 1424 | template="../templates/product-portlet-packages.pt"/> | ||
104 | 1425 | <browser:page | ||
105 | 1426 | for="lp.registry.interfaces.product.IProduct" | ||
106 | 1424 | class="lp.registry.browser.product.ProductSeriesView" | 1427 | class="lp.registry.browser.product.ProductSeriesView" |
107 | 1425 | name="+series" | 1428 | name="+series" |
108 | 1426 | facet="overview" | 1429 | facet="overview" |
109 | 1427 | 1430 | ||
110 | === modified file 'lib/lp/registry/browser/product.py' | |||
111 | --- lib/lp/registry/browser/product.py 2010-02-16 21:21:14 +0000 | |||
112 | +++ lib/lp/registry/browser/product.py 2010-03-06 12:18:33 +0000 | |||
113 | @@ -21,6 +21,7 @@ | |||
114 | 21 | 'ProductNavigationMenu', | 21 | 'ProductNavigationMenu', |
115 | 22 | 'ProductOverviewMenu', | 22 | 'ProductOverviewMenu', |
116 | 23 | 'ProductPackagesView', | 23 | 'ProductPackagesView', |
117 | 24 | 'ProductPackagesPortletView', | ||
118 | 24 | 'ProductRdfView', | 25 | 'ProductRdfView', |
119 | 25 | 'ProductReviewLicenseView', | 26 | 'ProductReviewLicenseView', |
120 | 26 | 'ProductSeriesView', | 27 | 'ProductSeriesView', |
121 | @@ -37,6 +38,7 @@ | |||
122 | 37 | ] | 38 | ] |
123 | 38 | 39 | ||
124 | 39 | 40 | ||
125 | 41 | from cgi import escape | ||
126 | 40 | from operator import attrgetter | 42 | from operator import attrgetter |
127 | 41 | 43 | ||
128 | 42 | from zope.component import getUtility | 44 | from zope.component import getUtility |
129 | @@ -45,6 +47,9 @@ | |||
130 | 45 | from zope.lifecycleevent import ObjectCreatedEvent | 47 | from zope.lifecycleevent import ObjectCreatedEvent |
131 | 46 | from zope.interface import implements, Interface | 48 | from zope.interface import implements, Interface |
132 | 47 | from zope.formlib import form | 49 | from zope.formlib import form |
133 | 50 | from zope.schema import Choice | ||
134 | 51 | from zope.schema.vocabulary import ( | ||
135 | 52 | SimpleVocabulary, SimpleTerm) | ||
136 | 48 | 53 | ||
137 | 49 | from z3c.ptcompat import ViewPageTemplateFile | 54 | from z3c.ptcompat import ViewPageTemplateFile |
138 | 50 | 55 | ||
139 | @@ -981,6 +986,56 @@ | |||
140 | 981 | return results | 986 | return results |
141 | 982 | 987 | ||
142 | 983 | 988 | ||
143 | 989 | class ProductPackagesPortletView(LaunchpadFormView): | ||
144 | 990 | """View class for product packaging portlet.""" | ||
145 | 991 | |||
146 | 992 | schema = Interface | ||
147 | 993 | custom_widget( | ||
148 | 994 | 'distributionsourcepackage', LaunchpadRadioWidget, | ||
149 | 995 | orientation='vertical') | ||
150 | 996 | suggestions = None | ||
151 | 997 | |||
152 | 998 | def setUpFields(self): | ||
153 | 999 | """See `LaunchpadFormView`.""" | ||
154 | 1000 | super(ProductPackagesPortletView, self).setUpFields() | ||
155 | 1001 | ubuntu = getUtility(ILaunchpadCelebrities).ubuntu | ||
156 | 1002 | source_packages = ubuntu.searchSourcePackages(self.context.name) | ||
157 | 1003 | # Based upon the matches, create a new vocabulary with | ||
158 | 1004 | # term descriptions that include a link to the source package. | ||
159 | 1005 | self.suggestions = [] | ||
160 | 1006 | vocab_terms = [] | ||
161 | 1007 | for package in source_packages: | ||
162 | 1008 | if package.upstream_product is not None: | ||
163 | 1009 | continue | ||
164 | 1010 | self.suggestions.append(package) | ||
165 | 1011 | item_url = canonical_url(package) | ||
166 | 1012 | description = """<a href="%s">%s</a>""" % ( | ||
167 | 1013 | item_url, escape(package.name)) | ||
168 | 1014 | vocab_terms.append(SimpleTerm(package, package.name, description)) | ||
169 | 1015 | vocabulary = SimpleVocabulary(vocab_terms) | ||
170 | 1016 | self.form_fields = form.Fields( | ||
171 | 1017 | Choice(__name__='distributionsourcepackage', | ||
172 | 1018 | title=_('Ubuntu packages'), | ||
173 | 1019 | default=None, | ||
174 | 1020 | vocabulary=vocabulary, | ||
175 | 1021 | required=True)) | ||
176 | 1022 | |||
177 | 1023 | @action(_('Link to this Ubuntu Package'), name='link') | ||
178 | 1024 | def link(self, action, data): | ||
179 | 1025 | product = self.context | ||
180 | 1026 | dsp = data.get('distributionsourcepackage') | ||
181 | 1027 | assert dsp is not None, "distributionsourcepackage was not specified" | ||
182 | 1028 | product_series = product.development_focus | ||
183 | 1029 | ubuntu = getUtility(ILaunchpadCelebrities).ubuntu | ||
184 | 1030 | product_series.setPackaging(ubuntu.currentseries, | ||
185 | 1031 | dsp.sourcepackagename, | ||
186 | 1032 | self.user) | ||
187 | 1033 | self.request.response.addInfoNotification( | ||
188 | 1034 | 'This project was linked to the source package "%s"' % | ||
189 | 1035 | dsp.displayname) | ||
190 | 1036 | self.next_url = self.request.getURL() | ||
191 | 1037 | |||
192 | 1038 | |||
193 | 984 | class SeriesReleasePair: | 1039 | class SeriesReleasePair: |
194 | 985 | """Class for holding a series and release. | 1040 | """Class for holding a series and release. |
195 | 986 | 1041 | ||
196 | 987 | 1042 | ||
197 | === added file 'lib/lp/registry/browser/tests/product-portlet-packages-view.txt' | |||
198 | --- lib/lp/registry/browser/tests/product-portlet-packages-view.txt 1970-01-01 00:00:00 +0000 | |||
199 | +++ lib/lp/registry/browser/tests/product-portlet-packages-view.txt 2010-03-06 12:18:33 +0000 | |||
200 | @@ -0,0 +1,174 @@ | |||
201 | 1 | +portlet-packages | ||
202 | 2 | ----------------- | ||
203 | 3 | |||
204 | 4 | When the product is not linked to a source package in Ubuntu the | ||
205 | 5 | +portlet-packages will show suggestions on potential matches and ask | ||
206 | 6 | the user to make the connection. | ||
207 | 7 | |||
208 | 8 | Create a helper to update the distribution source package cache, which | ||
209 | 9 | does not happen automatically. | ||
210 | 10 | |||
211 | 11 | >>> from canonical.launchpad.testing.pages import find_tag_by_id | ||
212 | 12 | >>> from canonical.launchpad.testing.pages import extract_text | ||
213 | 13 | >>> from canonical.launchpad.interfaces.launchpad import ( | ||
214 | 14 | ... ILaunchpadCelebrities) | ||
215 | 15 | >>> from lp.registry.interfaces.product import IProductSet | ||
216 | 16 | >>> from lp.registry.interfaces.sourcepackagename import ( | ||
217 | 17 | ... ISourcePackageNameSet) | ||
218 | 18 | |||
219 | 19 | >>> import transaction | ||
220 | 20 | >>> from canonical.launchpad.scripts import QuietFakeLogger | ||
221 | 21 | >>> logger = QuietFakeLogger() | ||
222 | 22 | >>> from canonical.testing.layers import reconnect_stores | ||
223 | 23 | >>> from canonical.config import config | ||
224 | 24 | >>> def updateCache(): | ||
225 | 25 | ... # Switch to the statistician user who is the only user with | ||
226 | 26 | ... # write permission to the source package cache tables. | ||
227 | 27 | ... transaction.commit() | ||
228 | 28 | ... reconnect_stores(config.statistician.dbuser) | ||
229 | 29 | ... ubuntu = getUtility(ILaunchpadCelebrities).ubuntu | ||
230 | 30 | ... updated = ubuntu.updateCompleteSourcePackageCache( | ||
231 | 31 | ... archive=ubuntu.main_archive, log=logger, ztm=transaction) | ||
232 | 32 | ... transaction.commit() | ||
233 | 33 | ... reconnect_stores('launchpad') | ||
234 | 34 | ... # Get ubuntu, our product, and the sourcepackage name again | ||
235 | 35 | ... # since the transaction changed. | ||
236 | 36 | ... ubuntu = getUtility(ILaunchpadCelebrities).ubuntu | ||
237 | 37 | ... product = getUtility(IProductSet)['bingo'] | ||
238 | 38 | ... spn = getUtility(ISourcePackageNameSet)['bingo'] | ||
239 | 39 | ... login(ANONYMOUS) | ||
240 | 40 | ... return (ubuntu, product, spn) | ||
241 | 41 | |||
242 | 42 | |||
243 | 43 | Let's create a test project. | ||
244 | 44 | |||
245 | 45 | >>> product = factory.makeProduct(name="bingo") | ||
246 | 46 | >>> login_person(product.owner) | ||
247 | 47 | >>> view = create_initialized_view( | ||
248 | 48 | ... product, name="+portlet-packages", | ||
249 | 49 | ... principal=product.owner) | ||
250 | 50 | >>> print view.suggestions | ||
251 | 51 | [] | ||
252 | 52 | |||
253 | 53 | No distribution source packages match so the user is shown an | ||
254 | 54 | appropriate message asking to suggest a match. | ||
255 | 55 | |||
256 | 56 | >>> content = find_tag_by_id(view.render(), 'portlet-packages') | ||
257 | 57 | >>> print extract_text(content) | ||
258 | 58 | All packages | ||
259 | 59 | Packages in Ubuntu | ||
260 | 60 | Launchpad doesn't know which Ubuntu packages this project | ||
261 | 61 | provides. Links from distribution packages to upstream projects | ||
262 | 62 | let distribution and upstream maintainers share bugs, patches, and | ||
263 | 63 | translations efficiently. | ||
264 | 64 | There are no unlinked source packages that are a good match. Can you suggest one? | ||
265 | 65 | Link to Ubuntu package | ||
266 | 66 | |||
267 | 67 | |||
268 | 68 | A distribution source package in a distribution other than ubuntu will | ||
269 | 69 | not be suggested. | ||
270 | 70 | |||
271 | 71 | >>> spn = factory.makeSourcePackageName(name="bingo") | ||
272 | 72 | >>> distro_package = factory.makeDistributionSourcePackage( | ||
273 | 73 | ... sourcepackagename=spn) | ||
274 | 74 | >>> spph = factory.makeSourcePackagePublishingHistory( | ||
275 | 75 | ... sourcepackagename=spn) | ||
276 | 76 | >>> (ubuntu, product, spn) = updateCache() | ||
277 | 77 | >>> view = create_initialized_view( | ||
278 | 78 | ... product, name="+portlet-packages", | ||
279 | 79 | ... principal=product.owner) | ||
280 | 80 | >>> print view.suggestions | ||
281 | 81 | [] | ||
282 | 82 | |||
283 | 83 | An Ubuntu distribution package that is not in the current series | ||
284 | 84 | will be suggested. | ||
285 | 85 | |||
286 | 86 | >>> distro_package = factory.makeDistributionSourcePackage( | ||
287 | 87 | ... sourcepackagename=spn, distribution=ubuntu) | ||
288 | 88 | >>> warty = ubuntu.getSeries('warty') | ||
289 | 89 | >>> warty == ubuntu.currentseries | ||
290 | 90 | False | ||
291 | 91 | >>> spph = factory.makeSourcePackagePublishingHistory( | ||
292 | 92 | ... sourcepackagename=spn, distroseries=warty) | ||
293 | 93 | >>> (ubuntu, product, spn) = updateCache() | ||
294 | 94 | >>> view = create_initialized_view( | ||
295 | 95 | ... product, name="+portlet-packages", | ||
296 | 96 | ... principal=product.owner) | ||
297 | 97 | >>> for dsp in view.suggestions: | ||
298 | 98 | ... print dsp.name | ||
299 | 99 | bingo | ||
300 | 100 | |||
301 | 101 | And the user is presented with a form to select the distribution | ||
302 | 102 | source package. | ||
303 | 103 | |||
304 | 104 | >>> content = find_tag_by_id(view.render(), 'portlet-packages') | ||
305 | 105 | |||
306 | 106 | >>> print extract_text(content) | ||
307 | 107 | All packages | ||
308 | 108 | Packages in Ubuntu | ||
309 | 109 | Launchpad doesn't know which Ubuntu packages this project | ||
310 | 110 | provides. Links from distribution packages to upstream projects | ||
311 | 111 | let distribution and upstream maintainers share bugs, patches, and | ||
312 | 112 | translations efficiently. | ||
313 | 113 | Ubuntu packages: | ||
314 | 114 | bingo... | ||
315 | 115 | |||
316 | 116 | A distribution series with a matching name in the Ubuntu current | ||
317 | 117 | series will be suggested. | ||
318 | 118 | |||
319 | 119 | >>> distro_package = factory.makeDistributionSourcePackage( | ||
320 | 120 | ... sourcepackagename=spn, distribution=ubuntu) | ||
321 | 121 | >>> spph = factory.makeSourcePackagePublishingHistory( | ||
322 | 122 | ... sourcepackagename=spn, distroseries=ubuntu.currentseries) | ||
323 | 123 | >>> (ubuntu, product, spn) = updateCache() | ||
324 | 124 | >>> view = create_initialized_view( | ||
325 | 125 | ... product, name="+portlet-packages", | ||
326 | 126 | ... principal=product.owner) | ||
327 | 127 | >>> for dsp in view.suggestions: | ||
328 | 128 | ... print dsp.name | ||
329 | 129 | bingo | ||
330 | 130 | |||
331 | 131 | If multiple source packages match they will all be displayed. | ||
332 | 132 | |||
333 | 133 | >>> spn = factory.makeSourcePackageName(name="ba-bingo") | ||
334 | 134 | >>> distro_package = factory.makeDistributionSourcePackage( | ||
335 | 135 | ... sourcepackagename=spn, distribution=ubuntu) | ||
336 | 136 | >>> spph = factory.makeSourcePackagePublishingHistory( | ||
337 | 137 | ... sourcepackagename=spn, distroseries=ubuntu.currentseries) | ||
338 | 138 | >>> (ubuntu, product, spn) = updateCache() | ||
339 | 139 | >>> view = create_initialized_view( | ||
340 | 140 | ... product, name="+portlet-packages", | ||
341 | 141 | ... principal=product.owner) | ||
342 | 142 | >>> for dsp in view.suggestions: | ||
343 | 143 | ... print dsp.name | ||
344 | 144 | bingo | ||
345 | 145 | ba-bingo | ||
346 | 146 | |||
347 | 147 | >>> content = find_tag_by_id(view.render(), 'portlet-packages') | ||
348 | 148 | >>> print extract_text(content) | ||
349 | 149 | All packages | ||
350 | 150 | Packages in Ubuntu | ||
351 | 151 | Launchpad doesn't know which Ubuntu packages this project | ||
352 | 152 | provides. Links from distribution packages to upstream projects | ||
353 | 153 | let distribution and upstream maintainers share bugs, patches, and | ||
354 | 154 | translations efficiently. | ||
355 | 155 | Ubuntu packages: | ||
356 | 156 | bingo | ||
357 | 157 | ba-bingo... | ||
358 | 158 | |||
359 | 159 | If a package matches by name but is already linked to an Ubuntu | ||
360 | 160 | package then it will not be shown as one of the suggestions. | ||
361 | 161 | |||
362 | 162 | >>> new_product = factory.makeProduct(name="not-bingo") | ||
363 | 163 | >>> product_series = new_product.development_focus | ||
364 | 164 | >>> babingo_spn = getUtility(ISourcePackageNameSet)['ba-bingo'] | ||
365 | 165 | >>> pkg = product_series.setPackaging( | ||
366 | 166 | ... ubuntu.currentseries, | ||
367 | 167 | ... babingo_spn, product.owner) | ||
368 | 168 | >>> (ubuntu, product, spn) = updateCache() | ||
369 | 169 | >>> view = create_initialized_view( | ||
370 | 170 | ... product, name="+portlet-packages", | ||
371 | 171 | ... principal=product.owner) | ||
372 | 172 | >>> for dsp in view.suggestions: | ||
373 | 173 | ... print dsp.name | ||
374 | 174 | bingo | ||
375 | 0 | 175 | ||
376 | === modified file 'lib/lp/registry/browser/tests/product-views.txt' | |||
377 | --- lib/lp/registry/browser/tests/product-views.txt 2010-02-17 11:19:42 +0000 | |||
378 | +++ lib/lp/registry/browser/tests/product-views.txt 2010-03-06 12:18:33 +0000 | |||
379 | @@ -478,3 +478,78 @@ | |||
380 | 478 | portlet-latest-bugs | 478 | portlet-latest-bugs |
381 | 479 | >>> print find_tag_by_id(content, 'portlet-blueprints')['id'] | 479 | >>> print find_tag_by_id(content, 'portlet-blueprints')['id'] |
382 | 480 | portlet-blueprints | 480 | portlet-blueprints |
383 | 481 | |||
384 | 482 | |||
385 | 483 | +portlet-packages | ||
386 | 484 | ----------------- | ||
387 | 485 | |||
388 | 486 | When the product is not linked to a source package in Ubuntu the | ||
389 | 487 | +portlet-packages will show suggestions on potential matches and ask | ||
390 | 488 | the user to make the connection. | ||
391 | 489 | |||
392 | 490 | >>> product = factory.makeProduct(name="bingo") | ||
393 | 491 | >>> login_person(product.owner) | ||
394 | 492 | >>> view = create_initialized_view( | ||
395 | 493 | ... product, name="+portlet-packages", | ||
396 | 494 | ... principal=product.owner) | ||
397 | 495 | >>> print view.suggestions | ||
398 | 496 | [] | ||
399 | 497 | |||
400 | 498 | >>> content = find_tag_by_id(view.render(), 'portlet-packages') | ||
401 | 499 | >>> print extract_text(content) | ||
402 | 500 | All packages | ||
403 | 501 | Packages in Ubuntu | ||
404 | 502 | Launchpad doesn't know which Ubuntu packages this project | ||
405 | 503 | provides. Links from distribution packages to upstream projects | ||
406 | 504 | let distribution and upstream maintainers share bugs, patches, and | ||
407 | 505 | translations efficiently. | ||
408 | 506 | There are no unlinked source packages that are a good match. | ||
409 | 507 | Can you suggest one? | ||
410 | 508 | Link to Ubuntu package | ||
411 | 509 | |||
412 | 510 | >>> spn = factory.makeSourcePackageName(name="bingo") | ||
413 | 511 | >>> from canonical.launchpad.interfaces.launchpad import ( | ||
414 | 512 | ... ILaunchpadCelebrities) | ||
415 | 513 | >>> ubuntu = getUtility(ILaunchpadCelebrities).ubuntu | ||
416 | 514 | >>> distro_package = factory.makeDistributionSourcePackage( | ||
417 | 515 | ... sourcepackagename=spn, distribution=ubuntu) | ||
418 | 516 | >>> spph = factory.makeSourcePackagePublishingHistory( | ||
419 | 517 | ... sourcepackagename=spn, distroseries=ubuntu.currentseries) | ||
420 | 518 | |||
421 | 519 | >>> view = create_initialized_view( | ||
422 | 520 | ... product, name="+portlet-packages", | ||
423 | 521 | ... principal=product.owner) | ||
424 | 522 | >>> print view.suggestions | ||
425 | 523 | [] | ||
426 | 524 | |||
427 | 525 | >>> distro_package = factory.makeDistributionSourcePackage( | ||
428 | 526 | ... sourcepackagename=spn, distribution=ubuntu) | ||
429 | 527 | |||
430 | 528 | >>> view = create_initialized_view( | ||
431 | 529 | ... product, name="+portlet-packages", | ||
432 | 530 | ... principal=product.owner) | ||
433 | 531 | >>> print view.suggestions | ||
434 | 532 | [] | ||
435 | 533 | |||
436 | 534 | >>> import transaction | ||
437 | 535 | >>> #transaction.commit() | ||
438 | 536 | >>> from canonical.launchpad.scripts import QuietFakeLogger | ||
439 | 537 | >>> logger = QuietFakeLogger() | ||
440 | 538 | >>> from canonical.testing.layers import reconnect_stores | ||
441 | 539 | >>> from canonical.config import config | ||
442 | 540 | >>> # Switch to the statistician user who is the only user with | ||
443 | 541 | >>> # write permission to the source package cache tables. | ||
444 | 542 | >>> reconnect_stores(config.statistician.dbuser) | ||
445 | 543 | >>> # LaunchpadZopelessLayer.switchDbUser(config.statistician.dbuser) | ||
446 | 544 | >>> ubuntu = getUtility(ILaunchpadCelebrities).ubuntu | ||
447 | 545 | >>> updated = ubuntu.updateCompleteSourcePackageCache( | ||
448 | 546 | ... archive=ubuntu.main_archive, log=logger, ztm=transaction) | ||
449 | 547 | >>> transaction.commit() | ||
450 | 548 | >>> reconnect_stores('launchpad') | ||
451 | 549 | >>> login(ANONYMOUS) | ||
452 | 550 | >>> product = getUtility(IProductSet)['bingo'] | ||
453 | 551 | >>> view = create_initialized_view( | ||
454 | 552 | ... product, name="+portlet-packages", | ||
455 | 553 | ... principal=product.owner) | ||
456 | 554 | >>> print view.suggestions | ||
457 | 555 | [] | ||
458 | 481 | 556 | ||
459 | === modified file 'lib/lp/registry/model/distributionsourcepackage.py' | |||
460 | --- lib/lp/registry/model/distributionsourcepackage.py 2010-02-27 20:20:03 +0000 | |||
461 | +++ lib/lp/registry/model/distributionsourcepackage.py 2010-03-06 12:18:33 +0000 | |||
462 | @@ -187,7 +187,7 @@ | |||
463 | 187 | PackagePublishingStatus.PUBLISHED, | 187 | PackagePublishingStatus.PUBLISHED, |
464 | 188 | PackagePublishingStatus.OBSOLETE), | 188 | PackagePublishingStatus.OBSOLETE), |
465 | 189 | clauseTables=["SourcePackagePublishingHistory", | 189 | clauseTables=["SourcePackagePublishingHistory", |
467 | 190 | "SourcePackageRelease", | 190 | "SourcePackageRelease", |
468 | 191 | "DistroSeries"], | 191 | "DistroSeries"], |
469 | 192 | orderBy=["status", | 192 | orderBy=["status", |
470 | 193 | SQLConstant( | 193 | SQLConstant( |
471 | @@ -319,6 +319,7 @@ | |||
472 | 319 | self.sourcepackagename) | 319 | self.sourcepackagename) |
473 | 320 | if source_package.direct_packaging is not None: | 320 | if source_package.direct_packaging is not None: |
474 | 321 | return source_package.direct_packaging.productseries.product | 321 | return source_package.direct_packaging.productseries.product |
475 | 322 | return None | ||
476 | 322 | 323 | ||
477 | 323 | # XXX kiko 2006-08-16: Bad method name, no need to be a property. | 324 | # XXX kiko 2006-08-16: Bad method name, no need to be a property. |
478 | 324 | @property | 325 | @property |
479 | 325 | 326 | ||
480 | === modified file 'lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt' | |||
481 | --- lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt 2010-02-18 20:41:01 +0000 | |||
482 | +++ lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt 2010-03-06 12:18:33 +0000 | |||
483 | @@ -1,13 +1,13 @@ | |||
484 | 1 | = Packaging = | 1 | = Packaging = |
485 | 2 | 2 | ||
487 | 3 | No Privileges Person visit the distroseries upstream linkes page for Hoary | 3 | No Privileges Person visit the distroseries upstream links page for Hoary |
488 | 4 | and sees that pmount is not linked. | 4 | and sees that pmount is not linked. |
489 | 5 | 5 | ||
490 | 6 | >>> user_browser.open( | 6 | >>> user_browser.open( |
491 | 7 | ... 'http://launchpad.dev/ubuntu/hoary/+needs-packaging') | 7 | ... 'http://launchpad.dev/ubuntu/hoary/+needs-packaging') |
492 | 8 | >>> print extract_text(find_tag_by_id(user_browser.contents, 'packages')) | 8 | >>> print extract_text(find_tag_by_id(user_browser.contents, 'packages')) |
495 | 9 | Source Package Bugs Translations | 9 | Source Package Bugs Translations |
496 | 10 | pmount No bugs 64 strings ... | 10 | pmount No bugs 64 strings ... |
497 | 11 | 11 | ||
498 | 12 | He looks at the pmount source package page in Hoary and reads that the | 12 | He looks at the pmount source package page in Hoary and reads that the |
499 | 13 | upstream project is not set. | 13 | upstream project is not set. |
500 | 14 | 14 | ||
501 | === modified file 'lib/lp/registry/stories/product/xx-product-index.txt' | |||
502 | --- lib/lp/registry/stories/product/xx-product-index.txt 2009-10-30 15:40:55 +0000 | |||
503 | +++ lib/lp/registry/stories/product/xx-product-index.txt 2010-03-06 12:18:33 +0000 | |||
504 | @@ -348,3 +348,36 @@ | |||
505 | 348 | >>> anon_browser.open('http://launchpad.dev/firefox') | 348 | >>> anon_browser.open('http://launchpad.dev/firefox') |
506 | 349 | >>> print extract_text(find_tag_by_id(anon_browser.contents, 'aliases')) | 349 | >>> print extract_text(find_tag_by_id(anon_browser.contents, 'aliases')) |
507 | 350 | Also known as: iceweasel, snowchicken | 350 | Also known as: iceweasel, snowchicken |
508 | 351 | |||
509 | 352 | |||
510 | 353 | Ubuntu packaging | ||
511 | 354 | ---------------- | ||
512 | 355 | |||
513 | 356 | If a product is packaged in Ubuntu the links are shown. | ||
514 | 357 | |||
515 | 358 | >>> user_browser.open('http://launchpad.dev/firefox') | ||
516 | 359 | >>> print extract_text( | ||
517 | 360 | ... find_tag_by_id(user_browser.contents, 'portlet-packages')) | ||
518 | 361 | All packages | ||
519 | 362 | Packages in distributions | ||
520 | 363 | “mozilla-firefox” source package in Hoary | ||
521 | 364 | “mozilla-firefox” source package in Warty Version 0.9 uploaded on... | ||
522 | 365 | |||
523 | 366 | A product that has linked packages now displays suggestions and asks | ||
524 | 367 | the user to select the package. | ||
525 | 368 | |||
526 | 369 | >>> login(ANONYMOUS) | ||
527 | 370 | >>> product = factory.makeProduct(name='pmount') | ||
528 | 371 | >>> logout() | ||
529 | 372 | >>> user_browser.open('http://launchpad.dev/pmount') | ||
530 | 373 | >>> print extract_text( | ||
531 | 374 | ... find_tag_by_id(user_browser.contents, 'portlet-packages')) | ||
532 | 375 | All packages... | ||
533 | 376 | Packages in Ubuntu... | ||
534 | 377 | Ubuntu packages: | ||
535 | 378 | pmount... | ||
536 | 379 | |||
537 | 380 | >>> user_browser.getControl(name='field.distributionsourcepackage').value = ['pmount'] | ||
538 | 381 | >>> user_browser.getControl('Link to this Ubuntu Package').click() | ||
539 | 382 | >>> print_feedback_messages(user_browser.contents) | ||
540 | 383 | This project was linked to the source package "pmount in ubuntu" | ||
541 | 351 | 384 | ||
542 | === modified file 'lib/lp/registry/templates/product-portlet-packages.pt' | |||
543 | --- lib/lp/registry/templates/product-portlet-packages.pt 2009-09-05 03:17:24 +0000 | |||
544 | +++ lib/lp/registry/templates/product-portlet-packages.pt 2010-03-06 12:18:33 +0000 | |||
545 | @@ -3,32 +3,71 @@ | |||
546 | 3 | xmlns:metal="http://xml.zope.org/namespaces/metal" | 3 | xmlns:metal="http://xml.zope.org/namespaces/metal" |
547 | 4 | xmlns:i18n="http://xml.zope.org/namespaces/i18n" | 4 | xmlns:i18n="http://xml.zope.org/namespaces/i18n" |
548 | 5 | omit-tag="" | 5 | omit-tag="" |
551 | 6 | define="packages context/sourcepackages" | 6 | define="packages context/sourcepackages"> |
552 | 7 | condition="packages"> | 7 | |
553 | 8 | <div class="portlet" id="portlet-packages"> | 8 | <div class="portlet" id="portlet-packages"> |
578 | 9 | <h2> | 9 | |
579 | 10 | <span class="see-all"><a | 10 | <tal:has_packages condition="packages"> |
580 | 11 | tal:attributes="href context/menu:overview/packages/fmt:url">All | 11 | <h2> |
581 | 12 | packages</a></span> | 12 | <span class="see-all"><a |
582 | 13 | Packages in distributions | 13 | tal:attributes="href context/menu:overview/packages/fmt:url">All |
583 | 14 | </h2> | 14 | packages</a></span> |
584 | 15 | 15 | Packages in distributions | |
585 | 16 | <ul> | 16 | </h2> |
586 | 17 | <tal:pair tal:repeat="package packages"> | 17 | |
587 | 18 | <li> | 18 | <ul> |
588 | 19 | <a class="sprite package-source" | 19 | <tal:pair tal:repeat="package packages"> |
589 | 20 | tal:attributes="href package/fmt:url" | 20 | <li> |
590 | 21 | tal:content="package/title">apache in ubuntu hoary</a> | 21 | <a class="sprite package-source" |
591 | 22 | <br /> | 22 | tal:attributes="href package/fmt:url" |
592 | 23 | <span class="registered" | 23 | tal:content="package/title">apache in ubuntu hoary</a> |
593 | 24 | tal:define="release package/currentrelease" | 24 | <br /> |
594 | 25 | tal:condition="release"> | 25 | <span class="registered" |
595 | 26 | <strong>Version | 26 | tal:define="release package/currentrelease" |
596 | 27 | <tal:version content="release/version">2.3</tal:version></strong> | 27 | tal:condition="release"> |
597 | 28 | uploaded <tal:date replace="release/dateuploaded/fmt:displaydate" /> | 28 | <strong>Version |
598 | 29 | </span> | 29 | <tal:version content="release/version">2.3</tal:version></strong> |
599 | 30 | </li> | 30 | uploaded <tal:date replace="release/dateuploaded/fmt:displaydate" /> |
600 | 31 | </tal:pair> | 31 | </span> |
601 | 32 | </ul> | 32 | </li> |
602 | 33 | </tal:pair> | ||
603 | 34 | </ul> | ||
604 | 35 | </tal:has_packages> | ||
605 | 36 | |||
606 | 37 | <tal:has_no_packages condition="not:packages"> | ||
607 | 38 | <h2> | ||
608 | 39 | <span class="see-all"><a | ||
609 | 40 | tal:attributes="href context/menu:overview/packages/fmt:url">All | ||
610 | 41 | packages</a></span> | ||
611 | 42 | Packages in Ubuntu | ||
612 | 43 | </h2> | ||
613 | 44 | |||
614 | 45 | <p> | ||
615 | 46 | Launchpad doesn't know which Ubuntu packages this project | ||
616 | 47 | provides. Links from distribution packages to upstream projects | ||
617 | 48 | let distribution and upstream maintainers share bugs, patches, and | ||
618 | 49 | translations efficiently. | ||
619 | 50 | </p> | ||
620 | 51 | <div id="suggestions" tal:condition="view/suggestions"> | ||
621 | 52 | <div metal:use-macro="context/@@launchpad_form/form"> | ||
622 | 53 | <div class="actions" metal:fill-slot="buttons"> | ||
623 | 54 | <input tal:replace="structure view/link/render"/> | ||
624 | 55 | or | ||
625 | 56 | <a tal:replace="structure | ||
626 | 57 | context/development_focus/menu:overview/ubuntupkg/fmt:link" /> | ||
627 | 58 | </div> | ||
628 | 59 | </div> | ||
629 | 60 | </div> | ||
630 | 61 | |||
631 | 62 | <div id="suggestions" tal:condition="not:view/suggestions"> | ||
632 | 63 | <p> | ||
633 | 64 | There are no unlinked source packages that are a good match. | ||
634 | 65 | Can you suggest one? | ||
635 | 66 | </p> | ||
636 | 67 | <a tal:replace="structure | ||
637 | 68 | context/development_focus/menu:overview/ubuntupkg/fmt:link" /> | ||
638 | 69 | </div> | ||
639 | 70 | |||
640 | 71 | </tal:has_no_packages> | ||
641 | 33 | </div> | 72 | </div> |
642 | 34 | </tal:root> | 73 | </tal:root> |
643 | 35 | 74 | ||
644 | === modified file 'lib/lp/registry/tests/test_doc_product.py' | |||
645 | --- lib/lp/registry/tests/test_doc_product.py 2009-06-30 16:56:07 +0000 | |||
646 | +++ lib/lp/registry/tests/test_doc_product.py 2010-03-06 12:18:33 +0000 | |||
647 | @@ -3,7 +3,7 @@ | |||
648 | 3 | 3 | ||
649 | 4 | """Test the doctests in the product module.""" | 4 | """Test the doctests in the product module.""" |
650 | 5 | 5 | ||
652 | 6 | # XXX sinzui 2009-04-03 bug=354881: This test harness shold be removed | 6 | # XXX sinzui 2009-04-03 bug=354881: This test harness should be removed |
653 | 7 | # and the inline tests moved to docs/ | 7 | # and the inline tests moved to docs/ |
654 | 8 | 8 | ||
655 | 9 | __metaclass__ = type | 9 | __metaclass__ = type |
= Summary =
Change the packaging portlet on the product index page to suggest Ubuntu packages
that may be potential matches if the product is not currently linked.
== Proposed fix ==
Create a new view to query ubuntu. searchSourcePac kages and show the results in the
portlet.
== Pre-implementation notes ==
Chats with Curtis.
== Implementation details ==
As above.
== Tests ==
bin/test -vvm lp.registry -t product- portlet- packages- view.txt \ index.txt
-t xx-product-
== Demo and Q/A ==
In launchpad.dev create a product called pmount. Visit https:/ /launchpad. dev/pmount
and see that the pmount package in the sample data is suggested. Make the link and
then marvel that it is shown on the product's index page.
= Launchpad lint =
Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.
Linting changed files: registry/ browser/ configure. zcml registry/ stories/ packaging/ xx-sourcepackag e-packaging. txt registry/ browser/ product. py registry/ browser/ tests/product- views.txt registry/ browser/ tests/product- portlet- packages- view.txt registry/ templates/ product- portlet- packages. pt registry/ tests/test_ doc_product. py registry/ stories/ product/ xx-product- index.txt
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
== Pylint notices ==
lib/lp/ registry/ browser/ product. py
59: [F0401] Unable to import 'lazr.delegates' (No module named delegates)