From e6a9db4456bca3dc9c0b30985026275bfe7b4f03 Mon Sep 17 00:00:00 2001 From: Eric Milles Date: Thu, 11 Jun 2026 15:40:08 -0500 Subject: [PATCH] IVY-1665: verify version is greater before reporting on available update --- .../ivy/ant/IvyDependencyUpdateChecker.java | 44 +++++++++++++++++-- .../ant/IvyDependencyUpdateCheckerTest.java | 20 +++++++++ .../repositories/IVY-1665/bar/foo/foo-1.0.jar | 1 + .../IVY-1665/bar/foo/foo-2.0-M1.jar | 1 + .../repositories/IVY-1665/bar/foo/ivy-1.0.xml | 22 ++++++++++ .../IVY-1665/bar/foo/ivy-2.0-M1.xml | 22 ++++++++++ test/repositories/IVY-1665/ivysettings.xml | 28 ++++++++++++ 7 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 test/repositories/IVY-1665/bar/foo/foo-1.0.jar create mode 100644 test/repositories/IVY-1665/bar/foo/foo-2.0-M1.jar create mode 100644 test/repositories/IVY-1665/bar/foo/ivy-1.0.xml create mode 100644 test/repositories/IVY-1665/bar/foo/ivy-2.0-M1.xml create mode 100644 test/repositories/IVY-1665/ivysettings.xml diff --git a/src/java/org/apache/ivy/ant/IvyDependencyUpdateChecker.java b/src/java/org/apache/ivy/ant/IvyDependencyUpdateChecker.java index d467d23c..76e9d090 100644 --- a/src/java/org/apache/ivy/ant/IvyDependencyUpdateChecker.java +++ b/src/java/org/apache/ivy/ant/IvyDependencyUpdateChecker.java @@ -127,9 +127,9 @@ public class IvyDependencyUpdateChecker extends IvyPostResolveTask { boolean dependencyUpdateDetected = false; for (IvyNode latest : latestReport.getDependencies()) { for (IvyNode originalDependency : originalReport.getDependencies()) { - if (originalDependency.getModuleId().equals(latest.getModuleId())) { - if (!originalDependency.getResolvedId().getRevision() - .equals(latest.getResolvedId().getRevision())) { + if (latest.getModuleId().equals(originalDependency.getModuleId())) { + if (isGreater(latest.getResolvedId().getRevision(), + originalDependency.getResolvedId().getRevision())) { // is this dependency a transitive or a direct dependency? // (unfortunately .isTransitive() methods do not have the same meaning) boolean isTransitiveDependency = latest.getDependencyDescriptor(latest @@ -195,4 +195,42 @@ public class IvyDependencyUpdateChecker extends IvyPostResolveTask { } } } + + //-------------------------------------------------------------------------- + + private static boolean isGreater(String string1, String string2) { + String[] tokens1 = string1.split("[\\._\\-\\+]"); + String[] tokens2 = string2.split("[\\._\\-\\+]"); + int i = 0; + for (final int n = Math.min(tokens1.length, tokens2.length); i < n; i += 1) { + if (!tokens1[i].equals(tokens2[i])) { + boolean is1Number = isNumeric(tokens1[i]); + boolean is2Number = isNumeric(tokens2[i]); + if (is1Number && is2Number) { + return Long.valueOf(tokens1[i]).compareTo(Long.valueOf(tokens2[i])) > 0; + } else if (is1Number && !is2Number) { + return true; + } else if (!is1Number && is2Number) { + return false; + } + return true; // special meanings accounted for by resolve + } + } + if (i < tokens1.length) { + return isNumeric(tokens1[i]); + } + if (i < tokens2.length) { + return !isNumeric(tokens2[i]); + } + return false; + } + + private static boolean isNumeric(String string) { + for (int i = 0, n = string.length(); i < n; ++i) { + if (!Character.isDigit(string.charAt(i))) { + return false; + } + } + return true; + } } diff --git a/test/java/org/apache/ivy/ant/IvyDependencyUpdateCheckerTest.java b/test/java/org/apache/ivy/ant/IvyDependencyUpdateCheckerTest.java index 26f14e84..48565de1 100644 --- a/test/java/org/apache/ivy/ant/IvyDependencyUpdateCheckerTest.java +++ b/test/java/org/apache/ivy/ant/IvyDependencyUpdateCheckerTest.java @@ -220,6 +220,26 @@ public class IvyDependencyUpdateCheckerTest extends AntTaskTestCase { assertLogContaining("org1#mod1.2\t2.0 -> 2.2"); } + /** + * Test case for IVY-1665. + * + * @see IVY-1665 + */ + @Test + public void testLatestRelease() { + dependencyUpdateChecker.getProject().setProperty("ivy.settings.file", "test/repositories/IVY-1665/ivysettings.xml"); + dependencyUpdateChecker.setRevisionToCheck("latest.release"); // exclude milestone (2.0-M1) + dependencyUpdateChecker.setOrganisation("bar"); + dependencyUpdateChecker.setModule("foo"); + dependencyUpdateChecker.setRevision("2.0-M1"); + dependencyUpdateChecker.setInline(true); + dependencyUpdateChecker.execute(); + + assertLogNotContaining("bar#foo\t2.0-M1 -> 1.0"); + // expect listing for 2.0 when it comes available + assertLogContaining("All dependencies are up to date"); + } + @Test public void testSimpleExtends() { dependencyUpdateChecker.setFile(new File("test/java/org/apache/ivy/ant/ivy-extends-multiconf.xml")); diff --git a/test/repositories/IVY-1665/bar/foo/foo-1.0.jar b/test/repositories/IVY-1665/bar/foo/foo-1.0.jar new file mode 100644 index 00000000..945c9b46 --- /dev/null +++ b/test/repositories/IVY-1665/bar/foo/foo-1.0.jar @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/test/repositories/IVY-1665/bar/foo/foo-2.0-M1.jar b/test/repositories/IVY-1665/bar/foo/foo-2.0-M1.jar new file mode 100644 index 00000000..945c9b46 --- /dev/null +++ b/test/repositories/IVY-1665/bar/foo/foo-2.0-M1.jar @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/test/repositories/IVY-1665/bar/foo/ivy-1.0.xml b/test/repositories/IVY-1665/bar/foo/ivy-1.0.xml new file mode 100644 index 00000000..75071478 --- /dev/null +++ b/test/repositories/IVY-1665/bar/foo/ivy-1.0.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/test/repositories/IVY-1665/bar/foo/ivy-2.0-M1.xml b/test/repositories/IVY-1665/bar/foo/ivy-2.0-M1.xml new file mode 100644 index 00000000..341093d7 --- /dev/null +++ b/test/repositories/IVY-1665/bar/foo/ivy-2.0-M1.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/test/repositories/IVY-1665/ivysettings.xml b/test/repositories/IVY-1665/ivysettings.xml new file mode 100644 index 00000000..908e5d48 --- /dev/null +++ b/test/repositories/IVY-1665/ivysettings.xml @@ -0,0 +1,28 @@ + + + + + + + + + + +