# Composite Builds Hierarchical Multirepo Sample

version 9.3.0-20251220022016+0000

- Groovy DSL

- Kotlin DSL

| You can open this sample in an IDE that supports Gradle.

## Using composite builds in a hierarchical multirepo project

This sample demonstrates how composite builds can be used to develop a hierarchical project that is composed from different Git repositories. Instead of Gradle subprojects in a multiproject build, this example uses separate Gradle builds included into a composite.

In addition to the benefits of a multirepo architecture, using a Gradle composite build in this way allows a developer to easily choose which modules to develop as source dependencies and which to integrate via a binary repository.

## Running `multirepo-app` with dependencies from included builds

In the first instance, all of the required dependencies are present as builds in the `modules` directory. In a real-world example, these could well be clones of different Git repositories.

In order to avoid hard-coding the included builds to load, the `settings.gradle` file in `multirepo-app` loads each of these builds dynamically:

settings.gradle.kts

    file("modules").listFiles().forEach { moduleBuild: File ->
        includeBuild(moduleBuild)
    }

settings.gradle

    file('modules').listFiles().each { File moduleBuild ->
        includeBuild moduleBuild
    }

When the `multirepo-app` build is executed, these module builds are used to generate the dependent artifacts:

    gradle run

And the 'dependencies' report shows the dependency substitution in action:

    gradle app:dependencies --configuration runtimeClasspath

    runtimeClasspath - Runtime classpath of source set 'main'.
    +--- org.sample:number-utils:1.0 -> project :number-utils
    \--- org.sample:string-utils:1.0 -> project :string-utils
         \--- org.apache.commons:commons-lang3:3.12.0

## Switching to use binary dependency

As long as the modules are available in a binary repository, the `multirepo-app` build will continue to work even if you don’t have some modules available locally. In this case Gradle will use a binary dependency downloaded from a repository instead.

### Preparing the binary repository

To demonstrate this functionality, we first need to publish each module to a binary repository. In this case we use a local file repository for this purpose:

    gradle :publishDeps

The `publishDeps` creates and uploads the artifacts for each included build. It is defined in `multirepo-app` as follows:

build.gradle.kts

    tasks.register("publishDeps") {
        dependsOn(gradle.includedBuilds.map { it.task(":publishMavenPublicationToMavenRepository") })
    }

build.gradle

    tasks.register('publishDeps') {
        dependsOn gradle.includedBuilds*.task(':publishMavenPublicationToMavenRepository')
    }

### Removing the local module source

With module artifacts available in a repository, we can now remove the module sources from the build. Since the composite is configured to automatically load available modules, this is as easy as deleting one or more module directories.

    rm -r modules/string-utils
    gradle run

Note that the `number-utils` dependency is still satisfied by the included build, while the `string-utils` dependency is now resolved from the repository.

The 'dependencies' report shows the dependency substitution in action:

    gradle app:dependencies --configuration runtimeClasspath

    runtimeClasspath - Runtime classpath of source set 'main'.
    +--- org.sample:number-utils:1.0 -> project :number-utils
    \--- org.sample:string-utils:1.0
         \--- org.apache.commons:commons-lang3:3.12.0

## Including an external library as a submodule

The power of this configuration can be demonstrated by adding the external 'commons-lang' build directly to the composite.

    git clone http://gitbox.apache.org/repos/asf/commons-lang.git modules/commons-lang --branch rel/commons-lang-3.12.0 --depth 1
    gradle --project-dir modules/commons-lang init
    gradle run

You can see the external transitive dependency `commons-lang` being replaced with the local project dependency by running:

    gradle app:dependencies --configuration runtimeClasspath