A sustainable pattern with Gradle

This is a highly configurable pattern that I’ve applied to Gradle. I describe how I scale Gradle, avoid duplicated Gradle code and do feature toggling.

I previously blogged about A sustainable pattern with Jenkins. This is that same pattern, but applied to Gradle. The basic idea is that you have:

  • Default configuration. Something that works for most projects.

Everything here is available in this repository:
https://github.com/tomasbjerre/gradle-scripts

This is an ongoing project. When you read this it may have changed, so check the code for latest details. But the general idea, described here, will not change.

The problem

I can divide my projects into 3 different types:

  • Java projects, typically a library.

The Gradle plugins should be published to Maven Central and Gradle Plugin Portal. The Java projects should be published to Maven Central.

All projects should optionally:

  • Be signed with PGP.

These features should be implemented so that I:

  • Don’t need to duplicate Gradle code in all my projects.

The solution

I create a Gradle script (main.gradle) that I package into a JAR. I release that JAR to Maven Central. I let the projects add that JAR to classpath, and apply the main.gradle from within that JAR.

The main.gradle has a defaultConfig that is basically a map with a bunch of configuration options.

The build.gradle in a project, can supply a buildConfig, it may look something like this:

apply plugin: 'java'

buildscript {
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
classpath 'se.bjurr.gradle:gradle-scripts:2.+'
}
}
project.ext.buildConfig = [
// Your can supply a given config here, a subset of defaultConfig.
]
apply from: project.buildscript.classLoader.getResource('main.gradle').toURI()
dependencies {
// Dependencies of the project here just like you would in any other project
}

The main.gradle will merge its defaultConfig with given buildConfig creating an effectiveConfig that is used throughout the main.gradle script.

My entire defaultConfig is available in the code. Here is a reduced version:

def defaultConfig = [
repoType: "DEFAULT",
staticCodeAnalysis: [
maxViolations: 9999,
],
publishing: [
mavenRepositoryUrl: 'https://oss.sonatype.org/service/local/staging/deploy/maven2/',
nexusCloseAndRelease: true,
sign: true,
relocate: [],
],
gradlePlugin: [
tags: []
],
changelog: [
enabled: true,
],
]

This means I can get the default behavior in my project if I just do:

project.ext.buildConfig = []
apply from: project.buildscript.classLoader.getResource('main.gradle').toURI()

I can also change it, to match my Violation needs, if I do:

project.ext.buildConfig = [
repoType: "VIOLATIONS",
publishing: [
relocate: [
'com.google',
'com.jakewharton'
]
]
]
apply from: project.buildscript.classLoader.getResource('main.gradle').toURI()

Or change it, to match my Gradle plugin needs, if I do:

project.ext.buildConfig = [
repoType: "GRADLE",
gradlePlugin: [
tags: ['violation', 'static code analysis', 'Checkstyle']
],
]
apply from: project.buildscript.classLoader.getResource('main.gradle').toURI()

Closure

Pull requests are very much welcome in the repo:
https://github.com/tomasbjerre/gradle-scripts
My intention is that not only I should be able to use this script.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store