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.
  • Given configuration. Something that can optionally be supplied by the project, to turn on/off features.

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.
  • Violation, Java projects but with some small adjustments that I use in my violations-lib and its tools.
  • Gradle plugins.

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.
  • Relocate, shadow, dependencies into a fat jar.
  • Produce a changelog
  • Have Spotbugs, static code analysis, configured and optionally fail build based on violations found.
  • Be configured to publish artifacts to Maven Central (along with all POM requirements Central demands). Or any other Nexus server.

These features should be implemented so that I:

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

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.

--

--

--

http://tomasbjerre.se/

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Comparison of Javascript, HTML, and JAVA

How to Test the Availability of Your API Server

Tutorial: More on the MTurk API and the React Javascript Library (Part 2)

Announcing Bit with Angular Public Beta

Rich editor for your react typescript project using hooks

React and React Native

New in MicroStation CONNECT Edition Update 16.1 — Parametric Modeling

Angular Project Structure

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
Tomas Bjerre

Tomas Bjerre

http://tomasbjerre.se/

More from Medium

Avoiding Over-Design

Introduction to PWA & TWA

Common-Closure Principle (CCP)

How Mature Architecture Happens