Scripts/convention/src/main/kotlin/io/gitlab/jfronny/scripts/SemanticVersion.kt

75 lines
3.2 KiB
Kotlin

package io.gitlab.jfronny.scripts
data class SemanticVersion(val major: Int, val minor: Int, val patch: Int, val type: VersionType, val build: String?): Comparable<SemanticVersion> {
init {
require(build == null || buildPattern.matches(build)) { "Illegal build string" }
}
override fun compareTo(other: SemanticVersion): Int =
when {
major > other.major -> 1
major < other.major -> -1
minor > other.minor -> 1
minor < other.minor -> -1
patch > other.patch -> 1
patch < other.patch -> -1
else -> when {
type != other.type -> type.compareTo(other.type)
build == null && other.build != null -> -1
build != null && other.build == null -> 1
build != null && other.build != null -> build.compareTo(other.build)
else -> 0
}
}
override fun toString(): String {
return "$major.$minor.$patch" + when (type) {
VersionType.RELEASE -> ""
else -> "-${type.semanticName}"
} + if (build == null) "" else "+$build"
}
fun unclassifiedToString(): String {
return "$major.$minor.$patch" + if (build == null) "" else "+$build"
}
fun incrementBy(commitType: CommitType, versionType: VersionType = VersionType.RELEASE, build: String? = null): SemanticVersion = when(commitType) {
CommitType.FIX -> SemanticVersion(major, minor, patch + 1, versionType, build)
CommitType.FEAT -> SemanticVersion(major, minor + 1, 0, versionType, build)
CommitType.BREAKING -> SemanticVersion(major + 1, 0, 0, versionType, build)
}
fun withType(versionType: VersionType) = SemanticVersion(major, minor, patch, versionType, build)
companion object {
private val identifier = Regex("[a-zA-Z1-9][a-zA-Z0-9]*")
private val buildPattern = Regex("$identifier(?:\\.$identifier)+")
private val number = Regex("[1-9][0-9]*|0")
private val versionCore = Regex("($number)\\.($number)\\.($number)")
private val legacyVersion = Regex("([vba]|rc)$versionCore(\\+$buildPattern)?")
private val restrictedSemver = Regex("$versionCore(-(?:alpha|beta|rc))?(\\+$buildPattern)?")
fun parse(source: String): SemanticVersion {
val legacyMatch = legacyVersion.matchEntire(source)
if (legacyMatch != null) {
val m = legacyMatch.groupValues
return SemanticVersion(
m[2].toInt(), m[3].toInt(), m[4].toInt(),
VersionType.byShorthand(m[1])!!,
m[5].ifEmpty { null }
)
}
val semverMatch = restrictedSemver.matchEntire(source)
if (semverMatch != null) {
val m = semverMatch.groupValues
return SemanticVersion(
m[1].toInt(), m[2].toInt(), m[3].toInt(),
VersionType.byName(m[4].ifEmpty { "release" })!!,
m[5].ifEmpty { null }
)
}
throw IllegalArgumentException("Source does not match supported version patterns: $source")
}
}
}