Add BOM versions mapping

Spring Cloud supports Spring Boot 1.2 and 1.3 in two different release
lines so there is a need to change the Spring Cloud version according
to the chosen Spring Boot version.

Each bom can have arbitrary number of version mappings that permit
to customize the version and even the repositories used to build the
project

Closes gh-121
This commit is contained in:
Stephane Nicoll 2015-07-09 17:12:51 +02:00
parent 714593e5a4
commit 6df0fd3000
7 changed files with 168 additions and 5 deletions

View File

@ -116,7 +116,7 @@ class ProjectRequest {
String bomId = it.bom String bomId = it.bom
if (!bomIds.contains(bomId)) { if (!bomIds.contains(bomId)) {
bomIds << bomId bomIds << bomId
boms << metadata.configuration.env.boms[bomId] boms << metadata.configuration.env.boms[bomId].resolve(requestedVersion)
} }
} }
if (it.repository) { if (it.repository) {
@ -142,12 +142,27 @@ class ProjectRequest {
this.applicationName = metadata.configuration.generateApplicationName(this.name) this.applicationName = metadata.configuration.generateApplicationName(this.name)
} }
initializeRepositories(metadata, requestedVersion)
afterResolution(metadata)
}
/**
* Set the repositories that this instance should use based on the {@link InitializrMetadata}
* and the requested Spring Boot {@link Version}.
*/
protected void initializeRepositories(InitializrMetadata metadata, Version requestedVersion) {
if (!'RELEASE'.equals(requestedVersion.qualifier.qualifier)) { if (!'RELEASE'.equals(requestedVersion.qualifier.qualifier)) {
repositories['spring-snapshots'] = metadata.configuration.env.repositories['spring-snapshots'] repositories['spring-snapshots'] = metadata.configuration.env.repositories['spring-snapshots']
repositories['spring-milestones'] = metadata.configuration.env.repositories['spring-milestones'] repositories['spring-milestones'] = metadata.configuration.env.repositories['spring-milestones']
} }
boms.each {
afterResolution(metadata) it.repositories.each {
if (!repositories[it]) {
repositories[it] = metadata.configuration.env.repositories[it]
}
}
}
} }
/** /**

View File

@ -16,7 +16,11 @@
package io.spring.initializr.metadata package io.spring.initializr.metadata
import com.fasterxml.jackson.annotation.JsonInclude
import groovy.transform.ToString import groovy.transform.ToString
import io.spring.initializr.util.InvalidVersionException
import io.spring.initializr.util.Version
import io.spring.initializr.util.VersionRange
/** /**
* Define a Bill Of Materials to be represented in the generated project * Define a Bill Of Materials to be represented in the generated project
@ -26,10 +30,65 @@ import groovy.transform.ToString
* @since 1.0 * @since 1.0
*/ */
@ToString(ignoreNulls = true, includePackage = false) @ToString(ignoreNulls = true, includePackage = false)
@JsonInclude(JsonInclude.Include.NON_NULL)
class BillOfMaterials { class BillOfMaterials {
String groupId String groupId
String artifactId String artifactId
/**
* The version of the BOM. Can be {@code null} if it is provided via
* a mapping.
*/
String version String version
List<String> repositories = []
final List<Mapping> mappings = []
void validate() {
if (!version && !mappings) {
throw new InvalidInitializrMetadataException("No version available for $this");
}
mappings.each {
try {
it.range = VersionRange.parse(it.versionRange)
} catch (InvalidVersionException ex) {
throw new InvalidInitializrMetadataException("Invalid version range $it.versionRange for $this", ex)
}
}
}
/**
* Resolve this instance according to the specified Spring Boot {@link Version}. Return
* a {@link BillOfMaterials} instance that holds the version and repositories to use, if
* any.
*/
BillOfMaterials resolve(Version bootVersion) {
if (!mappings) {
return this
}
for (Mapping mapping : mappings) {
if (mapping.range.match(bootVersion)) {
def resolvedBom = new BillOfMaterials(groupId: groupId, artifactId: artifactId,
version: mapping.version, repositories: repositories)
resolvedBom.repositories += mapping.repositories
return resolvedBom
}
}
throw new IllegalStateException("No suitable mapping was found for $this and version $bootVersion")
}
static class Mapping {
String versionRange
String version
List<String> repositories = []
private VersionRange range
}
} }

View File

@ -26,6 +26,10 @@ class InitializrConfiguration {
final Env env = new Env() final Env env = new Env()
void validate() {
env.validate()
}
void merge(InitializrConfiguration other) { void merge(InitializrConfiguration other) {
env.merge(other.env) env.merge(other.env)
} }
@ -137,6 +141,12 @@ class InitializrConfiguration {
this.artifactRepository = artifactRepository this.artifactRepository = artifactRepository
} }
void validate() {
boms.each {
it.value.validate()
}
}
void merge(Env other) { void merge(Env other) {
artifactRepository = other.artifactRepository artifactRepository = other.artifactRepository
springBootMetadataUrl = other.springBootMetadataUrl springBootMetadataUrl = other.springBootMetadataUrl

View File

@ -86,6 +86,7 @@ class InitializrMetadata {
* Validate the meta-data. * Validate the meta-data.
*/ */
void validate() { void validate() {
this.configuration.validate()
dependencies.validate() dependencies.validate()
for (Dependency dependency : dependencies.all) { for (Dependency dependency : dependencies.all) {

View File

@ -16,6 +16,7 @@
package io.spring.initializr.generator package io.spring.initializr.generator
import io.spring.initializr.metadata.BillOfMaterials
import io.spring.initializr.metadata.Dependency import io.spring.initializr.metadata.Dependency
import io.spring.initializr.test.GradleBuildAssert import io.spring.initializr.test.GradleBuildAssert
import io.spring.initializr.test.InitializrMetadataTestBuilder import io.spring.initializr.test.InitializrMetadataTestBuilder
@ -357,6 +358,53 @@ class ProjectGeneratorTests {
.hasBomsCount(1) .hasBomsCount(1)
} }
@Test
void mavenBomWithVersionMapping() {
def foo = new Dependency(id: 'foo', groupId: 'org.acme', artifactId: 'foo', bom: 'the-bom')
def bom = new BillOfMaterials(groupId: 'org.acme', artifactId: 'foo-bom')
bom.mappings << new BillOfMaterials.Mapping(versionRange: '[1.2.0.RELEASE,1.3.0.M1)', version: '1.0.0')
bom.mappings << new BillOfMaterials.Mapping(versionRange: '1.3.0.M1', version: '1.2.0')
def metadata = InitializrMetadataTestBuilder.withDefaults()
.addDependencyGroup('foo', foo)
.addBom('the-bom', bom).build()
projectGenerator.metadata = metadata
// First version
def request = createProjectRequest('foo')
request.bootVersion = '1.2.5.RELEASE'
generateMavenPom(request).hasDependency(foo)
.hasBom('org.acme', 'foo-bom', '1.0.0')
// Second version
def request2 = createProjectRequest('foo')
request2.bootVersion = '1.3.0.M1'
generateMavenPom(request2).hasDependency(foo)
.hasBom('org.acme', 'foo-bom', '1.2.0')
}
@Test
void mavenBomWithVersionMappingAndExtraRepositories() {
def foo = new Dependency(id: 'foo', groupId: 'org.acme', artifactId: 'foo', bom: 'the-bom')
def bom = new BillOfMaterials(groupId: 'org.acme', artifactId: 'foo-bom', repositories: ['foo-repo'])
bom.mappings << new BillOfMaterials.Mapping(versionRange: '[1.2.0.RELEASE,1.3.0.M1)', version: '1.0.0')
bom.mappings << new BillOfMaterials.Mapping(versionRange: '1.3.0.M1', version: '1.2.0', repositories: ['foo-repo', 'bar-repo'])
def metadata = InitializrMetadataTestBuilder.withDefaults()
.addDependencyGroup('foo', foo)
.addBom('the-bom', bom)
.addRepository('foo-repo', 'repo', 'http://example.com/foo', true)
.addRepository('bar-repo', 'repo', 'http://example.com/bar', false).build()
projectGenerator.metadata = metadata
// Second version
def request = createProjectRequest('foo')
request.bootVersion = '1.3.0.RELEASE'
generateMavenPom(request).hasDependency(foo)
.hasBom('org.acme', 'foo-bom', '1.2.0')
.hasRepository('foo-repo', 'repo', 'http://example.com/foo', true)
.hasRepository('bar-repo', 'repo', 'http://example.com/bar', false)
.hasRepositoriesCount(2)
}
@Test @Test
void gradleBom() { void gradleBom() {
def foo = new Dependency(id: 'foo', groupId: 'org.acme', artifactId: 'foo', bom: 'foo-bom') def foo = new Dependency(id: 'foo', groupId: 'org.acme', artifactId: 'foo', bom: 'foo-bom')

View File

@ -55,4 +55,32 @@ class InitializrMetadataTests {
builder.build() builder.build()
} }
@Test
void invalidBomNoVersion() {
def bom = new BillOfMaterials(groupId: 'org.acme', artifactId: 'foo-bom')
InitializrMetadataTestBuilder builder = InitializrMetadataTestBuilder
.withDefaults().addBom('foo-bom', bom)
thrown.expect(InvalidInitializrMetadataException)
thrown.expectMessage("No version")
thrown.expectMessage("foo-bom")
builder.build()
}
@Test
void invalidBomVersionRangeMapping() {
def bom = new BillOfMaterials(groupId: 'org.acme', artifactId: 'foo-bom')
bom.mappings << new BillOfMaterials.Mapping(versionRange: '[1.2.0.RELEASE,1.3.0.M1)', version: '1.0.0')
bom.mappings << new BillOfMaterials.Mapping(versionRange: 'FOO_BAR', version: '1.2.0')
InitializrMetadataTestBuilder builder = InitializrMetadataTestBuilder
.withDefaults().addBom('foo-bom', bom)
thrown.expect(InvalidInitializrMetadataException)
thrown.expectMessage("FOO_BAR")
thrown.expectMessage("foo-bom")
builder.build()
}
} }

View File

@ -142,9 +142,11 @@ class InitializrMetadataTestBuilder {
} }
InitializrMetadataTestBuilder addBom(String id, String groupId, String artifactId, String version) { InitializrMetadataTestBuilder addBom(String id, String groupId, String artifactId, String version) {
addBom(id, new BillOfMaterials(groupId: groupId, artifactId: artifactId, version: version))
}
InitializrMetadataTestBuilder addBom(String id, BillOfMaterials bom) {
builder.withCustomizer { builder.withCustomizer {
BillOfMaterials bom = new BillOfMaterials(
groupId: groupId, artifactId: artifactId, version: version)
it.configuration.env.boms[id] = bom it.configuration.env.boms[id] = bom
} }
this this