launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #15705
[Merge] lp:~ttx/launchpad/lp1193389 into lp:launchpad
Thierry Carrez has proposed merging lp:~ttx/launchpad/lp1193389 into lp:launchpad.
Commit message:
Expose specification goal management in specification API
- Expose proposeGoal, acceptGoal, declineGoal methods and has_accepted_goal attribute
- Under wgrant advice, remove lp.blueprints.subscribers.specification_goalstatus as it's not used and its security model blocks proxied objects
- Add unit tests
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1193389 in Launchpad itself: ""Series goal" should be exported through API"
https://bugs.launchpad.net/launchpad/+bug/1193389
For more details, see:
https://code.launchpad.net/~ttx/launchpad/lp1193389/+merge/171491
Expose specification goal management in specification API
- Expose proposeGoal, acceptGoal, declineGoal methods and has_accepted_goal attribute
- Under wgrant advice, remove lp.blueprints.subscribers.specification_goalstatus as it's not used and its security model blocks proxied objects
- Add unit tests
--
https://code.launchpad.net/~ttx/launchpad/lp1193389/+merge/171491
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~ttx/launchpad/lp1193389 into lp:launchpad.
=== modified file 'lib/lp/blueprints/configure.zcml'
--- lib/lp/blueprints/configure.zcml 2012-09-17 18:55:17 +0000
+++ lib/lp/blueprints/configure.zcml 2013-06-26 09:21:36 +0000
@@ -204,10 +204,6 @@
<subscriber
for="lp.blueprints.interfaces.specification.ISpecification
lazr.lifecycle.interfaces.IObjectModifiedEvent"
- handler="lp.blueprints.subscribers.specification_goalstatus"/>
- <subscriber
- for="lp.blueprints.interfaces.specification.ISpecification
- lazr.lifecycle.interfaces.IObjectModifiedEvent"
handler="lp.blueprints.mail.notifications.notify_specification_modified"/>
<!-- SpecificationSet -->
=== modified file 'lib/lp/blueprints/interfaces/specification.py'
--- lib/lp/blueprints/interfaces/specification.py 2013-04-11 00:51:46 +0000
+++ lib/lp/blueprints/interfaces/specification.py 2013-06-26 09:21:36 +0000
@@ -17,6 +17,7 @@
from lazr.restful.declarations import (
call_with,
export_as_webservice_entry,
+ export_operation_as,
export_write_operation,
exported,
mutator_for,
@@ -70,6 +71,7 @@
)
from lp.blueprints.interfaces.sprint import ISprint
from lp.bugs.interfaces.buglink import IBugLinkTarget
+from lp.bugs.interfaces.bugtarget import IBugTarget
from lp.code.interfaces.branchlink import IHasLinkedBranches
from lp.registry.interfaces.milestone import IMilestone
from lp.registry.interfaces.person import IPerson
@@ -476,20 +478,39 @@
"""Return the list of email addresses that receive notifications."""
# goal management
+ @call_with(proposer=REQUEST_USER)
+ @operation_parameters(
+ goal=Reference(schema=IBugTarget, title=_('Target'),
+ required=False, default=None))
+ @export_write_operation()
+ @operation_for_version("devel")
def proposeGoal(goal, proposer):
"""Propose this spec for a series or distroseries."""
+ @call_with(decider=REQUEST_USER)
+ @export_operation_as('acceptGoal')
+ @export_write_operation()
+ @operation_for_version("devel")
def acceptBy(decider):
"""Mark the spec as being accepted for its current series goal."""
+ @call_with(decider=REQUEST_USER)
+ @export_operation_as('declineGoal')
+ @export_write_operation()
+ @operation_for_version("devel")
def declineBy(decider):
"""Mark the spec as being declined as a goal for the proposed
series.
"""
- has_accepted_goal = Attribute('Is true if this specification has been '
- 'proposed as a goal for a specific series, '
- 'and the drivers of that series have accepted the goal.')
+ has_accepted_goal = exported(
+ Bool(title=_('Series goal is accepted'),
+ readonly=True, required=True,
+ description=_(
+ 'Is true if this specification has been '
+ 'proposed as a goal for a specific series, '
+ 'and the drivers of that series have accepted the goal.')),
+ as_of="devel")
# lifecycle management
def updateLifecycleStatus(user):
=== modified file 'lib/lp/blueprints/subscribers.py'
--- lib/lp/blueprints/subscribers.py 2011-12-30 06:14:56 +0000
+++ lib/lp/blueprints/subscribers.py 2013-06-26 09:21:36 +0000
@@ -9,17 +9,6 @@
from lp.services.database.sqlbase import block_implicit_flushes
-@block_implicit_flushes
-def specification_goalstatus(spec, event):
- """Update goalstatus if productseries or distroseries is changed."""
- delta = spec.getDelta(
- event.object_before_modification, IPerson(event.user))
- if delta is None:
- return
- if delta.productseries is not None or delta.distroseries is not None:
- spec.goalstatus = SpecificationGoalStatus.PROPOSED
-
-
def specification_update_lifecycle_status(spec, event):
"""Mark the specification as started and/or complete if appropriate.
=== modified file 'lib/lp/blueprints/tests/test_webservice.py'
--- lib/lp/blueprints/tests/test_webservice.py 2013-01-25 03:30:08 +0000
+++ lib/lp/blueprints/tests/test_webservice.py 2013-06-26 09:21:36 +0000
@@ -401,3 +401,65 @@
# Now that we've unlinked the bug, there are no linked bugs at all.
self.assertEqual(0, spec.bugs.total_size)
+
+
+class TestSpecificationGoalHandling(SpecificationWebserviceTestCase):
+
+ layer = AppServerLayer
+
+ def setUp(self):
+ super(TestSpecificationGoalHandling, self).setUp()
+ self.driver = self.factory.makePerson()
+ self.proposer = self.factory.makePerson()
+ self.product = self.factory.makeProduct(driver=self.driver)
+ self.series = self.factory.makeProductSeries(product=self.product)
+
+ def test_goal_propose_and_accept(self):
+ # Create spec
+ db_spec = self.factory.makeBlueprint(product=self.product,
+ owner=self.proposer)
+ # Propose for series goal
+ with person_logged_in(self.proposer):
+ launchpad = self.factory.makeLaunchpadService(person=self.proposer)
+ spec = ws_object(launchpad, db_spec)
+ series = ws_object(launchpad, self.series)
+ spec.proposeGoal(goal=series)
+ transaction.commit()
+ self.assertEqual(db_spec.goal, self.series)
+ self.assertFalse(spec.has_accepted_goal)
+
+ # Accept series goal
+ with person_logged_in(self.driver):
+ launchpad = self.factory.makeLaunchpadService(person=self.driver)
+ spec = ws_object(launchpad, db_spec)
+ spec.acceptGoal()
+ transaction.commit()
+ self.assertTrue(spec.has_accepted_goal)
+
+ def test_goal_propose_decline_and_clear(self):
+ # Create spec
+ db_spec = self.factory.makeBlueprint(product=self.product,
+ owner=self.proposer)
+ # Propose for series goal
+ with person_logged_in(self.proposer):
+ launchpad = self.factory.makeLaunchpadService(person=self.proposer)
+ spec = ws_object(launchpad, db_spec)
+ series = ws_object(launchpad, self.series)
+ spec.proposeGoal(goal=series)
+ transaction.commit()
+ self.assertEqual(db_spec.goal, self.series)
+ self.assertFalse(spec.has_accepted_goal)
+
+ with person_logged_in(self.driver):
+ # Decline series goal
+ launchpad = self.factory.makeLaunchpadService(person=self.driver)
+ spec = ws_object(launchpad, db_spec)
+ spec.declineGoal()
+ transaction.commit()
+ self.assertFalse(spec.has_accepted_goal)
+ self.assertEqual(db_spec.goal, self.series)
+
+ # Clear series goal as a driver
+ spec.proposeGoal(goal=None)
+ transaction.commit()
+ self.assertIsNone(db_spec.goal)