aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakob Odersky <jakob@odersky.com>2018-06-29 14:45:59 -0700
committerGitHub <noreply@github.com>2018-06-29 14:45:59 -0700
commit2fe92035d61b4cac0db5cbf32c108b64e3437ead (patch)
treef0ac027a6f4bd7a943a2295f8e8add0ed8f6e67f /src
parentb2f168fecedce20727835a0ea39c90668f117a30 (diff)
downloadsbt-settings-2fe92035d61b4cac0db5cbf32c108b64e3437ead.tar.gz
sbt-settings-2fe92035d61b4cac0db5cbf32c108b64e3437ead.tar.bz2
sbt-settings-2fe92035d61b4cac0db5cbf32c108b64e3437ead.zip
Refactor settings to use autoplugins (#4)
**Overview and motivation** This consolidates settings that were previously implemented as functions and/or implicit conversions into a suite of sbt autoplugins. The rationale is that this is well-defined pattern by sbt and allows easy build introspection with standard sbt functionality (for example, `sbt plugins` will list all active plugins in a build). Furthermore, it makes it very easy to disable certain features when required, such as removing linting during development. **Migration from current version** All features from the previous version should still be provided by the changes proposed here. The migration path is quite straight-forward: - Replace `project.driverService(name)` with `project.enablePlugins(Service)` (same goes for libraries) and make sure the project's name corresponds to the service's name - Linting, which was previously enabled by adding `lintingSettings` and `formatSettings` to a project, is automatically enabled. It may be removed by disabling the plugin: `project.dsiablePlugin(Linting)` All tasks and settings provided by sbt-settings should remain the same. **Additional features** An additional feature is that versioning is now handled the same way between libraries and services; that is, the version is derived from the latest git tag. Since services may be deployed from the same tag mutliple times, it is required that versions can be explicitly set to include additional information, such as a build number from a CI system. This was previously done interactively, using sbt's `set` command: ``` export TAG="$(sbt -no-colors version | tail -1 | awk '{ print $2 }').$TRAVIS_BUILD_NUMBER" sbt "set version := \"$TAG\"" docker:publishLocal ``` While this approach works, it has the downsides of requiring mutliple sbt invocations. The changes proposed in this PR will read the version from a VERSION environment variable first, defaulting to git if unavailable. Therefore, the additional sbt invocation can be removed with a CI script similar to the following: ``` export VERSION="$(git describe).$TRAVIS_BUILD_NUMBER"" sbt docker:publishLocal // use version in other steps ``` Using an autoplugin-based approach may also make it easier to cross-compile projects to ScalaJS and Native in the future, as support for them is built into sbt-crossproject.
Diffstat (limited to 'src')
-rwxr-xr-xsrc/main/resources/scalafmtbin12619 -> 0 bytes
-rw-r--r--src/main/scala/xyz.driver.sbt/IntegrationTestPackaging.scala44
-rw-r--r--src/main/scala/xyz.driver.sbt/Library.scala31
-rw-r--r--src/main/scala/xyz.driver.sbt/Linting.scala82
-rw-r--r--src/main/scala/xyz.driver.sbt/SbtSettings.scala390
-rw-r--r--src/main/scala/xyz.driver.sbt/Service.scala75
-rw-r--r--src/main/scala/xyz.driver.sbt/Versioning.scala31
-rw-r--r--src/sbt-test/sbt-settings/service/build.sbt3
-rw-r--r--src/sbt-test/sbt-settings/service/project/plugins.sbt5
-rw-r--r--src/sbt-test/sbt-settings/service/src/main/scala/Main.scala7
-rw-r--r--src/sbt-test/sbt-settings/service/test4
11 files changed, 248 insertions, 424 deletions
diff --git a/src/main/resources/scalafmt b/src/main/resources/scalafmt
deleted file mode 100755
index c5026e8..0000000
--- a/src/main/resources/scalafmt
+++ /dev/null
Binary files differ
diff --git a/src/main/scala/xyz.driver.sbt/IntegrationTestPackaging.scala b/src/main/scala/xyz.driver.sbt/IntegrationTestPackaging.scala
index 7f0c557..c89dcec 100644
--- a/src/main/scala/xyz.driver.sbt/IntegrationTestPackaging.scala
+++ b/src/main/scala/xyz.driver.sbt/IntegrationTestPackaging.scala
@@ -2,23 +2,18 @@ package xyz.driver.sbt
import java.nio.file._
-import scala.collection.JavaConverters._
-
-import com.lucidchart.sbt.scalafmt.ScalafmtCorePlugin.autoImport._
-import com.typesafe.sbt.packager._
import com.typesafe.sbt.packager.Keys._
-import com.typesafe.sbt.packager.docker._
import com.typesafe.sbt.packager.docker.DockerPlugin.autoImport.Docker
-import com.typesafe.sbt.packager.universal._
import com.typesafe.sbt.packager.universal.UniversalPlugin.autoImport._
-import sbt._
-import sbt.plugins._
import sbt.Keys._
+import sbt._
+
+import scala.collection.JavaConverters._
object IntegrationTestPackaging extends AutoPlugin {
- override def requires = UniversalPlugin && DockerPlugin
- override def trigger = AllRequirements
+ override def requires = Service
+ override def trigger = allRequirements
object autoImport {
lazy val IntegrationTest = config("it") extend (Test) // make test classes available
@@ -26,11 +21,11 @@ object IntegrationTestPackaging extends AutoPlugin {
import autoImport._
private def list(base: Path): Seq[(Path, String)] = base match {
- case _ if Files.isRegularFile(base) => Seq(base -> base.getFileName.toString)
case _ if Files.isDirectory(base) =>
Files.walk(base).iterator().asScala.toSeq.map { file =>
file -> base.relativize(file).toString
}
+ case file => Seq(file -> file.getFileName.toString)
}
private def configurationSettings =
@@ -39,21 +34,8 @@ object IntegrationTestPackaging extends AutoPlugin {
ivyConfigurations := overrideConfigs(IntegrationTest)(ivyConfigurations.value)
)
- private def formatSettings =
- inConfig(IntegrationTest)(scalafmtSettings) ++
- Seq(
- scalafmt in Test := {
- (scalafmt in Test).dependsOn(scalafmt in IntegrationTest).value
- },
- // test:scalafmt::test -> tests scalafmt format in src/test + src/it
- test in scalafmt in Test := {
- (test in scalafmt in Test).dependsOn(test in scalafmt in IntegrationTest).value
- }
- )
-
override def projectSettings =
configurationSettings ++
- formatSettings ++
Seq(
mappings in Universal ++= {
val cp: Seq[(File, String)] = (dependencyClasspath in IntegrationTest).value
@@ -94,16 +76,10 @@ object IntegrationTestPackaging extends AutoPlugin {
cp ++ tests ++ Seq(scriptFile -> s"bin/${normalizedName.value}-it")
},
- dockerCommands in Docker := {
- (dockerCommands in Docker).value ++ Seq(
- ExecCmd("RUN", "mkdir", "-p", "/test"),
- ExecCmd("RUN",
- "ln",
- "-s",
- s"${(defaultLinuxInstallLocation in Docker).value}/bin/${normalizedName.value}-it",
- "/test/run_integration_test.sh")
- )
- }
+ Service.autoImport.customCommands := List(
+ "mkdir -p test",
+ s"ln -s ${(defaultLinuxInstallLocation in Docker).value}/bin/${normalizedName.value}-it /test/run_integration_test.sh"
+ )
)
}
diff --git a/src/main/scala/xyz.driver.sbt/Library.scala b/src/main/scala/xyz.driver.sbt/Library.scala
new file mode 100644
index 0000000..4a5dc7c
--- /dev/null
+++ b/src/main/scala/xyz.driver.sbt/Library.scala
@@ -0,0 +1,31 @@
+package xyz.driver.sbt
+
+import sbt.Keys._
+import sbt._
+import sbt.plugins.JvmPlugin
+
+/** Common settings for a library, Driver style. */
+object Library extends AutoPlugin {
+
+ override def requires = JvmPlugin
+
+ lazy val repositorySettings: Seq[Setting[_]] = Seq(
+ resolvers += "releases" at "https://drivergrp.jfrog.io/drivergrp/releases",
+ resolvers += "snapshots" at "https://drivergrp.jfrog.io/drivergrp/snapshots"
+ )
+
+ lazy val publicationSettings: Seq[Setting[_]] = Seq(
+ publishTo := {
+ val jfrog = "https://drivergrp.jfrog.io/drivergrp/"
+ if (isSnapshot.value) Some("snapshots" at jfrog + "snapshots;build.timestamp=" + new java.util.Date().getTime)
+ else Some("releases" at jfrog + "releases")
+ }
+ )
+
+ override def projectSettings: Seq[Def.Setting[_]] = repositorySettings ++ publicationSettings ++ Seq(
+ javacOptions ++= Seq("-target", "1.8"),
+ crossScalaVersions := List("2.12.6"),
+ scalaVersion := crossScalaVersions.value.last
+ )
+
+}
diff --git a/src/main/scala/xyz.driver.sbt/Linting.scala b/src/main/scala/xyz.driver.sbt/Linting.scala
new file mode 100644
index 0000000..8a293b6
--- /dev/null
+++ b/src/main/scala/xyz.driver.sbt/Linting.scala
@@ -0,0 +1,82 @@
+package xyz.driver.sbt
+
+import com.lucidchart.sbt.scalafmt.ScalafmtCorePlugin.autoImport.{scalafmtConfig, _}
+import com.lucidchart.sbt.scalafmt.ScalafmtPlugin
+import org.scalastyle.sbt.ScalastylePlugin
+import org.scalastyle.sbt.ScalastylePlugin.autoImport.{scalastyle, scalastyleConfig}
+import sbt.Keys._
+import sbt._
+
+import scala.collection.JavaConverters._
+
+/** Enforces common formatting and catches compiler warnings. */
+object Linting extends AutoPlugin {
+
+ override def requires = ScalafmtPlugin && ScalastylePlugin
+ override def trigger = allRequirements
+
+ lazy val formatSettings: Seq[Def.Setting[_]] = Seq(
+ scalafmtConfig := {
+ val packaged = getClass.getClassLoader.getResourceAsStream("scalafmt.conf")
+ val out = file(".scalafmt.conf")
+ IO.write(out, IO.readBytes(packaged))
+ out
+ },
+ scalafmtTestOnCompile in Test := true
+ )
+
+ lazy val scalastyleSettings: Seq[Def.Setting[_]] = Seq(
+ scalastyleConfig := {
+ val stream = getClass.getClassLoader.getResourceAsStream("scalastyle-config.xml")
+ val out = file(".scalastyle-config.xml")
+ IO.write(out, IO.readBytes(stream))
+ out
+ },
+ test in Test := (test in Test).dependsOn((scalastyle in Test).toTask("")).value
+ )
+
+ lazy val scalacSettings: Seq[Def.Setting[_]] = Seq(
+ scalacOptions in Compile ++= Seq(
+ "-language:higherKinds",
+ "-language:implicitConversions",
+ "-language:postfixOps",
+ "-language:reflectiveCalls", // TODO this should be discouraged
+ "-unchecked",
+ "-deprecation",
+ "-feature",
+ "-encoding",
+ "utf8",
+ "-Xlint:_,-unused,-missing-interpolator",
+ "-Ywarn-numeric-widen",
+ "-Ywarn-dead-code",
+ "-Ywarn-unused:_,-explicits,-implicits"
+ ),
+ // Currently, scalac does not provide a way to fine-tune the treating of
+ // warnings as errors. Either all are considered errors
+ // (with -Xfatal-warnings), or none are. This hack analyzes the compiler's
+ // output and treats all warnings as errors, except for deprecations.
+ compile in Compile := {
+ val log = streams.value.log
+ val compiled = (compile in Compile).value
+ val problems = compiled.readSourceInfos().getAllSourceInfos.asScala.flatMap {
+ case (_, info) => info.getReportedProblems
+ }
+ var deprecationsOnly = true
+ problems.foreach { problem =>
+ if (!problem.message().contains("is deprecated")) {
+ deprecationsOnly = false
+ log.error(s"[fatal warning] ${problem.message()}")
+ }
+ }
+ if (!deprecationsOnly)
+ throw new FatalWarningsException("Fatal warnings: some warnings other than deprecations were found.")
+ compiled
+ }
+ )
+
+ lazy val lintSettings = formatSettings ++ scalastyleSettings ++ scalacSettings
+
+ override def projectSettings: Seq[Def.Setting[_]] = inConfig(Compile)(lintSettings) ++ inConfig(Test)(lintSettings)
+
+}
+case class FatalWarningsException(message: String) extends Exception(message)
diff --git a/src/main/scala/xyz.driver.sbt/SbtSettings.scala b/src/main/scala/xyz.driver.sbt/SbtSettings.scala
deleted file mode 100644
index 96ee267..0000000
--- a/src/main/scala/xyz.driver.sbt/SbtSettings.scala
+++ /dev/null
@@ -1,390 +0,0 @@
-package xyz.driver.sbt
-
-import com.lucidchart.sbt.scalafmt.ScalafmtCorePlugin.autoImport._
-import com.typesafe.sbt.SbtGit.git
-import com.typesafe.sbt.SbtNativePackager.autoImport._
-import com.typesafe.sbt.packager.archetypes._
-import com.typesafe.sbt.packager.docker.Cmd
-import com.typesafe.sbt.packager.docker.DockerPlugin.autoImport._
-import com.typesafe.sbt.{GitBranchPrompt, GitVersioning}
-import org.scalastyle.sbt.ScalastylePlugin.autoImport._
-import sbt.Keys._
-import sbt.{Project, State, _}
-import sbtassembly.AssemblyKeys._
-import sbtassembly._
-import sbtbuildinfo.BuildInfoPlugin
-import sbtbuildinfo.BuildInfoPlugin.autoImport.{BuildInfoKey, BuildInfoOption, _}
-import sbtrelease.ReleasePlugin.autoImport.ReleaseKeys._
-import sbtrelease.ReleasePlugin.autoImport.ReleaseTransformations._
-import sbtrelease.ReleasePlugin.autoImport._
-import sbtrelease.{Version, _}
-import scala.collection.JavaConverters._
-import IntegrationTestPackaging.autoImport.IntegrationTest
-
-// we hide the existing definition for setReleaseVersion to replace it with our own
-import sbtrelease.ReleaseStateTransformations.{setReleaseVersion => recordReleaseVersion, inquireVersions => _}
-
-/**
- * @see https://engineering.sharethrough.com/blog/2015/09/23/capturing-common-config-with-an-sbt-parent-plugin/
- */
-object SbtSettings extends AutoPlugin {
-
- val JMX_PORT = 8686
-
- object autoImport {
- lazy val formatSettings = {
- val generateScalafmtConfTask = Def.task {
- val scalafmtConfStream = getClass.getClassLoader.getResourceAsStream("scalafmt.conf")
- val formatConfFile = file(".scalafmt.conf")
- IO.write(formatConfFile, IO.readBytes(scalafmtConfStream))
- formatConfFile
- }
-
- Seq(
- scalafmtConfig := generateScalafmtConfTask.value,
- scalafmt in Compile := {
- (scalafmt in Compile).dependsOn(scalafmt in Test).value
- },
- // scalafmt::test -> tests scalafmt format in src/main + src/test (added behavior)
- test in scalafmt in Compile := {
- (test in scalafmt in Compile).dependsOn(test in scalafmt in Test).value
- },
- test in Test := {
- (test in scalafmt in Compile).value
- (test in Test).value
- }
- )
- }
-
- lazy val testScalastyle = taskKey[Unit]("testScalastyle")
-
- lazy val scalastyleSettings = {
- val generateScalastyleConfTask = Def.task {
- val stream = getClass.getClassLoader.getResourceAsStream("scalastyle-config.xml")
- val styleFile = file("scalastyle-config.xml")
- IO.write(styleFile, IO.readBytes(stream))
- Seq(styleFile)
- }
- Seq(
- resourceGenerators in Compile += generateScalastyleConfTask.taskValue,
- scalastyleConfig := file("scalastyle-config.xml"),
- testScalastyle := scalastyle.in(Compile).toTask("").value,
- testScalastyle in (Test, test) := {
- generateScalastyleConfTask.value
- (testScalastyle in (Test, test)).value
- },
- testExecution in (Test, test) := {
- generateScalastyleConfTask.value
- (testScalastyle in Compile).value
- (testScalastyle in Test).value
- (testExecution in (Test, test)).value
- }
- )
- }
-
- val scalacLintingSettings = Seq(
- scalacOptions ++= {
- Seq(
- "-Xlint:_,-unused,-missing-interpolator",
- "-Ywarn-numeric-widen",
- "-Ywarn-dead-code",
- "-Ywarn-unused:_,-explicits,-implicits"
- )
- },
- compile in Compile := {
- val compiled = (compile in Compile).value
- val problems = compiled.readSourceInfos().getAllSourceInfos.asScala.flatMap {
- case (_, info) =>
- info.getReportedProblems
- }
-
- val deprecationsOnly = problems.forall { problem =>
- problem.message().contains("is deprecated")
- }
-
- if (!deprecationsOnly) sys.error("Fatal warnings: some warnings other than deprecations were found.")
- compiled
- }
- )
-
- lazy val lintingSettings = scalacLintingSettings ++ scalastyleSettings
-
- lazy val repositoriesSettings: Seq[Setting[_]] = {
- Seq(
- resolvers += "releases" at "https://drivergrp.jfrog.io/drivergrp/releases",
- resolvers += "snapshots" at "https://drivergrp.jfrog.io/drivergrp/snapshots"
- )
- }
-
- lazy val publicationSettings: Seq[Setting[_]] = Seq(
- publishTo := {
- val jfrog = "https://drivergrp.jfrog.io/drivergrp/"
-
- if (isSnapshot.value) Some("snapshots" at jfrog + "snapshots;build.timestamp=" + new java.util.Date().getTime)
- else Some("releases" at jfrog + "releases")
- }
- )
-
- private def setVersionOnly(selectVersion: Versions => String): ReleaseStep = { st: State =>
- val vs = st
- .get(ReleaseKeys.versions)
- .getOrElse(sys.error("No versions are set! Was this release part executed before inquireVersions?"))
- val selected = selectVersion(vs)
-
- st.log.info("Setting version to '%s'." format selected)
- val useGlobal = Project.extract(st).get(releaseUseGlobalVersion)
-
- reapply(Seq(
- if (useGlobal) version in ThisBuild := selected else version := selected
- ),
- st)
- }
-
- lazy val setReleaseVersion: ReleaseStep = setVersionOnly(_._1)
-
- // Remove the prompt for next version
- lazy val inquireVersions: ReleaseStep = { st: State =>
- val extracted = Project.extract(st)
-
- val useDefs = st.get(useDefaults).getOrElse(false)
- val currentV = extracted.get(version)
-
- val (_, releaseFunc) = extracted.runTask(releaseVersion, st)
- val suggestedReleaseV = releaseFunc(currentV)
-
- // flatten the Option[Option[String]] as the get returns an Option, and the value inside is an Option
- val releaseV =
- readVersion(suggestedReleaseV, "Release version [%s] : ", useDefs, st.get(commandLineReleaseVersion).flatten)
- val nextV = releaseV
-
- st.put(versions, (releaseV, nextV))
-
- }
-
- def ServiceReleaseProcess = {
- Seq[ReleaseStep](
- checkSnapshotDependencies,
- inquireVersions,
- runTest,
- recordReleaseVersion, // set release version and persistent in version.sbt
- commitReleaseVersion, // performs the initial git checks
- tagRelease,
- pushChanges // also checks that an upstream branch is properly configured
- )
- }
-
- def LibraryReleaseProcess = {
- Seq[ReleaseStep](
- checkSnapshotDependencies,
- inquireVersions,
- setReleaseVersion,
- runTest,
- tagRelease,
- publishArtifacts,
- pushChanges // also checks that an upstream branch is properly configured
- )
- }
-
- def releaseSettings(releaseProcessSteps: Seq[ReleaseStep]): Seq[Setting[_]] = {
-
- val showReleaseVersion = taskKey[String]("the future version once releaseNextVersion has been applied to it")
- Seq(
- releaseCrossBuild := true,
- releaseIgnoreUntrackedFiles := true,
- // Check http://blog.byjean.eu/2015/07/10/painless-release-with-sbt.html for details
- releaseVersionBump := sbtrelease.Version.Bump.Bugfix,
- releaseVersion := {
- case ver @ snapshotVersion if snapshotVersion.endsWith("-SNAPSHOT") =>
- Version(ver).map(_.withoutQualifier.string).getOrElse(versionFormatError)
- case ver =>
- Version(ver).map(_.bumpBugfix.withoutQualifier.string).getOrElse(versionFormatError)
- },
- showReleaseVersion := {
- releaseVersion.value(version.value)
- },
- releaseProcess := releaseProcessSteps
- )
- }
-
- implicit class driverConfigurations(project: Project) {
-
- def gitPluginConfiguration: Project = {
- val VersionRegex = "v([0-9]+.[0-9]+.[0-9]+)-?(.*)?".r
-
- project
- .enablePlugins(GitVersioning, GitBranchPrompt)
- .settings(
- git.useGitDescribe := true,
- git.baseVersion := "0.0.0",
- git.gitTagToVersionNumber := {
- case VersionRegex(v, "SNAPSHOT") => // There are not committed changes at tagged commit
- val ver = Version(v)
- .map(_.withoutQualifier)
- .map(_.bump(sbtrelease.Version.Bump.Bugfix).string)
- .getOrElse(versionFormatError)
-
- Some(s"$ver-SNAPSHOT")
-
- case VersionRegex(v, "") =>
- Some(v)
-
- case VersionRegex(v, s) => // Commit is ahead of the last tagged commit
- val ver = Version(v)
- .map(_.withoutQualifier)
- .map(_.bump(sbtrelease.Version.Bump.Bugfix).string)
- .getOrElse(versionFormatError)
-
- Some(s"$ver-$s-SNAPSHOT")
-
- case _ => None
- }
- )
- }
-
- def buildInfoConfiguration(packageName: String = "xyz.driver"): Project = {
- project
- .enablePlugins(BuildInfoPlugin)
- .settings(
- buildInfoKeys := Seq[BuildInfoKey](name, version, scalaVersion, sbtVersion, git.gitHeadCommit),
- buildInfoPackage := packageName,
- buildInfoOptions += BuildInfoOption.BuildTime
- )
- }
-
- def packagingConfiguration: Project = {
- project
- .settings( // for assembly plugin
- test in assembly := {},
- assemblyMergeStrategy in assembly := {
- case PathList("org", "slf4j", "impl", xs @ _*) => MergeStrategy.first
- case "logback.xml" => MergeStrategy.first
- case strategy: String =>
- val oldStrategy = (assemblyMergeStrategy in assembly).value
- oldStrategy(strategy)
- }
- )
- }
-
- def dockerConfiguration(imageName: String,
- repository: String,
- exposedPorts: Seq[Int],
- baseImage: String = "java:8",
- customCommands: List[String] = List.empty[String],
- aggregateSubprojects: Boolean = false): Project = {
- import com.typesafe.sbt.packager.Keys._
-
- project
- .enablePlugins(JavaAppPackaging)
- .settings(
- // Settings reference http://www.scala-sbt.org/sbt-native-packager/formats/docker.html
- packageName in Docker := imageName,
- version in Docker := version.value.stripSuffix("-SNAPSHOT"),
- dockerRepository := Some(repository),
- maintainer := "Driver Inc. <info@driver.xyz>",
- dockerUpdateLatest := true, // to automatic update the latest tag
- dockerExposedPorts := exposedPorts,
- dockerBaseImage := baseImage,
- daemonUser in Docker := "root",
- dockerCommands := dockerCommands.value
- .flatMap { // @see http://blog.codacy.com/2015/07/16/dockerizing-scala/
- case cmd @ Cmd("FROM", _) => cmd :: customCommands.map(customCommand => Cmd("RUN", customCommand))
- case other => List(other)
- },
- aggregate in Docker := aggregateSubprojects // to include subprojects
- )
-
- // And then you can run "sbt docker:publish"
- }
-
- def deploymentConfiguration(imageName: String,
- exposedPorts: Seq[Int] = Seq(8080),
- clusterName: String = "sand-uw1a-1",
- clusterZone: String = "us-west1-a",
- gCloudProject: String = "driverinc-sandbox",
- baseImage: String = "java:8",
- dockerCustomCommands: List[String] = List.empty[String],
- aggregateSubprojects: Boolean = false) = {
-
- val repositoryName = "gcr.io/" + gCloudProject
-
- val keytoolCommand =
- "keytool -import -alias driverincInternal -keystore $JAVA_HOME/jre/lib/security/cacerts " +
- s"-file /etc/$imageName/ssl/issuing_ca -storepass changeit -noprompt"
-
- // If issuing_ca exists, import it into the internal default ca store
- val importTrustStoreCommand =
- s"if [ -f /etc/$imageName/ssl/issuing_ca ] ; then " + keytoolCommand + "; else echo \"No truststore customization.\"; fi"
-
- val dockerCommands = dockerCustomCommands // :+ importTrustStoreCommand
-
- val allExposedPorts = exposedPorts ++ Seq(JMX_PORT)
-
- dockerConfiguration(imageName, repositoryName, allExposedPorts, baseImage, dockerCommands, aggregateSubprojects)
- .settings(NativePackagerKeys.bashScriptExtraDefines += importTrustStoreCommand)
- .settings(NativePackagerKeys.bashScriptExtraDefines ++= Seq(
- """addJava "-Dcom.sun.management.jmxremote"""",
- s"""addJava "-Dcom.sun.management.jmxremote.port=$JMX_PORT"""",
- """addJava "-Dcom.sun.management.jmxremote.local.only=false"""",
- """addJava "-Dcom.sun.management.jmxremote.authenticate=false"""",
- """addJava "-Dcom.sun.management.jmxremote.ssl=false""""
- ))
- }
-
- def driverLibrary(libraryName: String): Project = {
- project
- .settings(name := libraryName)
- .gitPluginConfiguration
- .settings(repositoriesSettings ++ publicationSettings ++ releaseSettings(LibraryReleaseProcess))
- }
-
- def driverService(appName: String,
- exposedPorts: Seq[Int] = Seq(8080),
- clusterName: String = "sand-uw1a-1",
- clusterZone: String = "us-west1-a",
- gCloudProject: String = "driverinc-sandbox",
- baseImage: String = "java:8",
- dockerCustomCommands: List[String] = List.empty[String],
- aggregateSubprojects: Boolean = false): Project = {
- project
- .settings(name := appName)
- .settings(repositoriesSettings ++ releaseSettings(ServiceReleaseProcess))
- .buildInfoConfiguration()
- .deploymentConfiguration(appName,
- exposedPorts,
- clusterName,
- clusterZone,
- gCloudProject,
- baseImage,
- dockerCustomCommands,
- aggregateSubprojects)
- }
- }
- }
-
- val scalacDefaultOptions = Seq("-unchecked", "-deprecation", "-feature", "-Xlint", "-encoding", "utf8")
-
- val scalacLanguageFeatures = Seq(
- "-language:higherKinds",
- "-language:implicitConversions",
- "-language:postfixOps",
- "-language:reflectiveCalls"
- )
-
- override def trigger: PluginTrigger = allRequirements
- override def projectSettings: Seq[Setting[_]] = Seq(
- organization := "xyz.driver",
- crossScalaVersions := List("2.12.4"),
- scalaVersion := crossScalaVersions.value.last,
- scalacOptions := (scalacDefaultOptions ++ scalacLanguageFeatures),
- scalacOptions in (Compile, console) := (scalacDefaultOptions ++ scalacLanguageFeatures),
- scalacOptions in (Compile, consoleQuick) := (scalacDefaultOptions ++ scalacLanguageFeatures),
- scalacOptions in (Compile, consoleProject) := (scalacDefaultOptions ++ scalacLanguageFeatures),
- version := {
- // Sbt release versioning based on git given double -SNAPSHOT suffix
- // if current commit is not tagged AND there are uncommitted changes (e.g., some file is modified),
- // this setting fixes that, by just removing double -SNAPSHOT if it happened somehow
- Option(version.value).map(vv => vv.replaceAll("-SNAPSHOT-SNAPSHOT", "-SNAPSHOT")).getOrElse("0.0.0")
- },
- fork := true
- )
-}
diff --git a/src/main/scala/xyz.driver.sbt/Service.scala b/src/main/scala/xyz.driver.sbt/Service.scala
new file mode 100644
index 0000000..a0186e6
--- /dev/null
+++ b/src/main/scala/xyz.driver.sbt/Service.scala
@@ -0,0 +1,75 @@
+package xyz.driver.sbt
+
+import com.typesafe.sbt.GitPlugin.autoImport._
+import com.typesafe.sbt.packager.Keys.{
+ dockerBaseImage => _,
+ dockerCommands => _,
+ dockerExposedPorts => _,
+ dockerRepository => _,
+ dockerUpdateLatest => _,
+ _
+}
+import com.typesafe.sbt.packager.archetypes.JavaAppPackaging
+import com.typesafe.sbt.packager.docker.DockerPlugin.autoImport._
+import com.typesafe.sbt.packager.docker.{Cmd, DockerPlugin}
+import sbt.Keys._
+import sbt.{Def, _}
+import sbtbuildinfo.BuildInfoPlugin
+import sbtbuildinfo.BuildInfoPlugin.autoImport._
+
+/** Common settings to a service. */
+object Service extends AutoPlugin {
+
+ override def requires = BuildInfoPlugin && DockerPlugin && JavaAppPackaging
+
+ object autoImport {
+ val customCommands = taskKey[List[String]]("Additional commands that are run as part of docker packaging.")
+ }
+ import autoImport._
+
+ lazy val buildInfoSettings = Seq(
+ buildInfoKeys := Seq[BuildInfoKey](name, version, scalaVersion, sbtVersion, git.gitHeadCommit),
+ buildInfoPackage := organization.value,
+ buildInfoOptions += BuildInfoOption.BuildTime
+ )
+
+ lazy val dockerSettings = Seq(
+ name in Docker := name.value,
+ // Settings reference http://www.scala-sbt.org/sbt-native-packager/formats/docker.html
+ maintainer in Docker := "Driver Inc. <info@driver.xyz>",
+ aggregate in Docker := true, // include subprojects,
+ dockerRepository := Some("gcr.io/driverinc-sandbox"),
+ dockerUpdateLatest := true, // automatically update the latest tag
+ dockerBaseImage := "openjdk:10",
+ dockerCommands := dockerCommands.value.flatMap { // @see http://blog.codacy.com/2015/07/16/dockerizing-scala/
+ case cmd @ Cmd("FROM", _) => cmd :: customCommands.value.map(customCommand => Cmd("RUN", customCommand))
+ case other => List(other)
+ },
+ bashScriptExtraDefines += {
+ s"""|if [[ -f /etc/${name.value}/ssl/issuing_ca ]]; then
+ | keytool -import \
+ | -alias driverincInternal \
+ | -keystore $$JAVA_HOME/jre/lib/security/cacerts \
+ | -file /etc/${name.value}/ssl/issuing_ca \
+ | -storepass changeit -noprompt
+ |else
+ | echo "No truststore customization." >&2
+ |fi
+ |""".stripMargin
+ }
+ )
+
+ override def projectSettings: Seq[Def.Setting[_]] =
+ Library.repositorySettings ++ buildInfoSettings ++ dockerSettings ++ Seq(
+ crossScalaVersions := List("2.12.6"),
+ scalaVersion := crossScalaVersions.value.last,
+ publish := {
+ streams.value.log.warn(s"Service ${name.value} won't be published.")
+ }
+ )
+
+ override def buildSettings: Seq[Def.Setting[_]] =
+ addCommandAlias("start", "reStart") ++
+ addCommandAlias("stop", "reStop")
+
+}
diff --git a/src/main/scala/xyz.driver.sbt/Versioning.scala b/src/main/scala/xyz.driver.sbt/Versioning.scala
new file mode 100644
index 0000000..fe3a218
--- /dev/null
+++ b/src/main/scala/xyz.driver.sbt/Versioning.scala
@@ -0,0 +1,31 @@
+package xyz.driver.sbt
+
+import com.typesafe.sbt.GitPlugin
+import com.typesafe.sbt.SbtGit.git
+import sbt.Keys._
+import sbt.plugins.JvmPlugin
+import sbt.{AutoPlugin, _}
+
+object Versioning extends AutoPlugin {
+
+ override def requires = JvmPlugin
+ override def trigger = allRequirements
+
+ // Get version from git unless a VERSION environment variable is set
+ lazy val versionSettings: Seq[Setting[_]] = sys.env.get("VERSION") match {
+ case None =>
+ GitPlugin.autoImport.versionWithGit ++ Seq(
+ git.useGitDescribe := true, // get version from git
+ git.baseVersion := "0.0.0" // this version is used for new projects without any commits
+ )
+ case Some(v) =>
+ Seq(
+ version := v
+ )
+ }
+
+ override def buildSettings = versionSettings ++ Seq(
+ organization := "xyz.driver"
+ )
+
+}
diff --git a/src/sbt-test/sbt-settings/service/build.sbt b/src/sbt-test/sbt-settings/service/build.sbt
new file mode 100644
index 0000000..c55af36
--- /dev/null
+++ b/src/sbt-test/sbt-settings/service/build.sbt
@@ -0,0 +1,3 @@
+lazy val service = project
+ .in(file("."))
+ .enablePlugins(Service)
diff --git a/src/sbt-test/sbt-settings/service/project/plugins.sbt b/src/sbt-test/sbt-settings/service/project/plugins.sbt
new file mode 100644
index 0000000..2e7ed62
--- /dev/null
+++ b/src/sbt-test/sbt-settings/service/project/plugins.sbt
@@ -0,0 +1,5 @@
+sys.props.get("plugin.version") match {
+ case Some(v) => addSbtPlugin("xyz.driver" % "sbt-settings" % v)
+ case _ => sys.error("""|The system property 'plugin.version' is not defined.
+ |Specify this property using the scriptedLaunchOpts -D.""".stripMargin)
+}
diff --git a/src/sbt-test/sbt-settings/service/src/main/scala/Main.scala b/src/sbt-test/sbt-settings/service/src/main/scala/Main.scala
new file mode 100644
index 0000000..08a8f3f
--- /dev/null
+++ b/src/sbt-test/sbt-settings/service/src/main/scala/Main.scala
@@ -0,0 +1,7 @@
+import java.nio.file.{Files, Paths}
+
+object Main extends App {
+ val version = xyz.driver.BuildInfo.version
+ Files.write(Paths.get("out.txt"), s"$version\n".getBytes("utf-8"))
+ println(s"hello world ($version)")
+}
diff --git a/src/sbt-test/sbt-settings/service/test b/src/sbt-test/sbt-settings/service/test
new file mode 100644
index 0000000..99ad380
--- /dev/null
+++ b/src/sbt-test/sbt-settings/service/test
@@ -0,0 +1,4 @@
+> test
+> run
+$ exists out.txt
+> docker:publishLocal