Skip to content

Commit b143094

Browse files
Vampirekrzema12
andauthored
fix: fix erroneous version parsing and comparison (#1831)
Co-authored-by: Piotr Krzeminski <[email protected]>
1 parent e8dbda3 commit b143094

File tree

2 files changed

+74
-46
lines changed
  • shared-internal/src
    • main/kotlin/io/github/typesafegithub/workflows/shared/internal/model
    • test/kotlin/io/github/typesafegithub/workflows/shared/internal/model

2 files changed

+74
-46
lines changed

shared-internal/src/main/kotlin/io/github/typesafegithub/workflows/shared/internal/model/Version.kt

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,34 @@ data class Version(
66
val version: String,
77
private val dateProvider: suspend () -> ZonedDateTime? = { null },
88
) : Comparable<Version> {
9-
val input: String = version.removePrefix("v").removePrefix("V")
10-
val major = input.substringBefore(".").toIntOrNull() ?: 0
11-
val minor = input.substringAfter(".").substringBefore(".").toIntOrNull() ?: 0
12-
val patch = input.substringAfterLast(".").toIntOrNull() ?: 0
9+
private val versionParts: List<String> = version.removePrefix("v").removePrefix("V").split('.')
10+
private val versionIntParts: List<Int?> = versionParts.map { it.toIntOrNull() }
11+
val major: Int = versionIntParts.getOrNull(0) ?: 0
12+
val minor: Int = versionIntParts.getOrNull(1) ?: 0
13+
val patch: Int = versionIntParts.getOrNull(2) ?: 0
1314

1415
override fun compareTo(other: Version): Int {
15-
val c1 = major.compareTo(other.major)
16-
val c2 = minor.compareTo(other.minor)
17-
val c3 = patch.compareTo(other.patch)
18-
return when {
19-
c1 != 0 -> c1
20-
c2 != 0 -> c2
21-
c3 != 0 -> c3
22-
else -> version.compareTo(other.version)
16+
versionParts.forEachIndexed { i, part ->
17+
val otherPart = other.versionParts.getOrNull(i)
18+
if (otherPart == null) return 1
19+
val intPart = versionIntParts[i]
20+
val otherIntPart = other.versionIntParts[i]
21+
if ((intPart == null) && (otherIntPart == null)) {
22+
val comparison = part.compareTo(otherPart)
23+
if (comparison != 0) return comparison
24+
} else if (intPart == null) {
25+
return -1
26+
} else if (otherIntPart == null) {
27+
return 1
28+
}
2329
}
30+
if (versionParts.size < other.versionParts.size) return -1
31+
return version.compareTo(other.version)
2432
}
2533

2634
override fun toString(): String = version
2735

28-
fun isMajorVersion(): Boolean = version.removePrefix("v").removePrefix("V").toIntOrNull() != null
36+
fun isMajorVersion(): Boolean = versionIntParts.singleOrNull() != null
2937

3038
suspend fun getReleaseDate() = dateProvider()
3139
}

shared-internal/src/test/kotlin/io/github/typesafegithub/workflows/shared/internal/model/VersionTest.kt

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,65 @@ package io.github.typesafegithub.workflows.shared.internal.model
22

33
import io.kotest.assertions.assertSoftly
44
import io.kotest.core.spec.style.FunSpec
5+
import io.kotest.matchers.comparables.shouldBeGreaterThan
56
import io.kotest.matchers.shouldBe
67

78
class VersionTest :
8-
FunSpec({
9-
context("parsing") {
10-
listOf(
11-
Pair("v1.2.3", Triple(1, 2, 3)),
12-
Pair("1.2.3", Triple(1, 2, 3)),
13-
Pair("v1.2.3.4", Triple(1, 2, 4)),
14-
Pair("1.2.3.4", Triple(1, 2, 4)),
15-
Pair("v1.2", Triple(1, 2, 2)),
16-
Pair("v3", Triple(3, 3, 3)),
17-
Pair("V3", Triple(3, 3, 3)),
18-
Pair("v3-prerelease", Triple(0, 0, 0)),
19-
Pair("beta-v3", Triple(0, 0, 0)),
20-
).forEach { (string, version) ->
21-
test("correctly parses $string") {
22-
val parsedVersion = Version(string)
23-
assertSoftly {
24-
parsedVersion.major shouldBe version.first
25-
parsedVersion.minor shouldBe version.second
26-
parsedVersion.patch shouldBe version.third
9+
FunSpec(
10+
{
11+
context("parsing") {
12+
listOf(
13+
Pair("v1.2.3", Triple(1, 2, 3)),
14+
Pair("1.2.3", Triple(1, 2, 3)),
15+
Pair("v1.2.3.4", Triple(1, 2, 3)),
16+
Pair("1.2.3.4", Triple(1, 2, 3)),
17+
Pair("v1.2", Triple(1, 2, 0)),
18+
Pair("v3", Triple(3, 0, 0)),
19+
Pair("V3", Triple(3, 0, 0)),
20+
Pair("v3-prerelease", Triple(0, 0, 0)),
21+
Pair("beta-v3", Triple(0, 0, 0)),
22+
).forEach { (string, version) ->
23+
test("correctly parses $string") {
24+
val parsedVersion = Version(string)
25+
assertSoftly {
26+
parsedVersion.major shouldBe version.first
27+
parsedVersion.minor shouldBe version.second
28+
parsedVersion.patch shouldBe version.third
29+
}
2730
}
2831
}
2932
}
30-
}
3133

32-
context("isMajorVersion") {
33-
listOf(
34-
Pair("v1.2.3", false),
35-
Pair("v1.2", false),
36-
Pair("v3", true),
37-
Pair("V3", true),
38-
Pair("v3-prerelease", false),
39-
Pair("beta-v3", false),
40-
).forEach { (version, isMajor) ->
41-
test("isMajorVersion works correctly for $version") {
42-
Version(version).isMajorVersion() shouldBe isMajor
34+
context("isMajorVersion") {
35+
listOf(
36+
Pair("v1.2.3", false),
37+
Pair("v1.2", false),
38+
Pair("v3", true),
39+
Pair("V3", true),
40+
Pair("v3-prerelease", false),
41+
Pair("beta-v3", false),
42+
).forEach { (version, isMajor) ->
43+
test("isMajorVersion works correctly for $version") {
44+
Version(version).isMajorVersion() shouldBe isMajor
45+
}
46+
}
47+
}
48+
49+
context("compareTo") {
50+
listOf(
51+
Triple("v1.2.1", "v1.2", true),
52+
Triple("alpha", "beta", false),
53+
Triple("1.2.3", "1.2.3.4", false),
54+
Triple("3.2.1", "v3", true),
55+
).forEach { (left, right, leftIsGreater) ->
56+
test("compareTo works correctly for $left vs. $right") {
57+
if (leftIsGreater) {
58+
Version(left) shouldBeGreaterThan Version(right)
59+
} else {
60+
Version(right) shouldBeGreaterThan Version(left)
61+
}
62+
}
4363
}
4464
}
45-
}
46-
})
65+
},
66+
)

0 commit comments

Comments
 (0)