Gradle - Create jar only if tests pass - java

I am new to Gradle. I would like to manipulate the following build.gradle contents to do this. Instead of separately running the tests then building the jar via separate commands, I'd like to do both in one command, except that the jar does not get created if one of the tests fail (it will not even try to build the jar).
apply plugin: 'java'
apply plugin: 'eclipse'
version = '1.0'
sourceCompatibility = 1.6
targetCompatibility = 1.6
// Create a single Jar with all dependencies
jar {
manifest {
attributes 'Implementation-Title': 'Gradle Jar File Example',
'Implementation-Version': version,
'Main-Class': 'com.axa.openam'
}
baseName = project.name
from {
configurations.compile.collect {
it.isDirectory() ? it : zipTree(it)
}
}
}
// Get dependencies from Maven central repository
repositories {
mavenCentral()
}
test {
testLogging {
showStandardStreams = true
}
}
// Project dependencies
dependencies {
compile 'com.google.code.gson:gson:2.5'
testCompile 'junit:junit:4.12'
}
Thanks!

The simplest solution is to place all the tasks you want gradle to execute in order. So you may use the following:
gradle clean test jar
Tasks Breakout
clean: this is used mainly just to safely remove the last outdated jar (this is not mandatory);
test: execute the tests;
jar: create the jar artifact.
Key point: if one of the task fails for some reason gradle stops its execution.
So if just a single test fails for some reason an exception is thrown and the jar file is not created at all.
Alternative solution: add 'test' as dependency of 'jar'
Just to explore some other possibilities: modify the build.gralde file as follows:
[...]
jar {
dependsOn 'test'
[...]
}
[...]
Now every time you run gradle jar the test task is automatically executed before.
Emulate the pure command line solution using 'dependsOn'
To emulate the first command line approach (i.e., gradle clean test jar) using the dependency method you have to further modify the build.gradle. This is because is not assured that multiple dependsOn statements are evaluated in order:
[...]
jar {
dependsOn 'clean'
dependsOn 'test'
tasks.findByName('test').mustRunAfter 'clean'
[...]
}
[...]
Now you can use:
gradle jar
and both the tasks clean and test are executed (in the right order) before the actual jar task.

Related

How to manage external dependencies of a Gradle Plugin

Gradle Version: 1.12/2.0 (restricted due to Org policies)
JDK: 1.8
I have created a custom gradle plugin that performs some installation using code that has been defined in another sub-project of our source-code. The build.gradle for the plugin is
dependencies {
compile project(path: ':installlib', configuration: 'libConfig')
compile project(path: ':tools', configuration: 'toolConfig')
}
jar {
from {
// LINE#1 source-code of plugin
sourceSets.main.output
zip64 = true
// LINE#2 dependencies
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
baseName = 'myCustomPlugin'
version = '1.0'
destinationDir = new File(project.libDir)
}
The above plugin is consumed as follows - consumer.gradle
buildscript {
repositories { flatDir name: 'libs', dirs: System.env.CODESOURCE + '/lib/')
dependencies {
classpath: ':myCustomPlugin:1.0'
}
}
apply plugin: 'java'
apply plugin: 'myCustomPlugin'
...
...
//rest of the items of this gradle
Case-A
If I run this, I hit > Plugin with id 'myCustomPlugin' not found.
NOTE: I have META-INF/gradle-plugins/myCustomPlugin.properties created correctly with implementation-class pointing to my plugin code and this works fine if I don't get into creating the fat/uber-jar business and just include the sourceSets.main.output statement in my jar task. But since our entire project depends on file based artifacts, I am attempting to create a fat/uber-jar and that's where I start running into these issues.
Case-B
If I move the LINE#2 above the LINE#1, which looks like -
from {
// LINE#2 dependencies
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
// LINE#1 source-code of plugin
sourceSets.main.output
zip64 = true
}
If I run this, I hit ClassNotFoundException for one of the classes coming from the project 'installlib'. I can see the *.class file in the uber jar created but even then the class loader complains about this class.
Could anyone provide some pointers on how to resolve this ? The uber/fat jar creation (or the way I am doing it) is not helping with the plugin-source-code and dependencies of the plugin.
If not a fat jar, could anyone provide some inputs on how to resolve the dependencies in the buildscript of the consuming gradle ?

How to run shadow jar with a gradle task?

I want to run my app after building it with the shadow jar plugin.
build.gradle:
plugins {
id 'java'
id "org.jetbrains.kotlin.jvm" version "1.3.21"
id "com.github.johnrengelman.shadow" version "5.0.0"
}
group 'org.example.java'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
repositories {
jcenter()
}
dependencies {
compile "io.ktor:ktor-server-netty:1.1.3"
}
I also have a global init.gradle:
gradle.projectsLoaded {
rootProject.allprojects {
buildDir = "/Users/User/Builds/${rootProject.name}/${project.name}"
}
}
So now the fat jar can be built to my global build directory with the shadowJar task. But I want to be able to run and build it with just one run configuration in IntelliJ. How do I do that?
Maybe there is another way to let gradle redirect all my output to a global build directory. I don't want to configure each IntelliJ project with the same output path manually. Suggestions are welcome.
Thank you :)
You should not touch the buildDir property for achieving what you want.
Instead, you should create a JavaExec task that will start the application from the shadow jar.
If you want that execution to be at a different place than the default location of the generated jar, you should either change the output of the shadow task itself, and only that output or make your execution task depend on a copy task that would move the shadow jar around.
Something like:
shadowJar {
destinationDir = "/Users/User/Builds/${rootProject.name}/${project.name}"
}
task runApp(type: JavaExec) {
main = "your.main.Class
classpath = shadowJar.archiveFile // use archivePath before Gradle 5.1
}

Tasks for build and run works but executing with the generated run script doesn't

I am doing the simple HelloWorld example from https://spring.io/guides/gs/gradle/.
I had to do some changes (I'm using Gradle 5.2.1 on Ubuntu 18) to the build.gradle. I used gradlew wrapper. I managed to get tasks like 'build' and 'run' working. Everything is generated correctly, it seems. But running the app without gradle using the generated build/scripts/<appscript> does not work. Running the jar with
java -jar build/libs/hello-1.0.jar
works. But
./build/scripts/sayhello
Does not work and produces an error:
erno#moongate:~/Projects/java/sayhello$ ./build/scripts/sayhello
Error: Could not find or load main class hello.HelloWorld
Caused by: java.lang.ClassNotFoundException: hello.HelloWorld
Project file structure is as suggested:
sayhello/
build.gradle
gradlew
src/
main/
java/
hello/
Greeter.java
HelloWorld.java
I had to add the manifest and the mainclass attribute to the build configuration file as it seems that the gradle init --type java-application does not do it. Meaning that even trying to run the gradle generated base project does not work.
My build.gradle is like this:
plugins {
id 'java'
id 'application'
}
mainClassName = 'hello.HelloWorld'
repositories {
mavenCentral()
jcenter()
}
dependencies {
compile "joda-time:joda-time:2.10"
testCompile "junit:junit:4.12"
}
jar {
manifest {
attributes(
'Main-Class': 'hello.HelloWorld'
)
}
baseName = 'hello'
version = '1.0'
}
The problem with the startScripts task is that it generates a very basic script. It does not make sure dependent jars are in the right places - it expects this to be done by you. Also it assumes that you will be running the script from a directory it refers to as the $APP_HOME and this folder needs to contain a lib folder which contains all the jars your app needs.
My very hacky solution is to generate an even more basic unix script instead of relying on the default one.
startScripts {
dependsOn jar
doFirst {
unixStartScriptGenerator = configure(new CustomUnixStartScript()) {
classpath = configurations.runtimeClasspath + jar.outputs.files
}
}
}
class CustomUnixStartScript implements ScriptGenerator {
#InputFiles
FileCollection classpath
#Override
void generateScript (JavaAppStartScriptGenerationDetails details, Writer destination) {
destination << """java -classpath $classpath.asPath ${details.mainClassName}"""
}
}
You can extend this as you see fit.

using Kotlin with Gradle

I'm new to Kotlin and Gradle, and tried to follow these steps, so I got the following 2 files:
after running gradle init I changed the build.gradle to be:
// set up the kotlin-gradle plugin
buildscript {
ext.kotlin_version = '1.1.2-2'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
// apply the kotlin-gradle plugin
apply plugin: "kotlin"
apply plugin: 'application'
mainClassName = "hello.main"
// add kotlin-stdlib dependencies.
repositories {
mavenCentral()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
Hello.kt:
package hello
fun main(args: Array<String>) {
println("Hello World!")
}
Then I run the gradle build and got the build\classes\main\hello\HelloKt.class
my question is: Why the file generated is .class not .jar and how to get the .jar file and how to run it, I tried running the generated file using kotlin -classpath HelloKt.class main but got an error error: could not find or load main class hello.main
The classes are the direct output of the Kotlin compiler, and they should be packaged into a JAR by Gradle afterwards. To build a JAR, you can run the jar task, just as you would in a Java project:
gradle jar
This task is usually run during gradle build as well, due to the task dependencies.
This will pack the Kotlin classes into a JAR archive (together with other JVM classes, if you have a multi-language project), normally located at build/libs/yourProjectName.jar.
As to running the JAR, see this Q&A for a detailed explanation: (link)
Thanks for #hotkey answer, it helped me going the correct way.
First of all there is a mistake in the main class declaration, as it should follow the new methodology, that is in the below format:
mainClassName = '[your_namespace].[your_arctifact]Kt'
namespace = package name
arctifact = file name
so, considering the names given in the example above where filename is: Hello.kt, and the namespace is hello, then:
mainClassName = `[hello].[Hello]Kt`
using the previous method, that contains:
apply plugin: 'application'
mainClassName = 'hello.HelloKt'
the generated .jar file is not including the kotlin runtime, so the only way to execute it, is by:
d:/App/build/libs/kotlin -cp App.jar hello.HelloKt
but in order to generate a self contained jar that can be self-executed, and contains the kotlin runtime then the build.gradle should be written as:
// set up the kotlin-gradle plugin
buildscript {
ext.kotlin_version = '1.1.2-2'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
// apply the kotlin-gradle plugin
apply plugin: "kotlin"
// add kotlin-stdlib dependencies.
repositories {
mavenCentral()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
jar {
manifest {
//Define mainClassName as: '[your_namespace].[your_arctifact]Kt'
attributes 'Main-Class': 'hello.HelloKt'
}
// NEW LINE HERE !!!
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
followed by gradle build, the [your_working_folder].jar file will be generated at the build/libs folder, assuming the working folder name is app, then file app.jar will be generated.
To run this file, one of the following 2 commands can be used:
D:\App\build\libs\java -jar App.jar
OR
D:\App\build\libs\kotlin App.jar hello.HelloKt

No Main Maifest attribute Gradle

I have read all the other threads about this problem and applied all the solutions I could find. Nothing helped. When I run the gradle.build task I get a .jar file. But when running the file I get no main manifest attribute, in DiscordBotJDA-1.0.jar
Can annyone provide help?
Thanks a lot!
Here is my gradle.buidl file:
/*
* This build file was auto generated by running the Gradle 'init' task
* by 'Timbo' at '7/13/16 2:08 PM' with Gradle 2.9
*
* This generated file contains a sample Java project to get you started.
* For more details take a look at the Java Quickstart chapter in the Gradle
* user guide available at https://docs.gradle.org/2.9/userguide/tutorial_java_projects.html
*/
// Apply the java plugin to add support for Java
apply plugin: 'java'
apply plugin: 'application'
mainClassName = 'start.StartUp'
version = '1.0'
task fatJar(type: Jar) {
manifest {
attributes 'Implementation-Title': 'MCI_Bot',
'Implementation-Version': version,
'Main-Class': 'start.StartUp'
manifest.attributes("Main-Class": 'start.startUp')
}
baseName = project.name + '-all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
// In this section you declare where to find the dependencies of your project
repositories {
// Use 'jcenter' for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}
// In this section you declare the dependencies for your production and test code
dependencies {
// The production code uses the SLF4J logging API at compile time
compile 'org.slf4j:slf4j-api:1.7.13'
compile 'net.dv8tion:JDA:2.1.3_327'
// Declare the dependency for your favourite test framework you want to use in your tests.
// TestNG is also supported by the Gradle Test task. Just change the
// testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add
// 'test.useTestNG()' to your build script.
testCompile 'junit:junit:4.12'
}
I am using eclipse in case it matters.
Were you expecting that your "fatJar" task would be doing that? Just defining the task doesn't put it into the task execution tree. You have to either run the task directly, or specify a task dependency relationship including your task. For instance, saying that another task depends on it.
You might be better off just specifying a "jar" configuration block, which will configure the already existing "jar" task, which already has proper dependency relationships defined.
Read the User Guide for examples of configuring the "jar" task.
It might be more convenient to download the Gradle distribution, which provides the PDF of the User Guide, which might be easier to search.

Categories

Resources