smallrye-common icon indicating copy to clipboard operation
smallrye-common copied to clipboard

VersionScheme.MAVEN version comparison fails

Open gastaldi opened this issue 1 year ago • 8 comments

Given that 3.8.0.redhat-00001 is less than 3.8.0.SP1-redhat-00001, the following snippet returns 1 (expected is -1):

VersionScheme.MAVEN.compare("3.8.0.redhat-00001", "3.8.0.SP1-redhat-00001")

Originally posted by @gastaldi in https://github.com/smallrye/smallrye-common/pull/330#discussion_r1683430729

gastaldi avatar Jul 19 '24 00:07 gastaldi

I posted this in the other thread:

I believe that custom qualifiers come after predefined qualifiers (like SP) according to the Maven rules.

$ jbang --main=org.eclipse.aether.util.version.GenericVersionScheme org.apache.maven.resolver:maven-resolver-util:1.9.6 1.redhat 1.sp
Display parameters as parsed by Maven Resolver (in canonical form and as a list of tokens) and comparison result:
1. 1.redhat -> 1.redhat; tokens: [1, redhat]
   1.redhat > 1.sp
2. 1.sp -> 1.sp; tokens: [1, 1]
$ jbang --main=org.eclipse.aether.util.version.GenericVersionScheme org.apache.maven.resolver:maven-resolver-util:1.9.6 3.8.0.redhat-00001 3.8.0.SP1-redhat-00001
Display parameters as parsed by Maven Resolver (in canonical form and as a list of tokens) and comparison result:
1. 3.8.0.redhat-00001 -> 3.8.0.redhat-00001; tokens: [3, 8, redhat, 1]
   3.8.0.redhat-00001 > 3.8.0.SP1-redhat-00001
2. 3.8.0.SP1-redhat-00001 -> 3.8.0.SP1-redhat-00001; tokens: [3, 8, 1, 1, redhat, 1]

This was also verified using 1.9.7 and 1.9.8. In light of this fact, I think this is not a bug, WDYT?

dmlloyd avatar Jul 22 '24 15:07 dmlloyd

I don't know, I believe that the absence of a predefined qualifier should assume Final or RELEASE for comparison purposes.

Any thoughts @aloubyansky?

gastaldi avatar Jul 22 '24 15:07 gastaldi

Well, that would be nice. :-)

However, Maven doesn't have any way to know whether you intend to put Final/0/etc. before a qualifier. It only has rules for leading zeros and trailing zeros. Additionally, it appears to be the intent of the Maven developers that . and - (and the empty separator) will become equivalent.

What we are doing, when we add our redhat qualifier, is we're basically saying "here is our special version that comes immediately after the version we qualify". But syntactically, this is not actually what happens. The only way to do such a thing is to add 0.0.0.0.0.... (to infinity) in between the original version number and our qualifier, which is not ideal. Maven general qualifiers were not really intended for this situation, hence our current troubles.

Addressing a syntactic weakness like this is actually very difficult, because if you do change the rules for this use case, then you will likely break some (or many) other use cases. Thus we have to look at bugs such as this one as "we made a wrong assumption about how this works" rather than "it doesn't work the way we want, so it should be fixed".

In practice, I think adding a 0 or Final when productizing versions of things which do not have (standard) qualifiers before redhat is probably the right solution.

dmlloyd avatar Jul 22 '24 17:07 dmlloyd

Here is an implementation from the Maven resolver, to compare.

    public static void main(String[] args) throws Exception {
        compare("3.8.5", "3.8.5.redhat-00005");
        compare("3.8.5.SP1", "3.8.5.redhat-00005");
        compare("3.8.5.SP1", "3.8.5.SP1-redhat-00005");
        compare("3.8.5.SP2", "3.8.5.SP1-redhat-00005");
    }

    private static void compare(String v1, String v2) throws InvalidVersionSpecificationException {
        System.out.print(v1);
        var versionScheme = new org.eclipse.aether.util.version.GenericVersionScheme();
        final Version version1 = versionScheme.parseVersion(v1);
        final Version version2 = versionScheme.parseVersion(v2);
        final int result = version1.compareTo(version2);
        if(result < 0) {
            System.out.print(" < ");
        } else if(result == 0) {
            System.out.print(" = ");
        } else {
            System.out.print(" > ");
        }
        System.out.println(v2);
    }

results in

3.8.5 < 3.8.5.redhat-00005
3.8.5.SP1 < 3.8.5.redhat-00005
3.8.5.SP1 < 3.8.5.SP1-redhat-00005
3.8.5.SP2 > 3.8.5.SP1-redhat-00005

Where 3.8.5.SP1 < 3.8.5.redhat-00005 is not correct.

aloubyansky avatar Jul 22 '24 18:07 aloubyansky

From the two implementations, I'd probably pick org.eclipse.aether.util.version.GenericVersionScheme. At least it seems to pick the latest downstream version.

aloubyansky avatar Jul 22 '24 18:07 aloubyansky

To be perfectly clear, my jbang examples above were also from the Maven resolver, same class. So we agree that Maven presently considers 3.8.5.SP1 < 3.8.5.redhat-00005, and the SmallRye version implementation does also? Thus I would consider this "not a bug", though we might also consider it "not very nice" as well.

dmlloyd avatar Jul 23 '24 17:07 dmlloyd

I'd say that Maven is wrong and so is Smallrye for not considering an empty milestone as a release during comparison 😀

gastaldi avatar Jul 23 '24 17:07 gastaldi

Thank you both :)

aloubyansky avatar Jul 23 '24 20:07 aloubyansky

Given everything, I'm going to call this "not a bug". But we can reopen discussion if needed.

dmlloyd avatar Sep 27 '24 15:09 dmlloyd