Gradle embedded Project - gradle

Is it possible to embed multiple projects in a single build.gradle?
Something along the lines of:
project projX {
task a << {
}
}
project projY {
task a << {
}
}
Both within the same build.gradle. Is this possible?
I am asking this because I have multiple projects with equivalent task names which I want to execute from the root project, e.g.
gradle a
However the projects contain only automation tasks, which require no source files or resource files at all. Creating subdirectories just for the build.gradle files to be stored seems very ugly to me.
I could live with a solution with different .gradle files for each project, such as: build.gradle (root)
projA.gradle, projB.gradle within the same directory, however embedding project objects in the root build.gradle seems like the better option, if it is available.

project(":projX") { ... }
project(":projY") { ... }
Note that you still need a settings.gradle.
PS: It's not clear to me why you would want multiple projects in your case.

Related

How to copy files between sub-projects in Gradle

How can I make a sub-project copy a file that is produced by a sibling sub-project? All this with proper dependency management, and without assuming that any language-specific plugins (like the JavaPlugin) are used.
I have looked at the updated Gradle 6 draft Sharing artifacts between projects but it does not really answer that question.
My multi-project structure is something like:
top/
build.gradle
settings.gradle
producer/
build.gradle
myFile_template.txt
consumer/
build.gradle
I want a Copy-task in producer/build.gradle to copy+transform myFile_template.txt into $buildDir/target/myFile.txt and another Copy-task in consumer/build.gradle should further copy+transform that myFile.txt to a finalFile.txt.
Presumably a proper solution would be able to use task outputs.files or some such so that consumer/build.gradle does not need to explicitly mention the location of $buildDir/target/myFile.txt.
(I'm completely new to Gradle).
Gradle gives you lots of freedom but I prefer that projects only "share" with each other by Configurations and/or Artifacts. I feel that one project should never concern itself with another project's tasks and feel that the tasks are private to each project.
With this principle in mind you could do something like
project(':producer') {
configurations {
transformed
}
task transformTemplate(type: Copy) {
from 'src/main/template'
into "$buildDir/transformed"
filter(...) // transformation goes here
}
dependencies {
// file collection derived from a task.
// Any task which uses this as a task input will depend on the transformTemplate task
transformed files(transformTemplate)
}
}
project(':consumer') {
configurations {
producerTransformed
}
dependencies {
producerTransformed project(path: ':producer', configuration: 'transformed')
}
task transformProducer(type:Copy) {
from configurations.producerTransformed // this will create a task dependency
into ...
filter ...
}
}

Collect files in build directory of parent project

I have a multi-module project in Gradle
root
-- ProjectA
-- ProjectB
Both ProjectA and ProjectB use the application plugin to create a zip in "ProjectA/build/distributions" and "ProjectB/build/distributions" respectively.
Now I want to copy the two zip files into "root/build/distributions".
I have tried various approaches, e.g. adding this in the build.gradle of the root project:
subprojects {
task copyFiles(type: Copy) {
includeEmptyDirs = true
from "$buildDir/distributions"
include '*.zip'
into "$parent.buildDir/distributions"
}
copyFiles.dependsOn(build)
}
or just adding a task to the root project:
task copyFiles(type: Copy) {
from "ProjectA/build/distributions"
from "ProjectB/build/distributions"
include "*.zip"
into "$buildDir/distributions"
}
build.dependsOn(copyFiles)
However, in both cases, nothing happens. No file gets copied.
What am I doing wrong?
I can see two things you are doing wrong:
You have relative paths to the subprojects. This is discouraged as it means you will always have to invoke Gradle from the root folder. And if a Gradle daemon was started from somehere else, it will fail. You could fix it by using the rootDir property (e.g. `from "$rootDir/ProjectA/...") but there is a better way...
The other problem is that you have no dependencies from your copyFiles task in your root project to the required distZip tasks in the sub-projects. So if the distributions have not already been built previously, there are no guarantees that it will work (which it apparently doesn't).
To fix it, you can have a look at the question "Referencing the outputs of a task in another project in Gradle", which covers the more general use case of what you ask. There are currently two answers, both of which are good.
So in your case, you can probably do either this:
task copyFiles(type: Copy) {
from tasks.getByPath(":ProjectA:distZip").outputs
from tasks.getByPath(":ProjectB:distZip").outputs
into "$buildDir/distributions"
}
or this:
task copyFiles(type: Copy) {
subprojects {
from(tasks.withType(Zip)) {
include "*.zip"
}
}
into "$buildDir/distributions"
}
Gradle will implicitly make the copy task depend on the other tasks automatically, so you don't need to do that yourself.
Also note that the currently accepted answer to the question I referenced is about configuration variants, and this is probably the most correct way to model the relationships (see here for more documentation on the topic). But I prefer the simplicity of the direct access to the tasks over the verbose and arguably more complex way to model it through configurations. Let's hope it gets simpler in a later release.

Gradle replacing Maven assembly plugin

I'm fairly new to Gradle, and trying to port an existing Maven pom.xml that makes extensive use of maven-assembly-plugin to create various zip files.
In the example below, I'm getting files from various subdirectories (with particular extensions), and then mapping them in a flat structure to a ZIP file.
task batchZip(type: Zip) {
from fileTree('src/main/sas') {
include('**/*.sas')
include('**/*.ds')
}.files
}
This puts all the files in the root of the zip. What I ideally need though, is for the files to live under a particular path in the root of the zip, e.g. /shared/sas.
Is there a way to do this without first copying all the files to a local directory and then zipping that up?
task batchZip(type: Zip) {
into('shared/sas') {
from { fileTree('src/main/sas').files }
include('**/*.sas')
include('**/*.ds')
}
}
Have a look at the docs. It seems that if You specify appropriate into You'll get the result You're looking for.

How to add more files to be copied by Sync task, but only for one project

I have a multi project build with one root project and many sub-projects.
In the root configuration I have many task in common for all sub-projects.
I would like to extend one of them, only for a specific subproject
task distrib_bin(type: Sync) {
into "$buildDir/custom-distrib"
from '../bin-dist'
}
For that project (for example project 'broker') I need to add some files to the previous Sync task.
I tried with project.ext properties but I think I'm very far from the solution.
Thanks for all your help
In your subproject build file simply say:
distrib_bin {
from ... //whatever files you need to add here
}
It will allow you add more configuration to the task.

Copying Files From One Zip File Into Another In Gradle

We are working on migrating to Gradle from Maven. Unfortunately we still have a couple of War overlays to deal with.
As a work-around I am trying to copy the contents of one war file into another.
This is what I have so far:
task overlayWars (dependsOn: war) << {
// Get the source war files to copy the contents from...
def dependencyWars = configurations.runtime.filter { it.name.endsWith ('.war') }
dependencyWars.each { dependentWar ->
// Get the products, ie the target war file...
war.outputs.files.each { product ->
println "Copying $dependentWar contents into $product"
copy {
from { zipTree (dependentWar) }
into { zipTree (product)} // this seems to be the problem
include 'WEB-INF/classes/**/*.class'
include 'WEB-INF/jsp/**/*.jsp'
}
}
}
}
When into { zipTree (product)} is a file (like file ('tmp/whatever')) this works fine. When specifying another zip file (the target war file) it fails with the error:
Converting class
org.gradle.api.internal.file.collections.FileTreeAdapter to File using
toString() method has been deprecated and is scheduled to be removed
in Gradle 2.0. Please use java.io.File, java.lang.String,
java.net.URL, or java.net.URI instead.
If anyone has suggestions on this specifically, or a better way to "overlay" war files, I'd really appreciate it!
After chasing down a couple of different angles, I ended up with this:
war {
configurations.runtime.filter { it.name.endsWith ('.war') }.each {
from zipTree (it).matching {
include 'WEB-INF/classes/**/*.class'
include 'WEB-INF/jsp/**/*.jsp'
include 'images/**'
}
}
}
Basically I am just including filtered contents of any .war dependencies in the product. Being an alteration to the standard war task, the dependency tree is kept clean. It seems to work for us so far...
In case you are trying to merge Wars here, you can't do that with a Copy task/method. You'll have to use a Zip task (there is no equivalent method). In case you want to merge into an existing War, the way to do this is existingWar.from { zipTree(otherWar) }.

Resources