← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:snap-base-build-channels-by-arch into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:snap-base-build-channels-by-arch into launchpad:master.

Commit message:
Allow SnapBase to specify per-architecture build channels

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/407094

This will allow us to keep core18/i386 builds pinned to a version of snapcraft built for core18 even when snapcraft in general moves on to core20 (which no longer supports i386).
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:snap-base-build-channels-by-arch into launchpad:master.
diff --git a/lib/lp/snappy/interfaces/snapbase.py b/lib/lp/snappy/interfaces/snapbase.py
index ea164ae..4b7a42b 100644
--- a/lib/lp/snappy/interfaces/snapbase.py
+++ b/lib/lp/snappy/interfaces/snapbase.py
@@ -154,7 +154,10 @@ class ISnapBaseEditableAttributes(Interface):
         key_type=TextLine(), required=True, readonly=False,
         description=_(
             "A dictionary mapping snap names to channels to use when building "
-            "snaps that specify this base.")))
+            "snaps that specify this base.  The special '_byarch' key may "
+            "have a mapping of architecture names to mappings of snap names "
+            "to channels, which if present override the channels declared at "
+            "the top level when building for those architectures.")))
 
 
 class ISnapBaseEdit(Interface):
diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py
index cf51374..4eaa4ee 100644
--- a/lib/lp/snappy/model/snap.py
+++ b/lib/lp/snappy/model/snap.py
@@ -892,6 +892,7 @@ class Snap(Storm, WebhookTargetMixin):
             snap_base, snap_base_name = self._findBase(snapcraft_data)
             distro_series = self._pickDistroSeries(snap_base, snap_base_name)
             channels = self._pickChannels(snap_base, channels=channels)
+            channels_by_arch = channels.pop("_byarch", {})
 
             # Sort by Processor.id for determinism.  This is chosen to be
             # the same order as in BinaryPackageBuildSet.createForSource, to
@@ -915,10 +916,13 @@ class Snap(Storm, WebhookTargetMixin):
         builds = []
         for build_instance in architectures_to_build:
             arch = build_instance.architecture
+            arch_channels = dict(channels)
+            if arch in channels_by_arch:
+                arch_channels.update(channels_by_arch[arch])
             try:
                 build = self.requestBuild(
                     requester, archive, supported_arches[arch], pocket,
-                    snap_base=snap_base, channels=channels,
+                    snap_base=snap_base, channels=arch_channels,
                     build_request=build_request)
                 if logger is not None:
                     logger.debug(
diff --git a/lib/lp/snappy/tests/test_snap.py b/lib/lp/snappy/tests/test_snap.py
index a946b58..4d9c92f 100644
--- a/lib/lp/snappy/tests/test_snap.py
+++ b/lib/lp/snappy/tests/test_snap.py
@@ -857,6 +857,60 @@ class TestSnap(TestCaseWithFactory):
             snap_base, snap_base.build_channels,
             distro_series=snap_base.distro_series)
 
+    def test_requestBuildsFromJob_snap_base_build_channels_by_arch(self):
+        # If the snap base declares different build channels for specific
+        # architectures, then requestBuildsFromJob uses those when requesting
+        # builds for those architectures.
+        self.useFixture(GitHostingFixture(blob="base: test-base\n"))
+        processors = [
+            self.factory.makeProcessor(supports_virtualized=True)
+            for _ in range(3)]
+        distroseries = self.factory.makeDistroSeries()
+        for processor in processors:
+            self.makeBuildableDistroArchSeries(
+                distroseries=distroseries, architecturetag=processor.name,
+                processor=processor)
+        with admin_logged_in():
+            snap_base = self.factory.makeSnapBase(
+                name="test-base", distro_series=distroseries,
+                build_channels={
+                    "snapcraft": "stable/launchpad-buildd",
+                    "_byarch": {
+                        processors[0].name: {
+                            "core": "candidate",
+                            "snapcraft": "5.x/stable",
+                            },
+                        },
+                    })
+        snap = self.factory.makeSnap(
+            distroseries=None, git_ref=self.factory.makeGitRefs()[0])
+        job = getUtility(ISnapRequestBuildsJobSource).create(
+            snap, snap.owner.teamowner, snap_base.distro_series.main_archive,
+            PackagePublishingPocket.RELEASE, None)
+        self.assertEqual(
+            get_transaction_timestamp(IStore(snap)), job.date_created)
+        transaction.commit()
+        with person_logged_in(job.requester):
+            builds = snap.requestBuildsFromJob(
+                job.requester, job.archive, job.pocket,
+                build_request=job.build_request)
+        self.assertThat(builds, MatchesSetwise(
+            *(MatchesStructure(
+                requester=Equals(job.requester),
+                snap=Equals(job.snap),
+                archive=Equals(job.archive),
+                distro_arch_series=Equals(
+                    snap_base.distro_series[processor.name]),
+                pocket=Equals(job.pocket),
+                snap_base=Equals(snap_base),
+                channels=Equals(channels))
+              for processor, channels in (
+                  (processors[0],
+                   {"core": "candidate", "snapcraft": "5.x/stable"}),
+                  (processors[1], {"snapcraft": "stable/launchpad-buildd"}),
+                  (processors[2], {"snapcraft": "stable/launchpad-buildd"}),
+                  ))))
+
     def test_requestBuildsFromJob_unsupported_remote(self):
         # If the snap is based on an external Git repository from which we
         # don't support fetching blobs, requestBuildsFromJob falls back to