launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #26759
[Merge] ~cjwatson/launchpad:snap-build-record-snap-base into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:snap-build-record-snap-base into launchpad:master.
Commit message:
Record the snap base used for each snap build
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/400348
This will be needed in order to dispatch snap base archive dependencies.
DB MP: https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/400347
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:snap-build-record-snap-base into launchpad:master.
diff --git a/lib/lp/snappy/interfaces/snap.py b/lib/lp/snappy/interfaces/snap.py
index 35cf6f6..7448659 100644
--- a/lib/lp/snappy/interfaces/snap.py
+++ b/lib/lp/snappy/interfaces/snap.py
@@ -110,6 +110,7 @@ from lp.services.fields import (
URIField,
)
from lp.services.webhooks.interfaces import IWebhookTarget
+from lp.snappy.interfaces.snapbase import ISnapBase
from lp.snappy.interfaces.snappyseries import (
ISnappyDistroSeries,
ISnappySeries,
@@ -408,6 +409,7 @@ class ISnapView(Interface):
archive=Reference(schema=IArchive),
distro_arch_series=Reference(schema=IDistroArchSeries),
pocket=Choice(vocabulary=PackagePublishingPocket),
+ snap_base=Reference(schema=ISnapBase),
channels=Dict(
title=_("Source snap channels to use for this build."),
description=_(
@@ -419,13 +421,14 @@ class ISnapView(Interface):
@export_factory_operation(Interface, [])
@operation_for_version("devel")
def requestBuild(requester, archive, distro_arch_series, pocket,
- channels=None, build_request=None):
+ snap_base=None, channels=None, build_request=None):
"""Request that the snap package be built.
:param requester: The person requesting the build.
:param archive: The IArchive to associate the build with.
:param distro_arch_series: The architecture to build for.
:param pocket: The pocket that should be targeted.
+ :param snap_base: The `ISnapBase` to use for this build.
:param channels: A dictionary mapping snap names to channels to use
for this build.
:param build_request: The `ISnapBuildRequest` job being processed,
diff --git a/lib/lp/snappy/interfaces/snapbuild.py b/lib/lp/snappy/interfaces/snapbuild.py
index e812f46..7072731 100644
--- a/lib/lp/snappy/interfaces/snapbuild.py
+++ b/lib/lp/snappy/interfaces/snapbuild.py
@@ -1,4 +1,4 @@
-# Copyright 2015-2020 Canonical Ltd. This software is licensed under the
+# Copyright 2015-2021 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Snap package build interfaces."""
@@ -60,6 +60,7 @@ from lp.snappy.interfaces.snap import (
ISnap,
ISnapBuildRequest,
)
+from lp.snappy.interfaces.snapbase import ISnapBase
from lp.soyuz.interfaces.archive import IArchive
from lp.soyuz.interfaces.distroarchseries import IDistroArchSeries
@@ -164,6 +165,11 @@ class ISnapBuildView(IPackageBuild):
title=_("The pocket for which to build."),
vocabulary=PackagePublishingPocket, required=True, readonly=True))
+ snap_base = exported(Reference(
+ ISnapBase,
+ title=_("The snap base to use for this build."),
+ required=False, readonly=True))
+
channels = exported(Dict(
title=_("Source snap channels to use for this build."),
description=_(
@@ -355,7 +361,8 @@ class ISnapBuildSet(ISpecificBuildFarmJobSource):
"""Utility for `ISnapBuild`."""
def new(requester, snap, archive, distro_arch_series, pocket,
- date_created=DEFAULT):
+ snap_base=None, channels=None, date_created=DEFAULT,
+ store_upload_metadata=None, build_request=None):
"""Create an `ISnapBuild`."""
def preloadBuildsData(builds):
diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py
index 2eac649..523ae68 100644
--- a/lib/lp/snappy/model/snap.py
+++ b/lib/lp/snappy/model/snap.py
@@ -776,7 +776,7 @@ class Snap(Storm, WebhookTargetMixin):
raise SnapBuildArchiveOwnerMismatch()
def requestBuild(self, requester, archive, distro_arch_series, pocket,
- channels=None, build_request=None):
+ snap_base=None, channels=None, build_request=None):
"""See `ISnap`."""
self._checkRequestBuild(requester, archive)
if not self._isArchitectureAllowed(distro_arch_series, pocket):
@@ -800,7 +800,8 @@ class Snap(Storm, WebhookTargetMixin):
build = getUtility(ISnapBuildSet).new(
requester, self, archive, distro_arch_series, pocket,
- channels=channels, build_request=build_request)
+ snap_base=snap_base, channels=channels,
+ build_request=build_request)
build.queueBuild()
notify(ObjectCreatedEvent(build, user=requester))
return build
@@ -916,7 +917,8 @@ class Snap(Storm, WebhookTargetMixin):
try:
build = self.requestBuild(
requester, archive, supported_arches[arch], pocket,
- channels, build_request=build_request)
+ snap_base=snap_base, channels=channels,
+ build_request=build_request)
if logger is not None:
logger.debug(
" - %s/%s/%s: Build requested.",
diff --git a/lib/lp/snappy/model/snapbuild.py b/lib/lp/snappy/model/snapbuild.py
index 3a9475b..2b533b7 100644
--- a/lib/lp/snappy/model/snapbuild.py
+++ b/lib/lp/snappy/model/snapbuild.py
@@ -1,4 +1,4 @@
-# Copyright 2015-2020 Canonical Ltd. This software is licensed under the
+# Copyright 2015-2021 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
from __future__ import absolute_import, print_function, unicode_literals
@@ -157,6 +157,8 @@ class SnapBuild(PackageBuildMixin, Storm):
pocket = DBEnum(enum=PackagePublishingPocket, allow_none=False)
+ snap_base_id = Int(name='snap_base', allow_none=True)
+ snap_base = Reference(snap_base_id, 'SnapBase.id')
channels = JSON('channels', allow_none=True)
processor_id = Int(name='processor', allow_none=False)
@@ -190,8 +192,9 @@ class SnapBuild(PackageBuildMixin, Storm):
store_upload_metadata = JSON('store_upload_json_data', allow_none=True)
def __init__(self, build_farm_job, requester, snap, archive,
- distro_arch_series, pocket, channels, processor, virtualized,
- date_created, store_upload_metadata=None, build_request=None):
+ distro_arch_series, pocket, snap_base, channels,
+ processor, virtualized, date_created,
+ store_upload_metadata=None, build_request=None):
"""Construct a `SnapBuild`."""
super(SnapBuild, self).__init__()
self.build_farm_job = build_farm_job
@@ -200,6 +203,7 @@ class SnapBuild(PackageBuildMixin, Storm):
self.archive = archive
self.distro_arch_series = distro_arch_series
self.pocket = pocket
+ self.snap_base = snap_base
self.channels = channels
self.processor = processor
self.virtualized = virtualized
@@ -560,7 +564,7 @@ class SnapBuild(PackageBuildMixin, Storm):
class SnapBuildSet(SpecificBuildFarmJobSourceMixin):
def new(self, requester, snap, archive, distro_arch_series, pocket,
- channels=None, date_created=DEFAULT,
+ snap_base=None, channels=None, date_created=DEFAULT,
store_upload_metadata=None, build_request=None):
"""See `ISnapBuildSet`."""
store = IMasterStore(SnapBuild)
@@ -569,7 +573,7 @@ class SnapBuildSet(SpecificBuildFarmJobSourceMixin):
archive)
snapbuild = SnapBuild(
build_farm_job, requester, snap, archive, distro_arch_series,
- pocket, channels, distro_arch_series.processor,
+ pocket, snap_base, channels, distro_arch_series.processor,
not distro_arch_series.processor.supports_nonvirtualized
or snap.require_virtualized or archive.require_virtualized,
date_created, store_upload_metadata=store_upload_metadata,
diff --git a/lib/lp/snappy/tests/test_snap.py b/lib/lp/snappy/tests/test_snap.py
index e5ec2c7..f827970 100644
--- a/lib/lp/snappy/tests/test_snap.py
+++ b/lib/lp/snappy/tests/test_snap.py
@@ -243,12 +243,15 @@ class TestSnap(TestCaseWithFactory):
snap.owner, snap.distro_series.main_archive, distroarchseries,
PackagePublishingPocket.UPDATES)
self.assertTrue(ISnapBuild.providedBy(build))
- self.assertEqual(snap.owner, build.requester)
- self.assertEqual(snap.distro_series.main_archive, build.archive)
- self.assertEqual(distroarchseries, build.distro_arch_series)
- self.assertEqual(PackagePublishingPocket.UPDATES, build.pocket)
- self.assertIsNone(build.channels)
- self.assertEqual(BuildStatus.NEEDSBUILD, build.status)
+ self.assertThat(build, MatchesStructure(
+ requester=Equals(snap.owner),
+ archive=Equals(snap.distro_series.main_archive),
+ distro_arch_series=Equals(distroarchseries),
+ pocket=Equals(PackagePublishingPocket.UPDATES),
+ snap_base=Is(None),
+ channels=Is(None),
+ status=Equals(BuildStatus.NEEDSBUILD),
+ ))
store = Store.of(build)
store.flush()
build_queue = store.find(
@@ -292,6 +295,20 @@ class TestSnap(TestCaseWithFactory):
queue_record.score()
self.assertEqual(2610, queue_record.lastscore)
+ def test_requestBuild_snap_base(self):
+ # requestBuild can select a snap base.
+ processor = self.factory.makeProcessor(supports_virtualized=True)
+ distroarchseries = self.makeBuildableDistroArchSeries(
+ processor=processor)
+ snap = self.factory.makeSnap(
+ distroseries=distroarchseries.distroseries, processors=[processor])
+ with admin_logged_in():
+ snap_base = self.factory.makeSnapBase()
+ build = snap.requestBuild(
+ snap.owner, snap.distro_series.main_archive, distroarchseries,
+ PackagePublishingPocket.UPDATES, snap_base=snap_base)
+ self.assertEqual(snap_base, build.snap_base)
+
def test_requestBuild_channels(self):
# requestBuild can select non-default channels.
processor = self.factory.makeProcessor(supports_virtualized=True)
@@ -655,8 +672,8 @@ class TestSnap(TestCaseWithFactory):
snap, snap.owner.teamowner, distro.main_archive,
PackagePublishingPocket.RELEASE, {"snapcraft": "edge"})
- def assertRequestedBuildsMatch(self, builds, job, arch_tags, channels,
- distro_series=None):
+ def assertRequestedBuildsMatch(self, builds, job, arch_tags, snap_base,
+ channels, distro_series=None):
if distro_series is None:
distro_series = job.snap.distro_series
self.assertThat(builds, MatchesSetwise(
@@ -666,6 +683,7 @@ class TestSnap(TestCaseWithFactory):
archive=Equals(job.archive),
distro_arch_series=Equals(distro_series[arch_tag]),
pocket=Equals(job.pocket),
+ snap_base=Equals(snap_base),
channels=Equals(channels))
for arch_tag in arch_tags)))
@@ -687,7 +705,8 @@ class TestSnap(TestCaseWithFactory):
job.requester, job.archive, job.pocket,
channels=removeSecurityProxy(job.channels),
build_request=job.build_request)
- self.assertRequestedBuildsMatch(builds, job, ["sparc"], job.channels)
+ self.assertRequestedBuildsMatch(
+ builds, job, ["sparc"], None, job.channels)
def test_requestBuildsFromJob_no_explicit_architectures(self):
# If the snap doesn't specify any architectures,
@@ -704,7 +723,7 @@ class TestSnap(TestCaseWithFactory):
channels=removeSecurityProxy(job.channels),
build_request=job.build_request)
self.assertRequestedBuildsMatch(
- builds, job, ["mips64el", "riscv64"], job.channels)
+ builds, job, ["mips64el", "riscv64"], None, job.channels)
def test_requestBuildsFromJob_architectures_parameter(self):
# If an explicit set of architectures was given as a parameter,
@@ -722,7 +741,7 @@ class TestSnap(TestCaseWithFactory):
architectures={"avr", "riscv64"},
build_request=job.build_request)
self.assertRequestedBuildsMatch(
- builds, job, ["avr", "riscv64"], job.channels)
+ builds, job, ["avr", "riscv64"], None, job.channels)
def test_requestBuildsFromJob_no_distroseries_explicit_base(self):
# If the snap doesn't specify a distroseries but has an explicit
@@ -752,8 +771,8 @@ class TestSnap(TestCaseWithFactory):
job.requester, job.archive, job.pocket,
build_request=job.build_request)
self.assertRequestedBuildsMatch(
- builds, job, ["mips64el", "riscv64"], snap_base.build_channels,
- distro_series=snap_base.distro_series)
+ builds, job, ["mips64el", "riscv64"], snap_base,
+ snap_base.build_channels, distro_series=snap_base.distro_series)
def test_requestBuildsFromJob_no_distroseries_no_explicit_base(self):
# If the snap doesn't specify a distroseries and has no explicit
@@ -783,8 +802,8 @@ class TestSnap(TestCaseWithFactory):
job.requester, job.archive, job.pocket,
build_request=job.build_request)
self.assertRequestedBuildsMatch(
- builds, job, ["mips64el", "riscv64"], snap_base.build_channels,
- distro_series=snap_base.distro_series)
+ builds, job, ["mips64el", "riscv64"], snap_base,
+ snap_base.build_channels, distro_series=snap_base.distro_series)
def test_requestBuildsFromJob_no_distroseries_no_default_base(self):
# If the snap doesn't specify a distroseries and has an explicit
@@ -822,7 +841,7 @@ class TestSnap(TestCaseWithFactory):
removeSecurityProxy(job.channels),
build_request=job.build_request)
self.assertRequestedBuildsMatch(
- builds, job, ["mips64el", "riscv64"], job.channels)
+ builds, job, ["mips64el", "riscv64"], None, job.channels)
def test_requestBuildsFromJob_triggers_webhooks(self):
# requestBuildsFromJob triggers webhooks, and the payload includes a
diff --git a/lib/lp/snappy/tests/test_snapbuild.py b/lib/lp/snappy/tests/test_snapbuild.py
index ee67203..e949c69 100644
--- a/lib/lp/snappy/tests/test_snapbuild.py
+++ b/lib/lp/snappy/tests/test_snapbuild.py
@@ -760,6 +760,7 @@ class TestSnapBuildWebservice(TestCaseWithFactory):
self.assertEqual(
db_build.distro_arch_series.architecturetag, build["arch_tag"])
self.assertEqual("Updates", build["pocket"])
+ self.assertIsNone(build["snap_base_link"])
self.assertIsNone(build["channels"])
self.assertIsNone(build["score"])
self.assertFalse(build["can_be_rescored"])
diff --git a/lib/lp/testing/factory.py b/lib/lp/testing/factory.py
index d4ed1fd..10251b6 100644
--- a/lib/lp/testing/factory.py
+++ b/lib/lp/testing/factory.py
@@ -4831,9 +4831,9 @@ class BareLaunchpadObjectFactory(ObjectFactory):
def makeSnapBuild(self, requester=None, registrant=None, snap=None,
archive=None, distroarchseries=None, pocket=None,
- channels=None, date_created=DEFAULT, build_request=None,
- status=BuildStatus.NEEDSBUILD, builder=None,
- duration=None, **kwargs):
+ snap_base=None, channels=None, date_created=DEFAULT,
+ build_request=None, status=BuildStatus.NEEDSBUILD,
+ builder=None, duration=None, **kwargs):
"""Make a new SnapBuild."""
if requester is None:
requester = self.makePerson()
@@ -4861,7 +4861,7 @@ class BareLaunchpadObjectFactory(ObjectFactory):
pocket = PackagePublishingPocket.UPDATES
snapbuild = getUtility(ISnapBuildSet).new(
requester, snap, archive, distroarchseries, pocket,
- channels=channels, date_created=date_created,
+ snap_base=snap_base, channels=channels, date_created=date_created,
build_request=build_request)
if duration is not None:
removeSecurityProxy(snapbuild).updateStatus(