Loading...

October 26, 2012

Gradle Goodness: Distribute Custom Gradle in Our Company

The Gradle wrapper allows us to let developers use Gradle without the need for every developer to install Gradle. We can add the output of the Gradle wrapper task to version control. Developers only need to checkout the source for a project and invoke the gradlew or gradlew.bat scripts. The scripts will look for a Gradle distribution and download it to the local computer of a developer. We can customize the Gradle wrapper and provide a different source for the Gradle distribution. For example we can add the Gradle distribution ZIP file on our company intranet. We then use the distributionUrl property of the Wrapper task to reference the intranet location where we place the Gradle distribution ZIP file.

In the following sample file we use the distributionUrl property to reference our company intranet:

task createWrapper(type: Wrapper) {
    distributionUrl = 'http://intranet/tools/gradle-1.2-bin.zip'
}

When we execute the createWrapper task the wrapper script files and supporting files are created in the project directory. It is fine to remove the createWrapper task from the build file. If we want to change the location of the Gradle distribution ZIP file or if the version changes we change the file gradle/wrapper/gradle-wrapper.properties. This file has a key distributionUrl. We can change the value of this key, save the file, add it to version control. If other developers checkout the project the new Gradle distribution location is used and they will use the Gradle version we want them to use.

In a previous post we saw an initialization or init script that could be applied for all projects that are developed in our company. To distribute this script we can customize the Gradle distribution, put it on our company intranet and use the Gradle wrapper properties to reference this customized Gradle distribution. It turns out it is very easy to create a customized Gradle distribution with custom init scripts, plugin code, classpath extensions or anything else that can be part of a Gradle distribution. The code in this post is based on the samples from Luke Daley's presentation at SpringOne 2GX 2012. These samples can be found at Github.

In the following build file we customize a default Gradle distribution. First the Gradle distribution ZIP file for a specific Gradle version is downloaded. We create a new custom Gradle distribution ZIP file with a custom version number based on the downloaded ZIP file. We add a init script from the src/scripts/init.d directory. We can add also other files like JAR files to the custom Gradle distribution ZIP file. We have applied the base plugin and therefore can use configurations. We also reconfigure the uploadCompanyGradle task so we can use SCP to copy the resulting Gradle ZIP file to our company intranet webserver.

// Base plugin adds configuration
// support and build<Configuration> 
// and upload<Configuration> tasks.
apply plugin: 'base'

// Version is the version of the
// company Gradle. This can be independent
// of the Gradle version.
version = '1.0.2'

ext {
    // Gradle version to use as template for 
    // the custom Gradle distribution.
    gradleVersion = '1.2'
}

// Extra configuration to store
// company Gradle ZIP artifact and
// use for uploading.
configurations {
    companyGradle    
}


task downloadGradle(type: DownloadGradle) {
    description 'Download Gradle version from Gradle distributions website'

    gradleVersion project.gradleVersion
    destinationDir file("$buildDir/gradle-downloads")
}

task companyGradleZip(type: Zip, dependsOn: downloadGradle) {
    description 'Add extra files to company Gradle distribution'

    // Name for company Gradle ZIP distribution.
    baseName = 'company-gradle'
    classifier = 'bin'

    from zipTree(downloadGradle.destinationFile)
    into("${downloadGradle.distributionNameBase}") {
        into('init.d') {
            from "src/scripts/init.d"
        }
        // We can do extra stuff here 
        // to add to the company Gradle
        // distribution ZIP file.
    }    
}

artifacts {
    companyGradle companyGradleZip
}

// Configure upload task for company
// Gradle distribution ZIP.
uploadCompanyGradle {
    repositories {
        // Add SSH resolver to copy the resulting
        // company Gradle distribution to the 
        // company webserver.
        // user and userPassword are defined in external
        // gradle.properties file.
        add(new org.apache.ivy.plugins.resolver.SshResolver()) {
            name = 'company-intranet'           
            user = intranetUsername         
            userPassword = intranetPassword
            host = 'intranet'

            addArtifactPattern "/Library/WebServer/Documents/tools/[artifact]-[revision]-[classifier].[ext]"           
        }
    }
    uploadDescriptor = false

    // We can also use Maven repositories
    // (or other custom repositories) to upload.
}


class DownloadGradle extends DefaultTask {
    @Input 
    String gradleVersion
    
    @Input 
    File destinationDir
    
    @Input 
    String gradleDownloadBase = "http://services.gradle.org/distributions"

    @TaskAction 
    doDownloadGradle() {
        destinationFile.bytes = new URL(downloadUrl).bytes
    }

    String getDownloadUrl() {
        "$gradleDownloadBase/$downloadFileName"
    }

    String getDistributionNameBase() {
        "gradle-$gradleVersion"
    }

    String getDownloadFileName() {
        "$distributionNameBase-bin.zip"
    }

    @OutputFile 
    File getDestinationFile() {
        new File(destinationDir, downloadFileName)
    }
}

We create a very simple init script in the directory src/scripts/init.d. This file is added to the init.d directory of our company Gradle distribution. Files in this directory are automatically executed.

// File: src/scripts/init.d/sample.gradle
println "You are running the build with the Company Gradle"

In a project where we want to use the company Gradle distribution we either set the distributionUrl property of the Wrapper task or change the property distributionUrl in the file gradle/wrapper/gradle-wrapper.properties.

# File: gradle/wrapper/gradle-wrapper.properties
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=http://intranet/tools/company-gradle-1.0.2-bin.zip

When we use the gradlew script for the first time our company Gradle distribution ZIP file is downloaded and extracted. Notice the line "You are running the build with the Company Gradle" in the output from the sample.gradle init script.

$ ./gradlew tasks
Downloading http://intranet/tools/company-gradle-1.0.2-bin.zip
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
....................
Unzipping /Users/mrhaki/.gradle/wrapper/dists/company-gradle-1.0.2-bin/6scnmmqpv8l6j6f30lud9v9o6o/company-gradle-1.0.2-bin.zip to /Users/mrhaki/.gradle/wrapper/dists/company-gradle-1.0.2-bin/6scnmmqpv8l6j6f30lud9v9o6o
Set executable permissions for: /Users/mrhaki/.gradle/wrapper/dists/company-gradle-1.0.2-bin/6scnmmqpv8l6j6f30lud9v9o6o/gradle-1.2/bin/gradle
You are running the build with the Company Gradle
:tasks

------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------

Help tasks
----------
dependencies - Displays the dependencies of root project 'simple-project'.
help - Displays a help message
projects - Displays the sub-projects of root project 'simple-project'.
properties - Displays the properties of root project 'simple-project'.
tasks - Displays the tasks runnable from root project 'simple-project' (some of the displayed tasks may belong to subprojects).

Other tasks
-----------
wrapper

To see all tasks and more detail, run with --all.

BUILD SUCCESSFUL

Total time: 3.643 secs

We have seen how easy it is to distribute Gradle in our company. Even customizing the distribution ZIP file is easy to do and will ensure all developers share the same (customized) Gradle version and use the same configuration.

Code written with Gradle 1.2

The code is available at Github.