zafarkhaja / jsemver

Java implementation of the SemVer Specification
MIT License
429 stars 82 forks source link

Sorting of SNAPSHOT versions works differently to Maven and Gradle #62

Closed klu2 closed 5 months ago

klu2 commented 1 year ago

Consider the following Kotlin JUnit test, which sorts a couple of version numbers with 3 different libraries:

package io.cloudflight.gradle.autoconfigure.util

import com.github.zafarkhaja.semver.Version
import org.apache.maven.artifact.versioning.ComparableVersion
import org.gradle.util.internal.VersionNumber
import org.junit.jupiter.api.Test

class VersionUtilTest {

    private val versions = listOf(
        "1.0.0",
        "1.0.0-SNAPSHOT",
        "1.0.0-rc.1.8+3bb4161",
        "1.0.0-rc.1",
        "1.0.0-milestone.1.0+2cc3321",
        "1.0.0-rc.1.9+4cc4322",
    )

    @Test
    fun sortVersionsWithMaven() {
        println(
            versions.map { ComparableVersion(it) }.sorted().joinToString(separator = System.lineSeparator())
        )
    }

    @Test
    fun sortVersionsWithGradle() {
        println(
            versions.map { VersionNumber.parse(it) }.sorted().joinToString(separator = System.lineSeparator())
        )
    }

    @Test
    fun sortVersionsWithJavaSemver() {
        println(
            versions.map { Version.valueOf(it) }.sorted().joinToString(separator = System.lineSeparator())
        )
    }
}

The Maven and Gradle classes return:

1.0.0-milestone.1.0+2cc3321
1.0.0-rc.1
1.0.0-rc.1.8+3bb4161
1.0.0-rc.1.9+4cc4322
1.0.0-SNAPSHOT
1.0.0

whereas Java Semver returns:

1.0.0-SNAPSHOT
1.0.0-milestone.1.0+2cc3321
1.0.0-rc.1
1.0.0-rc.1.8+3bb4161
1.0.0-rc.1.9+4cc4322
1.0.0

I didn't find anything about -SNAPSHOT handling in the Semver Specification but simply the fact that the official Maven and Gradle libraries are working differently here, seems problematic to me.

We discovered this issue during discussing https://github.com/ajoberstar/reckon/issues/189.

Happy about your feedback

klu2 commented 1 year ago

Please also check my latest comment here https://github.com/ajoberstar/reckon/issues/189#issuecomment-1310077212

It seems that when it comes to details, Maven and Gradle also differ, so it may make sense to stick to the plain specification in this library - but it would probably be worth mentioning that neither Maven nor Gradle do so.

klu2 commented 1 year ago

you might also like https://github.com/cloudflightio/semantic-versioning

zafarkhaja commented 1 year ago

Hello Klaus!

Sorry it took me this long to get back to you. And thank you for sharing your findings on the matter.

I believe it has to do with the fact that the Specification implies the pre-release versions are case-sensitive (semver/semver#176) and the libraries/tools that don't claim to adhere to the Specification, don't have to play by the rules :)

zafarkhaja commented 5 months ago

After taking another look at the issue, feels like there's not much to add really.

In summary, thanks to the scripts and examples provided by @klu2, it appears that neither of the 2 most popular build tools fully comply with SemVer when it comes to comparing versions. That's something to keep in mind.

On the other hand, Java SemVer strives to strictly follow the specification, according to which "identifiers with letters or hyphens are compared lexically in ASCII sort order" (SemVer 2.0.0, p.11), in a case-sensitive manner (semver/semver#176).