sbt-assembly multimodule project? - scala

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

Related

Unit testing SBT code within the local project

I have an SBT project, within which I have defined a source generator that parses some DB migration scripts in order to make the current DB version available to the application at compile-time.
For example, I might have the following resources:
subproject1/src/main/resources/db/migration/
|- V1__Baseline.sql
|- V2__AddCustomerTable.sql
|- V2_1__Refactor.sql
And I would require my source generator to create a scala object with the field val version = "2.1".
The SBT project is structured as:
project/
|- build.sbt
|- SchemaVersionParser.scala
Where SchemaVersionParser defines the utility functions that are used by build.sbt in order to parse the resources and generate the appropriate file.
Now since this is a key component of my app, I'd like to ensure that the functions in SchemaVersionParser which extract and sort the versions are unit tested.
Is there any supported means of unit testing SBT code residing locally in the one project? I know I can do this if I create a separate SBT plugin, however it'd be nice if I could avoid this.
SBT build definitions are SBT projects. So put test code in project/src/test/scala should be able to access SchemaVersionParser, and to launch the tests you just do sbt test in project directory.

How to solve transitive dependencies version conflicts (scala/sbt)

I have a project with several utility classes. Let's name it Utils.
I have a proj1 which depends on Utils. And another proj2 that depends on proj1 and Utils.
The problem is if both proj1 and proj2 depend on different Utils version this will lead to problems.
What's the best solution?
This situation occurs in Scala/SBT projects, but I guess other languages have the same problems.
Edit:
Just to be clear, proj2 is the project that will run, that uses some code from proj1 and Utils.
This is classic Jar Hell, and it is a problem on any JVM based project not just scala with sbt.
There are 4 common solutions
Get rid of conflict by changing code, consolidate your multiple version dependency into a single dependency.
Shading (as mentioned above by #Sean Viera)
Multiple ClassLoader component architecture like OSGI (as mentioned by #tuxdna)
Run in separate JVMs like a microservice architecture (also mentioned by #tuxdna)
You have three different projects:
Utils
proj1 <- depends on Utils v1
proj2 <- depends on Utils v2
The only way you can be 100% sure that there are no conflicts between proj1 and proj2 is to run them in isolation.
As soon as you will mix proj1 and proj2 with different versions of Utils on the same classpath, you will end up override one or the other project.
You can achive isolation using:
run them in separate JVMs, with appropriate version of Utils
run them in same JVM but in different class loaders

How to setup SBT dependency for scala code that is located in same directory as Build.scala

Our project features a kind of adhoc "plugin" that reads csv files and stuffs the contents into a database.
This code is defined in /project/DataMigrate.scala
We had our own poorly implemented version of a CSV parser that isn't up to the task anymore so I tried to add this https://github.com/tototoshi/scala-csv to the libraryDependencies in /project/Build.scala but that did not make it importable from DataMigrate.scala. I also tried putting the library dependency in /project/build.sbt as I read something about "Build definition of a build definition", but that did not seem to help either.
Is it at all possible to add dependencies for code that lives in /project?
SBT is recursive, so just as you can define dependencies and settings of the actual project in [something].sbt or project/[something].scala you can define dependencies and settings of the projects project (any ad hoc plugins etc) in project/[something].sbt or project/project/[something].scala

Play Framework evolutions in different subprojects

I have a Play Framework 2.2 project that has different subprojects. Everything worked fine while only one of those subprojects had SQL evolution scripts.
Now, I'm trying to introduce another subproject with a SQL evolution script and I see no way of defining dependencies between them, or even to execute them both, while keeping them in their subprojects (where logically they belong).
So, how can I have evolution scripts in different submodules and have them all execute, respecting dependencies between them?
Thanks!
Add to application.conf file the list of models packages:
ebean.default = ["models.common.*","models.sub1.*", "models.sub2.*",
...]
And use dependsOn in build.sbt like this to get what you need:
lazy val sub1 = project.in(file("modules/sub1"))
.enablePlugins(PlayJava,PlayEbean)
.dependsOn(common)
Attention: the sintax is for play framework 2.4

How do I use shared configurations across SBT (Play) multi-projects?

I have several SBT 0.13 / Play 2.2 projects (websites). They are all multi-module as they share some common functionality. This makes their project configuration files both complex and almost identical, but not quite.
I would like to be able to share as much as possible of these configuration files across the projects (frequent play updates makes keeping 5+ websites up to date a royal pain, not to mention all the almost-identical-but-evolving dependency lists across the projects).
build.properties and plugins.sbt are identical across projects and can be overwritten by a simple script. Great.
Build.scala is trickier - I would like to introduce a shared base class like so:
abstract class MyBuildBase extends Build { ... }
that in Build.scala do:
object ApplicationBuild extends MyBuildBuild { ... }
In order for this to make any sense at all, MyBuildBase.scala needs to be shared across projects. This can be done with svn:external, which operates on directories. Which means I need to somehow make this shared directory accessible when Build.scala is compiled (otherwise sbt complains loudly).
Reading http://www.scala-sbt.org/0.13.0/docs/Detailed-Topics/Classpaths.html and http://www.scala-sbt.org/0.13.0/docs/Getting-Started/Full-Def.html it seems like this should be possible.
However, it is exceptionally unclear to me what to actually put in the project/project/Build.scala file to actually achieve this - I can't find an example of "an sbt build file that's intended to build an sbt build file and include some extra source files in the build".
Any suggestions?
What you probably want to do is create a plugin, or shared library.
You can make an sbt project with a build like follows:
build.sbt
sbtPlugin := true
organization := "you"
name := "common-build"
version := "1.0"
Then create in src/main/scala your abstract class "MyBuildBase". Release this project as an sbt plugin.
Then in your other projects, you can use this as a library/plugin. In project/plugins.sbt add:
addSbtPlugin("you" % "common-build" % "1.0")
And this will resolve your common build library when building your build.
If you need more information, look up more about sbt plugins and ignore the part about making something that extends a Plugin. Plugins are just libraries versioned with sbt's version number and your own. You should be able to put whatever code you want in there to share between builds.
Note: in 2016, Build.scala is deprecated for Build.sbt.
Here is the new (Dec. 2016) multi-module with App Scala sbt template by Michael Lewis.
Usage
sbt new lewismj/sbt-template.g8
You can then run:
sbt compile
sbt publish-local
sbt assembly
It is based on Scala SBT template (Library)
This giter8 template will write SBT build files for a Scala library.