From 827b9d6e93a80fcb57262c593b10cbef248ebebf Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 6 Dec 2016 16:39:23 +0100 Subject: [PATCH] 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 --- ...rActuatorEndpointsAutoConfiguration.groovy | 40 +++++ .../info/BomRangesInfoContributor.groovy | 56 +++++++ .../main/resources/META-INF/spring.factories | 1 + .../info/BomRangesInfoContributorTests.groovy | 82 ++++++++++ .../generator/CommandLineHelpGenerator.groovy | 15 +- .../generator/ProjectRequest.groovy | 9 +- .../metadata/BillOfMaterials.groovy | 11 +- .../metadata/DependenciesCapability.groovy | 10 +- .../initializr/metadata/Dependency.groovy | 17 ++- .../metadata/InitializrMetadata.groovy | 19 +++ .../io/spring/initializr/util/Version.groovy | 50 +++--- .../initializr/util/VersionParser.groovy | 143 ++++++++++++++++++ .../initializr/util/VersionRange.groovy | 31 +--- .../CommandLineHelpGeneratorTests.groovy | 10 +- .../metadata/BillOfMaterialsTests.groovy | 22 +++ .../metadata/DependencyTests.groovy | 32 ++++ .../metadata/InitializrMetadataTests.groovy | 31 ++++ .../initializr/util/VersionParserTests.groovy | 134 ++++++++++++++++ .../initializr/util/VersionRangeTests.groovy | 52 +++++-- .../initializr/util/VersionTests.groovy | 50 ++---- .../DefaultInitializrMetadataProvider.groovy | 3 +- .../initializr/web/ui/UiController.groovy | 3 +- 22 files changed, 673 insertions(+), 148 deletions(-) create mode 100644 initializr-actuator/src/main/groovy/io/spring/initializr/actuate/autoconfigure/InitializrActuatorEndpointsAutoConfiguration.groovy create mode 100644 initializr-actuator/src/main/groovy/io/spring/initializr/actuate/info/BomRangesInfoContributor.groovy create mode 100644 initializr-actuator/src/test/groovy/io/spring/initializr/actuate/info/BomRangesInfoContributorTests.groovy create mode 100644 initializr-generator/src/main/groovy/io/spring/initializr/util/VersionParser.groovy create mode 100644 initializr-generator/src/test/groovy/io/spring/initializr/util/VersionParserTests.groovy diff --git a/initializr-actuator/src/main/groovy/io/spring/initializr/actuate/autoconfigure/InitializrActuatorEndpointsAutoConfiguration.groovy b/initializr-actuator/src/main/groovy/io/spring/initializr/actuate/autoconfigure/InitializrActuatorEndpointsAutoConfiguration.groovy new file mode 100644 index 00000000..6b47862a --- /dev/null +++ b/initializr-actuator/src/main/groovy/io/spring/initializr/actuate/autoconfigure/InitializrActuatorEndpointsAutoConfiguration.groovy @@ -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) + } + +} diff --git a/initializr-actuator/src/main/groovy/io/spring/initializr/actuate/info/BomRangesInfoContributor.groovy b/initializr-actuator/src/main/groovy/io/spring/initializr/actuate/info/BomRangesInfoContributor.groovy new file mode 100644 index 00000000..9e6b20b3 --- /dev/null +++ b/initializr-actuator/src/main/groovy/io/spring/initializr/actuate/info/BomRangesInfoContributor.groovy @@ -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) + } + } + +} diff --git a/initializr-actuator/src/main/resources/META-INF/spring.factories b/initializr-actuator/src/main/resources/META-INF/spring.factories index 870aa803..96abd3fc 100644 --- a/initializr-actuator/src/main/resources/META-INF/spring.factories +++ b/initializr-actuator/src/main/resources/META-INF/spring.factories @@ -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 \ No newline at end of file diff --git a/initializr-actuator/src/test/groovy/io/spring/initializr/actuate/info/BomRangesInfoContributorTests.groovy b/initializr-actuator/src/test/groovy/io/spring/initializr/actuate/info/BomRangesInfoContributorTests.groovy new file mode 100644 index 00000000..83300191 --- /dev/null +++ b/initializr-actuator/src/test/groovy/io/spring/initializr/actuate/info/BomRangesInfoContributorTests.groovy @@ -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 ranges = info.details['bom-ranges'] as Map + assertThat(ranges).containsOnlyKeys('foo') + Map foo = ranges['foo'] as Map + 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() + } + +} diff --git a/initializr-generator/src/main/groovy/io/spring/initializr/generator/CommandLineHelpGenerator.groovy b/initializr-generator/src/main/groovy/io/spring/initializr/generator/CommandLineHelpGenerator.groovy index 8f211f0f..21208f82 100644 --- a/initializr-generator/src/main/groovy/io/spring/initializr/generator/CommandLineHelpGenerator.groovy +++ b/initializr-generator/src/main/groovy/io/spring/initializr/generator/CommandLineHelpGenerator.groovy @@ -19,7 +19,6 @@ package io.spring.initializr.generator import io.spring.initializr.metadata.InitializrMetadata import io.spring.initializr.metadata.Type import io.spring.initializr.util.GroovyTemplate -import io.spring.initializr.util.VersionRange /** * Generate help pages for command-line clients. @@ -144,7 +143,7 @@ class CommandLineHelpGenerator { String[] data = new String[3] data[0] = dep.id data[1] = dep.description ?: dep.name - data[2] = buildVersionRangeRepresentation(dep.versionRange) + data[2] = dep.versionRequirement dependencyTable[i + 1] = data } TableGenerator.generate(dependencyTable) @@ -182,18 +181,6 @@ class CommandLineHelpGenerator { 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) { if (type.tags.isEmpty()) { return ""; diff --git a/initializr-generator/src/main/groovy/io/spring/initializr/generator/ProjectRequest.groovy b/initializr-generator/src/main/groovy/io/spring/initializr/generator/ProjectRequest.groovy index 9127cfcc..9e2fd0bb 100644 --- a/initializr-generator/src/main/groovy/io/spring/initializr/generator/ProjectRequest.groovy +++ b/initializr-generator/src/main/groovy/io/spring/initializr/generator/ProjectRequest.groovy @@ -93,12 +93,9 @@ class ProjectRequest extends BasicProjectRequest { facets.add(it) } } - if (it.versionRange) { - def range = VersionRange.parse(it.versionRange) - if (!range.match(requestedVersion)) { - throw new InvalidProjectRequestException("Dependency '$it.id' is not compatible " + - "with Spring Boot $bootVersion") - } + if (!it.match(requestedVersion)) { + throw new InvalidProjectRequestException("Dependency '$it.id' is not compatible " + + "with Spring Boot $requestedVersion") } if (it.bom) { resolveBom(metadata, it.bom, requestedVersion) 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 8e31de66..da7f50ed 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 @@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonInclude import groovy.transform.ToString import io.spring.initializr.util.InvalidVersionException import io.spring.initializr.util.Version +import io.spring.initializr.util.VersionParser import io.spring.initializr.util.VersionRange /** @@ -75,9 +76,13 @@ class BillOfMaterials { if (!version && !mappings) { throw new InvalidInitializrMetadataException("No version available for $this"); } + updateVersionRange(VersionParser.DEFAULT) + } + + void updateVersionRange(VersionParser versionParser) { mappings.each { try { - it.range = VersionRange.parse(it.versionRange) + it.range = versionParser.parseRange(it.versionRange) } catch (InvalidVersionException ex) { throw new InvalidInitializrMetadataException("Invalid version range $it.versionRange for $this", ex) } @@ -119,6 +124,10 @@ class BillOfMaterials { private VersionRange range + String determineVersionRangeRequirement() { + range.toString() + } + } } diff --git a/initializr-generator/src/main/groovy/io/spring/initializr/metadata/DependenciesCapability.groovy b/initializr-generator/src/main/groovy/io/spring/initializr/metadata/DependenciesCapability.groovy index b7feacf2..55d29a6b 100644 --- a/initializr-generator/src/main/groovy/io/spring/initializr/metadata/DependenciesCapability.groovy +++ b/initializr-generator/src/main/groovy/io/spring/initializr/metadata/DependenciesCapability.groovy @@ -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"); * you may not use this file except in compliance with the License. @@ -16,6 +16,8 @@ package io.spring.initializr.metadata +import io.spring.initializr.util.VersionParser + /** * A {@link ServiceCapability} listing the available dependencies defined as a * {@link ServiceCapabilityType#HIERARCHICAL_MULTI_SELECT} capability. @@ -53,6 +55,12 @@ class DependenciesCapability extends ServiceCapability> { index() } + void updateVersionRange(VersionParser versionParser) { + indexedDependencies.values().each { + it.updateVersionRanges(versionParser) + } + } + @Override void merge(List otherContent) { otherContent.each { group -> diff --git a/initializr-generator/src/main/groovy/io/spring/initializr/metadata/Dependency.groovy b/initializr-generator/src/main/groovy/io/spring/initializr/metadata/Dependency.groovy index d7e88ce9..d661f531 100644 --- a/initializr-generator/src/main/groovy/io/spring/initializr/metadata/Dependency.groovy +++ b/initializr-generator/src/main/groovy/io/spring/initializr/metadata/Dependency.groovy @@ -23,6 +23,7 @@ import groovy.transform.AutoCloneStyle import groovy.transform.ToString import io.spring.initializr.util.InvalidVersionException import io.spring.initializr.util.Version +import io.spring.initializr.util.VersionParser import io.spring.initializr.util.VersionRange /** @@ -84,6 +85,8 @@ class Dependency extends MetadataElement { @JsonIgnore String versionRequirement + + private VersionRange range String bom @@ -159,18 +162,22 @@ class Dependency extends MetadataElement { "Invalid dependency, id should have the form groupId:artifactId[:version] but got $id") } } + updateVersionRanges(VersionParser.DEFAULT) + } + + def updateVersionRanges(VersionParser versionParser) { if (versionRange) { try { - def range = VersionRange.parse(versionRange) + range = versionParser.parseRange(versionRange) versionRequirement = range.toString() } catch (InvalidVersionException ex) { throw new InvalidInitializrMetadataException("Invalid version range '$versionRange' for " + - "dependency with id '$id'") + "dependency with id '$id'", ex) } } mappings.each { try { - it.range = VersionRange.parse(it.versionRange) + it.range = versionParser.parseRange(it.versionRange) } catch (InvalidVersionException 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. */ boolean match(Version version) { - if (versionRange) { - return VersionRange.parse(versionRange).match(version) + if (range) { + return range.match(version) } true } 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 44ef4ab4..37eb1bac 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 @@ -16,6 +16,9 @@ package io.spring.initializr.metadata +import io.spring.initializr.util.Version +import io.spring.initializr.util.VersionParser + /** * 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 versionsMetadata) { + bootVersions.content.clear() + bootVersions.content.addAll(versionsMetadata) + List bootVersions = bootVersions.content.collect { + Version.parse(it.id) + } + VersionParser parser = new VersionParser(bootVersions) + dependencies.updateVersionRange(parser) + configuration.env.boms.values().each { + it.updateVersionRange(parser) + } } /** diff --git a/initializr-generator/src/main/groovy/io/spring/initializr/util/Version.groovy b/initializr-generator/src/main/groovy/io/spring/initializr/util/Version.groovy index 48333aa1..5496d9b6 100644 --- a/initializr-generator/src/main/groovy/io/spring/initializr/util/Version.groovy +++ b/initializr-generator/src/main/groovy/io/spring/initializr/util/Version.groovy @@ -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"); * you may not use this file except in compliance with the License. @@ -44,13 +44,22 @@ final class Version implements Serializable, Comparable { private static final VersionQualifierComparator qualifierComparator = new VersionQualifierComparator() - Integer major - Integer minor - Integer patch - Qualifier qualifier - + private static final VersionParser parser = new VersionParser(Collections.EMPTY_LIST) + + final Integer major + 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 - public String toString() { + String toString() { "${major}.${minor}.${patch}" + (qualifier?".${qualifier.qualifier}${qualifier.version?:''}" : '') } @@ -60,29 +69,10 @@ final class Version implements Serializable, Comparable { * @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) + * @see {@link VersionParser} */ static 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 (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 + return parser.parse(text) } /** @@ -91,7 +81,7 @@ final class Version implements Serializable, Comparable { * 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) + * @see {@link VersionParser} */ static safeParse(String text) { try { @@ -129,7 +119,7 @@ final class Version implements Serializable, Comparable { @ToString @EqualsAndHashCode - public static class Qualifier { + static class Qualifier { String qualifier Integer version } diff --git a/initializr-generator/src/main/groovy/io/spring/initializr/util/VersionParser.groovy b/initializr-generator/src/main/groovy/io/spring/initializr/util/VersionParser.groovy new file mode 100644 index 00000000..a9cae65a --- /dev/null +++ b/initializr-generator/src/main/groovy/io/spring/initializr/util/VersionParser.groovy @@ -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". + *

+ * 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 latestVersions; + + VersionParser(List 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}. + *

+ * 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) + } + +} diff --git a/initializr-generator/src/main/groovy/io/spring/initializr/util/VersionRange.groovy b/initializr-generator/src/main/groovy/io/spring/initializr/util/VersionRange.groovy index 472f830d..23f2c447 100644 --- a/initializr-generator/src/main/groovy/io/spring/initializr/util/VersionRange.groovy +++ b/initializr-generator/src/main/groovy/io/spring/initializr/util/VersionRange.groovy @@ -17,7 +17,6 @@ package io.spring.initializr.util import groovy.transform.EqualsAndHashCode -import groovy.transform.ToString import org.springframework.util.Assert @@ -41,15 +40,13 @@ import org.springframework.util.Assert @EqualsAndHashCode class VersionRange { - private static final String RANGE_REGEX = "(\\(|\\[)(.*),(.*)(\\)|\\])" - final Version lowerVersion final boolean lowerInclusive final Version higherVersion final boolean higherInclusive - private VersionRange(Version lowerVersion, boolean lowerInclusive, - Version higherVersion, boolean higherInclusive) { + protected VersionRange(Version lowerVersion, boolean lowerInclusive, + Version higherVersion, boolean higherInclusive) { this.lowerVersion = lowerVersion this.lowerInclusive = lowerInclusive this.higherVersion = higherVersion @@ -86,31 +83,9 @@ class VersionRange { sb.append("${lowerInclusive ? '>=' : '>'}${lowerVersion}") } if (higherVersion) { - sb.append(" and ${higherInclusive ? '<=' : '<'}${higherVersion}") + sb.append(" and ${higherInclusive ? '<=' : '<'}${higherVersion}") } 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) - } - } diff --git a/initializr-generator/src/test/groovy/io/spring/initializr/generator/CommandLineHelpGeneratorTests.groovy b/initializr-generator/src/test/groovy/io/spring/initializr/generator/CommandLineHelpGeneratorTests.groovy index e0398995..d32bf43b 100644 --- a/initializr-generator/src/test/groovy/io/spring/initializr/generator/CommandLineHelpGeneratorTests.groovy +++ b/initializr-generator/src/test/groovy/io/spring/initializr/generator/CommandLineHelpGeneratorTests.groovy @@ -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 metadata = InitializrMetadataTestBuilder.withDefaults().addDependencyGroup("test", first, second).build() String content = generator.generateSpringBootCliCapabilities(metadata, "https://fake-service") - 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('| first | first desc | >=1.2.0.RELEASE |') + 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("| dependencies") assertThat content, containsString("| applicationName") @@ -124,11 +124,11 @@ class CommandLineHelpGeneratorTests { assertThat content, not(containsString('| Tags')) } - private static def createDependency(String id, String name) { + private static createDependency(String id, String name) { 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) } diff --git a/initializr-generator/src/test/groovy/io/spring/initializr/metadata/BillOfMaterialsTests.groovy b/initializr-generator/src/test/groovy/io/spring/initializr/metadata/BillOfMaterialsTests.groovy index c4fa7887..b8b025fc 100644 --- a/initializr-generator/src/test/groovy/io/spring/initializr/metadata/BillOfMaterialsTests.groovy +++ b/initializr-generator/src/test/groovy/io/spring/initializr/metadata/BillOfMaterialsTests.groovy @@ -17,6 +17,7 @@ package io.spring.initializr.metadata import io.spring.initializr.util.Version +import io.spring.initializr.util.VersionParser import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException @@ -108,4 +109,25 @@ class BillOfMaterialsTests { 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')) + } + } diff --git a/initializr-generator/src/test/groovy/io/spring/initializr/metadata/DependencyTests.groovy b/initializr-generator/src/test/groovy/io/spring/initializr/metadata/DependencyTests.groovy index ae66bd45..fc794c34 100644 --- a/initializr-generator/src/test/groovy/io/spring/initializr/metadata/DependencyTests.groovy +++ b/initializr-generator/src/test/groovy/io/spring/initializr/metadata/DependencyTests.groovy @@ -17,6 +17,7 @@ package io.spring.initializr.metadata import io.spring.initializr.util.Version +import io.spring.initializr.util.VersionParser import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException @@ -201,6 +202,37 @@ class DependencyTests { '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( def dependency, def expectedGroupId, def expectedArtifactId, def expectedVersion) { assertEquals expectedVersion, dependency.version diff --git a/initializr-generator/src/test/groovy/io/spring/initializr/metadata/InitializrMetadataTests.groovy b/initializr-generator/src/test/groovy/io/spring/initializr/metadata/InitializrMetadataTests.groovy index 7ad6e10c..ed585bf7 100644 --- a/initializr-generator/src/test/groovy/io/spring/initializr/metadata/InitializrMetadataTests.groovy +++ b/initializr-generator/src/test/groovy/io/spring/initializr/metadata/InitializrMetadataTests.groovy @@ -17,10 +17,13 @@ package io.spring.initializr.metadata import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder +import io.spring.initializr.util.Version import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException +import static org.assertj.core.api.Assertions.assertThat + /** * @author Stephane Nicoll */ @@ -146,6 +149,34 @@ class InitializrMetadataTests { 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 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 void invalidParentMissingVersion() { InitializrMetadataTestBuilder builder = InitializrMetadataTestBuilder diff --git a/initializr-generator/src/test/groovy/io/spring/initializr/util/VersionParserTests.groovy b/initializr-generator/src/test/groovy/io/spring/initializr/util/VersionParserTests.groovy new file mode 100644 index 00000000..11812cf9 --- /dev/null +++ b/initializr-generator/src/test/groovy/io/spring/initializr/util/VersionParserTests.groovy @@ -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 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 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 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 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 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 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") + } + +} diff --git a/initializr-generator/src/test/groovy/io/spring/initializr/util/VersionRangeTests.groovy b/initializr-generator/src/test/groovy/io/spring/initializr/util/VersionRangeTests.groovy index 6e37b6ca..5548a8ff 100644 --- a/initializr-generator/src/test/groovy/io/spring/initializr/util/VersionRangeTests.groovy +++ b/initializr-generator/src/test/groovy/io/spring/initializr/util/VersionRangeTests.groovy @@ -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"); * 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'))) } - @Test - void invalidRange() { - thrown.expect(InvalidVersionException) - VersionRange.parse("foo-bar") - } - @Test void rangeWithSpaces() { 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) { - 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 { private final VersionRange range; + private final VersionParser parser; - VersionRangeMatcher(String text) { - this.range = VersionRange.parse(text) + VersionRangeMatcher(String text, VersionParser parser) { + this.parser = parser + this.range = parser.parseRange(text) } @Override @@ -113,12 +138,13 @@ class VersionRangeTests { if (!item instanceof String) { return false; } - return this.range.match(Version.parse(item)) + return this.range.match(this.parser.parse((String) item)) } @Override void describeTo(Description description) { - description.appendText(range) + description.appendText(range.toString()) } } + } diff --git a/initializr-generator/src/test/groovy/io/spring/initializr/util/VersionTests.groovy b/initializr-generator/src/test/groovy/io/spring/initializr/util/VersionTests.groovy index bd984105..12d730cf 100644 --- a/initializr-generator/src/test/groovy/io/spring/initializr/util/VersionTests.groovy +++ b/initializr-generator/src/test/groovy/io/spring/initializr/util/VersionTests.groovy @@ -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"); * you may not use this file except in compliance with the License. @@ -16,41 +16,20 @@ package io.spring.initializr.util -import org.junit.Rule 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.Matchers.* -import static org.junit.Assert.assertNull +import static org.hamcrest.Matchers.comparesEqualTo +import static org.hamcrest.Matchers.equalTo +import static org.hamcrest.Matchers.greaterThan +import static org.hamcrest.Matchers.lessThan /** * @author Stephane Nicoll */ class VersionTests { - @Rule - 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')) - } + private static final VersionParser parser = new VersionParser(Collections.EMPTY_LIST) @Test void equalNoQualifier() { @@ -146,20 +125,9 @@ class VersionTests { assertThat(parse('1.2.0.BUILD-SNAPSHOT'), lessThan(parse('1.2.0.RELEASE'))) } - @Test - void parseInvalidVersion() { - thrown.expect(InvalidVersionException) - parse('foo') - } - - @Test - void safeParseInvalidVersion() { - assertNull safeParse('foo') - } - - @Test - void parseVersionWithSpaces() { - assertThat(parse(' 1.2.0.RC3 '), lessThan(parse('1.3.0.RELEASE'))) + private static Version parse(String text) { + def version = parser.parse(text) + version } } diff --git a/initializr-web/src/main/groovy/io/spring/initializr/web/support/DefaultInitializrMetadataProvider.groovy b/initializr-web/src/main/groovy/io/spring/initializr/web/support/DefaultInitializrMetadataProvider.groovy index bfbc22c9..6eed5ebe 100644 --- a/initializr-web/src/main/groovy/io/spring/initializr/web/support/DefaultInitializrMetadataProvider.groovy +++ b/initializr-web/src/main/groovy/io/spring/initializr/web/support/DefaultInitializrMetadataProvider.groovy @@ -55,8 +55,7 @@ class DefaultInitializrMetadataProvider implements InitializrMetadataProvider { if (!bootVersions.find { it.default }) { // No default specified bootVersions[0].default = true } - metadata.bootVersions.content.clear() - metadata.bootVersions.content.addAll(bootVersions) + metadata.updateSpringBootVersions(bootVersions) } } diff --git a/initializr-web/src/main/groovy/io/spring/initializr/web/ui/UiController.groovy b/initializr-web/src/main/groovy/io/spring/initializr/web/ui/UiController.groovy index 33349ca2..51e0101a 100644 --- a/initializr-web/src/main/groovy/io/spring/initializr/web/ui/UiController.groovy +++ b/initializr-web/src/main/groovy/io/spring/initializr/web/ui/UiController.groovy @@ -22,7 +22,6 @@ import groovy.json.JsonBuilder import io.spring.initializr.metadata.Dependency import io.spring.initializr.metadata.InitializrMetadataProvider import io.spring.initializr.util.Version -import io.spring.initializr.util.VersionRange import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.MediaType @@ -52,7 +51,7 @@ class UiController { dependencyGroups.each { g -> g.content.each { d -> if (v && d.versionRange) { - if (VersionRange.parse(d.versionRange).match(v)) { + if (d.match(v)) { content << new DependencyItem(g.name, d) } } else {