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-->
|
||||
<module name="GenericWhitespace"/>
|
||||
<module name="NoWhitespaceBefore"/>
|
||||
<module name="NoWhitespaceAfter"/>
|
||||
<module name="WhitespaceAfter"/>
|
||||
<module name="WhitespaceAround">
|
||||
<property name="allowEmptyConstructors" 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;
|
||||
|
||||
/**
|
||||
* Version utility.
|
||||
*
|
||||
* @author ryanwang
|
||||
* @author johnniang
|
||||
* @date 2020-02-03
|
||||
* @see "com.sun.xml.internal.ws.util.VersionUtil"
|
||||
* @date 2020-08-03
|
||||
*/
|
||||
@Slf4j
|
||||
public class VersionUtil {
|
||||
|
@ -20,6 +23,7 @@ public class VersionUtil {
|
|||
private VersionUtil() {
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static int[] getCanonicalVersion(String version) {
|
||||
Assert.hasText(version, "Version must not be blank");
|
||||
|
||||
|
@ -66,6 +70,7 @@ public class VersionUtil {
|
|||
return canonicalVersion;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static int compare(String version1, String version2) {
|
||||
log.debug("Comparing version [{}] with [{}]", version1, version2);
|
||||
|
||||
|
@ -98,6 +103,9 @@ public class VersionUtil {
|
|||
* @return true or false.
|
||||
*/
|
||||
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() {
|
||||
assertTrue(VersionUtil.compareVersion("1.2.0", "1.1.1"));
|
||||
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"));
|
||||
assertFalse(VersionUtil.compareVersion("1.1.1", "1.2.0"));
|
||||
assertFalse(VersionUtil.compareVersion("0.0.1", "1.2.0"));
|
||||
|
@ -29,7 +29,7 @@ class VersionUtilTest {
|
|||
RandomStringUtils.randomNumeric(1),
|
||||
RandomStringUtils.randomNumeric(2),
|
||||
RandomStringUtils.randomNumeric(3));
|
||||
VersionUtil.compareVersion(HaloConst.UNKNOWN_VERSION, randomVersion);
|
||||
assertFalse(VersionUtil.compareVersion(HaloConst.UNKNOWN_VERSION, randomVersion));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue