How to handle multiple build targets eg. dev, test, main?

I am currently switching from Maven to SBT and I am struggling to figure out how I can handle multiple build targets (dev, test, train, prod, etc.).

For example, I have persistence.xml

one that looks like this:

    <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.driver.OracleDriver"/>
    <property name="javax.persistence.jdbc.url" value="${db.connectionURL}"/>
    <property name="javax.persistence.jdbc.user" value="${db.username}"/>
    <property name="javax.persistence.jdbc.password" value="${db.password}"/>
    <property name="" value="Oracle10"/>


With Maven it was very easy to get around using profiles.

I've already tried what has been suggested here for SBT, but I haven't had that much success. How to add environment profile configuration to SBT .

Also, using this approach, I will need a new directory for every new environment. I just think there must be a better way to handle this kind of setup using SBT?


source to share

1 answer

tl; dr Use ivyConfigurations

to add custom configurations and resourceGenerators

to process files in the environment.

All credits go to Eugene Yokota for his answer to How to Add Environment Profile Configuration to SBT . There are some modifications that make my decision ... cough ... cough ... a little better.

The next one build.sbt

defines two new configurations - dev and qa . It also defines, resourceGenerators

for each configuration, which effectively allows access to the configuration that the new resource generator is executing:

val Dev = config("dev") extend Runtime

val Qa  = config("qa") extend Runtime

ivyConfigurations ++= Seq(Dev, Qa)

lazy val bareResourceGenerators: Seq[Setting[_]] = Seq(
  resourceGenerators += Def.task {
    val file = resourceManaged.value / "demo" / ""
    println(s"Inside ${configuration.value}")
    val contents = s"config=${configuration.value}"
    IO.write(file, contents)

inConfig(Dev)(Defaults.configSettings ++ bareResourceGenerators)

inConfig(Qa)(Defaults.configSettings ++ bareResourceGenerators)


Inside the new ResourceGenerator, you can do whatever you want, and handling each configuration is possible with a parameter configuration

that gives you the name of the configuration:

> show dev:configuration
[info] dev
> show qa:configuration
[info] qa


Now when you execute show qa:resources

, you will see that there are two files generated with the target/scala-2.10/resource_managed/qa/demo/

content defined for the config:

> show qa:resources
Inside qa
[info] List(/Users/jacek/sandbox/envs/target/scala-2.10/resource_managed/qa/demo/, /Users/jacek/sandbox/envs/src/qa/resources)


Now you need to use the ResourceGenerator to meet your needs, and since you are in Scala code you can do whatever you want, just use it configuration.value

as a qualifier for the configuration specific code.

Let's say you want to use a properties file qa

in the standard directory src/main/resources

. Just know what the value is bound to (what configuration and value setting comes from). It's simple compile:resourceDirectory


> show compile:resourceDirectory
[info] /Users/jacek/sandbox/envs/src/main/resources


Just use resourceDirectory in Compile

whenever you need a "stable" (as well as a fixed configuration) value, eg src/main/resources


val props = (resourceDirectory in Compile).value / s"${}.properties"
println(s"Read files from $props")


With the above lines, you get:

> show qa:resources
Inside qa
Read files from /Users/jacek/sandbox/envs/src/main/resources/
[info] List(/Users/jacek/sandbox/envs/target/scala-2.10/resource_managed/qa/demo/, /Users/jacek/sandbox/envs/src/qa/resources)

> show dev:resources
Inside dev
Read files from /Users/jacek/sandbox/envs/src/main/resources/
[info] List(/Users/jacek/sandbox/envs/target/scala-2.10/resource_managed/dev/demo/, /Users/jacek/sandbox/envs/src/dev/resources)




All Articles