Merge lp:~bac/launchpad/bug-512408 into lp:launchpad

Proposed by Brad Crittenden
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
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.

To post a comment you must log in.
Revision history for this message
Brad Crittenden (bac) wrote :

= 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.searchSourcePackages 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 \
   -t xx-product-index.txt

== 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:
  lib/lp/registry/browser/configure.zcml
  lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt
  lib/lp/registry/browser/product.py
  lib/lp/registry/browser/tests/product-views.txt
  lib/lp/registry/browser/tests/product-portlet-packages-view.txt
  lib/lp/registry/templates/product-portlet-packages.pt
  lib/lp/registry/tests/test_doc_product.py
  lib/lp/registry/stories/product/xx-product-index.txt

== Pylint notices ==

lib/lp/registry/browser/product.py
    59: [F0401] Unable to import 'lazr.delegates' (No module named delegates)

Revision history for this message
Aaron Bentley (abentley) :
review: Approve
Revision history for this message
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.

review: Approve (ui)
Revision history for this message
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.

Diff @ http://pastebin.ubuntu.com/386572/

Revision history for this message
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.

review: Approve (code + ui)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/testing/pages.py'
--- lib/canonical/launchpad/testing/pages.py 2010-02-24 23:18:40 +0000
+++ lib/canonical/launchpad/testing/pages.py 2010-03-06 12:18:33 +0000
@@ -14,7 +14,6 @@
14import pprint14import pprint
15import re15import re
16import transaction16import transaction
17import sys
18import unittest17import unittest
1918
20from BeautifulSoup import (19from BeautifulSoup import (
@@ -34,7 +33,7 @@
34 IOAuthConsumerSet, OAUTH_REALM, ILaunchpadCelebrities,33 IOAuthConsumerSet, OAUTH_REALM, ILaunchpadCelebrities,
35 TeamMembershipStatus)34 TeamMembershipStatus)
36from canonical.launchpad.testing.systemdocs import (35from canonical.launchpad.testing.systemdocs import (
37 LayeredDocFileSuite, SpecialOutputChecker, strip_prefix)36 LayeredDocFileSuite, SpecialOutputChecker, stop, strip_prefix)
38from canonical.launchpad.webapp import canonical_url37from canonical.launchpad.webapp import canonical_url
39from canonical.launchpad.webapp.interfaces import OAuthPermission38from canonical.launchpad.webapp.interfaces import OAuthPermission
40from canonical.launchpad.webapp.url import urlsplit39from canonical.launchpad.webapp.url import urlsplit
@@ -715,16 +714,6 @@
715 return setupBrowser(auth='Basic re@ex.com:test')714 return setupBrowser(auth='Basic re@ex.com:test')
716715
717716
718def stop():
719 # Temporarily restore the real stdout.
720 old_stdout = sys.stdout
721 sys.stdout = sys.__stdout__
722 try:
723 pdb.set_trace()
724 finally:
725 sys.stdout = old_stdout
726
727
728def setUpGlobs(test):717def setUpGlobs(test):
729 test.globs['transaction'] = transaction718 test.globs['transaction'] = transaction
730 test.globs['http'] = UnstickyCookieHTTPCaller()719 test.globs['http'] = UnstickyCookieHTTPCaller()
731720
=== modified file 'lib/canonical/launchpad/testing/systemdocs.py'
--- lib/canonical/launchpad/testing/systemdocs.py 2009-10-15 11:47:32 +0000
+++ lib/canonical/launchpad/testing/systemdocs.py 2010-03-06 12:18:33 +0000
@@ -10,12 +10,14 @@
10 'SpecialOutputChecker',10 'SpecialOutputChecker',
11 'setUp',11 'setUp',
12 'setGlobs',12 'setGlobs',
13 'stop',
13 'strip_prefix',14 'strip_prefix',
14 'tearDown',15 'tearDown',
15 ]16 ]
1617
17import logging18import logging
18import os19import os
20import pdb
19import pprint21import pprint
20import sys22import sys
2123
@@ -170,6 +172,16 @@
170 "%r: %r" % (key, value) for key, value in sorted(dict.items()))172 "%r: %r" % (key, value) for key, value in sorted(dict.items()))
171173
172174
175def stop():
176 # Temporarily restore the real stdout.
177 old_stdout = sys.stdout
178 sys.stdout = sys.__stdout__
179 try:
180 pdb.set_trace()
181 finally:
182 sys.stdout = old_stdout
183
184
173def setGlobs(test):185def setGlobs(test):
174 """Add the common globals for testing system documentation."""186 """Add the common globals for testing system documentation."""
175 test.globs['ANONYMOUS'] = ANONYMOUS187 test.globs['ANONYMOUS'] = ANONYMOUS
@@ -186,6 +198,7 @@
186 test.globs['ordered_dict_as_string'] = ordered_dict_as_string198 test.globs['ordered_dict_as_string'] = ordered_dict_as_string
187 test.globs['verifyObject'] = verifyObject199 test.globs['verifyObject'] = verifyObject
188 test.globs['pretty'] = pprint.PrettyPrinter(width=1).pformat200 test.globs['pretty'] = pprint.PrettyPrinter(width=1).pformat
201 test.globs['stop'] = stop
189202
190203
191def setUp(test):204def setUp(test):
192205
=== modified file 'lib/lp/registry/browser/configure.zcml'
--- lib/lp/registry/browser/configure.zcml 2010-03-05 14:18:18 +0000
+++ lib/lp/registry/browser/configure.zcml 2010-03-06 12:18:33 +0000
@@ -1412,15 +1412,18 @@
1412 facet="overview"1412 facet="overview"
1413 template="../templates/product-portlet-license-missing.pt"/>1413 template="../templates/product-portlet-license-missing.pt"/>
1414 <browser:page1414 <browser:page
1415 name="+portlet-packages"
1416 facet="overview"
1417 template="../templates/product-portlet-packages.pt"/>
1418 <browser:page
1419 name="+purchase-subscription"1415 name="+purchase-subscription"
1420 template="../templates/product-purchase-subscription.pt"/>1416 template="../templates/product-purchase-subscription.pt"/>
1421 </browser:pages>1417 </browser:pages>
1422 <browser:page1418 <browser:page
1423 for="lp.registry.interfaces.product.IProduct"1419 for="lp.registry.interfaces.product.IProduct"
1420 permission="zope.Public"
1421 name="+portlet-packages"
1422 facet="overview"
1423 class="lp.registry.browser.product.ProductPackagesPortletView"
1424 template="../templates/product-portlet-packages.pt"/>
1425 <browser:page
1426 for="lp.registry.interfaces.product.IProduct"
1424 class="lp.registry.browser.product.ProductSeriesView"1427 class="lp.registry.browser.product.ProductSeriesView"
1425 name="+series"1428 name="+series"
1426 facet="overview"1429 facet="overview"
14271430
=== modified file 'lib/lp/registry/browser/product.py'
--- lib/lp/registry/browser/product.py 2010-02-16 21:21:14 +0000
+++ lib/lp/registry/browser/product.py 2010-03-06 12:18:33 +0000
@@ -21,6 +21,7 @@
21 'ProductNavigationMenu',21 'ProductNavigationMenu',
22 'ProductOverviewMenu',22 'ProductOverviewMenu',
23 'ProductPackagesView',23 'ProductPackagesView',
24 'ProductPackagesPortletView',
24 'ProductRdfView',25 'ProductRdfView',
25 'ProductReviewLicenseView',26 'ProductReviewLicenseView',
26 'ProductSeriesView',27 'ProductSeriesView',
@@ -37,6 +38,7 @@
37 ]38 ]
3839
3940
41from cgi import escape
40from operator import attrgetter42from operator import attrgetter
4143
42from zope.component import getUtility44from zope.component import getUtility
@@ -45,6 +47,9 @@
45from zope.lifecycleevent import ObjectCreatedEvent47from zope.lifecycleevent import ObjectCreatedEvent
46from zope.interface import implements, Interface48from zope.interface import implements, Interface
47from zope.formlib import form49from zope.formlib import form
50from zope.schema import Choice
51from zope.schema.vocabulary import (
52 SimpleVocabulary, SimpleTerm)
4853
49from z3c.ptcompat import ViewPageTemplateFile54from z3c.ptcompat import ViewPageTemplateFile
5055
@@ -981,6 +986,56 @@
981 return results986 return results
982987
983988
989class ProductPackagesPortletView(LaunchpadFormView):
990 """View class for product packaging portlet."""
991
992 schema = Interface
993 custom_widget(
994 'distributionsourcepackage', LaunchpadRadioWidget,
995 orientation='vertical')
996 suggestions = None
997
998 def setUpFields(self):
999 """See `LaunchpadFormView`."""
1000 super(ProductPackagesPortletView, self).setUpFields()
1001 ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
1002 source_packages = ubuntu.searchSourcePackages(self.context.name)
1003 # Based upon the matches, create a new vocabulary with
1004 # term descriptions that include a link to the source package.
1005 self.suggestions = []
1006 vocab_terms = []
1007 for package in source_packages:
1008 if package.upstream_product is not None:
1009 continue
1010 self.suggestions.append(package)
1011 item_url = canonical_url(package)
1012 description = """<a href="%s">%s</a>""" % (
1013 item_url, escape(package.name))
1014 vocab_terms.append(SimpleTerm(package, package.name, description))
1015 vocabulary = SimpleVocabulary(vocab_terms)
1016 self.form_fields = form.Fields(
1017 Choice(__name__='distributionsourcepackage',
1018 title=_('Ubuntu packages'),
1019 default=None,
1020 vocabulary=vocabulary,
1021 required=True))
1022
1023 @action(_('Link to this Ubuntu Package'), name='link')
1024 def link(self, action, data):
1025 product = self.context
1026 dsp = data.get('distributionsourcepackage')
1027 assert dsp is not None, "distributionsourcepackage was not specified"
1028 product_series = product.development_focus
1029 ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
1030 product_series.setPackaging(ubuntu.currentseries,
1031 dsp.sourcepackagename,
1032 self.user)
1033 self.request.response.addInfoNotification(
1034 'This project was linked to the source package "%s"' %
1035 dsp.displayname)
1036 self.next_url = self.request.getURL()
1037
1038
984class SeriesReleasePair:1039class SeriesReleasePair:
985 """Class for holding a series and release.1040 """Class for holding a series and release.
9861041
9871042
=== added file 'lib/lp/registry/browser/tests/product-portlet-packages-view.txt'
--- lib/lp/registry/browser/tests/product-portlet-packages-view.txt 1970-01-01 00:00:00 +0000
+++ lib/lp/registry/browser/tests/product-portlet-packages-view.txt 2010-03-06 12:18:33 +0000
@@ -0,0 +1,174 @@
1+portlet-packages
2-----------------
3
4When the product is not linked to a source package in Ubuntu the
5+portlet-packages will show suggestions on potential matches and ask
6the user to make the connection.
7
8Create a helper to update the distribution source package cache, which
9does not happen automatically.
10
11 >>> from canonical.launchpad.testing.pages import find_tag_by_id
12 >>> from canonical.launchpad.testing.pages import extract_text
13 >>> from canonical.launchpad.interfaces.launchpad import (
14 ... ILaunchpadCelebrities)
15 >>> from lp.registry.interfaces.product import IProductSet
16 >>> from lp.registry.interfaces.sourcepackagename import (
17 ... ISourcePackageNameSet)
18
19 >>> import transaction
20 >>> from canonical.launchpad.scripts import QuietFakeLogger
21 >>> logger = QuietFakeLogger()
22 >>> from canonical.testing.layers import reconnect_stores
23 >>> from canonical.config import config
24 >>> def updateCache():
25 ... # Switch to the statistician user who is the only user with
26 ... # write permission to the source package cache tables.
27 ... transaction.commit()
28 ... reconnect_stores(config.statistician.dbuser)
29 ... ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
30 ... updated = ubuntu.updateCompleteSourcePackageCache(
31 ... archive=ubuntu.main_archive, log=logger, ztm=transaction)
32 ... transaction.commit()
33 ... reconnect_stores('launchpad')
34 ... # Get ubuntu, our product, and the sourcepackage name again
35 ... # since the transaction changed.
36 ... ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
37 ... product = getUtility(IProductSet)['bingo']
38 ... spn = getUtility(ISourcePackageNameSet)['bingo']
39 ... login(ANONYMOUS)
40 ... return (ubuntu, product, spn)
41
42
43Let's create a test project.
44
45 >>> product = factory.makeProduct(name="bingo")
46 >>> login_person(product.owner)
47 >>> view = create_initialized_view(
48 ... product, name="+portlet-packages",
49 ... principal=product.owner)
50 >>> print view.suggestions
51 []
52
53No distribution source packages match so the user is shown an
54appropriate message asking to suggest a match.
55
56 >>> content = find_tag_by_id(view.render(), 'portlet-packages')
57 >>> print extract_text(content)
58 All packages
59 Packages in Ubuntu
60 Launchpad doesn't know which Ubuntu packages this project
61 provides. Links from distribution packages to upstream projects
62 let distribution and upstream maintainers share bugs, patches, and
63 translations efficiently.
64 There are no unlinked source packages that are a good match. Can you suggest one?
65 Link to Ubuntu package
66
67
68A distribution source package in a distribution other than ubuntu will
69not be suggested.
70
71 >>> spn = factory.makeSourcePackageName(name="bingo")
72 >>> distro_package = factory.makeDistributionSourcePackage(
73 ... sourcepackagename=spn)
74 >>> spph = factory.makeSourcePackagePublishingHistory(
75 ... sourcepackagename=spn)
76 >>> (ubuntu, product, spn) = updateCache()
77 >>> view = create_initialized_view(
78 ... product, name="+portlet-packages",
79 ... principal=product.owner)
80 >>> print view.suggestions
81 []
82
83An Ubuntu distribution package that is not in the current series
84will be suggested.
85
86 >>> distro_package = factory.makeDistributionSourcePackage(
87 ... sourcepackagename=spn, distribution=ubuntu)
88 >>> warty = ubuntu.getSeries('warty')
89 >>> warty == ubuntu.currentseries
90 False
91 >>> spph = factory.makeSourcePackagePublishingHistory(
92 ... sourcepackagename=spn, distroseries=warty)
93 >>> (ubuntu, product, spn) = updateCache()
94 >>> view = create_initialized_view(
95 ... product, name="+portlet-packages",
96 ... principal=product.owner)
97 >>> for dsp in view.suggestions:
98 ... print dsp.name
99 bingo
100
101And the user is presented with a form to select the distribution
102source package.
103
104 >>> content = find_tag_by_id(view.render(), 'portlet-packages')
105
106 >>> print extract_text(content)
107 All packages
108 Packages in Ubuntu
109 Launchpad doesn't know which Ubuntu packages this project
110 provides. Links from distribution packages to upstream projects
111 let distribution and upstream maintainers share bugs, patches, and
112 translations efficiently.
113 Ubuntu packages:
114 bingo...
115
116A distribution series with a matching name in the Ubuntu current
117series will be suggested.
118
119 >>> distro_package = factory.makeDistributionSourcePackage(
120 ... sourcepackagename=spn, distribution=ubuntu)
121 >>> spph = factory.makeSourcePackagePublishingHistory(
122 ... sourcepackagename=spn, distroseries=ubuntu.currentseries)
123 >>> (ubuntu, product, spn) = updateCache()
124 >>> view = create_initialized_view(
125 ... product, name="+portlet-packages",
126 ... principal=product.owner)
127 >>> for dsp in view.suggestions:
128 ... print dsp.name
129 bingo
130
131If multiple source packages match they will all be displayed.
132
133 >>> spn = factory.makeSourcePackageName(name="ba-bingo")
134 >>> distro_package = factory.makeDistributionSourcePackage(
135 ... sourcepackagename=spn, distribution=ubuntu)
136 >>> spph = factory.makeSourcePackagePublishingHistory(
137 ... sourcepackagename=spn, distroseries=ubuntu.currentseries)
138 >>> (ubuntu, product, spn) = updateCache()
139 >>> view = create_initialized_view(
140 ... product, name="+portlet-packages",
141 ... principal=product.owner)
142 >>> for dsp in view.suggestions:
143 ... print dsp.name
144 bingo
145 ba-bingo
146
147 >>> content = find_tag_by_id(view.render(), 'portlet-packages')
148 >>> print extract_text(content)
149 All packages
150 Packages in Ubuntu
151 Launchpad doesn't know which Ubuntu packages this project
152 provides. Links from distribution packages to upstream projects
153 let distribution and upstream maintainers share bugs, patches, and
154 translations efficiently.
155 Ubuntu packages:
156 bingo
157 ba-bingo...
158
159If a package matches by name but is already linked to an Ubuntu
160package then it will not be shown as one of the suggestions.
161
162 >>> new_product = factory.makeProduct(name="not-bingo")
163 >>> product_series = new_product.development_focus
164 >>> babingo_spn = getUtility(ISourcePackageNameSet)['ba-bingo']
165 >>> pkg = product_series.setPackaging(
166 ... ubuntu.currentseries,
167 ... babingo_spn, product.owner)
168 >>> (ubuntu, product, spn) = updateCache()
169 >>> view = create_initialized_view(
170 ... product, name="+portlet-packages",
171 ... principal=product.owner)
172 >>> for dsp in view.suggestions:
173 ... print dsp.name
174 bingo
0175
=== modified file 'lib/lp/registry/browser/tests/product-views.txt'
--- lib/lp/registry/browser/tests/product-views.txt 2010-02-17 11:19:42 +0000
+++ lib/lp/registry/browser/tests/product-views.txt 2010-03-06 12:18:33 +0000
@@ -478,3 +478,78 @@
478 portlet-latest-bugs478 portlet-latest-bugs
479 >>> print find_tag_by_id(content, 'portlet-blueprints')['id']479 >>> print find_tag_by_id(content, 'portlet-blueprints')['id']
480 portlet-blueprints480 portlet-blueprints
481
482
483+portlet-packages
484-----------------
485
486When the product is not linked to a source package in Ubuntu the
487+portlet-packages will show suggestions on potential matches and ask
488the user to make the connection.
489
490 >>> product = factory.makeProduct(name="bingo")
491 >>> login_person(product.owner)
492 >>> view = create_initialized_view(
493 ... product, name="+portlet-packages",
494 ... principal=product.owner)
495 >>> print view.suggestions
496 []
497
498 >>> content = find_tag_by_id(view.render(), 'portlet-packages')
499 >>> print extract_text(content)
500 All packages
501 Packages in Ubuntu
502 Launchpad doesn't know which Ubuntu packages this project
503 provides. Links from distribution packages to upstream projects
504 let distribution and upstream maintainers share bugs, patches, and
505 translations efficiently.
506 There are no unlinked source packages that are a good match.
507 Can you suggest one?
508 Link to Ubuntu package
509
510 >>> spn = factory.makeSourcePackageName(name="bingo")
511 >>> from canonical.launchpad.interfaces.launchpad import (
512 ... ILaunchpadCelebrities)
513 >>> ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
514 >>> distro_package = factory.makeDistributionSourcePackage(
515 ... sourcepackagename=spn, distribution=ubuntu)
516 >>> spph = factory.makeSourcePackagePublishingHistory(
517 ... sourcepackagename=spn, distroseries=ubuntu.currentseries)
518
519 >>> view = create_initialized_view(
520 ... product, name="+portlet-packages",
521 ... principal=product.owner)
522 >>> print view.suggestions
523 []
524
525 >>> distro_package = factory.makeDistributionSourcePackage(
526 ... sourcepackagename=spn, distribution=ubuntu)
527
528 >>> view = create_initialized_view(
529 ... product, name="+portlet-packages",
530 ... principal=product.owner)
531 >>> print view.suggestions
532 []
533
534 >>> import transaction
535 >>> #transaction.commit()
536 >>> from canonical.launchpad.scripts import QuietFakeLogger
537 >>> logger = QuietFakeLogger()
538 >>> from canonical.testing.layers import reconnect_stores
539 >>> from canonical.config import config
540 >>> # Switch to the statistician user who is the only user with
541 >>> # write permission to the source package cache tables.
542 >>> reconnect_stores(config.statistician.dbuser)
543 >>> # LaunchpadZopelessLayer.switchDbUser(config.statistician.dbuser)
544 >>> ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
545 >>> updated = ubuntu.updateCompleteSourcePackageCache(
546 ... archive=ubuntu.main_archive, log=logger, ztm=transaction)
547 >>> transaction.commit()
548 >>> reconnect_stores('launchpad')
549 >>> login(ANONYMOUS)
550 >>> product = getUtility(IProductSet)['bingo']
551 >>> view = create_initialized_view(
552 ... product, name="+portlet-packages",
553 ... principal=product.owner)
554 >>> print view.suggestions
555 []
481556
=== modified file 'lib/lp/registry/model/distributionsourcepackage.py'
--- lib/lp/registry/model/distributionsourcepackage.py 2010-02-27 20:20:03 +0000
+++ lib/lp/registry/model/distributionsourcepackage.py 2010-03-06 12:18:33 +0000
@@ -187,7 +187,7 @@
187 PackagePublishingStatus.PUBLISHED,187 PackagePublishingStatus.PUBLISHED,
188 PackagePublishingStatus.OBSOLETE),188 PackagePublishingStatus.OBSOLETE),
189 clauseTables=["SourcePackagePublishingHistory",189 clauseTables=["SourcePackagePublishingHistory",
190 "SourcePackageRelease", 190 "SourcePackageRelease",
191 "DistroSeries"],191 "DistroSeries"],
192 orderBy=["status",192 orderBy=["status",
193 SQLConstant(193 SQLConstant(
@@ -319,6 +319,7 @@
319 self.sourcepackagename)319 self.sourcepackagename)
320 if source_package.direct_packaging is not None:320 if source_package.direct_packaging is not None:
321 return source_package.direct_packaging.productseries.product321 return source_package.direct_packaging.productseries.product
322 return None
322323
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.
324 @property325 @property
325326
=== modified file 'lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt'
--- lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt 2010-02-18 20:41:01 +0000
+++ lib/lp/registry/stories/packaging/xx-sourcepackage-packaging.txt 2010-03-06 12:18:33 +0000
@@ -1,13 +1,13 @@
1= Packaging =1= Packaging =
22
3No Privileges Person visit the distroseries upstream linkes page for Hoary3No Privileges Person visit the distroseries upstream links page for Hoary
4and sees that pmount is not linked.4and sees that pmount is not linked.
55
6 >>> user_browser.open(6 >>> user_browser.open(
7 ... 'http://launchpad.dev/ubuntu/hoary/+needs-packaging')7 ... 'http://launchpad.dev/ubuntu/hoary/+needs-packaging')
8 >>> print extract_text(find_tag_by_id(user_browser.contents, 'packages'))8 >>> print extract_text(find_tag_by_id(user_browser.contents, 'packages'))
9 Source Package Bugs Translations9 Source Package Bugs Translations
10 pmount No bugs 64 strings ...10 pmount No bugs 64 strings ...
1111
12He looks at the pmount source package page in Hoary and reads that the12He looks at the pmount source package page in Hoary and reads that the
13upstream project is not set.13upstream project is not set.
1414
=== modified file 'lib/lp/registry/stories/product/xx-product-index.txt'
--- lib/lp/registry/stories/product/xx-product-index.txt 2009-10-30 15:40:55 +0000
+++ lib/lp/registry/stories/product/xx-product-index.txt 2010-03-06 12:18:33 +0000
@@ -348,3 +348,36 @@
348 >>> anon_browser.open('http://launchpad.dev/firefox')348 >>> anon_browser.open('http://launchpad.dev/firefox')
349 >>> print extract_text(find_tag_by_id(anon_browser.contents, 'aliases'))349 >>> print extract_text(find_tag_by_id(anon_browser.contents, 'aliases'))
350 Also known as: iceweasel, snowchicken350 Also known as: iceweasel, snowchicken
351
352
353Ubuntu packaging
354----------------
355
356If a product is packaged in Ubuntu the links are shown.
357
358 >>> user_browser.open('http://launchpad.dev/firefox')
359 >>> print extract_text(
360 ... find_tag_by_id(user_browser.contents, 'portlet-packages'))
361 All packages
362 Packages in distributions
363 “mozilla-firefox” source package in Hoary
364 “mozilla-firefox” source package in Warty Version 0.9 uploaded on...
365
366A product that has linked packages now displays suggestions and asks
367the user to select the package.
368
369 >>> login(ANONYMOUS)
370 >>> product = factory.makeProduct(name='pmount')
371 >>> logout()
372 >>> user_browser.open('http://launchpad.dev/pmount')
373 >>> print extract_text(
374 ... find_tag_by_id(user_browser.contents, 'portlet-packages'))
375 All packages...
376 Packages in Ubuntu...
377 Ubuntu packages:
378 pmount...
379
380 >>> user_browser.getControl(name='field.distributionsourcepackage').value = ['pmount']
381 >>> user_browser.getControl('Link to this Ubuntu Package').click()
382 >>> print_feedback_messages(user_browser.contents)
383 This project was linked to the source package "pmount in ubuntu"
351384
=== modified file 'lib/lp/registry/templates/product-portlet-packages.pt'
--- lib/lp/registry/templates/product-portlet-packages.pt 2009-09-05 03:17:24 +0000
+++ lib/lp/registry/templates/product-portlet-packages.pt 2010-03-06 12:18:33 +0000
@@ -3,32 +3,71 @@
3 xmlns:metal="http://xml.zope.org/namespaces/metal"3 xmlns:metal="http://xml.zope.org/namespaces/metal"
4 xmlns:i18n="http://xml.zope.org/namespaces/i18n"4 xmlns:i18n="http://xml.zope.org/namespaces/i18n"
5 omit-tag=""5 omit-tag=""
6 define="packages context/sourcepackages"6 define="packages context/sourcepackages">
7 condition="packages">7
8<div class="portlet" id="portlet-packages">8<div class="portlet" id="portlet-packages">
9 <h2>9
10 <span class="see-all"><a10 <tal:has_packages condition="packages">
11 tal:attributes="href context/menu:overview/packages/fmt:url">All11 <h2>
12 packages</a></span>12 <span class="see-all"><a
13 Packages in distributions13 tal:attributes="href context/menu:overview/packages/fmt:url">All
14 </h2>14 packages</a></span>
1515 Packages in distributions
16 <ul>16 </h2>
17 <tal:pair tal:repeat="package packages">17
18 <li>18 <ul>
19 <a class="sprite package-source"19 <tal:pair tal:repeat="package packages">
20 tal:attributes="href package/fmt:url"20 <li>
21 tal:content="package/title">apache in ubuntu hoary</a>21 <a class="sprite package-source"
22 <br />22 tal:attributes="href package/fmt:url"
23 <span class="registered"23 tal:content="package/title">apache in ubuntu hoary</a>
24 tal:define="release package/currentrelease"24 <br />
25 tal:condition="release">25 <span class="registered"
26 <strong>Version26 tal:define="release package/currentrelease"
27 <tal:version content="release/version">2.3</tal:version></strong>27 tal:condition="release">
28 uploaded <tal:date replace="release/dateuploaded/fmt:displaydate" />28 <strong>Version
29 </span>29 <tal:version content="release/version">2.3</tal:version></strong>
30 </li>30 uploaded <tal:date replace="release/dateuploaded/fmt:displaydate" />
31 </tal:pair>31 </span>
32 </ul>32 </li>
33 </tal:pair>
34 </ul>
35 </tal:has_packages>
36
37 <tal:has_no_packages condition="not:packages">
38 <h2>
39 <span class="see-all"><a
40 tal:attributes="href context/menu:overview/packages/fmt:url">All
41 packages</a></span>
42 Packages in Ubuntu
43 </h2>
44
45 <p>
46 Launchpad doesn't know which Ubuntu packages this project
47 provides. Links from distribution packages to upstream projects
48 let distribution and upstream maintainers share bugs, patches, and
49 translations efficiently.
50 </p>
51 <div id="suggestions" tal:condition="view/suggestions">
52 <div metal:use-macro="context/@@launchpad_form/form">
53 <div class="actions" metal:fill-slot="buttons">
54 <input tal:replace="structure view/link/render"/>
55 &nbsp;or&nbsp;
56 <a tal:replace="structure
57 context/development_focus/menu:overview/ubuntupkg/fmt:link" />
58 </div>
59 </div>
60 </div>
61
62 <div id="suggestions" tal:condition="not:view/suggestions">
63 <p>
64 There are no unlinked source packages that are a good match.
65 Can you suggest one?
66 </p>
67 <a tal:replace="structure
68 context/development_focus/menu:overview/ubuntupkg/fmt:link" />
69 </div>
70
71 </tal:has_no_packages>
33</div>72</div>
34</tal:root>73</tal:root>
3574
=== modified file 'lib/lp/registry/tests/test_doc_product.py'
--- lib/lp/registry/tests/test_doc_product.py 2009-06-30 16:56:07 +0000
+++ lib/lp/registry/tests/test_doc_product.py 2010-03-06 12:18:33 +0000
@@ -3,7 +3,7 @@
33
4"""Test the doctests in the product module."""4"""Test the doctests in the product module."""
55
6# XXX sinzui 2009-04-03 bug=354881: This test harness shold be removed6# XXX sinzui 2009-04-03 bug=354881: This test harness should be removed
7# and the inline tests moved to docs/7# and the inline tests moved to docs/
88
9__metaclass__ = type9__metaclass__ = type