mirror of
https://gitee.com/dcren/initializr.git
synced 2025-12-26 22:25:51 +08:00
Support version format
This commit clarifies that Version now handles two different formats, the original one (flagged V1) and a SemVer compliant format (flagged V2). Both Version and VersionRange can switch from one format to the other to produce backward compatible content. See gh-1092
This commit is contained in:
@@ -23,19 +23,25 @@ import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Define the version number of a module. A typical version is represented as
|
||||
* {@code MAJOR.MINOR.PATCH.QUALIFIER} where the qualifier can have an extra version.
|
||||
* Define a version. A typical version is represented as
|
||||
* {@code MAJOR.MINOR.PATCH[QUALIFIER]} where the qualifier is optional and can have an
|
||||
* extra version.
|
||||
* <p>
|
||||
* For example: {@code 1.2.0.RC1} is the first release candidate of 1.2.0 and
|
||||
* {@code 1.5.0.M4} is the fourth milestone of 1.5.0. The special {@code RELEASE}
|
||||
* qualifier indicates a final release (a.k.a. GA)
|
||||
* {@code 1.5.0-M4} is the fourth milestone of 1.5.0. The special {@code RELEASE}
|
||||
* qualifier indicates a final release (a.k.a. GA).
|
||||
* <p>
|
||||
* The main purpose of parsing a version is to compare it with another version, see
|
||||
* {@link Comparable}.
|
||||
* Two formats are currently supported, {@link Format#V1} that uses a dot to separate the
|
||||
* qualifier from the version itself and {@link Format#V2} that is SemVer compliant (and
|
||||
* therefore uses a dash to separate the qualifier).
|
||||
* <p>
|
||||
* The main purpose of parsing a version is to compare it with another version.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@@ -54,11 +60,68 @@ public final class Version implements Serializable, Comparable<Version> {
|
||||
|
||||
private final Qualifier qualifier;
|
||||
|
||||
private final Format format;
|
||||
|
||||
public Version(Integer major, Integer minor, Integer patch, Qualifier qualifier) {
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
this.patch = patch;
|
||||
this.qualifier = qualifier;
|
||||
this.format = determineFormat(qualifier);
|
||||
}
|
||||
|
||||
private static Format determineFormat(Qualifier qualifier) {
|
||||
if (qualifier == null) {
|
||||
return Format.V2;
|
||||
}
|
||||
return (qualifier.getSeparator().equals(".")) ? Format.V1 : Format.V2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format this version to the specified {@link Format}.
|
||||
* @param format the format to use
|
||||
* @return a version compliant with the specified format.
|
||||
*/
|
||||
public Version format(Format format) {
|
||||
Assert.notNull(format, () -> "Format must not be null");
|
||||
if (this.format == format) {
|
||||
return this;
|
||||
}
|
||||
if (format == Format.V1) {
|
||||
Qualifier qualifier = formatQualifier(".", this::toV1Qualifier);
|
||||
return new Version(this.major, this.minor, this.patch, qualifier);
|
||||
}
|
||||
Qualifier qualifier = formatQualifier("-", this::toV2Qualifier);
|
||||
return new Version(this.major, this.minor, this.patch, qualifier);
|
||||
}
|
||||
|
||||
private Qualifier formatQualifier(String newSeparator, Function<String, String> idTransformer) {
|
||||
String originalQualifier = (this.qualifier != null) ? this.qualifier.getId() : null;
|
||||
String newId = idTransformer.apply(originalQualifier);
|
||||
if (newId != null) {
|
||||
return new Qualifier(newId, (this.qualifier != null) ? this.qualifier.getVersion() : null, newSeparator);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String toV1Qualifier(String id) {
|
||||
if ("SNAPSHOT".equals(id)) {
|
||||
return "BUILD-SNAPSHOT";
|
||||
}
|
||||
if (id == null) {
|
||||
return "RELEASE";
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
private String toV2Qualifier(String id) {
|
||||
if ("BUILD-SNAPSHOT".equals(id)) {
|
||||
return "SNAPSHOT";
|
||||
}
|
||||
if ("RELEASE".equals(id)) {
|
||||
return null;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public Integer getMajor() {
|
||||
@@ -77,6 +140,10 @@ public final class Version implements Serializable, Comparable<Version> {
|
||||
return this.qualifier;
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return this.format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the string representation of a {@link Version}. Throws an
|
||||
* {@link InvalidVersionException} if the version could not be parsed.
|
||||
@@ -262,6 +329,26 @@ public final class Version implements Serializable, Comparable<Version> {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the supported version format.
|
||||
*/
|
||||
public enum Format {
|
||||
|
||||
/**
|
||||
* Original version format, i.e. {@code Major.Minor.Patch.Qualifier} using
|
||||
* {@code BUILD-SNAPSHOT} as the qualifier for snapshots and {@code RELEASE} for
|
||||
* GAs.
|
||||
*/
|
||||
V1,
|
||||
|
||||
/**
|
||||
* SemVer-compliant format, i.e. {@code Major.Minor.Patch-Qualifier} using
|
||||
* {@code SNAPSHOT} as the qualifier for snapshots and no qualifier for GAs.
|
||||
*/
|
||||
V2;
|
||||
|
||||
}
|
||||
|
||||
private static class VersionQualifierComparator implements Comparator<Qualifier> {
|
||||
|
||||
static final String RELEASE = "RELEASE";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 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.generator.version;
|
||||
|
||||
import io.spring.initializr.generator.version.Version.Format;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -27,9 +29,8 @@ import org.springframework.util.Assert;
|
||||
* <ul>
|
||||
* <li>"[1.2.0.RELEASE,1.3.0.RELEASE)" version 1.2.0 and any version after this, up to,
|
||||
* but not including, version 1.3.0.</li>
|
||||
* <li>"(2.0.0.RELEASE,3.2.0.RELEASE]" any version after 2.0.0 up to and including version
|
||||
* 3.2.0.</li>
|
||||
* <li>"1.4.5.RELEASE", version 1.4.5 and all later versions.</li>
|
||||
* <li>"(2.0.0,3.2.0]" any version after 2.0.0 up to and including version 3.2.0.</li>
|
||||
* <li>"2.5.0-M1", the first milestone of 2.5.0 and any version after that.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
@@ -83,6 +84,17 @@ public class VersionRange {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format this version range to the specified {@link Format}.
|
||||
* @param format the version format to use
|
||||
* @return a version range whose boundaries are compliant with the specified format.
|
||||
*/
|
||||
public VersionRange format(Format format) {
|
||||
Version lower = this.lowerVersion.format(format);
|
||||
Version higher = (this.higherVersion != null) ? this.higherVersion.format(format) : null;
|
||||
return new VersionRange(lower, this.lowerInclusive, higher, this.higherInclusive);
|
||||
}
|
||||
|
||||
public Version getLowerVersion() {
|
||||
return this.lowerVersion;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
@@ -19,12 +19,15 @@ package io.spring.initializr.generator.version;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import io.spring.initializr.generator.version.Version.Format;
|
||||
import org.assertj.core.api.Condition;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link VersionRange}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class VersionRangeTests {
|
||||
@@ -148,6 +151,34 @@ class VersionRangeTests {
|
||||
assertThat(range.toRangeString()).isEqualTo("(1.3.5.RELEASE,1.5.5.RELEASE)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void formatLowerOnlyV1toV2() {
|
||||
VersionRange range = parse("1.2.0.RELEASE").format(Format.V2);
|
||||
assertThat(range.toRangeString()).isEqualTo("1.2.0");
|
||||
}
|
||||
|
||||
@Test
|
||||
void formatV1toV2() {
|
||||
VersionRange range = parse("[1.2.0.RELEASE,1.3.0.M1)").format(Format.V2);
|
||||
assertThat(range.toRangeString()).isEqualTo("[1.2.0,1.3.0-M1)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void formatLowerOnlyV2toV1() {
|
||||
VersionRange range = parse("1.2.0").format(Format.V1);
|
||||
assertThat(range.toRangeString()).isEqualTo("1.2.0.RELEASE");
|
||||
}
|
||||
|
||||
@Test
|
||||
void formatV2toV1() {
|
||||
VersionRange range = parse("[1.2.0,1.3.0-M1)").format(Format.V1);
|
||||
assertThat(range.toRangeString()).isEqualTo("[1.2.0.RELEASE,1.3.0.M1)");
|
||||
}
|
||||
|
||||
private static VersionRange parse(String text) {
|
||||
return new VersionParser(Collections.emptyList()).parseRange(text);
|
||||
}
|
||||
|
||||
private static Condition<String> match(String range) {
|
||||
return match(range, new VersionParser(Collections.emptyList()));
|
||||
}
|
||||
|
||||
@@ -21,11 +21,14 @@ import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import io.spring.initializr.generator.version.Version.Format;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link Version}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class VersionTests {
|
||||
@@ -153,6 +156,54 @@ class VersionTests {
|
||||
"2020.0.0-SNAPSHOT", "2020.0.0");
|
||||
}
|
||||
|
||||
@Test
|
||||
void formatV1toV1() {
|
||||
Version version = Version.parse("1.2.0.RELEASE");
|
||||
assertThat(version.format(Format.V1)).isSameAs(version);
|
||||
}
|
||||
|
||||
@Test
|
||||
void formatV1SnapshotToV2() {
|
||||
Version version = Version.parse("1.2.0.BUILD-SNAPSHOT");
|
||||
assertThat(version.format(Format.V2)).hasToString("1.2.0-SNAPSHOT");
|
||||
}
|
||||
|
||||
@Test
|
||||
void formatV1GAToV2() {
|
||||
Version version = Version.parse("1.2.0.RELEASE");
|
||||
assertThat(version.format(Format.V2)).hasToString("1.2.0");
|
||||
}
|
||||
|
||||
@Test
|
||||
void formatNoQualifierToV1() {
|
||||
Version version = Version.parse("1.2.0");
|
||||
assertThat(version.format(Format.V1)).hasToString("1.2.0.RELEASE");
|
||||
}
|
||||
|
||||
@Test
|
||||
void formatV2toV2() {
|
||||
Version version = Version.parse("1.2.0-RC1");
|
||||
assertThat(version.format(Format.V2)).isSameAs(version);
|
||||
}
|
||||
|
||||
@Test
|
||||
void formatV2SnapshotToV1() {
|
||||
Version version = Version.parse("1.2.0-SNAPSHOT");
|
||||
assertThat(version.format(Format.V1)).hasToString("1.2.0.BUILD-SNAPSHOT");
|
||||
}
|
||||
|
||||
@Test
|
||||
void formatV2GAToV1() {
|
||||
Version version = Version.parse("1.2.0");
|
||||
assertThat(version.format(Format.V1)).hasToString("1.2.0.RELEASE");
|
||||
}
|
||||
|
||||
@Test
|
||||
void formatNoQualifierToV2() {
|
||||
Version version = Version.parse("1.2.0");
|
||||
assertThat(version.format(Format.V2)).hasToString("1.2.0");
|
||||
}
|
||||
|
||||
private Version parse(String text) {
|
||||
return this.parser.parse(text);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user