Auto-updatable version ranges

This commit improves the version format so that the minor and patch
elements can hold a special 'x' character besides the version, i.e.
`1.x.x.RELEASE` or `2.4.x.BUILD-SNAPSHOT`. A `VersionParser` now takes
care to resolve those against a list of known Spring Boot versions.

This is particularly useful in version ranges that have to change when
the latest Spring Boot versions change. Spring Initializr already auto-
udpates itself based on the sagan metadata. When a range is using this
feature, it is also automatically updated.

It might be hard to track the actual range values on a given instance so
an `InfoContributor` is now automatically exposed to list them.

Closes gh-328
This commit is contained in:
Stephane Nicoll
2016-12-06 16:39:23 +01:00
parent 814a4ad260
commit 827b9d6e93
22 changed files with 673 additions and 148 deletions

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2012-2016 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.initializr.actuate.autoconfigure
import io.spring.initializr.actuate.info.BomRangesInfoContributor
import io.spring.initializr.metadata.InitializrMetadataProvider
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} to improve actuator endpoints with initializr specific information.
*
* @author Stephane Nicoll
*/
@Configuration
class InitializrActuatorEndpointsAutoConfiguration {
@Bean
BomRangesInfoContributor bomRangesInfoContributor(
InitializrMetadataProvider metadataProvider) {
return new BomRangesInfoContributor(metadataProvider)
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2012-2016 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.initializr.actuate.info
import io.spring.initializr.metadata.InitializrMetadataProvider
import org.springframework.boot.actuate.info.Info
import org.springframework.boot.actuate.info.InfoContributor
/**
* An {@link InfoContributor} that exposes the actual ranges used by each bom
* defined in the project.
*
* @author Stephane Nicoll
*/
class BomRangesInfoContributor implements InfoContributor {
private final InitializrMetadataProvider metadataProvider
BomRangesInfoContributor(InitializrMetadataProvider metadataProvider) {
this.metadataProvider = metadataProvider
}
@Override
void contribute(Info.Builder builder) {
def details = [:]
metadataProvider.get().configuration.env.boms.each { k, v ->
if (v.mappings) {
def bom = [:]
v.mappings.each {
String requirement = "Spring Boot ${it.determineVersionRangeRequirement()}"
bom[it.version] = requirement
}
details[k] = bom
}
}
if (details) {
builder.withDetail('bom-ranges', details)
}
}
}

View File

@@ -1,3 +1,4 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
io.spring.initializr.actuate.autoconfigure.InitializrActuatorEndpointsAutoConfiguration,\
io.spring.initializr.actuate.autoconfigure.InitializrStatsAutoConfiguration,\
io.spring.initializr.actuate.autoconfigure.InitializrMetricsConfiguration

View File

@@ -0,0 +1,82 @@
/*
* Copyright 2012-2016 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.initializr.actuate.info
import io.spring.initializr.metadata.BillOfMaterials
import io.spring.initializr.metadata.InitializrMetadata
import io.spring.initializr.metadata.SimpleInitializrMetadataProvider
import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder
import org.junit.Test
import org.springframework.boot.actuate.info.Info
import static org.assertj.core.api.Assertions.assertThat
import static org.assertj.core.api.Assertions.entry
/**
* Tests for {@link BomRangesInfoContributor}
*
* @author Stephane Nicoll
*/
class BomRangesInfoContributorTests {
@Test
void noBom() {
def metadata = InitializrMetadataTestBuilder.withDefaults().build()
def info = getInfo(metadata)
assertThat(info.details).doesNotContainKeys('bom-ranges')
}
@Test
void noMapping() {
def bom = new BillOfMaterials(groupId: 'com.example', artifactId: 'bom', version: '1.0.0')
def metadata = InitializrMetadataTestBuilder.withDefaults()
.addBom('foo', bom)
.build()
def info = getInfo(metadata)
assertThat(info.details).doesNotContainKeys('bom-ranges')
}
@Test
void withMappings() {
BillOfMaterials bom = new BillOfMaterials(groupId: 'com.example',
artifactId: 'bom', version: '1.0.0')
bom.mappings << new BillOfMaterials.Mapping(
versionRange: '[1.3.0.RELEASE,1.3.8.RELEASE]', version: '1.1.0')
bom.mappings << new BillOfMaterials.Mapping(
versionRange: '1.3.8.BUILD-SNAPSHOT', version: '1.1.1-SNAPSHOT')
def metadata = InitializrMetadataTestBuilder.withDefaults()
.addBom('foo', bom)
.build()
def info = getInfo(metadata)
assertThat(info.details).containsKeys('bom-ranges')
Map<String,Object> ranges = info.details['bom-ranges'] as Map<String, Object>
assertThat(ranges).containsOnlyKeys('foo')
Map<String,Object> foo = ranges['foo'] as Map<String, Object>
assertThat(foo).containsExactly(
entry('1.1.0', 'Spring Boot >=1.3.0.RELEASE and <=1.3.8.RELEASE'),
entry('1.1.1-SNAPSHOT', 'Spring Boot >=1.3.8.BUILD-SNAPSHOT'))
}
private static Info getInfo(InitializrMetadata metadata) {
Info.Builder builder = new Info.Builder()
new BomRangesInfoContributor(new SimpleInitializrMetadataProvider(metadata))
.contribute(builder)
builder.build()
}
}