Given a project file structure like this:
git-root
├── ServerApp
│ ├── build.gradle
│ └── src
│ └── ...
└── ClientJAR
├── build.gradle
└── src
└── ...
ServerApp
needs to include an artifact of ClientJAR
‘s build (the default artifact) as one of its resources. There is no dependency between ServerApp
and ClientJAR
in the traditional sense – neither project references code from the other.
As the diagram shows, the two Gradle projects are siblings in a single git repo. Changing that structure (eg, to make this a container/composite build) is only a last resort; I’m looking for a solution that keeps this structure intact.
Some Background/Context
The intention is that the application built by ServerApp
has an endpoint that can be used to download the artifact that was built in ClientJAR
project. The most obvious way (to me) to implement that is to have ClientJAR
‘s artifact be embedded into ServerApp
(which is a Spring Boot application) as a resource at build time.
I’ve tried using includeFlat
and declaring ClientJAR
as a dependency in ServerApp
, but that caused the “plain” ClientJAR
JAR artifact to be included in ServerApp
‘s libs, which isn’t what I need. I need the bootJar artifact (which is currently the result of calling gradlew build
in ClientJAR
).
Is there a clean way to “embed” a sibling like this? Even a concrete example of one build invoking another (sibling) and then copying its output into the /build/resources
folder would be a reasonable option (I think).
I’m still testing and checking, but here is what I got working using a combination of custom GradleBuild
and Copy
tasks.
In ServerApp
I added these custom tasks:
task buildClient(type: GradleBuild) {
buildFile="../ClientJAR/build.gradle"
tasks = ['clean', 'build']
}
task copyClient(type: Copy, dependsOn: buildClient) {
from ('../ClientJAR/build/libs/') {
include 'client-*.jar'
rename { 'client.jar' }
}
into "$buildDir/resources/main"
}
I also declared that processResources
should depend on copyClient
:
processResources {
dependsOn copyClient
}
With that, client.jar
ends up in ServerApp/build/resources/main/
(and in the final Boot WAR artifact) as expected.
You can do this in three steps:
- Link the build of the projects together so they can reference one another;
- Obtain the desired JAR in the
ServerApp
build by depending on aClientJAR
configuration; and - Copy the JAR to the location it needs to be in resources.
1. Link the build of the projects together
As you have already done, you can achieve this with the use of includeFlat
:
// ServerApp/settings.gradle
includeFlat("ClientJAR")
2. Obtain the JAR in the consuming project via new configurations
Gradle have instructions for sharing artifacts in this way. To summarise, you can do it in four steps:
(a) Add a new consumable configuration to the producer project (ClientJAR
):
// ClientJAR/build.gradle
configurations {
bootJarConsumable {
canBeConsumed = true
canBeResolved = false
}
}
(b) Add the desired artifact to it, using the Jar task which generates bootJar
(assumed called bootJarTaskName
):
// ClientJAR/build.gradle
artifacts {
bootJarConsumable(tasks.named('bootJarTaskName'))
}
(c) Add a new configuration to ServerJAR
for loading the JAR
// ServerApp/build.gradle
configurations {
bootJarResolvable {
canBeConsumed = false
canBeResolved = true
}
}
(d) Depend on the artifact in consuming project by depending on the new configuration:
// ServerApp/build.gradle
dependencies {
bootJarResolvable project(path: ':ClientJAR', configuration: 'bootJarConsumable')
}
3. Copy the JAR to the location it needs to be in resources
ServerApp
then has access to the JAR, but it is not in the desired location. You can write a task to do the final copy step:
// ServerApp/build.gradle
tasks.register('copyToResources', Copy) {
from configurations.named('bootJarResolvable')
into sourceSets.main.resources.sourceDirectories.singleFile
}
Finally, you need to ensure the processResources
task depends on this so all everything will run when the ServerApp
build is run:
// ServerApp/build.gradle
processResources {
dependsOn copyToResources
}