Run "clean" all dependent SBT subprojects - scala

I have an SBT project, specifically a Play Framework 2.1 project, that has a number of subprojects specified in the configuration. The dependencies seem to work fine when compiling, but "clean" only seems to clean the currently selected project, not including its dependencies. Is there any way to clean both the selected project and its dependent subprojects?

If your main project aggregates subjects, like this:
lazy val root = Project("name", file("."))
.aggregate(module1, module2, macros)
then any command called on this root project will be executed for all subprojects. If you call inspect clean command in your sbt session, you'll see, under Related section all subprojects which relates on this clean
On the side note in the comment
aggregate and dependsOn are different command for different purposes. The purpose of aggregation is in running commands called on the root project. In my example by calling test command on my root project, this command will be executed also for module1 module2 and macros. If you want to turn off such behaviour with the following setting:
aggregate in test := false
Aggregated project are independent on the code in them. It's usually used on the root project, nfor example not to call test on each project, but to call it on root. Remeber that in case of aggregation commands will be executed in parallel.
And dependsOn means that your project will depend on the code from other project. And in this case SBT will execute command sequentialy, in order to compile your root project, which dependsOn some modules, it should compile those modules at first step, the the root project.

Related

Build sbt project in uber jar instead of individual submodule jars

Been recently trying to change the way my Scala project does the assembly so that only a single jar is generated out of it instead of one per module.
main-project
| - inner-module-one [inner_module_one]
| - inner-module-two [inner_module_two]
What I've currently done is the following for the main module (the one I want its uber jar containing other modules content).
project
.in(file("."))
.settings(
name := "main-project",
assemblyName,
settings
)
.aggregate(
inner_module_one,
inner_module_two
)
Having the other two modules declared as follows.
lazy val inner_module_one = project
.in(file("inner-module-one"))
.settings(
name := "inner-module-one",
assemblyName,
settings,
dependencies and such (...)
)
.dependsOn(
inner_module_two
)
The jar file generated for the main-project is really, really small (no more than 5mbs in size) and only contains Scala related stuff, no project classes or such. However, other modules jars are complete and contains everything they require.
I've already tried adding the following setting to the main-project.
aggregate in assembly := false
But still no luck so far. Jars for submodules aren't generated but the main-project jar still doesn't contain the contents of the submodules.
Any clue where the issue could be?
EDIT
Tried what #LuisMiguelMejíaSuárez suggested and seems to be wanting to build, however, some errors arise that were already solved within their respective modules. In a given module there are some conflicts which are solved due to some overrides, but now they are appearing again.
[error] deduplicate: different file contents found in the following:
Having the dependsOn instead of aggregate affects the way dependencies are added, overridden and such?
Let's divide your question into two sections, how to include the submodules into the main-project, and you want to know how to not package assembly the 2 submodules.
Let's start from the easier, the second. sbt-assembly, is a plugin for sbt. Just like any other plugin, you cann disable it using the disablePlugins command. Therefore, if you define:
lazy val inner_module_one = project.disablePlugins(AssemblyPlugin)
.in(file("inner-module-one"))
.settings(
name := "inner-module-one"
)
.dependsOn(
inner_module_two
)
then inner_module_one won't build a jar.
To solve the first question, we need to understand the difference between aggregate and dependsOn. For that I'll quote from Jacek Laskowski great explanation:
aggregate causes the tasks to be executed in the aggregating module and all aggregated one while dependsOn sets a CLASSPATH dependency so the libraries are visible to the aggregateing module (depending on the configuration that's compile aka default in the example).
Therefore, when you aggregate inner_module_one, and inner_module_two, you just cause then to assembly as well. In order to get those to be part of main-project all you need to do is declare:
project
.in(file("."))
.settings(
name := "main-project",
assemblyName,
settings
)
.dependsOn(
inner_module_one,
inner_module_two
)
In order to test it, I created the following structue:
main-project
|-inner_module_one
|-main
|-scala
|One.scala
|-inner_module_two
|-main
|-scala
|Two.scala
In order to check whether the class One was in a jar I used the command:
jar tfv inner-module-one/target/scala-2.12/inner-module-one-assembly-0.1.0-SNAPSHOT.jar | grep One
Then, when running sbt assembly with the original aggregate, the command above provided empty results on the output jar. And when running sbt assembly with dependsOn, the command above provided one result:
480 Fri Oct 09 01:48:14 IDT 2020 One.class
If this causes conflicts, you can read about it at sbt-assembly: deduplication found error

sbt-assembly multimodule project?

My project is separated on multiple parts:
* core project
* utils (as example) project
Both of them have some unit-tests, and "core project" relies on code in "utils" project by "dependsOn" mechanism of sbt.
I am using sbt-assembly plugin for building "uber-jar"/"fat-jar", but sbt assembly task does`t run test on utils project - which is what I am trying to achieve (I can not see any tests from "utils project" in logs)
Changing "dependsOn" to "aggregate" introduce new problem:
sbt assembly aggregate deduplicate
something similar to this issue-on-github
So my question is how to organize multimodule project which can be assembled by sbt-assembly and all of the tests are executed during assembly task?
My guess is that you should have both dependsOn and aggregate relationships between your subprojects. They are not mutually exclusive, only serve different purposes.
DependsOn introduces code dependency, so if core depends on utils it means that you can reference types from utils in core.
Aggregate introduces task dependency. That means if you execute compile or test on core and it aggregates utils then the task will be executed on both subprojects.
Problems with deduplicate are another beast - it means, that there are duplicates in resources or classes when attempting to create one jar. The reasons for this may be various and you can tackle them by verifying the library dependencies in the build or creating MergeStrategy - https://github.com/sbt/sbt-assembly#merge-strategy

Running gradle tasks from a subproject with unknown root

I have a multi-project setup in gradle with a somewhat-flat structure like so:
RootProject/
build.gradle
settings.gradle
SubProjectA/
build.gradle
anotherDirectory/
SubProjectB/
build.gradle
SubProjectC/
build.gradle
The root project is really just a root build. It's there to tie all of the other projects together. SubProjectB depends on SubProjectC, and C depends on A.
Running tasks from the root project works as expected. I can run gradle :SubProjectB:build and it will build SubProjectB and its dependencies without error.
My problem is that if I try to run a task from a sub-project's directory, it fails if that sub-project depends on any of the other sub-projects because it doesn't know where any of the others are without the root project's settings file. So running A's build from its directory would work, but running B's or C's would fail.
Is there anything I can do within this structure to define what the root project actually is, so that if I run gradle build from B, it would behave the same as running gradle :SubProjectB:build from the root project's directory?
The end goals are to make it easier to use gradle from the command line, and to get functional default tasks on the sub-projects. That way I should be able to double-click a project Eclipse's Gradle tasks list, and have it run the default tasks as though it were running the tasks from root.
In this case, you can use composite builds. Let say you are at SubProjectA and want to build against SubProjectB. The you can execute the command below:
gradle --include-build ../anotherDirectory/SubProjectB run
SubProjectB will build first and then SubProjectA.

Running multi-project sbt project results in clobbered compilation of shared project

I have a play application and a normal scala application that have shared code in a dependency defined as such:
project A
project B
shared
lazy val shared = (project in file("shared")).settings(...)
lazy val projectA = (project in file("A")).settings(...).dependsOn(shared)
lazy val projectB = (project in file("B")).settings(...).dependsOn(shared)
Due to the way sbt handles triggered execution, running sbt ~run in development mode is not usable for handling file changes correctly. I'm also using sbt-revolver to handle re-running the non-play application. As a result, I run both applications separately using the commands:
sbt 'project A' '~run'
sbt 'project B' '~reStart'
in parallel, so when I make a change to shared, both try to recompile it, and therefore sometimes result in an error. I frankly despise SBT's documentation, and cannot figure out how to get this to work within SBT, so I am asking for help.

sbt skip tests in subproject unless running from within that project?

I have an SBT project with multiple subprojects. One of the subprojects have tests that I don't want to run unless I explicitly do something like ";project xyz ;test-only". So, if my project structure is:
main
main/abc
main/def
main/xyz
Ideally, running "test" in main would execute any tests in main, main/abc, and main/def projects, but not main/xyz.
I tried to add a test filter in the build file for the main class that excludes all tests in main/xyz (by package name), then adding a separate build.sbt file in the main/xyz project to add them back, but this still results in the tests being executed from the top-level project...
"Aggregation" is the name of the feature that makes test execute on other projects (known as aggregated projects or "execution dependencies") as well as the current one. You can find more information on the Multi-Project Builds page.
I would create a custom task in the "main" project that depends on the tasks you want to run. For example,
myTestTask <<= Seq(
test in (main, Test),
test in (abc, Test),
test in (deff, Test)
).dependOn
where val myTestTask = TaskKey[Unit]("my-test-task") and main, abc, and deff are references to your Projects.
Aggregation is only applied to the top-level task specified on the command line. So, if you call my-test-task, that will be the only task aggregated (in this case, it won't be defined on any subprojects, so no tasks get added through aggregation). In particular, its dependencies, the explicitly listed test tasks, don't get aggregated. The consequence is that test in xyz doesn't get executed when you call my-test-task.
Finally, note that you can say xyz/test-only to run test-only for the xyz project without changing to that project.