gradle composite build: jars from included build in ant taskdef classpath - gradle

Project foo defines some ant tasks that are used in root project. For composite build:
setting.gradle
includeBuild '../foo'
build.gradle
configurations {
foo
}
dependencies {
foo fileTree(dir : '../foo/build/libs', include: ['*.jar'])
}
ant.taskdef(name: 'foo',
classname: 'mypackage.Foo',
classpath: configurations.foo.asPath)
The jar of included project foo should be built before evaluating the root project so that the jar will be available in the ant taskdef classpath. How?
but task dependency is in the execution phase, like
task run {
dependsOn gradle.includedBuild('../foo').task(':jar')
}
The jar will be available only after the task is executed, too late.

You can configure ant taskdef at execution phase, when the included project is already built. e.g.
task run {
dependsOn gradle.includedBuild('../foo').task(':jar')
doFirst {
ant.taskdef(name: 'foo',
classname: 'mypackage.Foo',
classpath: configurations.foo.asPath)
// call your ant target as usual
}
}
Even if there is a way of configuring evaluation-time dependency on a composite subproject, you will get a great performance degradation of project evaluation. Even a simple task like tasks or projects will require a full build of ant tasks - definetly not something you want

Related

Why won't gradle jar build a jar that gradle build does?

In my Gradle project, I define an additional sourceSet.
sourceSets {
sample {
java {
srcDir 'sample/java'
}
compileClasspath += sourceSets.main.output + sourceSets.main.compileClasspath
}
}
I then add a task:
task sampleJar(type: Jar) {
classifier 'sample'
from sourceSets.sample.output
}
artifacts {
archives sampleJar
}
If I do > gradle build the additional jar file builds from the additional source set. However, if I do > gradle jar, it doesn't. any reason why?
When I go through the output messages, I see:
gradle build has sampleJar in the Tasks to be executed:
but
gradle jar doesn't.
But unsure as to why?
Because jar is just the task that assembles the main jar file.
build, on the other hand, is the top-level life-cycle task, which depends on assemble. And assemble is documented as
Depends on: jar, and all other tasks that create artifacts attached to the archives configuration.
Since your sampleJar pecisely creates an artifact attached to the archives configuration, assemble, and thus build depends on it.

gradle composite build execute tasks transitively

When executing gradle build in a composite gradle build only compileJava task is executed transitively. Others, like the test task are not.
How can I enforce that my tests are also run on build?
I tried:
build.dependsOn gradle.includedBuilds*.task(':build')
but that did not work.
https://docs.gradle.org/current/userguide/composite_builds.html
here is the gist:
// settings
if (file('../myModule').exists()) {
includeBuild('../myModule')
}
// build1
dependencies {
compile 'mygroup:MyModule:1.0.0'
}

Gradle root project depends on subprojects build

How can I mention subproject should build before root project.
in settings.gradle
rootProject.name = 'loginmodule'
include 'servicebundle'
include 'webbundle'
include 'webredirectbundle'
When I try this build dependson subprojects:build it is giving error like circular dependency.
Currently in my root project build.gradle is bundling all subprojects like below
task createESA(type: Zip, dependsOn: generateSubSystemFile) {
subprojects.each { dependsOn("${it.name}:build") }
from subprojects.collect { "${it.buildDir}/libs" }
from (subsystemFile) {
into 'OSGI-INF'
}
from ('resources/OSGI-INF') {
into 'OSGI-INF'
}
baseName project.name
extension 'esa'
}
build.finalizedBy createESA
I am using gradle clean build to build the project.
Is there any better way to do that ?? I just want to build all subprojects first before root project build.
Have your createESA task depend on subprojects*.build, it'll say that task can't run until all of the build tasks in all of the subprojects have run. Then, declare that the root project's build task depends on createESA.
task createESA(type: Zip, dependsOn: subprojects*.build) {
// etc...
}
build.dependsOn createESA

How to set output file from another gradle build script's task from GradleBuild task?

I have project A with gradle build. I have another project B with gradle build also. I want to include project B's jar into project A's war. I can call project B's build script from project A's build script (see below).
But I can not set project B's jar as output file of task buildB.
Is there any way to set project B's jar (which is output file of task jar) as output file of task buildB?
task buildB(type: GradleBuild) {
buildFile = "../BProject/build.gradle"
tasks = ["clean", "jar"] // jar task produce xxx.jar as it's outputs.files
// HERE, any script to set xxx.jar as outputs.files of task buildB???
}
war {
from (buildB) { // can not get xxx.jar from buildB
into "WEB-INF/classes"
}
}
You probably need to configure a multi module project and define a project-scope dependency.
Since the answer full answer will be lengthy, here you can find a demo that shows how it can be done.
The demo consists of two projects. One project is built to war and has a dependency to another project which is built to war. If you build a project, b will be built automatically and included as a jar.
This is what I did.
/settings.gradle
include 'AProject', 'BProject'
/AProject/build.gradle
task buildB(type: GradleBuild) {
buildFile = "../BProject/build.gradle"
tasks = ["clean", "jar"] // jar task produce xxx.jar as it's outputs.files
}
war {
dependsOn buildB
doFirst {
from (project(':BProject').tasks['jar']) {
into "WEB-INF/classes"
}
}
}

Gradle: Task does not execute another task based on the configuration it uses

I've got a very simple multiproject build like below:
module1, which generates a public API jar and exposes it through "publicAPI" configuration:
configurations {
publicAPI
}
task generatePublicAPI(type: Jar) {
outputs.upToDateWhen { false }
baseName 'public-api'
from sourceSets.main.output
}
artifacts {
publicAPI generatePublicAPI
}
module2, which uses the public API jar (by referencing 'publicAPI' configuration defined in module1) to generate a application jar:
configurations {
generateApplication
}
dependencies {
generateApplication project(path: ':module1', configuration: 'publicAPI')
}
task jarApp(type: Jar) {
baseName 'app'
from configurations.generateApplication.collect {
it.isDirectory() ? it : zipTree(it)
}
}
Now, when I execute 'gradle :module2:jarApp" task, I got the following error:
Cannot expand ZIP
'/home/picasso/Documents/GradlePlayground/module1/build/libs/public-api.jar'
as it does not exist
and I can see that gradle was not trying to execute 'generatePublicAPI' of module1.
However, if I make "jarApp" task depends on "generatePublicAPI" task explicitly,
task jarApp(dependsOn: 'module1:generatePublicAPI', type: Jar) {...}
then everything's fine.
BUT, wouldn't this approach against one of the purpose of using dependency configuration so that I don't have to worry about the details of how module1 is built, e.g. which task generates the jar and what artifacts it produces?
I thought gradle is able to work out the tasks it needs to execute by following along the "route" of the referenced dependency configuration.
Am I missing something here so that "generatePublicAPI" task can be executed automatically without have to declare "dependsOn" explicitly for "createApp" task?
I asked the same question on Gradleware's forum and got the answer from one of the core developer, here's the link.
Basically, the issue is that collect method returns a new collection but gradle has no way to know that this new collection was generated from the configuration, therefore it couldn't infer which task to execute.
The solution is instead of declaring a dependency on a task, declare a dependency on the actual configuration instead like the following:
task jarApp(dependsOn: configurations.generateApplication, type: Jar)

Resources