launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #00831
[Merge] lp:~edwin-grubbs/launchpad/bug-597738-bug-service-status into lp:launchpad/devel
Edwin Grubbs has proposed merging lp:~edwin-grubbs/launchpad/bug-597738-bug-service-status into lp:launchpad/devel with lp:~jcsackett/launchpad/deprecate-official_codehosting as a prerequisite.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
#597738 Launchpad must state the project's official services
https://bugs.launchpad.net/bugs/597738
Summary
-------
This branch provides the user with more information about filing bugs on
the bugs.launchpad.net/$project page. This branch also takes advantage
of the new bug_tracking_usage attribute that returns an enum as opposed
to the old official_malone boolean. If the project is not using
Launchpad as the bug tracker, the page will also inform the user of any
ubuntu packages linked to the project under which bugs can be filed.
This branch is dependent on
lp:~jcsackett/launchpad/deprecate-official_codehosting
Implementation details
----------------------
lib/lp/answers/browser/questiontarget.py
lib/lp/answers/browser/tests/test_questiontarget.py
lib/lp/answers/templates/unknown-support.pt
lib/lp/bugs/browser/bugtarget.py
lib/lp/bugs/stories/bugs/xx-front-page-info.txt
lib/lp/bugs/templates/bugtarget-bugs.pt
lib/lp/registry/doc/product.txt
lib/lp/registry/interfaces/product.py
lib/lp/registry/model/product.py
Tests
-----
./bin/test -vv -t 'xx-front-page-info.txt|doc/product.txt'
Demo and Q/A
------------
* Open http://launchpad.dev/firefox/+configure-bugtracker
* Switch the "Bugs are tracked" field between the values.
* Open http://bugs.launchpad.dev/firefox
* If bugs are tracked in launchpad, a bug table should be shown.
* If bugs are tracked externally, the page should contain:
<meta name="robots" content="noindex,nofollow"/>
<strong>Bugs are tracked in _SOME BUGTRACKER_.</strong>
<a>Getting started with bug tracking in Launchpad.</a>
Firefox bug reports are also tracked in <a>mozilla-firefox in Ubuntu</a>.
* If launchpad doesn't know where bugs are tracked, it should contain:
<meta name="robots" content="noindex,nofollow"/>
<strong>
Launchpad does not know where to forward bug reports to contact the*
developers of Mozilla Firefox.
</strong>
<a>Getting started with bug tracking in Launchpad.</a>
Firefox bug reports are tracked in <a>mozilla-firefox in Ubuntu</a>.
--
https://code.launchpad.net/~edwin-grubbs/launchpad/bug-597738-bug-service-status/+merge/34250
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~edwin-grubbs/launchpad/bug-597738-bug-service-status into lp:launchpad/devel.
=== modified file 'lib/canonical/launchpad/doc/vocabularies.txt'
--- lib/canonical/launchpad/doc/vocabularies.txt 2010-08-26 08:02:08 +0000
+++ lib/canonical/launchpad/doc/vocabularies.txt 2010-08-31 21:27:50 +0000
@@ -259,9 +259,9 @@
>>> mozilla_project = getUtility(IProjectGroupSet).getByName('mozilla')
>>> for product in mozilla_project.products:
- ... print "%s: %s" % (product.name, product.official_malone)
- firefox: True
- thunderbird: False
+ ... print "%s: %s" % (product.name, product.bug_tracking_usage.name)
+ firefox: LAUNCHPAD
+ thunderbird: UNKNOWN
>>> mozilla_products_vocabulary = vocabulary_registry.get(
... mozilla_project,'ProjectProductsUsingMalone')
=== modified file 'lib/canonical/launchpad/vocabularies/dbobjects.py'
--- lib/canonical/launchpad/vocabularies/dbobjects.py 2010-08-26 08:02:08 +0000
+++ lib/canonical/launchpad/vocabularies/dbobjects.py 2010-08-31 21:27:50 +0000
@@ -85,6 +85,7 @@
SQLObjectVocabularyBase,
)
from lp.app.browser.stringformatter import FormattersAPI
+from lp.app.enums import ServiceUsage
from lp.blueprints.model.specification import Specification
from lp.blueprints.model.sprint import Sprint
from lp.bugs.interfaces.bugtask import IBugTask
@@ -231,6 +232,7 @@
These are branches that the user is guaranteed to be able to push
to.
"""
+
def __init__(self, context=None):
"""Pass a Person as context, or anything else for the current user."""
super(HostedBranchRestrictedOnOwnerVocabulary, self).__init__(context)
@@ -338,6 +340,7 @@
This vocabulary contains all the languages known to Launchpad,
excluding English and non-visible languages.
"""
+
def __contains__(self, language):
"""See `IVocabulary`.
@@ -379,7 +382,7 @@
return SimpleVocabulary([
SimpleTerm(product, product.name, title=product.displayname)
for product in project.products
- if product.official_malone])
+ if product.bug_tracking_usage == ServiceUsage.LAUNCHPAD])
class TranslationGroupVocabulary(NamedSQLObjectVocabulary):
@@ -413,14 +416,12 @@
if context.productseries != None:
self._filter = AND(
POTemplate.iscurrent == True,
- POTemplate.productseries == context.productseries
- )
+ POTemplate.productseries == context.productseries)
else:
self._filter = AND(
POTemplate.iscurrent == True,
POTemplate.distroseries == context.distroseries,
- POTemplate.sourcepackagename == context.sourcepackagename
- )
+ POTemplate.sourcepackagename == context.sourcepackagename)
super(TranslationTemplateVocabulary, self).__init__(context)
def toTerm(self, obj):
@@ -661,7 +662,8 @@
return Distribution.selectBy(official_malone=True).count()
def __contains__(self, obj):
- return IDistribution.providedBy(obj) and obj.official_malone
+ return (IDistribution.providedBy(obj)
+ and obj.bug_tracking_usage == ServiceUsage.LAUNCHPAD)
def getQuery(self):
return None
=== modified file 'lib/lp/answers/browser/questiontarget.py'
--- lib/lp/answers/browser/questiontarget.py 2010-08-26 17:45:46 +0000
+++ lib/lp/answers/browser/questiontarget.py 2010-08-31 21:27:50 +0000
@@ -506,22 +506,6 @@
question.sourcepackagename.name)
@property
- def ubuntu_packages(self):
- """The Ubuntu `IDistributionSourcePackage`s linked to the context.
-
- If the context is an `IProduct` and it has `IPackaging` links to
- Ubuntu, a list is returned. Otherwise None is returned
- """
- if IProduct.providedBy(self.context):
- ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
- packages = [
- package for package in self.context.distrosourcepackages
- if package.distribution == ubuntu]
- if len(packages) > 0:
- return packages
- return None
-
- @property
def can_configure_answers(self):
"""Can the user configure answers for the `IQuestionTarget`."""
target = self.context
=== modified file 'lib/lp/answers/browser/tests/test_questiontarget.py'
--- lib/lp/answers/browser/tests/test_questiontarget.py 2010-08-26 17:45:46 +0000
+++ lib/lp/answers/browser/tests/test_questiontarget.py 2010-08-31 21:27:50 +0000
@@ -133,30 +133,6 @@
self.assertViewTemplate(question_set, 'question-listing.pt')
-class TestSearchQuestionsView_ubuntu_packages(TestSearchQuestionsView):
- """Test the behaviour of SearchQuestionsView.ubuntu_packages."""
-
- def test_nonproduct_ubuntu_packages(self):
- distribution = self.factory.makeDistribution()
- view = create_initialized_view(distribution, '+questions')
- packages = view.ubuntu_packages
- self.assertEqual(None, packages)
-
- def test_product_ubuntu_packages_unlinked(self):
- product = self.factory.makeProduct()
- view = create_initialized_view(product, '+questions')
- packages = view.ubuntu_packages
- self.assertEqual(None, packages)
-
- def test_product_ubuntu_packages_linked(self):
- product = self.factory.makeProduct()
- self.linkPackage(product, 'cow')
- view = create_initialized_view(product, '+questions')
- packages = view.ubuntu_packages
- self.assertEqual(1, len(packages))
- self.assertEqual('cow', packages[0].name)
-
-
class TestSearchQuestionsViewUnknown(TestSearchQuestionsView):
"""Test the behaviour of SearchQuestionsView unknown support."""
=== modified file 'lib/lp/answers/templates/unknown-support.pt'
--- lib/lp/answers/templates/unknown-support.pt 2010-08-05 17:14:05 +0000
+++ lib/lp/answers/templates/unknown-support.pt 2010-08-31 21:27:50 +0000
@@ -21,9 +21,9 @@
</p>
<p id="ubuntu-support"
- tal:define="packages view/ubuntu_packages"
+ tal:define="packages context/ubuntu_packages | nothing"
tal:condition="packages">
- <tal:project replace="context/displayname" /> questions are also
+ <tal:project replace="context/displayname" /> questions are
tracked in: <tal:packages repeat="package packages">
<tal:package replace="structure package/fmt:link" /><tal:comma
condition="not:repeat/package/end">, </tal:comma></tal:packages>.
=== modified file 'lib/lp/bugs/browser/bugalsoaffects.py'
--- lib/lp/bugs/browser/bugalsoaffects.py 2010-08-20 20:31:18 +0000
+++ lib/lp/bugs/browser/bugalsoaffects.py 2010-08-31 21:27:50 +0000
@@ -56,6 +56,7 @@
from canonical.widgets.itemswidgets import LaunchpadRadioWidget
from canonical.widgets.popup import SearchForUpstreamPopupWidget
from canonical.widgets.textwidgets import StrippedTextWidget
+from lp.app.enums import ServiceUsage
from lp.bugs.interfaces.bug import IBug
from lp.bugs.interfaces.bugtask import (
BugTaskImportance,
@@ -319,10 +320,11 @@
if bug_watch is None:
bug_watch = task_added.bug.addWatch(
extracted_bugtracker, extracted_bug, self.user)
- if not target.official_malone:
+ if target.bug_tracking_usage != ServiceUsage.LAUNCHPAD:
task_added.bugwatch = bug_watch
- if (not target.official_malone and task_added.bugwatch is not None
+ if (target.bug_tracking_usage != ServiceUsage.LAUNCHPAD
+ and task_added.bugwatch is not None
and (task_added.bugwatch.bugtracker.bugtrackertype !=
BugTrackerType.EMAILADDRESS)):
# A remote bug task gets its status from a bug watch, so
@@ -371,7 +373,7 @@
if (not bug_url and
not self.request.get('ignore_missing_remote_bug') and
- not target.official_malone):
+ target.bug_tracking_usage != ServiceUsage.LAUNCHPAD):
# We have no URL for the remote bug and the target does not use
# Launchpad for bug tracking, so we warn the user this is not
# optimal and ask for his confirmation.
@@ -404,7 +406,7 @@
"""
target = self.getTarget(data)
bug_url = data.get('bug_url')
- if bug_url and target.official_malone:
+ if bug_url and target.bug_tracking_usage == ServiceUsage.LAUNCHPAD:
self.addError(
"Bug watches can not be added for %s, as it uses Launchpad"
" as its official bug tracker. Alternatives are to add a"
=== modified file 'lib/lp/bugs/browser/bugtarget.py'
--- lib/lp/bugs/browser/bugtarget.py 2010-08-22 18:31:30 +0000
+++ lib/lp/bugs/browser/bugtarget.py 2010-08-31 21:27:50 +0000
@@ -92,11 +92,15 @@
GhostWidget,
ProductBugTrackerWidget,
)
+from lp.app.enums import ServiceUsage
from lp.app.errors import (
NotFoundError,
UnexpectedFormData,
)
-from lp.app.interfaces.launchpad import ILaunchpadUsage
+from lp.app.interfaces.launchpad import (
+ ILaunchpadUsage,
+ IServiceUsage,
+ )
from lp.bugs.browser.bugrole import BugRoleMixin
from lp.bugs.browser.bugtask import BugTaskSearchListingView
from lp.bugs.interfaces.apportjob import IProcessApportBlobJobSource
@@ -384,7 +388,7 @@
# actually uses Malone for its bug tracking.
product_or_distro = self.getProductOrDistroFromContext()
if (product_or_distro is not None and
- not product_or_distro.official_malone):
+ product_or_distro.bug_tracking_usage != ServiceUsage.LAUNCHPAD):
self.setFieldError(
'bugtarget',
"%s does not use Launchpad as its bug tracker " %
@@ -426,10 +430,11 @@
if IProjectGroup.providedBy(self.context):
products_using_malone = [
product for product in self.context.products
- if product.official_malone]
+ if product.bug_tracking_usage == ServiceUsage.LAUNCHPAD]
return len(products_using_malone) > 0
else:
- return self.getMainContext().official_malone
+ bug_tracking_usage = self.getMainContext().bug_tracking_usage
+ return bug_tracking_usage == ServiceUsage.LAUNCHPAD
def getMainContext(self):
if IDistributionSourcePackage.providedBy(self.context):
@@ -1084,7 +1089,7 @@
def products_using_malone(self):
return [
product for product in self.context.products
- if product.official_malone]
+ if product.bug_tracking_usage == ServiceUsage.LAUNCHPAD]
@property
def default_product(self):
@@ -1247,13 +1252,13 @@
bug_statuses_to_show.append(BugTaskStatus.FIXRELEASED)
@property
- def uses_launchpad_bugtracker(self):
- """Whether this distro or product tracks bugs in launchpad.
+ def bug_tracking_usage(self):
+ """Whether the context tracks bugs in launchpad.
- :returns: boolean
+ :returns: ServiceUsage enum value
"""
- launchpad_usage = ILaunchpadUsage(self.context)
- return launchpad_usage.official_malone
+ service_usage = IServiceUsage(self.context)
+ return service_usage.bug_tracking_usage
@property
def external_bugtracker(self):
@@ -1273,7 +1278,7 @@
:returns: str which may contain HTML.
"""
- if self.uses_launchpad_bugtracker:
+ if self.bug_tracking_usage == ServiceUsage.LAUNCHPAD:
return 'Launchpad'
elif self.external_bugtracker:
return BugTrackerFormatterAPI(self.external_bugtracker).link(None)
=== modified file 'lib/lp/bugs/browser/bugtask.py'
--- lib/lp/bugs/browser/bugtask.py 2010-08-27 05:34:32 +0000
+++ lib/lp/bugs/browser/bugtask.py 2010-08-31 21:27:50 +0000
@@ -119,15 +119,11 @@
SimpleVocabulary,
)
from zope.security.interfaces import Unauthorized
-from zope.security.proxy import (
- isinstance as zope_isinstance,
- removeSecurityProxy,
- )
+from zope.security.proxy import isinstance as zope_isinstance
from zope.traversing.interfaces import IPathAdapter
from canonical.cachedproperty import cachedproperty
from canonical.config import config
-from canonical.database.sqlbase import cursor
from canonical.launchpad import (
_,
helpers,
@@ -193,6 +189,7 @@
)
from canonical.widgets.project import ProjectScopeWidget
from lp.answers.interfaces.questiontarget import IQuestionTarget
+from lp.app.enums import ServiceUsage
from lp.app.errors import (
NotFoundError,
UnexpectedFormData,
@@ -275,6 +272,7 @@
PersonFormatterAPI(context.assignee).link(None))
return render
+
@component.adapter(IBugTask, IReference, IWebServiceClientRequest)
@implementer(IFieldHTMLRenderer)
def bugtarget_renderer(context, field, request):
@@ -289,6 +287,7 @@
return html
return render
+
def unique_title(title):
"""Canonicalise a message title to help identify messages with new
information in their titles.
@@ -1082,7 +1081,7 @@
activity_and_comments.append({
'activity': activity_dict,
'date': date,
- 'person': activity_dict[0]['activity'][0].person
+ 'person': activity_dict[0]['activity'][0].person,
})
activity_and_comments.sort(key=itemgetter('date'))
@@ -1668,7 +1667,7 @@
new_product = data.get('product')
if (old_product is None or old_product == new_product or
- not bugtask.pillar.official_malone):
+ bugtask.pillar.bug_tracking_usage != ServiceUsage.LAUNCHPAD):
# Either the product wasn't changed, we're dealing with a #
# distro task, or the bugtask's product doesn't use Launchpad,
# which means the product can't be changed.
@@ -1823,9 +1822,11 @@
# Launchpad status, but it's not trivial to do at the
# moment. I will fix this later.
bugtask.transitionToStatus(
- BugTaskStatus.UNKNOWN, bug_importer)
+ BugTaskStatus.UNKNOWN,
+ bug_importer)
bugtask.transitionToImportance(
- BugTaskImportance.UNKNOWN, bug_importer)
+ BugTaskImportance.UNKNOWN,
+ bug_importer)
bugtask.transitionToAssignee(None)
if changed:
@@ -1994,7 +1995,7 @@
"""
if not IProduct.providedBy(self.context):
return None
- if self.context.official_malone:
+ if self.context.bug_tracking_usage == ServiceUsage.LAUNCHPAD:
return None
return "%s?field.status_upstream=pending_bugwatch" % (
canonical_url(self.context, view_name='+bugs'))
@@ -2081,7 +2082,7 @@
"""
if not IProduct.providedBy(self.context):
return None
- if self.context.official_malone:
+ if self.context.bug_tracking_usage == ServiceUsage.LAUNCHPAD:
return None
params = get_default_search_params(self.user)
params.pending_bugwatch_elsewhere = True
@@ -2359,9 +2360,12 @@
bugtask_listing_item.review_action_widget = CustomWidgetFactory(
NominationReviewActionWidget)
setUpWidget(
- bugtask_listing_item, 'review_action',
- review_action_field, IInputWidget,
- value=NominatedBugReviewAction.NO_CHANGE, context=bug_nomination)
+ bugtask_listing_item,
+ 'review_action',
+ review_action_field,
+ IInputWidget,
+ value=NominatedBugReviewAction.NO_CHANGE,
+ context=bug_nomination)
return bugtask_listing_item
@@ -2913,7 +2917,7 @@
if fieldname != "orderby":
sortlink += "%s&" % urllib.urlencode(
- {fieldname : fieldvalue}, doseq=True)
+ {fieldname: fieldvalue}, doseq=True)
sorted, ascending = self._getSortStatus(colname)
if sorted and ascending:
@@ -2997,7 +3001,7 @@
"""Is the context a Product that does not use Malone?"""
return (
IProduct.providedBy(self.context)
- and not self.context.official_malone)
+ and self.context.bug_tracking_usage != ServiceUsage.LAUNCHPAD)
def _upstreamContext(self):
"""Is this page being viewed in an upstream context?
@@ -3065,7 +3069,6 @@
return None
-
class BugNominationsView(BugTaskSearchListingView):
"""View for accepting/declining bug nominations."""
@@ -3129,8 +3132,7 @@
declined += 1
else:
raise AssertionError(
- 'Unknown NominatedBugReviewAction: %r' % (
- review_action,))
+ 'Unknown NominatedBugReviewAction: %r' % review_action)
if accepted > 0:
self.request.response.addInfoNotification(
@@ -3197,7 +3199,7 @@
else:
raise AssertionError('Uknown context type: %s' % self.context)
- return u"".join("%d\n" % bug_id for bug_id in
+ return u"".join("%d\n" % bug_id for bug_id in
getUtility(IBugTaskSet).searchBugIds(search_params))
@@ -3370,8 +3372,7 @@
self._getTableRowView(
nomination, is_converted_to_question, False)
for nomination in target_nominations
- if nomination.status != BugNominationStatus.APPROVED
- )
+ if nomination.status != BugNominationStatus.APPROVED)
# Fill the ValidPersonOrTeamCache cache (using getValidPersons()),
# so that checking person.is_valid_person, when rendering the
@@ -3849,6 +3850,7 @@
class BugTaskExpirableListingView(LaunchpadView):
"""View for listing Incomplete bugs that can expire."""
+
@property
def can_show_expirable_bugs(self):
"""Return True or False if expirable bug listing can be shown."""
=== modified file 'lib/lp/bugs/browser/distribution_upstream_bug_report.py'
--- lib/lp/bugs/browser/distribution_upstream_bug_report.py 2010-08-20 20:31:18 +0000
+++ lib/lp/bugs/browser/distribution_upstream_bug_report.py 2010-08-31 21:27:50 +0000
@@ -6,8 +6,8 @@
__metaclass__ = type
__all__ = [
- 'DistributionUpstreamBugReport'
-]
+ 'DistributionUpstreamBugReport',
+ ]
from operator import attrgetter
@@ -17,6 +17,7 @@
LaunchpadView,
)
from canonical.launchpad.webapp.url import urlappend
+from lp.app.enums import ServiceUsage
from lp.bugs.browser.bugtask import get_buglisting_search_filter_url
# TODO: fix column sorting to work for the different colspans, or
@@ -145,9 +146,11 @@
- dssp: an IDistributionSeriesSourcepackage
- product: an IProduct
- bugtracker: convenience holder for the product's bugtracker
- - official_malone: convenience boolean for IProduct.official_malone
+ - bug_tracking_usage: convenience enum for
+ IProduct.bug_tracking_usage
- *_url: convenience URLs
"""
+
def __init__(self, dsp, dssp, product, open_bugs, triaged_bugs,
upstream_bugs, watched_bugs, bugs_with_upstream_patches):
BugReportData.__init__(self, open_bugs, triaged_bugs, upstream_bugs,
@@ -162,9 +165,12 @@
self.open_bugs_url = urlappend(
dsp_bugs_url, get_buglisting_search_filter_url())
- self.official_malone = bool(product and product.official_malone)
- self.branch = (
- product and product.development_focus.branch)
+ if product is not None:
+ self.bug_tracking_usage = product.bug_tracking_usage
+ self.branch = product.development_focus.branch
+ else:
+ self.bug_tracking_usage = ServiceUsage.UNKNOWN
+ self.branch = None
# If a product is specified, build some convenient links to
# pages which allow filling out required information. The
@@ -180,7 +186,7 @@
# Create a 'bugtracker_name' attribute for searching.
if self.bugtracker is not None:
self.bugtracker_name = self.bugtracker.title
- elif self.product.official_malone:
+ elif self.product.bug_tracking_usage == ServiceUsage.LAUNCHPAD:
self.bugtracker_name = 'Launchpad'
else:
self.bugtracker_name = None
@@ -374,4 +380,3 @@
dsp, dssp, product, open, triaged, upstream, watched,
bugs_with_upstream_patches)
self._data.append(item)
-
=== modified file 'lib/lp/bugs/browser/tests/bugtask-adding-views.txt'
--- lib/lp/bugs/browser/tests/bugtask-adding-views.txt 2010-07-26 12:49:23 +0000
+++ lib/lp/bugs/browser/tests/bugtask-adding-views.txt 2010-08-31 21:27:50 +0000
@@ -224,8 +224,8 @@
offical bug tracker.
>>> evolution_task = bug_four.bugtasks[0]
- >>> evolution_task.target.official_malone
- True
+ >>> evolution_task.target.bug_tracking_usage
+ <DBItem ServiceUsage.LAUNCHPAD, (20) Launchpad>
>>> transaction.commit()
@@ -275,8 +275,8 @@
are set to the default values.
>>> alsa_task = bug_four.bugtasks[0]
- >>> alsa_task.target.official_malone
- False
+ >>> alsa_task.target.bug_tracking_usage
+ <DBItem ServiceUsage.UNKNOWN, (10) Unknown>
>>> alsa_task.status.title
'New'
>>> alsa_task.importance.title
@@ -368,8 +368,8 @@
>>> alsa_task = bug_four.bugtasks[0]
>>> alsa_task.bugtargetname
u'alsa-utils'
- >>> alsa_task.product.official_malone
- False
+ >>> alsa_task.product.bug_tracking_usage
+ <DBItem ServiceUsage.UNKNOWN, (10) Unknown>
>>> alsa_task.bugwatch == bug_four.watches[0]
True
=== modified file 'lib/lp/bugs/browser/tests/test_bugtarget_configure.py'
--- lib/lp/bugs/browser/tests/test_bugtarget_configure.py 2010-08-20 20:31:18 +0000
+++ lib/lp/bugs/browser/tests/test_bugtarget_configure.py 2010-08-31 21:27:50 +0000
@@ -6,6 +6,7 @@
__metaclass__ = type
from canonical.testing import DatabaseFunctionalLayer
+from lp.app.enums import ServiceUsage
from lp.testing import (
login_person,
TestCaseWithFactory,
@@ -59,7 +60,9 @@
self.assertEqual([], view.errors)
self.assertEqual(self.owner, self.product.bug_supervisor)
self.assertEqual(self.owner, self.product.security_contact)
- self.assertTrue(self.product.official_malone)
+ self.assertEqual(
+ ServiceUsage.LAUNCHPAD,
+ self.product.bug_tracking_usage)
self.assertTrue(self.product.enable_bug_expiration)
self.assertEqual('sf-boing', self.product.remote_product)
self.assertEqual('guidelines', self.product.bug_reporting_guidelines)
=== modified file 'lib/lp/bugs/model/bug.py'
--- lib/lp/bugs/model/bug.py 2010-08-29 22:05:15 +0000
+++ lib/lp/bugs/model/bug.py 2010-08-31 21:27:50 +0000
@@ -108,6 +108,7 @@
MAIN_STORE,
)
from lp.answers.interfaces.questiontarget import IQuestionTarget
+from lp.app.enums import ServiceUsage
from lp.app.errors import (
NotFoundError,
UserCannotUnsubscribePerson,
@@ -1170,7 +1171,7 @@
if len(non_invalid_bugtasks) != 1:
return None
[valid_bugtask] = non_invalid_bugtasks
- if valid_bugtask.pillar.official_malone:
+ if valid_bugtask.pillar.bug_tracking_usage == ServiceUsage.LAUNCHPAD:
return valid_bugtask
else:
return None
=== modified file 'lib/lp/bugs/model/bugtask.py'
--- lib/lp/bugs/model/bugtask.py 2010-08-30 19:30:45 +0000
+++ lib/lp/bugs/model/bugtask.py 2010-08-31 21:27:50 +0000
@@ -17,7 +17,8 @@
'bugtask_sort_key',
'get_bug_privacy_filter',
'get_related_bugtasks_search_params',
- 'search_value_to_where_condition']
+ 'search_value_to_where_condition',
+ ]
import datetime
@@ -92,6 +93,7 @@
IStoreSelector,
MAIN_STORE,
)
+from lp.app.enums import ServiceUsage
from lp.app.errors import NotFoundError
from lp.bugs.interfaces.bug import IBugSet
from lp.bugs.interfaces.bugattachment import BugAttachmentType
@@ -157,16 +159,30 @@
from lp.soyuz.model.publishing import SourcePackagePublishingHistory
from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
-debbugsseveritymap = {
- None: BugTaskImportance.UNDECIDED,
- 'wishlist': BugTaskImportance.WISHLIST,
- 'minor': BugTaskImportance.LOW,
- 'normal': BugTaskImportance.MEDIUM,
- 'important': BugTaskImportance.HIGH,
- 'serious': BugTaskImportance.HIGH,
- 'grave': BugTaskImportance.HIGH,
- 'critical': BugTaskImportance.CRITICAL,
- }
+<<<<<<< TREE
+debbugsseveritymap = {
+ None: BugTaskImportance.UNDECIDED,
+ 'wishlist': BugTaskImportance.WISHLIST,
+ 'minor': BugTaskImportance.LOW,
+ 'normal': BugTaskImportance.MEDIUM,
+ 'important': BugTaskImportance.HIGH,
+ 'serious': BugTaskImportance.HIGH,
+ 'grave': BugTaskImportance.HIGH,
+ 'critical': BugTaskImportance.CRITICAL,
+ }
+=======
+
+debbugsseveritymap = {
+ None: BugTaskImportance.UNDECIDED,
+ 'wishlist': BugTaskImportance.WISHLIST,
+ 'minor': BugTaskImportance.LOW,
+ 'normal': BugTaskImportance.MEDIUM,
+ 'important': BugTaskImportance.HIGH,
+ 'serious': BugTaskImportance.HIGH,
+ 'grave': BugTaskImportance.HIGH,
+ 'critical': BugTaskImportance.CRITICAL,
+ }
+>>>>>>> MERGE-SOURCE
def bugtask_sort_key(bugtask):
@@ -460,13 +476,19 @@
sourcepackagename=self.sourcepackagename,
distribution=self.distribution,
distroseries=self.distroseries)
- utility_iface = {
+ utility_iface_dict = {
'productID': IProductSet,
'productseriesID': IProductSeriesSet,
'sourcepackagenameID': ISourcePackageNameSet,
'distributionID': IDistributionSet,
+<<<<<<< TREE
'distroseriesID': IDistroSeriesSet,
}[attr]
+=======
+ 'distroseriesID': IDistroSeriesSet,
+ }
+ utility_iface = utility_iface_dict[attr]
+>>>>>>> MERGE-SOURCE
if value is None:
target_params[attr[:-2]] = None
else:
@@ -655,7 +677,7 @@
# one thing they often have to filter for is completeness. We maintain
# this single canonical query string here so that it does not have to be
# cargo culted into Product, Distribution, ProductSeries etc
- completeness_clause = """
+ completeness_clause = """
BugTask.status IN ( %s )
""" % ','.join([str(a.value) for a in RESOLVED_BUGTASK_STATUSES])
@@ -845,7 +867,7 @@
"""See `IBugTask`"""
# XXX sinzui 2007-10-04 bug=149009:
# This property is not needed. Code should inline this implementation.
- return self.pillar.official_malone
+ return (self.pillar.bug_tracking_usage == ServiceUsage.LAUNCHPAD)
def transitionToMilestone(self, new_milestone, user):
"""See `IBugTask`."""
@@ -1178,7 +1200,7 @@
if IUpstreamBugTask.providedBy(self):
header_value = 'product=%s;' % self.target.name
elif IProductSeriesBugTask.providedBy(self):
- header_value = 'product=%s; productseries=%s;' % (
+ header_value = 'product=%s; productseries=%s;' % (
self.productseries.product.name, self.productseries.name)
elif IDistroBugTask.providedBy(self):
header_value = ((
@@ -2219,7 +2241,7 @@
(BugTask, Product, SourcePackageName, Bug),
AutoTables(SQL("1=1"), tables),
query)
- decorator=lambda row:bugtask_decorator(row[0])
+ decorator=lambda row: bugtask_decorator(row[0])
resultset.order_by(orderby)
return DecoratedResultSet(resultset, result_decorator=decorator)
=== modified file 'lib/lp/bugs/stories/bugs/xx-front-page-info.txt'
--- lib/lp/bugs/stories/bugs/xx-front-page-info.txt 2010-05-08 15:29:56 +0000
+++ lib/lp/bugs/stories/bugs/xx-front-page-info.txt 2010-08-31 21:27:50 +0000
@@ -19,7 +19,8 @@
>>> anon_browser.open('http://bugs.launchpad.dev/test-project')
>>> uses_malone_p = find_tag_by_id(anon_browser.contents, 'no-malone')
>>> print extract_text(uses_malone_p)
- Simple Test Project does not use Launchpad for bug tracking.
+ Launchpad does not know where to forward bug reports to contact the
+ developers of Simple Test Project.
Only users who have permission to do so can enable bug tracking
for a project.
@@ -112,8 +113,7 @@
Advanced search
Projects that use an external bug tracker will list the tracker on a
-bugs home page in addition to the message that the project does not
-use Launchpad for bug tracking.
+bugs home page.
>>> login('foo.bar@xxxxxxxxxxxxx')
>>> some_tracker = factory.makeBugTracker(
@@ -121,9 +121,6 @@
>>> test_project.bugtracker = some_tracker
>>> logout()
>>> anon_browser.open('http://bugs.launchpad.dev/test-project')
- >>> uses_malone_p = find_tag_by_id(anon_browser.contents, 'no-malone')
- >>> print extract_text(uses_malone_p)
- Simple Test Project does not use Launchpad for bug tracking.
>>> tracker_text = find_tag_by_id(anon_browser.contents, 'bugtracker')
>>> print extract_text(tracker_text)
Bugs are tracked in tracker.example.com/.
=== modified file 'lib/lp/bugs/templates/bug-create-question.pt'
--- lib/lp/bugs/templates/bug-create-question.pt 2009-08-31 09:58:28 +0000
+++ lib/lp/bugs/templates/bug-create-question.pt 2010-08-31 21:27:50 +0000
@@ -17,7 +17,7 @@
A question was already created from this bug.
</tal:question>
<tal:uses-malone
- condition="not: context/pillar/official_malone">
+ condition="not: context/pillar/bug_tracking_usage/enumvalue:LAUNCHPAD">
<tal:target
replace="context/target/displayname">Firefox</tal:target>
does not use Launchpad to track bugs.
=== modified file 'lib/lp/bugs/templates/bugtarget-bugs.pt'
--- lib/lp/bugs/templates/bugtarget-bugs.pt 2010-08-04 11:01:15 +0000
+++ lib/lp/bugs/templates/bugtarget-bugs.pt 2010-08-31 21:27:50 +0000
@@ -10,12 +10,15 @@
i18n:domain="malone"
>
<metal:block fill-slot="head_epilogue">
+ <meta tal:condition="not: view/bug_tracking_usage/enumvalue:LAUNCHPAD"
+ name="robots" content="noindex,nofollow" />
<style type="text/css">
p#more-hot-bugs {float:right; margin-top:7px;}
</style>
</metal:block>
<body>
- <tal:side metal:fill-slot="side" condition="view/uses_launchpad_bugtracker">
+ <tal:side metal:fill-slot="side"
+ condition="view/bug_tracking_usage/enumvalue:LAUNCHPAD">
<div id="involvement" class="portlet">
<ul class="involvement">
<li style="border: none">
@@ -95,7 +98,8 @@
- <tal:uses_malone condition="view/uses_launchpad_bugtracker">
+ <tal:uses_launchpad_bugtracker
+ condition="view/bug_tracking_usage/enumvalue:LAUNCHPAD">
<tal:has_bugtasks condition="context/has_bugtasks">
<div class="search-box" style="margin-bottom:2em">
<metal:search
@@ -162,27 +166,55 @@
<p id="no-bugs-report"><a href="+filebug">Report a bug.</a></p>
</tal:no_hot_bugs>
- </tal:uses_malone>
-
- <tal:not_uses_malone condition="not: view/uses_launchpad_bugtracker"
- tal:define ="configure_bugtracker context/menu:overview/configure_bugtracker | nothing">
- <p id="no-malone"><strong><tal:project_title replace="context/title" /> does not use Launchpad for
- bug tracking.</strong></p>
- <p tal:condition="view/external_bugtracker"
- id="bugtracker"><strong>Bugs are tracked in
- <tal:bugtracker replace="structure view/bugtracker" />.</strong>
- </p>
-
- <p tal:condition="context/required:launchpad.Edit"
- id="no-malone-edit"
- >
- <a tal:condition="configure_bugtracker"
- tal:replace="structure configure_bugtracker/fmt:link"/>
- <a tal:condition="not: configure_bugtracker"
- tal:attributes="href string:${context/fmt:url/+edit}">
- Enable bug tracking.</a>
- </p>
- </tal:not_uses_malone>
+ </tal:uses_launchpad_bugtracker>
+
+ <p id="no-malone"
+ tal:condition="view/bug_tracking_usage/enumvalue:UNKNOWN">
+ <strong>
+ Launchpad does not know where to forward bug reports to contact the
+ developers of <tal:project_title replace="context/title" />.
+ </strong>
+ </p>
+
+ <p tal:condition="view/external_bugtracker"
+ id="bugtracker">
+ <strong>Bugs are tracked in
+ <tal:bugtracker replace="structure view/bugtracker" />.
+ </strong>
+ </p>
+
+ <tal:also_in_ubuntu
+ condition="not: view/bug_tracking_usage/enumvalue:LAUNCHPAD">
+ <p tal:define="packages context/ubuntu_packages | nothing"
+ tal:condition="packages">
+ <tal:displayname replace="context/displayname"/>
+ bug reports are
+ <tal:also condition="view/external_bugtracker">also</tal:also>
+ tracked in:
+ <tal:packages repeat="package packages">
+ <span style="white-space: nowrap"
+ tal:content="structure package/fmt:link" /><tal:comma
+ condition="not:repeat/package/end">,</tal:comma></tal:packages>.
+ </p>
+ </tal:also_in_ubuntu>
+
+ <div
+ tal:condition="not: view/bug_tracking_usage/enumvalue:LAUNCHPAD"
+ tal:define="configure_bugtracker context/menu:overview/configure_bugtracker | nothing">
+ <a class="sprite maybe"
+ href="https://help.launchpad.net/Bugs">Getting started
+ with bug tracking in Launchpad</a>.
+
+ <p tal:condition="context/required:launchpad.Edit"
+ id="no-malone-edit"
+ >
+ <a tal:condition="configure_bugtracker"
+ tal:replace="structure configure_bugtracker/fmt:link"/>
+ <a tal:condition="not: configure_bugtracker"
+ tal:attributes="href string:${context/fmt:url/+edit}">
+ Enable bug tracking.</a>
+ </p>
+ </div>
</div><!-- main -->
</body>
=== modified file 'lib/lp/bugs/templates/bugtarget-macros-filebug.pt'
--- lib/lp/bugs/templates/bugtarget-macros-filebug.pt 2010-07-01 06:14:05 +0000
+++ lib/lp/bugs/templates/bugtarget-macros-filebug.pt 2010-08-31 21:27:50 +0000
@@ -298,7 +298,7 @@
</p>
</tal:singular>
<ul class="product-bug-options" tal:repeat="product context/products">
- <li condition="product/official_malone">
+ <li condition="product/bug_tracking_usage/enumvalue:LAUNCHPAD">
<tal:link replace="structure product/fmt:link" />
<ul class="bulleted">
<tal:external-tracker
=== modified file 'lib/lp/bugs/templates/bugtask-requestfix-upstream.pt'
--- lib/lp/bugs/templates/bugtask-requestfix-upstream.pt 2010-07-23 16:00:36 +0000
+++ lib/lp/bugs/templates/bugtask-requestfix-upstream.pt 2010-08-31 21:27:50 +0000
@@ -50,7 +50,7 @@
</div>
</div>
- <div id="upstream-text" tal:condition="not: product/official_malone"
+ <div id="upstream-text" tal:condition="not: product/bug_tracking_usage/enumvalue:LAUNCHPAD"
tal:define="widgets view/bugwatch_widgets;
bugtracker product/getExternalBugTracker">
<p tal:condition="bugtracker">
@@ -156,14 +156,14 @@
</p>
<tal:no_bug_supervisor tal:condition="not:product/bug_supervisor">
- <p tal:condition="product/official_malone">
+ <p tal:condition="product/bug_tracking_usage/enumvalue:LAUNCHPAD">
<a tal:replace="structure product/owner/fmt:link">Sample Person</a>, the
<tal:product tal:replace="product/displayname">Firefox</tal:product>
registrant, will be notified about this bug.
</p>
- <p tal:condition="not: product/official_malone">
+ <p tal:condition="not: product/bug_tracking_usage/enumvalue:LAUNCHPAD">
There is no bug supervisor for
<tal:product tal:replace="product/displayname">Firefox</tal:product>.
This means that there is nobody upstream we can notify about
=== modified file 'lib/lp/bugs/templates/distribution-upstream-bug-report.pt'
--- lib/lp/bugs/templates/distribution-upstream-bug-report.pt 2010-02-16 17:59:59 +0000
+++ lib/lp/bugs/templates/distribution-upstream-bug-report.pt 2010-08-31 21:27:50 +0000
@@ -166,10 +166,12 @@
</td>
</tal:has-bugtracker>
<tal:has-no-bugtracker condition="not: item/bugtracker">
- <td tal:condition="item/official_malone" align="center">
+ <td tal:condition="item/bug_tracking_usage/enumvalue:LAUNCHPAD"
+ align="center">
<img src="/@@/yes" title="Launchpad" />
</td>
- <td tal:condition="not: item/official_malone" align="center">
+ <td tal:condition="not: item/bug_tracking_usage/enumvalue:LAUNCHPAD"
+ align="center">
<img src="/@@/no" title="Unknown" />
<a tal:condition="item/product/required:launchpad.Edit"
tal:attributes="href item/product_edit_url">
@@ -225,11 +227,11 @@
tal:content="item/upstream_bugs_delta"></a>
</td>
<tal:upstream-in-launchpad
- condition="item/official_malone">
+ condition="item/bug_tracking_usage/enumvalue:LAUNCHPAD">
<td colspan="4" class="good"> </td>
</tal:upstream-in-launchpad>
<tal:upstream-not-in-launchpad
- condition="not: item/official_malone">
+ condition="not: item/bug_tracking_usage/enumvalue:LAUNCHPAD">
<td tal:attributes="class string:amount ${item/watched_bugs_class}"
tal:content="item/watched_bugs" />
<td tal:attributes="class string:amount ${item/watched_bugs_class}"
=== modified file 'lib/lp/bugs/tests/bugtarget-questiontarget.txt'
--- lib/lp/bugs/tests/bugtarget-questiontarget.txt 2009-06-12 16:36:02 +0000
+++ lib/lp/bugs/tests/bugtarget-questiontarget.txt 2010-08-31 21:27:50 +0000
@@ -43,8 +43,8 @@
prerequisite for a bug to become a question is that the bugtarget's
pillar must use Launchpad to track bugs.
- >>> bug.affected_pillars[0].official_malone
- True
+ >>> bug.affected_pillars[0].bug_tracking_usage
+ <DBItem ServiceUsage.LAUNCHPAD, (20) Launchpad>
>>> bug.canBeAQuestion()
True
@@ -56,8 +56,8 @@
>>> firefox = firefox_bug.bugtasks[0].target
>>> IQuestionTarget.providedBy(firefox)
True
- >>> firefox.distribution.official_malone
- False
+ >>> firefox.distribution.bug_tracking_usage
+ <DBItem ServiceUsage.UNKNOWN, (10) Unknown>
>>> firefox_bug.canBeAQuestion()
False
=== modified file 'lib/lp/bugs/tests/test_bugtask_1.py'
--- lib/lp/bugs/tests/test_bugtask_1.py 2010-08-20 20:31:18 +0000
+++ lib/lp/bugs/tests/test_bugtask_1.py 2010-08-31 21:27:50 +0000
@@ -17,6 +17,7 @@
)
from canonical.launchpad.webapp.interfaces import ILaunchBag
from canonical.testing import DatabaseFunctionalLayer
+from lp.app.enums import ServiceUsage
from lp.bugs.interfaces.bug import IBugSet
from lp.bugs.interfaces.bugtask import (
BugTaskStatus,
@@ -73,7 +74,9 @@
# Mark an upstream task on bug #1 "Fix Released"
bug_one = bugset.get(1)
firefox_upstream = self._getBugTaskByTarget(bug_one, firefox)
- self.assert_(firefox_upstream.product.official_malone)
+ self.assertEqual(
+ ServiceUsage.LAUNCHPAD,
+ firefox_upstream.product.bug_tracking_usage)
self.old_firefox_status = firefox_upstream.status
firefox_upstream.transitionToStatus(
BugTaskStatus.FIXRELEASED, getUtility(ILaunchBag).user)
@@ -127,12 +130,10 @@
"""
non_malone_using_bugtasks = [
related_task for related_task in bugtask.related_tasks
- if not related_task.target_uses_malone
- ]
+ if not related_task.target_uses_malone]
pending_bugwatch_bugtasks = [
related_bugtask for related_bugtask in non_malone_using_bugtasks
- if related_bugtask.bugwatch is None
- ]
+ if related_bugtask.bugwatch is None]
self.assert_(
len(pending_bugwatch_bugtasks) > 0,
'Bugtask %s on %s has no related bug watches elsewhere.' % (
@@ -166,8 +167,7 @@
resolved_related_tasks = [
related_task for related_task in bugtask.related_tasks
if (_is_resolved_upstream_task(related_task) or
- _is_resolved_bugwatch_task(related_task))
- ]
+ _is_resolved_bugwatch_task(related_task))]
self.assert_(len(resolved_related_tasks) > 0)
self.assert_(
@@ -203,8 +203,7 @@
open_related_tasks = [
related_task for related_task in bugtask.related_tasks
if (_is_open_upstream_task(related_task) or
- _is_open_bugwatch_task(related_task))
- ]
+ _is_open_bugwatch_task(related_task))]
self.assert_(
len(open_related_tasks) > 0,
=== modified file 'lib/lp/registry/adapters.py'
--- lib/lp/registry/adapters.py 2010-08-20 20:31:18 +0000
+++ lib/lp/registry/adapters.py 2010-08-31 21:27:50 +0000
@@ -7,16 +7,25 @@
__all__ = [
'distroseries_to_launchpadusage',
+ 'distroseries_to_serviceusage',
'PollSubset',
'productseries_to_product',
]
-from zope.component import getUtility
+from zope.component import (
+ adapter,
+ getUtility,
+ )
from zope.component.interfaces import ComponentLookupError
-from zope.interface import implements
+from zope.interface import (
+ implementer,
+ implements,
+ )
from canonical.launchpad.webapp.interfaces import ILaunchpadPrincipal
+from lp.app.interfaces.launchpad import IServiceUsage
+from lp.registry.interfaces.distroseries import IDistroSeries
from lp.registry.interfaces.poll import (
IPollSet,
IPollSubset,
@@ -25,6 +34,13 @@
)
+@implementer(IServiceUsage)
+@adapter(IDistroSeries)
+def distroseries_to_serviceusage(distroseries):
+ """Adapts `IDistroSeries` object to `IServiceUsage`."""
+ return distroseries.distribution
+
+
def distroseries_to_launchpadusage(distroseries):
"""Adapts `IDistroSeries` object to `ILaunchpadUsage`."""
return distroseries.distribution
=== modified file 'lib/lp/registry/browser/sourcepackage.py'
--- lib/lp/registry/browser/sourcepackage.py 2010-08-23 22:29:52 +0000
+++ lib/lp/registry/browser/sourcepackage.py 2010-08-31 21:27:50 +0000
@@ -73,6 +73,7 @@
from canonical.launchpad.webapp.publisher import LaunchpadView
from canonical.lazr.utils import smartquote
from canonical.widgets import LaunchpadRadioWidget
+from lp.app.enums import ServiceUsage
from lp.answers.browser.questiontarget import (
QuestionTargetAnswersMenu,
QuestionTargetFacetMixin,
@@ -283,8 +284,7 @@
self.product = getUtility(IProductSet)[product_name]
series_list = [
series for series in self.product.series
- if series.status != SeriesStatus.OBSOLETE
- ]
+ if series.status != SeriesStatus.OBSOLETE]
# If the product is not being changed, then the current
# productseries can be the default choice. Otherwise,
@@ -306,8 +306,7 @@
series_list.remove(dev_focus)
vocab_terms = [
SimpleTerm(series, series.name, series.name)
- for series in series_list
- ]
+ for series in series_list]
dev_focus_term = SimpleTerm(
dev_focus, dev_focus.name, "%s (Recommended)" % dev_focus.name)
vocab_terms.insert(0, dev_focus_term)
@@ -339,6 +338,7 @@
next_url = None
main_action_label = u'Change'
+
def main_action(self, data):
productseries = data['productseries']
# Because it is part of a multistep view, the next_url can't
@@ -575,7 +575,7 @@
if self.context.productseries is None:
return False
product = self.context.productseries.product
- if product.official_malone:
+ if product.bug_tracking_usage == ServiceUsage.LAUNCHPAD:
return True
bugtracker = product.bugtracker
if bugtracker is None:
=== modified file 'lib/lp/registry/browser/tests/distribution-views.txt'
--- lib/lp/registry/browser/tests/distribution-views.txt 2010-06-16 08:22:00 +0000
+++ lib/lp/registry/browser/tests/distribution-views.txt 2010-08-31 21:27:50 +0000
@@ -106,8 +106,8 @@
The view accepts most of the distribution fields.
- >>> distribution.official_malone
- False
+ >>> distribution.bug_tracking_usage
+ <DBItem ServiceUsage.UNKNOWN, (10) Unknown>
>>> view.field_names
['displayname', 'title', 'summary', 'description',
@@ -131,7 +131,7 @@
guidelines
>>> distribution.official_malone
- True
+ <DBItem ServiceUsage.LAUNCHPAD, (20) Launchpad>
Only admins and owners can access the view.
=== modified file 'lib/lp/registry/browser/tests/sourcepackage-views.txt'
--- lib/lp/registry/browser/tests/sourcepackage-views.txt 2010-08-04 05:27:22 +0000
+++ lib/lp/registry/browser/tests/sourcepackage-views.txt 2010-08-31 21:27:50 +0000
@@ -293,8 +293,8 @@
>>> view = create_initialized_view(
... package, name='+upstream-connections')
- >>> print product.official_malone
- False
+ >>> print product.bug_tracking_usage.name
+ UNKNOWN
>>> print product.bugtracker
None
>>> print view.has_bugtracker
=== modified file 'lib/lp/registry/configure.zcml'
--- lib/lp/registry/configure.zcml 2010-08-23 03:25:20 +0000
+++ lib/lp/registry/configure.zcml 2010-08-31 21:27:50 +0000
@@ -171,6 +171,8 @@
factory="lp.registry.adapters.distroseries_to_launchpadusage"
permission="zope.Public"/>
<adapter
+ factory="lp.registry.adapters.distroseries_to_serviceusage" />
+ <adapter
provides="canonical.launchpad.webapp.interfaces.IBreadcrumb"
for="lp.registry.interfaces.distroseries.IDistroSeries"
factory="lp.registry.browser.distroseries.DistroSeriesBreadcrumb"
@@ -1379,6 +1381,11 @@
factory="lp.registry.adapters.productseries_to_product"
permission="zope.Public"/>
<adapter
+ provides="lp.app.interfaces.launchpad.IServiceUsage"
+ for="lp.registry.interfaces.productseries.IProductSeries"
+ factory="lp.registry.adapters.productseries_to_product"
+ permission="zope.Public"/>
+ <adapter
provides="lp.app.interfaces.launchpad.ILaunchpadUsage"
for="lp.registry.interfaces.productseries.IProductSeries"
factory="lp.registry.adapters.productseries_to_product"
=== modified file 'lib/lp/registry/doc/product.txt'
--- lib/lp/registry/doc/product.txt 2010-08-22 19:46:19 +0000
+++ lib/lp/registry/doc/product.txt 2010-08-31 21:27:50 +0000
@@ -1,4 +1,5 @@
-= Product =
+Product
+=======
Launchpad keeps track of the "upstream" world as well as the "distro" world.
The anchorpiece of the "upstream" world is the Product, which is a piece of
@@ -162,7 +163,8 @@
Obsolete Junk
-== Translatable Products ==
+Translatable Products
+---------------------
IProductSet will also tell us which products can be translated:
@@ -217,11 +219,16 @@
The packaging table allows us to list source and distro source packages
related to a certain upstream:
- >>> alsa = productset.getByName('alsa-utils')
- >>> [(sp.name, sp.distroseries.name) for sp in alsa.sourcepackages]
- [(u'alsa-utils', u'sid'), (u'alsa-utils', u'warty')]
- >>> [(sp.name, sp.distribution.name) for sp in alsa.distrosourcepackages]
- [(u'alsa-utils', u'debian'), (u'alsa-utils', u'ubuntu')]
+ >>> alsa = productset.getByName('alsa-utils')
+ >>> [(sp.name, sp.distroseries.name) for sp in alsa.sourcepackages]
+ [(u'alsa-utils', u'sid'), (u'alsa-utils', u'warty')]
+ >>> [(sp.name, sp.distribution.name) for sp in alsa.distrosourcepackages]
+ [(u'alsa-utils', u'debian'), (u'alsa-utils', u'ubuntu')]
+
+For convenience, you can get just the distro source packages for Ubuntu.
+
+ >>> [(sp.name, sp.distribution.name) for sp in alsa.ubuntu_packages]
+ [(u'alsa-utils', u'ubuntu')]
The date_next_suggest_packaging attribute records the date when Launchpad can
resume suggesting Ubuntu packages that the project provides. A value of None
@@ -258,8 +265,8 @@
one.
>>> firefox = getUtility(IProductSet).getByName('firefox')
- >>> firefox.official_malone
- True
+ >>> firefox.bug_tracking_usage
+ <DBItem ServiceUsage.LAUNCHPAD, (20) Launchpad>
>>> print firefox.bug_tracking_usage.name
LAUNCHPAD
>>> firefox.getExternalBugTracker() is None
@@ -307,7 +314,8 @@
True
-== Answer Tracking ==
+Answer Tracking
+---------------
Firefox uses the Answer Tracker as the official application to provide
answers to questions.
@@ -321,7 +329,8 @@
False
-== Product Creation ==
+Product Creation
+----------------
We can create new products with the createProduct() method:
@@ -374,20 +383,21 @@
True
-== Specification Listings ==
+Specification Listings
+----------------------
We should be able to set whether or not a Product uses specifications
officially. It defaults to False.
- >>> firefox = productset.getByName('firefox')
- >>> firefox.official_blueprints
- False
+ >>> firefox = productset.getByName('firefox')
+ >>> firefox.official_blueprints
+ False
We can change it to True.
- >>> firefox.official_blueprints = True
- >>> firefox.official_blueprints
- True
+ >>> firefox.official_blueprints = True
+ >>> firefox.official_blueprints
+ True
We should be able to get lists of specifications in different states
related to a product.
@@ -395,39 +405,40 @@
Basically, we can filter by completeness, and by whether or not the spec is
informational.
- >>> firefox = productset.getByName('firefox')
- >>> from canonical.launchpad.interfaces import SpecificationFilter
+ >>> firefox = productset.getByName('firefox')
+ >>> from canonical.launchpad.interfaces import SpecificationFilter
First, there should be only one informational spec for firefox:
- >>> filter = [SpecificationFilter.INFORMATIONAL]
- >>> for spec in firefox.specifications(filter=filter):
- ... print spec.name
- extension-manager-upgrades
+ >>> filter = [SpecificationFilter.INFORMATIONAL]
+ >>> for spec in firefox.specifications(filter=filter):
+ ... print spec.name
+ extension-manager-upgrades
There are no completed specs for firefox:
- >>> filter = [SpecificationFilter.COMPLETE]
- >>> for spec in firefox.specifications(filter=filter):
- ... print spec.name
+ >>> filter = [SpecificationFilter.COMPLETE]
+ >>> for spec in firefox.specifications(filter=filter):
+ ... print spec.name
And there are five incomplete specs:
- >>> filter = [SpecificationFilter.INCOMPLETE]
- >>> firefox.specifications(filter=filter).count()
- 5
+ >>> filter = [SpecificationFilter.INCOMPLETE]
+ >>> firefox.specifications(filter=filter).count()
+ 5
We can filter for specifications that contain specific text:
- >>> for spec in firefox.specifications(filter=['new']):
- ... print spec.name
- canvas
- e4x
-
-
-== Milestones ==
+ >>> for spec in firefox.specifications(filter=['new']):
+ ... print spec.name
+ canvas
+ e4x
+
+
+Milestones
+----------
We can use IProduct.milestones to get all milestones associated with any
ProductSeries of a product.
@@ -470,7 +481,8 @@
[u'1.0.0', u'0.9.2', u'0.9.1', u'0.9', u'1.0', u'1.0-rc1']
-== Release ==
+Release
+-------
All the releases for a Product can be retrieved through the releases property.
@@ -489,7 +501,8 @@
0.9.1
-== Products With Branches ==
+Products With Branches
+----------------------
Products are considered to officially support Launchpad as a location
for their branches after a branch is set for the development focus
@@ -568,7 +581,8 @@
landscape
-== Primary translatable ==
+Primary translatable
+--------------------
Primary translatable series in a product should follow series where
development is focused on. To be able to do changes to facilitate
@@ -642,7 +656,8 @@
1.0
-= Series list =
+Series list
+-----------
The series for a product are returned as a sorted list, with the
exception that the current development focus is first.
@@ -697,7 +712,9 @@
... print series.name
trunk
-= Changing ownership =
+
+Changing ownership
+==================
If the owner of a project changes, all series and productreleases
owned by the old owner are transfered to the new owner.
=== modified file 'lib/lp/registry/interfaces/product.py'
--- lib/lp/registry/interfaces/product.py 2010-08-22 19:26:46 +0000
+++ lib/lp/registry/interfaces/product.py 2010-08-31 21:27:50 +0000
@@ -637,6 +637,9 @@
distrosourcepackages = Attribute(_("List of distribution packages for "
"this product"))
+ ubuntu_packages = Attribute(
+ _("List of distribution packages for this product in Ubuntu"))
+
series = exported(
doNotSnapshot(
CollectionField(value_type=Object(schema=IProductSeries))))
=== modified file 'lib/lp/registry/model/product.py'
--- lib/lp/registry/model/product.py 2010-08-23 18:03:26 +0000
+++ lib/lp/registry/model/product.py 2010-08-31 21:27:50 +0000
@@ -796,8 +796,6 @@
dsps = []
for packaging in ret:
distro = packaging.distroseries.distribution
- if distro in distros:
- continue
distros.add(distro)
dsps.append(DistributionSourcePackage(
sourcepackagename=packaging.sourcepackagename,
@@ -806,6 +804,15 @@
(x.sourcepackagename.name, x.distribution.name))
@property
+ def ubuntu_packages(self):
+ """The Ubuntu `IDistributionSourcePackage`s linked to the `IProduct`.
+ """
+ ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
+ return [
+ package for package in self.distrosourcepackages
+ if package.distribution == ubuntu]
+
+ @property
def bugtargetdisplayname(self):
"""See IBugTarget."""
return self.displayname
=== modified file 'lib/lp/registry/templates/distribution-index.pt'
--- lib/lp/registry/templates/distribution-index.pt 2010-08-06 16:01:38 +0000
+++ lib/lp/registry/templates/distribution-index.pt 2010-08-31 21:27:50 +0000
@@ -55,7 +55,7 @@
tal:condition="context/official_answers" />
<div tal:replace="structure context/@@+portlet-latestbugs"
- tal:condition="context/official_malone" />
+ tal:condition="context/bug_tracking_usage/enumvalue:LAUNCHPAD" />
<div tal:replace="structure context/@@+portlet-top-contributors" />
</div>
=== modified file 'lib/lp/registry/templates/distribution-search.pt'
--- lib/lp/registry/templates/distribution-search.pt 2009-08-05 19:34:07 +0000
+++ lib/lp/registry/templates/distribution-search.pt 2010-08-31 21:27:50 +0000
@@ -69,7 +69,7 @@
tal:define="distribution package/distribution">
<a
tal:define="link package/menu:bugs/filebug"
- tal:condition="distribution/official_malone"
+ tal:condition="distribution/bug_tracking_usage/enumvalue:LAUNCHPAD"
tal:attributes="href link/url">
<img
tal:attributes="alt link/text"
=== modified file 'lib/lp/registry/templates/product-index.pt'
--- lib/lp/registry/templates/product-index.pt 2010-08-25 19:15:48 +0000
+++ lib/lp/registry/templates/product-index.pt 2010-08-31 21:27:50 +0000
@@ -218,7 +218,7 @@
tal:condition="context/official_answers" />
<div tal:content="structure context/@@+portlet-latestbugs"
- tal:condition="context/official_malone" />
+ tal:condition="context/bug_tracking_usage/enumvalue:LAUNCHPAD" />
<div tal:content="structure context/@@+portlet-top-contributors" />
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2010-08-30 06:38:53 +0000
+++ lib/lp/testing/factory.py 2010-08-31 21:27:50 +0000
@@ -836,7 +836,7 @@
project=project,
registrant=registrant)
if official_malone is not None:
- product.official_malone = official_malone
+ removeSecurityProxy(product).official_malone = official_malone
if official_rosetta is not None:
removeSecurityProxy(product).official_rosetta = official_rosetta
if bug_supervisor is not None: