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
This commit is contained in:
Stephane Nicoll 2017-01-17 18:25:30 +01:00
parent 1d16c49b76
commit 330cb13c64
9 changed files with 161 additions and 7 deletions

View File

@ -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)

View File

@ -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

View File

@ -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)
}
/**

View File

@ -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()}"<% } %>
}
}

View File

@ -76,7 +76,7 @@
</dependencies>
<% if (boms) { %>
<dependencyManagement>
<dependencies><% boms.values().each { %>
<dependencies><% resolvedBoms.each { %>
<dependency>
<groupId>${it.groupId}</groupId>
<artifactId>${it.artifactId}</artifactId>

View File

@ -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)

View File

@ -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"
}
}

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.acme</groupId>
<artifactId>foo</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.acme</groupId>
<artifactId>foo-bom</artifactId>
<version>1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.acme</groupId>
<artifactId>biz-bom</artifactId>
<version>1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.acme</groupId>
<artifactId>bar-bom</artifactId>
<version>1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -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"