From 330cb13c64aabc2e85ca2d6cef51df8b82ee8176 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 17 Jan 2017 18:25:30 +0100 Subject: [PATCH] Add support for BOM ordering This commit adds an `order` attribute on `BillOfMaterials` that allows to order BOMs in the generated project. Lowest value have higher priority. When the project is generatede with a custom parent, the Spring Boot dependencies BOM itself has an order of a 100. Any BOM that is added with an order lower than 100 has higher priority, i.e. could potentially override dependencies provided by the Spring Boot dependency mechanism. This mechanism does not work reliably when using the `spring-boot-starter-parent` so it should be used with care. However, it can be useful when overriding dependencies that Spring Boot does not manage itself. Closes gh-343 --- .../generator/ProjectGenerator.groovy | 2 + .../metadata/BillOfMaterials.groovy | 11 ++- .../metadata/InitializrMetadata.groovy | 2 +- .../resources/templates/starter-build.gradle | 2 +- .../main/resources/templates/starter-pom.xml | 2 +- .../ProjectGeneratorBuildTests.groovy | 27 ++++++- .../gradle/bom-ordering-build.gradle.gen | 42 ++++++++++ .../project/maven/bom-ordering-pom.xml.gen | 76 +++++++++++++++++++ .../metadata/config/test-default.json | 4 +- 9 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 initializr-generator/src/test/resources/project/gradle/bom-ordering-build.gradle.gen create mode 100644 initializr-generator/src/test/resources/project/maven/bom-ordering-pom.xml.gen diff --git a/initializr-generator/src/main/groovy/io/spring/initializr/generator/ProjectGenerator.groovy b/initializr-generator/src/main/groovy/io/spring/initializr/generator/ProjectGenerator.groovy index 7b7c0b78..a9a2dee8 100644 --- a/initializr-generator/src/main/groovy/io/spring/initializr/generator/ProjectGenerator.groovy +++ b/initializr-generator/src/main/groovy/io/spring/initializr/generator/ProjectGenerator.groovy @@ -258,6 +258,8 @@ class ProjectGenerator { model['includeSpringBootBom'] = parentPom.includeSpringBootBom } + model['resolvedBoms'] = request.boms.values().sort {a, b -> a.order <=> b.order } + model['compileDependencies'] = filterDependencies(dependencies, Dependency.SCOPE_COMPILE) model['runtimeDependencies'] = filterDependencies(dependencies, Dependency.SCOPE_RUNTIME) model['compileOnlyDependencies'] = filterDependencies(dependencies, Dependency.SCOPE_COMPILE_ONLY) diff --git a/initializr-generator/src/main/groovy/io/spring/initializr/metadata/BillOfMaterials.groovy b/initializr-generator/src/main/groovy/io/spring/initializr/metadata/BillOfMaterials.groovy index da7f50ed..916c11c2 100644 --- a/initializr-generator/src/main/groovy/io/spring/initializr/metadata/BillOfMaterials.groovy +++ b/initializr-generator/src/main/groovy/io/spring/initializr/metadata/BillOfMaterials.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,13 @@ class BillOfMaterials { */ String versionProperty + /** + * The relative order of this BOM where lower values have higher priority. The + * default value is {@code Integer.MAX_VALUE}, indicating lowest priority. The + * Spring Boot dependencies bom has an order of 100. + */ + Integer order = Integer.MAX_VALUE + /** * The BOM(s) that should be automatically included if this BOM is required. Can be * {@code null} if it is provided via a mapping. @@ -102,7 +109,7 @@ class BillOfMaterials { for (Mapping mapping : mappings) { if (mapping.range.match(bootVersion)) { def resolvedBom = new BillOfMaterials(groupId: groupId, artifactId: artifactId, - version: mapping.version, versionProperty: versionProperty) + version: mapping.version, versionProperty: versionProperty, order: order) resolvedBom.repositories += mapping.repositories ?: repositories resolvedBom.additionalBoms += mapping.additionalBoms ?: additionalBoms return resolvedBom diff --git a/initializr-generator/src/main/groovy/io/spring/initializr/metadata/InitializrMetadata.groovy b/initializr-generator/src/main/groovy/io/spring/initializr/metadata/InitializrMetadata.groovy index 37eb1bac..292d6999 100644 --- a/initializr-generator/src/main/groovy/io/spring/initializr/metadata/InitializrMetadata.groovy +++ b/initializr-generator/src/main/groovy/io/spring/initializr/metadata/InitializrMetadata.groovy @@ -168,7 +168,7 @@ class InitializrMetadata { */ BillOfMaterials createSpringBootBom(String bootVersion, String versionProperty) { new BillOfMaterials(groupId: 'org.springframework.boot', artifactId: 'spring-boot-dependencies', - version: bootVersion, versionProperty: versionProperty) + version: bootVersion, versionProperty: versionProperty, order: 100) } /** diff --git a/initializr-generator/src/main/resources/templates/starter-build.gradle b/initializr-generator/src/main/resources/templates/starter-build.gradle index 146a1699..cf3271b7 100644 --- a/initializr-generator/src/main/resources/templates/starter-build.gradle +++ b/initializr-generator/src/main/resources/templates/starter-build.gradle @@ -53,7 +53,7 @@ dependencies {<% compileDependencies.each { %> } <% if (boms) { %> dependencyManagement { - imports {<% boms.values().each { %> + imports {<% resolvedBoms.reverse().each { %> mavenBom "${it.groupId}:${it.artifactId}:${it.determineVersionToken()}"<% } %> } } diff --git a/initializr-generator/src/main/resources/templates/starter-pom.xml b/initializr-generator/src/main/resources/templates/starter-pom.xml index 6f14a1e4..d51cc265 100644 --- a/initializr-generator/src/main/resources/templates/starter-pom.xml +++ b/initializr-generator/src/main/resources/templates/starter-pom.xml @@ -76,7 +76,7 @@ <% if (boms) { %> - <% boms.values().each { %> + <% resolvedBoms.each { %> ${it.groupId} ${it.artifactId} diff --git a/initializr-generator/src/test/groovy/io/spring/initializr/generator/ProjectGeneratorBuildTests.groovy b/initializr-generator/src/test/groovy/io/spring/initializr/generator/ProjectGeneratorBuildTests.groovy index d2637442..992e563d 100644 --- a/initializr-generator/src/test/groovy/io/spring/initializr/generator/ProjectGeneratorBuildTests.groovy +++ b/initializr-generator/src/test/groovy/io/spring/initializr/generator/ProjectGeneratorBuildTests.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -138,6 +138,31 @@ class ProjectGeneratorBuildTests extends AbstractProjectGeneratorTests { .equalsTo(new ClassPathResource("project/$build/compile-only-dependency-$assertFileName")) } + @Test + void bomWithOrdering() { + def foo = new Dependency(id: 'foo', groupId: 'org.acme', artifactId: 'foo', bom: 'foo-bom') + def barBom = new BillOfMaterials(groupId: 'org.acme', artifactId: 'bar-bom', + version: '1.0', order: 50) + def bizBom = new BillOfMaterials(groupId: 'org.acme', artifactId: 'biz-bom', + order: 40, additionalBoms: ['bar-bom']) + bizBom.mappings << new BillOfMaterials.Mapping(versionRange: '1.0.0.RELEASE', + version: '1.0') + def fooBom = new BillOfMaterials(groupId: 'org.acme', artifactId: 'foo-bom', + version: '1.0', order: 20, additionalBoms: ['biz-bom']) + + def metadata = InitializrMetadataTestBuilder.withDefaults() + .addDependencyGroup('foo', foo) + .addBom('foo-bom', fooBom) + .addBom('bar-bom', barBom) + .addBom('biz-bom', bizBom) + .build() + applyMetadata(metadata) + def request = createProjectRequest('foo') + def project = generateProject(request) + project.sourceCodeAssert("$fileName") + .equalsTo(new ClassPathResource("project/$build/bom-ordering-$assertFileName")) + } + @Override ProjectRequest createProjectRequest(String... styles) { def request = super.createProjectRequest(styles) diff --git a/initializr-generator/src/test/resources/project/gradle/bom-ordering-build.gradle.gen b/initializr-generator/src/test/resources/project/gradle/bom-ordering-build.gradle.gen new file mode 100644 index 00000000..73f520e9 --- /dev/null +++ b/initializr-generator/src/test/resources/project/gradle/bom-ordering-build.gradle.gen @@ -0,0 +1,42 @@ +buildscript { + ext { + springBootVersion = '1.2.3.RELEASE' + } + repositories { + mavenCentral() + } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") + classpath('io.spring.gradle:dependency-management-plugin:0.5.1.RELEASE') + } +} + +apply plugin: 'java' +apply plugin: 'eclipse' +apply plugin: 'spring-boot' +apply plugin: 'io.spring.dependency-management' + +jar { + baseName = 'demo' + version = '0.0.1-SNAPSHOT' +} + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + + +dependencies { + compile('org.acme:foo') + testCompile('org.springframework.boot:spring-boot-starter-test') +} + +dependencyManagement { + imports { + mavenBom "org.acme:bar-bom:1.0" + mavenBom "org.acme:biz-bom:1.0" + mavenBom "org.acme:foo-bom:1.0" + } +} diff --git a/initializr-generator/src/test/resources/project/maven/bom-ordering-pom.xml.gen b/initializr-generator/src/test/resources/project/maven/bom-ordering-pom.xml.gen new file mode 100644 index 00000000..b61236c4 --- /dev/null +++ b/initializr-generator/src/test/resources/project/maven/bom-ordering-pom.xml.gen @@ -0,0 +1,76 @@ + + + 4.0.0 + + com.example + demo + 0.0.1-SNAPSHOT + jar + + demo + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 1.2.3.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.acme + foo + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.acme + foo-bom + 1.0 + pom + import + + + org.acme + biz-bom + 1.0 + pom + import + + + org.acme + bar-bom + 1.0 + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/initializr-web/src/test/resources/metadata/config/test-default.json b/initializr-web/src/test/resources/metadata/config/test-default.json index e59ada71..ac5f869e 100644 --- a/initializr-web/src/test/resources/metadata/config/test-default.json +++ b/initializr-web/src/test/resources/metadata/config/test-default.json @@ -86,6 +86,7 @@ "my-api-bom": { "groupId": "org.acme", "artifactId": "my-api-bom", + "order": 2147483647, "repositories": [], "additionalBoms": [ "my-api-dependencies-bom" @@ -117,7 +118,8 @@ "mappings": [], "artifactId": "my-api-dependencies-bom", "additionalBoms": [], - "version": "1.0.0.RELEASE" + "version": "1.0.0.RELEASE", + "order": 2147483647 } }, "springBootMetadataUrl": "https://spring.io/project_metadata/spring-boot"