From 0e40cc68fef5292627b2ce989bfbd966a531ea02 Mon Sep 17 00:00:00 2001 From: JFronny Date: Sun, 9 Jun 2024 10:00:30 +0200 Subject: [PATCH] fix(autoversion): support additional version formats --- .../gitlab/jfronny/scripts/SemanticVersion.kt | 49 +++++++++---------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/convention/src/main/kotlin/io/gitlab/jfronny/scripts/SemanticVersion.kt b/convention/src/main/kotlin/io/gitlab/jfronny/scripts/SemanticVersion.kt index f9286df..ec844cf 100644 --- a/convention/src/main/kotlin/io/gitlab/jfronny/scripts/SemanticVersion.kt +++ b/convention/src/main/kotlin/io/gitlab/jfronny/scripts/SemanticVersion.kt @@ -1,31 +1,24 @@ package io.gitlab.jfronny.scripts -data class SemanticVersion(val major: Int, val minor: Int, val patch: Int, val type: VersionType, val build: String?): Comparable { +/** + * A semantic version representation. + * Not strictly following the semver spec, but a subset of it. + * For example, the pre-release type identifier is restricted to alpha, beta, rc followed by an optional number. + * Parsing also supports legacy version strings like v1.2.3, b1.2.3, a1.2.3, rc1.2.3. + */ +data class SemanticVersion(val major: Int, val minor: Int, val patch: Int, val type: VersionType, val typeSupplement: Int?, val build: String?): Comparable { 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 compareTo(other: SemanticVersion): Int { + return compareValuesBy(this, other, SemanticVersion::major, SemanticVersion::minor, SemanticVersion::patch, SemanticVersion::type, SemanticVersion::typeSupplement, SemanticVersion::build) + } override fun toString(): String { return "$major.$minor.$patch" + when (type) { VersionType.RELEASE -> "" - else -> "-${type.semanticName}" + else -> "-${type.semanticName}" + if(typeSupplement != null) ".$typeSupplement" else "" } + if (build == null) "" else "+$build" } @@ -34,28 +27,29 @@ data class SemanticVersion(val major: Int, val minor: Int, val patch: Int, val t } 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) + CommitType.FIX -> SemanticVersion(major, minor, patch + 1, versionType, null, build) + CommitType.FEAT -> SemanticVersion(major, minor + 1, 0, versionType, null, build) + CommitType.BREAKING -> SemanticVersion(major + 1, 0, 0, versionType, null, build) } - fun withType(versionType: VersionType) = SemanticVersion(major, minor, patch, versionType, build) + fun withType(versionType: VersionType) = SemanticVersion(major, minor, patch, versionType, null, 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 versionCore = Regex("($number)\\.($number)(?:\\.($number))?") private val legacyVersion = Regex("([vba]|rc)$versionCore(\\+$buildPattern)?") - private val restrictedSemver = Regex("$versionCore(?:-(alpha|beta|rc))?(\\+$buildPattern)?") + private val restrictedSemver = Regex("$versionCore(?:-(alpha|beta|rc)(\\.?\\d+)?)?(\\+$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(), + m[2].toInt(), m[3].toInt(), m[4].ifEmpty { "0" }.toInt(), VersionType.byShorthand(m[1])!!, + null, m[5].ifEmpty { null } ) } @@ -63,9 +57,10 @@ data class SemanticVersion(val major: Int, val minor: Int, val patch: Int, val t if (semverMatch != null) { val m = semverMatch.groupValues return SemanticVersion( - m[1].toInt(), m[2].toInt(), m[3].toInt(), + m[1].toInt(), m[2].toInt(), m[3].ifEmpty { "0" }.toInt(), VersionType.byName(m[4].ifEmpty { "release" })!!, - m[5].ifEmpty { null } + m[5].ifEmpty { null }?.trimStart('.')?.toInt(), + m[6].ifEmpty { null }?.substring(1) ) } throw IllegalArgumentException("Source does not match supported version patterns: $source")