October 14, 2010

Gradle Goodness: Set Task Values with Project Convention

In a previous post we wrote a custom task to generate a file with version information. When we created the task in our build file we had to provide values for the task properties version and outputFile. Now we want these values to have default values and we want to be able to set values with project properties instead of only task properties.

First we write a plugin where we create a new Plain Old Groovy Object (POGO) which will store the project properties in a convention object. Next we assign the values from the convention object properties to the task properties with a closure. This means the value of the properties are lazy set: only when the task gets executed the task property values are calculated.

Let's take a look at the source files for the plugin, POGO and task before we see what our new build script looks like.

// File: buildSrc/src/main/groovy/com/mrhaki/gradle/generate/GeneratePlugin.groovy
package com.mrhaki.gradle.generate

import org.gradle.api.Project
import org.gradle.api.Plugin

class GeneratePlugin implements Plugin<Project> {
    void apply(Project project) {
        def convention = new GeneratePluginConvention(project)
        project.convention.plugins.generate = convention

        project.tasks.withType(Generate.class).allTasks { Generate task ->
            task.conventionMapping.version = { convention.outputVersion ?: project.version }
            task.conventionMapping.outputFile = { convention.outputFile }
// File: buildSrc/src/main/groovy/com/mrhaki/gradle/generate/GeneratePluginConvention.groovy
package com.mrhaki.gradle.generate

import org.gradle.api.Project

class GeneratePluginConvention {
    final Project project
    String outputFilename
    String outputVersion

    public GeneratePluginConvention(Project project) {
        this.project = project
        this.outputFilename = 'version.txt'

    File getOutputFile() {
// File: buildSrc/src/main/groovy/com/mrhaki/gradle/generate/Generate.groovy
package com.mrhaki.gradle.generate

import org.gradle.api.internal.ConventionTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction

class Generate extends ConventionTask {
    String version

    File outputFile

    void generate() {
        def file = getOutputFile()
        if (!file.isFile()) {
        file.write "Version: ${getVersion()}"

Our build script has changed to:

// File: build.gradle
import com.mrhaki.gradle.generate.*

apply plugin: GeneratePlugin

version = '3.0'
// Or use explicit values:
// outputVersion = 'OUTPUT' 
// outputFilename = 'another-version.txt'

task generateVersionFile(type: Generate)

task showContents << {
    println generateVersionFile.outputFile.text
showContents.dependsOn generateVersionFile

The version property value of the Generate task is now set by either a project property outputVersion or the project version. And the outputFile property is assigned from the default version.txt or the value of the property property outputFilename.