launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #27029
[Merge] ~cjwatson/launchpad:snap-base-arch into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:snap-base-arch into launchpad:master.
Commit message:
Add and use SnapBaseArch
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1862258 in Launchpad itself: "base: core20 snap builds are dispatched for i386, which always fails"
https://bugs.launchpad.net/launchpad/+bug/1862258
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/402533
A snap base may not support all the architectures supported by its underlying distroseries: in particular, core20 does not support i386. Add a `SnapBaseArch` table along the same lines as the existing `SnapArch` (but with a simpler `setProcessors`, since only registry experts and admins can edit `SnapBase` anyway), and intersect the architectures supported by the snap base with other existing constraints when dispatching snap builds.
DB MP: https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/402532
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:snap-base-arch into launchpad:master.
diff --git a/database/schema/security.cfg b/database/schema/security.cfg
index c3aba65..b13d4a8 100644
--- a/database/schema/security.cfg
+++ b/database/schema/security.cfg
@@ -301,6 +301,7 @@ public.sharingjob = SELECT, INSERT, UPDATE, DELETE
public.snap = SELECT, INSERT, UPDATE, DELETE
public.snaparch = SELECT, INSERT, DELETE
public.snapbase = SELECT, INSERT, UPDATE, DELETE
+public.snapbasearch = SELECT, INSERT, DELETE
public.snapbuild = SELECT, INSERT, UPDATE, DELETE
public.snapbuildjob = SELECT, INSERT, UPDATE, DELETE
public.snapfile = SELECT, INSERT, UPDATE, DELETE
@@ -842,6 +843,7 @@ public.product = SELECT
public.snap = SELECT, UPDATE
public.snaparch = SELECT
public.snapbase = SELECT
+public.snapbasearch = SELECT
public.snapbuild = SELECT, INSERT
public.snapbuildjob = SELECT
public.sourcepackagename = SELECT
@@ -1032,6 +1034,7 @@ public.seriessourcepackagebranch = SELECT
public.snap = SELECT
public.snaparch = SELECT
public.snapbase = SELECT
+public.snapbasearch = SELECT
public.snapbuild = SELECT, UPDATE
public.snapbuildjob = SELECT, INSERT
public.snapfile = SELECT
@@ -1490,6 +1493,7 @@ public.signedcodeofconduct = SELECT
public.snap = SELECT, UPDATE
public.snaparch = SELECT
public.snapbase = SELECT
+public.snapbasearch = SELECT
public.snapbuild = SELECT, UPDATE
public.snapbuildjob = SELECT, INSERT, UPDATE
public.snapfile = SELECT, INSERT, UPDATE
@@ -2719,6 +2723,7 @@ public.product = SELECT
public.snap = SELECT, UPDATE
public.snaparch = SELECT
public.snapbase = SELECT
+public.snapbasearch = SELECT
public.snapbuild = SELECT, INSERT, UPDATE
public.snapbuildjob = SELECT, UPDATE
public.snapfile = SELECT
diff --git a/lib/lp/snappy/interfaces/snapbase.py b/lib/lp/snappy/interfaces/snapbase.py
index a5fdf90..21e4729 100644
--- a/lib/lp/snappy/interfaces/snapbase.py
+++ b/lib/lp/snappy/interfaces/snapbase.py
@@ -44,12 +44,14 @@ from zope.schema import (
Datetime,
Dict,
Int,
+ List,
TextLine,
)
from lp import _
from lp.app.errors import NameLookupFailed
from lp.app.validators.name import name_validator
+from lp.buildmaster.interfaces.processor import IProcessor
from lp.registry.interfaces.distroseries import IDistroSeries
from lp.services.fields import (
ContentNameField,
@@ -125,6 +127,12 @@ class ISnapBaseView(Interface):
could not be found.
"""
+ processors = exported(CollectionField(
+ title=_("Processors"),
+ description=_("The architectures that the snap base supports."),
+ value_type=Reference(schema=IProcessor),
+ readonly=True))
+
class ISnapBaseEditableAttributes(Interface):
"""`ISnapBase` attributes that can be edited.
@@ -197,6 +205,14 @@ class ISnapBaseEdit(Interface):
:param dependency: an `IArchive`.
"""
+ @operation_parameters(
+ processors=List(
+ value_type=Reference(schema=IProcessor), required=True))
+ @export_write_operation()
+ @operation_for_version("devel")
+ def setProcessors(processors):
+ """Set the architectures that the snap base supports."""
+
@export_destructor_operation()
@operation_for_version("devel")
def destroySelf():
@@ -218,11 +234,14 @@ class ISnapBaseSetEdit(Interface):
"""`ISnapBaseSet` methods that require launchpad.Edit permission."""
@call_with(registrant=REQUEST_USER)
+ @operation_parameters(
+ processors=List(
+ value_type=Reference(schema=IProcessor), required=False))
@export_factory_operation(
ISnapBase, ["name", "display_name", "distro_series", "build_channels"])
@operation_for_version("devel")
def new(registrant, name, display_name, distro_series, build_channels,
- date_created=None):
+ processors=None, date_created=None):
"""Create an `ISnapBase`."""
@operation_parameters(
diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py
index 1a108b0..4dc26e5 100644
--- a/lib/lp/snappy/model/snap.py
+++ b/lib/lp/snappy/model/snap.py
@@ -612,7 +612,7 @@ class Snap(Storm, WebhookTargetMixin):
processors = property(_getProcessors, setProcessors)
- def _isBuildableArchitectureAllowed(self, das):
+ def _isBuildableArchitectureAllowed(self, das, snap_base=None):
"""Check whether we may build for a buildable `DistroArchSeries`.
The caller is assumed to have already checked that a suitable chroot
@@ -624,20 +624,21 @@ class Snap(Storm, WebhookTargetMixin):
and das.processor in self.processors
and (
das.processor.supports_virtualized
- or not self.require_virtualized))
+ or not self.require_virtualized)
+ and (snap_base is None or das.processor in snap_base.processors))
- def _isArchitectureAllowed(self, das, pocket):
+ def _isArchitectureAllowed(self, das, pocket, snap_base=None):
return (
das.getChroot(pocket=pocket) is not None
- and self._isBuildableArchitectureAllowed(das))
+ and self._isBuildableArchitectureAllowed(das, snap_base=snap_base))
- def getAllowedArchitectures(self, distro_series=None):
+ def getAllowedArchitectures(self, distro_series=None, snap_base=None):
"""See `ISnap`."""
if distro_series is None:
distro_series = self.distro_series
return [
das for das in distro_series.buildable_architectures
- if self._isBuildableArchitectureAllowed(das)]
+ if self._isBuildableArchitectureAllowed(das, snap_base=snap_base)]
@property
def store_distro_series(self):
@@ -779,7 +780,8 @@ class Snap(Storm, WebhookTargetMixin):
snap_base=None, channels=None, build_request=None):
"""See `ISnap`."""
self._checkRequestBuild(requester, archive)
- if not self._isArchitectureAllowed(distro_arch_series, pocket):
+ if not self._isArchitectureAllowed(
+ distro_arch_series, pocket, snap_base=snap_base):
raise SnapBuildDisallowedArchitecture(distro_arch_series, pocket)
if not channels:
@@ -898,7 +900,8 @@ class Snap(Storm, WebhookTargetMixin):
# minimise confusion.
supported_arches = OrderedDict(
(das.architecturetag, das) for das in sorted(
- self.getAllowedArchitectures(distro_series),
+ self.getAllowedArchitectures(
+ distro_series, snap_base=snap_base),
key=attrgetter("processor.id"))
if (architectures is None or
das.architecturetag in architectures))
diff --git a/lib/lp/snappy/model/snapbase.py b/lib/lp/snappy/model/snapbase.py
index 8916c61..c2f2a76 100644
--- a/lib/lp/snappy/model/snapbase.py
+++ b/lib/lp/snappy/model/snapbase.py
@@ -27,6 +27,7 @@ from zope.interface import implementer
from zope.security.proxy import removeSecurityProxy
from lp.app.errors import NotFoundError
+from lp.buildmaster.model.processor import Processor
from lp.registry.interfaces.pocket import PackagePublishingPocket
from lp.registry.model.person import Person
from lp.services.database.constants import DEFAULT
@@ -85,6 +86,30 @@ class SnapBase(Storm):
self.date_created = date_created
self.is_default = False
+ def _getProcessors(self):
+ return list(Store.of(self).find(
+ Processor,
+ Processor.id == SnapBaseArch.processor_id,
+ SnapBaseArch.snap_base == self))
+
+ def setProcessors(self, processors):
+ """See `ISnapBase`."""
+ enablements = dict(Store.of(self).find(
+ (Processor, SnapBaseArch),
+ Processor.id == SnapBaseArch.processor_id,
+ SnapBaseArch.snap_base == self))
+ for proc in enablements:
+ if proc not in processors:
+ Store.of(self).remove(enablements[proc])
+ for proc in processors:
+ if proc not in self.processors:
+ snap_base_arch = SnapBaseArch()
+ snap_base_arch.snap_base = self
+ snap_base_arch.processor = proc
+ Store.of(self).add(snap_base_arch)
+
+ processors = property(_getProcessors, setProcessors)
+
@property
def dependencies(self):
"""See `ISnapBase`."""
@@ -145,18 +170,35 @@ class SnapBase(Storm):
Store.of(self).remove(self)
+class SnapBaseArch(Storm):
+ """Link table to back `SnapArch.processors`."""
+
+ __storm_table__ = "SnapBaseArch"
+ __storm_primary__ = ("snap_base_id", "processor_id")
+
+ snap_base_id = Int(name="snap_base", allow_none=False)
+ snap_base = Reference(snap_base_id, "SnapBase.id")
+
+ processor_id = Int(name="processor", allow_none=False)
+ processor = Reference(processor_id, "Processor.id")
+
+
@implementer(ISnapBaseSet)
class SnapBaseSet:
"""See `ISnapBaseSet`."""
def new(self, registrant, name, display_name, distro_series,
- build_channels, date_created=DEFAULT):
+ build_channels, processors=None, date_created=DEFAULT):
"""See `ISnapBaseSet`."""
store = IMasterStore(SnapBase)
snap_base = SnapBase(
registrant, name, display_name, distro_series, build_channels,
date_created=date_created)
store.add(snap_base)
+ if processors is None:
+ processors = [
+ das.processor for das in distro_series.enabled_architectures]
+ snap_base.setProcessors(processors)
return snap_base
def __iter__(self):
diff --git a/lib/lp/snappy/tests/test_snap.py b/lib/lp/snappy/tests/test_snap.py
index be338d7..50d1269 100644
--- a/lib/lp/snappy/tests/test_snap.py
+++ b/lib/lp/snappy/tests/test_snap.py
@@ -300,7 +300,8 @@ class TestSnap(TestCaseWithFactory):
snap = self.factory.makeSnap(
distroseries=distroarchseries.distroseries, processors=[processor])
with admin_logged_in():
- snap_base = self.factory.makeSnapBase()
+ snap_base = self.factory.makeSnapBase(
+ distro_series=distroarchseries.distroseries)
build = snap.requestBuild(
snap.owner, snap.distro_series.main_archive, distroarchseries,
PackagePublishingPocket.UPDATES, snap_base=snap_base)
@@ -745,20 +746,21 @@ class TestSnap(TestCaseWithFactory):
# base, requestBuildsFromJob requests builds for the appropriate
# distroseries for the base.
self.useFixture(GitHostingFixture(blob="base: test-base\n"))
- with admin_logged_in():
- snap_base = self.factory.makeSnapBase(
- name="test-base",
- build_channels={"snapcraft": "stable/launchpad-buildd"})
- self.factory.makeSnapBase()
+ distroseries = self.factory.makeDistroSeries()
for arch_tag in ("mips64el", "riscv64"):
self.makeBuildableDistroArchSeries(
- distroseries=snap_base.distro_series, architecturetag=arch_tag,
+ distroseries=distroseries, architecturetag=arch_tag,
processor=self.factory.makeProcessor(
name=arch_tag, supports_virtualized=True))
+ with admin_logged_in():
+ snap_base = self.factory.makeSnapBase(
+ name="test-base", distro_series=distroseries,
+ build_channels={"snapcraft": "stable/launchpad-buildd"})
+ self.factory.makeSnapBase()
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,
+ snap, snap.owner.teamowner, distroseries.main_archive,
PackagePublishingPocket.RELEASE, None)
self.assertEqual(
get_transaction_timestamp(IStore(snap)), job.date_created)
@@ -769,27 +771,29 @@ class TestSnap(TestCaseWithFactory):
build_request=job.build_request)
self.assertRequestedBuildsMatch(
builds, job, ["mips64el", "riscv64"], snap_base,
- snap_base.build_channels, distro_series=snap_base.distro_series)
+ snap_base.build_channels, distro_series=distroseries)
def test_requestBuildsFromJob_no_distroseries_no_explicit_base(self):
# If the snap doesn't specify a distroseries and has no explicit
# base, requestBuildsFromJob requests builds for the appropriate
# distroseries for the default base.
self.useFixture(GitHostingFixture(blob="name: foo\n"))
+ distroseries = self.factory.makeDistroSeries()
+ for arch_tag in ("mips64el", "riscv64"):
+ self.makeBuildableDistroArchSeries(
+ distroseries=distroseries, architecturetag=arch_tag,
+ processor=self.factory.makeProcessor(
+ name=arch_tag, supports_virtualized=True))
with admin_logged_in():
snap_base = self.factory.makeSnapBase(
+ distro_series=distroseries,
build_channels={"snapcraft": "stable/launchpad-buildd"})
getUtility(ISnapBaseSet).setDefault(snap_base)
self.factory.makeSnapBase()
- for arch_tag in ("mips64el", "riscv64"):
- self.makeBuildableDistroArchSeries(
- distroseries=snap_base.distro_series, architecturetag=arch_tag,
- processor=self.factory.makeProcessor(
- name=arch_tag, supports_virtualized=True))
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,
+ snap, snap.owner.teamowner, distroseries.main_archive,
PackagePublishingPocket.RELEASE, None)
self.assertEqual(
get_transaction_timestamp(IStore(snap)), job.date_created)
@@ -800,7 +804,7 @@ class TestSnap(TestCaseWithFactory):
build_request=job.build_request)
self.assertRequestedBuildsMatch(
builds, job, ["mips64el", "riscv64"], snap_base,
- snap_base.build_channels, distro_series=snap_base.distro_series)
+ snap_base.build_channels, distro_series=distroseries)
def test_requestBuildsFromJob_no_distroseries_no_default_base(self):
# If the snap doesn't specify a distroseries and has an explicit
@@ -821,6 +825,40 @@ class TestSnap(TestCaseWithFactory):
job.requester, job.archive, job.pocket,
build_request=job.build_request)
+ def test_requestBuildsFromJob_snap_base_architectures(self):
+ # requestBuildsFromJob intersects the architectures supported by the
+ # snap base with any other constraints.
+ 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"},
+ processors=processors[:2])
+ 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.assertRequestedBuildsMatch(
+ builds, job, [processor.name for processor in processors[:2]],
+ snap_base, snap_base.build_channels,
+ distro_series=snap_base.distro_series)
+
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
@@ -2544,12 +2582,14 @@ class TestSnapSet(TestCaseWithFactory):
def test_makeAutoBuilds_infers_distroseries(self):
# ISnapSet.makeAutoBuilds can infer the series of a snap from the base
# specified in its snapcraft.yaml.
- with admin_logged_in():
- snap_base = self.factory.makeSnapBase(name="core20")
+ distroseries = self.factory.makeDistroSeries()
das = self.makeBuildableDistroArchSeries(
- distroseries=snap_base.distro_series, architecturetag='riscv64',
+ distroseries=distroseries, architecturetag='riscv64',
processor=self.factory.makeProcessor(
name='riscv64', supports_virtualized=True))
+ with admin_logged_in():
+ snap_base = self.factory.makeSnapBase(
+ name="core20", distro_series=distroseries)
[git_ref] = self.factory.makeGitRefs()
owner = self.factory.makePerson()
snap = self.factory.makeSnap(
diff --git a/lib/lp/snappy/tests/test_snapbase.py b/lib/lp/snappy/tests/test_snapbase.py
index 67754d2..c528f40 100644
--- a/lib/lp/snappy/tests/test_snapbase.py
+++ b/lib/lp/snappy/tests/test_snapbase.py
@@ -31,6 +31,7 @@ from lp.snappy.interfaces.snapbase import (
)
from lp.soyuz.interfaces.component import IComponentSet
from lp.testing import (
+ admin_logged_in,
api_url,
celebrity_logged_in,
logout,
@@ -78,6 +79,56 @@ class TestSnapBase(TestCaseWithFactory):
self.assertRaises(CannotDeleteSnapBase, snap_base.destroySelf)
+class TestSnapBaseProcessors(TestCaseWithFactory):
+
+ layer = ZopelessDatabaseLayer
+
+ def setUp(self):
+ super(TestSnapBaseProcessors, self).setUp(user="foo.bar@xxxxxxxxxxxxx")
+ self.unrestricted_procs = [
+ self.factory.makeProcessor() for _ in range(3)]
+ self.restricted_procs = [
+ self.factory.makeProcessor(restricted=True, build_by_default=False)
+ for _ in range(2)]
+ self.procs = self.unrestricted_procs + self.restricted_procs
+ self.factory.makeProcessor()
+ self.distroseries = self.factory.makeDistroSeries()
+ for processor in self.procs:
+ self.factory.makeDistroArchSeries(
+ distroseries=self.distroseries, architecturetag=processor.name,
+ processor=processor)
+
+ def test_new_default_processors(self):
+ # SnapBaseSet.new creates a SnapBaseArch for each available
+ # Processor for the corresponding series.
+ snap_base = getUtility(ISnapBaseSet).new(
+ registrant=self.factory.makePerson(),
+ name=self.factory.getUniqueUnicode(),
+ display_name=self.factory.getUniqueUnicode(),
+ distro_series=self.distroseries, build_channels={})
+ self.assertContentEqual(self.procs, snap_base.processors)
+
+ def test_new_override_processors(self):
+ # SnapBaseSet.new can be given a custom set of processors.
+ snap_base = getUtility(ISnapBaseSet).new(
+ registrant=self.factory.makePerson(),
+ name=self.factory.getUniqueUnicode(),
+ display_name=self.factory.getUniqueUnicode(),
+ distro_series=self.distroseries, build_channels={},
+ processors=self.procs[:2])
+ self.assertContentEqual(self.procs[:2], snap_base.processors)
+
+ def test_set(self):
+ # The property remembers its value correctly.
+ snap_base = self.factory.makeSnapBase()
+ snap_base.setProcessors(self.restricted_procs)
+ self.assertContentEqual(self.restricted_procs, snap_base.processors)
+ snap_base.setProcessors(self.procs)
+ self.assertContentEqual(self.procs, snap_base.processors)
+ snap_base.setProcessors([])
+ self.assertContentEqual([], snap_base.processors)
+
+
class TestSnapBaseSet(TestCaseWithFactory):
layer = ZopelessDatabaseLayer
@@ -368,6 +419,71 @@ class TestSnapBaseWebservice(TestCaseWithFactory):
with person_logged_in(person):
self.assertEqual([], list(snap_base.dependencies))
+ def setUpProcessors(self):
+ self.unrestricted_procs = [
+ self.factory.makeProcessor() for _ in range(3)]
+ self.unrestricted_proc_names = [
+ processor.name for processor in self.unrestricted_procs]
+ self.restricted_procs = [
+ self.factory.makeProcessor(restricted=True, build_by_default=False)
+ for _ in range(2)]
+ self.restricted_proc_names = [
+ processor.name for processor in self.restricted_procs]
+ self.procs = self.unrestricted_procs + self.restricted_procs
+ self.factory.makeProcessor()
+ self.distroseries = self.factory.makeDistroSeries()
+ for processor in self.procs:
+ self.factory.makeDistroArchSeries(
+ distroseries=self.distroseries, architecturetag=processor.name,
+ processor=processor)
+
+ def setProcessors(self, user, snap_base_url, names):
+ ws = webservice_for_person(
+ user, permission=OAuthPermission.WRITE_PUBLIC)
+ return ws.named_post(
+ snap_base_url, "setProcessors",
+ processors=["/+processors/%s" % name for name in names],
+ api_version="devel")
+
+ def assertProcessors(self, user, snap_base_url, names):
+ body = webservice_for_person(user).get(
+ snap_base_url + "/processors", api_version="devel").jsonBody()
+ self.assertContentEqual(
+ names, [entry["name"] for entry in body["entries"]])
+
+ def test_setProcessors_admin(self):
+ """An admin can change the supported processor set."""
+ self.setUpProcessors()
+ with admin_logged_in():
+ snap_base = self.factory.makeSnapBase(
+ distro_series=self.distroseries,
+ processors=self.unrestricted_procs)
+ snap_base_url = api_url(snap_base)
+ admin = self.factory.makeAdministrator()
+ self.assertProcessors(
+ admin, snap_base_url, self.unrestricted_proc_names)
+
+ response = self.setProcessors(
+ admin, snap_base_url,
+ [self.unrestricted_proc_names[0], self.restricted_proc_names[0]])
+ self.assertEqual(200, response.status)
+ self.assertProcessors(
+ admin, snap_base_url,
+ [self.unrestricted_proc_names[0], self.restricted_proc_names[0]])
+
+ def test_setProcessors_non_admin_forbidden(self):
+ """Only admins and registry experts can call setProcessors."""
+ self.setUpProcessors()
+ with admin_logged_in():
+ snap_base = self.factory.makeSnapBase(
+ distro_series=self.distroseries)
+ snap_base_url = api_url(snap_base)
+ person = self.factory.makePerson()
+
+ response = self.setProcessors(
+ person, snap_base_url, [self.unrestricted_proc_names[0]])
+ self.assertEqual(401, response.status)
+
def test_collection(self):
# lp.snap_bases is a collection of all SnapBases.
person = self.factory.makePerson()
diff --git a/lib/lp/testing/factory.py b/lib/lp/testing/factory.py
index e95e83d..e65a596 100644
--- a/lib/lp/testing/factory.py
+++ b/lib/lp/testing/factory.py
@@ -4911,7 +4911,7 @@ class BareLaunchpadObjectFactory(ObjectFactory):
return snappy_series
def makeSnapBase(self, registrant=None, name=None, display_name=None,
- distro_series=None, build_channels=None,
+ distro_series=None, build_channels=None, processors=None,
date_created=DEFAULT):
"""Make a new SnapBase."""
if registrant is None:
@@ -4927,7 +4927,7 @@ class BareLaunchpadObjectFactory(ObjectFactory):
build_channels = {u"snapcraft": u"stable"}
return getUtility(ISnapBaseSet).new(
registrant, name, display_name, distro_series, build_channels,
- date_created=date_created)
+ processors=processors, date_created=date_created)
def makeOCIProjectName(self, name=None):
if name is None: