Colin Watson has proposed merging lp:~cjwatson/launchpad/snap-build-channels-feature-flag into lp:launchpad with lp:~cjwatson/launchpad/snap-build-channels-ui as a prerequisite.
Commit message: Add a feature flag to control the installation source for snapcraft. Requested reviews: Launchpad code reviewers (launchpad-reviewers) Related bugs: Bug #1737994 in Launchpad itself: "build.snapcraft.io uses snapcraft from the deb archive" https://bugs.launchpad.net/launchpad/+bug/1737994 For more details, see: https://code.launchpad.net/~cjwatson/launchpad/snap-build-channels-feature-flag/+merge/344868 -- Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/snap-build-channels-feature-flag into lp:launchpad.
=== modified file 'lib/lp/snappy/browser/snap.py' --- lib/lp/snappy/browser/snap.py 2018-04-30 22:27:39 +0000 +++ lib/lp/snappy/browser/snap.py 2018-04-30 22:27:40 +0000 @@ -334,13 +334,6 @@ 'auto_build_channels', 'store_upload', ]) - auto_build_channels = copy_field( - ISnap['auto_build_channels'], - description=( - u'The channels to use for build tools when building the snap ' - u'package. If unset, or if the channel for snapcraft is set to ' - u'"apt", the default behaviour is to install snapcraft from the ' - u'source archive using apt.')) store_distro_series = Choice( vocabulary='BuildableSnappyDistroSeries', required=True, title=u'Series') === modified file 'lib/lp/snappy/browser/widgets/snapbuildchannels.py' --- lib/lp/snappy/browser/widgets/snapbuildchannels.py 2018-04-30 22:27:39 +0000 +++ lib/lp/snappy/browser/widgets/snapbuildchannels.py 2018-04-30 22:27:40 +0000 @@ -23,10 +23,12 @@ from zope.security.proxy import isinstance as zope_isinstance from lp.app.errors import UnexpectedFormData +from lp.services.features import getFeatureFlag from lp.services.webapp.interfaces import ( IAlwaysSubmittedWidget, ISingleLineWidgetLayout, ) +from lp.snappy.interfaces.snap import SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG @implementer(ISingleLineWidgetLayout, IAlwaysSubmittedWidget, IInputWidget) @@ -37,6 +39,25 @@ snap_names = ["core", "snapcraft"] _widgets_set_up = False + def __init__(self, context, request): + super(SnapBuildChannelsWidget, self).__init__(context, request) + self.hint = ( + 'The channels to use for build tools when building the snap ' + 'package.\n') + default_snapcraft_channel = ( + getFeatureFlag(SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG) or "apt") + if default_snapcraft_channel == "apt": + self.hint += ( + 'If unset, or if the channel for snapcraft is set to "apt", ' + 'the default is to install snapcraft from the source archive ' + 'using apt.') + else: + self.hint += ( + 'If unset, the default is to install snapcraft from the "%s" ' + 'channel. Setting the channel for snapcraft to "apt" causes ' + 'snapcraft to be installed from the source archive using ' + 'apt.' % default_snapcraft_channel) + def setUpSubWidgets(self): if self._widgets_set_up: return === modified file 'lib/lp/snappy/browser/widgets/tests/test_snapbuildchannelswidget.py' --- lib/lp/snappy/browser/widgets/tests/test_snapbuildchannelswidget.py 2018-04-30 22:27:39 +0000 +++ lib/lp/snappy/browser/widgets/tests/test_snapbuildchannelswidget.py 2018-04-30 22:27:40 +0000 @@ -14,10 +14,12 @@ from zope.schema import Dict from lp.services.beautifulsoup import BeautifulSoup +from lp.services.features.testing import FeatureFixture from lp.services.webapp.servers import LaunchpadTestRequest from lp.snappy.browser.widgets.snapbuildchannels import ( SnapBuildChannelsWidget, ) +from lp.snappy.interfaces.snap import SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG from lp.testing import ( TestCaseWithFactory, verifyObject, @@ -35,9 +37,9 @@ __name__="auto_build_channels", title="Source snap channels for automatic builds") self.context = self.factory.makeSnap() - field = field.bind(self.context) - request = LaunchpadTestRequest() - self.widget = SnapBuildChannelsWidget(field, request) + self.field = field.bind(self.context) + self.request = LaunchpadTestRequest() + self.widget = SnapBuildChannelsWidget(self.field, self.request) def test_implements(self): self.assertTrue(verifyObject(IBrowserWidget, self.widget)) @@ -48,6 +50,40 @@ self.widget.template.filename.endswith("snapbuildchannels.pt"), "Template was not set up.") + def test_hint_no_feature_flag(self): + self.assertEqual( + 'The channels to use for build tools when building the snap ' + 'package.\n' + 'If unset, or if the channel for snapcraft is set to "apt", ' + 'the default is to install snapcraft from the source archive ' + 'using apt.', + self.widget.hint) + + def test_hint_feature_flag_apt(self): + self.useFixture( + FeatureFixture({SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG: "apt"})) + widget = SnapBuildChannelsWidget(self.field, self.request) + self.assertEqual( + 'The channels to use for build tools when building the snap ' + 'package.\n' + 'If unset, or if the channel for snapcraft is set to "apt", ' + 'the default is to install snapcraft from the source archive ' + 'using apt.', + widget.hint) + + def test_hint_feature_flag_real_channel(self): + self.useFixture( + FeatureFixture({SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG: "stable"})) + widget = SnapBuildChannelsWidget(self.field, self.request) + self.assertEqual( + 'The channels to use for build tools when building the snap ' + 'package.\n' + 'If unset, the default is to install snapcraft from the "stable" ' + 'channel. Setting the channel for snapcraft to "apt" causes ' + 'snapcraft to be installed from the source archive using ' + 'apt.', + widget.hint) + def test_setUpSubWidgets_first_call(self): # The subwidgets are set up and a flag is set. self.widget.setUpSubWidgets() === modified file 'lib/lp/snappy/interfaces/snap.py' --- lib/lp/snappy/interfaces/snap.py 2018-04-21 10:01:22 +0000 +++ lib/lp/snappy/interfaces/snap.py 2018-04-30 22:27:40 +0000 @@ -19,6 +19,7 @@ 'NoSourceForSnap', 'NoSuchSnap', 'SNAP_PRIVATE_FEATURE_FLAG', + 'SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG', 'SNAP_TESTING_FLAGS', 'SNAP_WEBHOOKS_FEATURE_FLAG', 'SnapAuthorizationBadMacaroon', @@ -102,6 +103,7 @@ SNAP_PRIVATE_FEATURE_FLAG = u"snap.allow_private" +SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG = u"snap.channels.snapcraft" SNAP_WEBHOOKS_FEATURE_FLAG = u"snap.webhooks.enabled" === modified file 'lib/lp/snappy/model/snapbuildbehaviour.py' --- lib/lp/snappy/model/snapbuildbehaviour.py 2018-04-30 22:27:39 +0000 +++ lib/lp/snappy/model/snapbuildbehaviour.py 2018-04-30 22:27:40 +0000 @@ -30,8 +30,12 @@ ) from lp.registry.interfaces.series import SeriesStatus from lp.services.config import config +from lp.services.features import getFeatureFlag from lp.services.webapp import canonical_url -from lp.snappy.interfaces.snap import SnapBuildArchiveOwnerMismatch +from lp.snappy.interfaces.snap import ( + SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG, + SnapBuildArchiveOwnerMismatch, + ) from lp.snappy.interfaces.snapbuild import ISnapBuild from lp.soyuz.adapters.archivedependencies import ( get_sources_list_for_building, @@ -110,12 +114,15 @@ logger=logger)) args["archive_private"] = build.archive.private args["build_url"] = canonical_url(build) - if (build.channels is not None and - build.channels.get("snapcraft") != "apt"): + channels = build.channels or {} + if "snapcraft" not in channels: + channels["snapcraft"] = ( + getFeatureFlag(SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG) or "apt") + if channels.get("snapcraft") != "apt": # We have to remove the security proxy that Zope applies to this # dict, since otherwise we'll be unable to serialise it to # XML-RPC. - args["channels"] = removeSecurityProxy(build.channels) + args["channels"] = removeSecurityProxy(channels) if build.snap.branch is not None: args["branch"] = build.snap.branch.bzr_identity elif build.snap.git_ref is not None: === modified file 'lib/lp/snappy/tests/test_snapbuildbehaviour.py' --- lib/lp/snappy/tests/test_snapbuildbehaviour.py 2018-04-30 22:27:39 +0000 +++ lib/lp/snappy/tests/test_snapbuildbehaviour.py 2018-04-30 22:27:40 +0000 @@ -55,9 +55,13 @@ from lp.registry.interfaces.pocket import PackagePublishingPocket from lp.registry.interfaces.series import SeriesStatus from lp.services.config import config +from lp.services.features.testing import FeatureFixture from lp.services.log.logger import BufferLogger from lp.services.webapp import canonical_url -from lp.snappy.interfaces.snap import SnapBuildArchiveOwnerMismatch +from lp.snappy.interfaces.snap import ( + SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG, + SnapBuildArchiveOwnerMismatch, + ) from lp.snappy.model.snapbuildbehaviour import SnapBuildBehaviour from lp.soyuz.adapters.archivedependencies import ( get_sources_list_for_building, @@ -438,6 +442,33 @@ self.assertNotIn("channels", args) @defer.inlineCallbacks + def test_extraBuildArgs_channels_feature_flag_real_channel(self): + # If the snap.channels.snapcraft feature flag is set, it identifies + # the default channel to be used for snapcraft. + self.useFixture( + FeatureFixture({SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG: "stable"})) + job = self.makeJob() + expected_archives, expected_trusted_keys = ( + yield get_sources_list_for_building( + job.build, job.build.distro_arch_series, None)) + args = yield job._extraBuildArgs() + self.assertFalse(isProxy(args["channels"])) + self.assertEqual({"snapcraft": "stable"}, args["channels"]) + + @defer.inlineCallbacks + def test_extraBuildArgs_channels_feature_flag_overridden(self): + # The snap.channels.snapcraft feature flag can be overridden by + # explicit configuration. + self.useFixture( + FeatureFixture({SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG: "stable"})) + job = self.makeJob(channels={"snapcraft": "apt"}) + expected_archives, expected_trusted_keys = ( + yield get_sources_list_for_building( + job.build, job.build.distro_arch_series, None)) + args = yield job._extraBuildArgs() + self.assertNotIn("channels", args) + + @defer.inlineCallbacks def test_extraBuildArgs_disallow_internet(self): # If external network access is not allowed for the snap, # _extraBuildArgs does not dispatch a proxy token.
_______________________________________________ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp