gradle custom task that depends on build task without testing - gradle

I am using gradle 6.0.1
I am trying to write my on task, but I want first the the build task is executed but without tests.
I tried (from build.gradle):
task startEnv(type: GradleBuild) {
tasks = ['build']
doLast {
// START ENV CODE
}
}
However, I don't manage to find a way to call build without running tests, as I would run
gradle build -x test
Is it possible to achieve this functionality?
Another option I can use, is to check inside my startEnv task whether build already exists and run this task only if build exists - Is there a way to query whether build exists? (this is a multi module projects, so I am not sure it is enough to check whether build directory exists on the root project).
I followed the comments and tried the solution mentioned at Skip a task when running another task
I added to build.gradle:
gradle.taskGraph.whenReady { graph ->
if (graph.hasTask(startEnv)) {
println("DEBUG1")
test.enabled = false
}
}
task startEnv(type: GradleBuild) {
tasks = ['build']
doLast {
// START ENV CODE
}
}
But when I run ./gradlew startEnv - it still fails with some tests that in current phase I know they should fail.
I can see the DEBUG1 print when I execute this command but the build fails with tests that are failing.
Thank you,

Related

Gradle disable automatic subproject execution for specific task

I have a multi-project Gradle build and I customised the "run" task to do something a bit different in the root project.
However, I don't want it to call the "run" task of each sub-project after completion, as it does now. But this behaviour should only be for this task, I want every other task to be recursively executed as is the default, but the run task not. I also cannot disable the run task globally for every subproject, because it does have a purpose in each subproject when executed on its own.
In the root build.gradle, consider the following (full example here):
gradle.taskGraph.whenReady { graph ->
def hasRootRunTask = graph.hasTask(':run')
if (hasRootRunTask) {
graph.getAllTasks().each { task ->
// look for :abc:run, :def:run etc
def subRunTask = (task.path =~ /:.+:run/)
if (subRunTask) {
println "TRACER skipping ${task.path} because ':run' was specified"
task.enabled = false
}
}
}
}
This will check the task graph for :run. When it exists, then :abc:run (that is, a subproject task) will be disabled.
Example output for root run task:
$ gradle -q run
TRACER skipping :abc:run because ':run' was specified
TRACER skipping :def:run because ':run' was specified
TRACER executing run for path :
Example output for run task in abc subproject on its own:
$ gradle -q :abc:run
TRACER executing run for path :abc

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"

Gradle Run Task Even If Build Fails

So I'm trying to print some stuff to the console in Gradle even if the build fails. How can I do this?
I've found build.finalizedBy(taskName) but that only runs if the build finishes normally.
You can let any build continue on task failures by using the --continue parameter on Gradle invocation. If you do not want to type this parameter all the time you can use the following code in your settings.gradle:
startParameter.continueOnFailure = true
Please note that other tasks may fail due to an earlier task that failed. Using this option, tasks connected via finalizedBy will be executed, but you should only use this option if the tasks are related, even for non-failure cases.
Of course, you can also use lifecycle listeners of the Gradle object or its TaskExecutionGraph. You can use
afterTask
a full TaskExecutionListener implementation
buildFinished (for the whole build)
You can use either gradle.buildFinished or a finalizer task (as you mentioned).
In your example, build.finalizedBy(taskName) will only execute taskName if the build task executes. If the build fails before the build task executes, taskName won't be executed.
e.g., this prints a message based on the result of the build:
gradle.buildFinished { result ->
if (result.failure) {
logger.lifecycle("build failed")
} else {
logger.lifecycle("build successful")
}
}

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