How to manage dependencies in a Gradle multi-project build
Iāve been aĀ fanĀ of the Gradle build tool from quite early on. ItsĀ potential was clear even before the 1.0 version, whenĀ changesĀ were regularly breaking. Today,Ā upgrading rarely cause surprises. The tool has becomeĀ mature and performs well.
Gradle includes aĀ powerful dependency managementĀ system that can work with Maven and Ivy repositories as well as local file system dependencies.
During my work with Gradle Iāve come to rely onĀ a pattern for managing dependencies in a multi-project build that I want to share. This pattern consists of twoĀ key practices:
- Centralize dependency declarations in
build.gradle - Centralize dependency version declarations in
gradle.properties
Both practices are examples of applyingĀ software development best practices like DRYĀ to the code that makes up the Gradle build. Letās look at them in some more detail.
Centralize dependency declarations
In the root projectās build.gradle file,Ā declare a new configuration for each dependency used in the entire project. In each sub-project that uses the dependency, declare that the compile (or testCompile, etc) configuration extends the configuration for the dependency:
Root project build.gradle
subprojects {
configurations {
commonsIo
}
dependencies {
commonsIo 'commons-io:commons-io:2.5'
}
}Sub-project build.gradle
configurations {
compile.extendsFrom commonsIo
}By putting all dependencyĀ declarations in a single place, we know where to look and we prevent multiple sub-projects from declaring the same dependency with different versions.
Furthermore, the sub-projects are now more declarative, specifying onlyĀ whatĀ logical components they depend on, rather than all the details ofĀ how a component is built up from individual jar files.Ā When there is a one-to-one correspondence, as in the commons IO example, thatās not such a big deal, butĀ the difference is pronounced when working with components that are made up of multiple jars, like the Spring framework or Jetty.
Centralize dependency version declarations
The next step is to replaceĀ all the version numbers from the root projectāsbuild.gradle file by properties defined in the root projectās
gradle.properties:
build.gradle
dependencies {
commonsIo "commons-io:commons-io:$commonsIoVersion"
}gradle.properties
commonsIoVersion=2.5
This practice allows you to reuse the version numbers for related dependencies. For instance, if youāre using theĀ Spring framework, you may want to declare dependencies on spring-mvcĀ and spring-jdbcĀ with the same version number.
There is an additional advantage of this approach. Upgrading a dependency means updating gradle.properties, while adding a new dependency means updating build.gradle. This makes it easy to gaugeĀ from a commit feed what types of changes could have been made and thus to determine whether a closer inspection is warranted.
You can take thisĀ a step further and put the configurations anddependencies blocks in a separate file, e.g. dependencies.gradle.
And beyondā¦
Having all the dependencies declared in a single location is aĀ stepping stone to more advanced supply chain management practices.
The centrally declared configurations giveĀ a good overview of all the components that you use in your product, the so-called Bill of MaterialsĀ (BOM). You can use the above technique, or useĀ the Gradle BOM plugin.
The BOM makes it easier to use a tool likeĀ OWASP DependencyCheck to check for publicly disclosed vulnerabilities in the dependencies that you use. At EMC, about 80% of vulnerabilities reported against our products are caused by issues in 3rd party components, so it makes sense to keep a security eye on dependencies.
A solid BOM also makes it easier to review licenses and their compliance requirements. If you canāt afford a tool like BlackDuck Protex, you canĀ write something less advanced yourself with modestĀ effort.
| Reference: | How to manage dependencies in a Gradle multi-project build from our JCG partner Remon Sinnema at the Secure Software Development blog. |


what if have more than one common dependencies?