← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~benji/launchpad/bug-839831 into lp:launchpad

 

Benji York has proposed merging lp:~benji/launchpad/bug-839831 into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #839831 in Launchpad itself: "Can't link blueprints and bugs through the API"
  https://bugs.launchpad.net/launchpad/+bug/839831

For more details, see:
https://code.launchpad.net/~benji/launchpad/bug-839831/+merge/77232

This branch exposes linking a blueprint (specification) to a bug via the
web service.

Tests: tests were added to lib/lp/blueprints/tests/test_webservice.py, run with
bin/test -c -m lp.blueprints.tests.test_webservice -t TestSpecificationBugLinks

Lint: some pre-existing lint was fixed in
lib/lp/blueprints/tests/test_webservice.py

QA: use launchpadlib to link a blueprint to a bug

-- 
https://code.launchpad.net/~benji/launchpad/bug-839831/+merge/77232
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~benji/launchpad/bug-839831 into lp:launchpad.
=== modified file 'lib/canonical/launchpad/interfaces/_schema_circular_imports.py'
--- lib/canonical/launchpad/interfaces/_schema_circular_imports.py	2011-07-15 14:28:21 +0000
+++ lib/canonical/launchpad/interfaces/_schema_circular_imports.py	2011-09-27 20:38:30 +0000
@@ -678,6 +678,10 @@
 patch_reference_property(IProductSeries, 'product', IProduct)
 
 # ISpecification
+ISpecification['linkBug'].queryTaggedValue(
+    LAZR_WEBSERVICE_EXPORTED)['params']['bug'].schema = IBug
+ISpecification['unlinkBug'].queryTaggedValue(
+    LAZR_WEBSERVICE_EXPORTED)['params']['bug'].schema = IBug
 patch_collection_property(ISpecification, 'dependencies', ISpecification)
 patch_collection_property(
     ISpecification, 'linked_branches', ISpecificationBranch)

=== modified file 'lib/lp/blueprints/configure.zcml'
--- lib/lp/blueprints/configure.zcml	2010-12-02 16:13:51 +0000
+++ lib/lp/blueprints/configure.zcml	2011-09-27 20:38:30 +0000
@@ -181,6 +181,7 @@
 
   <class class="lp.blueprints.model.specificationbug.SpecificationBug">
     <allow interface="lp.blueprints.interfaces.specificationbug.ISpecificationBug"/>
+    <allow interface="lazr.restful.interfaces.IJSONPublishable"/>
   </class>
 
   <subscriber

=== modified file 'lib/lp/blueprints/interfaces/specification.py'
--- lib/lp/blueprints/interfaces/specification.py	2011-09-01 13:00:35 +0000
+++ lib/lp/blueprints/interfaces/specification.py	2011-09-27 20:38:30 +0000
@@ -588,6 +588,26 @@
 
     export_as_webservice_entry(as_of="beta")
 
+    @operation_parameters(
+        bug=Reference(schema=Interface))  # Really IBug
+    @export_write_operation()
+    @operation_for_version('devel')
+    def linkBug(bug):
+        """Link a bug to this branch.
+
+        :param bug: IBug to link.
+        """
+
+    @operation_parameters(
+        bug=Reference(schema=Interface))  # Really IBug
+    @export_write_operation()
+    @operation_for_version('devel')
+    def unlinkBug(bug):
+        """Unlink a bug to this branch.
+
+        :param bug: IBug to unlink.
+        """
+
 
 class ISpecificationSet(IHasSpecifications):
     """A container for specifications."""

=== modified file 'lib/lp/blueprints/interfaces/specificationbug.py'
--- lib/lp/blueprints/interfaces/specificationbug.py	2010-08-20 20:31:18 +0000
+++ lib/lp/blueprints/interfaces/specificationbug.py	2011-09-27 20:38:30 +0000
@@ -23,5 +23,3 @@
 
     specification = Object(title=_('The specification linked to the bug.'),
         required=True, readonly=True, schema=ISpecification)
-
-

=== modified file 'lib/lp/blueprints/model/specificationbug.py'
--- lib/lp/blueprints/model/specificationbug.py	2010-08-20 20:31:18 +0000
+++ lib/lp/blueprints/model/specificationbug.py	2011-09-27 20:38:30 +0000
@@ -7,6 +7,7 @@
 
 __all__ = ['SpecificationBug']
 
+from lazr.restful.interfaces import IJSONPublishable
 from sqlobject import ForeignKey
 from zope.interface import implements
 
@@ -17,7 +18,7 @@
 class SpecificationBug(SQLBase):
     """A link between a spec and a bug."""
 
-    implements(ISpecificationBug)
+    implements(ISpecificationBug, IJSONPublishable)
 
     _table = 'SpecificationBug'
     specification = ForeignKey(dbName='specification',
@@ -30,3 +31,9 @@
         """See IBugLink."""
         return self.specification
 
+    def toDataForJSON(self, media_type):
+        """See IJSONPublishable.
+
+        These objects have no JSON representation.
+        """
+        return None

=== modified file 'lib/lp/blueprints/tests/test_webservice.py'
--- lib/lp/blueprints/tests/test_webservice.py	2011-06-21 11:44:21 +0000
+++ lib/lp/blueprints/tests/test_webservice.py	2011-09-27 20:38:30 +0000
@@ -187,7 +187,7 @@
 
     def test_get_specification_on_product(self):
         product = self.factory.makeProduct(name="fooix")
-        spec_object = self.factory.makeSpecification(
+        self.factory.makeSpecification(
             product=product, name="some-spec")
         product_on_webservice = self.getPillarOnWebservice(product)
         spec = product_on_webservice.getSpecification(name="some-spec")
@@ -196,7 +196,7 @@
 
     def test_get_specification_on_distribution(self):
         distribution = self.factory.makeDistribution(name="foobuntu")
-        spec_object = self.factory.makeSpecification(
+        self.factory.makeSpecification(
             distribution=distribution, name="some-spec")
         distro_on_webservice = self.getPillarOnWebservice(distribution)
         spec = distro_on_webservice.getSpecification(name="some-spec")
@@ -207,7 +207,7 @@
         product = self.factory.makeProduct(name="fooix")
         productseries = self.factory.makeProductSeries(
             product=product, name="fooix-dev")
-        spec_object = self.factory.makeSpecification(
+        self.factory.makeSpecification(
             product=product, name="some-spec", goal=productseries)
         product_on_webservice = self.getPillarOnWebservice(product)
         productseries_on_webservice = product_on_webservice.getSeries(
@@ -220,7 +220,7 @@
         distribution = self.factory.makeDistribution(name="foobuntu")
         distroseries = self.factory.makeDistroSeries(
             distribution=distribution, name="maudlin")
-        spec_object = self.factory.makeSpecification(
+        self.factory.makeSpecification(
             distribution=distribution, name="some-spec",
             goal=distroseries)
         distro_on_webservice = self.getPillarOnWebservice(distribution)
@@ -333,3 +333,51 @@
         result = webservice.named_get(
             subscription['self_link'], 'canBeUnsubscribedByUser').jsonBody()
         self.assertFalse(result)
+
+
+class TestSpecificationBugLinks(SpecificationWebserviceTestCase):
+
+    layer = AppServerLayer
+
+    def test_bug_linking(self):
+        # Set up a spec, person, and bug.
+        with person_logged_in(ANONYMOUS):
+            db_spec = self.factory.makeSpecification()
+            db_person = self.factory.makePerson()
+            db_bug = self.factory.makeBug()
+            launchpad = self.factory.makeLaunchpadService()
+
+        # Link the bug to the spec via the web service.
+        with person_logged_in(db_person):
+            spec = ws_object(launchpad, db_spec)
+            bug = ws_object(launchpad, db_bug)
+            # There are no bugs associated with the spec/blueprint yet.
+            self.assertEqual(0, spec.bugs.total_size)
+            spec.linkBug(bug=bug)
+            transaction.commit()
+
+        # The spec now has one bug associated with it and that bug is the one
+        # we linked.
+        self.assertEqual(1, spec.bugs.total_size)
+        self.assertEqual(bug.id, spec.bugs[0].id)
+
+    def test_bug_unlinking(self):
+        # Set up a spec, person, and bug, then link the bug to the spec.
+        with person_logged_in(ANONYMOUS):
+            db_spec = self.factory.makeBlueprint()
+            db_person = self.factory.makePerson()
+            db_bug = self.factory.makeBug()
+            launchpad = self.factory.makeLaunchpadService(person=db_person)
+
+        spec = ws_object(launchpad, db_spec)
+        bug = ws_object(launchpad, db_bug)
+        spec.linkBug(bug=bug)
+
+        # There is only one bug linked at the moment.
+        self.assertEqual(1, spec.bugs.total_size)
+
+        spec.unlinkBug(bug=bug)
+        transaction.commit()
+
+        # Now that we've unlinked the bug, there are no linked bugs at all.
+        self.assertEqual(0, spec.bugs.total_size)