##// END OF EJS Templates
Variants validation + fail-fast
cin -
r28:1a0b4caf9976 default
parent child
Show More
@@ -120,7 +120,10 public abstract class BuildVariant imple
120
120
121 public LayerLink link(String from, String to, String kind) {
121 public LayerLink link(String from, String to, String kind) {
122 ensureMutable("add links");
122 ensureMutable("add links");
123 var link = new LayerLink(from, to, kind);
123 var link = new LayerLink(
124 requireLinkValue("from", from),
125 requireLinkValue("to", to),
126 requireLinkValue("kind", kind));
124 links.add(link);
127 links.add(link);
125 return link;
128 return link;
126 }
129 }
@@ -191,6 +194,13 public abstract class BuildVariant imple
191 throw new InvalidUserDataException("Variant '" + name + "' is finalized and cannot " + operation);
194 throw new InvalidUserDataException("Variant '" + name + "' is finalized and cannot " + operation);
192 }
195 }
193
196
197 private static String requireLinkValue(String field, String value) {
198 if (value == null || value.trim().isEmpty())
199 throw new InvalidUserDataException("Link '" + field + "' must not be null or blank");
200
201 return value.trim();
202 }
203
194 public final class RolesSpec {
204 public final class RolesSpec {
195 public BuildRole role(String name, Action<? super BuildRole> configure) {
205 public BuildRole role(String name, Action<? super BuildRole> configure) {
196 return BuildVariant.this.role(name, configure);
206 return BuildVariant.this.role(name, configure);
@@ -158,8 +158,18 public abstract class BuildVariantsExten
158 var errors = new ArrayList<String>();
158 var errors = new ArrayList<String>();
159
159
160 var layersByName = new LinkedHashMap<String, BuildLayer>();
160 var layersByName = new LinkedHashMap<String, BuildLayer>();
161 for (var layer : layers)
161 for (var layer : layers) {
162 layersByName.put(layer.getName(), layer);
162 var layerName = normalize(layer.getName());
163 if (layerName == null) {
164 errors.add("Layer name must not be blank");
165 continue;
166 }
167
168 var previous = layersByName.putIfAbsent(layerName, layer);
169 if (previous != null) {
170 errors.add("Layer '" + layerName + "' is declared more than once");
171 }
172 }
163
173
164 for (var variant : variants)
174 for (var variant : variants)
165 validateVariant(variant, layersByName, errors);
175 validateVariant(variant, layersByName, errors);
@@ -174,28 +184,69 public abstract class BuildVariantsExten
174 }
184 }
175
185
176 private static void validateVariant(BuildVariant variant, Map<String, BuildLayer> layersByName, List<String> errors) {
186 private static void validateVariant(BuildVariant variant, Map<String, BuildLayer> layersByName, List<String> errors) {
187 var variantName = normalize(variant.getName());
188 if (variantName == null) {
189 errors.add("Variant name must not be blank");
190 return;
191 }
192
193 validateRoleAndArtifactNames(variant, errors);
177 var variantLayers = validateRoleMappings(variant, layersByName, errors);
194 var variantLayers = validateRoleMappings(variant, layersByName, errors);
178 validateLinks(variant, variantLayers, errors);
195 validateLinks(variant, variantLayers, errors);
179 }
196 }
180
197
198 private static void validateRoleAndArtifactNames(BuildVariant variant, List<String> errors) {
199 var roleNames = new LinkedHashSet<String>();
200 for (var role : variant.getRoles()) {
201 var roleName = normalize(role.getName());
202 if (roleName == null) {
203 errors.add("Variant '" + variant.getName() + "' contains blank role name");
204 continue;
205 }
206 if (!roleNames.add(roleName)) {
207 errors.add("Variant '" + variant.getName() + "' contains duplicated role name '" + roleName + "'");
208 }
209 }
210
211 var slotNames = new LinkedHashSet<String>();
212 for (var slot : variant.getArtifactSlots()) {
213 var slotName = normalize(slot.getName());
214 if (slotName == null) {
215 errors.add("Variant '" + variant.getName() + "' contains blank artifact slot name");
216 continue;
217 }
218 if (!slotNames.add(slotName)) {
219 errors.add("Variant '" + variant.getName() + "' contains duplicated artifact slot name '" + slotName + "'");
220 }
221 }
222 }
223
181 private static Set<String> validateRoleMappings(BuildVariant variant, Map<String, BuildLayer> layersByName,
224 private static Set<String> validateRoleMappings(BuildVariant variant, Map<String, BuildLayer> layersByName,
182 List<String> errors) {
225 List<String> errors) {
183 var variantLayers = new LinkedHashSet<String>();
226 var variantLayers = new LinkedHashSet<String>();
184
227
185 for (var role : variant.getRoles()) {
228 for (var role : variant.getRoles()) {
229 var seenLayers = new LinkedHashSet<String>();
186 for (var layerName : role.getLayers().getOrElse(List.of())) {
230 for (var layerName : role.getLayers().getOrElse(List.of())) {
187 if (isBlank(layerName)) {
231 var normalizedLayerName = normalize(layerName);
232 if (normalizedLayerName == null) {
188 errors.add("Variant '" + variant.getName() + "', role '" + role.getName() + "' contains blank layer name");
233 errors.add("Variant '" + variant.getName() + "', role '" + role.getName() + "' contains blank layer name");
189 continue;
234 continue;
190 }
235 }
191
236
192 var layer = layersByName.get(layerName);
237 var layer = layersByName.get(normalizedLayerName);
193 if (layer == null) {
238 if (layer == null) {
194 errors.add("Variant '" + variant.getName() + "' references unknown layer '" + layerName + "'");
239 errors.add("Variant '" + variant.getName() + "' references unknown layer '" + normalizedLayerName + "'");
195 continue;
240 continue;
196 }
241 }
197
242
198 variantLayers.add(layerName);
243 if (!seenLayers.add(normalizedLayerName)) {
244 errors.add("Variant '" + variant.getName() + "', role '" + role.getName()
245 + "' contains duplicated layer reference '" + normalizedLayerName + "'");
246 continue;
247 }
248
249 variantLayers.add(normalizedLayerName);
199 }
250 }
200 }
251 }
201
252
@@ -40,6 +40,7 public abstract class VariantSourcesExte
40 private final List<SourceSetContext> boundContexts = new ArrayList<>();
40 private final List<SourceSetContext> boundContexts = new ArrayList<>();
41 private final LinkedHashMap<String, NamedDomainObjectProvider<GenericSourceSet>> sourceSetsByName = new LinkedHashMap<>();
41 private final LinkedHashMap<String, NamedDomainObjectProvider<GenericSourceSet>> sourceSetsByName = new LinkedHashMap<>();
42 private final LinkedHashMap<String, String> sourceSetLayersByName = new LinkedHashMap<>();
42 private final LinkedHashMap<String, String> sourceSetLayersByName = new LinkedHashMap<>();
43 private boolean sourceSetsRegistered;
43
44
44 @Inject
45 @Inject
45 public VariantSourcesExtension(ObjectFactory objects) {
46 public VariantSourcesExtension(ObjectFactory objects) {
@@ -137,6 +138,10 public abstract class VariantSourcesExte
137 }
138 }
138
139
139 void registerSourceSets(BuildVariantsExtension variants, NamedDomainObjectContainer<GenericSourceSet> sources) {
140 void registerSourceSets(BuildVariantsExtension variants, NamedDomainObjectContainer<GenericSourceSet> sources) {
141 if (sourceSetsRegistered) {
142 throw new InvalidUserDataException("variantSources source sets are already registered");
143 }
144
140 validateBindings(variants);
145 validateBindings(variants);
141
146
142 var usages = layerUsages(variants).toList();
147 var usages = layerUsages(variants).toList();
@@ -157,6 +162,8 public abstract class VariantSourcesExte
157 registeredContexts.size() - registeredBefore,
162 registeredContexts.size() - registeredBefore,
158 boundContexts.size() - boundBefore,
163 boundContexts.size() - boundBefore,
159 sourceSetsByName.size());
164 sourceSetsByName.size());
165
166 sourceSetsRegistered = true;
160 }
167 }
161
168
162 private Stream<LayerUsage> layerUsages(BuildVariantsExtension variants) {
169 private Stream<LayerUsage> layerUsages(BuildVariantsExtension variants) {
@@ -156,7 +156,7 class VariantsPluginFunctionalTest {
156 link('a', 'b', null)
156 link('a', 'b', null)
157 }
157 }
158 }
158 }
159 """, "has incomplete link (from/to/kind are required)");
159 """, "Link 'kind' must not be null or blank");
160 }
160 }
161
161
162 @Test
162 @Test
@@ -224,6 +224,25 class VariantsPluginFunctionalTest {
224 }
224 }
225
225
226 @Test
226 @Test
227 void failsOnDuplicatedLayerReferenceInRole() throws Exception {
228 assertBuildFails("""
229 plugins {
230 id 'org.implab.gradle-variants'
231 }
232
233 variants {
234 layer('a')
235
236 variant('browser') {
237 role('main') {
238 layers('a', 'a')
239 }
240 }
241 }
242 """, "contains duplicated layer reference 'a'");
243 }
244
245 @Test
227 void failsOnLateLayerMutationAfterFinalize() throws Exception {
246 void failsOnLateLayerMutationAfterFinalize() throws Exception {
228 assertBuildFails("""
247 assertBuildFails("""
229 plugins {
248 plugins {
General Comments 0
You need to be logged in to leave comments. Login now