Why won't Gradle pass runtime args to Groovy? - gradle

Gradle 2.14 and Groovy 2.4.7 here. I have the following Groovy:
#Slf4j
class Driver {
static void main(String[] args) {
log.info("Fizz prop value is: ${System.properties['fizz']}.")
}
}
I'm using the Gradle Application plugin. When I run:
./gradlew run -Pfizz=buzz
I get he following console output:
[main] INFO com.me.myapp.Driver - Fizz prop value is: null.
Why does my app think the fizz property is null, when I am passing its value as buzz on the command-line?

You are passing it with -P which are properties for gradle
Try passing it with -D

try without the System.properties and passing -Pfizz=buzz:
log.info("Fizz prop value is: ${fizz}.")

Related

using environment variables in flywayMigrate with intellij

I configured flyway to use environment variables like so
flyway.url=${JDBC_DATABASE_URL}
flyway.locations=filesystem:db/migrations
running JDBC_DATABASE_URL=... ./gradlew flyMigrate is working as expected. similarly, set -a && source dev.env && ./gradlew flyMigrate is working as expected.
The challange is using Intellij. I've set the environment varables with the command set -a && source dev.env && idea When I run the flyMigrate gradle task, it is not able to read the env variables.
However the following code is working as expected
public class TestEnv {
public static void main(String[] args) {
System.out.println(System.getenv("JDBC_DATABASE_URL"));
}
}
What am I missing?

Spring boot: external properties file an PropertySource

I am developing a spring boot application with gradle.
I would love to tell spring where to read .properties files with a parameter. Since I am still running it via gradle, I have added this to my build.gradle
bootRun {
args = [
"--spring.config.additional-location=file:/path/to/my/props/folder/,file:/path/to/another/props/folder/"
]
}
into /path/to/my/props/folder/ I have created a file remote-connection.properties:
### remote-connection
remote.ip.address=127.0.0.1
remote.ip.port=5001
and I am trying to load those props like this
#RestController
#PropertySource("file:remote-connection.properties")
public class MyController {
#Value("${remote.ip.address}")
private String remoteIpAddress;
}
When i run ./gradlew bootRun i have the following error
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [my.package.MyApplication]; nested exception is java.io.FileNotFoundException: remote-connection.properties (No such file or directory)
(I have also tried #PropertySource("classpath:remote-connection.properties") and #PropertySource("remote-connection.properties"))
It works flawlessly if I place remote-connection.properties into src/main/resources, but I want that config file to be outside the resulting jar, being able to run it with
java -jar my-application.jar --spring.config.additional-location=file:/path/to/my/props/folder/,file:/path/to/another/props/folder/
What am I missing?
Thanks in advance.
Answering my own question.
Following this guide https://mkyong.com/spring/spring-propertysources-example/ I have changed my run args to
bootRun {
args = [
"--my.props.folder=/path/to/my/props/folder",
"--my.other.props.folder=/path/to/another/props/folder",
]
}
and loading props like this
#RestController
#PropertySource("file:${my.props.folder}/remote-connection.properties")
#PropertySource("file:${my.other.props.folder}/some-more.properties")
public class MyController {
#Value("${remote.ip.address}")
private String remoteIpAddress;
}
This way, it works!!

Minor Gradle upgrade breaks test compilation

I want to incrementally upgrade the Gradle wrapper in order to improve build speed. After moving from 2.3 to 2.4 the test compilation fails with an incompatible types error and I am struggling with dependencies.
Consider this Spock test:
class DetailsSortKeySpec extends Specification {
def 'Simple Test'() {
given:
TestDetailsSortKey testDetailsSortKey = new TestDetailsSortKey(details, collationKey)
expect:
testDetailsSortKey.details.equals(details)
where:
details | collationKey
new TestDetails(id: 0) | Collator.getInstance(Locale.ENGLISH).getCollationKey('')
}
private class TestDetailsSortKey extends DetailsSortKey<TestDetails> {
TestDetailsSortKey(TestDetails details, CollationKey collationKey) {
super(details, collationKey)
}
}
}
And this Java class:
public class DetailsSortKey<T extends Details> {
private final T details;
private final CollationKey collationKey;
public DetailsSortKey(final T details, final CollationKey collationKey) {
this.details = details;
this.collationKey = Objects.requireNonNull(collationKey);
}
public final T getDetails() {
return details;
}
}
Following error message appears when running compileTestGroovy:
/var/lib/jenkins/workspace/gradle_upgrade/build/tmp/compileTestGroovy/groovy-java-stubs/com/vendor/transfer/sorting/DetailsSortKeySpec.java:25: error: incompatible types: Details cannot be converted to TestDetails
super ((com.vendor.common.transfer.Details)null, (java.text.CollationKey)null);
^
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error
startup failed:
Compilation failed; see the compiler error output for details.
1 error
FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':WEB-Commons:compileTestGroovy'.
> Compilation failed; see the compiler error output for details.
The Release Notes do not list any issues that seem to be responsible for this, so I dug through Groovy Issues that could be the root cause and for real found an issue about Generics. But the bug should already be fixed. I do not understand where and why there is a try to covert Details to TestDetails, which is just a plain and empty derivation from the Details class.
These are the used Groovy versions in both Gradle distros:
Gradle 2.3: Groovy: 2.3.9
Gradle 2.4: Groovy 2.3.10
To me, this seems exactly like the referenced Groovy bug, but that one should be fixed since 2.3.8 and should not affect this build. Furthermore, the dependencies are declared as followed in the project:
dependencies {
// mandatory dependencies for using Spock
compile "org.codehaus.groovy:groovy-all:2.4.11"
testCompile "org.spockframework:spock-core:1.1-groovy-2.4"
}
And the difference between the output of both gradlew :dependencies do only contain tools, that are mentioned in the release notes but do not belong to the test scope.
Eventually, which Groovy version is used here?
I think you are wanting to compile with a different version of Groovy than the one bundled with Gradle. See GroovyCompile.groovyClasspath
Eg:
configurations {
groovy
}
dependencies {
groovy 'org.codehaus.groovy:groovy-all:2.4.11'
compile 'org.codehaus.groovy:groovy-all:2.4.11'
testCompile('org.spockframework:spock-core:1.0-groovy-2.4') {
exclude module: 'groovy-all'
}
}
compileGroovy {
groovyClasspath = configurations.groovy
}
* Edit *
To see what version is being picked (due to dependency resolution) you can
gradle dependencies
Or (where xxx is a subproject name)
gradle xxx:dependencies
To force a specific dependency version you can
configurations.all {
resolutionStrategy {
force 'org.codehaus.groovy:groovy-all:2.4.11'
}
}
See ResolutionStrategy
Spock has a transitive dependency on groovy-all which might be conflicting with the groovy-all version you are declaring. Also you are not using Gradle's version of groovy-all (you are declaring yet another version of this). I declare those two dependencies differently, like this:
dependencies {
compile localGroovy()
testCompile('org.spockframework:spock-core:1.0-groovy-2.4') {
exclude module: 'groovy-all'
}
}

In Gradle, how to set unique system property before each execution of JUnit test class?

In the gradle script below, maxParallelForks and forkEvery will start a new process with a new JVM per Junit test class. Is there a way to give each test process/JVM/Junit class its own unique system property?
I tried an experiment where I passed a UUID value as a system property in the beforeSuite method.
apply plugin:'java'
test {
ignoreFailures = true
maxParallelForks = 8
forkEvery = 1
systemProperty 'some.prop', 'value'
beforeSuite { descriptor ->
logger.lifecycle("Before suite: " + descriptor)
def theuuid = UUID.randomUUID().toString()
println "beforeSuite uuid =" + theuuid
systemProperty 'some.uuid', theuuid
}
beforeTest { descriptor ->
logger.lifecycle("Running test: " + descriptor)
}
}
repositories {
mavenCentral()
}
dependencies {
testCompile 'junit:junit:4.12'
}
The JUnit test classes, LoginTest1 and LoginTest2 print out the system property in a test method.
public class LoginTest1 {
private String userName="Gradle";
#Test
public void testUserName() throws Exception {
System.out.println("LoginTest1: Testing Login ");
System.out.println("LoginTest1: Testing Login some.prop -> "
+ System.getProperty("some.prop"));
System.out.println("LoginTest1: Testing Login some.uuid -> "
+ System.getProperty("some.uuid"));
assertTrue(userName.equals("Gradle"));
}
}
public class LoginTest2 {
private String userName="Gradle";
#Test
public void testUserName() throws Exception {
System.out.println("LoginTest2: Testing Login ");
System.out.println("LoginTest2: Testing Login some.prop -> "
+ System.getProperty("some.prop"));
System.out.println("LoginTest2: Testing Login some.uuid -> "
+ System.getProperty("some.uuid"));
assertTrue(userName.equals("Gradle"));
}
}
As you can see from the gradle output below, the beforeSuite method is called before running individual JUnit test methods. Both test classes get the same system property of 6a006689-474f-47d5-9649-a88c92b45095
$ gradle clean test
> Task :test
Before suite: Gradle Test Run :test
beforeSuite uuid =6a006689-474f-47d5-9649-a88c92b45095
Before suite: Gradle Test Executor 1
beforeSuite uuid =39edb608-3027-4ad8-bd15-f52f50175582
Before suite: Test class ch6.login.LoginTest1
beforeSuite uuid =c0ce55e0-924c-4319-becb-bc27229c9cf3
Before suite: Gradle Test Executor 2
beforeSuite uuid =c15eaac0-7ea7-46d2-8235-8dc49b3f7a39
Running test: Test testUserNameNotNull(ch6.login.LoginTest1)
Before suite: Test class ch6.login.LoginTest2
beforeSuite uuid =73abbe24-5b78-4935-867a-445ac4ac20ef
Running test: Test testUserName(ch6.login.LoginTest1)
Running test: Test testUserName(ch6.login.LoginTest2)
JUnit test class output:
LoginTest1: Testing Login
LoginTest1: Testing Login some.prop -> value
LoginTest1: Testing Login some.uuid -> 6a006689-474f-47d5-9649-a88c92b45095
LoginTest2: Testing Login
LoginTest2: Testing Login some.prop -> value
LoginTest2: Testing Login some.uuid -> 6a006689-474f-47d5-9649-a88c92b45095
It looks like there's an initial call to beforeSuite (seen as ":test") and then once per Test Executor. The first uuid value ("6a006689") is set across all JVMs. Is there anything like a simple beforeClass method I could use?
In the debug log below,it looks like the Test Executors are given the jvm argument -Dsome.uuid=6a006689-474f-47d5-9649-a88c92b45095 and that is used soley to create new JVMs (as per the forkEvery config). This makes me think that what I want to do is impossible in Gradle.
20:23:42.466 [INFO] [org.gradle.process.internal.DefaultExecHandle] Starting process 'Gradle Test Executor 1'. Working directory: /a/b/ Command: /usr/lib/jvm/java-8-openjdk-amd64/bin/java -Djava.security.manager=worker.org.gradle.process.internal.worker.child.BootstrapSecurityManager -Dorg.g
radle.native=false -Dsome.prop=value -Dsome.uuid=6a006689-474f-47d5-9649-a88c92b45095 -Dfile.encoding=UTF-8 -Duser.country=US -Duser.language=en -Duser.variant -ea -cp /data/.gradle/caches/4.3.1/workerMain/gradle-worker.jar worker.org.gradle.process.internal.worker.GradleWorkerMain 'Gradle Test Executor 1'
20:23:42.466 [INFO] [org.gradle.process.internal.DefaultExecHandle] Starting process 'Gradle Test Executor 2'. Working directory: /a/b/ Command: /usr/lib/jvm/java-8-openjdk-amd64/bin/java -Djava.security.manager=worker.org.gradle.process.internal.worker.child.BootstrapSecurityManager -Dorg.g
radle.native=false -Dsome.prop=value -Dsome.uuid=6a006689-474f-47d5-9649-a88c92b45095 -Dfile.encoding=UTF-8 -Duser.country=US -Duser.language=en -Duser.variant -ea -cp /data/.gradle/caches/4.3.1/workerMain/gradle-worker.jar worker.org.gradle.process.internal.worker.GradleWorkerMain 'Gradle Test Executor 2'
Update 8/2018
The following solution does not work in Gradle 4.9 and greater
Instead, there is a org.gradle.test.worker system property which you can use to distinguish between workers, calculate display names, temporary directories, etc. This test.worker is simply an increasing long value. The Gradle team has no plans on making Test Workers configurable. A pity because I had to do some major refactoring in my test code in order to upgrade Gradle. The "#BeforeAllCallback" in JUnit 5 might be useful to you.
Trying to solve by intercepting Test.copyTo(JavaForkOptions target)
This code demonstrates lance-java 's suggestion and succeeds in answering my question. I have the following build.gradle script which uses MyTestTask to extend Test and add a unique value called my_uuid. Note that the build script must have forkEvery = 1 to ensure copyTo is called once per JUnit test:
class MyTestTask extends Test {
public Test copyTo(JavaForkOptions target) {
super.copyTo(target);
String uuid = UUID.randomUUID().toString();
System.out.println("MyTestTask copyTo:\n my_uuid=" + uuid);
System.out.println("\t before getJvmArgs:" + target.getJvmArgs());
System.out.println("\t before getSystemProperties:" + target.getSystemProperties());
target.systemProperty("my_uuid", uuid);
System.out.println("\t after getJvmArgs:" + target.getJvmArgs());
System.out.println("\t after getSystemProperties:" + target.getSystemProperties());
return this;
}
}
///
subprojects {
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
testCompile 'junit:junit:4.12'
}
test {
enabled false // This doesn't seem to matter.
}
task my_test(type: MyTestTask) {
forkEvery 1 // need this so copyTo called each JUnit test
testLogging.showStandardStreams = true
doFirst {
def uuid = UUID.randomUUID().toString()
println "TEST:Task name is $name. In doFirst. uuid is " + uuid
jvmArgs '-Dcommon_uuid='+ uuid
}
}
}
The Junit tests that are executed are trivial and simply print out System.getProperty("my_uuid") and System.getProperty("common_uuid").
> Task :CustomCopyToSubProject:my_test
TEST:Task name is my_test. In doFirst. uuid is eed1ee92-7805-4b8e-a74c-96218d1be6e1
MyTestTask copyTo:
MyTestTask copyTo:
my_uuid=a7996c20-1085-4397-9e32-fd84467dcb45
my_uuid=69f6f347-71d0-4e5d-9fad-66bf4468fab3
before getJvmArgs:[]
before getJvmArgs:[]
before getSystemProperties:[common_uuid:eed1ee92-7805-4b8e-a74c-96218d1be6e1]
before getSystemProperties:[common_uuid:eed1ee92-7805-4b8e-a74c-96218d1be6e1]
after getJvmArgs:[]
after getJvmArgs:[]
after getSystemProperties:[common_uuid:eed1ee92-7805-4b8e-a74c-96218d1be6e1, my_uuid:69f6f347-71d0-4e5d-9fad-66bf4468fab3]
after getSystemProperties:[common_uuid:eed1ee92-7805-4b8e-a74c-96218d1be6e1, my_uuid:a7996c20-1085-4397-9e32-fd84467dcb45]
ch3.LoginTest2 > testUserName2 STANDARD_OUT
LoginTest2.java: Testing Login ! >>---> my_uuid=a7996c20-1085-4397-9e32-fd84467dcb45 common_uuid=eed1ee92-7805-4b8e-a74c-96218d1be6e1
ch3.LoginTest1 > testUserName1 STANDARD_OUT
LoginTest1.java: Testing Login ! >>---> my_uuid=69f6f347-71d0-4e5d-9fad-66bf4468fab3 common_uuid=eed1ee92-7805-4b8e-a74c-96218d1be6e1
The task my_test sets common_uuid in doFirst. The MyTestTask.copyTo method sets its own my_uuid.
You can see from the output and MyTestTask is called twice, once per JUnit test task (LoginTest1 and LoginTest2). The two JUnit tests get their own unique system property in my_uuid.
I think you want to intercept Test.copyTo(JavaForkOptions target), unfortunately the only way I can see to do this is to extend Test
eg
public class Test2 extends org.gradle.api.tasks.testing.Test {
public Test copyTo(JavaForkOptions target) {
super.copyTo(target);
target.systemProperty("uuid", UUID.randomUUID().toString());
return this;
}
}
build.gradle
apply plugin: 'java'
test {
enabled = false
}
task test2(type: Test2) {
// guessing you'll need to configure a bit of stuff here
}
check.dependsOn test2
Since a new JVM is forked for every test you could just use a static field that is initialized with a UUID.
public class Helper {
public static final String uuid = UUID.randomUUID().toString();
}
public class LoginTest2 {
private String userName="Gradle";
#Test
public void testUserName() throws Exception {
System.out.println("LoginTest2: Testing Login ");
System.out.println("LoginTest2: Testing Login some.uuid -> "
+ Helper.uuid;
assertTrue(userName.equals("Gradle"));
}
}

Gradle build for javafx application: Virtual Keyboard is not working due to missing System property

i am using a javafx application and we developed a gradle build system for this application. The jar file can be created with the following gradle task:
task fatJar(type: Jar) {
manifest {
attributes 'Main-Class': 'myProject'
}
baseName = project.name + '-all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
with jar
}
This works so far - the only problem is that we want to use the virtual keyboard (javafx) and therefore we need to set the following system properties:
systemProperty 'com.sun.javafx.isEmbedded', 'true'
systemProperty 'com.sun.javafx.touch', 'true'
systemProperty 'com.sun.javafx.virtualKeyboard', 'javafx'
Can i set this properties in the gradle build or is it necessary to start the application with
java -Dcom.sun.javafx.isEmbedded=true -Dcom.sun.javafx.touch=true -Dcom.sun.javafx.virtualKeyboard=javafx -jar myProject.jar
best regards
__________________________________-
The solution (big thanks to Frederic Henri :-)) is to write a wrapper class like
public class AppWrapper
{
public static void main(String[] args) throws Exception
{
Class<?> app = Class.forName("myProject");
Method main = app.getDeclaredMethod("main", String[].class);
System.setProperty("com.sun.javafx.isEmbedded", "true");
System.setProperty("com.sun.javafx.touch", "true");
System.setProperty("com.sun.javafx.virtualKeyboard", "javafx");
Object[] arguments = new Object[]{args};
main.invoke(null, arguments);
}
}
I dont think this job can be done from the build phase (I'd be happy to be wrong and see another answer though) -
It seems there is another answer here Java: Modify System properties via runtime where it says to write a wrapper around your final main method and so you can pass the properties you need, not sure how good it is though.

Resources