Explicitly run Gradle DefaultTasks in addition to another task - gradle

I have some defaultTasks specified in my build.gradle. For the purposes of CI I want to be able to run these tasks in addition to some other tasks.
Is it possible to invoke gradle to run the default tasks in addition to some other tasks (without explicitly specific all tasks that are part of "default tasks").
For example:
In build.gradle:
defaultTasks 'A','C','D'
In my CI i want to run specified default tasks plus task 'E'
So something like:
gradle defaultTasks E
I want to avoid having to explicitly list all the tasks again like:
gradle A C D E
Possible ? (with a single gradle invocation)

You can make a new task, called runDefaultTasks and make it dependent on any tasks you wish to run by default. Something like this:
def defaultTasks = ['A','B','C']
task runDefaultTasks(dependsOn: defaultTasks) {
}
And then just call it as follows:
gradle runDefaultTasks E

Related

Configure a Gradle Task at Runtime

Is It possible to configure inputs of a gradle task at runtime after other tasks have run?
For example I am calculating a SHA of a zip in one step, and then uploading the zip with a path consisting of the SHA from a previous step. But when I got get get the value of the SHA which is contained in a file via: def sha = shaFile.text I get an error: (No such file or directory).
I had always assumed tasks were closures which were run at runtime but I guess that is just the doFirst & doLast, but the inputs need to be configured already before that.
Is It possible to configure inputs of a gradle task at runtime after other tasks have run?
Think of it this way:
In order for task B to run, task A must run first, that is to say, task B has a dependency on task A.
Refer to Adding dependencies to a task for more details on task dependencies.
Ok so now we're at the point where we need the output of task A (SHA value) as an input for task B. Since we have a dependency on task A, Gradle well make sure that task A is executed prior to B's execution.
Here's quick dirty example in Kotlin DSL (should be easily translated to Groovy):
tasks {
val taskA = register("taskA") {
val shaText = File("sha.txt")
if (shaText.exists()) {
shaText.delete()
}
File("sha.txt").writeText("abc");
}
register("taskB") {
dependsOn(taskA)
println(File("sha.txt").readText())
}
}
Ideally, you should create a custom task type specifying the input file and also specifying the output file so that Gradle can cache tasks inputs/outputs. Refer to Incremental tasks
for more details.

Make gradle execute a finalizedBy task for each time it is set (multiple times)

I ran into the problem using the following situation:
To run different native testplugins in a row I dynamically create some tasks to prepare the environment appropriately for each plugin and then create a plugin_task for each testplugin that hosts the dependencies.
To start the tests on the device, the plugin_task is finalizedBy connectedAndroidTest.
So e.g. the call gradle plugin_name_1 works fine, it prepares the environment and starts the tests.
tasks.register("allTests"){}
name_list.each { test_name ->
def prepare_dir = tasks.register("${test_name}_Prepare_Dir") {...}
def copy_files = tasks.register("${test_name}_Copy_Files") {...}
def plugin_task = tasks.register(test_name){
dependsOn prepare_dir
dependsOn copy_files
finalizedBy connectedAndroidTest
}
allTests.configure {
dependsOn pluginTask
}
}
The problem now occurs, when I try run the allTests task:
gradle then correctly operates over all the dynamicly created tasks "prepare_dir", "copy_files" for each of the plugins, all of them are executed.
But the connectedAndroidTest will only be executed at the very end of allTests, so only runs once. But I need this task to be executed at every end of each plugin_task.
The behavior of gradle is correct, as it sees that all plugin_tasks shall be finalized by connectedAndroidTest and so puts it at the end of the graph.
Is there any possibility to make gradle execute this task multiple times?
Would be glad for help.
Wrapping the connectedAndroidTest task into dynamically created tasks and let the plugin_tasks depend on them, does not help. Also the parameter "rerun-tasks" has no effect.
That's not how Gradle works. Each task will execute either 1 or 0 times per Gradle invocation. If you want to execute the same task multiple times (with different task inputs) then you'll need multiple task instances, not one.

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

Task with path 'build' not found in root project

I have a multiproject and after the last subproject is built, I'd like to process all jars.
Therefore I created a task in the root-project:
task install(dependsOn: 'build', type: Copy) {
doLast {
println "exec install task"
}
}
Upon calling ./gradlew install in the root directory, I'm facing this error:
FAILURE: Build failed with an exception.
* What went wrong:
Could not determine the dependencies of task ':install'.
> Task with path 'build' not found in root project 'foo'.
However, calling ./gradlew tasks shows me these tasks:
:tasks
------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------
Build tasks
-----------
assemble - Assembles the outputs of this project.
build - Assembles and tests this project.
...
How can I achieve the desired functionality?
I assume, that your root project organizes the build, but does not define build action taken by itself. The build task is often defined by language plugins (in most cases via apply plugin: 'java'), but if your root project does not use any of them, it won't have a build task.
The description of the help task tasks, which you used, says:
Displays the tasks runnable from root project 'projectReports' (some of the displayed tasks may belong to subprojects).
The help task followes the same logic as the task activation via the command line. You can provide a task name and any task with the name in any subproject will be executed (thats why gradle build works).
But if you define a dependsOn dependency, the given string is evaluated as task path for a single task. Since each task name can only be used once in a project, the name is unique for tasks in the root project, but many tasks could be found, if subprojects would be considered. Therefor, one can use the syntax :<projectName>:<taskName> to identify tasks in subprojects.
Now, let's face your specific problem: If the install task should depend on the build task of one single subproject, you could use dependsOn ':<mySubproject>:build'. But I assume you want the install task to depend on each subproject build task, so I'd like to propose this approach:
task install(type: Copy) {
dependsOn subprojects*.tasks*.findByName('build').minus(null)
doLast {
println "exec install task"
}
}
This way, for each registered subproject, findByName('build') is called and the result (the found task or null) is put into a list, which is then used as task dependency list. I added the .minus(null) part to remove null entries from the list, because I am not sure how Gradle handles such entries in a dependency collection. If you are sure, that each subproject provides a build task, you can use getByName('build'), too.
EDIT: OP found the optionally recursive getTasksByName method, which suits this case even better than iterating over all subprojects manually:
dependsOn getTasksByName('build', true)

Gradle multi project, scope task

I have a multi project in the following way:
rootProject
Subproject1
Subproject2
task whatever << {
println "WHATEVER"
}
I want to be able to configure task 'whatever' once and execute it from any scope (root or subproject) and be executed only once!
This means:
If I run /gradle whatever, I should get: "WHATEVER"
If I run /subproject1/gradle whatever, I should get: "WHATEVER"
In summary, I don't what to execute the same task several tasks according to the number of projects.
I haven't been able to get such a simple result. Please let me know if you can offer any help! Thanks!
gradle whatever searches for whatever in the current subproject and below. Instead, use gradle :whatever and declare the task in the root project.

Resources