Gradle task execution order doesn't seem to be garuanteed order - gradle

I have written a tool OwnerFinder that does some annotation processing on some jars of an application. I need to expose this tool on TeamCity so have written a gradle script which performs following tasks
Extract the application zip file
Copy the application jars to a location build/appJars
compile tool OwnerFinder (keep the appJars in the classpath)
create jar of OwnerFinder
Run OwnerFinder(keep the appJars in the classpath)
(I need to keep the app jars in the class path because the annotation for which processing needs to be done is in those jars)
But somehow the order of the task is not guaranteed even after using dependsOn and mustRunAfter. The script fails either at
compilation task (where its not able to find the annotation in the dependencies)
or
run task where its not able to find the class OwnerFinder
but after 2nd or 3rd try it runs sucessfully. This makes me think that the gradle tasks are not executing as per order.
Following is my gradle script:-
apply from: 'http://some-gradle-util-script'
apply plugin: 'java'
def confs = ["someApplicationConf"]
confs.each { configurations.create it }
configurations { sources }
configureDownload('ivy', 'ivy-integrated')
dependencies {
def someApplicationVersion = '1.12.0.+'
someApplicationConf "com.soft:someApplication-sync:${someApplicationVersion}#zip"
compile 'com.google.guava:guava:16.0.1',
'com.google.code.gson:gson:2.2.2'
testCompile group: 'junit', name: 'junit', version: '4.11'
}
task unzip(type: Copy, dependsOn: clean) {
from zipTree(configurations.someApplicationConf.singleFile)
into "$buildDir/unzipped"
}
task copyJar(type: Copy, dependsOn: unzip) {
from "$buildDir/unzipped/modules"
into "$buildDir/op"
}
copyJar.mustRunAfter unzip
task compileOwnerFinder(type: JavaCompile, dependsOn: copyJar) {
FileCollection f = files(fileTree(dir: 'build/op', include: '*.jar').files, configurations.compile.files)
source = fileTree(dir: 'src', include: '**/*.java')
classpath = f
destinationDir = new File("$buildDir/classes/main")
}
compileOwnerFinder.mustRunAfter copyJar
task jarOwnerFinder(type: Jar, dependsOn: compileOwnerFinder) {
from files(sourceSets.main.output.classesDir)
}
task runOwnerFinder(type: Exec, dependsOn: jarR) {
def classpath = fileTree(dir: 'build/op', include: '*.jar').files + configurations.compile.files +
fileTree(dir: 'build/libs', include: '*.jar').files
commandLine "java", "-classpath", classpath.join(File.pathSeparator), "OwnerFinder"
}
runOwnerFinder.mustRunAfter jarOwnerFinder

Related

gradle - Add custom configuration to installDist for a specific task

I'm trying to make a custom runtime dependency configuration, so that the specified dependencies will only be installed for a specific task. The dependencies are installed using the installDist task. So it seems like I need the configuration to be added to the runtimeClasspath for one task and not the other. I'm thinking I need a custom distribution, but I'm not sure how to set that to have a different runtimeClasspath.
In the example below, I want the run2 task to have the myRuntimeDep dependencies installed, but for the run1 task I do not.
I've be struggling to figure this out all day, does someone know what I'm missing?
Example build.gradle:
configurations {
myRuntimeDep.extendsFrom runtimeOnly
}
dependencies {
...
myRuntimeDep 'the:dependency:1.0'
}
task run1(type: JavaExec, dependsOn: installDist) {
// does not need myRuntimeDep dependencies
}
task run2(type: JavaExec, dependsOn: installDist) {
// needs myRuntimeDep dependencies
}
So after a long weekend, I sort of got something working. Maybe someone can tell me if there's a better way? Also, it doesn't fully work because it doesn't follow transitive dependencies with the configuration (which is kind of a pain because all sub-dependencies need to be manually added).
Solution:
top-level build.gradle
...
subprojects {
configurations {
fooRuntime.extendsFrom runtimeOnly
fooClasspath.extendsFrom runtimeClasspath, fooRuntime
}
distributions {
foo {
contents {
from installDist.destinationDir
from(configurations.fooClasspath) {
into 'lib'
}
}
}
}
installFooDist.dependsOn installDist
}
project A build.gradle
dependencies {
fooRuntime project(':projectB')
fooRuntime project(':projectC') // only need this because transitive dependencies won't work
}
task run(type: JavaExec, dependsOn: installFooDist) {
classpath = fileTree("$installFooDist.destinationDir/lib")
}
project B build.gradle
dependencies {
fooRuntime project(':projectC')
}
task run(type: JavaExec, dependsOn: installFooDist) {
classpath = fileTree("$installFooDist.destinationDir/lib")
}

In gradle, how to copy a subset of compiled test classes

I tried taking a portion of the compiled test classes of a Gradle project, and put them in a jar file (to create a test case). What happened was, only those classes got compiled out of all test classes. Any idea how to do it right?
Here's my build.gradle:
plugins {
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
}
task testSampleJar(type: Zip) {
archiveName "sample.jar"
from compileTestJava {
include "org/example/samples/**"
}
}
test {
dependsOn(testSampleJar)
}
So what seems to be happening is that by just defining the testSampleJar task, the compileTestJava task gets modified to only compile under org.example.samples package. My intent was to use the outputs of compileTestJava and pick something out of them them.
Thanks,
Uri
OK, figured it out, so the two possible solutions are:
//a global filter
task testSampleJar(type: Zip) {
archiveName "sample.jar"
from compileTestJava
include "org/example/samples/**"
}
Or
//Child specification - notice the parentheses around compileTestJava
task testSampleJar(type: Zip) {
archiveName "sample.jar"
from (compileTestJava) {
include "org/example/samples/**"
}
}
I guess the original code was defining compileTestJava instead of using its output, but I don't have a full grasp of Groovy/Gradle DSL to be certain.

Gradle 5 QueryDsl Generating Duplicate Classes

I am using queryDsl to generate Q classes with Gradle. It used to work fine with Gradle 3.5, but on upgrading to Gradle 5.5.1, it is failing with duplicate class error.
My generateQueryDsl task works fine generating the classes under 'gensrc/' but on compileJava, the classes are generated again under 'build/generated/' which ends up giving duplicate class error.
dependencies {
api("org.springframework.boot:spring-boot-starter-data-jpa") {
exclude group: "org.hibernate", module: "hibernate-entitymanager"
exclude group: "org.hibernate", module: "hibernate-core"
exclude group: "org.apache.tomcat", module: "tomcat-jdbc"
}
api("com.zaxxer:HikariCP:${hikaricpVersion}")
api("com.h2database:h2:1.4.193")
api("mysql:mysql-connector-java")
api("com.microsoft.sqlserver:sqljdbc42:6.0.8112")
api("org.springframework.data:spring-data-jpa")
api("org.springframework:spring-jdbc")
api("org.springframework:spring-orm")
api("org.eclipse.persistence:javax.persistence:${eclipseLinkPersistenceVersion}")
api("org.eclipse.persistence:eclipselink:${eclipseLinkVersion}")
api("org.eclipse.persistence:org.eclipse.persistence.jpa:${eclipseLinkVersion}")
api("com.mysema.querydsl:querydsl-sql:${queryDslVersion}")
api("com.mysema.querydsl:querydsl-jpa:${queryDslVersion}")
api("com.mysema.querydsl:querydsl-apt:${queryDslVersion}")
annotationProcessor('com.mysema.querydsl:querydsl-apt:3.7.4:jpa')
annotationProcessor("org.springframework.boot:spring-boot-starter-data-jpa")
}
task generateQueryDSL(type: JavaCompile, group: 'build) {
source = sourceSets.main.java
classpath = configurations.compileClasspath
options.annotationProcessorPath = configurations.annotationProcessor
destinationDir = file('gensrc/main/java')
}
compileJava {
dependsOn generateQueryDSL
}
error: duplicate class: com.persistence.domain.model.QOrganizationBasedModel
and likewise for all generated classes
When you use the annotationProcessor configuration, the default compileJava task adds the processor to the compiler, and it will generate classes in build/generated/sources/annotationProcessor/java/main.
In your case, you also declare an additional JavaCompile task, which you give the same annotationProcessor configuration, which will then generate the same classes again.
To solve this, I would simply delete generateQueryDSL task entirely as compileJava most likely does everything you need already. And if you like the generated sources in a different folder, you can do that through CompileOptions, but I would recommend having them under the build folder for most cases.

How to create a custom task in gradle to pack java and kotlin code to a jar?

We have a multi modular setup and we are sharing some tests classes between the modules (mainly Fakes implementations). Our current solution (that you can find below) works just for classes written in Java, but we are looking at supporting also shared kotlin classes.
if (isAndroidLibrary()) {
task compileTestCommonJar(type: JavaCompile) {
classpath = compileDebugUnitTestJavaWithJavac.classpath
source sourceSets.testShared.java.srcDirs
destinationDir = file('build/testCommon')
}
taskToDependOn = compileDebugUnitTestSources
} else {
task compileTestCommonJar(type: JavaCompile) {
classpath = compileTestJava.classpath
source sourceSets.testShared.java.srcDirs
destinationDir = file('build/testCommon')
}
taskToDependOn = testClasses
}
task testJar(type: Jar, dependsOn: taskToDependOn) {
classifier = 'tests'
from compileTestCommonJar.outputs
}
How can I modify the compileTestCommonJar so it supports kotlin?
Here is what we do:
In the module with shared test classes, pack the test source set output into a jar
configurations { tests }
...
task testJar(type: Jar, dependsOn: testClasses) {
baseName = "test-${project.archivesBaseName}"
from sourceSets.test.output
}
artifacts { tests testJar }
In a module that depends on the shared classes
dependencies {
testCompile project(path: ":my-project-with-shared-test-classes", configuration: "tests")
}
PS: Honestly, I would prefer to have a separate Gradle module with common test classes as it's more explicit solution.
The task compileTestCommonJar(type: JavaCompile) compiles .java files only because its the task of JavaCompile type.
There's KotlinCompile task aswell, so you would need to merge it, it basically works similary to JavaCompile but compiles .kt files only.
Said that i wouldn't use task system to share the dependencies across, i would use separate module and work with default compileTestKotlin and compileTestJava task's outputs

Can there be multiple war tasks in build.gradle to generate multiple wars with different dependencies

I am trying to do similar thing as: Create multiple .WAR files with different dependencies in Gradle
But the solution given in this post is not working. I am using gradle 2.5 to achieve this.
Expectation is to generate 3 different wars as output of the script. I created a simplest project with minimal dependencies. When i execute build.gradle, it just gives me single war named: Test-1.0.war. Test is name of the sample project i created.
Here is build.gradle:
apply plugin: 'java'
apply plugin: 'war'
sourceCompatibility = 1.5
version = '1.0'
task createStandardWar(type: War, dependsOn: classes) {
baseName = 'standard'
destinationDir = file("$buildDir/libs")
classifier = 'Functional'
}
task createStandardWarQasOnly(type: War, dependsOn: classes) {
baseName = 'standard-qas-only'
destinationDir = file("$buildDir/libs")
classifier = 'Functional2'
}
task createStandardWarQasAndLog4J(type: War, dependsOn: classes) {
baseName = 'standard-qas-log4j'
destinationDir = file("$buildDir/libs")
classifier = 'Functional3'
}
task createDists(dependsOn: [createStandardWar, createStandardWarQasOnly, createStandardWarQasAndLog4J])
repositories {
mavenCentral()
}
dependencies {
compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
testCompile group: 'junit', name: 'junit', version: '4.+'
}
test {
systemProperties 'property': 'value'
}

Resources