aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.ci/build3
-rw-r--r--.travis.yml7
-rw-r--r--README.md122
-rw-r--r--build.sbt21
-rw-r--r--project/plugins.sbt1
-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
16 files changed, 350 insertions, 476 deletions
diff --git a/.ci/build b/.ci/build
index ad52e38..9e4930f 100755
--- a/.ci/build
+++ b/.ci/build
@@ -3,7 +3,8 @@ set -ev
sbt \
scalafmt::test \
- test
+ test \
+ scripted
# Automatic publishing for tags that start with `v<digit>`
if [[ "$TRAVIS_PULL_REQUEST" == "false" && "$TRAVIS_TAG" =~ ^v[0-9].* ]]; then
diff --git a/.travis.yml b/.travis.yml
index c841aab..171ebe3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,11 @@
+sudo: required
+
+services:
+ - docker
+
language: scala
jdk:
- - oraclejdk8 # this should be changed to openjdk as soon as it becomes available on Travis CI
+ - oraclejdk8
env:
- secure: "qZvexfj0uZLwgn0aKy9rQjBCw8LHbSQJNlA/DrNHDi10SsABNgeE4EDyoPD9+csNchbBmPpUObROCm7k/bDPLO6+cgncHbZlfqet0PGryGldF6XzY0uWVl06l40YXZrCyxeRcIKHzkneo4q3zSxJlkWXFBxFPanZVzyO94riMopKpDT41bKLqdiWIboq7ydeZWo538fuSOKjZjoTWwexX5KMnTePGeYVS2vbJIUXHa6kEzXx5MU8Lf1VcnGQER/1KMN7OrAtqJ72zvo/K6mcU1XGkEYxqQK2hxt3kUACunb1NWQoWjCKWKB9TgiCd/sOAkzhNgnZoYpcSXkBK0XPbjmYNHnIXL1aLdHl3n2jzpjVimFUzW8m7tMqJPJMn1igY+xTqjpoRI8sGS47XQMIhbH0SEQpwU0yY+Lnxo3WcXw0o+r3lW+P4jGv1PrzF6EkERjRICjU0B5XRXwgejvzuETjkzJRfiuvgSpdeCnlO6JK1IoKalJGMETme/Nb5pJfaFMzZ7UsnQzXwPZtZXKYEeWwt86RFggd/P6vmUcK4E1wOMXI5TRdIEN7RVA06GgzU5va7M41er1j8c2yCiu89YYLXchupQvoBAmLqWa5C/fk5dXVatsv13/XXuHBl6BFNRS/Rd850Z/254nQxAdupcZzztX5oMKu/QxBkor27wY="
diff --git a/README.md b/README.md
index c8eca3a..ab33606 100644
--- a/README.md
+++ b/README.md
@@ -1,65 +1,105 @@
[![Build Status](https://travis-ci.org/drivergroup/sbt-settings.svg?branch=master)](https://travis-ci.org/drivergroup/sbt-settings)
[![Scaladex](https://index.scala-lang.org/drivergroup/sbt-settings/latest.svg)](https://index.scala-lang.org/drivergroup/sbt-settings)
-# _sbt_ plugin for common _sbt_ settings
-Provides common Driver Scala projects configuration for sbt, Scala compiler, testing, linting, formatting, release process, packaging, publication. Allows to use only necessary parts. Sets artifact `organization` to `xyz.driver`.
+# Common sbt settings
+
+Provides common settings for Scala projects, as they are typically
+configured at Driver.
+
+sbt-settings is a suite of [sbt
+autoplugins](https://www.scala-sbt.org/1.0/docs/Plugins.html) that
+provide common settings for the scala compiler, testing, linting,
+formatting, release process, packaging and publication.
## Getting started
-### project/plugins.sbt
+Adding the following snippet to `project/plugins.sbt` will make the
+plugins available:
+
+```scala
+addSbtPlugin("xyz.driver" % "sbt-settings" % "<latest_tag>")
+```
+
+The next section exlains what plugins are available and which ones are
+activated out-of-the-box.
+
+## Plugins
+
+### Summary
+
+| Name | Enabled |
+|--------------------------|----------------------------------------|
+| Linting | automatic |
+| Versioning | automatic |
+| IntegrationTestPackaging | automatic, if ServicePlugin is enabled |
+| Library | manual |
+| Service | manual |
+
+### Linting
+
+*[source](src/main/scala/xyz.driver.sbt/Linting.scala)*
+
+- Includes configuration for scalafmt and scalastyle, modifies the
+ `test` task to check for formatting and styling.
+- Sets strict compiler flags and treats warnings as errors (with the
+ exception of deprecations).
+
+This plugin can get in the way of developer productivity. If that is
+the case, it can simply be disabled.
+
+### Versioning
+
+*[source](src/main/scala/xyz.driver.sbt/Versioning.scala)*
- addSbtPlugin("xyz.driver" % "sbt-settings" % "<latest_tag>")
+Sets the project organization and reads version information from
+git. It also enables overriding the version by setting a `VERSION`
+environment variable (which may be useful to do from CI).
-### build.sbt
+### Integration Test Packaging
-There are two different ways to use the `sbt-settings` configuration:
+*[source](src/main/scala/xyz.driver.sbt/IntegrationTestPackaging.scala)*
- * As a "Service" — deployed application distributed as a Docker container. Includes Driver Inc.'s artifactory settings, Docker packaging with truststore configuration, build info generation. Versioned using `version.sbt` file for major and minor versions. Usage example, as follows
+Augments the packaging configuration of ServicePlugin, to include
+integration tests in deployed applications images.
- ```
- lazy val root = (project in file("."))
- .driverService ("Name-Of-Your-Service")
- .integrationTestingConfiguration // Enable integration tests
- .packagingConfiguration // To package to zip file as java server app
- .settings(lintingSettings) // Scala code linting settings
- .settings(formatSettings) // Standard Scala code formatting
- .settings(releaseSettings(ServiceReleaseProcess)) // Release process configuration
- ```
+### Library Plugin
- * As a "Library" — commonly used code, distributed as jar using artifactory. Versioned using git tag-based versioning. Includes Driver Inc.'s artifactory settings, publication to artifactory, `sbt release` settings,
+*[source](src/main/scala/xyz.driver.sbt/Library.scala)*
- ```
- lazy val root = (project in file("."))
- .driverLibrary("Name-Of-Your-Library")
- .settings(lintingSettings ++ formatSettings)
- ```
+Common settings for libraries. It only sets the default publish
+target to Driver's artifactory.
-Do `sbt reload` after adding a plugin and changing project configuration.
+### Service Plugin
-## Reference
+*[source](src/main/scala/xyz.driver.sbt/Service.scala)*
-Artifact organization is set to `xyz.driver`.
+Packages an application as a docker image and provides a way to
+include internal TLS certificates.
-### Scala compiler settings
-Scala version — 2.12, flags configured:
+It also includes some utility commands such as `start` and `stop`
+(based on [sbt-revolver](https://github.com/spray/sbt-revolver), to
+enable rapid local development cycles of applications.
- - Common settings: `-unchecked -feature -encoding utf8`,
- - _Advanced Scala features_: `-language:higherKinds -language:implicitConversions -language:postfixOps -language:reflectiveCalls`,
- - _Compiler linting_: `-Xlint -deprecation -Ywarn-numeric-widen -Ywarn-dead-code -Ywarn-unused -Ywarn-unused-import -Xfatal-warnings -Xlint:-missing-interpolator`.
+## Canonical Use Case
+sbt-settings provides many plugins, which may be used in various
+ways. Typically however, a project is either a Library or a Service,
+and as such, it will enable one of those plugins explicitly. The other
+plugins will provide general settings for common conventions and are
+always enabled.
-### Used sbt plugins
+The following provides a typical example for configuring a project as
+a service called "myservice":
- - [sbt-scalafmt](https://olafurpg.github.io/scalafmt/) - code formatter for Scala,
- - [scalastyle-sbt-plugin](https://github.com/scalastyle) - examines your Scala code and indicates potential problems with it,
- - [sbt-revolver](https://github.com/spray/sbt-revolver) - for dangerously fast development turnaround in Scala,
- - [sbt-buildinfo](https://github.com/sbt/sbt-buildinfo) - generates Scala source from your build definitions,
- - [sbt-git](https://github.com/sbt/sbt-git) - to get access to git data (commit hash, branch) in sbt,
- - [sbt-native-packager](https://github.com/sbt/sbt-native-packager) - build application packages in native formats,
- - [sbt-assembly](https://github.com/sbt/sbt-assembly) - deploy fat JARs. Restart processes (sbt-native-packager is used instead,)
- - [sbt-release](https://github.com/sbt/sbt-release) - customizable release process,
- - [sbt-docker](https://github.com/marcuslonnberg/sbt-docker) - create Docker images directly from sbt.
+```scala
+lazy val myservice = project
+ .in(file("."))
+ .enablePlugin(ServicePlugin)
+ .disablePlugins(IntegrationTestPackaging) // we don't need integration tests
+ .disablePlugins(LintPlugin) // I don't need style check during development!
+ .settings( /* custom settings */)
+```
-## Developing
+## Developing this Plugin
This project is set up to auto-deploy on push. If an annotated tag in
the form `v<digit>.*` is pushed, a new version of this project will be
built and published to Maven Central.
diff --git a/build.sbt b/build.sbt
index 21b06e2..b89775c 100644
--- a/build.sbt
+++ b/build.sbt
@@ -1,18 +1,21 @@
sbtPlugin := true
name := "sbt-settings"
-scalaVersion := "2.12.5"
+scalaVersion := "2.12.6"
-addSbtPlugin("com.lucidchart" %% "sbt-scalafmt" % "1.14")
+// Plugins that will be included transitively in projects depending on sbt-settings
+addSbtPlugin("com.lucidchart" %% "sbt-scalafmt" % "1.15")
addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "1.0.0")
-
-// Launch and deploy/release plugins
addSbtPlugin("io.spray" %% "sbt-revolver" % "0.9.1")
-addSbtPlugin("com.eed3si9n" %% "sbt-buildinfo" % "0.7.0")
-addSbtPlugin("com.typesafe.sbt" %% "sbt-git" % "0.9.3")
-addSbtPlugin("com.typesafe.sbt" %% "sbt-native-packager" % "1.3.2")
-addSbtPlugin("com.eed3si9n" %% "sbt-assembly" % "0.14.5")
-addSbtPlugin("com.github.gseitz" %% "sbt-release" % "1.0.7")
+addSbtPlugin("com.eed3si9n" %% "sbt-buildinfo" % "0.9.0")
+addSbtPlugin("com.typesafe.sbt" %% "sbt-git" % "1.0.0")
+addSbtPlugin("com.typesafe.sbt" %% "sbt-native-packager" % "1.3.4")
+addSbtPlugin("com.github.gseitz" %% "sbt-release" % "1.0.8")
// the following prevents thousands of meaningless stacktraces by docker plugin on JDK 9
libraryDependencies += "javax.activation" % "activation" % "1.1.1" % Test
+
+scriptedLaunchOpts := { scriptedLaunchOpts.value ++
+ Seq("-Xmx1024M", "-Dplugin.version=" + version.value)
+}
+scriptedBufferLog := false
diff --git a/project/plugins.sbt b/project/plugins.sbt
index 4da7bd5..a769906 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -1 +1,2 @@
addSbtPlugin("com.lucidchart" %% "sbt-scalafmt" % "1.14")
+libraryDependencies += { "org.scala-sbt" %% "scripted-plugin" % sbtVersion.value }
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