package io.gitlab.jfronny.scripts data class SemanticVersion(val major: Int, val minor: Int, val patch: Int, val type: VersionType, 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 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") } } }