1.1 Composite Builds

Authored by Atri

Sometimes there might be situations where you are working on a project that is made up of multiple libraries managed by yourself or your team. In situations like this, you might want to test how a change in one project will affect another project without deploying updates to an artifact repository. This is where the concept of Gradle composite builds comes into play.

Enabling Composite Builds

Composite builds are a concept which we use to describe a project which is made from multiple separated projects. This is typically beneficial for testing changes as previously mentioned. To enable these, its typically recommended you define your compositions in your settings.gradle or settings.gradle.kts file. For the purposes of this guide, we will be relying on the kts file definition.

// Functions
fun composite(block: () -> Unit) {
	if (File(".composite-enabled").exists()) {
		block()
	}
}

fun useLocal(
	module: String,
	projectName: String = module.substringAfter(":"),
) {
	includeBuild("../$projectName") {
		dependencySubstitution {
			substitute(module(module)).using(project(":"))
		}
	}
}

// Usage
composite {
	// For modules with the same project name
	useLocal("com.example:module")
	// For modules where the project name differs from the module name
	useLocal("com.example:other-module", "other-module-project")
}
Note

This function will search the parent directory of the current project for the local build, if you use this function as written you will need to make sure both this project and the dependency project are stored in the same directory as each other.

Extending Composite Support

If you want to take things a step further, it is possible to write custom Bash commands that you can use to generate or delete composite files for you. This works best if you work in a terminal environment which supports defining custom commands like ZSH.

Note

Put the following code in your .zshrc file, or whichever config file is used for your shell.

# Enables composition in current directory 
composite() {
	echo > .composite-enabled
}

# Disables composition in current directory
decomposite() {
	rm -f .composite-enabled
}

# Enables composition for all directories in the current working directory
composite-all() {
	for dir in ./*/; do
		cd $dir
		composite
	done
	cd -
}

# Disables composition for all directories in the current working directory
decomposite-all() {
	for dir in ./*/; do
		cd $dir
		decomposite
	done
	cd -
}

By running these commands in your terminal, you can set up composition for one or many projects at the same time. As long as these commands are also present in your environment, you may also set these up as part of automated tasks, these can be configured in many build systems including Gradle, as well as NPM, and Make,