First complete plugin implementation.

This commit is contained in:
Pat Garrity 2024-03-07 22:00:26 -06:00
parent 2c7ceabe7a
commit 73f35a406d
Signed by: pfm
GPG key ID: 5CA5D21BAB7F3A76
7 changed files with 221 additions and 20 deletions

View file

@ -8,7 +8,7 @@ externalResolvers := Seq(
)
val ProjectName: String = "sbt-gs-calver"
val Description: String = "SBT 1.9.0+ plugin for Git-based semantic versioning."
val Description: String = "SBT 1.9.0+ plugin for calendar versioning."
def getProperty[A](
name: String,

View file

@ -1 +1 @@
sbt.version=1.9.8
sbt.version=1.9.9

View file

@ -1,6 +1,169 @@
package gs
case class CalVer(value: String)
import java.time.LocalDate
import scala.collection.mutable.ListBuffer
/**
* Representation of a rendered Calendar Version.
*
* @param value The version string.
* @param pattern The pattern which rendered the version string.
*/
case class CalVer(
value: String,
pattern: CalVer.Pattern
)
object CalVer {
/**
* Render the given pattern to a Calendar Version.
*
* @param pattern The pattern to render.
* @return The rendered CalVer value.
*/
def render(pattern: Pattern): CalVer = {
val today = LocalDate.now()
CalVer(
value = pattern.items.map {
case Left(component) =>
component match {
case Component.YYYY => today.getYear().toString()
case Component.MM => today.getMonthValue().toString()
case Component.DD => today.getDayOfMonth().toString()
case Component.Label(label) => label
case Component.GitSha(length) => Git.getSha(length)
}
case Right(delimiter) => Delimiter.render(delimiter)
}.mkString,
pattern = pattern
)
}
object Defaults {
/**
* Default pattern for release versions.
*/
val ReleasePattern: Pattern =
Pattern
.builder(Component.YYYY)
.addDelimiter(Delimiter.Dot)
.addComponent(Component.MM)
.addDelimiter(Delimiter.Dot)
.addComponent(Component.DD)
.addDelimiter(Delimiter.Hyphen)
.addComponent(Component.GitSha(7))
.build()
/**
* Default pattern for pre-release versions.
*/
val PreReleasePattern: Pattern =
Pattern
.builder(Component.YYYY)
.addDelimiter(Delimiter.Dot)
.addComponent(Component.MM)
.addDelimiter(Delimiter.Dot)
.addComponent(Component.DD)
.addDelimiter(Delimiter.Hyphen)
.addComponent(Component.Label("SNAPSHOT"))
.build()
}
sealed trait Component
object Component {
/**
* CalVer Component: Year.
*/
case object YYYY extends Component
/**
* CalVer Component: Month (1-12), without a leading zero.
*/
case object MM extends Component
/**
* CalVer Component: Day of Month, without a leading zero.
*/
case object DD extends Component
/**
* CalVer Component: Label.
*
* This component contains an arbitrary string value.
*
* @param value The value of the label.
*/
case class Label(value: String) extends Component
/**
* CalVer Component. Git SHA.
*
* This component defines the length (first N characters) of the Git SHA to
* take from the current branch of the current repository. An empty string
* is used if lookup fails or no commits exist.
*
* @param length The number of characters of the Git SHA to use.
*/
case class GitSha(length: Int) extends Component
def describe(component: Component): String = component match {
case YYYY => "YYYY"
case MM => "MM"
case DD => "DD"
case Label(value) => value
case GitSha(length) => s"SHA($length)"
}
}
sealed abstract class Delimiter(val value: String)
object Delimiter {
case object Dot extends Delimiter(".")
case object Hyphen extends Delimiter("-")
case object Plus extends Delimiter("+")
case object Underscore extends Delimiter("_")
def render(delimiter: Delimiter): String = delimiter.value
}
final class Pattern private (val items: List[Pattern.Item]) {
lazy val str: String =
items.map {
case Left(component) => Component.describe(component)
case Right(delimiter) => Delimiter.render(delimiter)
}.mkString
override def toString(): String = str
}
object Pattern {
private type Item = Either[Component, Delimiter]
def builder(component: Component): Builder = Builder(component)
final class Builder private () {
private val buffer: ListBuffer[Item] = new ListBuffer()
def addComponent(component: Component): Builder = {
val _ = buffer.append(Left(component))
this
}
def addDelimiter(delimiter: Delimiter): Builder = {
val _ = buffer.append(Right(delimiter))
this
}
def build(): Pattern = new Pattern(buffer.toList)
}
object Builder {
def apply(component: Component): Builder = {
val b = new Builder()
b.addComponent(component)
b
}
}
}
}

View file

@ -12,6 +12,31 @@ object CalVerKeys {
"Calculated CalVer."
)
/**
* SBT setting which defines the CalVer pattern used to calculate the final
* version. This should not be set manually, please use
* `calVerReleasePattern` and `calVerPreReleasePattern`.
*/
lazy val calVerPattern = settingKey[CalVer.Pattern](
"Selected CalVer pattern."
)
/**
* User-defined SBT setting which defines the CalVer pattern to use for a
* release build.
*/
lazy val calVerReleasePattern = settingKey[Option[CalVer.Pattern]](
"Pattern to use for calculating CalVer for release builds."
)
/**
* User-defined SBT setting which defines the CalVer pattern to use for a
* pre-release build.
*/
lazy val calVerPreReleasePattern = settingKey[Option[CalVer.Pattern]](
"Pattern to use for calculating CalVer for pre-release builds."
)
/** Task which emits the current version at the informational log level.
*/
lazy val calVerInfo = taskKey[Unit](

View file

@ -11,9 +11,22 @@ object CalVerPlugin extends AutoPlugin {
// Perform all version calculations and expose as a variable.
lazy val calVerDefaults: Seq[Setting[_]] = {
// Expose the relevant values as setting keys.
val isRelease = PluginProperties.isRelease()
Seq(
calVer := ""
calVerReleasePattern := calVerReleasePattern.value.orElse(
Some(CalVer.Defaults.ReleasePattern)
),
calVerPreReleasePattern := calVerPreReleasePattern.value.orElse(
Some(CalVer.Defaults.PreReleasePattern)
),
calVerPattern := {
if (isRelease) {
calVerReleasePattern.value.getOrElse(CalVer.Defaults.ReleasePattern)
} else {
calVerPreReleasePattern.value.getOrElse(CalVer.Defaults.PreReleasePattern)
}
} ,
calVer := CalVer.render(calVerPattern.value).value
)
}
@ -25,6 +38,7 @@ object CalVerPlugin extends AutoPlugin {
calVerInfo := {
val log = Keys.streams.value.log
log.info(s"[CalVer] Version: ${calVer.value}")
log.info(s"[CalVer] Pattern: ${calVerPattern.value}")
}
)

View file

@ -1,15 +1,16 @@
package gs
//import java.io.File
//import scala.util.Try
object Git {
/*def getLatestSemVer(): SemVer = {
// Suppress all error output. Suppress exceptions for the failed process.
// Capture the standard output and parse it if the command succeeds.
/**
* Get the latest SHA. If there are no commits on this branch, the empty
* string will be returned.
*
* @param length The number of characters to take from the SHA.
* @return The latest SHA.
*/
def getSha(length: Int): String = {
val result = os
.proc("git", "describe", "--tags", "--abbrev=0")
.proc("git", "rev-parse", "HEAD")
.call(
stderr = os.ProcessOutput(
(
@ -21,9 +22,8 @@ object Git {
)
if (result.exitCode != 0)
SemVer.DefaultVersion
result.out.text().take(length)
else
SemVer.parse(result.out.text()).getOrElse(SemVer.DefaultVersion)
}*/
""
}
}

View file

@ -24,9 +24,8 @@ object PluginProperties {
/** Use one of the following to calculate an incremented release version:
*
* - `sbt -Drelease=major`
* - `sbt -Drelease=minor`
* - `sbt -Drelease=patch`
* - `sbt -Drelease=true`
* - `sbt -Drelease=false`
*/
val ReleaseProperty: String = "release"