I have a multi-project build and in the root project I want to write a Zip-type task which will gather files from sub-projects (the same set of files from each subproject) and then put them into a zip file within the root project. The only way I’ve been able to figure out how to do this is to make my task Zip task depend on another task which gathers the files from the sub-projects into a directory on the root project, and then zip up that directory, like this:
task copyArtifactsForDistributionZip(description: 'Copies the artifacts that will be included in the distribution zip file') {
ext {
tmpDir = file("${projectDir}/tmp")
artifactTempDir = file("${tmpDir}/dist")
}
outputs.dir artifactTempDir
doLast {
subprojects.each { project ->
def projectDir = project.file("${artifactTempDir}/${project.name}")
copy {
from project.buildDir
into projectDir
include 'docs/**'
include 'libs/**'
include 'reports/**'
include 'test-results/**'
}
}
}
}
task buildDistributionZip(type: Zip) {
dependsOn 'copyArtifactsForDistributionZip'
from copyArtifactsForDistributionZip.outputs.files
}
What I would really like to do is to encapsulate all of this within the Zip task itself, without having to make it dependent on the other task (and therefore avoid having to physically copy the files from the child projects into the root project. Is there an easy way to do this? Is there a way I can do something like (this is pseudo-code - I know it won’t work but just want to show the logic)
The task as you wrote it does not even compile - I get this error:
C:\Projects1\master>gradle distributionZip
FAILURE: Build failed with an exception.
* Where:
Script 'C:\Projects1\master\project-build.gradle' line: 27
* What went wrong:
A problem occurred evaluating script.
> Could not find property 'build' on project ':Content'.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: 4.181 secs
If I change it around a bit and remove the dependsOn
task distributionZip(type: Zip) {
subprojects.each { subproject ->
into(subproject.name) {
from subproject.buildDir
include 'docs/**'
include 'libs/**'
include 'reports/**'
include 'test-results/**'
}
}
}
then the task does not do anything - I get an UP-TO-DATE status when running the build, even though I have never run the task before.
I guess what I’m ultimately trying to accomplish is to have the root project of a build have a task which can generate a zip file of things that the subprojects tell it. So in the archive.zip at the root project there should be a subdirectory for each sub-project. Inside each subdirectory there should be “stuff” that each sub-project puts there. The root project should not know or care about what each subproject puts there - the root project could call a task or something that generates a CopySpec, which would in turn allow the root project to collect things from the subprojects and place it into the archive in the root project.
And then in my subprojects I have this (all subprojects have the same thing at the moment just to prove the concept, but each subproject could configure differently):
distributionZips {
includeEmptyDirs = false
into(project.name) {
from(buildDir) {
include 'docs/**'
include 'libs/**'
include 'reports/**'
include 'test-results/**'
}
}
}
My question is: How do I link the buildDistributionZip in the root project to the outputs of the tasks in the subprojects? Right now if I execute “gradle buildDistributionZip” from the root project directory it executes the task from the root project before going into the subprojects.
Ahhh so that’s how you do it. The subproject actually injects stuff directly into the root project’s task. The subprojects themselves don’t have a task.
The only issue now is in the structure inside the zip file. When I have this block inside build.gradle for a subproject
rootProject.distributionZips {
dependsOn // whatever is needed to create stuff
into (project.name) {
// configure to heart's content
}
the attribute “project.name” gets resolved to the project name of the root project - not the project name of the sub project. Inside the zip file at the root I want folders for each of the sub projects, so inside the zip it would look somewhat like this:
archive.zip
|
---SubprojectA
-------Some files/folders gathered from SubprojectA
---SubprojectB
-------Some files/folders gathered from SubprojectB
Each task object has a ‘getProject()’ method which returns the project the task is attached to. In this case it was shadowing the project that backed the script. The ‘this’ pointer lets you resolve to then containing script class, which implicitly delegates to the backing project, which has a ‘getProject()’ method that just returns “self”. The joys of dynamic languages