Call Zip Task Multiple Times In Gradle - gradle

I need to update 9 zip files and the code to do it is about 15 lines.
I'd rather not have to repeat the same 15 lines 9 times in the build script with just different variable names.
Is it possible to call a Zip task in a loop from another task?
Using dynamic tasks seems to be one way but it requires me to list the array of tasks twice which I can see causing an error in future when an extra item is added.
[war1, war2, war3, war4, war5, war6, war7, war8, war9].each { warName ->
task "task$warName"(type: Zip) {
archiveName = "${warName}.war"
//etc etc
}
}
task all(dependsOn: [taskwar1, taskwar2, taskwar3, taskwar4, taskwar5, taskwar6, taskwar7, taskwar8, taskwar9]) {
}
Is there any alternative?

Firs of all your code might be simplified just to:
task allWars
(1..9).each { id ->
task "taskwar${id}"(type: Zip) {
archiveName = "war${id}.war"
}
allWars.dependsOn "taskwar${id}"
}
And a solution with task rules:
tasks.addRule('Pattern: taskwar<ID>') { String taskName ->
if (taskName.startsWith('taskwar')) {
task(taskName, type: Zip) {
archiveName = "${taskName - 'task'}.war"
}
}
}
task allWars {
dependsOn << (1..9).collect { "taskwar$it" }
}
There are almost no obvious pros and cons - when it comes to functionality. Basically solution without rules is shorter as you can see, so if you represent attitude less code is better that's the way to go. However task rules were created in gradle for this kind of situations - where there are lots of predefined tasks. First solution is more groovier while the second one is more gradler ;)

One way is to store the list of 'war' names in a ext property and then iterate over it to create the tasks and use a mapping function for defining the dependencies for the all task.
// Define the variables here
ext.warTaskPrefix = "task"
ext.warNames = ["war1", "war2", "war3", "war4", "war5", "war6", "war7", "war8", "war9"]
// Define the war task dynamically
warNames.each { warName ->
task "${warTaskPrefix}${warName}"(type: Zip) {
archiveName = "${warName}.war"
//etc etc
}
}
// Define the task that depends on all war tasks
task all(dependsOn: warNames.collect{ warName -> "${warTaskPrefix}${warName}" }) {
}

Related

Gradle exclude resources for one task but not for second

Is it possible to exclude resources for a task, but do not exclude them for a second task? Both are triggered from a third task like this:
task createBoth {
dependsOn = [createFirst, createSecond]
}
task createFirst {
sourceSets.main.resources.excludes = ['**/images']
}
task createSecond {
sourceSets.main.resources.excludes = []
}
I tried to exclude in doFirst{} method, but it did not work. If run as a single task then it works fine. Both results are the same version of my Java project. Except they have a different main class and one does not need all images. So I want to create both files in a single run. Is it even possible?
Attempt 2:
task createSystemcheckJar(type: OneJar) {
exclude('**/images/ads/images') // And some ohter combinations with stars
}
Same problem.

Set the properties in the configuration phase of a task in another task

I have spent the last few hours trying to find a solution for my requirement, without luck:
I have a task that has to run some logic in a certain path:
task run(type: MyPlugin) {
pathForPlugin = myPath //Defined as a property in another gradle file
}
I want to set the "pathForPlugin" property dynamically in another task because it has to be read from some configuration file.
task initPaths(type: PathFinder) {
configurationFile = 'C:\\myConfig.conf'
}
The myConfig.conf would look like this:
pathForPlugin = 'C:\\Correct\\Path'
The problem is that "initPaths" has to run before the configuration phase of "run".
I have tried several approaches for this (GradleBuild task, dependsOn, Using Properties in the Plugin for "Lazy Configuration") but every approach only takes effect in the Execution phase leading to the "pathForPlugin" always staying at its default value.
Is there some way i can realize this or should i look for another solution outside of the gradle build?
I found a solution for the problem:
Instead of defining a task "initPaths" i directly used the java class "Pathfinder" in the build script:
import mypackage.PathFinder;
new PathFinder(project).run()
You only have to make sure that this part is above the definition of the task where the properties are used.
I admit this is a bit of a "hacky" solution but it works fine for my requirement.
you can do like this:
ext {
myPath //use it as a global variable that you can set and get from different gradle tasks and files
}
task firstTask {
doLast {
ext.myPath = "your path"
}
}
task run(type: MyPlugin) {
doFirst { //executed on runtime not on task definition
pathForPlugin = ext.myPath //Defined as a property in another gradle file
}
}
//example 2 - create run task dynamic
task initPath {
doLast {
tasks.create(name: "run", type: MyPlugin) {
pathForPlugin = ext.myPath
}
}
}

How to make Gradle run tasks in certain order?

Let's say that I have created separate tasks for running integration and acceptance tests in my gradle build script. When I run the build task I want to run testing tasks before in this order: unit tests(test task), integration tests (intergationTest task) and acceptance tests (acceptanceTest task). Is this possible and how?
You are looking for "should run after" described in Gradle documentation - http://www.gradle.org/docs/current/userguide/more_about_tasks.html
Here's how you can do it without creating artificial dependencies:
https://caffeineinduced.wordpress.com/2015/01/25/run-a-list-of-gradle-tasks-in-specific-order/
TLDR; version:
//--- build aliases : define a synonym here if you want a shortcut to run multiple targets
def buildAliases = [
'all' : ['clean', 'assemble', 'runProvisioner', 'stopTomcat', 'installTomcat', 'deployToTomcat', 'startTomcat'],
'rebuild' : ['clean', 'assemble']
]
def expandedTaskList = []
gradle.startParameter.taskNames.each {
expandedTaskList << (buildAliases[it] ? buildAliases[it] : it)
}
gradle.startParameter.taskNames = expandedTaskList.flatten()
println "\n\n\texpanded task list: ${gradle.startParameter.taskNames }\n\n"
This is what I did on my projects.
check.dependsOn integTest
integTest.mustRunAfter test
tasks.withType(Pmd) {
mustRunAfter integTest // Pointing to a task
}
tasks.withType(FindBugs) {
mustRunAfter tasks.withType(Pmd) // Pointing to a group of tasks under Pmd
}
tasks.withType(Checkstyle) {
mustRunAfter tasks.withType(FindBugs)
}
It helped me to order tasks by group.
I created this helper method based on a solution that I found on Gradle forum.
Task.metaClass.runFirst = { Task... others ->
delegate.dependsOn(others)
delegate.mustRunAfter(others[0])
for (def i=0; i < others.size() - 1; i++) {
def before = others[i]
def after = others[i+1]
after.mustRunAfter(before)
}
}
Then you can create tasks X, A, B and C and use like this:
X.runFirst A, B, C
The first answer in the list turned out to be great for me. I used
X.shouldRunAfter Y
UPDATE: While using this "solution" for a short while i found out, that it does not work 100% as intended. I don't know why though. Any help to make it work would be appreciated. Maybe it does not work properly when there is more than one task in the Set?! While testing i did add some dummy-Tasks which only printed a text inbetween each of the other tasks and all seemed to be ok.
After some attempts with other solutions i came up with this solution:
It uses the mustRunAfter command to chain Sets of Tasks into the required order.
I'm working with Sets instead of individual Tasks, because i got circular dependency issues otherwise, since some tasks already depended on each other.
Also important to note: the isNotEmpty() check was essential, as it would otherwise break the enforced ordering if an ampty set was passed to the method.
tasks.register("cleanAndGenerate") {
var lastTasks: Set<Task> = setOf()
fun findTasks(taskName: String): Set<Task> {
return if (taskName.startsWith(":")) { // task in specific sub-project
setOf(tasks.findByPath(taskName)!!)
} else { // tasks in all (sub-)projects
getTasksByName(taskName, true)
}
}
fun dependsOnSequential(taskName: String) {
val tasks = findTasks(taskName)
tasks.forEach { task -> task.mustRunAfter(lastTasks) }
dependsOn(tasks)
if (tasks.isNotEmpty()) {
lastTasks = tasks
}
}
dependsOnSequential(":project1:clean") // task in specific sub-project
dependsOnSequential(":project2:clean")
dependsOnSequential("task1") // tasks in all (sub-)projects
dependsOnSequential("task2")
// add more as needed
}

any way to write more concise gradle?

I do not know groovy well enough yet and just trying to get by right now. I have the following gradle working right now but am wondering if there is a more concise way to write it:
task staging(type: Sync) {
from(stagingDir) {}
into toStagingDir
}
task syncJars(type: Sync) {
from(configurations.compile) {}
from(fixedLibDir) {}
into toStagingLibsDir
}
task copyMainJar(type: Copy) {
from(libsDir) {}
into toStagingLibsDir
}
task myZip(type: Zip) {
archiveName "bacnet.zip"
from(buildDir) {
include project.name+'/**'
}
}
syncJars.dependsOn('staging')
copyMainJar.dependsOn('syncJars')
myZip.dependsOn('copyMainJar')
assemble.dependsOn('myZip')
Perhaps there is someway to write it like this:
task prepareStaging {
staging from stagingDir into toStagingDir
syncJars from configurations.compile from fixedLibDir into toStagingLibsDir
copyMainJar from libsDir into toStagingLibsDir
myZip archiveName "bacnet.zip" from buildDir { include project.name+'/**' }
}
assemble.dependsOn('prepareStaging')
Ideally, I LOVE self-documenting code. In this second example, it is obvious to the next developer I mean each of those small tasks to NOT be re-usable. This is very clear(ie. self-documenting). In the first way I wrote the code that is definitely not clear as those tasks could be re-used from other project files.
Any way to write it in that simpler form?
NOTE: I still want all the UP-TO-DATE checks to happen as well as usual though!!!
If I understood correctly, and toStagingDir and toStagingLibDir are just temporary directories that are created under the buildDir directory (in myZip task), then below should do an equivalent job to yours:
task myZip(type: Zip){
archiveName "bacnet.zip"
into('staging'){
from stagingDir
}
into('staging/libs'){
from fixedLibDir
from configurations.compile
from libsDir
//or this, if you just want to include current projects jars
from jar.outputs.files
}
}
The idea here is not to create a temporary directory yourself, but let gradle do it for you.
As long as you dont call cleanMyZip it will do UP-TO-DATE checks and do the bare minimum. Last time I checked Zip behaved much like Sync, in that it would remove any files from the zip that are no longer present in the source. This may behave slightly differently to copyMainJar task, because it's of type Copy which means if you ever delete a file from libsDir then in my case it would disappear from the zip, but in your code it will not.
Don't know if this is even close to what you're asking, but hope it's at least of a little use:)
Elaboration:
Tasks in gradle are always public by design AFAIK. There is an enhancement request but without much action around it. You can use standard groovy methods, which support private visibility, but they aren't as powerful as tasks. Although, you'll find that tasks can depend on groovy functions and more (or anything with call() method), so you can do stuff like:
def function = {
println "function here!"
}
task myTask(dependsOn: function) << {
println "myTask here!"
}
will generate:
function here!
:a:myTask
myTask here!
This should give you some flexibility, but if you really really really need an private task you can do some dirty hacking (I know Gradle guys will hate me for this xx;) ... here it is:
//Create a factory for creating tasks
import org.gradle.api.internal.project.taskfactory.ITaskFactory
def taskFactory = project.services.get(ITaskFactory)
//You can use the factory to create tasks without adding them to
//project.tasks, which will make them invisible to most irrelevant
//parts of your code, and they will not come up in `gradle tasks` list:
//Equivalent of:
// task myTask << {
// println "i'm invisible"
// }
def privateTask = taskFactory.createTask([name: 'myTask']).doLast {
println "i'm invisible"
}
//Equivalent of:
// task myCopyTask(type: Copy){
// from configurations.compile
// into 'libs'
// }
def privateCopyTask = taskFactory.createTask([name: 'myCopyTask', type: Copy])
.configure {
from configurations.compile
into 'lib-test'
}
//You can depend on the above tasks as usual from your public tasks:
task publicTask(dependsOn: [privateTask, privateCopyTask]) << {
println "I'm public task"
}
Note: Seems to work in Gradle 1.2, but use at your own risk!
Good luck!

Custom conditional configuration for Gradle project

Having an extract from https://github.com/gradle/gradle/blob/master/build.gradle:
ext {
isDevBuild = {
gradle.taskGraph.hasTask(developerBuild)
}
}
task developerBuild {
description = 'Builds distributions and runs pre-checkin checks'
group = 'build'
dependsOn testedDists
}
When I used this approach to create custom configuration in my project I discovered that:
isDevBuild === true
i.e. it's always true because task 'developerBuild' is inside my build.gradle project, and hence in graph. They have a couple of "different" configs (isCIBuild, isCommitBuild, isFinalReleaseBuild, ...) so I suppose I got something wrong here.
Can someone explain how to make this configs conditional based on some external parameter?
taskGraph.hasTask() tells if a task is in the task execution graph, that is whether it will get executed. Because the task execution graph is only created after the configuration phase, this method has to be called from a whenReady callback (or in the execution phase):
gradle.taskGraph.whenReady { graph ->
if (graph.hasTask(developerBuild)) {
// do conditional configuration
}
}
To make this more readable, we can introduce a new method:
def onlyFor(task, config) {
gradle.taskGraph.whenReady { graph ->
if (graph.hasTask(task)) {
project.configure(project, config)
}
}
}
Now we can write:
onlyFor(developerBuild) { ... }
onlyFor(ciBuild) { ... }
Another, simpler way to solve this problem is to check whether a particular task name is contained in gradle.startParameter.taskNames. However, this has two limitations: First, it compares task names, which can make a difference in multi-project builds. Second, it will only find tasks that have been specified directly (e.g. on the command line), but not dependencies thereof.
PS.: In your code, isDevBuild always holds because a (non-null) closure is true according to Groovy truth. (In contrast to isDevBuild(), isDevBuild won't call the closure.)

Resources