mirror of https://github.com/halo-dev/halo
Enable beta version comparable (#1011)
* Ensure whitespace after comma * Provide version resolver * Make version comparable * Refactor version util with version resolverpull/1040/head
parent
60b2527003
commit
3bfb60d5fb
|
@ -80,7 +80,7 @@
|
||||||
<!--whitespace-->
|
<!--whitespace-->
|
||||||
<module name="GenericWhitespace"/>
|
<module name="GenericWhitespace"/>
|
||||||
<module name="NoWhitespaceBefore"/>
|
<module name="NoWhitespaceBefore"/>
|
||||||
<module name="NoWhitespaceAfter"/>
|
<module name="WhitespaceAfter"/>
|
||||||
<module name="WhitespaceAround">
|
<module name="WhitespaceAround">
|
||||||
<property name="allowEmptyConstructors" value="true"/>
|
<property name="allowEmptyConstructors" value="true"/>
|
||||||
<property name="allowEmptyMethods" value="true"/>
|
<property name="allowEmptyMethods" value="true"/>
|
||||||
|
|
|
@ -0,0 +1,208 @@
|
||||||
|
package run.halo.app.utils;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
import run.halo.app.model.support.HaloConst;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version domain.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@Slf4j
|
||||||
|
public class Version implements Comparable<Version> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regex expression.
|
||||||
|
*/
|
||||||
|
private static final String REGEX = "^" +
|
||||||
|
"(?<major>0|[1-9]\\d*)\\." + // major number
|
||||||
|
"(?<minor>0|[1-9]\\d*)\\." + // minor number
|
||||||
|
"(?<patch>0|[1-9]\\d*)" + // patch number
|
||||||
|
"(?:-" + // pre-release start
|
||||||
|
"(?<preRelease>beta|alpha|rc)\\." + // pre-release type
|
||||||
|
"(?<preReleaseMajor>0|[1-9]\\d*)" + // pre-release major number
|
||||||
|
")?$"; // pre-release end
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pattern.
|
||||||
|
*/
|
||||||
|
private static final Pattern PATTERN = Pattern.compile(REGEX);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empty version.
|
||||||
|
*/
|
||||||
|
private static final Version EMPTY_VERSION = new Version(0, 0, 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Major number.
|
||||||
|
*/
|
||||||
|
private final long major;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minor number.
|
||||||
|
*/
|
||||||
|
private final long minor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Patch number.
|
||||||
|
*/
|
||||||
|
private final long patch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pre-release.
|
||||||
|
*/
|
||||||
|
private final PreRelease preRelease;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pre-release major number.
|
||||||
|
*/
|
||||||
|
private final long preReleaseMajor;
|
||||||
|
|
||||||
|
public Version() {
|
||||||
|
this(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Version(long major, long minor, long patch) {
|
||||||
|
this(major, minor, patch, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Version(long major, long minor, long patch, @Nullable PreRelease preRelease, @Nullable Long preReleaseMajor) {
|
||||||
|
if (major < 0) {
|
||||||
|
major = 0L;
|
||||||
|
}
|
||||||
|
if (minor < 0L) {
|
||||||
|
minor = 0;
|
||||||
|
}
|
||||||
|
if (patch < 0) {
|
||||||
|
minor = 0L;
|
||||||
|
}
|
||||||
|
this.major = major;
|
||||||
|
this.minor = minor;
|
||||||
|
this.patch = patch;
|
||||||
|
this.preRelease = preRelease;
|
||||||
|
if (preRelease != null) {
|
||||||
|
preReleaseMajor = preReleaseMajor == null ? Integer.MAX_VALUE : preReleaseMajor;
|
||||||
|
if (preReleaseMajor < 0) {
|
||||||
|
preReleaseMajor = 0L;
|
||||||
|
}
|
||||||
|
this.preReleaseMajor = preReleaseMajor;
|
||||||
|
} else {
|
||||||
|
this.preReleaseMajor = Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empty version.
|
||||||
|
*
|
||||||
|
* @return empty version
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static Version emptyVersion() {
|
||||||
|
return EMPTY_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve version.
|
||||||
|
*
|
||||||
|
* @param version version could be blank
|
||||||
|
* @return an optional corresponding version
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static Optional<Version> resolve(@Nullable String version) {
|
||||||
|
if (StringUtils.isBlank(version)) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
// handle unknown version
|
||||||
|
if (StringUtils.equalsIgnoreCase(version, HaloConst.UNKNOWN_VERSION)) {
|
||||||
|
return Optional.of(new Version());
|
||||||
|
}
|
||||||
|
// get matcher for version
|
||||||
|
Matcher matcher = PATTERN.matcher(version);
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
// if mismatches
|
||||||
|
log.warn("Version: [{}] didn't match version format", version);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
// get all groups
|
||||||
|
String major = matcher.group("major");
|
||||||
|
String minor = matcher.group("minor");
|
||||||
|
String patch = matcher.group("patch");
|
||||||
|
String preRelease = matcher.group("preRelease");
|
||||||
|
String preReleaseMajor = matcher.group("preReleaseMajor");
|
||||||
|
// build full version
|
||||||
|
return Optional.of(new Version(Long.parseLong(major),
|
||||||
|
Long.parseLong(minor),
|
||||||
|
Long.parseLong(patch),
|
||||||
|
PreRelease.of(preRelease),
|
||||||
|
StringUtils.isNotBlank(preReleaseMajor) ? Long.parseLong(preReleaseMajor) : null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@NotNull Version anotherVersion) {
|
||||||
|
// compare major
|
||||||
|
int majorCompare = Long.compare(major, anotherVersion.major);
|
||||||
|
if (majorCompare != 0) {
|
||||||
|
return majorCompare;
|
||||||
|
}
|
||||||
|
// compare minor
|
||||||
|
int minorCompare = Long.compare(minor, anotherVersion.minor);
|
||||||
|
if (minorCompare != 0) {
|
||||||
|
return minorCompare;
|
||||||
|
}
|
||||||
|
// compare patch
|
||||||
|
int patchCompare = Long.compare(patch, anotherVersion.patch);
|
||||||
|
if (patchCompare != 0) {
|
||||||
|
return patchCompare;
|
||||||
|
}
|
||||||
|
// if all the major, minor and patch are the same, then compare pre release number
|
||||||
|
return Long.compare(preReleaseMajor, anotherVersion.preReleaseMajor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pre release enum.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
*/
|
||||||
|
public enum PreRelease {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Beta.
|
||||||
|
*/
|
||||||
|
BETA,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alpha.
|
||||||
|
*/
|
||||||
|
ALPHA,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release candidate.
|
||||||
|
*/
|
||||||
|
RC;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
static PreRelease of(@Nullable String preReleaseStr) {
|
||||||
|
PreRelease[] preReleases = PreRelease.values();
|
||||||
|
for (PreRelease preRelease : preReleases) {
|
||||||
|
if (preRelease.name().equalsIgnoreCase(preReleaseStr)) {
|
||||||
|
return preRelease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,9 +8,12 @@ import java.util.Objects;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Version utility.
|
||||||
|
*
|
||||||
* @author ryanwang
|
* @author ryanwang
|
||||||
|
* @author johnniang
|
||||||
* @date 2020-02-03
|
* @date 2020-02-03
|
||||||
* @see "com.sun.xml.internal.ws.util.VersionUtil"
|
* @date 2020-08-03
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class VersionUtil {
|
public class VersionUtil {
|
||||||
|
@ -20,6 +23,7 @@ public class VersionUtil {
|
||||||
private VersionUtil() {
|
private VersionUtil() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static int[] getCanonicalVersion(String version) {
|
public static int[] getCanonicalVersion(String version) {
|
||||||
Assert.hasText(version, "Version must not be blank");
|
Assert.hasText(version, "Version must not be blank");
|
||||||
|
|
||||||
|
@ -66,6 +70,7 @@ public class VersionUtil {
|
||||||
return canonicalVersion;
|
return canonicalVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static int compare(String version1, String version2) {
|
public static int compare(String version1, String version2) {
|
||||||
log.debug("Comparing version [{}] with [{}]", version1, version2);
|
log.debug("Comparing version [{}] with [{}]", version1, version2);
|
||||||
|
|
||||||
|
@ -98,6 +103,9 @@ public class VersionUtil {
|
||||||
* @return true or false.
|
* @return true or false.
|
||||||
*/
|
*/
|
||||||
public static boolean compareVersion(String current, String require) {
|
public static boolean compareVersion(String current, String require) {
|
||||||
return compare(current, require) >= 0;
|
Version leftVersion = Version.resolve(current).orElse(Version.emptyVersion());
|
||||||
|
Version rightVersion = Version.resolve(require).orElse(Version.emptyVersion());
|
||||||
|
return leftVersion.compareTo(rightVersion) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,181 @@
|
||||||
|
package run.halo.app.utils;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.RandomUtils;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import run.halo.app.model.support.HaloConst;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version resolve test.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
*/
|
||||||
|
class VersionTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalid versions.
|
||||||
|
*/
|
||||||
|
String[] invalidVersions = new String[] {
|
||||||
|
null,
|
||||||
|
"",
|
||||||
|
"1",
|
||||||
|
"1.2",
|
||||||
|
"1.2.3-0123",
|
||||||
|
"1.2.3-0123.0123",
|
||||||
|
"1.1.2+.123",
|
||||||
|
"+invalid",
|
||||||
|
"-invalid",
|
||||||
|
"-invalid+invalid",
|
||||||
|
"-invalid.01",
|
||||||
|
"alpha",
|
||||||
|
"alpha.beta",
|
||||||
|
"alpha.beta.1",
|
||||||
|
"alpha.1",
|
||||||
|
"alpha+beta",
|
||||||
|
"alpha_beta",
|
||||||
|
"alpha.",
|
||||||
|
"alpha..",
|
||||||
|
"beta",
|
||||||
|
"1.0.0-alpha_beta",
|
||||||
|
"-alpha.",
|
||||||
|
"1.0.0-alpha..",
|
||||||
|
"1.0.0-alpha..1",
|
||||||
|
"1.0.0-alpha...1",
|
||||||
|
"1.0.0-alpha....1",
|
||||||
|
"1.0.0-alpha.....1",
|
||||||
|
"1.0.0-alpha......1",
|
||||||
|
"1.0.0-alpha.......1",
|
||||||
|
"01.1.1",
|
||||||
|
"1.01.1",
|
||||||
|
"1.1.01",
|
||||||
|
"1.2",
|
||||||
|
"1.2.3.DEV",
|
||||||
|
"1.2-SNAPSHOT",
|
||||||
|
"1.2.31.2.3----RC-SNAPSHOT.12.09.1--..12+788",
|
||||||
|
"1.2-RC-SNAPSHOT",
|
||||||
|
"-1.0.3-gamma+b7718",
|
||||||
|
"+justmeta",
|
||||||
|
"9.8.7+meta+meta",
|
||||||
|
"9.8.7-whatever+meta+meta",
|
||||||
|
"99999999999999999999999.999999999999999999.99999999999999999----RC-SNAPSHOT.12.09.1--------------------------------..12",
|
||||||
|
"1.0.0-0A.is.legal",
|
||||||
|
"1.0.0-alpha+beta",
|
||||||
|
"1.2.3----RC-SNAPSHOT.12.9.1--.12+788",
|
||||||
|
"1.2.3----R-S.12.9.1--.12+meta",
|
||||||
|
"1.2.3----RC-SNAPSHOT.12.9.1--.12",
|
||||||
|
"1.0.0+0.build.1-rc.10000aaa-kk-0.1",
|
||||||
|
"1.0.0-0A.is.legal",
|
||||||
|
"2.0.0+build.1848",
|
||||||
|
"1.0.0-alpha0.valid",
|
||||||
|
"1.0.0-alpha.0valid",
|
||||||
|
"1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay",
|
||||||
|
"1.0.0-rc.1+build.1",
|
||||||
|
"2.0.0-rc.1+build.123",
|
||||||
|
"1.2.3-beta",
|
||||||
|
"10.2.3-DEV-SNAPSHOT",
|
||||||
|
"1.2.3-SNAPSHOT-123",
|
||||||
|
"1.1.2-prerelease+meta",
|
||||||
|
"1.1.2+meta",
|
||||||
|
"1.1.2+meta-valid",
|
||||||
|
"1.0.0-alpha",
|
||||||
|
"1.0.0-beta",
|
||||||
|
"1.0.0-alpha.beta",
|
||||||
|
"1.0.0-alpha.beta.1"
|
||||||
|
};
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void invalidVersionResolve() {
|
||||||
|
Stream.of(invalidVersions).forEach(invalidVersion -> {
|
||||||
|
Optional<Version> versionOpt = Version.resolve(invalidVersion);
|
||||||
|
assertFalse(versionOpt.isPresent());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void releaseVersionResolve() {
|
||||||
|
long major = RandomUtils.nextLong();
|
||||||
|
long minor = RandomUtils.nextLong();
|
||||||
|
long patch = RandomUtils.nextLong();
|
||||||
|
String version = major + "." + minor + "." + patch;
|
||||||
|
Optional<Version> versionOpt = Version.resolve(version);
|
||||||
|
assertTrue(versionOpt.isPresent());
|
||||||
|
assertEquals(new Version(major, minor, patch), versionOpt.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void preReleaseVersionResolve() {
|
||||||
|
long major = RandomUtils.nextLong();
|
||||||
|
long minor = RandomUtils.nextLong();
|
||||||
|
long patch = RandomUtils.nextLong();
|
||||||
|
long preReleaseMajor = RandomUtils.nextLong();
|
||||||
|
String version = major + "." + minor + "." + patch + "-alpha." + preReleaseMajor;
|
||||||
|
Optional<Version> versionOpt = Version.resolve(version);
|
||||||
|
assertTrue(versionOpt.isPresent());
|
||||||
|
assertEquals(new Version(major, minor, patch, Version.PreRelease.ALPHA, preReleaseMajor),
|
||||||
|
versionOpt.get());
|
||||||
|
|
||||||
|
version = major + "." + minor + "." + patch + "-beta." + preReleaseMajor;
|
||||||
|
versionOpt = Version.resolve(version);
|
||||||
|
assertTrue(versionOpt.isPresent());
|
||||||
|
assertEquals(new Version(major, minor, patch, Version.PreRelease.BETA, preReleaseMajor),
|
||||||
|
versionOpt.get());
|
||||||
|
|
||||||
|
version = major + "." + minor + "." + patch + "-rc." + preReleaseMajor;
|
||||||
|
versionOpt = Version.resolve(version);
|
||||||
|
assertTrue(versionOpt.isPresent());
|
||||||
|
assertEquals(new Version(major, minor, patch, Version.PreRelease.RC, preReleaseMajor),
|
||||||
|
versionOpt.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void unknownVersionTest() {
|
||||||
|
Optional<Version> unknownVersionOpt = Version.resolve(HaloConst.UNKNOWN_VERSION);
|
||||||
|
assertTrue(unknownVersionOpt.isPresent());
|
||||||
|
assertEquals(new Version(0, 0, 0), unknownVersionOpt.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void compareTest() {
|
||||||
|
Version leftVersion = getVersion("1.2.3");
|
||||||
|
// compare with own
|
||||||
|
assertEquals(0, leftVersion.compareTo(leftVersion));
|
||||||
|
|
||||||
|
// compare with others
|
||||||
|
Version rightVersion = getVersion("1.2.4");
|
||||||
|
assertTrue(leftVersion.compareTo(rightVersion) < 0);
|
||||||
|
|
||||||
|
rightVersion = getVersion("1.3.3");
|
||||||
|
assertTrue(leftVersion.compareTo(rightVersion) < 0);
|
||||||
|
|
||||||
|
rightVersion = getVersion("2.2.3");
|
||||||
|
assertTrue(leftVersion.compareTo(rightVersion) < 0);
|
||||||
|
|
||||||
|
rightVersion = getVersion("0.2.3");
|
||||||
|
assertTrue(leftVersion.compareTo(rightVersion) > 0);
|
||||||
|
|
||||||
|
rightVersion = getVersion("1.1.3");
|
||||||
|
assertTrue(leftVersion.compareTo(rightVersion) > 0);
|
||||||
|
|
||||||
|
rightVersion = getVersion("1.2.2");
|
||||||
|
assertTrue(leftVersion.compareTo(rightVersion) > 0);
|
||||||
|
|
||||||
|
rightVersion = getVersion("1.2.3-alpha.0");
|
||||||
|
assertTrue(leftVersion.compareTo(rightVersion) > 0);
|
||||||
|
|
||||||
|
rightVersion = getVersion("1.2.4-alpha.0");
|
||||||
|
assertTrue(leftVersion.compareTo(rightVersion) < 0);
|
||||||
|
|
||||||
|
// compare with unkown version
|
||||||
|
assertTrue(leftVersion.compareTo(getVersion(HaloConst.UNKNOWN_VERSION)) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
Version getVersion(String version) {
|
||||||
|
return Version.resolve(version).orElseThrow(() -> new IllegalArgumentException("Invalid version"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ class VersionUtilTest {
|
||||||
void compareVersion() {
|
void compareVersion() {
|
||||||
assertTrue(VersionUtil.compareVersion("1.2.0", "1.1.1"));
|
assertTrue(VersionUtil.compareVersion("1.2.0", "1.1.1"));
|
||||||
assertTrue(VersionUtil.compareVersion("1.2.1", "1.2.0"));
|
assertTrue(VersionUtil.compareVersion("1.2.1", "1.2.0"));
|
||||||
assertTrue(VersionUtil.compareVersion("1.2.0", "1.1.1.0"));
|
assertTrue(VersionUtil.compareVersion("1.2.0", "1.1.1"));
|
||||||
assertTrue(VersionUtil.compareVersion("1.2.0", "0.4.4"));
|
assertTrue(VersionUtil.compareVersion("1.2.0", "0.4.4"));
|
||||||
assertFalse(VersionUtil.compareVersion("1.1.1", "1.2.0"));
|
assertFalse(VersionUtil.compareVersion("1.1.1", "1.2.0"));
|
||||||
assertFalse(VersionUtil.compareVersion("0.0.1", "1.2.0"));
|
assertFalse(VersionUtil.compareVersion("0.0.1", "1.2.0"));
|
||||||
|
@ -29,7 +29,7 @@ class VersionUtilTest {
|
||||||
RandomStringUtils.randomNumeric(1),
|
RandomStringUtils.randomNumeric(1),
|
||||||
RandomStringUtils.randomNumeric(2),
|
RandomStringUtils.randomNumeric(2),
|
||||||
RandomStringUtils.randomNumeric(3));
|
RandomStringUtils.randomNumeric(3));
|
||||||
VersionUtil.compareVersion(HaloConst.UNKNOWN_VERSION, randomVersion);
|
assertFalse(VersionUtil.compareVersion(HaloConst.UNKNOWN_VERSION, randomVersion));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in New Issue