Gradle - Recursively include external project and its subprojects - gradle

I have a gradle project with many submodules named shared-library.
I have a project named service that depends on one of the modules of shared-library. e.g., it depends on :shared-library:module1. Normally, I get this dependency from maven.
Now I want to modify shared-library and test my changes using the dependent project. Instead of making a change to shared-library, building, deploying to maven, then rebuilding my service, I'd like to instead have service depend on the shared-library gradle project directly.
So I found out that you can point gradle to arbitrary project directories on the filesystem:
service/settings.gradle
include "shared-library"
project(":shared-library").projectDir = new File("/projects/shared-library")
But when I do this, the project is not aware of shared-library's submodules. I cannot do this:
service/build.gradle
compile(
project(":shared-library:module1"),
)
So I tried includeing them directly. :shared-library:module1 depends on :shared-library:module2 so I include that one as well:
service/settings.gradle
include "shared-library"
project(":shared-library").projectDir = new File("/projects/shared-library")
include "shared-library:module2"
include "shared-library:module1"
But now when I try to run this, it complains that :shared-library:module1 cannot locate a project named :module2. This is because its dependency is configured as such:
shared-library/module1/build.gradle
compile(
project(":module2")
)
But if I change that to an absolute project path, now shared-library cannot compile on its own:
shared-library/module1/build.gradle
compile(
project(":shared-library:module2")
)
tl;dr, it seems like there is a mismatch between the way service resolves the shared-library submodule names and how shared-library does it.

You're right. You can import an external project, or even external subprojects, and reference them in your main project, but as soon as you compile the external entities they fail to resolve with the expected names.
I found that you can rename the external projects in your main project so that they match the names of the external projects. That way your main project and the external projects use the same name.
Change your service/settings.gradle to:
include "shared-library"
project(":shared-library").projectDir = new File("/projects/shared-library")
include "shared-library:module2"
project('shared-library:module2').name = ':module2'
include "shared-library:module1"
project('shared-library:module1').name = ':module1'
Now in your project and external project refer to your modules always as :module1 and :module2. In service/build.gradle use:
compile(project(":module1"))

Related

Add local Gradle source module by absolute path

I want to add a subproject to my Gradle project. The project is located somewhere on my hard disk drive, for example:
/A/Path/to/a/ProjectA
/Another/Path/to/another/ProjectB
What I want to achieve is to use ProjectB as a source module within Project A. However, all my attempts to do this so far - either by adding include /Another/Path/to/another/ProjectB or by adding include ':ProjectB'; project(':ProjectB').projectDir = ... in settings.gradle - just failed. Apparently, Gradle is not able to find the project.
How can I add ProjectB as a dependency without moving it from it's location?
Using Gradle 3.4.1, the following works for me (full example here):
include 'app', 'common'
def MY_PATH = '/Users/johndoe/foo'
assert new File("$MY_PATH/random/path/common").exists()
project(':common').projectDir = new File("$MY_PATH/random/path/common")
Thanks for your responses.
Turns out I've made several mistakes:
Adding the project to the built was dependent on the value of an environment variable. I replaced that with a property within gradle.properties.
I tested this by running the settings.gradle usind IntelliJ. I mistakingly expected this to work, but it didn't
I did not add the project as a dependency to the build.gradle file of the parent project.
It works now. Thank you all again!

Setting dependency of a component to mantle-usl - custom Groovy class

I have a custom groovy class inside mantle-usl component. I would like to use the class in other component. Hence, I need to add a dependency so that the new component (or project) has the jar of mantle-usl ready for use.
Is there anyone who can help with this? I attempted to modify the build.gradle file of the project. And add a project dependency, but it returned an error.
project(':runtime/component/warehouse-items-masterenumerator') {
dependencies {
compile project(':runtime/component/mantle-usl')
}
}
As you would expect, this does not work. It seems that I do not have the project references set correctly.
The mantle-usl component doesn't have any compiled code in it so the build.gradle file does not build a jar file, it is only used for running the Spock tests.
I wouldn't recommend adding your own code to mantle-usl, it is easier and cleaner to put it in a separate component. For an example of a build.gradle file that does build a jar file look at the moqui/example component or most of the moqui tool components (such as moqui-elasticsearch).
You also don't need to modify the main build.gradle file from the moqui-framework repository, dependencies should be declared in the build.gradle file in each component (which are picked up automatically in the main build).

Gradle dependency on module of another project failing

I realize there are a lot of posts online regarding Gradle setup. That being said, I have researched heavily and not found exactly what I'm looking for, or I'm using incorrect terms to do so. I'm using Gradle version 3.3.
So I've got multiple Gradle projects, each of which is maintained separately. There is no master Gradle project. Each projects has its own modules, build, and settings file. The structure of this is as so:
Projects
A
a1
build.gradle
a2
build.gradle
build.gradle
settings.gradle
B
b1
build.gradle
b2
build.gradle
build.gradle
settings.gradle
What I'm attempting to do is make B dependent on A's modules. Let's assume one of the modules in B is dependent on a1. In B's settings, I've done the following:
rootProject.name = 'B'
rootProject.setProjectDir(new File(".")
include 'a1'
project(':a1').setProjectDir(new File(settingsDir.getParentFile(), "/A/a1"))
The way I'm storing version numbers is through each project's build.gradle file in the ext closure. I then access them through the project. Here's how B's build file looks:
ext {
freemarkerVersion = '2.3.19'
}
dependencies {
compile project(':a1')
compile group: 'org.freemarker', name: 'freemarker', version: rootProject.properties.get('freemarkerVersion')
}
What I'm seeing is B is able to resolve its dependencies and is attempting to compile project a1, but it is using B's version numbers instead of A's. I verified this by putting a common dependency in both projects with different version numbers. The dependency showed up using B's version. I also changed the version number in B and further confirmed this. So if I could get any help for using project-appropriate versions in each of their own build.gradle files, that would be great!
EDIT: Updated post, figured out previous problem was from relative path not resolving.
Not to toot my own horn or anything, but I'm posting the solution I came up with, as I had no other answers knocking down my door.
The first thing I did was moved all of my version properties to an external gradle.properties file, instead of in an ext closure in the project's build.gradle file. Doing this, the project will load the properties file by default when compiled from its own context. It will of course be overridden from the user.home gradle.properties file, so keep this in mind. Example gradle.properties:
a_freemarkerVersion = 2.3.19
When using one project's modules from another project, you'll need a way to separately link the two so Gradle can resolve the dependency's properties. I achieved this by defining a method to load in the desired project's properties file. This method looks like so:
def addConfig(String parent, String filename) {
Properties props = new Properties()
props.load(new FileInputStream(new File(project.projectDir.getParent(), "/${parent}/${filename}")))
props.each { prop ->
project.ext.set(prop.key, prop.value)
}
}
addConfig("A", "gradle.properties")
All this method does is goes up one directory, goes into the project specified, and retrieves its gradle.properties file and loads these variables into the current project's properties. With that being said, there's one thing to note here: if you define the same variable in both, one of them will be overridden. To avoid this, I just prefixed all variables with the project name and then an underscore. This will guarantee they'll never conflict with one another.
I accessed the variables in all projects with this syntax:
dependencies {
compile group: 'org.freemarker', name: 'freemarker', version: "${a_freemarkerVersion}"
}
The rest of the setup is the same as I defined in my initial post. Just make sure to include the dependent module, specify its project directory, and compile that project from within the project's dependencies.

Defining cross project versions for gradle build

I have a several projects in a flat structure with dependencies between them.
Currently in each one a have a definition similar to this defining the versions used within the build script:
ext {
versions = [
scala: '2.11.1',
scalatra: '2.3.0',
jetty: '9.1.5.v20140505',
scalaTest: '2.3.0',
junit: '4.8.1',
]
}
and later usage:
compile group:'org.scala-lang' , name:'scala-library',version: versions.scala
As I have this defined in each build.gradle what I would rather want is to define the versions in one place and read in all files in the current build.
Writing to a global value will not be sufficient here as the combination of build files involved in a build may change (e.g. when testing a specific component only none of the components depending on it will be defined)
Put this map into its own .gradle file and include into your projects with apply from: '../dependencies.gradle'. Similar to what Gradle has in its own codebase

Gradle specify settings dir path for a sub project

In a multi-project build I have a module that in itself is composed of two sub-projects. If I just want the option of building the top-level module but also ensure both the sub-projects within it are also built, how I do achieve this?
include 'moduleA', 'moduleB', 'moduleC' (root project settings.gradle)
project(':moduleC').projectDir = new File('path to custom module that includes sub-projects)
project(':moduleC').settingsDir = ?? (gradle fails because there is no settingsDir path)
but moduleC has a settings.gradle in itself that has
include 'api'
include 'server'
Now I want both these to be triggered when I specify gradlew :moduleC:build, but instead it just builds moduleC root project. Is there a way? This use case does seem valid to me (i.e. for modularity, you want to keep the inclusion of sub-projects at moduleC's level and not at root level).
Thanks,
Paddy
As of Gradle 2.2, only a single settings.gradle per build is supported. If that file contains include "moduleC:api" and include "moduleC:server", then running gradle build from moduleC's project directory will also build api and server.

Resources