Multiple Build-Tasks with changing sets of dependencies in Gradle - gradle

I would like to run tests of an library against different backend implementations.
The implementations are injected in my project by the magic of Spring.
Currently I do this, by changing the line
testImplementation group: 'org.mycorp.exmpl' name: 'redis-backend' version: '0.0.1'
to
testImplementation group: 'org.mycorp.exmpl' name: 'mongo-backend' version: '0.0.1'
to
testImplementation group: 'org.mycorp.exmpl' name: '<whatever-backend>' version: '<whatever.version>'
then running
gradlew test
(resp. clicking on 'test' in my IntelliJ IDE)
This is cumbersome. And I can't do that with my build pipeline (I guess).
In my imagination, I would be able to create
a task testRedis which depends on the task buildRedisTestClasses
a task testMongo which depends on the task buildMongoTestClasses
...
so I can just select the correct task in my IDE or run all of them in my build pipeline.
I found some hints on the web, that you can use something like this:
dependencies {
testImplementation group: 'org.mycorp.exmpl', name: 'redis-backend', version: '0.0.1', configuration: 'redis'
testImplementation group: 'org.mycorp.exmpl', name: 'mongo-backend', version: '0.0.1', configuration: 'mongo'
}
But thats about where I stopped finding/understanding.
(As you might notice, I am a gradle novice)

Try something alike:
./gradlew test -Dbackend=redis
dependencies {
if (System.getProperty("backend") == "redis") {
implementation "org.mycorp.exmpl:redis-backend:0.0.1"
} else {
implementation "org.mycorp.exmpl:mongo-backend:0.0.1"
}
}
Or even:
./gradlew test -Dbackend=redis-backend:0.0.1
implementation "org.mycorp.exmpl:${System.getProperty("backend")}"
Making it a project property -Pbackend with a default value suggested.
See Environment Options.

Related

gradle dependencies for main and test

Selenide + Gradle When declaring a dependency like this:
testImplementation group: 'com.codeborne', name: 'selenide', version: '6.6.3' , I can only access Selenid elements and methods in test/java. But the page objects are in the src/main/java section. How should I write a dependency so that methods can be called both in test and in main? I did this, but it seems to me that it is wrong:
dependencies {
testImplementation group: 'com.codeborne', name: 'selenide', version: '6.6.3'
compileOnly group: 'com.codeborne', name: 'selenide', version: '6.6.3'
}
testImplentation means the dependency only has scope for testing. Change it to just implentation and it should work.

Jetty AnnotationParser scanned from multiple locations warning

I have a project build with Gradle, it's actually a Vaadin project, with a servlet where I use Jetty.
At the startup (i.e gradle run) I have a lot of different warning message from AnnotationParser about duplication of classes. I copy only one because the log is quite verbose:
[INFO ] 11:22:50.375 org.eclipse.jetty.server.Server.doStart() - jetty-9.4.31.v20200723; built: 2020-07-23T17:57:36.812Z; git: 450ba27947e13e66baa8cd1ce7e85a4461cacc1d; jvm 13.0.2+8
[WARN ] 11:22:50.777 org.eclipse.jetty.annotations.AnnotationParser.addParsedClass() - javax.websocket.ClientEndpoint scanned from multiple locations: jar:file:///Users/fox/.gradle/caches/modules-2/files-2.1/javax.websocket/javax.websocket-api/1.0/fc843b649d4a1dcb0497669d262befa3918c7ba8/javax.websocket-api-1.0.jar!/javax/websocket/ClientEndpoint.class, jar:file:///Users/fox/.gradle/caches/modules-2/files-2.1/javax.websocket/javax.websocket-client-api/1.0/afcf19e889d8725576811f8d47ab6c65d9dcbd78/javax.websocket-client-api-1.0.jar!/javax/websocket/ClientEndpoint.class
In this line AnnotationParser warns me that the ClientEndpoint.class is present in two jar, the javax.websocket-api-1.0.jar and the javax.websocket-client-api-1.0.jar.
With the command gradle dependencies I could see:
...
+--- org.eclipse.jetty.websocket:javax-websocket-client-impl:9.4.31.v20200723
| +--- org.eclipse.jetty.websocket:websocket-client:9.4.31.v20200723 (*)
| \--- javax.websocket:javax.websocket-client-api:1.0
+--- org.eclipse.jetty.websocket:websocket-server:9.4.31.v20200723 (*)
\--- javax.websocket:javax.websocket-api:1.0
In my gradle.build I only have:
dependencies {
// Vaadin
implementation enforcedPlatform('com.vaadin:vaadin-bom:18.0.6')
implementation("com.vaadin:vaadin-core")
implementation group: 'com.github.appreciated', name: 'vaadin-css-grid', version: '2.0.0'
// Logging
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.13.1'
implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.13.1'
implementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.13.1'
// Testing
testImplementation group: 'junit', name: 'junit', version: '4.12'
testImplementation group: 'org.skyscreamer', name: 'jsonassert', version: '1.5.0'
// Jetty
implementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.4.31.v20200723'
implementation group: 'org.eclipse.jetty', name: 'jetty-webapp', version: '9.4.31.v20200723'
implementation group: 'org.eclipse.jetty.websocket', name: 'websocket-server', version: '9.4.31.v20200723'
implementation group: 'org.eclipse.jetty.websocket', name: 'javax-websocket-server-impl', version: '9.4.31.v20200723'
}
All these logs are really annoying (they slow down the start up really much) and I can't understand if they are dangerous or not.
Which is the right way to avoid duplications ?
Is there a technique to instruct AnnotationParser to scan only some dependencies?
I know this topic is present in different questions but I didn't find a solution for gradle or a common solution strategy.
Thanks,
Stefano
Having the same class name in multiple locations on your classpath is a bad idea.
This is the most common form of unstable operation on Java there is!
The classloaders in Java have no guarantee of load order behavior if the same class is present in multiple locations within the classloader.
In one run you might accidentally load the classes in the order you intend, and have it run properly, then at a future date you run the same program and the load order is different, now you are running with a different class version and you have unexpected behavior.
The only way to fix this is to clean up your classloader and ensure that you only have 1 version of the class you intend to use.
This is what Jetty is telling you.
As for this specific one, javax.websocket-api and javax.websocket-client-api, you want to exclude javax.websocket-client-api at the gradle level, as all of the websocket client classes are also present in the javax.websocket-api.
The javax.websocket-client-api jar is only intended for projects that only use the javax.websocket Client, without a javax.websocket Server.
Following the suggestion of joakim-erdfelt
I have modified my build.gradle and this prevent the problem:
implementation ('org.eclipse.jetty.websocket:javax-websocket-server-impl:9.4.31.v20200723') {
exclude module: 'javax.websocket-client-api'
}
The Gradle documentation is here: Excluding transitive dependencies

Sonarqube gradle analyzing project, task not found in root project

Analysing project with this command
.\gradlew sonarqube \ -Dsonar.host.url=http://my.url \ -Dsonar.login=login --stacktrace
Getting this error
org.gradle.execution.TaskSelectionException: Task '\' not found in root project 'JavaLint'
And here is my gradle file
plugins {
id "org.sonarqube" version "2.6.2"
}
apply plugin: 'application'
apply plugin: 'java'
apply plugin: 'eclipse'
archivesBaseName = 'JavaLint'
version = '0.1-SNAPSHOT'
mainClassName = 'Main'
repositories {
mavenCentral()
}
jar {
manifest {
attributes 'Main-Class': 'com.test.Run'
}
}
sourceSets {
main {
java {
srcDirs 'src'
}
}
}
dependencies {
compile group: 'commons-io', name: 'commons-io', version: '2.6'
compile group: 'commons-lang', name: 'commons-lang', version: '2.6'
compile group: 'org.jsoup', name: 'jsoup', version: '1.11.2'
compile group: 'junit', name: 'junit', version: '4.12'
compile group: 'log4j', name: 'log4j', version: '1.2.16'
}
Stack trace
I don't understand what am i supposed to do with it.
It looks like you're using cmder (it's so beautiful) which means you're on Windows. For Windows you'll want to provide the arguments to gradle as follows
./gradlew sonarqube -D "sonar.projectKey=<your_project_name>" -D "sonar.host.url=http://localhost:9000" -D "sonar.login=<your_project_token>"
Thanks to the accepted answer by #ka whosyour above,I got my answer too.
Ok let me mention the details of how I was doing for an Android project in Android Studio and what I figured out after my research.
From the command generated by the Sonar Dashbaord, it is
./gradlew sonarqube \-Dsonar.projectKey=LetsGo \-Dsonar.host.url=http://localhost:9000 \-Dsonar.login=53689e9ceab73b3e8a76007d7953af3e9e2b2052
But, for Windows machine it should actually be:
gradlew sonarqube -Dsonar.projectKey=LetsGo -Dsonar.host.url=http://localhost:9000 -Dsonar.login=53689e9ceab73b3e8a76007d7953af3e9e2b2052
This worked like a charm for me.
Notice the Backwards slashes \ which are not needed on the windows machine.
Also, ./gradlew works in mac and gradlew on windows
Make sure first the directory contains gradle.build.
The command for windows :
./gradlew sonarqube -D "sonar.projectKey=your_sonarqube_key" -D "sonar.host.url=http://localhost:9000" -D "sonar.login=your_sonarqube_token"
This has worked for me as expected.
Use it like that in windows Terminal:
.\gradlew sonarqube -Dsonar.host.url=http://my.url -Dsonar.login=login --stacktrace
After that ,you will find the project already in the SonarQube server.

Unable to pass argument from gradle command line to Spring project (not Boot)

I am developing Spring project.
I would like to load credentials from the command line not storying them in the code. I'm trying to execute this gradle command
gradlew build -Dspring.datasource.username=tester
and when I startup the Spring project, the program stops on a breakpoint and I see whether variable is declared or not. I have tried using -P instead of -D but it still didn't help.
I deploy the spring app remotely using bmuschko plugin I've tried to use, but also without success. I checked in java code Properties by using System.getProperties() and Environment object supported by Spring.
gradlew cargoredeployremote -Dspring.datasource.username=tester
Application properties are loaded succesfully.
IMPORTANT: I saw many tutorials how to make it but using Spring Boot I use just selected components from Spring.
For instance: http://nixmash.com/post/passing-arguments-to-spring-boot - this doesn't work in my case because I have no bootRun task.
Any ideas? Am I missing something in my steps?
Here is my build.gradle
group 'example'
version '1.0.0'
apply plugin: 'application'
apply plugin: 'war'
apply plugin: 'java'
apply plugin: 'com.bmuschko.cargo'
apply plugin: 'org.liquibase.gradle'
compileJava.options.encoding = 'UTF-8'
mainClassName = 'api.optic.config.WebAppInitializer'
sourceCompatibility = 1.8
buildscript {
repositories{
jcenter()
mavenCentral()
}
dependencies{
classpath 'com.bmuschko:gradle-cargo-plugin:2.2.3'
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0-RC3'
classpath 'org.liquibase:liquibase-core:3.4.1'
classpath "org.liquibase:liquibase-gradle-plugin:1.2.4"
classpath "mysql:mysql-connector-java:5.1.13"
}
}
project.ext {
springVersion = "4.3.6.RELEASE"
junitVersion = "5.0.0-RC3"
}
repositories {
mavenCentral()
}
dependencies {
compile "org.springframework:spring-core:${springVersion}"
compile "org.springframework:spring-context:${springVersion}"
compile "org.springframework:spring-context-support:${springVersion}"
compile "org.springframework:spring-beans:${springVersion}"
compile "org.springframework:spring-web:${springVersion}"
compile "org.springframework:spring-webmvc:${springVersion}"
compile "org.springframework:spring-orm:${springVersion}"
compile "org.springframework:spring-oxm:${springVersion}"
compile "org.springframework:spring-jdbc:${springVersion}"
compile "org.springframework:spring-test:${springVersion}"
compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.38'
compile group: 'javax.mail', name: 'javax.mail-api', version: '1.5.6'
compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.25'
compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.2'
compile group: 'com.fasterxml.jackson.module', name: 'jackson-module-parameter-names', version: '2.9.0.pr2'
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jdk8', version: '2.9.0.pr2'
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.9.0.pr2'
compile 'javax.servlet:javax.servlet-api:3.1.0'
testCompile "org.junit.jupiter:junit-jupiter-api:${junitVersion}"
testRuntime("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
}
cargo {
containerId = 'tomcat8x'
port = 8080
deployable {
context = 'example'
}
remote {
hostname = 'host.name.com'
username = 'tomcat'
password = 'pass'
}
Basically were 2 issues
1. Name mismatch: in application.properties the name inside the ${} was different than this provided from command-line
Solution:
application.properties
spring.datasource.username=${username}
and in gradle command-line
gradle build -Pusername=tester
2. Dot issue with gradle:
Can't put
gradle build -Pspring.datasource.username=tester
even if you have in application.properties
spring.datasource.username=${spring.datasource.username}
because you get an exception:
Execution failed for task ':processResources'.
Could not copy file '.\src\main\resources\application.properties' to '.\build\resources\main\application.properties'.
Solution:
Instead of dots use _ sign
gradle build -Pspring_datasource_username=tester
and in Application properties
spring.datasource.username=${spring_datasource_username}

could not resolve all dependencies for configuration ':compile'

To study Gradle I am using the book Gradle in action.
There was an example of dependency definition.
dependencies {
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.1'
}
But when I do in console gradle build I've got an error
What is the problem? My whole .gradle file looks like this
apply plugin: 'java'
dependencies {
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.1'
}
You did not tell Gradle where to find commons-lang3 library. Easy fix is to add the following to your build script:
repositories {
mavenCentral()
}
Of course you can find this piece of information in documentation - http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html#N10608
I was facing this same issue. I fixed it by using local gradle distribution instead of the default gradle wrapper. This is how it goes, make sure that you have Gradle installed and setup(PATH variable).
Open IntelliJ. Goto File->setting->Build, Exec, Deployment->Build tools->Gradle and use local gradle distribution and add your Gradle Home. Apply changes and try to run it now.

Resources