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

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.

Related

Gradle execute task while another task is running

I'm working in a spring boot project to automate integration tests with gradle. I started working recently in a new enterprise, and my colleagues run integration tests as follows:
In the build.gradle file there is an integrationTest task
sourceSets {
integrationTest {
java {
compileClasspath = test.output + main.output + compileClasspath
runtimeClasspath = test.output + main.output + runtimeClasspath
}
resources.srcDir file('src/test/resources')
}
}
configurations {
mapstruct
integrationTestCompile.extendsFrom testCompile
integrationTestRuntime.extendsFrom testRuntime
}
compileJava {
options.compilerArgs = [
'-Amapstruct.defaultComponentModel=spring'
]
}
test {
ignoreFailures = true
}
task integrationTest(type: JavaExec) {
classpath = sourceSets.integrationTest.runtimeClasspath
}
After launching the task the application starts running in a designated port, then they open postman, import a collection and run the tests.
My job is to find a way to skip the extra clicks, i.e. run the postman collections automatically.
The first idea was to use the postman-runner gradle plugin but I cannot add it to the project due to connectivity issues of enterprise computers.
The second idea which I am currently working on, is to run newman on a powershell script and save the output.
The problem is that in gradle you can execute a task once another task is finished, but the integrationTest task never finishes. It launches the application in a port and keeps listening for requests. Is there a way to run the other task, which executes the powershell script, after the application has started running on the port and while it is waiting for requests ?
Thank you!
Simple answer: By design, it is not possible in Gradle to execute a task while another task is still running.
However, there might still be a solution for your problem. A task in Gradle is just a concept of something that needs to be done as a part of your build. But it does not necessarily represent a single process. Gradle might run a process using two tasks, one to start the process and another one to stop the process. The following Gradle "pseudo-code" shows an example of this idea.
def process
task start {
doFirst {
process = startProcess()
}
finalizedBy 'stop'
}
task stop {
dependsOn 'start'
doFirst {
process.stop()
}
}
This example even uses Gradle functionality to ensure that each time start is executed, stop will be executed later on and vice-versa. The Gradle Docker plugin uses a similar concept with its task types DockerStartContainer and DockerStopContainer.
Regarding your use case, you could use one task to start the application listening to a port, another task that runs the actual tests (using Postman) and another task that stops the application once the tests are finished:
task startApp {
doFirst {
println 'Starting app'
}
finalizedBy 'stopApp'
}
task integrationTest {
doFirst {
println 'Running integration tests'
}
dependsOn 'startApp'
finalizedBy 'stopApp'
}
task stopApp {
doFirst {
println 'Stopping app'
}
dependsOn 'startApp'
}
This second example is a valid build.gradle file that may be used as a template. When running gradle integrationTest, you will see that the tasks are executed in the correct order. Now all that is missing is the actual functionality of the tasks. Sadly, the JavaExec task type provided by Gradle does not support this kind of async execution, so you might need a third-party plugin or create your own task type (maybe based on ProcessBuilder). You might even wrap your application in a Docker container and use the plugin mentioned above.

How to call Gradle task execution from outside task?

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
}

Gradle : UP-TO-DATE task

I have task 'compileProfileObj' which mainly has to create a jar file.
Even in fresh environment setup, gradle logs outputs 'UP-TO-DATE' for this.
task compileProfileObj(type: JavaCompile, dependsOn: [generateArtifacts]) {
classpath = configurations.deployment
source fileTree(
dir: "${objDir}/app",
includes: ['com/main/**'])
destinationDir file("${proDir}/profileobjects-biz.jar")
doLast {
copy {
from "${objDir}"
include '*.xml'
exclude 'server.xml'
into "${proDir}/profileobjects-biz.jar/META-INF"
}
copy {
from "${objDir}/profileobjects"
into "${proDir}/profileobjects-biz.jar/META-INF"
}
}
}
I understand the gradle doesnot executed tasks in some cases if the tasks has successfully executed in previous build runs.
But in my case even in 1st run gradle doesn't execute this task and prints 'UP-TO-DATE'
Googling didnt help me much here.
Any suggestions in what scenarios this might happen will be really helpful.

Passing conflicting parameters in gradle - which one will be used?

Let's say we are trying to run gradle task with some additional parameters.
For example:
./gradlew -Pfeature=true -Pfeature=false
Which one of those properties will be passed to build?
I made an experiment using simple gradle task
task printProps {
doLast {
println props
}
}
I've run it twice:
./gradlew printProps -Pprops=false -Pprops=true -> true
./gradlew printProps -Pprops=true -Pprops=false -> false
So gradle uses the last parameter passed.

Gradle task not executed if added as a dependency

I have two gradle tasks in my build.gradle file, one to archive a folder and another to push it to a remote server.
task tarTask(type: Exec) {
commandLine 'tar', '-czf', 'javadocs.tgz', 'javadocs/'
}
If I execute tarTask alone with gradle tarTask and with the publish task commented out, the build succeeds.
I am using this task as a dependency in the publish task.
task publish(dependsOn: tarTask) {
ssh.run {
settings {
knownHosts = allowAnyHosts
fileTransfer = 'scp'
}
session(remotes.webServer) {
from: 'javadocs.tgz', into: 'publishingHouse/'
}
}
}
But when i execute gradle publish it fails saying that it is not able to find the tgz file which should have been created if the previous task is executed.
java.io.FileNotFoundException: javadocs.tgz
Being new to gradle i am not really sure what I am missing here. Any ideas on what I can do?
I suppose the reason is within the phase when tasks are executed. tarTask is configured at the configuration phase and will be executed at the execution phase.
And at the same time publish task doesn't have any behavior to execute at the execution phase, but has ssh.run to be executed during configuration.
This mean, that when you run gradle publish your logic to copy tar-archive is executed at the configuration phase, while tar-archive is not yet exists (it will be created later at the execution phase).
To make a copy execution at the execution phase you can simply add << to the publish task declaration as follows:
task publish(dependsOn: tarTask) << {
ssh.run {
settings {
knownHosts = allowAnyHosts
fileTransfer = 'scp'
}
session(remotes.webServer) {
from: 'javadocs.tgz', into: 'publishingHouse/'
}
}
}
Note, that << is the same as doLast and the closure will be excuted at the execution phase. You can read about Gradle build lifecycle here

Resources