Merge ~andrey-fedoseev/launchpad:snap-arch-multi-build-on into launchpad:master

Proposed by Andrey Fedoseev
Status: Merged
Approved by: Andrey Fedoseev
Approved revision: 555fc7b3a47e84a985051d1c0b1b9b5a9ba4cfad
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~andrey-fedoseev/launchpad:snap-arch-multi-build-on
Merge into: launchpad:master
Diff against target: 163 lines (+75/-18)
3 files modified
lib/lp/snappy/adapters/buildarch.py (+17/-10)
lib/lp/snappy/adapters/tests/test_buildarch.py (+51/-6)
lib/lp/snappy/model/snap.py (+7/-2)
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+428596@code.launchpad.net

Commit message

Allow duplicate `build-on` for `core22`

Description of the change

This allows the following configuration in `snapcraft.yaml` which is legit only for `core22`

architectures:
  - build-on: amd64
  - build-on: amd64
    build-for: [arm64]

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/snappy/adapters/buildarch.py b/lib/lp/snappy/adapters/buildarch.py
2index e4e92f7..102eb74 100644
3--- a/lib/lp/snappy/adapters/buildarch.py
4+++ b/lib/lp/snappy/adapters/buildarch.py
5@@ -146,11 +146,13 @@ class SnapBuildInstance:
6
7
8 def determine_architectures_to_build(
9+ snap_base: Optional[str],
10 snapcraft_data: Dict[str, Any],
11 supported_arches: List[str],
12 ) -> List[SnapBuildInstance]:
13 """Return a list of architectures to build based on snapcraft.yaml.
14
15+ :param snap_base: Name of the snap base.
16 :param snapcraft_data: A parsed snapcraft.yaml.
17 :param supported_arches: An ordered list of all architecture tags that
18 we can create builds for.
19@@ -182,16 +184,21 @@ def determine_architectures_to_build(
20 SnapArchitecture(build_on=a) for a in supported_arches
21 ]
22
23- # Ensure that multiple `build-on` items don't include the same
24- # architecture; this is ambiguous and forbidden by snapcraft. Checking
25- # this here means that we don't get duplicate supported_arch results
26- # below.
27- build_ons = Counter()
28- for arch in architectures:
29- build_ons.update(arch.build_on)
30- duplicates = {arch for arch, count in build_ons.items() if count > 1}
31- if duplicates:
32- raise DuplicateBuildOnError(duplicates)
33+ if snap_base not in {"core22"}:
34+ # Ensure that multiple `build-on` items don't include the same
35+ # architecture; this is ambiguous and forbidden by snapcraft prior
36+ # to core22. Checking this here means that we don't get duplicate
37+ # supported_arch results below.
38+
39+ # XXX andrey-fedoseev 2022-08-22: we should use the `SnapBase` model
40+ # to store the specific features of each base rather than hard-coding
41+ # the base names here
42+ build_ons = Counter()
43+ for arch in architectures:
44+ build_ons.update(arch.build_on)
45+ duplicates = {arch for arch, count in build_ons.items() if count > 1}
46+ if duplicates:
47+ raise DuplicateBuildOnError(duplicates)
48
49 architectures_to_build = []
50 for arch in architectures:
51diff --git a/lib/lp/snappy/adapters/tests/test_buildarch.py b/lib/lp/snappy/adapters/tests/test_buildarch.py
52index 81f3c87..db52baf 100644
53--- a/lib/lp/snappy/adapters/tests/test_buildarch.py
54+++ b/lib/lp/snappy/adapters/tests/test_buildarch.py
55@@ -5,6 +5,7 @@ from testscenarios import WithScenarios, load_tests_apply_scenarios
56 from testtools.matchers import HasLength
57
58 from lp.snappy.adapters.buildarch import (
59+ DuplicateBuildOnError,
60 SnapArchitecture,
61 SnapBuildInstance,
62 UnsupportedBuildOnError,
63@@ -392,16 +393,60 @@ class TestDetermineArchitecturesToBuild(WithScenarios, TestCase):
64 ],
65 },
66 ),
67+ (
68+ "multiple build-for for the same build-on",
69+ {
70+ "architectures": [
71+ {"build-on": "amd64", "build-for": ["amd64"]},
72+ {"build-on": "amd64", "build-for": ["i386"]},
73+ ],
74+ "supported_architectures": ["amd64", "i386", "armhf"],
75+ "expected": [
76+ {
77+ "architecture": "amd64",
78+ "target_architectures": ["amd64"],
79+ "required": True,
80+ },
81+ {
82+ "architecture": "amd64",
83+ "target_architectures": ["i386"],
84+ "required": True,
85+ },
86+ ],
87+ },
88+ ),
89+ (
90+ "multiple build-for for the same build-on: old base",
91+ {
92+ "snap_base": "core20",
93+ "architectures": [
94+ {"build-on": "amd64", "build-for": ["amd64"]},
95+ {"build-on": "amd64", "build-for": ["i386"]},
96+ ],
97+ "supported_architectures": ["amd64", "i386", "armhf"],
98+ "expected_exception": DuplicateBuildOnError,
99+ },
100+ ),
101 ]
102
103 def test_parser(self):
104 snapcraft_data = {"architectures": self.architectures}
105- build_instances = determine_architectures_to_build(
106- snapcraft_data, self.supported_architectures
107- )
108- self.assertThat(build_instances, HasLength(len(self.expected)))
109- for instance in build_instances:
110- self.assertIn(instance.__dict__, self.expected)
111+ snap_base = getattr(self, "snap_base", "core22")
112+ if hasattr(self, "expected_exception"):
113+ self.assertRaises(
114+ self.expected_exception,
115+ determine_architectures_to_build,
116+ snap_base,
117+ snapcraft_data,
118+ self.supported_architectures,
119+ )
120+ else:
121+ build_instances = determine_architectures_to_build(
122+ snap_base, snapcraft_data, self.supported_architectures
123+ )
124+ self.assertThat(build_instances, HasLength(len(self.expected)))
125+ for instance in build_instances:
126+ self.assertIn(instance.__dict__, self.expected)
127
128
129 load_tests = load_tests_apply_scenarios
130diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py
131index 28e1d28..e5fef93 100644
132--- a/lib/lp/snappy/model/snap.py
133+++ b/lib/lp/snappy/model/snap.py
134@@ -175,6 +175,7 @@ from lp.snappy.interfaces.snapbuild import ISnapBuild, ISnapBuildSet
135 from lp.snappy.interfaces.snapjob import ISnapRequestBuildsJobSource
136 from lp.snappy.interfaces.snappyseries import ISnappyDistroSeriesSet
137 from lp.snappy.interfaces.snapstoreclient import ISnapStoreClient
138+from lp.snappy.model.snapbase import SnapBase
139 from lp.snappy.model.snapbuild import SnapBuild
140 from lp.snappy.model.snapjob import SnapJob
141 from lp.snappy.model.snapsubscription import SnapSubscription
142@@ -898,7 +899,9 @@ class Snap(Storm, WebhookTargetMixin):
143 return self.getBuildRequest(job.job_id)
144
145 @staticmethod
146- def _findBase(snapcraft_data):
147+ def _findBase(
148+ snapcraft_data: t.Dict[str, t.Any]
149+ ) -> t.Tuple[SnapBase, t.Optional[str]]:
150 """Find a suitable base for a build."""
151 base = snapcraft_data.get("base")
152 build_base = snapcraft_data.get("build-base")
153@@ -1006,7 +1009,9 @@ class Snap(Storm, WebhookTargetMixin):
154 )
155 )
156 architectures_to_build = determine_architectures_to_build(
157- snapcraft_data, list(supported_arches.keys())
158+ snap_base.name if snap_base is not None else None,
159+ snapcraft_data,
160+ list(supported_arches.keys()),
161 )
162 except Exception as e:
163 if not allow_failures:

Subscribers

People subscribed via source and target branches

to status/vote changes: