Passing parameters to dependable task of custom task - gradle

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

Related

Run gradle test from another gradle task

I created Spring Boot project which uses gradle build system. I want to run one separate test class by custom gradle task to be able depend on it in other tasks. Now I can do it with this code:
import org.apache.tools.ant.taskdefs.condition.Os
def gradleWrapper = Os.isFamily(Os.FAMILY_WINDOWS) ? 'gradlew.bat' : './gradlew'
task runMyTest(type: Exec) {
workingDir "$rootDir"
commandLine gradleWrapper, ':test', '--tests', 'com.example.MyTest'
}
Obviously, this is not a very beautiful solution, because it launches an additional Gradle daemon. I tried before another solution:
task runMyTest(type: Test, dependsOn: testClasses) {
include 'com.example.MyTest'
}
But it is not working (do not execute my test class).
UPD: I tried yet another solution:
task runMyTest(type: Test) {
filter {
includeTestsMatching "com.example.MyTest"
}
}
It fails with this error message:
Execution failed for task ':runMyTest'.
> No tests found for given includes: [com.example.MyTest](filter.includeTestsMatching)
However, obviously, my test exists, since running the test through the command line produces the correct result.
UPD2: I missed useJUnitPlatform() inside my test task. It was in the default test task (written to my build.gradle by Spring Boot initializer), but not in the custom task.
You can do it using a TestFilter.
Using includeTestsMatching you can specify your class.
If you need to specify a single test method, you can use includeTest "com.example.MyTest", "someTestMethod".
task runMyTest(type: Test) {
useJUnitPlatform()
filter {
includeTestsMatching "com.example.MyTest"
}
}

How to conditionally enable launchScript() inside bootJar?

I'm trying to setup a conditional build process.
The following code works, but I need to specify the parameter on the command line, while It should be good to define two separate task to do that.
bootJar {
if (project.hasProperty("exec")) {
launchScript()
}
}
Is there a way to execute the bootJar or another custom task to enable/disable the launchScript()?
For example, how i can define the task bootJarExecutable that acts as the standard bootJar but with the launchScript ?
You can create another task that just configures your bootJar task when executed:
task bootJarExecutable {
finalizedBy bootJar
doFirst {
bootJar.launchScript()
}
}
However, this only works if you need either the one .jar or the other in one invocation, but not both. In this case, you would need to create another BootJar task and configure it on your own.

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

Gradle: Custom task with parameter set programmatically

I have the following scenario where I wish to disable JOOQ Schema generation unless explicitly called for:
gradle.taskGraph.beforeTask {
task ->
if (!rootProject.hasProperty("generate") && task.name.equals("generateSampleJooqSchemaSource")) {
task.enabled = false
}
}
Now I can always manually generate the schema when passing "generate" as a parameter as follows:
$ gradle build -Pgenerate
Whereas a normal
$ gradle build
would not regenerate all my schema classes.
However, I do not like this approach very much. You have to remember the parameter name, and also prepend it with -P which does not look as clean.
I would ideally like to be able to make a custom task as follows:
task generate {
tasks[build].executeWithParameter("generate")
}
So that it would also show up as an actual task.
How can I accomplish this?
You can create a task that dependsOn build task and disable jooq task from it. This requires the task declaration to be put after jooq task declaration.
task generate (dependsOn: build) {
tasks['generateSampleJooqSchemaSource'].enabled = false
}
to set project property from task
task generate (dependsOn: build) {
project.ext.generate = "true"
}

Skip a task when running another task

I added a task to my gradle project:
task deploy() {
dependsOn "build"
// excludeTask "test" <-- something like this
doFirst {
// ...
}
}
Now the build task always runs before the deploy task. This is fine because the build task has many steps included. Now I want to explicitly disable one of these included tasks.
Usually I disable it from command line with
gradle deploy -x test
How can I exclude the test task programmatically?
You need to configure tasks graph rather than configure the deploy task itself. Here's the piece of code you need:
gradle.taskGraph.whenReady { graph ->
if (graph.hasTask(deploy)) {
test.enabled = false
}
}
WARNING: this will skip the actions defined by the test task, it will NOT skip tasks that test depends on. Thus this is not the same behavior as passing -x test on the command line
I don't know what your deploy task does, but it probably just shouldn't depend on the 'build' task. The 'build' task is a very coarse grained lifecycle task that includes tons of stuff you probably don't want.
Instead it should correctly define its inputs (probably the artifacts that you wanna deploy) and then Gradle will only run the necessary tasks to build those inputs. Then you no longer need any excludes.
I ran into a similar problem. Here is how I prevent "test" from running when I run "intTest" and want the ITs to run alone:
test {
onlyIf { !gradle.startParameter.taskNames.contains("intTest") }
}
An alternative that doesn't depend on certain tasks being run explicitly:
test {
onlyIf { !gradle.taskGraph.hasTask(":intTest") || gradle.taskGraph.hasTask(":check") }
}

Resources