I have a multi-project SBT configuration. I have a class my.AClass in project1. What should I add to configuration to make scaladoc as follows
/**
* [[my.AClass]]
*/
class BClass
in project2 be successfully compiled by sbt project2/doc?
Are you using https://github.com/sbt/sbt-unidoc ? If not, perhaps it may be the solution you're looking for.
Something like this should work:
val scalaVer = "2.12"
val commonSettings: Seq[Def.Setting[_]] = Seq(
autoAPIMappings := true,
apiURL := Some(url(s"file:${baseDirectory.value.getAbsolutePath}/target/scala-${scalaVer}/api")),
)
lazy val a = (project in file("a")).settings(commonSettings)
lazy val b = (project in file("b")).settings(commonSettings)
Related
I'm using a compiler plugin I wrote that depends on the Kyro serialization library. When attempting to use my plugin I set this up in build.sbt (top-level) like this:
lazy val dependencies =
new {
val munit = "org.scalameta" %% "munit" % "0.7.12" % Test
val kyro = "com.esotericsoftware" % "kryo" % "5.0.0-RC9"
}
lazy val commonDependencies = Seq(
dependencies.kyro,
dependencies.munit
)
lazy val root = (project in file("."))
.settings(
libraryDependencies ++= commonDependencies,
Test / parallelExecution := false
)
addCompilerPlugin("co.blocke" %% "dotty-reflection" % reflectionLibVersion)
But when I compile my target project, I get a java.lang.NoClassDefFoundError that it can't find Kyro. I've added kyro to my dependencies, but since this is for the compiler, not my app, it's not picking that up.
How can I properly tell sbt about a dependency my plugin needs?
In all of the examples I've seen regarding multi-module builds and sbt-native-packager, they all aggregate the sub-projects into a single package. I have sub-projects that each provide a micro-service. I believe that each of these should have it's own native package, but I don't see how to do that and have a one command build for all of the sub-projects.
This turns out be straightforward. Simply provide native-packager settings for each of the sub-projects that you want to package and don't provide any on the aggregating project.
I tested by modifying https://github.com/muuki88/sbt-native-packager-examples/tree/master/multi-module-build accordingly:
import NativePackagerKeys._
name := "mukis-fullstack"
// used like the groupId in maven
organization in ThisBuild := "de.mukis"
// all sub projects have the same version
version in ThisBuild := "1.0"
scalaVersion in ThisBuild := "2.11.2"
// common dependencies
libraryDependencies in ThisBuild ++= Seq(
"com.typesafe" % "config" % "1.2.0"
)
// this is the root project, aggregating all sub projects
lazy val root = Project(
id = "root",
base = file("."),
// configure your native packaging settings here
// settings = packageArchetype.java_server++ Seq(
// maintainer := "John Smith <john.smith#example.com>",
// packageDescription := "Fullstack Application",
// packageSummary := "Fullstack Application",
// entrypoint
// mainClass in Compile := Some("de.mukis.frontend.ProductionServer")
// ),
// always run all commands on each sub project
aggregate = Seq(frontend, backend, api)
) dependsOn(frontend, backend, api) // this does the actual aggregation
// --------- Project Frontend ------------------
lazy val frontend = Project(
id = "frontend",
base = file("frontend"),
settings = packageArchetype.java_server++ Seq(
maintainer := "John Smith <john.smith#example.com>",
packageDescription := "Frontend appplication",
mainClass in Compile := Some("de.mukis.frontend.ProductionServer")
)
) dependsOn(api)
// --------- Project Backend ----------------
lazy val backend = Project(
id = "backend",
base = file("backend"),
settings = packageArchetype.java_server++ Seq(
maintainer := "John Smith <john.smith#example.com>",
packageDescription := "Fullstack Application",
packageSummary := "Fullstack Application",
// entrypoint
mainClass in Compile := Some("de.mukis.frontend.ProductionServer")
)
) dependsOn(api)
// --------- Project API ------------------
lazy val api = Project(
id = "api",
base = file("api")
Results:
debian:packageBin
...misc messages elided...
[info] dpkg-deb: building package `frontend' in `../frontend_1.0_all.deb'.
[info] dpkg-deb: building package `backend' in `../backend_1.0_all.deb'.
For whom just ended up here, a more up-to-date answer could look like:
lazy val root = (project in file("."))
.aggregate(common, frontend, backend)
lazy val common = (project in file("common"))
lazy val frontend = (project in file("frontend"))
.enablePlugins(JavaServerAppPackaging)
lazy val backend = (project in file("backend"))
.dependsOn(common)
.enablePlugins(JavaAppPackaging)
.settings(javaPackagingSettings)
lazy val javaPackagingSettings = Seq(
// follow sbt-native-packager to identify settings you need
)
Description
Here is the scenario supporting the above configuration
Project root is the parent and we don't want to package it. It aggregates other subprojects.
Project common is a sort of library and also we don't want to package it
Project backend depends on common for the libraries.
Project frontend is a standalone project packaged as a Java server app with default configuration
I want make a take cleanAll that executes the clean task on a number of subprojects. I don't want to use aggregation just for the sake of clean.
We've run into issues with play's asset routes when we've been using submodules.
It's well documented how to create a new task, but how do I call a task on a subproject?
Based on the example by Jacek Laskowski I've come up with the following plugin that should be placed in your /project folder:
import sbt._
import sbt.AutoPlugin
import sbt.Keys._
import sbt.plugins.JvmPlugin
object CleanAllPlugin extends AutoPlugin {
val cleanAll = taskKey[Unit]("Cleans all projects in a build, regardless of dependencies")
override def requires = JvmPlugin
override def projectSettings = Seq(
cleanAllTask
)
def cleanAllTask = cleanAll := Def.taskDyn {
val allProjects = ScopeFilter(inAnyProject)
clean.all(allProjects)
}.value
}
The plugin can now be added to the root project for usage:
val main = Project("root", file("."))
.enablePlugins(CleanAllPlugin)
It can be executed in SBT by calling: cleanAll
Use the following build.sbt:
val selectDeps = ScopeFilter(inDependencies(ThisProject))
clean in Compile := clean.all(selectDeps).value
It assumes that the build.sbt file is in the project that has clean executed on itself and dependsOn projects.
If you need it in project/Build.scala, just add the following:
val selectDeps = ScopeFilter(inDependencies(ThisProject))
val cleanInSubprojects = Seq(
clean in Compile := clean.all(selectDeps).value
)
and add cleanInSubprojects to settings of every project:
// definition of a project goes here
.settings(cleanInSubprojects: _*)
I have a variable libDir defined in Global & when I try to use it inside one of the sub-projects (with specifying the scope), it fails with:
[info] Loading project definition from /Users/chichu/ws/tip/TestMain/project
References to undefined settings:
*/*:libDir from Streaming/*:install (/Users/chinchu/ws/tip/TestMain/build.sbt:124)
Did you mean TestRoot/*:libDir ?
Here's the snippet from build.sbt:
===
def Streaming(name: String, dir: String,
archiveName: String, main: String): Project = {
...
...
install := {
val jarName = assembly.value
sbt.IO.copyFile(jarName, (libDir in Global).value) // copy over the jar
}
}
..
..
lazy val installDir = SettingKeyFile
libDir := baseDirectory.value / "install/lib"
==
Why is it not able to resolve "libDir" even when I specify "in Global" ? I also tried "libDir in TestRoot" & it reports "error: not found: value TestRoot"
Thanks
-C
The specification says, that if you define a setting like this:
libDir := baseDirectory.value / "install/lib"
It will set a task and a configuration scope to Global, but a project scope will be set to current project (that is a root project in your case).
When you refer to your setting as libDir in Global, you set configuration scope to Global but still, you are in the current build, that is some project, that tries to define the install setting.
You should define your libDir like this:
libDir in Global := baseDirectory.value / "install/lib"
which will set also the project scope to Global.
Example build.sbt
lazy val installDir = settingKey[File]("ff")
lazy val install = taskKey[Unit]("prints install")
installDir in Global := baseDirectory.value / "install/lib"
val projectA = project.in(file("projectA")).settings(
install := {
val install = (installDir in Global).value
println(install)
}
)
val projectB = project
Alternative Solution
Alternatively you could give a root project an explicit id, that is in your main build.sbt add a line
val root = Project("root", file("."))
then in your install task refer to Global in that project (root is a name of the project)
(libDir in Global in root).value
Example build.sbt
lazy val installDir = settingKey[File]("ff")
lazy val install = taskKey[Unit]("prints install")
installDir := baseDirectory.value / "install/lib"
lazy val root = Project("root", file("."))
lazy val projectA = project.in(file("projectA")).settings(
install := {
val install = (installDir in Global in root).value
println(install)
}
)
lazy val projectB = project
I would like to configure sbt-assembly to skip a specific test class.
Is there any way to do this? If it helps, I tagged the test using ScalaTest #Network tag.
See Additional test configurations with shared sources. This allows you to come up with alternative "test" task in FunTest configuration while reusing your test source.
After you have fun:test working with whatever filter you define using testOptions in FunTest := Seq(Tests.Filter(itFilter)), you can then rewire
test in assembly := test in FunTest
Eugene is right (obviously) but that wasn't quite enough information for me to get it to work - I have a build.scala file. I am defining baseSettings like this:
val baseSettings = Defaults.defaultSettings ++
buildSettings ++
Seq(sbt.Keys.test in assembly := {})
You can tag your tests with ignore, then sbt/ScalaTest won't run them. See ScalaTest docs on Tagging tests.
Just for completeness, if you want to skip all tests in assembly task or run only particular ones you can customize it with test in assembly := { ... }
Based on #eugene-yokata reply, I found how to use the flag from ScalaTest:
lazy val UnitTest = config("unit") extend (Test)
lazy val companyApp = (project in file("applications/"))
.assembly("com.company.app", "app.jar")
.configs(UnitTest)
.settings(
inConfig(UnitTest)(Defaults.testTasks),
UnitTest / testOptions ++= Seq(
Tests.Argument(
TestFrameworks.ScalaTest,
"-l",
"com.company.tag.HttpIntegrationTest"
),
Tests.Argument(
TestFrameworks.ScalaTest,
"-l",
"com.company.tag.EsIntegrationTest"
)
),
test in assembly := (UnitTest / test).value
)