launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #16150
[Merge] lp:~cjwatson/launchpad/builder-history-webservice into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/builder-history-webservice into lp:launchpad.
Commit message:
Export Builder.getBuildRecords and DistroArchSeries.getBuildRecords.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1236819 in Launchpad itself: "Export builder history over API"
https://bugs.launchpad.net/launchpad/+bug/1236819
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/builder-history-webservice/+merge/192820
== Summary ==
The only way to get at a builder's history programmatically is to screen-scrape the Builder:+history page. This results in some pretty awful client-side code. Other IHasBuildRecords objects export getBuildRecords methods; it seems like mainly an oversight that Builder doesn't.
== Proposed fix ==
Make IBuilder subclass IHasBuildRecords. Testing this revealed that it didn't actually implement the IHasBuildRecords.getBuildRecords contract properly (missing pocket keyword argument), so I fixed that too and enforced it with tests. We only get BinaryPackageBuild-type results because of the way that getBuildRecords is exported, but that's an awful lot better than nothing and for most of my purposes the other entries aren't all that interesting.
Along the way, I noticed that IDistroArchSeries also doesn't subclass IHasBuildRecords so in turn DistroArchSeries.getBuildRecords also isn't exported. I fixed that too.
== LOC Rationale ==
+37, mostly new test code. Worth it for the reduction in ridiculous HTML-scraping client code, I feel.
== Tests ==
bin/test -vvct lp.buildmaster.tests.test_builder -t lp.buildmaster.tests.test_webservice -t lp.soyuz.tests.test_binarypackagebuild
== Demo and Q/A ==
Call the relevant methods against qastaging and make sure they return sensible results.
--
https://code.launchpad.net/~cjwatson/launchpad/builder-history-webservice/+merge/192820
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/builder-history-webservice into lp:launchpad.
=== modified file 'lib/lp/buildmaster/configure.zcml'
--- lib/lp/buildmaster/configure.zcml 2013-02-04 06:55:17 +0000
+++ lib/lp/buildmaster/configure.zcml 2013-10-27 15:03:18 +0000
@@ -1,4 +1,4 @@
-<!-- Copyright 2010 Canonical Ltd. This software is licensed under the
+<!-- Copyright 2010-2013 Canonical Ltd. This software is licensed under the
GNU Affero General Public License version 3 (see the file LICENSE).
-->
@@ -17,8 +17,6 @@
class="lp.buildmaster.model.builder.Builder">
<allow
interface="lp.buildmaster.interfaces.builder.IBuilder"/>
- <allow
- interface="lp.soyuz.interfaces.buildrecords.IHasBuildRecords"/>
<require
permission="launchpad.Edit"
set_schema="lp.buildmaster.interfaces.builder.IBuilder"/>
=== modified file 'lib/lp/buildmaster/interfaces/builder.py'
--- lib/lp/buildmaster/interfaces/builder.py 2013-10-02 05:47:26 +0000
+++ lib/lp/buildmaster/interfaces/builder.py 2013-10-27 15:03:18 +0000
@@ -50,6 +50,7 @@
PersonChoice,
Title,
)
+from lp.soyuz.interfaces.buildrecords import IHasBuildRecords
from lp.soyuz.interfaces.processor import IProcessor
@@ -84,7 +85,7 @@
"""The build slave has suffered an error and cannot be used."""
-class IBuilder(IHasOwner):
+class IBuilder(IHasBuildRecords, IHasOwner):
"""Build-slave information and state.
Builder instance represents a single builder slave machine within the
=== modified file 'lib/lp/buildmaster/model/builder.py'
--- lib/lp/buildmaster/model/builder.py 2013-10-10 06:31:30 +0000
+++ lib/lp/buildmaster/model/builder.py 2013-10-27 15:03:18 +0000
@@ -130,17 +130,17 @@
self.builderok = False
self.failnotes = reason
- def getBuildRecords(self, build_state=None, name=None, arch_tag=None,
- user=None, binary_only=True):
+ def getBuildRecords(self, build_state=None, name=None, pocket=None,
+ arch_tag=None, user=None, binary_only=True):
"""See IHasBuildRecords."""
if binary_only:
return getUtility(IBinaryPackageBuildSet).getBuildsForBuilder(
- self.id, build_state, name, arch_tag, user)
+ self.id, build_state, name, pocket, arch_tag, user)
else:
- if arch_tag is not None or name is not None:
+ if arch_tag is not None or name is not None or pocket is not None:
raise IncompatibleArguments(
- "The 'arch_tag' and 'name' parameters can be used only "
- "with binary_only=True.")
+ "The 'arch_tag', 'name', and 'pocket' parameters can be "
+ "used only with binary_only=True.")
return getUtility(IBuildFarmJobSet).getBuildsForBuilder(
self, status=build_state, user=user)
=== modified file 'lib/lp/buildmaster/tests/test_webservice.py'
--- lib/lp/buildmaster/tests/test_webservice.py 2013-09-11 06:05:44 +0000
+++ lib/lp/buildmaster/tests/test_webservice.py 2013-10-27 15:03:18 +0000
@@ -1,4 +1,4 @@
-# Copyright 2011 Canonical Ltd. This software is licensed under the
+# Copyright 2011-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Tests for the builders webservice ."""
@@ -65,3 +65,19 @@
entry = self.webservice.get(
api_url(builder), api_version='devel').jsonBody()
self.assertEndsWith(entry['processor_link'], '/+processors/s1')
+
+ def test_getBuildRecords(self):
+ builder = self.factory.makeBuilder()
+ build = self.factory.makeBinaryPackageBuild(builder=builder)
+ build_title = build.title
+
+ logout()
+ results = self.webservice.named_get(
+ api_url(builder), 'getBuildRecords', pocket='Release',
+ api_version='devel').jsonBody()
+ self.assertEqual(
+ [build_title], [entry['title'] for entry in results['entries']])
+ results = self.webservice.named_get(
+ api_url(builder), 'getBuildRecords', pocket='Proposed',
+ api_version='devel').jsonBody()
+ self.assertEqual(0, len(results['entries']))
=== modified file 'lib/lp/soyuz/browser/tests/test_distroarchseries_webservice.py'
--- lib/lp/soyuz/browser/tests/test_distroarchseries_webservice.py 2013-06-24 15:51:00 +0000
+++ lib/lp/soyuz/browser/tests/test_distroarchseries_webservice.py 2013-10-27 15:03:18 +0000
@@ -58,6 +58,16 @@
#See note above regarding testing of length of .entries
self.assertEqual(1, len(ws_distroseries.architectures.entries))
+ def test_getBuildRecords(self):
+ das = self.factory.makeDistroArchSeries()
+ build = self.factory.makeBinaryPackageBuild(distroarchseries=das)
+ build_title = build.title
+ user = self.factory.makePerson()
+ launchpad = launchpadlib_for("testing", user)
+ ws_das = ws_object(launchpad, das)
+ self.assertEqual(
+ [build_title], [entry.title for entry in ws_das.getBuildRecords()])
+
def test_setChroot_removeChroot_random_user(self):
# Random users are not allowed to set or remove chroots.
das = self.factory.makeDistroArchSeries()
=== modified file 'lib/lp/soyuz/configure.zcml'
--- lib/lp/soyuz/configure.zcml 2013-09-12 05:19:43 +0000
+++ lib/lp/soyuz/configure.zcml 2013-10-27 15:03:18 +0000
@@ -606,8 +606,6 @@
<allow
interface="lp.soyuz.interfaces.distroarchseries.IDistroArchSeriesPublic"/>
<allow
- interface="lp.soyuz.interfaces.buildrecords.IHasBuildRecords"/>
- <allow
interface="lp.soyuz.interfaces.publishing.ICanPublishPackages"/>
<require
permission="launchpad.Admin"
=== modified file 'lib/lp/soyuz/interfaces/binarypackagebuild.py'
--- lib/lp/soyuz/interfaces/binarypackagebuild.py 2013-02-06 10:44:24 +0000
+++ lib/lp/soyuz/interfaces/binarypackagebuild.py 2013-10-27 15:03:18 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""BinaryPackageBuild interfaces."""
@@ -311,7 +311,7 @@
:param builder: An optional `IBuilder`.
"""
- def getBuildsForBuilder(builder_id, status=None, name=None,
+ def getBuildsForBuilder(builder_id, status=None, name=None, pocket=None,
arch_tag=None):
"""Return build records touched by a builder.
@@ -320,6 +320,8 @@
will be returned.
:param name: If name is provided, only builds which correspond to a
matching sourcepackagename will be returned (SQL LIKE).
+ :param pocket: If pocket is provided, only builds for that pocket
+ will be returned.
:param arch_tag: If arch_tag is provided, only builds for that
architecture will be returned.
:return: a `ResultSet` representing the requested builds.
=== modified file 'lib/lp/soyuz/interfaces/distroarchseries.py'
--- lib/lp/soyuz/interfaces/distroarchseries.py 2013-09-10 06:28:26 +0000
+++ lib/lp/soyuz/interfaces/distroarchseries.py 2013-10-27 15:03:18 +0000
@@ -40,6 +40,7 @@
from lp.registry.interfaces.distroseries import IDistroSeries
from lp.registry.interfaces.person import IPerson
from lp.registry.interfaces.role import IHasOwner
+from lp.soyuz.interfaces.buildrecords import IHasBuildRecords
@error_status(httplib.BAD_REQUEST)
@@ -47,7 +48,7 @@
"""Raised when the sha1sum of an uploaded chroot does not match."""
-class IDistroArchSeriesPublic(IHasOwner):
+class IDistroArchSeriesPublic(IHasBuildRecords, IHasOwner):
"""Public attributes for a DistroArchSeries."""
id = Attribute("Identifier")
=== modified file 'lib/lp/soyuz/model/binarypackagebuild.py'
--- lib/lp/soyuz/model/binarypackagebuild.py 2013-08-28 12:03:57 +0000
+++ lib/lp/soyuz/model/binarypackagebuild.py 2013-10-27 15:03:18 +0000
@@ -946,7 +946,7 @@
clauses.append(SourcePackageName.name.is_in(name))
def getBuildsForBuilder(self, builder_id, status=None, name=None,
- arch_tag=None, user=None):
+ pocket=None, arch_tag=None, user=None):
"""See `IBinaryPackageBuildSet`."""
# Circular. :(
from lp.soyuz.model.archive import (
@@ -959,7 +959,7 @@
origin = [Archive]
self.handleOptionalParamsForBuildQueries(
- clauses, origin, status, name, pocket=None, arch_tag=arch_tag)
+ clauses, origin, status, name, pocket, arch_tag=arch_tag)
return IStore(BinaryPackageBuild).using(*origin).find(
BinaryPackageBuild, *clauses).order_by(
=== modified file 'lib/lp/soyuz/tests/test_binarypackagebuild.py'
--- lib/lp/soyuz/tests/test_binarypackagebuild.py 2013-09-10 06:28:26 +0000
+++ lib/lp/soyuz/tests/test_binarypackagebuild.py 2013-10-27 15:03:18 +0000
@@ -17,6 +17,7 @@
from lp.buildmaster.interfaces.buildqueue import IBuildQueue
from lp.buildmaster.interfaces.packagebuild import IPackageBuild
from lp.buildmaster.model.buildqueue import BuildQueue
+from lp.registry.interfaces.pocket import PackagePublishingPocket
from lp.services.job.model.job import Job
from lp.services.webapp.interaction import ANONYMOUS
from lp.services.webapp.interfaces import OAuthPermission
@@ -349,7 +350,8 @@
self.factory.makeBinaryPackageBuild(
archive=self.ds.main_archive, distroarchseries=i386_das),
self.factory.makeBinaryPackageBuild(
- archive=self.ds.main_archive, distroarchseries=i386_das),
+ archive=self.ds.main_archive, distroarchseries=i386_das,
+ pocket=PackagePublishingPocket.PROPOSED),
self.factory.makeBinaryPackageBuild(
archive=self.ds.main_archive, distroarchseries=hppa_das),
]
@@ -437,6 +439,15 @@
arch_tag="i386")
self.assertContentEqual(builds, i386_builds)
+ def test_getBuildsForBuilder_by_pocket(self):
+ # Results can be filtered by pocket.
+ builds = self.build_set.getBuildsForBuilder(
+ self.builder.id, pocket=PackagePublishingPocket.RELEASE)
+ self.assertContentEqual([self.builds[0], self.builds[2]], builds)
+ builds = self.build_set.getBuildsForBuilder(
+ self.builder.id, pocket=PackagePublishingPocket.PROPOSED)
+ self.assertContentEqual([self.builds[1]], builds)
+
class TestBinaryPackageBuildWebservice(TestCaseWithFactory):
"""Test cases for BinaryPackageBuild on the webservice.
Follow ups