mirror of
https://gitee.com/dcren/initializr.git
synced 2025-07-15 23:13:30 +08:00
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:
parent
814a4ad260
commit
827b9d6e93
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
io.spring.initializr.actuate.autoconfigure.InitializrActuatorEndpointsAutoConfiguration,\
|
||||||
io.spring.initializr.actuate.autoconfigure.InitializrStatsAutoConfiguration,\
|
io.spring.initializr.actuate.autoconfigure.InitializrStatsAutoConfiguration,\
|
||||||
io.spring.initializr.actuate.autoconfigure.InitializrMetricsConfiguration
|
io.spring.initializr.actuate.autoconfigure.InitializrMetricsConfiguration
|
@ -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()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -19,7 +19,6 @@ package io.spring.initializr.generator
|
|||||||
import io.spring.initializr.metadata.InitializrMetadata
|
import io.spring.initializr.metadata.InitializrMetadata
|
||||||
import io.spring.initializr.metadata.Type
|
import io.spring.initializr.metadata.Type
|
||||||
import io.spring.initializr.util.GroovyTemplate
|
import io.spring.initializr.util.GroovyTemplate
|
||||||
import io.spring.initializr.util.VersionRange
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate help pages for command-line clients.
|
* Generate help pages for command-line clients.
|
||||||
@ -144,7 +143,7 @@ class CommandLineHelpGenerator {
|
|||||||
String[] data = new String[3]
|
String[] data = new String[3]
|
||||||
data[0] = dep.id
|
data[0] = dep.id
|
||||||
data[1] = dep.description ?: dep.name
|
data[1] = dep.description ?: dep.name
|
||||||
data[2] = buildVersionRangeRepresentation(dep.versionRange)
|
data[2] = dep.versionRequirement
|
||||||
dependencyTable[i + 1] = data
|
dependencyTable[i + 1] = data
|
||||||
}
|
}
|
||||||
TableGenerator.generate(dependencyTable)
|
TableGenerator.generate(dependencyTable)
|
||||||
@ -182,18 +181,6 @@ class CommandLineHelpGenerator {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String buildVersionRangeRepresentation(String range) {
|
|
||||||
if (!range) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
VersionRange versionRange = VersionRange.parse(range)
|
|
||||||
if (versionRange.higherVersion == null) {
|
|
||||||
return ">= $range"
|
|
||||||
} else {
|
|
||||||
return range.trim()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String buildTagRepresentation(Type type) {
|
private static String buildTagRepresentation(Type type) {
|
||||||
if (type.tags.isEmpty()) {
|
if (type.tags.isEmpty()) {
|
||||||
return "";
|
return "";
|
||||||
|
@ -93,12 +93,9 @@ class ProjectRequest extends BasicProjectRequest {
|
|||||||
facets.add(it)
|
facets.add(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (it.versionRange) {
|
if (!it.match(requestedVersion)) {
|
||||||
def range = VersionRange.parse(it.versionRange)
|
throw new InvalidProjectRequestException("Dependency '$it.id' is not compatible " +
|
||||||
if (!range.match(requestedVersion)) {
|
"with Spring Boot $requestedVersion")
|
||||||
throw new InvalidProjectRequestException("Dependency '$it.id' is not compatible " +
|
|
||||||
"with Spring Boot $bootVersion")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (it.bom) {
|
if (it.bom) {
|
||||||
resolveBom(metadata, it.bom, requestedVersion)
|
resolveBom(metadata, it.bom, requestedVersion)
|
||||||
|
@ -20,6 +20,7 @@ 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.InvalidVersionException
|
||||||
import io.spring.initializr.util.Version
|
import io.spring.initializr.util.Version
|
||||||
|
import io.spring.initializr.util.VersionParser
|
||||||
import io.spring.initializr.util.VersionRange
|
import io.spring.initializr.util.VersionRange
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,9 +76,13 @@ class BillOfMaterials {
|
|||||||
if (!version && !mappings) {
|
if (!version && !mappings) {
|
||||||
throw new InvalidInitializrMetadataException("No version available for $this");
|
throw new InvalidInitializrMetadataException("No version available for $this");
|
||||||
}
|
}
|
||||||
|
updateVersionRange(VersionParser.DEFAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateVersionRange(VersionParser versionParser) {
|
||||||
mappings.each {
|
mappings.each {
|
||||||
try {
|
try {
|
||||||
it.range = VersionRange.parse(it.versionRange)
|
it.range = versionParser.parseRange(it.versionRange)
|
||||||
} catch (InvalidVersionException ex) {
|
} catch (InvalidVersionException ex) {
|
||||||
throw new InvalidInitializrMetadataException("Invalid version range $it.versionRange for $this", ex)
|
throw new InvalidInitializrMetadataException("Invalid version range $it.versionRange for $this", ex)
|
||||||
}
|
}
|
||||||
@ -119,6 +124,10 @@ class BillOfMaterials {
|
|||||||
|
|
||||||
private VersionRange range
|
private VersionRange range
|
||||||
|
|
||||||
|
String determineVersionRangeRequirement() {
|
||||||
|
range.toString()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2015 the original author or authors.
|
* Copyright 2012-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package io.spring.initializr.metadata
|
package io.spring.initializr.metadata
|
||||||
|
|
||||||
|
import io.spring.initializr.util.VersionParser
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link ServiceCapability} listing the available dependencies defined as a
|
* A {@link ServiceCapability} listing the available dependencies defined as a
|
||||||
* {@link ServiceCapabilityType#HIERARCHICAL_MULTI_SELECT} capability.
|
* {@link ServiceCapabilityType#HIERARCHICAL_MULTI_SELECT} capability.
|
||||||
@ -53,6 +55,12 @@ class DependenciesCapability extends ServiceCapability<List<DependencyGroup>> {
|
|||||||
index()
|
index()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateVersionRange(VersionParser versionParser) {
|
||||||
|
indexedDependencies.values().each {
|
||||||
|
it.updateVersionRanges(versionParser)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void merge(List<DependencyGroup> otherContent) {
|
void merge(List<DependencyGroup> otherContent) {
|
||||||
otherContent.each { group ->
|
otherContent.each { group ->
|
||||||
|
@ -23,6 +23,7 @@ import groovy.transform.AutoCloneStyle
|
|||||||
import groovy.transform.ToString
|
import groovy.transform.ToString
|
||||||
import io.spring.initializr.util.InvalidVersionException
|
import io.spring.initializr.util.InvalidVersionException
|
||||||
import io.spring.initializr.util.Version
|
import io.spring.initializr.util.Version
|
||||||
|
import io.spring.initializr.util.VersionParser
|
||||||
import io.spring.initializr.util.VersionRange
|
import io.spring.initializr.util.VersionRange
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -84,6 +85,8 @@ class Dependency extends MetadataElement {
|
|||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
String versionRequirement
|
String versionRequirement
|
||||||
|
|
||||||
|
private VersionRange range
|
||||||
|
|
||||||
String bom
|
String bom
|
||||||
|
|
||||||
@ -159,18 +162,22 @@ class Dependency extends MetadataElement {
|
|||||||
"Invalid dependency, id should have the form groupId:artifactId[:version] but got $id")
|
"Invalid dependency, id should have the form groupId:artifactId[:version] but got $id")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
updateVersionRanges(VersionParser.DEFAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
def updateVersionRanges(VersionParser versionParser) {
|
||||||
if (versionRange) {
|
if (versionRange) {
|
||||||
try {
|
try {
|
||||||
def range = VersionRange.parse(versionRange)
|
range = versionParser.parseRange(versionRange)
|
||||||
versionRequirement = range.toString()
|
versionRequirement = range.toString()
|
||||||
} catch (InvalidVersionException ex) {
|
} catch (InvalidVersionException ex) {
|
||||||
throw new InvalidInitializrMetadataException("Invalid version range '$versionRange' for " +
|
throw new InvalidInitializrMetadataException("Invalid version range '$versionRange' for " +
|
||||||
"dependency with id '$id'")
|
"dependency with id '$id'", ex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mappings.each {
|
mappings.each {
|
||||||
try {
|
try {
|
||||||
it.range = VersionRange.parse(it.versionRange)
|
it.range = versionParser.parseRange(it.versionRange)
|
||||||
} catch (InvalidVersionException ex) {
|
} catch (InvalidVersionException ex) {
|
||||||
throw new InvalidInitializrMetadataException("Invalid version range $it.versionRange for $this", ex)
|
throw new InvalidInitializrMetadataException("Invalid version range $it.versionRange for $this", ex)
|
||||||
}
|
}
|
||||||
@ -200,8 +207,8 @@ class Dependency extends MetadataElement {
|
|||||||
* Specify if this dependency is available for the specified Spring Boot version.
|
* Specify if this dependency is available for the specified Spring Boot version.
|
||||||
*/
|
*/
|
||||||
boolean match(Version version) {
|
boolean match(Version version) {
|
||||||
if (versionRange) {
|
if (range) {
|
||||||
return VersionRange.parse(versionRange).match(version)
|
return range.match(version)
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package io.spring.initializr.metadata
|
package io.spring.initializr.metadata
|
||||||
|
|
||||||
|
import io.spring.initializr.util.Version
|
||||||
|
import io.spring.initializr.util.VersionParser
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Meta-data used to generate a project.
|
* Meta-data used to generate a project.
|
||||||
*
|
*
|
||||||
@ -132,7 +135,23 @@ class InitializrMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the available Spring Boot versions with the specified capabilities.
|
||||||
|
* @param versionsMetadata the Spring Boot boot versions metadata to use
|
||||||
|
*/
|
||||||
|
void updateSpringBootVersions(List<DefaultMetadataElement> versionsMetadata) {
|
||||||
|
bootVersions.content.clear()
|
||||||
|
bootVersions.content.addAll(versionsMetadata)
|
||||||
|
List<Version> bootVersions = bootVersions.content.collect {
|
||||||
|
Version.parse(it.id)
|
||||||
|
}
|
||||||
|
VersionParser parser = new VersionParser(bootVersions)
|
||||||
|
dependencies.updateVersionRange(parser)
|
||||||
|
configuration.env.boms.values().each {
|
||||||
|
it.updateVersionRange(parser)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2015 the original author or authors.
|
* Copyright 2012-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -44,13 +44,22 @@ final class Version implements Serializable, Comparable<Version> {
|
|||||||
|
|
||||||
private static final VersionQualifierComparator qualifierComparator = new VersionQualifierComparator()
|
private static final VersionQualifierComparator qualifierComparator = new VersionQualifierComparator()
|
||||||
|
|
||||||
Integer major
|
private static final VersionParser parser = new VersionParser(Collections.EMPTY_LIST)
|
||||||
Integer minor
|
|
||||||
Integer patch
|
final Integer major
|
||||||
Qualifier qualifier
|
final Integer minor
|
||||||
|
final Integer patch
|
||||||
|
final Qualifier qualifier
|
||||||
|
|
||||||
|
Version(Integer major, Integer minor, Integer patch, Qualifier qualifier) {
|
||||||
|
this.major = major
|
||||||
|
this.minor = minor
|
||||||
|
this.patch = patch
|
||||||
|
this.qualifier = qualifier
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
String toString() {
|
||||||
"${major}.${minor}.${patch}" + (qualifier?".${qualifier.qualifier}${qualifier.version?:''}" : '')
|
"${major}.${minor}.${patch}" + (qualifier?".${qualifier.qualifier}${qualifier.version?:''}" : '')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,29 +69,10 @@ final class Version implements Serializable, Comparable<Version> {
|
|||||||
* @param text the version text
|
* @param text the version text
|
||||||
* @return a Version instance for the specified version text
|
* @return a Version instance for the specified version text
|
||||||
* @throws InvalidVersionException if the version text could not be parsed
|
* @throws InvalidVersionException if the version text could not be parsed
|
||||||
* @see #safeParse(java.lang.String)
|
* @see {@link VersionParser}
|
||||||
*/
|
*/
|
||||||
static Version parse(String text) {
|
static Version parse(String text) {
|
||||||
Assert.notNull(text, 'Text must not be null')
|
return parser.parse(text)
|
||||||
def matcher = (text.trim() =~ VERSION_REGEX)
|
|
||||||
if (!matcher.matches()) {
|
|
||||||
throw new InvalidVersionException("Could not determine version based on '$text': version format " +
|
|
||||||
"is Minor.Major.Patch.Qualifier (i.e. 1.0.5.RELEASE)")
|
|
||||||
}
|
|
||||||
Version version = new Version()
|
|
||||||
version.major = Integer.valueOf(matcher[0][1])
|
|
||||||
version.minor = Integer.valueOf(matcher[0][2])
|
|
||||||
version.patch = Integer.valueOf(matcher[0][3])
|
|
||||||
String qualifierId = matcher[0][4]
|
|
||||||
if (qualifierId) {
|
|
||||||
Qualifier qualifier = new Qualifier(qualifier: qualifierId)
|
|
||||||
String o = matcher[0][5]
|
|
||||||
if (o != null) {
|
|
||||||
qualifier.version = Integer.valueOf(o)
|
|
||||||
}
|
|
||||||
version.qualifier = qualifier
|
|
||||||
}
|
|
||||||
version
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -91,7 +81,7 @@ final class Version implements Serializable, Comparable<Version> {
|
|||||||
* Return {@code null} if the text represents an invalid version.
|
* Return {@code null} if the text represents an invalid version.
|
||||||
* @param text the version text
|
* @param text the version text
|
||||||
* @return a Version instance for the specified version text
|
* @return a Version instance for the specified version text
|
||||||
* @see #parse(java.lang.String)
|
* @see {@link VersionParser}
|
||||||
*/
|
*/
|
||||||
static safeParse(String text) {
|
static safeParse(String text) {
|
||||||
try {
|
try {
|
||||||
@ -129,7 +119,7 @@ final class Version implements Serializable, Comparable<Version> {
|
|||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode
|
||||||
public static class Qualifier {
|
static class Qualifier {
|
||||||
String qualifier
|
String qualifier
|
||||||
Integer version
|
Integer version
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* 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.util
|
||||||
|
|
||||||
|
import org.springframework.util.Assert
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parser for {@link Version} and {@link VersionRange} that allows to resolve the minor
|
||||||
|
* and patch value against a configurable list of "latest versions".
|
||||||
|
* <p>
|
||||||
|
* For example a parser that is configured with {@code 1.3.7.RELEASE} and
|
||||||
|
* {@code 1.4.2.RELEASE} as latest versions can parse {@code 1.3.x.RELEASE} to
|
||||||
|
* {@code 1.3.7.RELEASE}. Note that the qualifier is important here:
|
||||||
|
* {@code 1.3.8.BUILD-SNAPSHOT} would be parsed as {@code 1.3.999.BUILD-SNAPSHOT} as the
|
||||||
|
* parser doesn't know the latest {@code BUILD-SNAPSHOT} in the {@code 1.3.x} release
|
||||||
|
* line.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
class VersionParser {
|
||||||
|
|
||||||
|
public static final VersionParser DEFAULT = new VersionParser(Collections.emptyList())
|
||||||
|
|
||||||
|
private static final String VERSION_REGEX = '^(\\d+)\\.(\\d+|x)\\.(\\d+|x)(?:\\.([^0-9]+)(\\d+)?)?$'
|
||||||
|
|
||||||
|
private static final String RANGE_REGEX = "(\\(|\\[)(.*),(.*)(\\)|\\])"
|
||||||
|
|
||||||
|
private final List<Version> latestVersions;
|
||||||
|
|
||||||
|
VersionParser(List<Version> latestVersions) {
|
||||||
|
this.latestVersions = latestVersions
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the string representation of a {@link Version}. Throws an
|
||||||
|
* {@link InvalidVersionException} if the version could not be parsed.
|
||||||
|
* @param text the version text
|
||||||
|
* @return a Version instance for the specified version text
|
||||||
|
* @throws InvalidVersionException if the version text could not be parsed
|
||||||
|
* @see #safeParse(java.lang.String)
|
||||||
|
*/
|
||||||
|
Version parse(String text) {
|
||||||
|
Assert.notNull(text, 'Text must not be null')
|
||||||
|
def matcher = (text.trim() =~ VERSION_REGEX)
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
throw new InvalidVersionException("Could not determine version based on '$text': version format " +
|
||||||
|
"is Minor.Major.Patch.Qualifier (e.g. 1.0.5.RELEASE)")
|
||||||
|
}
|
||||||
|
Integer major = Integer.valueOf(matcher[0][1])
|
||||||
|
String minor = matcher[0][2]
|
||||||
|
String patch = matcher[0][3]
|
||||||
|
def qualifier = null;
|
||||||
|
String qualifierId = matcher[0][4]
|
||||||
|
if (qualifierId) {
|
||||||
|
qualifier = new Version.Qualifier(qualifier: qualifierId)
|
||||||
|
String o = matcher[0][5]
|
||||||
|
if (o != null) {
|
||||||
|
qualifier.version = Integer.valueOf(o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (minor == "x" || patch == "x") {
|
||||||
|
Integer minorInt = minor == "x" ? null : Integer.parseInt(minor)
|
||||||
|
Version latest = findLatestVersion(major, minorInt, qualifier)
|
||||||
|
if (!latest) {
|
||||||
|
return new Version(major, (minor == "x" ? 999 : Integer.parseInt(minor)),
|
||||||
|
(patch == "x" ? 999 : Integer.parseInt(patch)), qualifier)
|
||||||
|
}
|
||||||
|
return new Version(major, latest.minor, latest.patch, latest.qualifier)
|
||||||
|
} else {
|
||||||
|
return new Version(major, Integer.parseInt(minor), Integer.parseInt(patch), qualifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse safely the specified string representation of a {@link Version}.
|
||||||
|
* <p>
|
||||||
|
* Return {@code null} if the text represents an invalid version.
|
||||||
|
* @param text the version text
|
||||||
|
* @return a Version instance for the specified version text
|
||||||
|
* @see #parse(java.lang.String)
|
||||||
|
*/
|
||||||
|
Version safeParse(String text) {
|
||||||
|
try {
|
||||||
|
return parse(text)
|
||||||
|
} catch (InvalidVersionException ex) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the string representation of a {@link VersionRange}. Throws an
|
||||||
|
* {@link InvalidVersionException} if the range could not be parsed.
|
||||||
|
* @param text the range text
|
||||||
|
* @return a VersionRange instance for the specified range text
|
||||||
|
* @throws InvalidVersionException if the range text could not be parsed
|
||||||
|
*/
|
||||||
|
VersionRange parseRange(String text) {
|
||||||
|
Assert.notNull(text, "Text must not be null")
|
||||||
|
def matcher = (text.trim() =~ RANGE_REGEX)
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
// Try to read it as simple string
|
||||||
|
Version version = parse(text)
|
||||||
|
return new VersionRange(version, true, null, true)
|
||||||
|
}
|
||||||
|
boolean lowerInclusive = matcher[0][1].equals('[')
|
||||||
|
Version lowerVersion = parse(matcher[0][2])
|
||||||
|
Version higherVersion = parse(matcher[0][3])
|
||||||
|
boolean higherInclusive = matcher[0][4].equals(']')
|
||||||
|
new VersionRange(lowerVersion, lowerInclusive, higherVersion, higherInclusive)
|
||||||
|
}
|
||||||
|
|
||||||
|
private Version findLatestVersion(Integer major, Integer minor,
|
||||||
|
Version.Qualifier qualifier) {
|
||||||
|
def matches = this.latestVersions.findAll {
|
||||||
|
if (major && major != it.major) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (minor && minor != it.minor) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (qualifier && it.qualifier != qualifier) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return (matches.size() == 1 ? matches[0] : null)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -17,7 +17,6 @@
|
|||||||
package io.spring.initializr.util
|
package io.spring.initializr.util
|
||||||
|
|
||||||
import groovy.transform.EqualsAndHashCode
|
import groovy.transform.EqualsAndHashCode
|
||||||
import groovy.transform.ToString
|
|
||||||
|
|
||||||
import org.springframework.util.Assert
|
import org.springframework.util.Assert
|
||||||
|
|
||||||
@ -41,15 +40,13 @@ import org.springframework.util.Assert
|
|||||||
@EqualsAndHashCode
|
@EqualsAndHashCode
|
||||||
class VersionRange {
|
class VersionRange {
|
||||||
|
|
||||||
private static final String RANGE_REGEX = "(\\(|\\[)(.*),(.*)(\\)|\\])"
|
|
||||||
|
|
||||||
final Version lowerVersion
|
final Version lowerVersion
|
||||||
final boolean lowerInclusive
|
final boolean lowerInclusive
|
||||||
final Version higherVersion
|
final Version higherVersion
|
||||||
final boolean higherInclusive
|
final boolean higherInclusive
|
||||||
|
|
||||||
private VersionRange(Version lowerVersion, boolean lowerInclusive,
|
protected VersionRange(Version lowerVersion, boolean lowerInclusive,
|
||||||
Version higherVersion, boolean higherInclusive) {
|
Version higherVersion, boolean higherInclusive) {
|
||||||
this.lowerVersion = lowerVersion
|
this.lowerVersion = lowerVersion
|
||||||
this.lowerInclusive = lowerInclusive
|
this.lowerInclusive = lowerInclusive
|
||||||
this.higherVersion = higherVersion
|
this.higherVersion = higherVersion
|
||||||
@ -86,31 +83,9 @@ class VersionRange {
|
|||||||
sb.append("${lowerInclusive ? '>=' : '>'}${lowerVersion}")
|
sb.append("${lowerInclusive ? '>=' : '>'}${lowerVersion}")
|
||||||
}
|
}
|
||||||
if (higherVersion) {
|
if (higherVersion) {
|
||||||
sb.append(" and ${higherInclusive ? '<=' : '<'}${higherVersion}")
|
sb.append(" and ${higherInclusive ? '<=' : '<'}${higherVersion}")
|
||||||
}
|
}
|
||||||
return sb.toString()
|
return sb.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the string representation of a {@link VersionRange}. Throws an
|
|
||||||
* {@link InvalidVersionException} if the range could not be parsed.
|
|
||||||
* @param text the range text
|
|
||||||
* @return a VersionRange instance for the specified range text
|
|
||||||
* @throws InvalidVersionException if the range text could not be parsed
|
|
||||||
*/
|
|
||||||
static VersionRange parse(String text) {
|
|
||||||
Assert.notNull(text, "Text must not be null")
|
|
||||||
def matcher = (text.trim() =~ RANGE_REGEX)
|
|
||||||
if (!matcher.matches()) {
|
|
||||||
// Try to read it as simple string
|
|
||||||
Version version = Version.parse(text)
|
|
||||||
return new VersionRange(version, true, null, true)
|
|
||||||
}
|
|
||||||
boolean lowerInclusive = matcher[0][1].equals('[')
|
|
||||||
Version lowerVersion = Version.parse(matcher[0][2])
|
|
||||||
Version higherVersion = Version.parse(matcher[0][3])
|
|
||||||
boolean higherInclusive = matcher[0][4].equals(']')
|
|
||||||
new VersionRange(lowerVersion, lowerInclusive, higherVersion, higherInclusive)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -112,11 +112,11 @@ class CommandLineHelpGeneratorTests {
|
|||||||
def second = new Dependency(id: 'second', description: 'second desc', versionRange: ' [1.2.0.RELEASE,1.3.0.M1) ')
|
def second = new Dependency(id: 'second', description: 'second desc', versionRange: ' [1.2.0.RELEASE,1.3.0.M1) ')
|
||||||
def metadata = InitializrMetadataTestBuilder.withDefaults().addDependencyGroup("test", first, second).build()
|
def metadata = InitializrMetadataTestBuilder.withDefaults().addDependencyGroup("test", first, second).build()
|
||||||
String content = generator.generateSpringBootCliCapabilities(metadata, "https://fake-service")
|
String content = generator.generateSpringBootCliCapabilities(metadata, "https://fake-service")
|
||||||
assertThat content, containsString('| first | first desc | >= 1.2.0.RELEASE |')
|
assertThat content, containsString('| first | first desc | >=1.2.0.RELEASE |')
|
||||||
assertThat content, containsString('| second | second desc | [1.2.0.RELEASE,1.3.0.M1) |')
|
assertThat content, containsString('| second | second desc | >=1.2.0.RELEASE and <1.3.0.M1 |')
|
||||||
}
|
}
|
||||||
|
|
||||||
private assertCommandLineCapabilities(String content) {
|
private static assertCommandLineCapabilities(String content) {
|
||||||
assertThat content, containsString("| Rel")
|
assertThat content, containsString("| Rel")
|
||||||
assertThat content, containsString("| dependencies")
|
assertThat content, containsString("| dependencies")
|
||||||
assertThat content, containsString("| applicationName")
|
assertThat content, containsString("| applicationName")
|
||||||
@ -124,11 +124,11 @@ class CommandLineHelpGeneratorTests {
|
|||||||
assertThat content, not(containsString('| Tags'))
|
assertThat content, not(containsString('| Tags'))
|
||||||
}
|
}
|
||||||
|
|
||||||
private static def createDependency(String id, String name) {
|
private static createDependency(String id, String name) {
|
||||||
createDependency(id, name, null)
|
createDependency(id, name, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static def createDependency(String id, String name, String description) {
|
private static createDependency(String id, String name, String description) {
|
||||||
new Dependency(id: id, name: name, description: description)
|
new Dependency(id: id, name: name, description: description)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package io.spring.initializr.metadata
|
package io.spring.initializr.metadata
|
||||||
|
|
||||||
import io.spring.initializr.util.Version
|
import io.spring.initializr.util.Version
|
||||||
|
import io.spring.initializr.util.VersionParser
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.rules.ExpectedException
|
import org.junit.rules.ExpectedException
|
||||||
@ -108,4 +109,25 @@ class BillOfMaterialsTests {
|
|||||||
bom.resolve(Version.parse('1.4.1.RELEASE'))
|
bom.resolve(Version.parse('1.4.1.RELEASE'))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void resolveRangeWithVariablePatch() {
|
||||||
|
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.x.RELEASE]', version: '1.1.0')
|
||||||
|
bom.mappings << new BillOfMaterials.Mapping(
|
||||||
|
versionRange: '[1.3.x.BUILD-SNAPSHOT,1.4.0.RELEASE)', version: '1.1.1-SNAPSHOT')
|
||||||
|
bom.validate()
|
||||||
|
|
||||||
|
bom.updateVersionRange(new VersionParser(Arrays.asList(
|
||||||
|
Version.parse("1.3.8.RELEASE"), Version.parse("1.3.9.BUILD-SNAPSHOT"))))
|
||||||
|
assertThat(bom.resolve(Version.parse('1.3.8.RELEASE')).version, equalTo('1.1.0'))
|
||||||
|
assertThat(bom.resolve(Version.parse('1.3.9.RELEASE')).version, equalTo('1.1.1-SNAPSHOT'))
|
||||||
|
|
||||||
|
bom.updateVersionRange(new VersionParser(Arrays.asList(
|
||||||
|
Version.parse("1.3.9.RELEASE"), Version.parse("1.3.10.BUILD-SNAPSHOT"))))
|
||||||
|
assertThat(bom.resolve(Version.parse('1.3.8.RELEASE')).version, equalTo('1.1.0'))
|
||||||
|
assertThat(bom.resolve(Version.parse('1.3.9.RELEASE')).version, equalTo('1.1.0'))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package io.spring.initializr.metadata
|
package io.spring.initializr.metadata
|
||||||
|
|
||||||
import io.spring.initializr.util.Version
|
import io.spring.initializr.util.Version
|
||||||
|
import io.spring.initializr.util.VersionParser
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.rules.ExpectedException
|
import org.junit.rules.ExpectedException
|
||||||
@ -201,6 +202,37 @@ class DependencyTests {
|
|||||||
'org.springframework.boot', 'spring-boot-starter-web', '0.3.0.RELEASE') // default
|
'org.springframework.boot', 'spring-boot-starter-web', '0.3.0.RELEASE') // default
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void resolveMatchingVersionWithVariablePatch() {
|
||||||
|
def dependency = new Dependency(id: 'web', description: 'A web dependency', version: '0.3.0.RELEASE',
|
||||||
|
keywords: ['foo', 'bar'], aliases: ['the-web'], facets: ['web'])
|
||||||
|
dependency.mappings << new Dependency.Mapping(
|
||||||
|
versionRange: '[1.1.0.RELEASE, 1.1.x.RELEASE]', version: '0.1.0.RELEASE')
|
||||||
|
dependency.mappings << new Dependency.Mapping(
|
||||||
|
versionRange: '[1.1.x.BUILD-SNAPSHOT, 1.2.0.RELEASE)', version: '0.2.0.RELEASE')
|
||||||
|
dependency.resolve()
|
||||||
|
|
||||||
|
dependency.updateVersionRanges(new VersionParser(Arrays.asList(
|
||||||
|
Version.parse("1.1.5.RELEASE"), Version.parse("1.1.6.BUILD-SNAPSHOT"))))
|
||||||
|
validateResolvedWebDependency(dependency.resolve(Version.parse('1.1.5.RELEASE')),
|
||||||
|
'org.springframework.boot', 'spring-boot-starter-web', '0.1.0.RELEASE')
|
||||||
|
validateResolvedWebDependency(dependency.resolve(Version.parse('1.1.6.BUILD-SNAPSHOT')),
|
||||||
|
'org.springframework.boot', 'spring-boot-starter-web', '0.2.0.RELEASE')
|
||||||
|
validateResolvedWebDependency(dependency.resolve(Version.parse('2.1.3.M1')),
|
||||||
|
'org.springframework.boot', 'spring-boot-starter-web', '0.3.0.RELEASE') // default
|
||||||
|
|
||||||
|
dependency.updateVersionRanges(new VersionParser(Arrays.asList(
|
||||||
|
Version.parse("1.1.6.RELEASE"), Version.parse("1.1.7.BUILD-SNAPSHOT"))))
|
||||||
|
validateResolvedWebDependency(dependency.resolve(Version.parse('1.1.5.RELEASE')),
|
||||||
|
'org.springframework.boot', 'spring-boot-starter-web', '0.1.0.RELEASE')
|
||||||
|
validateResolvedWebDependency(dependency.resolve(Version.parse('1.1.6.RELEASE')),
|
||||||
|
'org.springframework.boot', 'spring-boot-starter-web', '0.1.0.RELEASE')
|
||||||
|
validateResolvedWebDependency(dependency.resolve(Version.parse('1.1.7.BUILD-SNAPSHOT')),
|
||||||
|
'org.springframework.boot', 'spring-boot-starter-web', '0.2.0.RELEASE')
|
||||||
|
validateResolvedWebDependency(dependency.resolve(Version.parse('2.1.3.M1')),
|
||||||
|
'org.springframework.boot', 'spring-boot-starter-web', '0.3.0.RELEASE') // default
|
||||||
|
}
|
||||||
|
|
||||||
static void validateResolvedWebDependency(
|
static void validateResolvedWebDependency(
|
||||||
def dependency, def expectedGroupId, def expectedArtifactId, def expectedVersion) {
|
def dependency, def expectedGroupId, def expectedArtifactId, def expectedVersion) {
|
||||||
assertEquals expectedVersion, dependency.version
|
assertEquals expectedVersion, dependency.version
|
||||||
|
@ -17,10 +17,13 @@
|
|||||||
package io.spring.initializr.metadata
|
package io.spring.initializr.metadata
|
||||||
|
|
||||||
import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder
|
import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder
|
||||||
|
import io.spring.initializr.util.Version
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.rules.ExpectedException
|
import org.junit.rules.ExpectedException
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
*/
|
*/
|
||||||
@ -146,6 +149,34 @@ class InitializrMetadataTests {
|
|||||||
builder.build()
|
builder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void updateSpringBootVersions() {
|
||||||
|
def bom = new BillOfMaterials(groupId: 'org.acme', artifactId: 'foo-bom')
|
||||||
|
bom.mappings << new BillOfMaterials.Mapping(versionRange: '[1.3.0.RELEASE,1.3.x.RELEASE]', version: '1.0.0')
|
||||||
|
bom.mappings << new BillOfMaterials.Mapping(versionRange: '1.3.x.BUILD-SNAPSHOT', version: '1.1.0-BUILD-SNAPSHOT')
|
||||||
|
def dependency = new Dependency(id: 'bar')
|
||||||
|
dependency.mappings << new Dependency.Mapping(
|
||||||
|
versionRange: '[1.3.0.RELEASE, 1.3.x.RELEASE]', version: '0.1.0.RELEASE')
|
||||||
|
dependency.mappings << new Dependency.Mapping(
|
||||||
|
versionRange: '1.3.x.BUILD-SNAPSHOT', version: '0.2.0.RELEASE')
|
||||||
|
InitializrMetadata metadata = InitializrMetadataTestBuilder
|
||||||
|
.withDefaults().addDependencyGroup("test", dependency)
|
||||||
|
.addBom('foo-bom', bom).build();
|
||||||
|
|
||||||
|
List<DefaultMetadataElement> bootVersions = Arrays.asList(
|
||||||
|
new DefaultMetadataElement(id: '1.3.6.RELEASE', name: '1.3.6'),
|
||||||
|
new DefaultMetadataElement(id: '1.3.7.BUILD-SNAPSHOT', name: '1.3.7'))
|
||||||
|
metadata.updateSpringBootVersions(bootVersions)
|
||||||
|
assertThat(metadata.configuration.env.boms['foo-bom']
|
||||||
|
.resolve(Version.parse('1.3.6.RELEASE')).version).isEqualTo('1.0.0')
|
||||||
|
assertThat(metadata.configuration.env.boms['foo-bom']
|
||||||
|
.resolve(Version.parse('1.3.7.BUILD-SNAPSHOT')).version).isEqualTo('1.1.0-BUILD-SNAPSHOT')
|
||||||
|
assertThat(metadata.dependencies.get('bar')
|
||||||
|
.resolve(Version.parse('1.3.6.RELEASE')).version).isEqualTo('0.1.0.RELEASE')
|
||||||
|
assertThat(metadata.dependencies.get('bar')
|
||||||
|
.resolve(Version.parse('1.3.7.BUILD-SNAPSHOT')).version).isEqualTo('0.2.0.RELEASE')
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void invalidParentMissingVersion() {
|
void invalidParentMissingVersion() {
|
||||||
InitializrMetadataTestBuilder builder = InitializrMetadataTestBuilder
|
InitializrMetadataTestBuilder builder = InitializrMetadataTestBuilder
|
||||||
|
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* 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.util
|
||||||
|
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.rules.ExpectedException
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat
|
||||||
|
import static org.hamcrest.Matchers.equalTo
|
||||||
|
import static org.hamcrest.Matchers.lessThan
|
||||||
|
import static org.junit.Assert.assertNull
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link VersionParser}.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
class VersionParserTests {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final ExpectedException thrown = ExpectedException.none()
|
||||||
|
|
||||||
|
private VersionParser parser = new VersionParser(Collections.EMPTY_LIST)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void noQualifierString() {
|
||||||
|
def version = parser.parse('1.2.0')
|
||||||
|
assertThat(version.toString(), equalTo('1.2.0'))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void withQualifierString() {
|
||||||
|
def version = parser.parse('1.2.0.RELEASE')
|
||||||
|
assertThat(version.toString(), equalTo('1.2.0.RELEASE'))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void withQualifierAndVersionString() {
|
||||||
|
def version = parser.parse('1.2.0.RC2')
|
||||||
|
assertThat(version.toString(), equalTo('1.2.0.RC2'))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parseInvalidVersion() {
|
||||||
|
thrown.expect(InvalidVersionException)
|
||||||
|
parser.parse('foo')
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void safeParseInvalidVersion() {
|
||||||
|
assertNull parser.safeParse('foo')
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parseVersionWithSpaces() {
|
||||||
|
assertThat(parser.parse(' 1.2.0.RC3 '),
|
||||||
|
lessThan(parser.parse('1.3.0.RELEASE')))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parseVariableVersionMatch() {
|
||||||
|
List<Version> currentVersions = Arrays.asList(parser.parse('1.3.8.RELEASE'),
|
||||||
|
parser.parse('1.3.9.BUILD-SNAPSHOT'))
|
||||||
|
parser = new VersionParser(currentVersions)
|
||||||
|
assertThat(parser.parse('1.3.x.BUILD-SNAPSHOT').toString(),
|
||||||
|
equalTo('1.3.9.BUILD-SNAPSHOT'))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parseVariableVersionNoPatchMatch() {
|
||||||
|
List<Version> currentVersions = Arrays.asList(parser.parse('1.3.8.RELEASE'),
|
||||||
|
parser.parse('1.3.9.BUILD-SNAPSHOT'))
|
||||||
|
parser = new VersionParser(currentVersions)
|
||||||
|
assertThat(parser.parse('1.x.x.RELEASE').toString(),
|
||||||
|
equalTo('1.3.8.RELEASE'))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parseVariableVersionNoQualifierMatch() {
|
||||||
|
List<Version> currentVersions = Arrays.asList(parser.parse('1.3.8.RELEASE'),
|
||||||
|
parser.parse('1.4.0.BUILD-SNAPSHOT'))
|
||||||
|
parser = new VersionParser(currentVersions)
|
||||||
|
assertThat(parser.parse('1.4.x').toString(),
|
||||||
|
equalTo('1.4.0.BUILD-SNAPSHOT'))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parseVariableVersionNoMatch() {
|
||||||
|
List<Version> currentVersions = Arrays.asList(parser.parse('1.3.8.RELEASE'),
|
||||||
|
parser.parse('1.3.9.BUILD-SNAPSHOT'))
|
||||||
|
parser = new VersionParser(currentVersions)
|
||||||
|
assertThat(parser.parse('1.4.x.BUILD-SNAPSHOT').toString(),
|
||||||
|
equalTo("1.4.999.BUILD-SNAPSHOT"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parseVariableVersionNoPatchNoMatch() {
|
||||||
|
List<Version> currentVersions = Arrays.asList(parser.parse('1.3.8.RELEASE'),
|
||||||
|
parser.parse('1.3.9.BUILD-SNAPSHOT'))
|
||||||
|
parser = new VersionParser(currentVersions)
|
||||||
|
assertThat(parser.parse('2.x.x.RELEASE').toString(),
|
||||||
|
equalTo("2.999.999.RELEASE"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parseVariableVersionNoQualifierNoMatch() {
|
||||||
|
List<Version> currentVersions = Arrays.asList(parser.parse('1.3.8.RELEASE'),
|
||||||
|
parser.parse('1.4.0.BUILD-SNAPSHOT'))
|
||||||
|
parser = new VersionParser(currentVersions)
|
||||||
|
assertThat(parser.parse('1.2.x').toString(), equalTo("1.2.999"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void invalidRange() {
|
||||||
|
thrown.expect(InvalidVersionException)
|
||||||
|
parser.parseRange("foo-bar")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2015 the original author or authors.
|
* Copyright 2012-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -83,29 +83,54 @@ class VersionRangeTests {
|
|||||||
assertThat('1.1.9.RELEASE', not(match('1.2.0.RELEASE')))
|
assertThat('1.1.9.RELEASE', not(match('1.2.0.RELEASE')))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void invalidRange() {
|
|
||||||
thrown.expect(InvalidVersionException)
|
|
||||||
VersionRange.parse("foo-bar")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void rangeWithSpaces() {
|
void rangeWithSpaces() {
|
||||||
assertThat('1.2.0.RC3', match('[ 1.2.0.RC1 , 1.2.0.RC5]'))
|
assertThat('1.2.0.RC3', match('[ 1.2.0.RC1 , 1.2.0.RC5]'))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void matchLatestVersion() {
|
||||||
|
assertThat('1.2.8.RELEASE', match('[1.2.0.RELEASE,1.2.x.BUILD-SNAPSHOT]',
|
||||||
|
new VersionParser(Arrays.asList(Version.parse('1.2.9.BUILD-SNAPSHOT')))))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void matchOverLatestVersion() {
|
||||||
|
assertThat('1.2.10.RELEASE', not(match('[1.2.0.RELEASE,1.2.x.BUILD-SNAPSHOT]',
|
||||||
|
new VersionParser(Arrays.asList(Version.parse('1.2.9.BUILD-SNAPSHOT'))))))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void matchAsOfCurrentVersion() {
|
||||||
|
assertThat('1.3.5.RELEASE', match('[1.3.x.RELEASE,1.3.x.BUILD-SNAPSHOT]',
|
||||||
|
new VersionParser(Arrays.asList(Version.parse('1.3.4.RELEASE'),
|
||||||
|
Version.parse('1.3.6.BUILD-SNAPSHOT')))))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void matchOverAsOfCurrentVersion() {
|
||||||
|
assertThat('1.3.5.RELEASE', not(match('[1.3.x.RELEASE,1.3.x.BUILD-SNAPSHOT]',
|
||||||
|
new VersionParser(Arrays.asList(Version.parse('1.3.7.RELEASE'),
|
||||||
|
Version.parse('1.3.6.BUILD-SNAPSHOT'))))))
|
||||||
|
}
|
||||||
|
|
||||||
private static VersionRangeMatcher match(String range) {
|
private static VersionRangeMatcher match(String range) {
|
||||||
new VersionRangeMatcher(range)
|
new VersionRangeMatcher(range, new VersionParser(Collections.EMPTY_LIST))
|
||||||
|
}
|
||||||
|
|
||||||
|
private static VersionRangeMatcher match(String range, VersionParser parser) {
|
||||||
|
new VersionRangeMatcher(range, parser)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static class VersionRangeMatcher extends BaseMatcher<String> {
|
static class VersionRangeMatcher extends BaseMatcher<String> {
|
||||||
|
|
||||||
private final VersionRange range;
|
private final VersionRange range;
|
||||||
|
private final VersionParser parser;
|
||||||
|
|
||||||
VersionRangeMatcher(String text) {
|
VersionRangeMatcher(String text, VersionParser parser) {
|
||||||
this.range = VersionRange.parse(text)
|
this.parser = parser
|
||||||
|
this.range = parser.parseRange(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -113,12 +138,13 @@ class VersionRangeTests {
|
|||||||
if (!item instanceof String) {
|
if (!item instanceof String) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.range.match(Version.parse(item))
|
return this.range.match(this.parser.parse((String) item))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void describeTo(Description description) {
|
void describeTo(Description description) {
|
||||||
description.appendText(range)
|
description.appendText(range.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2015 the original author or authors.
|
* Copyright 2012-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -16,41 +16,20 @@
|
|||||||
|
|
||||||
package io.spring.initializr.util
|
package io.spring.initializr.util
|
||||||
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.rules.ExpectedException
|
|
||||||
|
|
||||||
import static io.spring.initializr.util.Version.parse
|
|
||||||
import static io.spring.initializr.util.Version.safeParse
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat
|
import static org.hamcrest.MatcherAssert.assertThat
|
||||||
import static org.hamcrest.Matchers.*
|
import static org.hamcrest.Matchers.comparesEqualTo
|
||||||
import static org.junit.Assert.assertNull
|
import static org.hamcrest.Matchers.equalTo
|
||||||
|
import static org.hamcrest.Matchers.greaterThan
|
||||||
|
import static org.hamcrest.Matchers.lessThan
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
*/
|
*/
|
||||||
class VersionTests {
|
class VersionTests {
|
||||||
|
|
||||||
@Rule
|
private static final VersionParser parser = new VersionParser(Collections.EMPTY_LIST)
|
||||||
public final ExpectedException thrown = ExpectedException.none()
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void noQualifierString() {
|
|
||||||
def version = parse('1.2.0')
|
|
||||||
assertThat(version.toString(), equalTo('1.2.0'))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void withQualifierString() {
|
|
||||||
def version = parse('1.2.0.RELEASE')
|
|
||||||
assertThat(version.toString(), equalTo('1.2.0.RELEASE'))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void withQualifierAndVersionString() {
|
|
||||||
def version = parse('1.2.0.RC2')
|
|
||||||
assertThat(version.toString(), equalTo('1.2.0.RC2'))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void equalNoQualifier() {
|
void equalNoQualifier() {
|
||||||
@ -146,20 +125,9 @@ class VersionTests {
|
|||||||
assertThat(parse('1.2.0.BUILD-SNAPSHOT'), lessThan(parse('1.2.0.RELEASE')))
|
assertThat(parse('1.2.0.BUILD-SNAPSHOT'), lessThan(parse('1.2.0.RELEASE')))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private static Version parse(String text) {
|
||||||
void parseInvalidVersion() {
|
def version = parser.parse(text)
|
||||||
thrown.expect(InvalidVersionException)
|
version
|
||||||
parse('foo')
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void safeParseInvalidVersion() {
|
|
||||||
assertNull safeParse('foo')
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void parseVersionWithSpaces() {
|
|
||||||
assertThat(parse(' 1.2.0.RC3 '), lessThan(parse('1.3.0.RELEASE')))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,7 @@ class DefaultInitializrMetadataProvider implements InitializrMetadataProvider {
|
|||||||
if (!bootVersions.find { it.default }) { // No default specified
|
if (!bootVersions.find { it.default }) { // No default specified
|
||||||
bootVersions[0].default = true
|
bootVersions[0].default = true
|
||||||
}
|
}
|
||||||
metadata.bootVersions.content.clear()
|
metadata.updateSpringBootVersions(bootVersions)
|
||||||
metadata.bootVersions.content.addAll(bootVersions)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ import groovy.json.JsonBuilder
|
|||||||
import io.spring.initializr.metadata.Dependency
|
import io.spring.initializr.metadata.Dependency
|
||||||
import io.spring.initializr.metadata.InitializrMetadataProvider
|
import io.spring.initializr.metadata.InitializrMetadataProvider
|
||||||
import io.spring.initializr.util.Version
|
import io.spring.initializr.util.Version
|
||||||
import io.spring.initializr.util.VersionRange
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
@ -52,7 +51,7 @@ class UiController {
|
|||||||
dependencyGroups.each { g ->
|
dependencyGroups.each { g ->
|
||||||
g.content.each { d ->
|
g.content.each { d ->
|
||||||
if (v && d.versionRange) {
|
if (v && d.versionRange) {
|
||||||
if (VersionRange.parse(d.versionRange).match(v)) {
|
if (d.match(v)) {
|
||||||
content << new DependencyItem(g.name, d)
|
content << new DependencyItem(g.name, d)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user