How to make the sbt assembly task depend on test - scala

When I run sbt assembly the tests are not run. How can I make the tests to run before running the assembly task?

From the documentation at https://github.com/sbt/sbt-assembly#assembly-task:
To run the test during assembly,
lazy val app = (project in file("app"))
.settings(
assembly / test := (Test / test).value,
// more settings here ...
)

Related

Set mainClass for sbt native packager Universal

I have a project that has the following build.sbt:
addCommandAlias("package", "dist")
lazy val actual = (project in file("."))
.enablePlugins(UniversalPlugin, JavaServerAppPackaging)
.settings(
name := "DeployerPod",
mainClass := Some("com.myself.executable.Runner"),
Compile / mainClass := Some("com.myself.executable.Runner"),
Compile / run / mainClass := Some("com.myself.utils.Pipeline"),
Universal / mainClass := Some("com.myself.executable.Runner"),
Universal / compile / mainClass := Some("com.myself.executable.Runner"),
)
We have a CICD which runs a Dockerfile.
There I have sbt run as one of the steps, which will execute com.myself.utils.Pipeline class to run a Scala class and do the pre requisites for the pipeline.
As one of the last sbt based steps, I'm also running sbt package, which eventually runs an sbt dist command. At this point, inside the extracted ZIP's bin folder, I see two BAT files corresponding to the two main classes. Unfortunately I only want the Runner class BAT instead of Pipeline BAT.
For this I tried running sbt package -main com.myself.executable.Runner but that failed saying Not a valid command: -
Is there a way I can specify the mainClass only for this Universal plugin somehow? Because the way I've tried in my build.sbt doesn't seem to work.

How to set main class from submodule to root in sbt

I have multimodule setup, where root is just a project wrapper for submodules core and util.
Core is actually the application and contains main class(extending App) which I want to run.
Staying at project root(wrapper) I want to run sbt run and execute the main method from core submodule
lazy val root = project
.in(file("."))
.aggregate(util, core)
.settings(
mainClass in Compile := (mainClass in Compile in core).value
)
lazy val util = project
.in(file("util"))
lazy val core = project
.in(file("core"))
.settings(
mainClass in Compile := Some("com.iwaneez.scala.Hello"),
libraryDependencies ++= commonDependencies
)
.dependsOn(util)
I expect to run the application just by executing sbt run
addCommandAlias can be used to replace run in the root project.
lazy val root = project
.in(file("."))
.aggregate(util, core)
.settings(
addCommandAlias("run", "core/run")
)
sbt:root> run --test
[info] Running com.iwaneez.scala.Hello --test
Hello List(--test)
The following command will let you run the project
sbt "project core" run

How to use SBT to run ScalaTest tests against a fat jar?

I have a simple SBT project, consisting of some Scala code in src/main/scala and some test code in src/test/scala. I use the sbt-assembly plugin to create a fat jar for deployment onto remote systems. The fat jar includes all the dependencies of the Scala project, including the Scala runtime itself. This all works great.
Now I'm trying to figure out a way I can run the Scala tests against the fat jar. I tried the obvious thing, creating a new config extending the Test config and modifying the dependencyClasspath to be the fat JAR instead of the default value, however this fails because (I assume because) the Scala runtime is included in the fat jar and collides somehow with the already-loaded Scala runtime.
My solution right now works but it has serious drawbacks. I just use Fork.java to invoke Java on the org.scalatest.tools.Runner runner with a classpath set to include the test code and the fat jar and all of the test dependencies. The downside is that none of the SBT test richness works, there's no testQuick, there's not testOnly, and the test failure reporting is on stdout.
My question boils down to this: how does one use SBT's test commands to run tests when those tests are dependent not on their corresponding SBT compile output, but on a fat JAR file which itself includes all the Scala runtimes?
This is what I landed on (for specs2, but can be adapted). This is basically what you said was your Fork solution, but I figured I'd leave this here in case someone wanted to know what that might be. Unfortunately I don't think you can run this "officially" as a SBT test runner. I should also add that you still want Fork.java even though this is Scala, because Fork.scala depends on a runner class that I don't seem to have.
test.sbt (or build.sbt, if you want to put a bunch of stuff there - SBT reads all .sbt files in the root if you want to organize):
// Set up configuration for building a test assembly
Test / assembly / assemblyJarName := s"${name.value}-test-${version.value}.jar"
Test / assembly / assemblyMergeStrategy := (assembly / assemblyMergeStrategy).value
Test / assembly / assemblyOption := (assembly / assemblyOption).value
Test / assembly / assemblyShadeRules := (assembly / assemblyShadeRules).value
Test / assembly / mainClass := Some("org.specs2.runner.files")
Test / test := {
(Test / assembly).value
val assembledFile: String = (Test / assembly / assemblyOutputPath).value.getAbsolutePath
val minimalClasspath: Seq[String] = (Test / assembly / fullClasspath).value
.filter(_.metadata.get(moduleID.key).get.organization.matches("^(org\\.(scala-lang|slf4j)|log4j).*"))
.map(_.data.getAbsolutePath)
val runClass: String = (Test / assembly / mainClass).value.get
val classPath: Seq[String] = Seq(assembledFile) ++ minimalClasspath
val args: Seq[String] = Seq("-cp", classPath.mkString(":"), runClass)
val exitCode = Fork.java((Test / assembly / forkOptions).value, args)
if (exitCode != 0) {
throw new TestsFailedException()
}
}
Test / assembly / test := {}
Change in build.sbt:
lazy val root = (project in file("."))
.settings(/* your original settings are here */)
.settings(inConfig(Test)(baseAssemblySettings): _*) // enable assembling in test

How to run task defined in sbt plugin

In my project I use plugin which exposes task genExport. I can run genExport task from console with:
sbt genExport
My problem is I cannot configure my sbt project to run genExport after project compilation:
lazy val sample:Project = project
.in(file("sample"))
.settings(
MyPluginKeys.someKey := "someKeyValue",
compile in Compile <<= (compile in Compile) map { x =>
println("----------")
// ???
x
}
)
.enablePlugins(MyPlugin)
From sbt documentation I could not get how to invoke task from plugin by name. I've experimented with:
taskKey[Unit]("genExport").taskValue
without any success. What I'm missing?
val genexport = TaskKey[Unit]("genExport")
And
genExport <<= genExport triggeredBy (compile in Compile)

Code coverage for Scala integration tests with SCCT

I'm running integration tests in Scala - these are found in the src/it/scala directory, and I've added the following to my build.sbt:
seq(Defaults.itSettings: _*)
However, when I run SCCT to calculate code coverage, the integration tests are not run. How can I make them be run?
I am using scct 0.3-SNAPSHOT / sbt 0.13
for mergin test + it:test try the following setting:
ScctPlugin.instrumentSettings ++ Defaults.itSettings ++ Seq(
resourceDirectory in ScctPlugin.ScctTest <<= (resourceDirectory in Test),
sources in ScctPlugin.ScctTest ++= (sources in IntegrationTest).value
)
this might get tricky if you have different resources