How to call Gradle task execution from outside task? - gradle

I have code:
task instalNodeModules {
doLast {
npmInstall.execute()
installGulp.execute()
}
}
task runTasks {
doLast {
instalNodeModules.execute()
gulpBuildWithOpts.execute()
}
}
Gradle 4.5.1 warns about it as
The TaskInternal.execute() method has been deprecated and is scheduled
to be removed in Gradle 5.0. There are better ways to re-use task
logic, see
https://docs.gradle.org/4.5.1/userguide/custom_tasks.html#sec:reusing_task_logic.
But link does not give me any hint how I could replace it because I can’t just setup task dependencies like dependsOn or finalizdBy - it called not from other task but from end of build.

You are not supposed to call the execute method directly, but rather model your tasks dependencies. This allows gradle to perform up-to-date checks and only execute the tasks that are needed.
task runTasks {
dependsOn installNodeModules
dependsOn gulpBuildWithOpts
}

Related

Passing parameters to dependable task of custom task

There is task which can be executed with parameter like this:
./gradlew taskX -Pkey=value
And plugin with custom task which should execute taskX:
class CustomPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.tasks.register("custom", CustomTask::class.java)
.configure {
it.description = "Description"
it.group = "Group"
val taskX = project.getTasksByName("taskX", true).first()
it.dependsOn(taskX)
}
}
}
I would expect something like this for example:
it.dependsOn(taskX, "key=value")
How to pass parameters to dependsOn?
Simple answer: You can't. Task dependencies only express what needs to be done beforehand, not how it needs to be done.
Let me show you a simple example, why something like this is not possible in the Gradle task system:
First, we need to know that in Gradle, every task will be executed only once in a single invocation (often called build). Now imagine a task that needs to be run before two tasks that are unrelated to each other. A good real world example is the task compileJava from the Java plugin that both the test task and the jar task depend on. If dependsOn would support parameters, it could happen that two tasks depend on a single task with different parameters. What parameters should be used in this case?
As a solution, you may configure the other task directly in your plugin. If you want to pass the parameter only if your custom task is run, you may need to add another task that runs as a setup and applies the required configuration to the actual task:
task setup {
doFirst {
// apply configuration
}
}
taskX.mustRunAfter setup
task custom {
dependsOn setup
dependsOn taskX
}
This example uses Groovy, but it should be possible to translate it to Kotlin and use it in your plugin.
Edit regarding actual parameter
To be honest, I am not that familiar with the Android Gradle plugin, but if I get this documentation right, the project property android.testInstrumentationRunnerArguments.annotation is just an alternative to using the following code in the build script:
android {
defaultConfig {
testInstrumentationRunnerArgument 'annotation', '<some-value>'
}
}
You may try to define the following task and then run it using ./gradlew customTest
task customTest {
doFirst {
android.defaultConfig.testInstrumentationRunnerArgument 'annotation', '<some-value>'
}
finalizedBy 'connectedAndroidTest'
}

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"
}

Run a hava program from gradle as a part of another task

I can run a java program as a separate gradle task using JavaExec type for the task:
task (foo, type: JavaExec) {
main = '...'
...
}
However, how do I run a Java program as a part of another task, say in a doLast? I can probably do something with ant executor, but is there some way more native to gradle?
You can define a dependency with dependsOn between tasks or you can use javaexec method defined on project instance, see here.
Pseudocode:
task t {
doLast {
javaexec {
//logic goes here
}
}
}

Why gradle clean task starts all other non-default tasks?

I have gradle set up and running. My build.gradle has 2 tasks defined inside:
task setVersion() {
println('setVersion')
//...
}
task setIntegrationEnv() {
println('setIntegrationEnv')
//...
}
When I run
./gradlew clean
gradle runs both tasks setVersion and setIntegrationEnv and then it runs clean for all my modules (app, cloud_module) in that project, output:
Relying on packaging to define the extension of the main artifact has been deprecated and is scheduled to be removed in Gradle 2.0
setVersion
setIntegrationEnv
:cloud_module:clean
:app:clean
BUILD SUCCESSFUL
Total time: 14.18 secs
Why this happens, where this behavior is defined?
Could You please provide full build.gradle script? I'd be much easier to help You. You've probably mistaken gradle build phase with configuration phase - it's a common topic here.
General rule is that code You'd like to be run at build phase should be added as an action:
task someTask << {
println 'runtime'
}
while code You'd like to run at configuration phase should be added in task body:
task someTask {
println 'configuration
}
or all together:
task someTask {
println 'configuration'
doLast {
println 'runtime'
}
}
Additional info can be found here, here and here.

Resources