← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~sinzui/launchpad/bugtask-set-packaging-0 into lp:launchpad/devel

 

Curtis Hovey has proposed merging lp:~sinzui/launchpad/bugtask-set-packaging-0 into lp:launchpad/devel.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)


This is my branch to create a packaging during the bug-also-affects process.

    lp:~sinzui/launchpad/bugtask-set-packaging-0
    Diff size: 454
    Launchpad bug:
          https://bugs.launchpad.net/bugs/184077
    Test command: ./bin/test -vv \
          -t test_bugtask_adding -t bugtask-adding-views
    Pre-implementation: Deryck, Bryce, Brian
    Target release: 10.08


Create a packaging during the bug-also-affects process
------------------------------------------------------

When using the bug-also-affect process to add a BugTask, and there
is no Packaging link, the user is asked to locate the upstream/downstream,
and a notification is show suggesting that the step could be avoided by
creating a Packaging link. This is a bad experience, because the notification
takes the user away his goal. This is also bad because the Packaging link
process is very similar the the bug-also-affects process.

They user could state that the select upstream/downstream is the default
and Launchpad would create the Packaging link when the BugTask is added.


Rules
-----

    * Add a checkbox to the base also-affect form so that the user can
      indicate that the link should be created
      [X] Link the package to the upstream project?
          Always suggest this project when adding an upstream bug for this
          package.
    * Show the checkbox when the user is using affect project from a
      source package.
    * Show the checkbox when the user chooses to register a new project.
    * Show the checkbox when the user


QA
--

    * Visit a unlinked package with a bug.
    * Choose also affects project
    * Locate a project and select
      [X] Link the package to the upstream project?
    * Complete for form
    * Verify that the project is linked on the packages overview page.

    * Visit a unlinked package with a bug.
    * Choose also affects project
    * Choose to register a new project
    * Select
      [X] Link the package to the upstream project?
    * Complete for form
    * Verify that the project is linked on the packages overview page.


Lint
----

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/bugs/browser/bugalsoaffects.py
  lib/lp/bugs/browser/tests/bugtask-adding-views.txt
  lib/lp/bugs/browser/tests/test_bugtask_adding.py
  lib/lp/bugs/interfaces/bugtask.py
  lib/lp/bugs/templates/bugtask-affects-new-product.pt
  lib/lp/bugs/templates/bugtask-requestfix-upstream.pt

^ There is lint in
    lib/lp/bugs/browser/tests/bugtask-adding-views.txt
    lib/lp/bugs/interfaces/bugtask.py
that I can clean up after the review


Test
----

    * lib/lp/bugs/browser/tests/bugtask-adding-views.txt
      * Removed the obsolete test for the packaging notice.
      * Updated to form to work with the new changes.
      * I may be able to delete some redundant parts of this this test. It
        looked like some tinkering was need to remove parts and keep other
        parts still working.
    * lib/lp/bugs/browser/tests/test_bugtask_adding.py
      * Added new tests to verify when the add_packaging field is available
        and to verify when a packaging link is created.


Implementation
--------------

    * lib/lp/bugs/browser/bugalsoaffects.py
      * Replaced the field_names attribute with a property to include
        add_packaging when there is not packaging link.
      * Removed obsolete packaging link notice.
      * Added the add_packaging field to some of the steps to ensure the
        value is passed to the final step
      * Added a rule to create a packaging link.
    * lib/lp/bugs/interfaces/bugtask.py
      * Added add_packaging to the choose product and register product
        interfaces.
    * lib/lp/bugs/templates/bugtask-affects-new-product.pt
      * Added a field to collect the value of add_packaging if it can be
        used.
    * lib/lp/bugs/templates/bugtask-requestfix-upstream.pt
      * Added a field to pass the hidden value of add_packaging
-- 
https://code.launchpad.net/~sinzui/launchpad/bugtask-set-packaging-0/+merge/30861
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~sinzui/launchpad/bugtask-set-packaging-0 into lp:launchpad/devel.
=== modified file 'lib/lp/bugs/browser/bugalsoaffects.py'
--- lib/lp/bugs/browser/bugalsoaffects.py	2010-04-23 20:10:48 +0000
+++ lib/lp/bugs/browser/bugalsoaffects.py	2010-07-24 19:51:11 +0000
@@ -38,6 +38,7 @@
     IBugWatchSet, NoBugTrackerFound, UnrecognizedBugTrackerURL)
 from lp.registry.interfaces.distributionsourcepackage import (
     IDistributionSourcePackage)
+from lp.registry.interfaces.packaging import IPackagingUtil, PackagingType
 from lp.registry.interfaces.product import (IProductSet, License)
 from canonical.launchpad.validators import LaunchpadValidationError
 from canonical.launchpad.validators.email import email_validator
@@ -80,10 +81,24 @@
         '../templates/bugtask-choose-affected-product.pt')
 
     custom_widget('product', SearchForUpstreamPopupWidget)
-    _field_names = ['product']
     label = u"Record as affecting another project"
     step_name = "choose_product"
 
+    @property
+    def can_link_package(self):
+        bugtask = self.context
+        is_package_bugtask = IDistributionSourcePackage.providedBy(
+            bugtask.target)
+        return is_package_bugtask and bugtask.target.upstream_product is None
+
+    @property
+    def _field_names(self):
+        """The fields needed to choose an existing project."""
+        names = ['product']
+        if self.can_link_package:
+            names.append('add_packaging')
+        return names
+
     def initialize(self):
         super(ChooseProductStep, self).initialize()
         if (self.widgets['product'].hasInput() or
@@ -113,27 +128,10 @@
                 # so we can go straight to the page asking for the remote
                 # bug URL.
                 self.request.form['field.product'] = upstream.name
+                self.request.form['field.add_packaging'] = 'off'
                 self.next_step = ProductBugTaskCreationStep
             return
 
-        distroseries = bugtask.distribution.currentseries
-        if distroseries is not None:
-            sourcepackage = distroseries.getSourcePackage(
-                bugtask.sourcepackagename)
-
-            self.request.response.addInfoNotification(
-                self._needProjectNotice(bugtask, sourcepackage))
-
-    def _needProjectNotice(self, bugtask, sourcepackage):
-        return structured(
-            _("""
-                Please select the appropriate upstream project. This step can
-                be avoided by <a href="%(package_url)s/+edit-packaging"
-                >updating the packaging information for
-                %(full_package_name)s</a>."""),
-            full_package_name=bugtask.bugtargetdisplayname,
-            package_url=canonical_url(sourcepackage))
-
     def validateStep(self, data):
         if data.get('product'):
             try:
@@ -155,7 +153,7 @@
         self.setFieldError(
             'product',
             structured("""
-                There is no project in Launchpad named "%s". Please 
+                There is no project in Launchpad named "%s". Please
                 <a href="/projects"
                 onclick="YUI().use('event').Event.simulate(
                          document.getElementById('%s'), 'click');
@@ -169,6 +167,10 @@
         # Inject the selected product into the form and set the next_step to
         # be used by our multistep controller.
         self.request.form['field.product'] = data['product'].name
+        if data.get('add_packaging', False):
+            self.request.form['field.add_packaging'] = 'on'
+        else:
+            self.request.form['field.add_packaging'] = 'off'
         self.next_step = ProductBugTaskCreationStep
 
 
@@ -234,7 +236,7 @@
             except NoBugTrackerFound:
                 # Delegate to another view which will ask the user if (s)he
                 # wants to create the bugtracker now.
-                if list(self.target_field_names) == ['product']:
+                if 'product' in self.target_field_names:
                     self.next_step = UpstreamBugTrackerCreationStep
                 else:
                     assert 'distribution' in self.target_field_names
@@ -488,7 +490,7 @@
         '../templates/bugtask-requestfix-upstream.pt')
 
     label = "Confirm project"
-    target_field_names = ('product',)
+    target_field_names = ('product', 'add_packaging')
     main_action_label = u'Add to Bug Report'
     schema = IAddBugTaskWithUpstreamLinkForm
 
@@ -523,8 +525,7 @@
             LinkUpstreamHowOptions.LINK_UPSTREAM:
                 'bug_url',
             LinkUpstreamHowOptions.EMAIL_UPSTREAM_DONE:
-                'upstream_email_address_done'
-            }
+                'upstream_email_address_done'}
 
         # Examine the radio group if it has valid input.
         link_upstream_how = self.widgets['link_upstream_how']
@@ -596,7 +597,15 @@
             getUtility(IBugTrackerSet).ensureBugTracker(
                 bug_url, self.user, BugTrackerType.EMAILADDRESS)
             data['bug_url'] = bug_url
-
+        if data.get('add_packaging', False):
+            # Create a packaging link so that Launchpad will suggest the
+            # upstream project to the user.
+            packaging_util = getUtility(IPackagingUtil)
+            packaging_util.createPackaging(
+                productseries=data['product'].development_focus,
+                sourcepackagename=self.context.target.sourcepackagename,
+                distroseries=self.context.target.distribution.currentseries,
+                packaging=PackagingType.PRIME, owner=self.user)
         return super(ProductBugTaskCreationStep, self).main_action(data)
 
     @property
@@ -680,11 +689,25 @@
     schema = IAddBugTaskWithProductCreationForm
     custom_widget('bug_url', StrippedTextWidget, displayWidth=62)
     custom_widget('existing_product', LaunchpadRadioWidget)
-    field_names = ['bug_url', 'displayname', 'name', 'summary']
     existing_products = None
     MAX_PRODUCTS_TO_DISPLAY = 10
     licenses = [License.DONT_KNOW]
 
+    @property
+    def can_link_package(self):
+        bugtask = self.context
+        is_package_bugtask = IDistributionSourcePackage.providedBy(
+            bugtask.target)
+        return is_package_bugtask and bugtask.target.upstream_product is None
+
+    @property
+    def field_names(self):
+        """The fields needed to choose an existing project."""
+        names = ['bug_url', 'displayname', 'name', 'summary']
+        if self.can_link_package:
+            names.append('add_packaging')
+        return names
+
     def _loadProductsUsingBugTracker(self):
         """Find products using the bugtracker wich runs on the given URL.
 
@@ -791,8 +814,7 @@
             name=data['name'],
             displayname=data['displayname'], title=data['displayname'],
             summary=data['summary'], licenses=self.licenses,
-            registrant=self.user
-            )
+            registrant=self.user)
         data['product'] = product
         self._createBugTaskAndWatch(data, set_bugtracker=True)
         # Now that the product is configured set the owner to be the registry

=== modified file 'lib/lp/bugs/browser/tests/bugtask-adding-views.txt'
--- lib/lp/bugs/browser/tests/bugtask-adding-views.txt	2010-04-23 20:10:48 +0000
+++ lib/lp/bugs/browser/tests/bugtask-adding-views.txt	2010-07-24 19:51:11 +0000
@@ -29,6 +29,7 @@
     >>> add_task_view = get_and_setup_view(
     ...     firefox_task, '+choose-affected-product', form={}, method='GET')
 
+
 We haven't posted the form, so we'll see one button.
 
     >>> [action.label for action in add_task_view.actions]
@@ -65,6 +66,7 @@
 
     >>> form = {
     ...     'field.actions.continue': '', 'field.product': 'evolution',
+    ...     'field.add_packaging': 'off',
     ...     'field.__visited_steps__': 'choose_product'}
     >>> add_task_view = get_and_setup_view(
     ...     firefox_task, '+choose-affected-product', form)
@@ -118,8 +120,8 @@
     u'firefox'
 
 If some package doesn't have a packaging link, a product will have to
-be chosen manually, and a notification will be displayed, explaining
-why the product wasn't chosen automatically.
+be chosen manually, and the user may choose to link the package to the
+project..
 
     >>> ubuntu_thunderbird = ubuntu.getSourcePackage('thunderbird')
     >>> thunderbird_bug = ubuntu_thunderbird.createBug(create_params)
@@ -131,13 +133,11 @@
 
     >>> add_task_view.step_name
     'choose_product'
+    >>> add_task_view.field_names
+    ['product', 'add_packaging', '__visited_steps__']
+
     >>> print add_task_view.widgets['product']._getFormInput()
     None
-    >>> len(add_task_view.request.response.notifications)
-    1
-    >>> for notification in add_task_view.request.response.notifications:
-    ...     print notification.message
-    Please select the appropriate upstream project. This step...
 
 Sometimes the distribution won't have any series, though. In that
 case, we won't prompt the user to add a link, since he can't actually
@@ -187,6 +187,7 @@
     >>> form = {
     ...     'field.actions.continue': '1',
     ...     'field.product': u'no-such-product',
+    ...     'field.add_packaging': 'off',
     ...     'field.__visited_steps__':
     ...         'choose_product|specify_remote_bug_url',
     ...     }
@@ -602,6 +603,7 @@
 
     >>> form = {
     ...     'field.actions.continue': '', 'field.product': 'frobnitz',
+    ...     'field.add_packaging': 'off',
     ...     'field.__visited_steps__': 'choose_product'}
     >>> add_task_view = get_and_setup_view(
     ...     firefox_task, '+choose-affected-product', form)

=== added file 'lib/lp/bugs/browser/tests/test_bugtask_adding.py'
--- lib/lp/bugs/browser/tests/test_bugtask_adding.py	1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/browser/tests/test_bugtask_adding.py	2010-07-24 19:51:11 +0000
@@ -0,0 +1,158 @@
+# Copyright 2010 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+__metaclass__ = type
+
+
+from zope.component import getUtility
+
+from lp.registry.interfaces.packaging import IPackagingUtil, PackagingType
+from lp.testing import TestCaseWithFactory
+from lp.testing.views import create_initialized_view
+
+from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
+from canonical.launchpad.ftests import login_person
+from canonical.testing import DatabaseFunctionalLayer
+
+
+class TestProductBugTaskCreationStep(TestCaseWithFactory):
+
+    layer = DatabaseFunctionalLayer
+
+    def setUp(self):
+        super(TestProductBugTaskCreationStep, self).setUp()
+        ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
+        self.ubuntu_series = ubuntu['hoary']
+        self.sourcepackagename = self.factory.makeSourcePackageName('bat')
+        self.sourcepackage = self.factory.makeSourcePackage(
+            sourcepackagename=self.sourcepackagename,
+            distroseries=self.ubuntu_series)
+        self.distrosourcepackage = self.factory.makeDistributionSourcePackage(
+            sourcepackagename=self.sourcepackagename, distribution=ubuntu)
+        self.factory.makeSourcePackagePublishingHistory(
+            sourcepackagename=self.sourcepackagename,
+            distroseries=self.ubuntu_series)
+        self.product = self.factory.makeProduct(name="bat")
+        self.packaging_util = getUtility(IPackagingUtil)
+        self.user = self.factory.makePerson()
+        login_person(self.user)
+        self.bug_task = self.factory.makeBugTask(
+            target=self.distrosourcepackage, owner=self.user)
+        self.bug = self.bug_task.bug
+
+    def test_choose_product_when_packaging_does_not_exist(self):
+        # Verify the view is on the first step and that it includes the
+        # add_packaging field.
+        view = create_initialized_view(
+            self.bug_task, '+choose-affected-product')
+        self.assertEqual('choose_product', view.view.step_name)
+        self.assertEqual(
+            ['product', 'add_packaging', '__visited_steps__'],
+            view.view.field_names)
+
+    def test_choose_product_when_packaging_does_exist(self):
+        # Verify the view is on the second step and that the add_packaging
+        # field was set to False.
+        self.packaging_util.createPackaging(
+            self.product.development_focus, self.sourcepackagename,
+            self.ubuntu_series, PackagingType.PRIME, self.user)
+        view = create_initialized_view(
+            self.bug_task, '+choose-affected-product')
+        self.assertEqual('specify_remote_bug_url', view.view.step_name)
+        field_names = [
+            'link_upstream_how', 'upstream_email_address_done', 'bug_url',
+            'product', 'add_packaging', '__visited_steps__']
+        self.assertEqual(field_names, view.view.field_names)
+        add_packaging_field = view.view.widgets['add_packaging']
+        self.assertEqual(False, add_packaging_field.getInputValue())
+
+    def test_rechoose_product_when_packaging_does_exist(self):
+        # Verify the user can rechoose the product (the first step) and that
+        # the add_packaging field is not included when the package is linked.
+        self.packaging_util.createPackaging(
+            self.product.development_focus, self.sourcepackagename,
+            self.ubuntu_series, PackagingType.PRIME, self.user)
+        form = {'field.product': 'bat'}
+        view = create_initialized_view(
+            self.bug_task, '+choose-affected-product', form=form)
+        self.assertEqual('choose_product', view.view.step_name)
+        field_names = ['product', '__visited_steps__']
+        self.assertEqual(field_names, view.view.field_names)
+
+    def test_create_upstream_bugtask_without_packaging(self):
+        # Verify that the project has a new bugtask and no packaging link.
+        form = {
+            'field.product': 'bat',
+            'field.add_packaging': 'off',
+            'field.__visited_steps__':
+                'choose_product|specify_remote_bug_url',
+            'field.actions.continue': 'Continue',
+            }
+        view = create_initialized_view(
+            self.bug_task, '+choose-affected-product', form=form)
+        self.assertEqual([], view.view.errors)
+        self.assertTrue(self.bug.getBugTask(self.product) is not None)
+        has_packaging = self.packaging_util.packagingEntryExists(
+            self.sourcepackagename, self.ubuntu_series,
+            self.product.development_focus)
+        self.assertFalse(has_packaging)
+
+    def test_create_upstream_bugtask_with_packaging(self):
+        # Verify that the project has a new bugtask and packaging link.
+        form = {
+            'field.product': 'bat',
+            'field.add_packaging': 'on',
+            'field.__visited_steps__':
+                'choose_product|specify_remote_bug_url',
+            'field.actions.continue': 'Continue',
+            }
+        view = create_initialized_view(
+            self.bug_task, '+choose-affected-product', form=form)
+        self.assertEqual([], view.view.errors)
+        self.assertTrue(self.bug.getBugTask(self.product) is not None)
+        has_packaging = self.packaging_util.packagingEntryExists(
+            self.sourcepackagename, self.ubuntu_series,
+            self.product.development_focus)
+        self.assertTrue(has_packaging)
+
+    def test_register_product_fields_packaging_exists(self):
+        # The view includes the add_packaging field.
+        view = create_initialized_view(
+            self.bug_task, '+affects-new-product')
+        self.assertEqual(
+            ['bug_url', 'displayname', 'name', 'summary', 'add_packaging'],
+            view.field_names)
+
+    def test_register_product_fields_packaging_does_not_exist(self):
+        # The view does not include the add_packaging field.
+        self.packaging_util.createPackaging(
+            self.product.development_focus, self.sourcepackagename,
+            self.ubuntu_series, PackagingType.PRIME,
+            self.user)
+        view = create_initialized_view(
+            self.bug_task, '+affects-new-product')
+        self.assertEqual(
+            ['bug_url', 'displayname', 'name', 'summary'],
+             view.field_names)
+
+    def test_register_project_create_upstream_bugtask_with_packaging(self):
+        # Verify the new project has a bug task and packaging link.
+        form = {
+            'field.bug_url': 'http://bugs.foo.org/bugs/show_bug.cgi?id=8',
+            'field.name': 'fruit',
+            'field.displayname': 'Fruit',
+            'field.summary': 'The Fruit summary',
+            'field.add_packaging': 'on',
+            'field.actions.continue': 'Continue',
+            }
+        view = create_initialized_view(
+            self.bug_task, '+affects-new-product', form=form)
+        self.assertEqual([], view.errors)
+        targets = [bugtask.target for bugtask in self.bug.bugtasks
+                   if bugtask.target.name == 'fruit']
+        self.assertEqual(1, len(targets))
+        product = targets[0]
+        has_packaging = self.packaging_util.packagingEntryExists(
+            self.sourcepackagename, self.ubuntu_series,
+            product.development_focus)
+        self.assertTrue(has_packaging)

=== modified file 'lib/lp/bugs/interfaces/bugtask.py'
--- lib/lp/bugs/interfaces/bugtask.py	2010-06-25 15:03:10 +0000
+++ lib/lp/bugs/interfaces/bugtask.py	2010-07-24 19:51:11 +0000
@@ -1494,6 +1494,11 @@
     bug_url = StrippedTextLine(
         title=_('URL'), required=False, constraint=valid_remote_bug_url,
         description=_("The URL of this bug in the remote bug tracker."))
+    add_packaging = Bool(
+        title=_('Link the package to the upstream project?'),
+        description=_('Always suggest this project when adding an '
+                      'upstream bug for this package.'),
+        required=True, default=False)
 
 
 class IAddBugTaskWithProductCreationForm(Interface):
@@ -1509,6 +1514,11 @@
             "followed by letters, dots, hyphens or plusses. e.g. firefox, "
             "linux, gnome-terminal."))
     summary = Summary(title=_('Project summary'), required=True)
+    add_packaging = Bool(
+        title=_('Link the package to the upstream project?'),
+        description=_('Always suggest this project when adding an '
+                      'upstream bug for this package.'),
+        required=True, default=False)
 
 
 class INominationsReviewTableBatchNavigator(ITableBatchNavigator):

=== modified file 'lib/lp/bugs/templates/bugtask-affects-new-product.pt'
--- lib/lp/bugs/templates/bugtask-affects-new-product.pt	2010-07-02 16:21:46 +0000
+++ lib/lp/bugs/templates/bugtask-affects-new-product.pt	2010-07-24 19:51:11 +0000
@@ -64,6 +64,12 @@
           <tal:product-summary define="widget nocall:widgets/summary">
             <metal:block use-macro="context/@@launchpad_form/widget_row" />
           </tal:product-summary>
+
+          <tal:can_link_package condition="view/can_link_package">
+            <tal:add-packaging define="widget nocall:widgets/add_packaging">
+              <metal:block use-macro="context/@@launchpad_form/widget_row" />
+            </tal:add-packaging>
+          </tal:can_link_package>
         </table>
 
         <div class="actions">

=== modified file 'lib/lp/bugs/templates/bugtask-requestfix-upstream.pt'
--- lib/lp/bugs/templates/bugtask-requestfix-upstream.pt	2009-09-08 09:25:58 +0000
+++ lib/lp/bugs/templates/bugtask-requestfix-upstream.pt	2010-07-24 19:51:11 +0000
@@ -36,6 +36,8 @@
 
       <tal:visited_steps
           replace="structure view/widgets/__visited_steps__/hidden" />
+      <tal:add_packaging
+          replace="structure view/widgets/add_packaging/hidden" />
 
       <div class="field">