diff --git a/multiapps-common/pom.xml b/multiapps-common/pom.xml
index a5260ab7..fb01a8e5 100644
--- a/multiapps-common/pom.xml
+++ b/multiapps-common/pom.xml
@@ -29,7 +29,7 @@
commons-lang3
- tools.jackson.core
+ com.fasterxml.jackson.core
jackson-databind
diff --git a/multiapps-mta/pom.xml b/multiapps-mta/pom.xml
index ae725f9f..47512e9b 100644
--- a/multiapps-mta/pom.xml
+++ b/multiapps-mta/pom.xml
@@ -21,7 +21,7 @@
commons-collections4
- org.semver4j
+ com.vdurmont
semver4j
diff --git a/multiapps-mta/src/main/java/module-info.java b/multiapps-mta/src/main/java/module-info.java
index e337fdb6..1a092d01 100644
--- a/multiapps-mta/src/main/java/module-info.java
+++ b/multiapps-mta/src/main/java/module-info.java
@@ -29,7 +29,7 @@
requires org.apache.commons.collections4;
requires org.apache.commons.io;
requires org.apache.commons.lang3;
- requires org.semver4j;
+ requires semver4j;
requires org.apache.commons.compress;
requires static java.compiler;
diff --git a/multiapps-mta/src/main/java/org/cloudfoundry/multiapps/mta/model/Version.java b/multiapps-mta/src/main/java/org/cloudfoundry/multiapps/mta/model/Version.java
index 67eaf16b..f8f2efc3 100644
--- a/multiapps-mta/src/main/java/org/cloudfoundry/multiapps/mta/model/Version.java
+++ b/multiapps-mta/src/main/java/org/cloudfoundry/multiapps/mta/model/Version.java
@@ -4,12 +4,16 @@
import org.cloudfoundry.multiapps.common.ParsingException;
import org.cloudfoundry.multiapps.mta.Messages;
+import org.cloudfoundry.multiapps.mta.parsers.PartialVersionConverter;
-import org.semver4j.Semver;
-import org.semver4j.SemverException;
+import com.vdurmont.semver4j.Semver;
+import com.vdurmont.semver4j.Semver.SemverType;
+import com.vdurmont.semver4j.SemverException;
public class Version implements Comparable {
+ private static final PartialVersionConverter PARTIAL_VERSION_CONVERTER = new PartialVersionConverter();
+
private final Semver version;
private Version(Semver version) {
@@ -28,12 +32,21 @@ public int getPatch() {
return version.getPatch();
}
+ public String getBuild() {
+ return version.getBuild();
+ }
+
+ public String[] getSuffixTokens() {
+ return version.getSuffixTokens();
+ }
+
public static Version parseVersion(String versionString) {
- var version = Semver.coerce(versionString);
- if (version == null) {
- throw new ParsingException(MessageFormat.format(Messages.UNABLE_TO_PARSE_VERSION, versionString));
+ try {
+ String fullVersionString = PARTIAL_VERSION_CONVERTER.convertToFullVersionString(versionString);
+ return new Version(new Semver(fullVersionString, SemverType.NPM));
+ } catch (SemverException e) {
+ throw new ParsingException(e, Messages.UNABLE_TO_PARSE_VERSION, versionString);
}
- return new Version(version);
}
@Override
@@ -43,7 +56,7 @@ public int hashCode() {
@Override
public String toString() {
- return version.toString();
+ return version.getValue();
}
@Override
@@ -68,8 +81,7 @@ public boolean equals(Object obj) {
public boolean satisfies(String requirement) {
try {
- // The second parameter is preventing the default behavior of Semver to treat the suffix as a pre-release tag.
- return version.satisfies(requirement, true);
+ return version.satisfies(requirement);
} catch (SemverException e) {
throw new IllegalArgumentException(MessageFormat.format(Messages.UNABLE_TO_PARSE_VERSION_REQUIREMENT, requirement));
}
diff --git a/multiapps-mta/src/main/java/org/cloudfoundry/multiapps/mta/parsers/PartialVersionConverter.java b/multiapps-mta/src/main/java/org/cloudfoundry/multiapps/mta/parsers/PartialVersionConverter.java
new file mode 100644
index 00000000..22059356
--- /dev/null
+++ b/multiapps-mta/src/main/java/org/cloudfoundry/multiapps/mta/parsers/PartialVersionConverter.java
@@ -0,0 +1,48 @@
+package org.cloudfoundry.multiapps.mta.parsers;
+
+import com.vdurmont.semver4j.Semver;
+import com.vdurmont.semver4j.Semver.SemverType;
+
+public class PartialVersionConverter {
+
+ private static final String VERSION_STRING_TEMPLATE = "%s.%s.%s%s%s";
+ private static final String VERSION_SUFFIX_STRING_TEMPLATE = "-%s";
+ private static final String VERSION_BUILD_STRING_TEMPLATE = "+%s";
+ private static final String DEFAULT_VERSION_SUFFIX = "";
+
+ public String convertToFullVersionString(String partialVersionString) {
+ Semver partialVersion = new Semver(partialVersionString, SemverType.LOOSE);
+ Integer majorVersion = partialVersion.getMajor();
+ Integer minorVersion = partialVersion.getMinor();
+ Integer patchVersion = partialVersion.getPatch();
+
+ if (minorVersion == null) {
+ minorVersion = 0;
+ }
+ if (patchVersion == null) {
+ patchVersion = 0;
+ }
+ return buildVersionString(majorVersion, minorVersion, patchVersion, partialVersion.getSuffixTokens(), partialVersion.getBuild());
+ }
+
+ private String buildVersionString(int major, int minor, int patch, String[] suffixTokens, String buildVersion) {
+ String formattedSuffixTokens = formatSuffixTokens(suffixTokens);
+ String formattedBuildVersion = formatBuildVersion(buildVersion);
+ return String.format(VERSION_STRING_TEMPLATE, major, minor, patch, formattedSuffixTokens, formattedBuildVersion);
+ }
+
+ private String formatSuffixTokens(String[] suffixTokens) {
+ if (suffixTokens.length == 0) {
+ return DEFAULT_VERSION_SUFFIX;
+ }
+ return String.format(VERSION_SUFFIX_STRING_TEMPLATE, String.join(".", suffixTokens));
+ }
+
+ private String formatBuildVersion(String buildVersion) {
+ if (buildVersion == null) {
+ return DEFAULT_VERSION_SUFFIX;
+ }
+ return String.format(VERSION_BUILD_STRING_TEMPLATE, buildVersion);
+ }
+
+}
diff --git a/multiapps-mta/src/test/java/org/cloudfoundry/multiapps/mta/model/VersionTest.java b/multiapps-mta/src/test/java/org/cloudfoundry/multiapps/mta/model/VersionTest.java
deleted file mode 100644
index c3a0d3d5..00000000
--- a/multiapps-mta/src/test/java/org/cloudfoundry/multiapps/mta/model/VersionTest.java
+++ /dev/null
@@ -1,205 +0,0 @@
-package org.cloudfoundry.multiapps.mta.model;
-
-import java.util.stream.Stream;
-
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNotEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-class VersionTest {
-
- private static final String UNABLE_TO_PARSE_VERSION = "Unable to parse version";
-
- // ---------------------------------------------------------------------------------------------
- // PARSING AND NORMALIZATION TESTS
- // ---------------------------------------------------------------------------------------------
- @Nested
- @DisplayName("parseVersion() and normalization behavior")
- class ParseVersionTests {
-
- @Test
- @DisplayName("should parse complex versions with build metadata and timestamps")
- void testParseComplexVersions() {
- Version v1 = Version.parseVersion("0.0.1-20251105063220+e303076b5d51da7f0f3a10cd69de018ac0a3853d");
- Version v2 = Version.parseVersion("1.2.0-20251105043948+cb754700fb069b3367c869938ac6beb396c800e4");
- Version v3 = Version.parseVersion("1.0.0-SNAPSHOT-20240116224612+200df4832787863cc2f94d998c6cbcd711518933");
-
- assertNotNull(v1);
- assertNotNull(v2);
- assertNotNull(v3);
-
- assertVersionParts(v1, 0, 0, 1);
- assertVersionParts(v2, 1, 2, 0);
- assertVersionParts(v3, 1, 0, 0);
- }
-
- private void assertVersionParts(Version version, int major, int minor, int patch) {
- assertEquals(major, version.getMajor());
- assertEquals(minor, version.getMinor());
- assertEquals(patch, version.getPatch());
- }
-
- @ParameterizedTest(name = "Partial version \"{0}\" should normalize to \"{1}\"")
- @MethodSource
- void testNormalizePartialVersions(String input, String expected) {
- Version version = Version.parseVersion(input);
- assertEquals(expected, version.toString());
- }
-
- static Stream testNormalizePartialVersions() {
- return Stream.of(
- Arguments.of("1.0.0", "1.0.0"),
- Arguments.of("2.1", "2.1.0"),
- Arguments.of("2", "2.0.0"),
- Arguments.of("1.9.0-SNAPSHOT", "1.9.0-SNAPSHOT"),
- Arguments.of("1.9-SNAPSHOT", "1.9.0"),
- Arguments.of("1-SNAPSHOT", "1.0.0"),
- Arguments.of("1.2.0-beta+exp.sha.5114f85", "1.2.0-beta+exp.sha.5114f85"),
- Arguments.of("1.2-beta+exp.sha.5114f85", "1.2.0"),
- Arguments.of("1-beta+exp.sha.5114f85", "1.0.0"),
- Arguments.of("v1.2.3", "1.2.3")
- );
- }
-
- @ParameterizedTest(name = "Invalid version \"{0}\" should throw SemverException or ParsingException")
- @MethodSource
- void testInvalidVersions(String invalid, String expectedMessage) {
- Exception ex = assertThrows(Exception.class, () -> Version.parseVersion(invalid));
- assertTrue(ex.getMessage()
- .contains(expectedMessage));
- }
-
- static Stream testInvalidVersions() {
- return Stream.of(
- Arguments.of("a.b.c", UNABLE_TO_PARSE_VERSION),
- Arguments.of("", UNABLE_TO_PARSE_VERSION),
- Arguments.of("null", UNABLE_TO_PARSE_VERSION),
- Arguments.of("not-a-version", UNABLE_TO_PARSE_VERSION)
- );
- }
- }
-
- // ---------------------------------------------------------------------------------------------
- // COMPARISON AND EQUALITY TESTS
- // ---------------------------------------------------------------------------------------------
- @Nested
- @DisplayName("compareTo() and equality behavior")
- class CompareTests {
-
- @Test
- void testVersionComparison() {
- Version v1 = Version.parseVersion("1.2.3");
- Version v2 = Version.parseVersion("1.3.0");
- Version v3 = Version.parseVersion("1.2.3");
-
- assertTrue(v1.compareTo(v2) < 0);
- assertTrue(v2.compareTo(v1) > 0);
- assertEquals(0, v1.compareTo(v3));
- }
-
- @Test
- void testEqualsAndHashCode() {
- Version v1 = Version.parseVersion("2.0.0");
- Version v2 = Version.parseVersion("2.0.0");
- Version v3 = Version.parseVersion("2.0.1");
-
- assertEquals(v1, v2);
- assertNotEquals(v1, v3);
- assertEquals(v1.hashCode(), v2.hashCode());
- assertNotEquals(v1.hashCode(), v3.hashCode());
- }
- }
-
- // ---------------------------------------------------------------------------------------------
- // TO STRING & EDGE CASE TESTS
- // ---------------------------------------------------------------------------------------------
- @Nested
- class ToStringAndEdgeCases {
-
- @Test
- void testToStringRepresentation() {
- String raw = "3.4.5-alpha+build";
- Version version = Version.parseVersion(raw);
- assertEquals(raw, version.toString());
- }
-
- @Test
- void testLargeVersionNumbers() {
- Version version = Version.parseVersion("9999.9999.9999");
- assertEquals(9999, version.getMajor());
- }
-
- @Test
- void testPreReleaseVersion() {
- Version version = Version.parseVersion("1.0.0-alpha");
- assertTrue(version.toString()
- .contains("alpha"));
- }
- }
-
- // ---------------------------------------------------------------------------------------------
- // SATISFIES() RANGE CHECK TESTS
- // ---------------------------------------------------------------------------------------------
- @Nested
- class SatisfiesBehavior {
-
- @Test
- void testSimpleComparisons() {
- Version v = Version.parseVersion("3.1.4");
-
- assertTrue(v.satisfies(">3.0.0"));
- assertTrue(v.satisfies(">=3.1.4"));
- assertFalse(v.satisfies("<3.0.0"));
- assertFalse(v.satisfies("<=3.1.3"));
- }
-
- @Test
- void testCompositeRanges() {
- Version v = Version.parseVersion("3.1.4");
- assertTrue(v.satisfies(">=3.1.4 <4.0.0"));
- assertTrue(v.satisfies(">=3.0.0 <=3.1.4"));
- assertFalse(v.satisfies(">=3.2.0 <4.0.0"));
- }
-
- @Test
- void testCaretAndTilde() {
- Version v = Version.parseVersion("1.3.5");
- assertTrue(v.satisfies("^1.3.0"));
- assertTrue(v.satisfies("~1.3.0"));
- assertFalse(v.satisfies("^2.0.0"));
- }
-
- @Test
- void testMalformedRequirementsReturnFalse() {
- Version v = Version.parseVersion("3.1.4");
- assertFalse(v.satisfies("not-a-requirement"));
- assertFalse(v.satisfies("pesho3.1.4"));
- assertFalse(v.satisfies("3.1.4.2.3.4.5"));
- }
-
- @Test
- void testNullRequirement() {
- Version v = Version.parseVersion("3.1.4");
- assertThrows(NullPointerException.class, () -> v.satisfies(null));
- }
-
- @Test
- void testSatisfiesWithComplexVersions() {
- Version v = Version.parseVersion("1.2.3-20251105063220+e303076b5d51da7f0f3a10cd69de018ac0a3853d");
- assertTrue(v.satisfies(">=1.2.0"));
- assertFalse(v.satisfies(">1.2.3"));
- assertTrue(v.satisfies(">=1.2.0 <2.0.0"));
- assertFalse(v.satisfies(">1.2.3 <2.0.0"));
- }
- }
-}
\ No newline at end of file
diff --git a/multiapps-mta/src/test/java/org/cloudfoundry/multiapps/mta/parsers/PartialVersionConverterTest.java b/multiapps-mta/src/test/java/org/cloudfoundry/multiapps/mta/parsers/PartialVersionConverterTest.java
new file mode 100644
index 00000000..5a539d72
--- /dev/null
+++ b/multiapps-mta/src/test/java/org/cloudfoundry/multiapps/mta/parsers/PartialVersionConverterTest.java
@@ -0,0 +1,72 @@
+package org.cloudfoundry.multiapps.mta.parsers;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.stream.Stream;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import com.vdurmont.semver4j.SemverException;
+
+class PartialVersionConverterTest {
+
+ private final PartialVersionConverter partialVersionConverter = new PartialVersionConverter();
+
+ @ParameterizedTest
+ @MethodSource
+ void testConvertWithInvalidVersions(String versionString, String expectedExceptionMessage) {
+ SemverException exception = assertThrows(SemverException.class,
+ () -> partialVersionConverter.convertToFullVersionString(versionString));
+
+ assertEquals(expectedExceptionMessage, exception.getMessage());
+ }
+
+ static Stream testConvertWithInvalidVersions() {
+ return Stream.of(
+// @formatter:off
+ Arguments.of("1.0.0-beta+", "The build cannot be empty."),
+ Arguments.of("3.a", "Invalid version (no minor version): 3.a"),
+ Arguments.of("a.b.c", "Invalid version (no major version): a.b.c"),
+ Arguments.of( "", "Invalid version (no major version): "),
+ Arguments.of("[ 2.0, 2.1 ]", "Invalid version (no major version): [ 2.0, 2.1 ]")
+// @formatter:on
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ void testConvertWithValidVersions(String versionString, String expectedResult) {
+ String fullVersionString = partialVersionConverter.convertToFullVersionString(versionString);
+
+ assertEquals(expectedResult, fullVersionString);
+ }
+
+ static Stream testConvertWithValidVersions() {
+ return Stream.of(
+// @formatter:off
+ // Full version:
+ Arguments.of("1.0.0", "1.0.0"),
+ // Partial version with minor version:
+ Arguments.of("2.1", "2.1.0"),
+ // Partial version with patch version:
+ Arguments.of("2", "2.0.0"),
+ // Full version with suffix tokens:
+ Arguments.of("1.9.0-SHAPSHOT", "1.9.0-SHAPSHOT"),
+ // Partial version with suffix tokens:
+ Arguments.of("1.9-SHAPSHOT", "1.9.0-SHAPSHOT"),
+ // Partial version with suffix tokens:
+ Arguments.of("1-SHAPSHOT", "1.0.0-SHAPSHOT"),
+ // Full version with suffix tokens and build information:
+ Arguments.of("1.2.0-beta+exp.sha.5114f85", "1.2.0-beta+exp.sha.5114f85"),
+ // Partial version with suffix tokens and build information:
+ Arguments.of("1.2-beta+exp.sha.5114f85", "1.2.0-beta+exp.sha.5114f85"),
+ // Partial version with suffix tokens and build information:
+ Arguments.of("1-beta+exp.sha.5114f85", "1.0.0-beta+exp.sha.5114f85")
+// @formatter:on
+ );
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index 4f0ec48a..d333ff11 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,18 +18,20 @@
cloudfoundry
../multiapps-coverage/target/site/jacoco-aggregate/jacoco.xml
- 6.0.1
- 5.20.0
- 3.19.0
+ 5.13.4
+ 1.13.2
+ 5.18.0
+ 3.18.0
4.5.0
2.20.0
- 2.5
- 6.0.0
- 2.11.7
- 3.0.1
- 2.20.1
- 4.0.6
- 4.0.4
+ 2.4
+
+
+ 3.1.0
+ 2.10.1
+ 2.19.2
+ 4.0.5
+ 4.0.2
1.28.0
@@ -119,7 +121,7 @@
org.apache.maven.plugins
maven-javadoc-plugin
- 3.12.0
+ 3.11.2
@@ -215,7 +217,7 @@
org.junit.platform
junit-platform-launcher
- ${junit.version}
+ ${junit-platform.version}
test
@@ -244,17 +246,16 @@
jaxb-runtime
${jaxb-runtime.version}
-
+
- tools.jackson.core
+ com.fasterxml.jackson.core
jackson-databind
${jackson.version}
-
com.fasterxml.jackson.datatype
jackson-datatype-jsr310
- ${jackson.datatype.jsr310.version}
+ ${jackson.version}
@@ -280,9 +281,9 @@
snakeyaml
${snakeyaml.version}
-
+
- org.semver4j
+ com.vdurmont
semver4j
${semver4j.version}