Composite Build

A composite build is similar to a Gradle multi-project build, except that instead of including subprojects, entire builds are included.

Question: What does it mean to say entire build?

In Short

  • Each included project:
    • Has its own settings.gradle.kts (settings.gradle.kts) and build.gradle.kts.
    • Has its own lifecycle, versioning, dependencies, and configuration.

GPT Response

In Gradle, a composite build is a build setup that allows multiple independent Gradle builds to be combined and work together. When you include an "entire build" in a composite build, it means that instead of breaking a project into sub-projects under one unified build, you are combining separate, independent builds. Each of these builds typically has its own settings.gradle.kts, build.gradle.kts, and its own lifecycle, versioning, dependencies, and configuration.

In contrast, in a multi-project build, all sub-projects share the same build lifecycle and configuration defined by the root project’s settings.

Key Differences:

  • Multi-project build: Sub-projects are included in a single, unified build managed by the root project.
  • Composite build: Entire independent builds (including their configurations and dependencies) are combined and linked together, allowing them to interact without merging them into a single build.

When to Use a Composite Build:

  • You have independent projects that need to work together (for example, different services or libraries that have their own lifecycle but need to be tested or built together).
  • You want to keep independent versioning and releases for projects but still benefit from Gradle’s ability to share outputs and dependencies across builds.

This feature is useful in large-scale environments where multiple teams might maintain different parts of a system or different libraries, but need to integrate them for a specific build or deployment without tightly coupling them as sub-projects.

Question: Can composite build include another composite build?: Somewhat supported

Yes, a composite build can include another composite build in Gradle, but there are some limitations to consider. Gradle allows you to include other builds using includeBuild, which links external builds into your project. However, when dealing with nested composite builds (where one composite build includes another), it's important to note that Gradle does not allow recursively nesting composite builds by default.

In other words:

  • You can include multiple independent builds into a composite build.
  • Nested composite builds (one composite build including another composite build) are NOT fully supported and could lead to issues with dependency resolution and configuration. (according to GPT)

Key Points:

  • Flat structure: It’s recommended to keep a flat structure when using composite builds, where each composite build includes independent projects directly.
  • Workaround: If you need to link multiple composite builds, you might need to manage them manually or rely on external tools, but this requires careful consideration of dependencies and task executions.

You can learn more about this in the official Gradle documentation on composite builds.

From official documentation:

When a composite build is included in another composite build, both builds have the same parent. In other words, the nested composite build structure is flattened. - ref

Official Example

From docs.gradle.org/sample_composite_builds_basics.html.

Glass thought Sandbox Snapshot

Command to reproduce:

gt.sandbox.checkout.commit fd396501a86b5a565736 \
&& cd "${GT_SANDBOX_REPO}/sample_composite_builds_basics-kotlin-dsl" \
&& cmd.run.announce "cd ${GT_SANDBOX_REPO:?}/sample_composite_builds_basics-kotlin-dsl && ./gradlew build"

Recorded output of command:


> Task :buildEnvironment
Daemon JVM: Homebrew JDK 17.0.12+0
  | Location:           /opt/homebrew/Cellar/openjdk@17/17.0.12/libexec/openjdk.jdk/Contents/Home
  | Language Version:   17
  | Vendor:             Homebrew
  | Architecture:       aarch64
  | Is JDK:             true


------------------------------------------------------------
Root project 'my-composite'
------------------------------------------------------------

classpath
No dependencies

A web-based, searchable dependency report is available by adding the --scan option.

BUILD SUCCESSFUL in 429ms
1 actionable task: 1 executed


#to-review (Private):

Multi-Project Build Setup in Gradle: Focusing on Composite Builds

Purpose:

A multi-project build in Gradle allows developers to organize and manage large codebases by breaking them into smaller, logically separated modules or projects. This setup enhances modularity, enabling better collaboration, faster builds, and more manageable maintenance of large systems.

A specific aspect of multi-project builds is Composite Builds, which enable combining multiple independent builds into a unified one, while retaining the independence of the individual projects.

Key Concepts of Multi-Project Builds:

In Gradle, a multi-project build setup can be categorized into two types:

  1. Traditional Multi-Project Build: A single Gradle project hierarchy where multiple subprojects share the same root settings.gradle.
  2. Composite Builds: Allows integrating separate, independent Gradle builds together to work as a single build, without merging them into a single repository or file structure.

Composite Builds Approach:

1. What Are Composite Builds?

A Composite Build in Gradle refers to a setup where you combine multiple independent Gradle builds into one. Unlike a traditional multi-project build, composite builds do not require the projects to reside in the same repository or share a single root. This flexibility makes them ideal for situations where you need to combine different projects temporarily or retain autonomy over separate codebases.

2. Why Use Composite Builds?
  • Separation of Concerns: Each project can exist independently, but when required, multiple projects can work together.
  • Development Efficiency: You can work on multiple related projects without switching repositories.
  • Dependency Substitution: Composite builds allow for dependency substitution, meaning you can substitute a binary dependency with a source dependency, reducing the need for artifact publication during development.
3. How Composite Builds Work

In composite builds, Gradle allows you to combine multiple independent builds by including them in a single root project’s settings.gradle file. This is achieved by linking them with the includeBuild directive, which adds these separate builds into the root project's build logic.

// Root Project settings.gradle

includeBuild('../some-other-project')

This simple inclusion means that tasks and dependencies across builds can now interact as if they were part of the same build hierarchy.

4. Composite Builds vs Traditional Multi-Project Builds

In traditional multi-project builds, projects are physically located under the same root directory, and they share common configuration files (settings.gradle and build.gradle). Conversely, composite builds allow projects to stay in their original repositories or directories, preserving their independence. Composite builds avoid the complexity of merging repositories, and the projects can be developed and maintained separately.

5. Advantages of Composite Builds
  • Independent Version Control: Projects in a composite build can remain in separate repositories with their own version control.
  • Collaboration Between Projects: Composite builds allow developers to work across multiple independent projects without needing to merge them into one repository.
  • Avoiding Binary Dependencies: During development, instead of relying on published binaries, you can substitute them with local source dependencies using composite builds. This reduces the overhead of publishing artifacts and enables faster iteration.
6. Configuring Dependency Substitution

Composite builds enable dependency substitution, which means you can replace a binary dependency (usually a published artifact) with a source dependency during development. This feature is highly beneficial when working on related projects across repositories.

For example, suppose projectA depends on projectB. You can substitute the published dependency of projectB with its source by specifying:

// Root project build.gradle

dependencies {
    implementation('com.example:projectB:1.0') // The binary dependency

    // In development, substitute with source
    components {
        withModule('com.example:projectB') {
            all { componentMetadata ->
                componentMetadata.status = 'integration'
            }
        }
    }
}

With composite builds, you can avoid publishing the binary and instead link projectB as a local project dependency.

7. Composite Builds in Practice: Example

Assume we have two independent projects, library-project and app-project, in separate repositories. You are working on app-project, which depends on a library that library-project provides.

  • Without composite builds, you would need to publish library-project as a binary dependency, and app-project would need to fetch it from a repository.
  • With composite builds, you can work on library-project in tandem with app-project without publishing the library every time.

To achieve this:

  1. In the app-project, modify the settings.gradle file:

    // app-project/settings.gradle
    includeBuild('../library-project') // Including the library as a composite build
    
  2. Now, Gradle will recognize that instead of fetching the published library-project dependency, it can use the source from the included build.

This approach significantly simplifies development when you're working on multiple related projects simultaneously, eliminating the need for constant publishing.

8. Running Composite Builds

To run tasks across composite builds, Gradle allows you to execute them just like any other task. For instance, you can run a build for both the app-project and library-project together:

gradle build

Gradle will detect the included build and execute all necessary tasks across the projects.

Conclusion:

Composite builds in Gradle offer a powerful mechanism for working across multiple independent projects, without sacrificing autonomy or requiring extensive repository merges. By allowing dependency substitution and enabling collaboration between independent builds, composite builds are essential for managing large-scale, interconnected systems in a modular and efficient way.


Children
  1. Example
  2. Gpt Generated
  3. Question: Can composite build include another composite build? (Nested Composite Builds)
  4. Ref

Backlinks