How add gradle to subproject root project as dependency? - gradle

I have the following project structure settings.gradle:
include 'B'
include 'C'
rootProject.name = 'A'
How add gradle to subproject root project as dependency?

As far as the project method is concerned, the root project has no name. So this is the syntax in project B's build.gradle:
dependencies {
compile project(':')
}
However, it is rarely a good idea to do this. It is too easy to end up with circular dependencies. Most multi-module projects have a separate "main" projects (called something like "main", "core" or "base"), and other modules can easily depend on that using compile project(':core') or whatever.

I assume the question being asked is: "How to add a Gradle root project as dependency to a subproject?"
The following worked for me, when I added this in my subproject's build.gradle.
dependencies {
//Add the root/parent project as a dependency
compile project(":")
}
//Without this, my subproject's tests would not compile or run
sourceSets {
test{
compileClasspath += project(":").sourceSets.main.output.classesDirs
runtimeClasspath += project(":").sourceSets.main.output.classesDirs
}
}
Note: I am using gradle version 5.6.4.

Related

IntelliJ gradle integration issue with independent gradle subprojects

I have two independent gradle projects that I also want to build from one main gradle project:
main-project
build.gradle
settings.gradle
--subproject-one
build.gradle
settings.gradle
--module-a
build.gradle
--subproject-two
build.gradle
settings.gradle
--module-b
build.gradle
My top settings.gradle includes all modules from the sub projects:
file('subproject-one').eachDir { dir ->
if(dir.list().contains("build.gradle")) {
include dir.name
project(":${dir.name}").projectDir = dir
}
}
file('subproject-two').eachDir { dir ->
if(dir.list().contains("build.gradle")) {
include dir.name
project(":${dir.name}").projectDir = dir
}
}
Now i have a dependency from module-b in subproject-two to module-a in subproject-one. I use a compile switch (useProjectDependencies) to include them as project dependencies when I build from the main project and as normal dependencies when i build from the subprojects:
if(useProjectDependencies){
compile project(':module-b')
} else {
//Client dependencies
compile "my.group.id:module-b
}
Via gradle I'm now able to build the main-project including the subproject and also each subproject on it's own.
When I open the main-project now via IntelliJ I see all the modules are recognized correctly and also the cross references to classes between the modules work correctly (refactoring interface between to components are working great).
When I now try to use the gradle integration from Intellij and click on assemble for the module-b then it incorrectly uses the build.gradle form and settings.gradle from subproject-two and doesn't use the project dependencies. It looks like IntelliJ or the gradle daemon searches for the first settings.gradle in a bottom up way from the module-b instead of using the one in the main-project.
When I build via terminal from the main-project folder all works correctly:
gradlew :module-b:assemble //correct *settings.gradle* and *build.gradle* is used
When I delete the settings.gradle and build.gradle from subproject-two then the build.gradle from the main-project is correctly used.
Is there a way to specify the settings.gradle and build.gradle that is used as part of the IntelliJ gradle integration?

How to build a jar from a multi-module project when using Gradle?

I'm working on a multi-module library project which I build with Gradle. I have a dependency to another module of this project in my dependencies section:
dependencies {
compile project(':my-other-module')
}
My problem is that I want to build a .jar file which only contains the local modules in the final file, not its transitive dependencies. I tried this:
jar {
from project(':my-other-module').configurations.compile.collect { zipTree it }
}
but this added all the transitive dependencies as well. I want to create a .jar which only contains my own files, so the users of this library can have their own versions of transitive dependencies. How can I do so?
Further clarification:
I have dependencies declared in my project to external jars like apache-commons. I want these not to be in my resulting .jar file but I want the users of my library to be able to just add my library as a dependency and let Maven/Gradle download the transitive dependencies. I don't want these transitive dependencies to be in the .jar file I deploy to Maven Central. compileOnly is not an option since the dependencies I use like apache-commons are not provided by a framework or a container. They need to be present as compile dependencies. I just want to build and deploy a .jar file which has all the files in my project which has multiple modules.
I am not sure it'll help you or not but, you can try this.
In your build.gradle file, customize your jar task as follows:
// This closure will return the full directory path of folder where your classes are built
ext.moduleClassPath = { moduleName ->
def classOutputDirConst = "/classes/java/main"
return "${project(":${moduleName}").buildDir}${classOutputDirConst}"
}
// Now jar task will include only the built file of specified project
jar {
from(moduleClassPath("projectName1"), moduleClassPath("projectName2"))
}
Check the reference for the from(SourcePaths) method here: Reference: https://docs.gradle.org/current/dsl/org.gradle.jvm.tasks.Jar.html#org.gradle.jvm.tasks.Jar:from(java.lang.Object[])
Gradle has a compile-only dependency concept, similar to Maven's provided scope:
Compile-only dependencies are distinctly different than regular compile dependencies. They are not included on the runtime classpath and they are non-transitive, meaning they are not included in dependent projects.
The dependencies you don't want can be declared in the compileOnly configuration, rather than compile, eg:
dependencies {
compileOnly 'javax.servlet:servlet-api:2.5'
}
compileOnly is not even visible to unit tests, by default. We change this in a common gradle snippet which we include in each build:
// compileOnly isn't visible to tests by default, add it
plugins.withType(JavaPlugin).whenPluginAdded {
sourceSets {
test.compileClasspath += configurations.compileOnly
test.runtimeClasspath += configurations.compileOnly
}
}
For the second part, for which I believe you want to create a single "fat" jar,
I would suggest creating your jar using the very good Shadow Plugin, rather than manually extending the jar task. By default, the shadow plugin will not include anything in the compileOnly configuration in the resulting jar.

Using gradle for a flat, multi-module project where settings.gradle is not the highest-level dependency

I have a multi-module project with a directory structure like:
proj
|-modA
|-modB
|-modMain
\-modSysTest
The dependencies are:
modB -> modA
modMain -> modB
modMain -> modA
modSysTest -> modMain
We currently use Ant as our build system. Every module has a build.xml. There is a master.xml that runs the multi-module build, which is in modMain.
I am investigating switching our project to use gradle. I can get a multi-module build working if I put a build.gradle and settings.gradle in a new sibling directory and set up the dependent modules using includeFlat.
I tried moving the gradle files into modMain, which is the home of both the main component of our system as well as the top-level build script (master.xml) that builds the whole system, but I cannot get the build working this way. My main stumbling block at the moment is trying to configure modSysTest to depend on modMain from within modMain.
Here is the settings.gradle from modMain:
includeFlat 'modA', 'modB', 'modSysTest'
Here is the build.gradle file from modMain:
allprojects {
apply plugin: 'java'
repositories {
mavenCentral()
};
dependencies {
testCompile 'junit:junit:4.11'
}
}
project(':modB') {
dependencies {
compile project(':modA')
}
}
project(':modSysTest') {
dependencies {
compile project(':modMain')
}
}
dependencies {
compile project(':modA'), project(':modB')
}
When using this configuration, I get the error:
A problem occurred evaluating root project 'modMain'.
> Project with path ':modMain' could not be found in project ':modSysTest'.
I am not sure how to specify modMain as a dependency for modSysTest.
The project path of the root project is :, not :modMain. It's not very customary (but possible) to have code in the root project. I don't see how putting build.gradle and settings.gradle into a sibling directory of modMain would give a different result (unless you also changed the contents of settings.gradle). Note that with such a setup, Gradle won't find settings.gradle unless you start the build from the modMain directory or pass the location of the settings file with -c.

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