launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #27704
[Merge] ~cjwatson/launchpad:snap-build-channels-field into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:snap-build-channels-field into launchpad:master.
Commit message:
Refactor field declarations for snap build channels
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/411626
We were repeating the list of known core snaps in quite a lot of places. Start the process of reducing this by introducing a `SnapBuildChannelsField`, used instead of several similar `Dict` field declarations.
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:snap-build-channels-field into launchpad:master.
diff --git a/lib/lp/charms/browser/charmrecipe.py b/lib/lp/charms/browser/charmrecipe.py
index b09b778..da8f66c 100644
--- a/lib/lp/charms/browser/charmrecipe.py
+++ b/lib/lp/charms/browser/charmrecipe.py
@@ -27,10 +27,7 @@ from zope.interface import (
implementer,
Interface,
)
-from zope.schema import (
- Dict,
- TextLine,
- )
+from zope.schema import TextLine
from zope.security.interfaces import Unauthorized
from lp import _
@@ -622,9 +619,9 @@ class CharmRecipeRequestBuildsView(LaunchpadFormView):
class schema(Interface):
"""Schema for requesting a build."""
- channels = Dict(
- title="Source snap channels", key_type=TextLine(), required=True,
- description=ICharmRecipe["auto_build_channels"].description)
+ channels = copy_field(
+ ICharmRecipe["auto_build_channels"], __name__="channels",
+ title="Source snap channels", required=True)
custom_widget_channels = CharmRecipeBuildChannelsWidget
diff --git a/lib/lp/charms/interfaces/charmrecipe.py b/lib/lp/charms/interfaces/charmrecipe.py
index 5f95f7c..da09993 100644
--- a/lib/lp/charms/interfaces/charmrecipe.py
+++ b/lib/lp/charms/interfaces/charmrecipe.py
@@ -90,6 +90,7 @@ from lp.registry.interfaces.product import IProduct
from lp.services.fields import (
PersonChoice,
PublicPersonChoice,
+ SnapBuildChannelsField,
)
from lp.services.webhooks.interfaces import IWebhookTarget
from lp.snappy.validators.channels import channels_validator
@@ -332,13 +333,12 @@ class ICharmRecipeView(Interface):
@call_with(requester=REQUEST_USER)
@operation_parameters(
- channels=Dict(
+ channels=SnapBuildChannelsField(
title=_("Source snap channels to use for these builds."),
- description=_(
+ description_prefix=_(
"A dictionary mapping snap names to channels to use for these "
- "builds. Currently only 'charmcraft', 'core', 'core18', "
- "'core20', and 'core22' keys are supported."),
- key_type=TextLine(), required=False))
+ "builds."),
+ required=False, extra_snap_names=["charmcraft"]))
@export_factory_operation(ICharmRecipeBuildRequest, [])
@operation_for_version("devel")
def requestBuilds(requester, channels=None, architectures=None):
@@ -518,13 +518,12 @@ class ICharmRecipeEditableAttributes(Interface):
"Whether this charm recipe is built automatically when its branch "
"changes.")))
- auto_build_channels = exported(Dict(
+ auto_build_channels = exported(SnapBuildChannelsField(
title=_("Source snap channels for automatic builds"),
- key_type=TextLine(), required=False, readonly=False,
- description=_(
+ required=False, readonly=False, extra_snap_names=["charmcraft"],
+ description_prefix=_(
"A dictionary mapping snap names to channels to use when building "
- "this charm recipe. Currently only 'charmcraft', 'core', "
- "'core18', 'core20', and 'core22' keys are supported.")))
+ "this charm recipe.")))
is_stale = exported(Bool(
title=_("Charm recipe is stale and is due to be rebuilt."),
diff --git a/lib/lp/charms/interfaces/charmrecipebuild.py b/lib/lp/charms/interfaces/charmrecipebuild.py
index 4a33e19..0faac93 100644
--- a/lib/lp/charms/interfaces/charmrecipebuild.py
+++ b/lib/lp/charms/interfaces/charmrecipebuild.py
@@ -37,7 +37,6 @@ from zope.schema import (
Bool,
Choice,
Datetime,
- Dict,
Int,
TextLine,
)
@@ -51,6 +50,7 @@ from lp.charms.interfaces.charmrecipe import (
)
from lp.registry.interfaces.person import IPerson
from lp.services.database.constants import DEFAULT
+from lp.services.fields import SnapBuildChannelsField
from lp.services.librarian.interfaces import ILibraryFileAlias
from lp.soyuz.interfaces.distroarchseries import IDistroArchSeries
@@ -126,13 +126,12 @@ class ICharmRecipeBuildView(IPackageBuild):
arch_tag = exported(
TextLine(title=_("Architecture tag"), required=True, readonly=True))
- channels = exported(Dict(
+ channels = exported(SnapBuildChannelsField(
title=_("Source snap channels to use for this build."),
- description=_(
+ description_prefix=_(
"A dictionary mapping snap names to channels to use for this "
- "build. Currently only 'charmcraft', 'core', 'core18', 'core20', "
- "and 'core22' keys are supported."),
- key_type=TextLine()))
+ "build."),
+ extra_snap_names=["charmcraft"]))
virtualized = Bool(
title=_("If True, this build is virtualized."), readonly=True)
diff --git a/lib/lp/charms/interfaces/charmrecipejob.py b/lib/lp/charms/interfaces/charmrecipejob.py
index d353bb6..3f4a9b6 100644
--- a/lib/lp/charms/interfaces/charmrecipejob.py
+++ b/lib/lp/charms/interfaces/charmrecipejob.py
@@ -16,7 +16,6 @@ from zope.interface import (
)
from zope.schema import (
Datetime,
- Dict,
List,
Set,
TextLine,
@@ -29,6 +28,7 @@ from lp.charms.interfaces.charmrecipe import (
)
from lp.charms.interfaces.charmrecipebuild import ICharmRecipeBuild
from lp.registry.interfaces.person import IPerson
+from lp.services.fields import SnapBuildChannelsField
from lp.services.job.interfaces.job import (
IJob,
IJobSource,
@@ -57,13 +57,12 @@ class ICharmRecipeRequestBuildsJob(IRunnableJob):
title=_("The person requesting the builds."), schema=IPerson,
required=True, readonly=True)
- channels = Dict(
+ channels = SnapBuildChannelsField(
title=_("Source snap channels to use for these builds."),
- description=_(
+ description_prefix=_(
"A dictionary mapping snap names to channels to use for these "
- "builds. Currently only 'charmcraft', 'core', 'core18', "
- "'core20', and 'core22' keys are supported."),
- key_type=TextLine(), required=False, readonly=True)
+ "builds."),
+ required=False, readonly=True, extra_snap_names=["charmcraft"])
architectures = Set(
title=_("If set, limit builds to these architecture tags."),
diff --git a/lib/lp/services/fields/__init__.py b/lib/lp/services/fields/__init__.py
index 7d5ff4e..07fc278 100644
--- a/lib/lp/services/fields/__init__.py
+++ b/lib/lp/services/fields/__init__.py
@@ -40,6 +40,7 @@ __all__ = [
'ProductNameField',
'PublicPersonChoice',
'SearchTag',
+ 'SnapBuildChannelsField',
'StrippedTextLine',
'Summary',
'Tag',
@@ -75,6 +76,7 @@ from zope.schema import (
Choice,
Date,
Datetime,
+ Dict,
Int,
Object,
Text,
@@ -933,3 +935,25 @@ class IInlineObject(IObject):
@implementer(IInlineObject)
class InlineObject(Object):
"""An object that is represented as a dict rather than a URL reference."""
+
+
+class SnapBuildChannelsField(Dict):
+ """A field that holds source snap channels for builds."""
+
+ _core_snap_names = ["core", "core18", "core20", "core22"]
+
+ def __init__(self, description_prefix=None, description=None,
+ extra_snap_names=None, **kwargs):
+ snap_names = list(self._core_snap_names)
+ if extra_snap_names is not None:
+ snap_names.extend(extra_snap_names)
+ if description is None:
+ if description_prefix is None:
+ description = ""
+ else:
+ description = description_prefix + "\n"
+ description += "Supported snap names: {}".format(", ".join(
+ "'{}'".format(snap_name) for snap_name in sorted(snap_names)))
+ super().__init__(
+ key_type=Choice(values=snap_names), value_type=TextLine(),
+ description=description, **kwargs)
diff --git a/lib/lp/snappy/browser/snap.py b/lib/lp/snappy/browser/snap.py
index 6055137..fa8396d 100644
--- a/lib/lp/snappy/browser/snap.py
+++ b/lib/lp/snappy/browser/snap.py
@@ -31,7 +31,6 @@ from zope.interface import (
)
from zope.schema import (
Choice,
- Dict,
List,
TextLine,
)
@@ -418,9 +417,9 @@ class SnapRequestBuildsView(LaunchpadFormView):
'its configuration.'))
pocket = copy_field(
ISnapBuild['pocket'], title='Pocket', readonly=False)
- channels = Dict(
- title='Source snap channels', key_type=TextLine(), required=True,
- description=ISnap['auto_build_channels'].description)
+ channels = copy_field(
+ ISnap['auto_build_channels'], __name__='channels',
+ title='Source snap channels', required=True)
custom_widget_archive = SnapArchiveWidget
custom_widget_distro_arch_series = LabeledMultiCheckBoxWidget
diff --git a/lib/lp/snappy/interfaces/snap.py b/lib/lp/snappy/interfaces/snap.py
index 957a378..c569135 100644
--- a/lib/lp/snappy/interfaces/snap.py
+++ b/lib/lp/snappy/interfaces/snap.py
@@ -104,6 +104,7 @@ from lp.registry.interfaces.role import IHasOwner
from lp.services.fields import (
PersonChoice,
PublicPersonChoice,
+ SnapBuildChannelsField,
URIField,
)
from lp.services.webhooks.interfaces import IWebhookTarget
@@ -407,13 +408,12 @@ class ISnapView(Interface):
distro_arch_series=Reference(schema=IDistroArchSeries),
pocket=Choice(vocabulary=PackagePublishingPocket),
snap_base=Reference(schema=ISnapBase),
- channels=Dict(
+ channels=SnapBuildChannelsField(
title=_("Source snap channels to use for this build."),
- description=_(
+ description_prefix=_(
"A dictionary mapping snap names to channels to use for this "
- "build. Currently only 'core', 'core18', 'core20', 'core22', "
- "and 'snapcraft' keys are supported."),
- key_type=TextLine(), required=False))
+ "build."),
+ required=False, extra_snap_names=["snapcraft"]))
# Really ISnapBuild, patched in lp.snappy.interfaces.webservice.
@export_factory_operation(Interface, [])
@operation_for_version("devel")
@@ -437,13 +437,12 @@ class ISnapView(Interface):
@operation_parameters(
archive=Reference(schema=IArchive),
pocket=Choice(vocabulary=PackagePublishingPocket),
- channels=Dict(
+ channels=SnapBuildChannelsField(
title=_("Source snap channels to use for this build."),
- description=_(
+ description_prefix=_(
"A dictionary mapping snap names to channels to use for this "
- "build. Currently only 'core', 'core18', 'core20', 'core22', "
- "and 'snapcraft' keys are supported."),
- key_type=TextLine(), required=False))
+ "build."),
+ required=False, extra_snap_names=["snapcraft"]))
@export_factory_operation(ISnapBuildRequest, [])
@operation_for_version("devel")
def requestBuilds(requester, archive, pocket, channels=None):
@@ -833,13 +832,12 @@ class ISnapEditableAttributes(IHasOwner):
"used to select the pocket in the distribution's primary "
"archive.")))
- auto_build_channels = exported(Dict(
+ auto_build_channels = exported(SnapBuildChannelsField(
title=_("Source snap channels for automatic builds"),
- key_type=TextLine(), required=False, readonly=False,
- description=_(
+ required=False, readonly=False, extra_snap_names=["snapcraft"],
+ description_prefix=_(
"A dictionary mapping snap names to channels to use when building "
- "this snap package. Currently only 'core', 'core18', "
- "'core20', 'core22', and 'snapcraft' keys are supported.")))
+ "this snap package.")))
is_stale = exported(Bool(
title=_("Snap package is stale and is due to be rebuilt."),
diff --git a/lib/lp/snappy/interfaces/snapbuild.py b/lib/lp/snappy/interfaces/snapbuild.py
index 6d41fbe..af9415f 100644
--- a/lib/lp/snappy/interfaces/snapbuild.py
+++ b/lib/lp/snappy/interfaces/snapbuild.py
@@ -53,6 +53,7 @@ from lp.buildmaster.interfaces.packagebuild import IPackageBuild
from lp.registry.interfaces.person import IPerson
from lp.registry.interfaces.pocket import PackagePublishingPocket
from lp.services.database.constants import DEFAULT
+from lp.services.fields import SnapBuildChannelsField
from lp.services.librarian.interfaces import ILibraryFileAlias
from lp.snappy.interfaces.snap import (
ISnap,
@@ -174,13 +175,12 @@ class ISnapBuildView(IPackageBuild, IPrivacy):
title=_("The snap base to use for this build."),
required=False, readonly=True))
- channels = exported(Dict(
+ channels = exported(SnapBuildChannelsField(
title=_("Source snap channels to use for this build."),
- description=_(
+ description_prefix=_(
"A dictionary mapping snap names to channels to use for this "
- "build. Currently only 'core', 'core18', 'core20', 'core22', "
- "and 'snapcraft' keys are supported."),
- key_type=TextLine()))
+ "build."),
+ extra_snap_names=["snapcraft"]))
virtualized = Bool(
title=_("If True, this build is virtualized."), readonly=True)
diff --git a/lib/lp/snappy/interfaces/snapjob.py b/lib/lp/snappy/interfaces/snapjob.py
index 9a5b1f2..131e424 100644
--- a/lib/lp/snappy/interfaces/snapjob.py
+++ b/lib/lp/snappy/interfaces/snapjob.py
@@ -17,7 +17,6 @@ from zope.interface import (
from zope.schema import (
Choice,
Datetime,
- Dict,
List,
Set,
TextLine,
@@ -26,6 +25,7 @@ from zope.schema import (
from lp import _
from lp.registry.interfaces.person import IPerson
from lp.registry.interfaces.pocket import PackagePublishingPocket
+from lp.services.fields import SnapBuildChannelsField
from lp.services.job.interfaces.job import (
IJob,
IJobSource,
@@ -68,13 +68,12 @@ class ISnapRequestBuildsJob(IRunnableJob):
title=_("The pocket that should be targeted."),
vocabulary=PackagePublishingPocket, required=True, readonly=True)
- channels = Dict(
+ channels = SnapBuildChannelsField(
title=_("Source snap channels to use for these builds."),
- description=_(
+ description_prefix=_(
"A dictionary mapping snap names to channels to use for these "
- "builds. Currently only 'core', 'core18', 'core20', 'core22', "
- "and 'snapcraft' keys are supported."),
- key_type=TextLine(), required=False, readonly=True)
+ "builds."),
+ required=False, readonly=True, extra_snap_names=["snapcraft"])
architectures = Set(
title=_("If set, limit builds to these architecture tags."),