:samples-dir: /home/tcagent1/agent/work/64493a816be20d5a/promote-projects/gradle/build/git-checkout/platforms/documentation/docs/build/working/samples/install/composite-builds-hierarchical-multirepo
:gradle-version: 9.2.0-rc-1

= Composite Builds Hierarchical Multirepo Sample

[.download]
- link:zips/sample_composite_builds_hierarchical_multirepo-groovy-dsl.zip[icon:download[] Groovy DSL]
- link:zips/sample_composite_builds_hierarchical_multirepo-kotlin-dsl.zip[icon:download[] Kotlin DSL]

NOTE: You can open this sample in an link:{userManualPath}/gradle_ides.html#gradle_ides[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:

====
include::sample[dir="kotlin",files="settings.gradle.kts[tags=include_builds]"]
include::sample[dir="groovy",files="settings.gradle[tags=include_builds]"]
====

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:

====
include::sample[dir="kotlin",files="build.gradle.kts"]
include::sample[dir="groovy",files="build.gradle"]
====

=== 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
```
