How to execute another task from a task with dependencies - gradle

I have multiple gradle files to run test suites. Each gradle file has multiple tasks with dependencies defined. And there will be a task with same name as file name to run all those tasks.
Example
foo_test.gradle
task testBlockA << {
// do some tests here
}
task testBlockB(dependsOn: testBlockC) << {
// do some tests here
}
task testBlockC << {
// do some stuff here
}
task foo_test(dependsOn: testBlockA, testBlockB)
Now I want to write a common test.gradle file which, based on argument provided, loads the given test gradle file and runs the task
gradle -b test.gradle -Ptest_to_run=foo_test
How to I create a task in test.gradle, which will run foo_test task of foo_test.gradle, along with its dependencies (testBlockA-C)
As I read tasks['foo_test'].execute() will not work as it does not execute the dependsOn tasks.

In your main build.gradle file, you can read the provided -P attribute in your build.gradle file:
if(project.hasProperty("test_to_run")){
apply from:test_to_run
defaultTasks test_to_run
}
this snippet applies a buildscript based on the input property and also declares a defaultTask to run.

Related

How can I debug Gradle does not know how file '...' was created?

I have created a task in Gradle as follows:
task findTaskCreatingSpecificOutput() {
dependsOn testClasses
doLast {
tasks.findAll { task ->
task.outputs.getFiles().getFiles().each { output ->
if (output != null && output.getAbsolutePath().contains('generated')) {
println task
println output
}
}
}
}
}
to try and find which two tasks are writing to the same generated location. However the output is a list of tasks and directories which do not overlap at all so it should be easy for Gradle to know exactly which task created the location.
Example output of ./gradlew clean findTaskCreatingSpecificOutput --info
/Users/mylocation/shared/build/generated/sources/annotationProcessor/java/main
task ':shared:compileJava'
/Users/mylocation/shared/build/generated/sources/headers/java/main
task ':shared:compileTestFixturesJava'
/Users/mylocation/shared/build/generated/sources/annotationProcessor/java/testFixtures
task ':shared:compileTestFixturesJava'
/Users/mylocation/shared/build/generated/sources/headers/java/testFixtures
task ':shared:compileTestJava'
/Users/mylocation/shared/build/generated/sources/annotationProcessor/java/test
task ':shared:compileTestJava'
/Users/mylocation/shared/build/generated/sources/headers/java/test
task ':shared:delombok'
/Users/mylocation/shared/build/generated/sources/delombok/java/main
task ':shared:delombokTest'
/Users/mylocation/shared/build/generated/sources/delombok/java/test
task ':shared:delombokTestFixtures'
/Users/mylocation/shared/build/generated/sources/delombok/java/testFixtures
However I still get the warning Gradle does not know how file 'build/classes/java/main/generated' was created (output property 'destinationDirectory'). Task output caching requires exclusive access to output paths to guarantee correctness (i.e. multiple tasks are not allowed to produce output in the same location).
I don't think there's any way to find out which task actually wrote any particular file. The code I used only lists the declared outputs.
In my case the problem was that I was running a bytecode weaving task in doLast for compileJava.
I've changed compileJava to write to a new directory using destinationDirectory and then the weaving task writes the updated classes to sourceSets.main.output.classesDirs.singleFile

How can I only execute specific task in build.gradle?

build.gradle is:
task copy(type: Copy, group: "Custom", description: "Copies sources to the dest directory") {
from "src"
into "dest"
println "copy"
}
task hello {
println "hello"
}
And when I try with ./gradlew copy, both copy and hello are executed. Output like below:
> Configure project :
copy
hello
How can I only execute copy?
In your example, only the copy task is executed. However, both are configured.
A Gradle build has three distinct phases in the build lifecycles:
An initialization phase
A configuration phase
An execution phase
By default, Gradle configures all tasks at start-up, though many types of configurations can be deferred (lazy configuration).
The println statement you have in the hello task is part of the configuration and this is why you see it no matter what task you intend to execute. You can also see in the output that is under the > Configure project : header.
If you want to only print "hello" when it actually executes, move it into a doLast block like this:
task hello {
doLast {
println "hello"
}
}

skip a task in gradle, but only if the task exists

I have a complex multi sub-project gradle project with a little kotlin multiplatform inside and a fex custom gradle plugin.
My issue is , when I want to run the build by skipping some tasks(mostly test), not all the project have the same test task name : for some it's call jsTest, for other nodeJsTest, for other jvmTest.
So when I call gradle build -x jsTest -x nodeJsTest I have error because sometime some of the tasks to skip don't exist.
How can I skip the task, and ignore-it if it don't exist?
You can modify your Gradle file to do something like (Kotlin DSL):
tasks.named("build") {
dependsOn.removeIf { it.toString().contains("flakyTest") }
}
Otherwise you will need to aggregate your tasks to what you want specifically either by doing ./gradlew myTask anotherTask anotherOne andAnotherOne or create a task that dependsOn all the tasks you want.
Instead of making your test tasks to depend on build directly, you can create generic test task task testType in the middle- build triggers task testType and then it triggers jsTest or whatever relevant test task you create in that module.
Now you can safely run gradle build -x testType.
For example (in your .gradle file):
task jsTest { ... }
task testType { dependsOn jsTest }
build.finalizedBy(testType)
Do the same for the rest of your test tasks files, you can also create task testType globaly if you want the solution to be cleaner.

Depend on multiple gradle tasks in multi project build

Currently I have task which starts Google Cloud server, runs tests and stops server. It is defined at root project:
buildscript {...}
allprojects {...}
task startServer (dependsOn: "backend:appengineStart") {}
task testPaid (dependsOn: "app:connectedPaidDebugAndroidTest") {}
task stopServer (dependsOn: "backend:appengineStop") {}
task GCEtesting {
dependsOn = ["startServer",
"testPaid",
"stopServer"]
group = 'custom'
description 'Starts GCE server, runs tests and stops server.'
testPaid.mustRunAfter 'startServer'
stopServer.mustRunAfter 'testPaid'
}
I tried multiple ways to write it something like this, short with only one task. I didn't get how to refer to task from another project and call mustRunAfter on it. This doesn't work (I also tried to refer from Project.tasks.getByPath, root.tasks, etc):
task GCEtesting {
dependsOn = ["backend:appengineStart",
"app:connectedPaidDebugAndroidTest",
"backend:appengineStop"]
group = 'custom'
description 'Starts GCE server, runs tests and stops server.'
"app:connectedPaidDebugAndroidTest".mustRunAfter "backend:appengineStart"
"backend:appengineStop".mustRunAfter "app:connectedPaidDebugAndroidTest"
}
Is it possible? What is correct syntax to make this work?
It looks like your problem is that you're treating dependsOn as meaning "invoke this task". It actually means "ensure the result of the depended on task is available before the dependent task starts". That's why your first solution didn't work: statements like testPaid.mustRunAfter only affect the actions of the testPaid task itself, not its dependencies.
Anyway, you can get the behaviour you want using dependsOn and finalizedBy, but they have to be declared in the build file of the app subproject.
app/build.gradle:
task connectedPaidDebugAndroidTest {
//
//...
//
dependsOn 'backend:appengineStart' // Ensure appengineStart is run at some point before this task
finalizedBy 'backend:appendginStop' // Ensure appengineStop is run at some point after this task
}
Then, you can run your tests simply with gradle app:connectedPaidDebugAndroidTest. If you really want to define a task in the root project to run the tests, then that's easy too:
build.gradle:
task GCEtesting {
dependsOn = "app:connectedPaidDebugAndroidTest"
}

Using GradleBuild , how to specify individual task to execute from tasks list

I've two gradle files :
build.gradle
apply from :'other.gradle'
task hiHelloWrapper(type: GradleBuild) {
buildFile = 'other.gradle'
tasks = ['hi','hello']
}
other.gradle
task hello<<{
println 'hello from other'
}
task hi<<{
println 'hi from other'
}
Now, when I execute
>gradle hiHelloWrapper
it results in both tasks hi and hello being executed and they are executed in their relative order in tasks list .
Is there any way that I can execute selectively one of them without creating another task which includes only one of them?
As far as I understood you just need to run:
gradle hi
or
gradle hello
All tasks from other.gradle are imported to build gradle and can be used out of the box.

Resources