sbt - defining custom configuration for sequential tests - scala

Some of my tests require that they are sequentially executed. I read about custom configurations on http://www.scala-sbt.org/0.13.0/docs/Detailed-Topics/Testing.html but I am missing something because my configuration is not working properly.
Here it is:
import sbt._
import Keys._
object SchedulingBackendBuild extends Build {
lazy val SequentialTest = config("sequentialTest") extend(Test)
def sequentialTestFilter(name: String): Boolean = {
println("===seq test filter")
name endsWith "SeqSpec"
}
def unitTestFilter(name: String): Boolean = {
println("===unit test filter")
!sequentialTestFilter(name)
}
lazy val root = Project(id = "scheduling-backend",
base = file("."),
settings = Project.defaultSettings
).configs(SequentialTest)
.settings(inConfig(SequentialTest)(Defaults.testTasks): _*)
.settings(
testOptions in Test ++= Seq(Tests.Filter(unitTestFilter)),
testOptions in SequentialTest ++= Seq(Tests.Filter(sequentialTestFilter))
)
}
I want test to only execute tests that are not ending with SeqSpec and this is working, but when I try to execute sequentialTest:test no tests are executed. I added println to my filters and I can see that even if I execute sequentialTest:test I am getting
===unit test filter
===seq test filter
===seq test filter
so both filters are executed.
When I type inspect sequentialTest:testOptions I am getting
[info] Task: scala.collection.Seq[sbt.TestOption]
[info] Description:
[info] Options for running tests.
[info] Provided by:
[info] {file:/path/to/project/scheduling-backend/}scheduling-backend/sequentialTest:testOptions
[info] Defined at:
[info] /path/to/project/scheduling-backend/project/Build.scala:22
[info] Reverse dependencies:
[info] sequentialTest:testOnly::testOptions
[info] sequentialTest:testQuick::testOptions
[info] sequentialTest:test::testOptions
[info] Delegates:
[info] sequentialTest:testOptions
[info] test:testOptions
[info] runtime:testOptions
[info] compile:testOptions
[info] *:testOptions
[info] {.}/sequentialTest:testOptions
[info] {.}/test:testOptions
[info] {.}/runtime:testOptions
[info] {.}/compile:testOptions
[info] {.}/*:testOptions
[info] */sequentialTest:testOptions
[info] */test:testOptions
[info] */runtime:testOptions
[info] */compile:testOptions
[info] */*:testOptions
[info] Related:
[info] sequentialTest:testOnly::testOptions
[info] sequentialTest:testQuick::testOptions
[info] test:testOptions
[info] test:testQuick::testOptions
[info] */*:testOptions
[info] test:testOnly::testOptions
[info] test:test::testOptions
[info] sequentialTest:test::testOptions
so for me it looks ok, line 22 is testOptions in SequentialTest ++= Seq(Tests.Filter(sequentialTestFilter))

Partial answer: if I change ++= operator (appending to the sequence) to := (replacing the sequence) everything works fine (and := operators are used in the documentation). Even so I would want to know why ++= in this case is bad choice.

Related

(rootProject/*:bintrayEnsureLicenses) you must define at least one license for this project

I am trying to publish my project on bintray for the first time. I read the documentation here
https://github.com/sbt/sbt-bintray
My plugins.sbt file is
addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.1")
This is my build.sbt. You can see that I have defined the license for my project
lazy val publishSettings = Seq(
licenses += ("MIT", url("http://opensource.org/licenses/MIT")),
bintrayOrganization := Some("abhishes"),
bintrayRepository := "AbhiTestRepo",
bintrayPackageLabels := Seq("foo", "bar")
)
lazy val commonSettings = Seq(
"organization" := "abhishes",
version := "1.0",
scalaVersion := "2.12.3"
)
lazy val project1 = (project in file("SubProject1")).settings(commonSettings)
.settings(publishSettings)
.settings(
name := "SubProject1"
)
lazy val project2 = (project in file("SubProject2")).settings(commonSettings)
.settings(publishSettings)
.settings(
name := "SubProject2"
)
lazy val rootProject = (project in file("."))
.settings(commonSettings)
.settings(publishSettings)
.settings(
name := "MyScalaProject"
).dependsOn(project1, project2)
when I say sbt publish I still get this error
> publish
[trace] Stack trace suppressed: run last rootProject/*:bintrayEnsureLicenses for the full output.
[error] (rootProject/*:bintrayEnsureLicenses) you must define at least one license for this project. Please choose one or more of
[error] AFL-3.0, AGPL-V3, APL-1.0, APSL-2.0, Apache-1.0, Apache-1.1, Apache-2.0, Artistic-License-2.0, Attribution, BSD, BSD New, BSD Simplified, BSL-1.0, Bouncy-Castle, CA-TOSL-1.1, CDDL-1.0, CPAL-1.0, CPL-1.0, CPOL-1.02, CUAOFFICE-1.0, Codehaus, Day, Day-Addendum, ECL2, EUDATAGRID, EUPL-1.1, Eclipse-1.0, Eiffel-2.0, Entessa-1.0, Fair, Frameworx-1.0, GPL-2.0, GPL-2.0+CE, GPL-3.0, HSQLDB, Historical, IBMPL-1.0, IPAFont-1.0, ISC, IU-Extreme-1.1.1, JA-SIG, JSON, JTidy, LGPL-2.1, LGPL-3.0, Lucent-1.02, MIT, MPL-2.0, MS-PL, MS-RL, MirOS, Motosoto-0.9.1, Mozilla-1.1, Multics, NASA-1.3, NAUMEN, NOSL-3.0, NTP, Nethack, Nokia-1.0a, OCLC-2.0, OSL-3.0, Openfont-1.1, Opengroup, PHP-3.0, PostgreSQL, Public Domain, Public Domain - SUN, PythonPL, PythonSoftFoundation, QTPL-1.0, RPL-1.5, Real-1.0, RicohPL, SUNPublic-1.0, SimPL-2.0, Sleepycat, Sybase-1.0, TMate, Unlicense, UoI-NCSA, VovidaPL-1.0, W3C, WTFPL, Xnet, ZLIB, ZPL-2.0, wxWindows
[error] Total time: 1 s, completed Aug 26, 2017 1:00:10 PM
>
EDIT: This is the output of inspect licenses
> inspect licenses
[info] Setting: scala.collection.Seq[scala.Tuple2[java.lang.String, java.net.URL]] = List()
[info] Description:
[info] Project licenses as (name, url) pairs.
[info] Provided by:
[info] */*:licenses
[info] Defined at:
[info] (sbt.Classpaths) Defaults.scala:1186
[info] Reverse dependencies:
[info] rootProject/*:bintrayEnsureBintrayPackageExists
[info] rootProject/*:projectInfo
[info] rootProject/*:bintrayEnsureLicenses
[info] Delegates:
[info] rootProject/*:licenses
[info] {.}/*:licenses
[info] */*:licenses
[info] Related:
[info] */*:licenses
>
Edit2: Here is the output of inspect rootProject/licenses
> inspect rootProject/licenses
[info] Setting: scala.collection.Seq[scala.Tuple2[java.lang.String, java.net.URL]] = List()
[info] Description:
[info] Project licenses as (name, url) pairs.
[info] Provided by:
[info] */*:licenses
[info] Defined at:
[info] (sbt.Classpaths) Defaults.scala:1186
[info] Reverse dependencies:
[info] rootProject/*:bintrayEnsureBintrayPackageExists
[info] rootProject/*:projectInfo
[info] rootProject/*:bintrayEnsureLicenses
[info] Delegates:
[info] rootProject/*:licenses
[info] {.}/*:licenses
[info] */*:licenses
[info] Related:
[info] */*:licenses
I was able to resolve the problem myself. If you look in the source code of the plugin
https://github.com/sbt/sbt-bintray/blob/7a14108bd273a8bb469ad118ccd7cce5b4042099/src/main/scala/Bintray.scala#L33
The data type of of licenses is Seq[(String, url)]
Based on this I changed my code accordingly by making the licenses as a sequence of tuples of type (String, url) and the problem got resolved.
lazy val publishSettings = Seq(
licenses ++= Seq(("MIT", url("http://opensource.org/licenses/MIT"))),
bintrayOrganization := Some("abhishes"),
bintrayRepository := "AbhiTestRepo",
bintrayPackageLabels := Seq("foo", "bar")
)

In sbt, how do you override scalacOptions for console in all configurations?

I like defining scalacOptions at the top level like so (as an example, ignoring project axis for now):
scalacOptions += "-Ywarn-unused-import"
But then I realised that's too strict for console. So I tried setting:
scalacOptions in console ~= (_ filterNot (_ == "-Ywarn-unused-import"))
But that didn't work (still got (fatal) warnings in the REPL).
I used inspect to try and understand why:
> inspect console
[info] Task: Unit
[info] Description:
[info] Starts the Scala interpreter with the project classes on the classpath.
[info] Provided by:
[info] {file:/a/}b/compile:console
[info] Defined at:
[info] (sbt.Defaults) Defaults.scala:261
[info] Dependencies:
[info] compile:console::compilers
[info] compile:console::initialCommands
[info] compile:console::fullClasspath
[info] compile:console::taskTemporaryDirectory
[info] compile:console::scalaInstance
[info] compile:console::streams
[info] compile:console::cleanupCommands
[info] compile:console::scalacOptions
[info] Delegates:
[info] compile:console
[info] *:console
[info] {.}/compile:console
[info] {.}/*:console
[info] */compile:console
[info] */*:console
[info] Related:
[info] test:console
Note: console is
provided by compile:console
depends on compile:console::scalacOptions
then:
> inspect compile:console::scalacOptions
[info] Task: scala.collection.Seq[java.lang.String]
[info] Description:
[info] Options for the Scala compiler.
[info] Provided by:
[info] {file:/a/}b/compile:scalacOptions
[info] Defined at:
[info] (sbt.Classpaths) Defaults.scala:1593
[info] Reverse dependencies:
[info] compile:console
[info] Delegates:
[info] compile:console::scalacOptions
[info] compile:scalacOptions
[info] *:console::scalacOptions
[info] *:scalacOptions
[info] {.}/compile:console::scalacOptions
[info] {.}/compile:scalacOptions
[info] {.}/*:console::scalacOptions
[info] {.}/*:scalacOptions
[info] */compile:console::scalacOptions
[info] */compile:scalacOptions
[info] */*:console::scalacOptions
[info] */*:scalacOptions
[info] Related:
[info] *:console::scalacOptions
[info] compile:scalacOptions
[info] *:scalacOptions
[info] */*:scalacOptions
[info] test:scalacOptions
Note: compile:console::scalacOptions is
provided by compile:scalacOptions
doesn't reach *:console::scalacOptions (which is what I defined) in the delegation chain
My question is how do I override scalacOptions for all configurations for console? Is it possible to change the delegation chain?
I'd like to avoid having to set scalacOptions in (Compile, console) (as it would be duplicated for (Test, console)) or define a val of scalac options.
My question is how do I override scalacOptions for all configurations for console?
I don't think we can given the presence of compile:scalacOptions provided by sbt's Defaults. The only scope that has higher precedence is compile:console::scalacOptions.
In most cases one would not want Compile and Test settings to cross wire, so configuration scoping higher precedence I don't think is a bad default.
lazy val commonSettings = Seq(
scalaVersion := "2.11.4",
scalacOptions += "-Ywarn-unused-import",
scalacOptions in (Compile, console) ~= (_ filterNot (_ == "-Ywarn-unused-import")),
scalacOptions in (Test, console) := (scalacOptions in (Compile, console)).value
)
Is it possible to change the delegation chain?
No, this is not possible.
There's a single instance of delegates function in BuildStructure, and it's initialized at the loading time and used for all tasks.
The ordering is done in Scope.delegates.
I fix the bad scalac options in an autoplugin:
package console
import sbt._
/** [[FixScalacOptionsInConsole]] is an [[AutoPlugin]] that removes
* noisy or unnecessary scalac options when running an sbt console.
*/
object FixScalacOptionsInConsole extends AutoPlugin {
import Keys._
override def requires = plugins.JvmPlugin
override def trigger = allRequirements
override lazy val projectSettings = Seq(
Compile / console / scalacOptions ~= filter,
Test / console / scalacOptions ~= filter
)
def filter: Seq[String] => Seq[String] =
_ .filterNot(_ == "-feature")
.filterNot(_.startsWith("-opt:"))
.filterNot(_ == "-unchecked")
.filterNot(_.startsWith("-Xlint:"))
.filterNot(_ == "-Xfatal-warnings")
.filterNot(_.startsWith("-Ywarn"))
}

Can't add compile dependencies using sbt.AutoPlugins

I am trying to build a plugin that automatically sets up a set of scalariform preferences.
My plugin's build.sbt:
name := "my-scalariform"
organization := "com.my"
version := "1.0-SNAPSHOT"
sbtPlugin := true
scalacOptions ++= Seq("-feature", "-deprecation", "-unchecked")
addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.3.0")
My initial plugin design:
package com.my.plugins
import com.typesafe.sbt.SbtScalariform
import com.typesafe.sbt.SbtScalariform.{
ScalariformKeys,
scalariformSettings
}
import sbt.AutoPlugin
import sbt.{ Compile, Test }
import sbt.Keys.{ compile, compileInputs }
import scalariform.formatter.preferences.{
DoubleIndentClassDeclaration,
FormattingPreferences,
IndentSpaces,
IndentWithTabs,
PreserveDanglingCloseParenthesis
}
object MyScalariformPlugin extends AutoPlugin {
override def trigger = allRequirements
lazy val formattingPreferences = {
import scalariform.formatter.preferences._
Seq(
ScalariformKeys.preferences := FormattingPreferences()
.setPreference(DoubleIndentClassDeclaration, true)
.setPreference(IndentSpaces, 2)
.setPreference(IndentWithTabs, false)
.setPreference(PreserveDanglingCloseParenthesis, true)
)
}
override lazy val projectSettings = scalariformSettings ++ formattingPreferences
}
When I added this plugin to my project I can see my scalariform settings:
> scalariform-preferences
[info] FormattingPreferences(Map(DoubleIndentClassDeclaration -> true, IndentSpaces -> 2, IndentWithTabs -> false, PreserveDanglingCloseParenthesis -> true))
However the compileInputs is missing the scalariform-format dependency:
> inspect compile:compile::compileInputs
...
[info] Defined at:
[info] (sbt.Defaults) Defaults.scala:792
[info] Dependencies:
[info] compile:compile::incCompileSetup
[info] compile:compile::streams
[info] compile:compile::dependencyClasspath
[info] compile:compile::compileOrder
[info] compile:compile::scalacOptions
[info] compile:compile::classDirectory
[info] compile:compile::javacOptions
[info] compile:compile::sourcePositionMappers
[info] compile:compile::compilers
[info] compile:compile::sources
[info] compile:compile::maxErrors
[info] Reverse dependencies:
[info] compile:compile
...
If I explicitly add the scalariform command overrides as a value in my plugin and then explicitly add it to my project I get the correct dependencies:
lazy val commandSettings = Seq(
compileInputs in (Compile, compile) <<= (compileInputs in (Compile, compile)) dependsOn (ScalariformKeys.format in Compile),
compileInputs in (Test, compile) <<= (compileInputs in (Test, compile)) dependsOn (ScalariformKeys.format in Test)
)
Dependencies:
> inspect compile:compile::compileInputs
...
[info] Defined at:
[info] (sbt.Defaults) Defaults.scala:792
[info] (com.my.plugins.MyScalariformPlugin) MyScalariformPlugin.scala:22
[info] Dependencies:
[info] compile:compile::incCompileSetup
[info] compile:compile::streams
[info] compile:compile::dependencyClasspath
[info] compile:scalariformFormat
[info] compile:compile::compileOrder
[info] compile:compile::scalacOptions
[info] compile:compile::classDirectory
[info] compile:compile::javacOptions
[info] compile:compile::sourcePositionMappers
[info] compile:compile::compilers
[info] compile:compile::sources
[info] compile:compile::maxErrors
[info] Reverse dependencies:
[info] compile:compile
...
I have tried specifying this dependency myself using an autoImport but that results in an error:
object autoImport {
lazy val commandSettings = Seq(
compileInputs in (Compile, compile) <<= (compileInputs in (Compile, compile)) dependsOn (ScalariformKeys.format in Compile),
compileInputs in (Test, compile) <<= (compileInputs in (Test, compile)) dependsOn (ScalariformKeys.format in Test)
)
}
import autoImport._
Errors:
[error] References to undefined settings:
[error]
[error] */test:compile::compileInputs from */test:compile::compileInputs ((com.my.plugins.MyScalariformPlugin.autoImport) MyScalariformPlugin.scala:24)
[error] Did you mean test:compile::compileInputs ?
[error]
[error] */test:scalariformFormat from */test:compile::compileInputs ((com.my.plugins.MyScalariformPlugin.autoImport) MyScalariformPlugin.scala:24)
[error] Did you mean test:scalariformFormat ?
[error]
[error] */compile:compile::compileInputs from */compile:compile::compileInputs ((com.my.plugins.MyScalariformPlugin.autoImport) MyScalariformPlugin.scala:23)
[error] Did you mean compile:compile::compileInputs ?
[error]
[error] */compile:scalariformFormat from */compile:compile::compileInputs ((com.my.plugins.MyScalariformPlugin.autoImport) MyScalariformPlugin.scala:23)
[error] Did you mean compile:scalariformFormat ?
[error]
Add this line to MyScalariformPlugin (don't ask me why :))
override def requires = plugins.JvmPlugin

How to add examples to an SBT project?

I want to add some examples to my Scala library. I prefer a directory layout like this:
examples/
example1/
Main.scala
...
example2/
Main.scala
...
src/
main/
scala/
...
test/
scala/
...
build.sbt
The examples use the packages in src/main/scala/. Is it possible to build and run the examples using SBT? Is it also possible to have dependencies specific to the examples?
It is possible, but you likely have to resort to complete .scala definition. I've put example project on bitbucket.
Here is the showcase:
// [info] Loading global plugins from /Users/omnomnom/.sbt/0.13/plugins
// [info] Loading project definition from /Users/omnomnom/projects/example-of-examples/project
// [info] Set current project to root-project (in build file:/Users/omnomnom/projects/example-of-examples/)
> projects
// [info] In file:/Users/omnomnom/projects/example-of-examples/
// [info] example1
// [info] example2
// [info] * root-project
> project example1
// [info] Set current project to example1 (in build file:/Users/omnomnom/projects/example-of-examples/)
> run
// [info] Updating {file:/Users/omnomnom/projects/example-of-examples/}root-project...
// [info] Resolving org.fusesource.jansi#jansi;1.4 ...
// [info] Done updating.
// [info] Updating {file:/Users/omnomnom/projects/example-of-examples/}example1...
// [info] Resolving org.fusesource.jansi#jansi;1.4 ...
// [info] Done updating.
// [info] Compiling 1 Scala source to /Users/omnomnom/projects/example-of-examples/target/scala-2.10/classes...
// [info] Running Main
I'm example #1
// [success] Total time: 4 s, completed Jul 4, 2014 10:17:54 PM
> project example2
// [info] Set current project to example2 (in build file:/Users/omnomnom/projects/example-of-examples/)
> run
// [info] Updating {file:/Users/omnomnom/projects/example-of-examples/}example2...
// [info] Resolving org.fusesource.jansi#jansi;1.4 ...
// [info] Done updating.
// [info] Compiling 1 Scala source to /Users/omnomnom/projects/example-of-examples/examples/example2/target/scala-2.10/classes...
// [info] Running Main
I'm example #2
// [success] Total time: 3 s, completed Jul 4, 2014 10:18:04 PM
And Build.scala, just for the case:
import sbt._
import Keys._
object Build extends Build {
override lazy val settings = super.settings ++ Seq(
scalacOptions ++= Seq("-unchecked", "-deprecation", "-Xlint"),
organization := "me.lazyval",
scalaVersion := "2.10.4",
initialCommands in console := "import me.lazyval._"
)
// altering source path, since you don't want to replicate usual src/main ... stuff
val exampleSourcePath = scalaSource in Compile := baseDirectory.value / "."
lazy val root = Project(id = "root-project", base = file("."), settings = Project.defaultSettings ++ settings)
lazy val example1 = Project(id = "example1", base = file("./examples/example1"), settings = Project.defaultSettings ++ settings ++ Seq(exampleSourcePath)) dependsOn root
// in `settings= ...` section you can set whatever dependencies you like
lazy val example2 = Project(id = "example2", base = file("./examples/example2"), settings = Project.defaultSettings ++ settings ++ Seq(exampleSourcePath)) dependsOn root
}

scala-sbt change javacOptions in task

I'm trying to create a simple ant task, which depends on compile. The problem I'm having is that I can't seem to set the javacOptions from within my task (only in the global scope).
val metamodelSettings = TaskKey[Unit]("metamodelSettings")
val metamodel = TaskKey[Unit]("metamodel")
metamodelSettings := {
print("Metamodel generation started")
javacOptions := Seq(
"-verbose",
"-g",
"-processor", "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor",
"-s", "app",
"-proc:only"
)
}
metamodel := {
print("Metamodel generation complete")
}
metamodel <<= metamodel.dependsOn(metamodelSettings, compile in Compile)
How can I change the javacOptions just for my metamodel task?
Edit:
[info] This is sbt 0.13.0
$ inspect metamodelSettings:javacOptions
[info] Task: scala.collection.Seq[java.lang.String]
[info] Description:
[info] Options for the Java compiler.
[info] Provided by:
[info] */*:javacOptions
[info] Defined at:
[info] (sbt.Defaults) Defaults.scala:209
[info] Delegates:
[info] metamodelSettings:javacOptions
[info] *:javacOptions
[info] {.}/metamodelSettings:javacOptions
[info] {.}/*:javacOptions
[info] */metamodelSettings:javacOptions
[info] */*:javacOptions
[info] Related:
[info] *:metamodelSettings::javacOptions
[info] compile:javacOptions
[info] *:metamodel::javacOptions
[info] */*:javacOptions
[info] compile:doc::javacOptions
show metamodelSettings::javacOptions is showing the expected values, but still not using them.
[test] $ show metamodelSettings::javacOptions
[info] List(-verbose, -g, -processor, org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor, -s, app, -proc:only)
[success] Total time: 0 s, completed 04-Feb-2014 11:29:56
If you want to set javacOptions only for metamodelSettings then use in to provide a scope for settings:
javacOptions in metamodelSettings := Seq(...)
You can also use different style whith inTask;
inTask(metamodelSettings) {
// your settings
}
As I was unable to override the settings, I resorted to invoking the compiler directly. This seems like a nasty solution to me, but maybe somebody will find it useful.
val metamodel = TaskKey[Unit]("metamodel")
javacOptions := Seq("-proc:none")
cleanFiles <++= baseDirectory (_ ** "*_.java" get)
metamodel := {
managedClasspath in Compile <<= (classpathTypes, update) map {
(ct, report) =>
Classpaths.managedJars(Compile, Set("jar", "zip"), report)
}
val javac = (Keys.compileInputs in Keys.compile in Compile).value.compilers.javac
val src = (file("app") / "models") ** "*.java"
val cp = (managedClasspath in Compile).value.map(x => x.data)
val out = file("app/models")
val args = Seq(
"-processor", "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor",
"-s", "app",
"-proc:only"
)
javac(sources=src.get, classpath=cp, outputDirectory=out, options=args)(ConsoleLogger())
}