Multi-project gradle build with Nexus artifact repository - gradle

Consider the following multi-project gradle build, where ProjectA depends on ProjectB, and ProjectB depends on ProjectC. Dependencies are specified in the form compile project(':ProjectX'). This requires that each project be checked out in order to build, say, ProjectA.
I want to use an artifact repo such as Sonatype Nexus, to make the build simpler for developers so that if they are only working on ProjectA, then they do not need to have the dependent projects checked out, and they can be retrieved from Nexus. Similarly, if you are working on the dependent projects and they are checked out locally, I want them to be build instead of being retrieved from Nexus.
In summary, the dependency resolution strategy is: If project dependency and checked out, build locally, else retrieve from Nexus
How can I achieve this in gradle?

I got this working by flipping my dependency definitions from compile project(':ProjectX') to compile "my-group:ProjectX:version", and use the following dependency substitution resolution strategy:
configurations.all {
resolutionStrategy.dependencySubstitution.all { DependencySubstitution dependency ->
if (dependency.requested instanceof ModuleComponentSelector && dependency.requested.group == "my-group") {
def proj = "${dependency.requested.module}"
if (new File(rootDir, '../' + proj).exists()) {
dependency.useTarget findProject(":${proj}")
}
}
}
}

Related

Gradle fails to detect flat dependency

I have a multi-project Gradle build (Gradle 4.4).
And I encountered the following issue.
Let's say I have proj1 project with the following build.gradle:
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
compile name: 'lombok-edge'
}
proj1 has libs folder with lombok-edge.jar. Project is built successfully.
And I have proj2 that imports proj1:
dependencies {
compile project(':proj1')
}
When I try to build the whole project proj1 is build but Gradle fails to build proj2 with an error:
What went wrong:
Could not resolve all files for configuration ':proj2:compileClasspath'.
Could not find :lombok-edge:.
Required by:
project :proj2 > project :proj1
Please advise.
Well, Gradle supports transitive dependencies, but the way how to get a dependency (and therefor any repository information) is not transitive. Gradle (like Maven) does not care where a dependency comes from, as long as it matches a given signature (group, id, version).
In your example, project 1 defines a Maven dependency and can resolve it via the given flatDir repository. Project 2 has dependencies on both project 1 (which is resolved by Gradle) and the transitive Maven dependency. It's the responsibility of project 2 to resolve this dependency and it will check any defined repository, but cannot find it, because the local repository is unkown. This is the reason why the build fails.
If the two projects are related, as they should be if they are both parts of a multi-project build, you should define the local repository in a top-level build.gradle file and a subprojects closure.

Add dependencies via transitive dependencies of another configuration in Gradle

I would like Gradle to compute the dependencies for a configuration by adding dependencies from dependencies loaded via a second configuration.
Example with two Gradle projects:
dependency/build.gradle:
configurations {
other
}
dependencies {
other "bar:artifact1:0.4"
}
top/build.gradle:
configurations {
other
modules
}
dependencies {
modules "foo:dependency:1.0"
other "bar:artifact2:0.1"
}
So the top project depends on dependency via the modules configuration, but I want the other configuration in top to contain both "bar:artifact1:0.4" and "bar:artifact2:0.1".
In my concrete case, the other dependencies are listed in an Ivy file for each artifact. I want to collect the other dependencies of all the artifacts a project depends on.
This is not a multi-project build, but other projects' artifacts are loaded from a remote repository.
Is there a way to configure Gradle to include the configurations of all transitive dependencies?

Gradle/Maven project fork provides original artifact (only download fork)

Description
I have forked another project and uploaded it to my own maven repository. The dependency graph, however, pulls the original project too, meaning I two versions of the projects. The compilation works fine in command-line but not in eclipse as it reads the original project's jar first and then skips my forked project.
Dependency graph
+--- com.spiddekauga.gdx:gdx-spiddekauga (fork)
+--- com.badlogicgames.gdx:gdx-box2d
| \--- com.badlogicgames.gdx:gdx (original)
What I've tried
First I tried using the original name of com.badlogicgames.gdx:gdx but the project was downloaded from the original maven repository instead of mine even if my maven repository is listed before.
build.gradle
allprojects {
...
repositories {
maven { url "http://maven.MY-DOMAIN.org/" }
mavenCentral()
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
maven { url "https://oss.sonatype.org/content/repositories/releases/" }
}
...
}
Another thing I've search for is to make com.spiddekauga.gdx:gdx-spiddekauga provide com.badlogicgames.gdx:gdx so that it doesn't have to be downloaded, but I haven't found a way to do this in neither in gradle or maven.
Questions
How can I solve so that only my forked project is pulled? Either by a) renaming to com.badlogicgames.gdx:gdx so it searches my maven repository first; or b) by excluding the dependency com.badlogicgames.gdx:gdx.
[minor question] Is it possible to set that a maven project provides another artifact? E.g. like this:
pom.xml
<project>
<groupId>com.spiddekauga.gdx</groupId>
<artifactId>gdx-spiddekauga</artifactId>
<provides>
<project>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx</gdx>
</project>
</provides>
</project>
Forking the project does not change the project coordinates (groupId, projectId and version) in the pomor gradle files. You would need to search and replace all of them for it to work.
Also the dependencies that you are referring to are available in mavenCentral, which is the first in the repositories list.

gradle with maven submodule

There is any way to build gradle project with maven submodule ? I created a project in gradle but at now I must add module (that module used a maven) I don't have any idea how to used this. There is any good way?
I will be very gratefull for any suggestions.
Either convert the Maven project to Gradle (gradle init is a good start) and turn the Gradle build into a multi-project build, or publish the Maven build's artifact to the local or a remote Maven repository, and configure the Gradle build to consume it from there (or the other way around).
Create a build.gradle(.kts) that wraps the Maven project in its root directory:
val build = task<Exec>("build") {
commandLine("mvn", "package")
}
val default by configurations.creating {
isCanBeConsumed = true
isCanBeResolved = false
}
artifacts {
add(default.name, File("$projectDir/target/<name of the jar>.jar")) {
builtBy(build)
}
}
You can then depend on it like this:
implementation(project(":<path to the module>", "default"))

Gradle prefer repository on duplicate entries

I have a build tool thats tied the version to the SCM. I can't set the version of a jar when I build it locally. If someone were to change what I'm working on locally it would push the version number (which I can get), but when I publish to my local repo (Ivy) Gradle seems to prefer the external repo.
build.gradle
repositories {
mavenCentral()
ivy {
url "${System.properties['user.home']}/.ivy2/local/"
layout "pattern", {
artifact "[organization]/[module]/[revision]/[artifact](-[classifier]).[ext]"
ivy "[organization]/[module]/[revision]/ivy.xml"
}
}
ivy {
url "https://repo/"
layout "pattern", {
artifact myPattern
ivy myIvyPattern
}
}
}
Without changing the build for the jar that I'm editing. How can I have gradle always prefer the local repo? I have a feeling that resolutionStrategy might be the best way, but I don't know how accomplish this.
Edit 1
To help clarify, Artifactory has a jar (published by jenkins) with version 1.2.3. I have a jar that I build locally that saves into my local repository as 1.2.3. When I build a project having both repositories in my repository closure (with my local one on top) Gradle seems to pull in the one from Artifactory.
Edit 2
Dependency definition
dependencies {
compile ('company:project:1.2.+')
}
I don't really understand what you are saying, but Gradle searches repositories in their declared order, and picks the first matching module that it finds (as least as long as fixed versions are used).

Resources