Is there a way to "merge" gradle tasks to avoid many dependsOn declarations - gradle

Suppose this gradle script:
task copyGroovyScript(dependsOn: prepare, type: Copy) {
from "${scriptSrcLocation}/${scriptSrcName}"
into buildFolderZipSource
}
task copyDependenciesForGroovyScript(dependsOn: copyGroovyScript, type: Copy) {
from configurations.groovyScript.resolve()
into "${buildFolderZipSource}/groovy-plugin-lib"
}
task copyTestScripts(dependsOn: copyDependenciesForGroovyScript, type: Copy ) {
from "${scriptSrcLocation}/ReadClient.groovy"
into "${buildFolderZipSource}/test"
}
task copyTestScriptsBin(dependsOn: copyTestScripts, type: Copy ) {
from "${scriptSrcLocation}/bin"
into "${buildFolderZipSource}/test/bin"
}
task copyDependenciesForTestScripts(dependsOn: copyTestScriptsBin, type: Copy) {
from configurations.testScripts.resolve()
into "${buildFolderZipSource}/test/lib"
}
task packageAll(dependsOn: copyDependenciesForTestScripts, type:Zip) {
archiveName "output-${buildTime()}.zip"
excludes ['*.zip']
destinationDir buildFolder
from buildFolder
}
I need different Copy tasks before they have different output folders.
Is there a way to avoid having to have all those dependsOn statements and just have gradle execute things in order of declaration in the file somehow?

There's no way to execute in the way it's declared. But why don't you go this way:
task packageAll(dependsOn: copyDependenciesForTestScripts, type:Zip) {
doFirst {
copy {
from "${scriptSrcLocation}/${scriptSrcName}"
into buildFolderZipSource
}
}
//following doFirst and so on..
archiveName "output-${buildTime()}.zip"
excludes ['*.zip']
destinationDir buildFolder
from buildFolder
}
EDIT
After discussion in comments it turned out that the following piece of code should do the job
task prepare {
doFirst {
copy {
from "${scriptSrcLocation}/${scriptSrcName}"
into buildFolderZipSource
}
}
//following doFirst and so on..
}
task packageAll(dependsOn: prepare, type:Zip) {
archiveName "output-${buildTime()}.zip"
excludes ['*.zip']
destinationDir buildFolder
from buildFolder
}

Related

Using a gradle task generate a properties file to be included in a jar before the jar task is executed

Before is a snippet of my build.gradle, it lists a series of tasks which should ideally be run in the following order:
createPropertiesFile
jar
obfuscate
deleteNonObfuscatedJar
deletePropertiesFile
I need createPropertiesFile to run before jar, as users are building the .jar using ./gradlew jar.
The problem I'm seeing at the moment is this error:
> Could not find method doFirst() for arguments [task ':createAuthenticationPropertiesFile']
on task ':jar' of type org.gradle.api.tasks.bundling.Jar.
I've also tried jar.dependsOn(project.tasks.createAuthenticationPropertiesFile) but I've seen that custom.properties is not included in the generated .jar when using jar.dependsOn
build.gradle:
nonObfuscatedJar = 'appNotObfuscated.jar'
task createPropertiesFile << {
def props = project.file('src/main/resources/custom.properties')
props << 'prop1=value1'
}
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
archiveName = "$nonObfuscatedJar"
from sourceSets.main.output.classesDir
from configurations.compileOnly.asFileTree.files.collect { zipTree(it) }
include '**/*.class'
include '**/custom.properties'
manifest {
attributes 'Main-Class': 'com.bobbyrne01.App'
}
exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
}
task obfuscate(type: proguard.gradle.ProGuardTask) {
configuration 'proguard.txt'
injars "$libsDir/$nonObfuscatedJar"
outjars "$libsDir/app.jar"
libraryjars "${System.getProperty('java.home')}/lib/rt.jar"
}
task deleteNonObfuscatedJar (type: Delete) {
delete "$libsDir/$nonObfuscatedJar"
}
task deletePropertiesFile (type: Delete) {
delete project.file('src/main/resources/custom.properties')
}
jar.doFirst(project.tasks.createPropertiesFile)
jar.finalizedBy(project.tasks.obfuscate)
jar.finalizedBy(project.tasks.deleteNonObfuscatedJar)
jar.finalizedBy(project.tasks.deletePropertiesFile)
As a workaround, move the properties file creation to the start of the jar task:
jar {
// Create properties file
def props = project.file('src/main/resources/custom.properties')
props << 'prop1=value1'
// Build jar
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
archiveName = "$nonObfuscatedJar"
from sourceSets.main.output.classesDir
from configurations.compileOnly.asFileTree.files.collect { zipTree(it) }
include '**/*.class'
include '**/custom.properties'
manifest {
attributes 'Main-Class': 'com.bobbyrne01.App'
}
exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
}

How to ignore dependsOn failure because some subprojects don't have the defined task

I have a multi-project gradle build where not all of the subprojects have the same plugin, but I would like to define tasks in the root build.gradle file like this:
subprojects {
task continuousBuild(dependsOn: ["clean", "check", "jacocoTestReport", "integrationTests"]
}
Not all subprojects have "jacocoTestReport" or "integrationTests" defined, but this task will fail because of that fact. How do I configure this to work, and frankly, why is the default behavior so strict?
This is what ended up working for me:
task continuousBuild(dependsOn: ['clean', 'check']) {
def uncommonTasks = ['jacocoTestReport', 'integrationTests']
dependsOn += tasks
.findAll { uncommonTasks.contains(name) }
}
And I forgot that I actually needed to run integrationTests in a doLast, which looks like this:
task continuousBuild(dependsOn: ['clean', 'check']) {
dependsOn += tasks
.findAll { 'jacocoTestReport' == name) }
if (tasks.findByName('integrationTests')) {
doLast {
integrationTests
}
}
}

Gradle copy task fails silently

I have a copy task for 1 file
task myCopyTask(type: Copy) {
copy {
from "/path/to/my/file"
into "path/to/out/dir"
}
}
How to do, so the task fails if the copy fails? Right now if the file does not exist, it does not give an error.
Fail Gradle Copy task if source directory not exist gives a solution. This does not work, because if everything is not inside of
copy { ... }
the task does not work at all.
I tried also
task myCopyTask(type: Copy) {
copy {
from "/path/to/my/file"
into "path/to/out/dir"
inputs.sourceFiles.stopExecutionIfEmpty()
}
}
The above would fail, as inputs.sourceFiles would be empty.
Why don't you specify your task as:
task myCopyTask(type: Copy) {
from "/path/to/my/file"
into "path/to/out/dir"
inputs.sourceFiles.stopExecutionIfEmpty()
}
This would work as expected during execution phase, while your solution would try to copy something during configuration phase of the build every time you call any task.
The very first definition of the tasks actually doesn't do what you expect from the task:
task myCopyTask(type: Copy) {
copy {
from "/path/to/my/file"
into "path/to/out/dir"
}
is acutually same as
task myCopyTask(type: Copy) {
project.copy {
from "/path/to/my/file"
into "path/to/out/dir"
}
}
And it will execute copy action during task configuration, no matter if the task is called or not.
What you need is:
task myCopyTask(type: Copy) {
from "/path/to/my/file"
into "path/to/out/dir"
doFirst {
if(inputs.empty) throw new GradleException("Input source for myCopyTask doesn't exist")
}
}
This solution for Kotlin DSL works for me:
tasks.register<Copy>("myCopyTask") {
val path = "/path/to/my/file"
from(path)
into("path/to/out/dir")
if (inputs.sourceFiles.isEmpty) {
throw GradleException("File not found: $path")
}
}

Execute one gradle task

I've this two tasks:
war {
webInf { from 'src/main/resources/WEB-INF' }
manifest {
attributes 'Implementation-Version': versioning.info.display
}
}
task createDemoWar(type: War, dependsOn: classes) {
archiveName "webapi-demo-${versioning.info.display}.war"
destinationDir = file("$buildDir/dist")
copy {
from 'scopes'
include 'configuration.demo.properties'
into 'src/main/resources/'
}
}
task createDevelopmentWar(type: War, dependsOn: classes) {
archiveName "webapi-dev-${versioning.info.display}.war"
destinationDir = file("$buildDir/dist")
copy {
from 'scopes/'
include 'configuration.development.properties'
into 'src/main/resources/'
}
}
Both tasks are trying to copy a property file fromscopes folder to src/main/resources/ folder.
I only run one task, however two files are copied in src/main/resources/ (configuration.demo.properties and configuration.development,properties.
Any ideas?
You use two copy specifications at the configuration phase (note, copy specification in that case doesn't configure your task, but add some extra action to it's configuration). That means, your files are getting copied during configuration. That's all because of this:
copy {
...
}
You have to run it during execution, to do that, try to move it into the doLast or doFirst closure, like so (for both tasks):
task createDemoWar(type: War, dependsOn: classes) {
archiveName "webapi-demo-${versioning.info.display}.war"
destinationDir = file("$buildDir/dist")
doFirst {
copy {
from 'scopes'
include 'configuration.demo.properties'
into 'src/main/resources/'
}
}
}
In that case, files will be copied only if task will be executed, right before the execution.

Change copy task destination

I would like to change the destination dir for file copy depending on the chosen build.
This does not work since the task graph is executed in execution phase but the copyTask is set in configuration phase.
How can I achieve this?
gradle.taskGraph.whenReady { taskGraph ->
println('taskGraph')
if (taskGraph.hasTask(buildRelease)){
File toDir=file('test/r')
println('Copy to: ' + toDir.getName())
}else if (taskGraph.hasTask(buildDevel)) {
File toDir=file('test/d')
println('Copy to: ' + toDir.getName())
}
}
task buildDevel (dependsOn: ['copyTask']){}
task buildRelease (dependsOn: ['copyTask']){}
task copyTask(type: Copy) {
from "test"
into toDir
include 'a.txt'
}
This may help You (You need to create a.txt file on the same level as build.gradle is located:
gradle.taskGraph.whenReady { taskGraph ->
def cp = project.copyTask
if (taskGraph.hasTask(buildRelease)){
cp.into 'lol1'
} else if (taskGraph.hasTask(buildDevel)) {
cp.into 'lol2'
}
}
task buildDevel (dependsOn: ['copyTask']){}
task buildRelease (dependsOn: ['copyTask']){}
task copyTask(type: Copy) {
from file('.')
include 'a.txt'
}
This will also work:
task buildDevel
task buildRelease
buildDevel.doFirst {
cp('lol1')
}
buildRelease.doFirst {
cp('lol2')
}
def cp(to) {
copy {
from file('.')
into to
include 'a.txt'
}
}

Resources