Gradle: Custom task with parameter set programmatically - gradle

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

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

How to wrap an existing Gradle task with parameters into a custom task?

I am trying to create a custom Gradle task which invokes an existing Gradle task with parameters which are specific to my project. Here is how I invoke the task from the command line:
./gradlew downloadJson \
-Pendpoint=http://example.com/foo \
-Pdestination=src/main/com/example/foo.json
I would like to create a downloadFoo task which I can invoke without specifying the parameters explicitely.
tasks.register("downloadFoo" /* type needed? */) {
// What goes here?
}
Related
Create Gradle Tasks that executes other gradle task with parameters
How to pass Custom gradle Task as parameter to another Custom gradle Task
There's no real concept of tasks wrapping other tasks in Gradle...
What you can do in this situation is to just create a new task of type ApolloDownloadSchemaTask, and then set the properties:
import com.apollographql.apollo.gradle.internal.ApolloDownloadSchemaTask
tasks.register("downloadFoo", ApolloDownloadSchemaTask) { task ->
description("Downloads foo.")
group("Apollo")
task.schemaFilePath.set("src/main/com/example/foo.json")
task.endpointUrl.set("http://example.com/foo")
}
Try this form:
tasks.register("downloadBackendSchema", com.apollographql.apollo.gradle.internal.ApolloDownloadSchemaTask) { task ->
description("Downloads Apollo Schema")
group("Apollo")
task.schemaRelativeToProject.set("src/main/java/com/project/backend/grqphql/schema.json")
task.endpoint.set("http://your-project.com/graphql")
}

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 short task

For fust build project I use such command
gradle clean build -x checkstyleMain -x checkstyleTest -x findbugsMain -x findbugsTest -x test
How I can create short task for this?
Something like this
task short {
clean
// build-x checkstyleMain -x checkstyleTest -x findbugsMain -x findbugsTest -x test
}
I have error with -x
UPDATE
I add such
gradle.taskGraph.whenReady {
if (gradle.taskGraph.hasTask(":fastRun")) {
checkstyleMain.enabled = false
checkstyleTest.enabled = false
findbugsMain = fasle
findbugsTest = false
test = false
}
}
task fastRun {
// clean
// build
}
And run
gradle clean build fastRun
But all tasks run =(
Gradle is not lifecycle based the way Maven is. Instead of asking for a task that includes all these other tasks you do not want to do, you are better off finding a task that does what you want without including all these others.
For example, assuming you are using the java plugin:
assemble: will create all archives in the project, but not run any tests or checks
compileTestJava: will compile all main and test Java classes but will not run tests or create binaries. Unless their creation is required by a different project in a multi-project build.
???: some task that maybe does exactly what you want
And if point 3 has no answer for you, you can define a new task that will depend only on what you want to achieve and not the rest.
See the Java plugin documentation for an exhaustive list of the tasks added, including the high level ones.
Unfortunately, usual ways of skipping tasks won't work in your case just out of the box.
But you can use a TaskGraph to check whether your custom task will be executed and if it'll be, disable all the tasks you don't want to be executed. For that, you need to add such a configuration snippet:
gradle.taskGraph.whenReady {
if (gradle.taskGraph.hasTask(":short")) {
checkstyleMain.enabled = false
checkstyleTest.enabled = false
// any other task you want to skip...
}
}
This snippet should be placed into the root of the build skript. Just note, that task names could differ depending on the project structure you have.
It's waiting until the task graph is ready and if it has a task named short (that means, that this task will be executed), then it disables some other tasks.
You can add the following codes to skip the tasks,
gradle.startParameter.excludedTaskNames += "testClasses"
gradle.startParameter.excludedTaskNames += "test"

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