How to pass command to includedproject for build.gradle - gradle

I need to pass command like "build -x test" to included project, how to do it?
any hints will be more than welcome! , currently it is without -x test like below
plugins {
id "com.gradle.build-scan" version "1.6"
}
apply plugin: 'eclipse'
defaultTasks 'build'
//gradle build -Pfast=true
task build{
if(project.findProperty('fast')&&project.findProperty('fast').toLowerCase()=='true') {
println "#### build fast### " + project.findProperty('fast')
gradle.includedBuild('another-project').task(':build')
}else{
println "#### build normally###"
dependsOn gradle.includedBuild('another-project').task(':test')
dependsOn gradle.includedBuild('another-project').task(':build')
}
}
task clean{
dependsOn gradle.includedBuild('another-project').task(':clean')
}
task test{
dependsOn gradle.includedBuild('another-project').task(':clean')
dependsOn gradle.includedBuild('another-project').task(':test')
}

below wordaround will solve my problem
workingDir '../another-project'
commandLine 'gradle', 'build' ,'-x' ,'test'

Related

How do I make a Task depend on the build.gradle itself?

I have the following build.gradle file. Currently the task generateSources runs every time gradle is executed ("BUILD SUCCESSFUL"). I would instead like it to only execute when the build.gradle file itself changes, so that the build is an incremental build ("UP-TO-DATE")
i.e. I want it's "input" to be the "build.gradle" itself.
How do I do this?
apply plugin: 'java'
apply plugin: 'application'
mainClassName = 'Main'
version = "1.0"
task generateSources() {
// inputs = ????
// onlyIf ???
outputs.upToDateWhen { true } // in the real code this is a file
doFirst {
println("Hello, World! $project.version")
}
}
compileJava.dependsOn generateSources
(The code above is simplified to the bare minimum. In reality the task generate some files, and they are configured properly in Task.output)
There are two ways as I know, finalizedBy and dependsOn
The finalizedBy means do this after this task
tasks.named("build") { finalizedBy("myTaskName") }
And the dependsOn means that after build do this task
tasks.named("myTaskName") { dependsOn("build") }
More information about tasks on the official docs
It turns out you can just put an input-dependency on the project file object itself with something like inputs.file project.buildFile.
apply plugin: 'java'
apply plugin: 'application'
mainClassName = 'Main'
version = "1.0"
task generateSources() {
inputs.file project.buildFile // only rebuild when _this_ build.gradle changes
outputs.upToDateWhen { true } // in the real code this is a file
doFirst {
println("Hello, World! $project.version")
}
}
compileJava.dependsOn generateSources

Custom Gradle exec tasks won't run in parallel

My goal is that I can run ./gradlew deployStaging, and it executes buildDockerStatic, and buildDockerBackend in parallel, and after both tasks have finished, the deployStaging will run. With the code below, the tasks run serially. I've tried a few things, but buildDockerStatic, and buildDockerBackend always run serially.
tasks.register("buildDockerStatic", BuildDockerStatic) {
workingDir rootDir
}
tasks.register("buildDockerBackend", BuildDockerBackend) {
workingDir rootDir
}
//noinspection GroovyAssignabilityCheck
task deployStaging() {
dependsOn tasks.buildDockerStatic
dependsOn tasks.buildDockerBackend
doLast {
exec {
workingDir rootDir
commandLine 'sh', './scripts/build_deploy_staging.sh'
}
}
}
class BuildDockerStatic extends AbstractExecTask<BuildDockerStatic> {
BuildDockerStatic() {
//noinspection GroovyAssignabilityCheck
super(BuildDockerStatic)
commandLine 'sh', './scripts/build_static.sh'
}
}
class BuildDockerBackend extends AbstractExecTask<BuildDockerBackend> {
BuildDockerBackend() {
//noinspection GroovyAssignabilityCheck
super(BuildDockerBackend)
commandLine 'sh', './scripts/build_backend.sh'
}
}
In order to be run in parallel, the build tasks need to be placed in sub-projects.
They should contain doLast; otherwise they will be executed when calling eg. gradle clean. And probably, a definition using the plain task {..} will be enough.
Parallel: from the docs at Gradle:parallel execution
By using the --parallel switch, you can force Gradle to execute tasks in parallel as long as those tasks are in different projects.
See a modified example below; it will run two sub-tasks (to sleep and log), in parallel.
It can be run with gradle clean deployStaging --parallel
Multi project structure
build-backend
+--build.gradle
build-static
+--build.gradle
build.gradle
settings.gradle
build-backend/build.gradle :
apply plugin: 'base'
task buildDockerBackend {
doLast{
exec {
println 'BuildDockerBackend: started at ' + new java.util.Date()
workingDir rootDir
sleep 4000
//commandLine 'sh', './scripts/build_backend.sh'
commandLine 'echo', 'task: build-backend'
println 'BuildDockerBackend: done at ' + new java.util.Date()
}
}
}
build-static/build.gradle
apply plugin: 'base'
task buildDockerStatic {
doLast{
exec {
println 'BuildDockerStatic: started at ' + new java.util.Date()
workingDir rootDir
sleep 8000
//commandLine 'sh', './scripts/build_static.sh'
commandLine 'echo', 'task: build-static'
println 'BuildDockerStatic: done at ' + new java.util.Date()
}
}
}
build.gradle
apply plugin: 'base'
task deployStaging {
doLast {
exec {
workingDir rootDir
//commandLine 'sh', './scripts/build_deploy_staging.sh'
commandLine 'echo', 'task: deploy-staging'
}
}
}
deployStaging.dependsOn ':build-static:buildDockerStatic'
deployStaging.dependsOn ':build-backend:buildDockerBackend'
settings.gradle
include 'build-static'
include 'build-backend'

Gradle's mustRunAfter/finalizedBy only for a specific task?

I'm trying to get Gradle's mustRunAfter and finalizedBy to work only for a specific task. Take this example build.gradle:
task removeTestDatabaseContainer {
doLast {
println '\ninside removeTestDatabaseContainer\n'
}
}
task startTestDatabaseContainer {
doLast {
println '\ninside startTestDatabaseContainer\n'
}
finalizedBy removeTestDatabaseContainer
}
task flywayMigrate { t->
doLast {
println '\n inside flywayMigrate\n'
}
}
task flywayClean { t->
doLast {
println '\n inside flywayClean\n'
}
}
task testEverything {
dependsOn startTestDatabaseContainer
dependsOn flywayMigrate
dependsOn flywayClean
flywayMigrate.mustRunAfter startTestDatabaseContainer
flywayMigrate.finalizedBy flywayClean
flywayClean.mustRunAfter flywayMigrate
flywayClean.finalizedBy removeTestDatabaseContainer
}
I'm happy with how testEverything works. I want the output I'm getting from that task:
➜ gradle testEverything
Parallel execution is an incubating feature.
:startTestDatabaseContainer
inside startTestDatabaseContainer
:flywayMigrate
inside flywayMigrate
:flywayClean
inside flywayClean
:removeTestDatabaseContainer
inside removeTestDatabaseContainer
:testEverything
BUILD SUCCESSFUL
Total time: 0.597 secs
However, when I run only flywayMigrate I get unexpected problems. This is the output:
➜ gradle flywayMigrate
Parallel execution is an incubating feature.
:flywayMigrate
inside flywayMigrate
:flywayClean
inside flywayClean
:removeTestDatabaseContainer
inside removeTestDatabaseContainer
BUILD SUCCESSFUL
Total time: 0.605 secs
This is not the output I want. I would like only flywayMigrate to run. Question 1) How can I make testEverything work as it does and at the same time have gradle flywayMigrate invoke only the flywayMigrate-task?
Question 2)
I'm told this has something to do with the fact that everything inside the brackets of task testEverything {} is configuration, which is always processed by Gradle. So any mustRunAfter/finalizedBy I set within a task will have "global effect". But in that case, why doesn't gradle flywayMigrate invoke startTestDatabaseContainer? (Because of the line flywayMigrate.mustRunAfter startTestDatabaseContainer inside the testEverything task.)
Edit: I was directed to Ordering tasks and Finalizer tasks in the Gradle documentation and they answer question 2: mustRunAfter only takes effect when both tasks are ran. finalizedBy on the other hand takes effect when only the task it is set on is ran. That answers why flywayClean and removeTestDatabasContainer are ran when I execute gradle flywayMigrate.
I'm still struggling to make gradle testEverything work as it does above and at the same time get gradle flywayMigrate to just execute flywayMigrate.
Thanks to the help of eskatos on #gradle on Freenode I found a solution. It was simply to remove the finalizedBy-lines i had. Updated build.gradle that works:
task removeTestDatabaseContainer {
doLast {
println '\ninside removeTestDatabaseContainer\n'
}
}
task startTestDatabaseContainer {
doLast {
println '\ninside startTestDatabaseContainer\n'
}
finalizedBy removeTestDatabaseContainer
}
task flywayMigrate { t->
doLast {
println '\n inside flywayMigrate\n'
}
}
task flywayClean { t->
doLast {
println '\n inside flywayClean\n'
}
}
task testEverything {
dependsOn startTestDatabaseContainer
dependsOn flywayMigrate
dependsOn flywayClean
flywayMigrate.mustRunAfter startTestDatabaseContainer
//flywayMigrate.finalizedBy flywayClean
flywayClean.mustRunAfter flywayMigrate
//flywayClean.finalizedBy removeTestDatabaseContainer
}

How should I structure these gradle task dependencies?

I have these gradle tasks:
- startTestDatabaseContainer: builds and starts a docker container with a database
- removeTestDatabaseContainer: stops and removes the docker container
- flywayValidate: a task from org.flywaydb.flyway that validates my migration files
I wish to run these three tasks in order. Reading this leads me to this solution:
flywayValidate.dependsOn startTestDatabaseContainer
flywayValidate.finalizedBy removeTestDatabaseContainer
This works ok, but then I can't run gradle flywayValidate from the commandline without startTestDatabaseContainer and removeTestDatabaseContainer also being invoked. I want to be able to run flywayValidate without that happening.
What can I do to accomplish this when I cannot have ordered dependencies in gradle?
My first attempt was simply:
task validateMigration {
dependsOn startTestDatabaseContainer
dependsOn flywayValidate
finalizedBy removeTestDatabaseContainer
}
But that fails because flywayValidate can run before startTestDatabaseContainer.
Edit: I've setup a demonstration base on Opal's solution here: github.com/stianlagstad/flyway-migration-error-causes-final-gradle-task-to-not-execute. Clone it and run gradle validateMigration. The migration will fail and the final gradle task won't run (and docker ps will show the container still running). If you fix the migration file then everything works as expected. I'm sure I'm misunderstanding something. Any pointers would be helpful!
The following setup should meet all your requirements:
task startTestDatabaseContainer {
doLast {
println 'startTestDatabaseContainer'
}
}
task flywayValidate {
doLast {
println 'flywayValidate'
}
}
task removeTestDatabaseContainer {
doLast {
println 'removeTestDatabaseContainer'
}
}
task validateMigration {
dependsOn startTestDatabaseContainer
dependsOn flywayValidate
flywayValidate.mustRunAfter startTestDatabaseContainer
finalizedBy removeTestDatabaseContainer
}
EDIT
task removeTestDatabaseContainer {
doLast {
println 'removeTestDatabaseContainer'
}
}
task startTestDatabaseContainer {
doLast {
println 'startTestDatabaseContainer'
}
finalizedBy removeTestDatabaseContainer
}
task flywayValidate { t->
doLast {
println 'flywayValidate'
throw new TaskExecutionException(t, new RuntimeException('whatever'))
}
}
task validateMigration {
dependsOn startTestDatabaseContainer
dependsOn flywayValidate
flywayValidate.mustRunAfter startTestDatabaseContainer
}
Here's a demo.
task validateMigration {
dependsOn startTestDatabaseContainer
dependsOn flywayMigrate
flywayMigrate.finalizedBy removeTestDatabaseContainer
flywayMigrate.mustRunAfter startTestDatabaseContainer
}
This did the trick! Thank you orzeh for the PR on Github, and thank you Opal for the help!

Gradle project, sub projects executed repeatedly

I have a project with sub projects. The layout:
rootproj
--subproj1
----mybuild.number
--subproj2
--build.gradle
--gradle.properties
--settings.gradle
mybuild.number
#Build Number for ANT. Do not edit!
#Wed Nov 210 2121:210:2121 PST 2102121
build.number=1
settings.gradle
include ('subproj1', 'subproj2')
build.gradle
allprojects {
repositories {
mavenLocal()
maven {url "http://repo1.maven.org/maven2"}
}
}
subprojects {
project (':subproj1') {
def oldN = new File("D:/rootproj/subproj1/mybuild.number").text.split("=")[1]
def newN = (oldN.toInteger() + 1).toString()
ant.replace(
file: "mybuild.number",
token: "${oldN}",
value: "${newN}"
)
println "From subproj1 : ${newN}"
task hello(overwrite: true){
doLast{
println "hello from subproject 1"
}
}
}
project (':subproj2'){
println "the build Dir: $buildDir"
task hello(overwrite: true){
doLast{
println "hello from subproject 2"
}
}
}
}
when I run
gradle -q subproj1:hello
or
gradle -q subproj2:hello
or
gradle
from the rootproj, I always get e.g.
....
From subproj1 : 24
the build Dir: D:\rootproj\subproj2\build
From subproj1 : 25
the build Dir: D:\rootproj\subproj2\build
1. Why the two sub projects always get executed twice, therefore the build number is incremented twice, instead of once?
2. why all sub projects get executed even though I explicitly specified the project:task in the command line?
I have searched the Internet, could not find useful information.
Thanks for your help in advance.
EDIT:
Change build.gradle as #JB Nizet suggested:
move the ant.replace to task incr
comment out subprojects
It works exactly as I expected.
allprojects {
repositories {
mavenLocal()
maven {url "http://repo1.maven.org/maven2"}
}
}
//subprojects {
def oldN = new File("E:/hqin/build/gradle/rootproj/subproj1/mybuild.number").text.split("=")[1]
def newN = (oldN.toInteger() + 1).toString()
project (':subproj1') {
task incr {
doLast{
ant.replace(
file: "mybuild.number",
token: "${oldN}",
value: "${newN}"
)
}
println "From subproj1 : ${newN}"
}
task hello(overwrite: true, dependsOn: 'incr'){
doLast{
println "hello from subproject 1"
}
}
}
project (':subproj2'){
task hello(overwrite: true){
doLast{
println "the build Dir: $buildDir"
println "hello from subproject 2"
}
}
}
//}
Regarding the second point: because your code is run as part of the project configuration, which is always run, whatever the task being executed. If you want code being executed when a task is executed, then it should be inside the doLast closure of a task definition:
task someTask {
doLast {
...
}
}
Regarding the first point: the closure passed to subprojects is executed for every subproject. So, it's called once for the subproject 1, and configures subproject 1 and subproject 2, then it's called again for subproject 2, and reconfigures subproject 1 and subproject 2 again. You shouldn't have subprojects at all.

Resources