If subproject has dependency add another - gradle

I have a multi-module project and I want to add another dependency automatically if a submodule contains a specific dependency.
So far I've added this on my root build.gradle.kts
subprojects {
apply {
plugin("java")
}
project.configurations.implementation.get().allDependencies.forEach {
println(it.name)
}
}
But it prints nothing. How can I get all dependencies implemented by a subproject and then another if it contains one already?
Thanks

Related

Injecting plugin/runtimeOnly configuration(s) from one module to another module (within the same project) in gradle multi module project

I am referring to my post here :Moving Jib configuration of one module into a new module, to refactor multi-module gradle project
With the same refactoring goal of keeping jib related configuration in a separate module, I want to inject some "runtimeOnly" dependencies from the new module so that jar gets added in the classpath.
['jib', 'jibDockerBuild', 'jibBuildTar'].each { jibTaskName ->
task "${jibTaskName}Webapp" {
doFirst {
project(':webapp').jib {
to.image = 'jib-webapp'
// and more ....
}
***project(':webapp').configurations {
dependencies {
runtimeOnly project(':abc')
}
}***
}
finalizedBy ":webapp:$jibTaskName"
}
task "${jibTaskName}App" {
doFirst {
project(':app').jib {
to.image = 'jib-app'
// and more ...
}
}
finalizedBy ":app:$jibTaskName"
}
}
but ./gradlew jibDockerBuildWebapp won't add the ":abc" module artifacts (jar) in the war lib directory.
Only way I am able to get this working by adding "runtimeOnly project(':abc') in the ":webapp" module's build.gradle file.. but that's not I intend to do.
Can you please suggest how to get this working?
I was searching for diff options in Jib settings if I could add the module dependency there for it to add the artifacts in the lib directory. I need to add additional jars to run a setup program before starting tomcat.
You can just add dependencies to a module from another module.
// to make sure :webapp is evaluated before this project
evaluationDependsOn(':webapp')
project(':webapp').dependencies {
runtimeOnly 'junit:junit:4.13'
}
['jib', 'jibDockerBuild', 'jibBuildTar'].each { jibTaskName ->
...
However, I'm not sure if this is a good practice. It's the same as defining dependencies in the target build.gradle, and the only difference is that it's being done at a different place. I think this may confuse first-time readers of your repo as to how and why some dependencies are added out of the blue.
BTW, the following also worked for me:
...
task "${jibTaskName}Webapp" {
doFirst {
project(':sub1') {
jib.to.image='jib-sub1'
dependencies {
runtimeOnly 'junit:junit:4.13'
}
}
}
}
However, it's not exactly same as above in that the dependencies are added in a later phase (not in the Gradle configuration phase) and only when the task is executed. Again, I'm not sure if this is a good practice.

Selective dependencies in Gradle

I'm setting up a multi-project Gradle build to replace an existing Ant build, where all the sub projects have their own build.gradle file in which the sub-project's dependencies are defined.
My sub projects all have their own dependencies, and there's a small subset of those (all 3rd party jars) that are only needed as a compile-time dependency in all the sub projects, like Maven's provided scope. (I have already found how I can create a configuration in Gradle that behaves like that.)
However, since this is a small set of jars, and they're the same for all sub projects, I'd like to extract the knowledge of which jars are provided out of the individual sub projects's dependency lists, and into the main build script, somehow. I want this so that developers who add a sub project to the system, don't need to know about which dependencies are provided and which aren't.
In other words, I would like to have a configuration that behaves as provided for a specific list of dependencies, and as compile for all the others.
I have this in the main build.gradle:
ext.providedDependencies = [
"org.apache.log4j:log4j:1.2.16",
"joda-time:joda-time:2.0"
]
...
configurations { myconfig }
And one or more of the sub projects have a build.gradle like this:
dependencies {
myconfig "org.apache.log4j:log4j:1.2.16"
myconfig "org.apache.commons:commons-lang3:3.3.2"
}
Then I want the behavior to be like this:
dependencies {
provided "org.apache.log4j:log4j:1.2.16"
compile "org.apache.commons:commons-lang3:3.3.2"
}
Because log4j is in ext.providedDependencies, and commons-lang3 isn't. I want this same behavior for all of my subprojects.
I have tried to (partially) implement myconfig like this:
subprojects {
dependencies {
configurations.myconfig.dependencies.each { dep ->
if (providedDependencies.contains(dep)) {
compile dep
}
}
}
}
But that does not work, because it turns out that configurations.myconfig.dependencies is empty (I don't understand why, though). In other words, the dependencies don't get added.
I also tried this, but here the opposite happens: all the dependencies are added, including those that are in the list of provided dependencies.
subprojects {
dependencies {
compile(configurations.myconfig) {
providedDependencies.each { exclude it }
}
}
}
Please let me know how I can make this work, or if there is a different, better way to achieve what I want.
EDIT Partially re-written for clarity
ext{
dependencies = [
"dependencyGroup:dependencyName:dependencyVersion",
"dependency2Group:dependency2Name:dependency2Version"
]
}
subprojects{
dependencies {
provided dependencies
}
configurations {
compile.exclude group: 'dependencyGroup'
compile.exclude group: 'dependency2Group'
}
}
In the above example, we have defined a list of dependencies with the name dependencies.
EDIT -- We are excluding the dependencies from the compile configuration if they need to be provided. This means that all even if a subproject adds a dependency that you want to be provided as compile, it won't happen.

How to let gradle build dependent sub-project first when using non-compile dependencies

How can I tell gradle to build a certain sub-projects first, even though I don't have a compile dependency to them? How are project dependencies handled internally?
Example:
settings.gradle:
include "app", "schema"
build.gradle:
allprojects {
apply plugin: 'java'
}
schema/build.gradle:
// empty
app/build.gradle:
configurations {
schemas
}
dependencies {
schemas project(":schema")
schemas "org.example:example-schema:1.0"
}
task extractSchema(type: Copy) {
from {
configurations.schemas.collect { zipTree(it) }
}
into "build/schemas"
}
//compileJava.dependsOn extractSchema
And when running:
$ cd app
$ gradle extractSchema
I get:
Cannot expand ZIP 'schema/build/libs/schema.jar' as it does not exist.
What I want is that gradle automatically builds all sub-projectes defined in the configurations.schemas dependency list first (if they are projects).
Note: I want to be able to share the extractSchema task across multiple gradle projects, so it is important that gradle takes the list of sub-project to be built first from the configurations.schemas list.
Thanks
Gradle build order is never on the project level, but always on the task level. from(configuration.schemas) would infer task dependencies automatically, but in case of from(configuration.schemas.collect { ... }), this doesn't work because the resulting value is no longer Buildable. Adding dependsOn configurations.schemas should solve the problem.

Gradle dependency to project in buildscript

Trying to get my head around if it is possible to use Tasks from other projects in Gradle. Let's say ProjectB is a project with src/main/groovy containing com.MyTask, having parent ProjectA
In build.gradle in ProjectC, also having parent ProjectA:
buildscript {
dependencies{
project(':ProjectB')
}
}
That seems to be legit, because introdusing a typo in "project(:'ProjectB')" fails hard. What also fails is introducing this line:
import com.MyTask
Is project-references not valid in buildscript closure? Also tried moving com.MyTask to buildSrc/src/main/groovy with the same amount of success.
The solution which worked for me was to make "com.MyTask" available both at configurationtime and in sources.
ProjectA(the parent) got this added to buildSrc/build.gradle's sourceSets:
sourceSets{
main{
groovy{
srcDir 'ProjectB/src/main/groovy'
}
}
}
Now ProjectC and all other projects can use MyTask. At the same time it is bundled with the final jar of ProjectB.
The issue has also been discussed thoroughly between between Adam Murdoch, Luke Daley and Steve Ebersole: http://gradle.1045684.n5.nabble.com/buildSrc-as-a-regular-project-td5677255.html
Edit: It was smarter manipulating parent buildSrc than the standalone project. That way IntelliJ is happy-go-lucky.
From Gradle documentation 15.4. Adding dependencies to a task:
Example 15.13. Adding dependency on task from another project
build.gradle
project('projectA') {
task taskX(dependsOn: ':projectB:taskY') << {
println 'taskX'
}
}
project('projectB') {
task taskY << {
println 'taskY'
}
}

Gradle multiproject gives "Could not find property 'sourceSets' on project" error

I had quite good gradle configuration, that built everything just fine. But one of the projects of my multi-project build derived from the rest of them so much, that I would gladly move it to another git repo and configure submodules to handle it.
First, I moved Project and its resources to subfolder Libraries/MovedProject. After altering some lines in gradle configurations it worked fine. But then I decided to write a new build.gradle just for this project, and move all configurations there from the main one.
And this is where everything stopped working. When I try to call any task it always ends
with Could not find property 'sourceSets' on project ':Libraries/MovedProject'. Line which is responsible for it is:
dependencies {
...
if (noEclipseTask) {
testCompile project(':Libraries/MovedLibrary').sourceSets.test.output
}
}
which I use for running tests in which I use classes from other projects. If I remove that line, the build fails only when it reaches compileTestJava task of projects that make use of MovedProject. If I remove that line and call gradle :Libraries/MovedLibrary:properties I can see :
...
sourceCompatibility: 1.7
sourceSets: [source set main, source set test]
standardOutputCapture: org.gradle.logging.internal.DefaultLoggingManager#1e263938
...
while gradle :Libraries/MovedLibrary:build builds correctly.
Currently I've got everything set up as following:
directories:
/SomeMainProject1
/SomeMainProject2
/SomeMainProject3
/Libraries
/MovedProject
build.gradle
dependencies.gradle
project.gradle
tasks.gradle
/Builder
dependencies.gradle
project.gradle
tasks.gradle
build.gradle
settings.gradle
settings.gradle
include Libraries/MovedProject,
SomeMainProject1,
SomeMainProject2,
SomeMainProject3
sourceSets for MovedProject are defined in Libraries/MovedProject/project.gradle:
sourceSets {
main {
java {
srcDir 'src'
srcDir 'resources'
}
resources { srcDir 'resources' }
}
test { java {
srcDir 'test/unit'
} }
}
dependencies that makes use of sourceSets.test.output are stored in Builder/dependancies.gradle, and set for each project that needs MovedProject to run tests:
project(':SomeMainProject1') {
dependencies {
...
if (noEclipseTask) {
testCompile project(':Libraries/net.jsdpu').sourceSets.test.output
}
}
}
What would be the easiest way to get rid of that error and make gradle build projects with current directory structure? I would like to understand why gradle cannot see that property.
The line in question is problematic because it makes the assumption that project :Libraries/MovedLibrary is evaluated (not executed) before the current project, which may not be the case. And if it's not, the source sets of the other project will not have been configured yet. (There won't even be a sourceSets property because the java-base plugin hasn't been applied yet.)
In general, it's best not to reach out into project models of other projects, especially if they aren't children of the current project. In the case of project A using project B's test code, the recommended solution is to have project B expose a test Jar (via an artifacts {} block) that is then consumed by project A.
If you want to keep things as they are, you may be able to work around the problem by using gradle.projectsEvaluated {} or project.evaluationDependsOn(). See the Gradle Build Language Reference for more information.
I had a similar error happen to me in a multimodule project, but for me the cause was as simple as I had forgotten to apply the java-library plugin within the configurations, I only had maven-publish plugin in use.
Once I added the plugin, sourceSets was found normally:
configure(subprojects) {
apply plugin: 'maven-publish'
apply plugin: 'java-library'
....

Resources