diff --git a/README.md b/README.md index 9a886eb7..2c88cbec 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,9 @@ The default settings make use of the helper class [`Version`](https://github.com // strip the qualifier off the input version, eg. 1.2.1-SNAPSHOT -> 1.2.1 releaseVersion := { ver => Version(ver).map(_.withoutQualifier.string).getOrElse(versionFormatError(ver)) } +// strip the snapshot off the input version, eg. 1.2.1-SNAPSHOT -> 1.2.1 +releaseVersion := { ver => Version(ver).map(_.withoutSnapshot.string).getOrElse(versionFormatError(ver)) } + // bump the version and append '-SNAPSHOT', eg. 1.2.1 -> 1.3.0-SNAPSHOT releaseNextVersion := { ver => Version(ver).map(_.bump(releaseVersionBump.value).asSnapshot.string).getOrElse(versionFormatError(ver)) diff --git a/src/main/scala/Version.scala b/src/main/scala/Version.scala index c64482d4..dec70e11 100644 --- a/src/main/scala/Version.scala +++ b/src/main/scala/Version.scala @@ -8,11 +8,36 @@ object Version { } object Bump { - case object Major extends Bump { def bump = _.bumpMajor } - case object Minor extends Bump { def bump = _.bumpMinor } - case object Bugfix extends Bump { def bump = _.bumpBugfix } - case object Nano extends Bump { def bump = _.bumpNano } - case object Next extends Bump { def bump = _.bump } + + /** + * Strategy to always bump the major version by default. Ex. 1.0.0 would be bumped to 2.0.0 + */ + case object Major extends Bump { def bump: Version => Version = _.bumpMajor } + /** + * Strategy to always bump the minor version by default. Ex. 1.0.0 would be bumped to 1.1.0 + */ + case object Minor extends Bump { def bump: Version => Version = _.bumpMinor } + /** + * Strategy to always bump the bugfix version by default. Ex. 1.0.0 would be bumped to 1.0.1 + */ + case object Bugfix extends Bump { def bump: Version => Version = _.bumpBugfix } + /** + * Strategy to always bump the nano version by default. Ex. 1.0.0.0 would be bumped to 1.0.0.1 + */ + case object Nano extends Bump { def bump: Version => Version = _.bumpNano } + + case object Next extends Bump { def bump: Version => Version = _.bump } + /** + * Strategy to always increment to the next version from smallest to greatest + * Ex: + * Major: 1 becomes 2 + * Minor: 1.0 becomes 1.1 + * Bugfix: 1.0.0 becomes 1.0.1 + * Nano: 1.0.0.0 becomes 1.0.0.1 + * Qualifier with version number: 1.0-RC1 becomes 1.0-RC2 + * Qualifier without version number: 1.0-alpha becomes 1.0 + */ + case object NextWithQualifier extends Bump { def bump: Version => Version = _.bumpWithQualifier } val default = Next } @@ -46,6 +71,30 @@ case class Version(major: Int, subversions: Seq[Int], qualifier: Option[String]) .getOrElse(bumpedMajor) } + def bumpWithQualifier = { + val maybeBumpedPrerelease = qualifier.collect { + case rawQualifier @ Version.PreReleaseQualifierR() => + val qualifierEndsWithNumberRegex = """[0-9]*$""".r + + val opt = for { + versionNumberQualifierStr <- qualifierEndsWithNumberRegex.findFirstIn(rawQualifier) + versionNumber <- Try(versionNumberQualifierStr.toInt) + .toRight(new Exception(s"Version number not parseable to a number. Version number received: $versionNumberQualifierStr")) + .toOption + newVersionNumber = versionNumber + 1 + newQualifier = rawQualifier.replaceFirst(versionNumberQualifierStr, newVersionNumber.toString) + } yield Version(major, subversions, Some(newQualifier)) + + opt.getOrElse(copy(qualifier = None)) + } + def maybeBumpedLastSubversion = bumpSubversionOpt(subversions.length-1) + def bumpedMajor = copy(major = major + 1) + + maybeBumpedPrerelease + .orElse(maybeBumpedLastSubversion) + .getOrElse(bumpedMajor) + } + def bumpMajor = copy(major = major + 1, subversions = Seq.fill(subversions.length)(0)) def bumpMinor = maybeBumpSubversion(0) def bumpBugfix = maybeBumpSubversion(1) @@ -65,7 +114,19 @@ case class Version(major: Int, subversions: Seq[Int], qualifier: Option[String]) def bump(bumpType: Version.Bump): Version = bumpType.bump(this) def withoutQualifier = copy(qualifier = None) - def asSnapshot = copy(qualifier = Some("-SNAPSHOT")) + def asSnapshot = copy(qualifier = qualifier.map { qualifierStr => + s"$qualifierStr-SNAPSHOT" + }.orElse(Some("-SNAPSHOT"))) + + def withoutSnapshot: Version = copy(qualifier = qualifier.flatMap { qualifierStr => + val snapshotRegex = """-SNAPSHOT""".r + val newQualifier = snapshotRegex.replaceFirstIn(qualifierStr, "") + if (newQualifier == qualifierStr) { + None + } else { + Some(newQualifier) + } + }) def string = "" + major + mkString(subversions) + qualifier.getOrElse("") diff --git a/src/test/scala/VersionSpec.scala b/src/test/scala/VersionSpec.scala index a0f12f32..51f37429 100644 --- a/src/test/scala/VersionSpec.scala +++ b/src/test/scala/VersionSpec.scala @@ -9,6 +9,46 @@ object VersionSpec extends Specification { case None => sys.error("Can't parse version " + v) } + "Version bumping with Qualifier" should { + def bump(v: String) = version(v).bumpWithQualifier.string + + "bump the major version if there's only a major version" in { + bump("1") must_== "2" + } + "bump the minor version if there's only a minor version" in { + bump("1.2") must_== "1.3" + } + "bump the bugfix version if there's only a bugfix version" in { + bump("1.2.3") must_== "1.2.4" + } + "bump the nano version if there's only a nano version" in { + bump("1.2.3.4") must_== "1.2.3.5" + } + "drop the qualifier if it's a pre release and there is no version number at the end" in { + bump("1-rc") must_== "1" + bump("1-beta") must_== "1" + bump("1-alpha") must_== "1" + } + "bump the qualifier if it's a pre release and there is a version number at the end" in { + bump("1-rc1") must_== "1-rc2" + bump("1.2-rc1") must_== "1.2-rc2" + bump("1.2.3-rc1") must_== "1.2.3-rc2" + + bump("1-RC1") must_== "1-RC2" + bump("1-M1") must_== "1-M2" + bump("1-rc-1") must_== "1-rc-2" + bump("1-rc.1") must_== "1-rc.2" + bump("1-beta-1") must_== "1-beta-2" + bump("1-beta.1") must_== "1-beta.2" + } + "not drop the qualifier if it's not a pre release" in { + bump("1.2.3-Final") must_== "1.2.4-Final" + } + "not drop the post-nano qualifier if it's not a pre release" in { + bump("1.2.3.4-Final") must_== "1.2.3.5-Final" + } + } + "Version bumping" should { def bump(v: String) = version(v).bump.string @@ -92,4 +132,13 @@ object VersionSpec extends Specification { } } + "Version as snapshot" should { + def snapshot(v: String) = version(v).asSnapshot.string + "include qualifier if it exists" in { + snapshot("1.0.0-RC1") must_== "1.0.0-RC1-SNAPSHOT" + } + "have no qualifier if none exists" in { + snapshot("1.0.0") must_== "1.0.0-SNAPSHOT" + } + } }