launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #23649
[Merge] lp:~cjwatson/launchpad/snap-request-build-select-channels into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/snap-request-build-select-channels into lp:launchpad.
Commit message:
Allow selecting source snap channels when requesting manual snap builds.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1791265 in Launchpad itself: "Manual snap builds don't allow for snapcraft/snapd channel selection"
https://bugs.launchpad.net/launchpad/+bug/1791265
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/snap-request-build-select-channels/+merge/367518
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/snap-request-build-select-channels into lp:launchpad.
=== modified file 'lib/lp/snappy/browser/snap.py'
--- lib/lp/snappy/browser/snap.py 2019-04-01 09:03:46 +0000
+++ lib/lp/snappy/browser/snap.py 2019-05-16 11:33:34 +0000
@@ -29,6 +29,7 @@
from zope.interface import Interface
from zope.schema import (
Choice,
+ Dict,
List,
TextLine,
)
@@ -294,10 +295,14 @@
description=(
u'The package stream within the source distribution series '
u'to use when building the snap package.'))
+ channels = Dict(
+ title=u'Source snap channels', key_type=TextLine(), required=True,
+ description=ISnap['auto_build_channels'].description)
custom_widget_archive = SnapArchiveWidget
custom_widget_distro_arch_series = LabeledMultiCheckBoxWidget
custom_widget_pocket = LaunchpadDropdownWidget
+ custom_widget_channels = SnapBuildChannelsWidget
help_links = {
"pocket": u"/+help-snappy/snap-build-pocket.html",
@@ -320,6 +325,7 @@
else self.context.distro_series.main_archive),
'distro_arch_series': [],
'pocket': PackagePublishingPocket.UPDATES,
+ 'channels': self.context.auto_build_channels,
}
def requestBuild(self, data):
@@ -336,7 +342,8 @@
for arch in data['distro_arch_series']:
try:
build = self.context.requestBuild(
- self.user, data['archive'], arch, data['pocket'])
+ self.user, data['archive'], arch, data['pocket'],
+ channels=data['channels'])
builds.append(build)
except SnapBuildAlreadyPending:
already_pending.append(arch)
@@ -356,7 +363,8 @@
self.request.response.addNotification(notification_text)
else:
self.context.requestBuilds(
- self.user, data['archive'], data['pocket'])
+ self.user, data['archive'], data['pocket'],
+ channels=data['channels'])
self.request.response.addNotification(
_('Builds will be dispatched soon.'))
self.next_url = self.cancel_url
=== modified file 'lib/lp/snappy/browser/tests/test_snap.py'
--- lib/lp/snappy/browser/tests/test_snap.py 2019-04-01 09:03:46 +0000
+++ lib/lp/snappy/browser/tests/test_snap.py 2019-05-16 11:33:34 +0000
@@ -1668,6 +1668,14 @@
\(\?\)
The package stream within the source distribution series to use
when building the snap package.
+ Source snap channels:
+ core
+ snapcraft
+ The channels to use for build tools when building the snap
+ package.
+ If unset, or if the channel for snapcraft is set to "apt", the
+ default is to install snapcraft from the source archive using
+ apt.
or
Cancel
""",
@@ -1717,6 +1725,21 @@
builds = self.snap.pending_builds
self.assertEqual([ppa], [build.archive for build in builds])
+ def test_request_builds_with_architectures_channels(self):
+ # Selecting different channels with architectures selected creates
+ # builds using those channels.
+ browser = self.getViewBrowser(
+ self.snap, "+request-builds", user=self.person)
+ browser.getControl(name="field.channels.core").value = "edge"
+ browser.getControl("amd64").selected = True
+ self.assertFalse(browser.getControl("i386").selected)
+ browser.getControl("Request builds").click()
+
+ login_person(self.person)
+ builds = self.snap.pending_builds
+ self.assertEqual(
+ [{"core": "edge"}], [build.channels for build in builds])
+
def test_request_builds_with_architectures_rejects_duplicate(self):
# A duplicate build request with architectures selected causes a
# notification.
@@ -1753,7 +1776,7 @@
_job=MatchesStructure(
requester=Equals(self.person),
pocket=Equals(PackagePublishingPocket.UPDATES),
- channels=Is(None))))
+ channels=Equals({}))))
def test_request_builds_no_architectures_ppa(self):
# Selecting a different archive with no architectures selected
@@ -1772,6 +1795,20 @@
[request] = self.snap.pending_build_requests
self.assertEqual(ppa, request.archive)
+ def test_request_builds_no_architectures_channels(self):
+ # Selecting different channels with no architectures selected
+ # creates a build request using those channels.
+ browser = self.getViewBrowser(
+ self.snap, "+request-builds", user=self.person)
+ browser.getControl(name="field.channels.core").value = "edge"
+ self.assertFalse(browser.getControl("amd64").selected)
+ self.assertFalse(browser.getControl("i386").selected)
+ browser.getControl("Request builds").click()
+
+ login_person(self.person)
+ [request] = self.snap.pending_build_requests
+ self.assertEqual({"core": "edge"}, request.channels)
+
def test_request_builds_no_distro_series(self):
# Requesting builds of a snap configured to infer an appropriate
# distro series from snapcraft.yaml creates a pending build request.
@@ -1792,4 +1829,4 @@
_job=MatchesStructure(
requester=Equals(self.person),
pocket=Equals(PackagePublishingPocket.UPDATES),
- channels=Is(None))))
+ channels=Equals({}))))
=== modified file 'lib/lp/snappy/interfaces/snap.py'
--- lib/lp/snappy/interfaces/snap.py 2019-04-16 13:05:56 +0000
+++ lib/lp/snappy/interfaces/snap.py 2019-05-16 11:33:34 +0000
@@ -332,6 +332,10 @@
title=u"The source archive for builds produced by this request",
required=True, readonly=True)
+ channels = Dict(
+ title=_("Source snap channels for builds produced by this request"),
+ key_type=TextLine(), required=False, readonly=True)
+
class ISnapView(Interface):
"""`ISnap` attributes that require launchpad.View permission."""
=== modified file 'lib/lp/snappy/model/snap.py'
--- lib/lp/snappy/model/snap.py 2019-04-16 13:05:56 +0000
+++ lib/lp/snappy/model/snap.py 2019-05-16 11:33:34 +0000
@@ -244,6 +244,11 @@
"""See `ISnapBuildRequest`."""
return self._job.archive
+ @property
+ def channels(self):
+ """See `ISnapBuildRequest`."""
+ return self._job.channels
+
@implementer(ISnap, IHasOwner)
class Snap(Storm, WebhookTargetMixin):
@@ -627,13 +632,18 @@
if not self._isArchitectureAllowed(distro_arch_series, pocket):
raise SnapBuildDisallowedArchitecture(distro_arch_series, pocket)
+ if not channels:
+ channels_clause = Or(
+ SnapBuild.channels == None, SnapBuild.channels == {})
+ else:
+ channels_clause = SnapBuild.channels == channels
pending = IStore(self).find(
SnapBuild,
SnapBuild.snap_id == self.id,
SnapBuild.archive_id == archive.id,
SnapBuild.distro_arch_series_id == distro_arch_series.id,
SnapBuild.pocket == pocket,
- SnapBuild.channels == channels,
+ channels_clause,
SnapBuild.status == BuildStatus.NEEDSBUILD)
if pending.any() is not None:
raise SnapBuildAlreadyPending
=== modified file 'lib/lp/snappy/templates/snap-request-builds.pt'
--- lib/lp/snappy/templates/snap-request-builds.pt 2019-02-07 10:34:20 +0000
+++ lib/lp/snappy/templates/snap-request-builds.pt 2019-05-16 11:33:34 +0000
@@ -28,6 +28,9 @@
<tal:widget define="widget nocall:view/widgets/pocket">
<metal:block use-macro="context/@@launchpad_form/widget_row" />
</tal:widget>
+ <tal:widget define="widget nocall:view/widgets/channels">
+ <metal:block use-macro="context/@@launchpad_form/widget_row" />
+ </tal:widget>
</table>
</metal:formbody>
</div>
=== modified file 'lib/lp/snappy/tests/test_snap.py'
--- lib/lp/snappy/tests/test_snap.py 2019-04-16 13:05:56 +0000
+++ lib/lp/snappy/tests/test_snap.py 2019-05-16 11:33:34 +0000
@@ -308,6 +308,19 @@
snap.requestBuild(
snap.owner, snap.distro_series.main_archive, arches[1],
PackagePublishingPocket.UPDATES)
+ # channels=None and channels={} are treated as equivalent, but
+ # anything else allows a new build.
+ self.assertRaises(
+ SnapBuildAlreadyPending, snap.requestBuild,
+ snap.owner, snap.distro_series.main_archive, arches[0],
+ PackagePublishingPocket.UPDATES, channels={})
+ snap.requestBuild(
+ snap.owner, snap.distro_series.main_archive, arches[0],
+ PackagePublishingPocket.UPDATES, channels={"core": "edge"})
+ self.assertRaises(
+ SnapBuildAlreadyPending, snap.requestBuild,
+ snap.owner, snap.distro_series.main_archive, arches[0],
+ PackagePublishingPocket.UPDATES, channels={"core": "edge"})
# Changing the status of the old build allows a new build.
old_build.updateStatus(BuildStatus.BUILDING)
old_build.updateStatus(BuildStatus.FULLYBUILT)
Follow ups