Skip to content

Instantly share code, notes, and snippets.

@dos65
Created February 8, 2017 14:51
Show Gist options
  • Save dos65/898f3c8a09b1a7178cfbb683b8141a87 to your computer and use it in GitHub Desktop.
Save dos65/898f3c8a09b1a7178cfbb683b8141a87 to your computer and use it in GitHub Desktop.
import sbt._
import sbt.Keys._
import complete.DefaultParsers._
import ComponentVersionsKeys._
object ComponentVersionsKeys {
lazy val versionFile = settingKey[File]("Version file")
lazy val projectTagName = settingKey[String]("Project name for tag naming")
lazy val latestRelease = settingKey[Semver]("Latest project release")
lazy val latestTagName = settingKey[String]("Latest tag name for project")
lazy val release = inputKey[Unit]("Release task")
}
object ComponentVersions {
val DefaultVersion = Semver("0.0.1")
lazy val settings = Seq(
versionFile <<= baseDirectory( _ / "version" ),
latestRelease <<= Def.setting({
val f = versionFile.value
IO.touch(f, false)
val content = IO.readLines(f)
content.headOption.map(Semver(_))
.getOrElse({
IO.write(f, DefaultVersion.toString)
DefaultVersion
})
}),
latestTagName := projectTagName.value + "_" + latestRelease.value.toString,
version <<= Def.setting({
val v = latestRelease.value.toString
val expected = latestTagName.value
val isTag = Git.pointsAtTags.contains(expected)
if (isTag) {
v
} else {
val sha = Git.head.substring(0, 9)
s"$v-$sha"
}
}),
release := {
val log = streams.value.log
val args = spaceDelimited("<arg>").parsed
val number = args.headOption match {
case Some("major") => Major
case Some("minor") => Minor
case Some("patch") => Patch
case _ => sys.error("You must specify number to bump. Possible values: major, minor, patch")
}
val next = latestRelease.value.bump(number).toString
log.info(s"Next version: $next")
val f = versionFile.value
IO.write(f, next)
Git.add()
Git.commit(s"Release $next for ${projectTagName.value}")
Git.push(Git.currentBranch)
val tagName = projectTagName.value + "_" + next
Git.tag(tagName)
Git.push(tagName)
}
)
}
object Git {
def add(): Unit =
Seq("git", "add", ".") !
def commit(description: String): Unit =
Seq("git", "commit", "-n" , "-m", description) !
def tag(name: String): Unit =
Seq("git", "tag", name) !
def push(ref: String): Unit =
Seq("git", "push", "origin", ref) !
def head: String =
(Seq("git", "rev-parse", "HEAD") !!).trim
def pointsAtTags: List[String] =
(Seq("git", "tag", "-l", "--points-at", "HEAD") !!).split("\n").toList
def currentBranch: String =
(Seq("git", "rev-parse", "--abbrev-ref", "HEAD")!!).trim
}
sealed trait VersionNumber
case object Major extends VersionNumber
case object Minor extends VersionNumber
case object Patch extends VersionNumber
case class Semver(
major: Int,
minor: Int,
patch: Int) {
def bump(n: VersionNumber): Semver = n match {
case Major => copy(major = major + 1, minor = 0, patch = 0)
case Minor => copy(minor = minor + 1, patch = 0)
case Patch => copy(patch = patch + 1)
}
override def toString: String = s"$major.$minor.$patch"
}
object Semver {
import scala.util.matching.Regex
private val pattern = ("\\s*[v=]*\\s*(\\d+)" // major
+ "\\.(\\d+)" // minor
+ "\\.(\\d+)" // patch
+ "(-\\d+-?)?" // build
+ "([a-zA-Z-+][a-zA-Z0-9-\\.:]*)?")r // tag
def apply(s: String): Semver = pattern.findFirstMatchIn(s) match {
case Some(m) => toSemver(m)
case None => throw new IllegalArgumentException(s"Invalid semver string:$version")
}
private def toSemver(m: Regex.Match): Semver = {
val groups = m.subgroups
Semver(
groups(0).toInt,
groups(1).toInt,
groups(2).toInt
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment