Dynamically switch between a binary dependency and a source dependency

Hi there,

I’m working on an POC that shows it is possible to dynamically switch between a binary dependency and a source dependency.
Consider the following use case: In a multi-repo context, I have an Android application (in a repo A) that depends on a library project (in a repo B). When implementing a new feature in the Android application, I have to modify the library project as well. I would like to be able to build the Android application (both locally and on a CI server) and use the updated version of my library project which is not yet released.
Locally, I know I can make use of the composite build functionality, but I’m wondering how to make it work for my CI server. I don’t want to clone every repository for every build just in case one of the libraries needs to be built from source.

A solution I could find to know whether or not I should build from source is looking at the git branch name. For example, I start implementing feature-A in the Android app project so I create a feature-A branch in repo A, and a feature-A branch in repo B to modify the library project as well.

What I currently have is:

build.gradle.kts (Android app - inside the dependencies block)

val currentBranch = functionToGetCurrentBranch()
val libraryHasSameBranch = functionToChekIfRemoteRepoHasSameBranch()
if(libraryHasSameBranch) {
    add("implementation", "organization:library") {
        version {
            branch = currentBranch
        }
    }
} else {
    add("implementation","organization:library:version")
}

settings.gradle.kts (Android app)

sourceControl {
    gitRepository(remoteRepositoryURI) {
        producesModule("organization:library")
    }
}

For some reason (there must be a perfectly valid one), when the remote repository for the library project doesn’t have a branch with a matching name the binary dependency is picked up and everything is compiling just fine, but when a matching branch is found, the build fails for an mysterious reason:

Details: org.gradle.api.artifacts.ResolveException: Could not resolve all dependencies for configuration ‘:app:debugImplementationDependenciesMetadata’. Caused by: java.lang.RuntimeException: Problems reading data from Binary store in /tmp/gradle7063330775827489046.bin (exist: true) Caused by: java.lang.NullPointerException: null

Can someone explain to me what I’m doing wrong, and ideally give me ideas on how to fix that problem?

Thanks in advance

Can anyone provide some support?

I’ve also been trying to use dependencySubstitution directly to replace binary dependencies by source dependencies, but the main challenge is that all projects are in their own git repository and the substitution needs to happen automatically (I know that I can call includeBuild manually in the settings.gradle.kts file).

So far I can locate the git repository corresponding to the binary dependency but I don’t know how to use that project once it’s been located…

Take a look at my original post for a CompositePlugin and this version by @rodney757 which is updated to use Gradle’s dependencySubstitution.

The CompositePlugin.groovy uses a project/source dependency if it’s available and otherwise falls back to jar dependencies. It can be force to use jars with the forceJars system property (or in settings.gradle you can comment out a projects includeFlatIfLocal). Anyway, those should be enough to get you started.