Say, I have a hierarchy of Gradle projects and some of them have java plugin applied:
root
projA
projA1
projA2 (java)
projB
projB1 (java)
projB2
projB21 (java)
projB22 (java)
projC (java)
I want to execute the test task in all subprojects where this task exists: :projA:projA2:test, :projB:projB1:test and :projC:test. Probably I will add more projects in future and I don't want to manually support a list of all test tasks in all subprojects. How can I achieve it?
One thing that came to my mind is something like the following:
// In root I iterate over all subprojects and find the task by name causing
// its creation and configuration
tasks.register("testAll") {
dependsOn subprojects.findResults { it.tasks.findByName("test") }
}
I don't like this approach as it goes against task configuration avoidance style.
Another option is to iterate over subprojects and check if the java plugin is applied there:
// In root
tasks.register("testAll") {
dependsOn subprojects.findAll { it.plugins.hasPlugin("java") }.collect { it.tasks.named("test") }
}
It works but I have a filling that I miss something simpler...
EDIT 1: Sorry for that but I forgot one important detail - I need to run tests in a subtree of projects. Say, everything down the path :projB.
Unless I'm missing something, you want to run tests for all of your submodules.
You can just...do that.
./gradlew clean test
This will run the test task in all of the subprojects that have it sufficiently configured.
If you need to run the tasks in a specific subproject, from the root project you can specify the subproject you want to run the task.
./gradlew clean :projB:test
If your subprojects have a task that needs to run after test, then you can do this in your subprojects block.
subprojects {
myTask.dependsOn("test")
}
Related
I have a Jenkins build where "goals" (or tasks, in Gradle) are passed as an environment variable to my Jenkinsfile.
e.g. sh "gradle ${GRADLE_TASKS}" where GRADLE_TASKS has the value "clean build" will run gradle clean build.
This works very well until I get to sub-projects.
Let's say I have subprojects
root
|-- com.mycompany
|-- com.mycompany.api
\-- com.mycompany.ui
As far as I'm aware, if I want to run a clean build on just com.mycompany.api I'd need the command:
gradle :com.mycompany.api:clean :com.mycompany.api:build
My problem is that the passed variable may represent one (or many) tasks to run.clean, build, clean build, deploy, clean deploy, clean publish deploy etc.
Note: I need to keep this to a solution that uses the Jenkinsfile (not the Gradle plugin, for example) because it is a hybrid build that doesn't only utilise Gradle.
My first instinct was to loop through the tasks (as below), but it seems Jenkins doesn't let you run loops like this.
def tasks = GRADLE_TASKS.split(' ')
tasks.each { task ->
sh "gradle :com.mycompany.api:${task}"
}
How should I go about this?
[edit] I should have also specified, is there some way to run this nested, so that I can clean all subprojects and then build?
e.g. The equivalent of:
gradle :com.mycompany.api:clean :com.mycompany.ui:clean
gradle :com.mycompany.api:build :com.mycompany.ui:build
I would do it like this (below) but obviously Jenkins doesn't like groovy closures...
tasks.each { task ->
subprojects.each {project ->
gradle :${project}:${task}
}
}
It looks like the answer provided by #tim_yates goes some way to answering the problem in a very 'groovy-like' manner.
sh "gradle ${GRADLE_TASKS.split(' ').collect { ":com.mycompany.api:${it}" }.join(' ')}"
I've defined my sourceSets as
sourceSets {
// Configuring SourceSets for all connector source files.
main {
java {
srcDirs = ['src']
}
}
test {
// integrationTests
}
unitTests {
//unitTests
}
}
test {
// integrationTests
}
task('unitTest', type: Test) {
//unitTests
}
When I kick off ./gradlew build it's check task basically calls the test target.
Can I override the default gradle build tasks's 'check' mechanism to call unitTest here instead of test?
First of all, please consider just using the task test for unit tests and using another source set for integration tests. Gradle and its plugins follow an approach called convention over configuration and the convention of the Java plugin is to use the task test for unit tests.
To actually answer your question, you can access and modify the dependencies of each task using getDependsOn() and setDependsOn(Iterable<?>), so a simple solution to your problem could be the following code:
check {
dependsOn.clear()
dependsOn unitTest
}
This removes all task dependencies from the task check and then adds a dependency on the task unitTest. However, this may cause new problems, because other plugins may automatically register task dependencies for check that will be removed, too.
An obvious improvement to the code above would be to just remove the dependency on the test task instead of all task dependencies. Sadly, this is not as simple as one would think. You may have noticed that the method getDependsOn() returns a Set<Object> and not a Set<Task>. For convenience, task dependencies may be expressed not only using tasks but also by passing other objects that will resolve to tasks later on (e.g. a string containing the name of a task). The current version of the Java plugin uses a Provider<Task> to register the dependency between the task check and the task test. To just remove the dependency on the task test, you would need to iterate over all dependencies in dependsOn and find the one with the type Provider that returns the task test via its get() method. You could then remove that Provider from dependsOn.
As you can see, it is possible to remove task dependencies once they have been registered, but it is not that easy, so you should probably just follow the convention and use the task test for unit tests.
As a part of a TDD workflow, I want to be able to check if my Java codebase compiles, but not if the tests pass.
Currently, if I run gradle build it runs the compile tasks (for source and tests) and then also executes the test task (and returns a non-zero exit code since the tests fail).
So I find that I have to run gradle build -x test to exclude the test task, and get a successful zero exit code.
What do I add to my build.gradle to define a new task, say compile that is an alias for build x test?
So far I have this, but it doesn't seem like dependsOn takes any arguments to customize the build task I want to execute:
task compile {
dependsOn build
}
I've been reading the docs here, I see different kinds of dependency chaining mechanisms, but not to disable/exclude a particular task. How does the -x flag even work then? I assumed there would be a way to control it programmatically too.
Thanks to Bjørn Vester's answer and reading the docs, I have implemented my task as follows:
task compile {
dependsOn classes
dependsOn testClasses
}
There are lots of different tasks you can run individually. For instance:
gradle classes: Will compile your "main" code.
gradle testClasses: Will compile your "main" code as well as test code.
gradle jar: Will compile your "main" code and assemble it into a jar.
None of the above will run your unit tests. On the other hand, the build task depends on all of the above, as well as the test task and more.
In general, if you like to run a particular set of tasks, you do that by defining a new task and then make dependencies to those other tasks you like to run with it. You tried that already, but instead of build you should have used something like compileJava or classes whatever other tasks you need. But always check if there isn't one already that satisfies your needs, like there are in this case. You can read about what tasks are available in Java projects in the documentation for the Gradle java plugin.
On a new environment gradle build takes quite a while because all dependencies have to be downloaded.
Is there a way to only download dependencies in order to speed up the following build?
That way we could for example already prefill a CI build environment.
Edit: Updated for Gradle 6+.
Some notes:
This new approach downloads jars into a folder, and then deletes the folder. So the result of having the jars in the Gradle cache is a side-effect.
It currently uses jars configured for the main source-set but could be generalized.
Even though it is neither efficient nor elegant, it can be useful if you actually want the jars (and transitive dependencies): simply comment-out the deletion of the runtime folder.
This solution can be handy when you want the jars (and transitive dependencies), as you simply have to comment-out deleting the folder.
Consider this build.gradle (as an arbitrary, concrete example):
apply plugin: 'java'
dependencies {
implementation 'org.apache.commons:commons-io:1.3.2'
implementation 'org.kie.modules:org-apache-commons-lang3:6.2.0.Beta2'
}
repositories {
jcenter()
}
task getDeps(type: Copy) {
from sourceSets.main.runtimeClasspath
into 'runtime/'
doFirst {
ant.delete(dir: 'runtime')
ant.mkdir(dir: 'runtime')
}
doLast {
ant.delete(dir: 'runtime')
}
}
Example run:
$ find /Users/measter/.gradle/caches -name "commons-io*1.3.2.jar"
$ gradle getDeps
$ find /Users/measter/.gradle/caches -name "commons-io*1.3.2.jar"
/Users/measter/.gradle/caches/modules-2/files-2.1/commons-io/commons-io/1.3.2/[snip]/commons-io-1.3.2.jar
I've found ./gradlew dependencies (as suggested by this user) to be very handy for Docker builds.
You can create a custom task that resolves all the configurations( in doing so, it will also download the dependencies without building the project)
task downloadDependencies {
doLast {
configurations.findAll{it.canBeResolved}.each{it.resolve()}
}
}
Run command ./gradlew downloadDependencies
My answer will favor the gradle plugins and built-in tasks.
I would use "gradle assemble" in the command-line.
It is a minor version of "gradle build".
This way, you may reduce the time of your preparations before running or building anything.
Check the link bellow for the documentation:
https://docs.gradle.org/current/userguide/java_plugin.html#lifecycle_tasks
In general, what is my recipe when I clone a new repository:
-gradle assemble
-do some coding
-gradle run (and basically test until done)
-gradle build (to make distributable files)
note: this last step may have adicional configurations for .jar files as outputs (depends on you).
I couldn't find any explanation on this topic, everywhere it's just given as a fact, but I'm interested in how that works.
For example let's take 'build' task, that's provided by 'java' plugin in subproject (but not available in root project).
In root we can call 'gradle build' or 'gradle :mysubproject:build'
eqally and subprojects build task will be called.
However, in root project we cannot write 'build dependsOn
someOtherTask', because it's not available in root - java plugin
isn't added there.
What makes build task available in root? Is there some property that makes task available in parent projects?
If you call Gradle with task names as arguments in a multi-project build, each task with the specified name in any root or subproject will be executed. If you only want to execute a specific task of the given name, use task paths like :mySubProject:build for a subproject or :build for the root project.
Please note, that this has nothing to do with accessing a project in a build.gradle file. In this file, only the tasks of the current project are available. To access tasks in other projects, you could use their task container like rootProject.tasks['build'] or project(':sub').tasks['build']. However, you may run into issues, cause the tasks might not be created when you try to access them.
For task dependencies, you can simply use strings that contain absolute task paths, like dependsOn ':sub:build' or dependsOn ':build'. Using just 'build' will in this context only refer to the task with the specific name in the current project.
The build task is a lifecycle task (ie a task which doesn't actually do anything itself but it can dependsOn other tasks). See base plugins which states the following about the base plugin
Adds the standard lifecycle tasks
If you want the build task in the root project you'll need to add:
apply plugin: 'base'