Where do SBT env variables come from? - scala

I'm moving my first steps with Scala (2.12.7) and SBT (1.2.7).
At some point, I want to get secret value from the environment:
sys.env("SECRET_TOKEN")
The problem is that, in the sbt shell, SECRET_TOKEN is not defined, therefore the application crashes.
So:
$ export SECRET_TOKEN="xxx"
$ sbt
[... sbt loads]
sbt> run
[ crashes because of the env var not found ]
It's like the sbt shell would get only a subset of the current environment.
Am I missing something?
Thanks

sbt (script + launcher) just launches a fancy java process, which should inherit the environment variables from the parent process.
Given
$ export SECRET_TOKEN="xxx"
Both build.sbt and your application during run should have access to sys.env("SECRET_TOKEN").
In the comment section, Bruno suggested SECRET_TOKEN="xxx" sbt, which apparently worked, but I don't know how that's different from export.
In any case,
object Hello extends App {
println(sys.env("SECRET_TOKEN"))
}
works for me
sbt:hello> run
[info] Running Hello
xxx

Related

Scala sbt -D environemt variable not found

I am trying to access an environment variable in my sbt build file.
As told I set the environment variable with the jvm -D Option
sbt -DaccessToken=***** compile
but scala cannot find the variable
sys.env.get("accessToken").getOrElse(throw new RuntimeException("System variable 'accessToken' with the credentials is not set."))
Why does the -D option have no effect?
If I set the variable with export in linux everything works fine.
Anything you pass as -D is not environment variable and cannot be read as sys.env.get.
You need to use Java API to read them
System.getProperty("accessToken")
Other option is to assign an environment variable before you launch your sbt. In bash, for example, it can be done like this but this, of course, depends on your environment.
accessToken=***** sbt compile

Is it possible to run 2 sbt projects at the same time?

I have 2 sbt projects that are runnable (akka app and another play application).
Is it possible to run both of them, and use ~reStart so they refresh on any changes to my project?
Any tips on doing this correctly so I don't run out of memory also?
If you are using Play Framework's latest version you can ~run without any plugin. Regarding standalone akka application you may use a library called sbt-revolver
runAkkaServer := {
(reStart in Compile in `akka-server`).evaluated
}
runWebServer := {
(~run in Compile in `web-server`).evaluated
}
mainClass in reStart := Some("com.example.MainAkka")
val runAkkaServer = inputKey[Unit]("Runs akka-server")
val runWebServer = inputKey[Unit]("Runs web-server")
NOTE: you can run both applications in restart mode without custom tasks:
1. ~run - Play server
2. reStart - Standalone
UPDATE:
I've tried to use following command to both of them, it seems that sbt-revolver is kinda trick and killing application onstart. When replace reStart with run it works perfect, but doesn't trigger changes.
screen -d -m sbt runAppServer; screen -d -m sbt runWebServer
So above code just doesnot behave as expected. Instead of custom tasks, we can run them in separate windows like this:
screen -dmS "appserver" sh -c "sbt 'project appserver;~reStart'; exec bash" ; screen -dmS "webserver" sh -c "sbt runWebServer; exec bash"
Also sbt runWebServer can be replaced by sbt 'project anothersubmodule;~run' if you wish.
I've created a simple demonstration project, you can find here
In order to start you can call just: ./starter.sh
NOTE: you can install screen command if you don't have easily.
Open two different Terminal tabs; cd into the specific directory in each tab and then run with SBT.
sbt run
For multiple web apps, specify a different port:
sbt run -Dhttp.port=8888

Run only tagged test in sbt custom test task

I have an sbt subproject that includes end to end tests. These are run as e2e:test. I have defined my config as
I have defined a tag in the same subproject.
object HealthCheckTest extends Tag("HealthCheckTest")
I am tagging some of my end to end tests with HealthCheckTest as follows:
it("should be able to verify the data", HealthCheckTest)
I want to run only the health check tests from command line. I am trying to do this via:
sbt 'project e2e' e2e:testOnly -- -n HealthCheckTest
but this leads to all of the e2e tests being run. I have tried giving the full path to the tag (com.s.p.e2etests.HealthCheckTest), but that does not work either.
Occasionally I get warnings about -- and - being deprecated; however, all documentation online says to use this syntax including scalatest docs.
How can I run just my tagged e2e tests?
I have also tried to create a separate task for health check tests but could only figure out how to filter based on test class name, not by tag.
The commandline you posted was missing quotes. Try it like this:
sbt 'project e2e' 'testOnly -- -n HealthCheckTest'
The sbt executable treats each argument as a full line to run in the sbt console, so you must place quotes around each full line.
Note that while this won't run the test cases, it will still instantiate test class and print out test case names.

sbt test-only specific test

I have several tests distributed over several classes.
I would like to run only the first test from the first class:
The class is:
class Step1_PrimarySpec
The test is:
test("case1: Primary (in isolation) should properly register itself to the provided Arbiter")
I tried:
sbt test-only Step1_PrimarySpec
and:
sbt test-only Step1_PrimarySpec 1
and:
sbt test-only "*Step1_PrimarySpec 1"
and:
sbt test-only "*Step1_PrimarySpec"
However, all of these commands ran the entire test suite.
So how can I run only that specific test?
You must place the double quotes around the whole command like this:
sbt "test-only <test-name>"
And according to this answer you should camelCase it to testOnly and use the -z argument
sbt "testOnly *Step1_PrimarySpec -- -z mytest"
That will run the test named mytest from the class (not the file) named Step1_PrimarySpec.
By using the *, the test runner saves us from specifying its fully qualified class name. i.e. org.path.to.Step1_PrimarySpec

Can sbt-native-packager generate multiple start scripts for one project?

I'm currently using sbt-native-packager to generate a start script for my scala application. I'm using packageArchetype.java_application. I create the script in sbt:
sbt clean myproject/stage
and then "install" the application by copying the created lib and bin directories to the installation directory. I'm not distributing it to anyone, so I'm not creating an executable jar or tarball or anything like that. I'm just compiling my classes, and putting my jar and all the library dependency jars in one place so the start script can execute.
Now I want to add a second main class to my application, so I want a second start script to appear in target/universal/stage/bin when I run sbt stage. I expect it will be the same script but with a different name and app_mainclass set to the different class. How would I do this?
The sbt-native-packager generated script allows you to pass in a -main argument to specify the main class you want to run. Here's what I do for a project named foo:
Create a run.sh script with whatever common options you want that calls the sbt-native-packager generated script:
#!/bin/bash
./target/universal/stage/bin/foo -main "$#"
Then I create a separate script for each main class I want to run. For example first.sh:
#!/bin/bash
export JAVA_OPTS="-Xms512m -Xmx512m"
./run.sh com.example.FirstApp -- "$#"
and second.sh:
#!/bin/bash
export JAVA_OPTS="-Xms2048m -Xmx2048m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC"
./run.sh com.example.SecondApp -- "$#"
Having multiple main classes is... supported now (Q4 2016, native package 1.2.0)
See "SBT Native Packager 1.2.0" by Muki Seiler
Single Project — Multiple Apps
A major pain point for beginners is the start script creation. The bash and bat start scripts are only generated when there is a either
Exactly one main class
Explicitly set main class with
mainClass in Compile := Some(“com.example.MainClass”)
For 1.2.x we will extends the implementation and support multiple main classes by default.
Native packager will generate a start script for each main class found on the classpath.
SBT provides them via the discoveredMainClasses in Compile task.
If there is only one main class, SBT will assign it to the mainClass in Compile setting. This leads to three cases:
Exactly one main class.
In this case native-packager will behave like previous versions and just generate a single start script, using the executableScriptName setting for the script name.
Multiple main classes and mainClass in Compile := None.
This is the default behaviour defined by SBT. In this case native-packager will generate the same start script for each main class.
Multiple main classes and mainClass in Compile := Some(…).
The user has set a specific main class, which will lead to a main start script being generated using the executableScriptName setting. For all other main classes native-packager generates forwarder scripts.
Having multiple main classes not supported now. As a workaround you could use single main class and check command line args.
Starting your app:
myApp prog1
In your main class:
def main(args: Array[String]): Unit = {
if(args[0] == "prog1")
Programm1.start()
else
Programm2.start()
}