Set System Property in Gradle command line [duplicate] - gradle

I am trying to run a command-line Java app via Gradle as part of a quick integration test. I am porting my build scripts from Maven, where this was easily done via exec-maven-plugin. My two big requirements are:
Being able to pass system properties to the executable Java code
Being able to pass command-line args to the executable Java code
Please note that I am not trying to read these properties in the build script, I'm trying to read them in the Java program that the script builds and executes.
I have found two other SO posts that address Java program execution via Gradle: one with an answer that advocates using apply plugin: "application" in the build file and gradle run at the command line, and another with answers advocating that approach as well as using task execute(type:JavaExec) in the build file and gradle execute at the command line. I have tried both approaches and have not succeeded.
I have two problems:
(1) I cannot get the Java executable to read the system properties
Whether I do this:
build.gradle:
apply plugin: 'application'
mainClassName = "com.mycompany.MyMain"
Command line:
gradle run -Dmyproperty=myvalue
Or this:
build.gradle:
task execute (type:JavaExec) {
main = "com.mycompany.MyMain"
classpath = sourceSets.main.runtimeClasspath
}
Command line:
gradle execute -Dmyproperty=myvalue
In either case, myproperty does not make it through. The code that begins running from MyMain.main (...) reads the myproperty system property as null/missing.
(2) I cannot pass command line arguments
This is probably related to the first problem. In exec-maven-plugin, for example, command line args were themselves passed in via a system property. Is that the case with Gradle, or is there another way to pass command line arguments?
How do I get these variables through? Also, is it better to use apply plugin: 'application' or task execute (type:JavaExec)?

Figured it out. The main issue is that when Gradle forks a new Java process, it does not automatically pass the environment variable values along to the new environment. One has to explicitly pass these variables via the systemProperties property of the task or plugin.
The other issue was understanding how to pass command-line args; these are via the args property on the task or plugin. As with the Maven exec-maven-plugin, they should be passed in on the command line via yet another system property, as a space-delimited list that then needs to be split() before setting args, which accepts List objects. I've named the property exec.args, which is the old Maven name.
It seems both the javaExec and application plugin approach are valid. One might favor the application plugin approach if one wants to use some of its other features (automatically putting together a distribution, etc.)
Here are the solutions:
JavaExec Approach
Command Line:
gradle execute -Dmyvariable=myvalue -Dexec.args="arg1 arg2 arg3"
build.gradle:
task execute (type:JavaExec) {
main = "com.myCompany.MyMain"
classpath = sourceSets.main.runtimeClasspath
/* Can pass all the properties: */
systemProperties System.getProperties()
/* Or just each by name: */
systemProperty "myvariable", System.getProperty("myvariable")
/* Need to split the space-delimited value in the exec.args */
args System.getProperty("exec.args", "").split()
}
Application Plugin Approach
Command Line:
gradle run -Dmyvariable=myvalue -Dexec.args="arg1 arg2 arg3"
build.gradle:
apply plugin: 'application'
mainClassName = "com.mycompany.MyMain"
run {
/* Can pass all the properties: */
systemProperties System.getProperties()
/* Or just each by name: */
systemProperty "myvariable", System.getProperty("myvariable")
/* Need to split the space-delimited value in the exec.args */
args System.getProperty("exec.args", "").split()
}

For those who might not want to pollute your application's system properties by passing unrelated Gradle props, I recommend namespacing your arguments.
tasks.withType(JavaExec) {
System.properties.each { k,v->
if (k.startsWith("prefix.")) {
systemProperty k - "prefix.", v
}
}
}
java ... -Dprefix.my.prop=true will pass my.prop

I'm new to gradle so I needed this and what is working for me with gradle 4.6 seems a little easier for the command line. Instead of parsing 1 arg string you can pass an array of args, and I found a way to pass in all property with one line as well. Combined below:
apply plugin: 'java'
apply plugin: 'org.springframework.boot' <- for my project
task runApp(type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = 'testit.TomcatApp'
// arguments to pass to the application
// args 'myarg1 -rest' <- came in as 1 string
args = ["--myarg1 with spaces even", "--myarg2"]
// and to pass in all -D system property args:
systemProperties = System.properties
}
gradle run -Dwhatever=xxx -Dmyarg2=hey
// Java reading them:
public static void main(String[] args) {
for ( int i = 0; i < args.length; i++ )
{
logger.info( "** args [" + i + "] =" + args[i] + "=" );
}
logger.info( "** -Dwhatever =" + System.getProperty("whatever") + "=" );
logger.info( "** -Dmyarg2 =" + System.getProperty("myarg2") + "=" );
[main] INFO testit.TomcatApp - ** args [0] =--myarg1 with spaces even=
[main] INFO testit.TomcatApp - ** args [1] =--myarg2=
[main] INFO testit.TomcatApp - ** -Dwhatever =xxx=
[main] INFO testit.TomcatApp - ** -Dmyarg2 =hey=

Maybe I am late for the party, but has anyone tried with "set the prop before executing gradle"? I have tested and this works too, apparently.
myVar=myVal gradle test
For example, you can set the active profile like:
SPRING_PROFILES_ACTIVE=dev gradle test
These also work, apparently:(tested)
set myVar=myVal && gradle test # for windows
export myVar=myVal && gradle test # for linux and mac
Be wary that myVar cannot be period-separated; or else only the part before the first period will be taken as key.

Related

Gradle: get task command line arguments inside the task

I'm running my tests with gradle using the command line:
./gradlew testManager:uiTest -PignoreTestFailures=true" +
"-DCHROMEDRIVER_VERSION=${env.CHROMEDRIVER_VERSION}" +
"-DBASE_URL=${params.BASE_URL}"
I need to propagate passed properties (e.g. BASE_URL) to the JMV with tests from the gradle task.
I know I could do the following inside the task:
systemProperties System.properties
But I'd like to avoid passing the whole set, as it overrides some other required values in tests.
So the question is: is there a way to get the only properties passed via -D command line parameter, inside the gradle task?
Found this pretty easy way:
task uiTest(type: Test) {
doFirst {
/* Propagate only command line start properties (-D) to the tests */
project.gradle.startParameter.systemPropertiesArgs.entrySet().collect() {
systemProperty it.key, it.value
}
}
}
So in a case of
./gradlew testManager:uiTest -PincludeTests=saveReleaseState/** -DBASE_URL=foobar
The tests receive only BASE_URL=foobar

How to get the exact copy of original Run task in Gradle?

Does anybody know what the simplest way to register several run tasks that represent exact copy of original one with changed app’s arguments ? Or may be how to supply run task with an optional argument that would represent app’s arguments.
Basically, I want my build to contain some pre-defined options how to run an application and don’t want to declare new JavaExec that requires its manual configuring while I have already had ready-to-go run task supplied by default.
gradle run --args='--mode=middle' ---> gradle run || gradle runDefault || gradle run default
gradle run --args='--mode=greed' ---> gradle runGreed || gradle run greed
gradle run --args='--mode=lavish' ---> gradle runLavish || gradle run lavish
As for now I came up only with the option that suggests implementing my own JavaExec_Custom task class with supplied arguments property. And it seems to be too complex and boilerplating as for my goal.
You can create tasks that modify the configuration of the actual run task in a doFirst or doLast closure:
// Groovy-DSL
task runGreed {
doFirst {
run.args '--mode=greed'
}
finalizedBy run
}
// Kotlin-DSL
register("runGreed") {
doFirst {
run.get().args = listOf("--mode=greed")
}
finalizedBy(run)
}
You can use a property for the args
task run(type: JavaExec) {
args property('run.args').split(' ')
...
}
Usage
gradle run -Prun.args='foo bar baz'

gradle: application run args can not pass system properties

Gradle 5.4.1
apply plugin: application
run {
main = "mypackage.Foo"
}
Run:
gradlew run --args="-Dfoo=bar -Dhello=world"
Trying to pass the system properties using --args when running the application. But they were not set.
gradlew -Dfoo=bar -Dhello=world run --args="arg1"
--args are what's passed to the main method.
You would need explicitly copy system properties from CLI into the corresponding run command/plugin system properties, unfortunatelly:
// The run task added by the application plugin is also of type JavaExec.
tasks.withType(JavaExec) {
// Assign all Java system properties from the command line to the JavaExec task.
systemProperties System.properties
}

A code generator task in a multi-project gradle build

I have studied thousand similar questions on SO and I am still lost. I have a simple multiproject build:
rootProject.name = 'mwe'
include ":Generator"
include ":projectB"
include ":projectC"
with a top level build.gradle as follows (settings.gradle):
plugins { id "java" }
allprojects { repositories { jcenter() } }
and with two kinds of project build.gradle files. The first one (Generator) exposes a run command that runs the generator taking the command line argument:
plugins {
id "application"
id "scala"
}
dependencies { compile "org.scala-lang:scala-library:2.12.3" }
mainClassName = "Main"
ext { cmdlineargs = "" }
run { args cmdlineargs }
The code generator is to be called from projectB (and an analogous projectC, and many others). I am trying to do this as follows (projectB/build.gradle):
task TEST {
project (":Generator").ext.cmdlineargs = "Hurray!"
println ("Value set:" + project(":Generator").ext.cmdlineargs )
dependsOn (":Generator:run")
}
Whatever I try to do (a gradle newbie here) I am not getting what I need. I have two problems:
The property cmdlineargs is not set at the point that task :projectB:TEST is run. The println sees the right value but the argument passed to the executed main method is the one configured in Generator/build.gradle, not the one in projectB/build.gradle. As pointed out in responses this can be work around using lazy property evaluation, but this does not solve the second problem.
The generator is only run once, even if I build both projectB and projectC. I need to run Generator:run for each of projectB and projectC separately (to generate different sources for each dependent project).
How can I get this to work? I suppose a completely different strategy is needed. I don't have to use command line and run; I can also try to run the main class of the generator more directly and pass arguments to it, but I do find the run task quite convenient (the complex classpath is set up automatically, etc.). The generator is a Java/Scala project itself that is compiled within the same multi-project build.
Note: tasks aren't like methods in java. A task will execute either 0 or 1 times per gradle invocation. A task will never execute twice (or more) in a single Gradle invocation
I think you want two or more tasks. Eg:
task run1(type:xxx) {
args 'foo'
}
task run2(type:xxx) {
args 'bar'
}
Then you can depend on run1 or run2 in your other projects.

How to pass system property to Gradle task

I'm using Gradle spring-boot plugin and I need to select a spring active profile for the test run.
How do I pass spring.profiles.active system property to the bootRun plugin's task?
What has already failed:
task bootRunLocal {
systemProperty "spring.profiles.active", "local"
System.setProperty("spring.profiles.active", "local")
tasks.bootRun.execute() // I suspect that this task is executed in a separate JVM
}
and some command line magic also fails:
./gradle -Dspring.profiles.active=local bootRun
Could someone kindly help me solve my troubles?
Update from the answers and comments:
I'm able to set the systemProperty and pass it to the spring container by doing :
run {
systemProperty "spring.profiles.active", "local"
}
However, when I do this, the local profile is being set for both bootRun task and bootRunLocal task. I need a way to set this property for bootRunLocal task and call booRun task from bootRunLocal.
That might sound very simple, but I come with peace from the structured world of Maven.
I know I'm late here... but I recently faced this exact issue. I was trying to launch bootRun with spring.profiles.active and spring.config.location set as system properties on the command line.
So, to get your command line "magic" to work, simply add this to your build.gradle
bootRun {
systemProperties System.properties
}
Then running from the command line...
gradle -Dspring.profiles.active=local bootRun
Will set local as the active profile, without needing to define a separate task simply to add the env variable.
task local {
run { systemProperty "spring.profiles.active", "local" }
}
bootRun.mustRunAfter local
Then run gradle command as:
gradle bootRun local
There is no generic way to pass system properties to a task. In a nutshell, it's only supported for tasks that fork a separate JVM.
The bootRunLocal task (as defined above) will not execute in a separate JVM, and calling execute() on a task isn't supported (and would have to happen in the execution phase in any case). Tests, on the other hand, are always executed in a separate JVM (if executed by a Test task). To set system properties for test execution, you need to configure the corresponding Test task(s). For example:
test {
systemProperty "spring.profiles.active", "local"
}
For more information, see Test in the Gradle Build Language Reference.
SPRING_PROFILES_ACTIVE=local gradle clean bootRun
This is according to this and this and it works.
According to the spring-boot-gradle-plugin documentation you should be able to pass arguments like this
./gradlew bootRun --args='--spring.profiles.active=dev'
Seems like this is a new gradle feature since 4.9. I used it in my project and it worked out of the box.
For gradle 2.14 below example works.
I have added as below.
When System.properties['spring.profiles.active'] is null then default profile is set.
bootRun {
systemProperty 'spring.profiles.active', System.properties['spring.profiles.active']
}
command line example
gradle bootRun -Dspring.profiles.active=dev
Just for reference if anyone will have this issue:
Vlad answer didn't quite worked for me but this one works great with 2.4,
task local <<{
bootRun { systemProperty "spring.profiles.active", "local" }
}
local.finalizedBy bootRun
then gradle local
Responding to OP's exact request here ...
How do I pass spring.profiles.active system property to the bootRun plugin's task?
And assuming by "pass" the OP meant "pass from commandline" or "pass from IDE invocation" ... This is how I like to do it.
Add this to build.gradle:
/**
* Task from spring-boot-gradle-plugin, configured for easier development
*/
bootRun {
/* Lets you pick Spring Boot profile by system properties, e.g. gradle bootRun -Dspring.profiles.active=dev */
systemProperties = System.properties
}
Then when you invoke it, use the familiar Java flag for setting a system property
gradle bootRun -Dspring.profiles.active=local
There is one main advantage of sticking to system properties, over the environment variables option (SPRING_PROFILES_ACTIVE=local gradle bootRun) ... and that's easy portability between Linux/OS X (bash, etc.) and Windows (cmd.exe anyway).
I learned this way from this blog post.
(UPDATE: Ah somehow I had missed #Erich's response with same recommendation. Oops! I'm leaving my answer, because of the additional details about portability, etc.)
You can create a new task (in discussed case with name bootRunLocal), that would extend org.springframework.boot.gradle.run.BootRunTask and setup properties before task execution. You can create such a task with following code:
task bootRunLocal(type: org.springframework.boot.gradle.run.BootRunTask) {
doFirst() {
main = project.mainClassName
classpath = sourceSets.main.runtimeClasspath
systemProperty "spring.profiles.active", "local"
}
}
More details can be found here:
https://karolkalinski.github.io/gradle-task-that-runs-spring-boot-aplication-with-profile-activated/
Starting from SpringBoot 2.0.0-M5 setSystemProperties() is no longer a method of the task bootRun.
The build.gradle needs to be updated to
bootRun {
execSpec {
// System.properties["spring.profiles.active"]
systemProperties System.properties
}
}
This is as springBoot's run task uses org.gradle.process.JavaExecSpec
This works for me using Gradle 4.2
This works:
SPRING_PROFILES_ACTIVE=production ./gradlew app-service:bootRun
with run command you can add to build file run { systemProperties = System.properties } and start with gradle run -Dspring.profiles.active=local
Another way which doesn't require any support from the gradle task: Set the JAVA_TOOL_OPTIONS environment variable:
JAVA_TOOL_OPTIONS='-Dfoo=bar' gradle ...
Or if the variable might already contain anything useful:
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -Dfoo=bar" gradle ...
// defualt value
def profiles = 'dev'
bootRun {
args = ["--spring.profiles.active=" + profiles]
}
Then you can simply pick a specific version when starting a gradle task, like
./gradlew bootRun -P dev
"dev" is gonna to take place "prod"

Resources