This tutorial is followup of the gradle custom plugin tutorial part-1. If you haven’t gone through it yet, then I would recommend you to first read it in order to get the better context. In this tutorial we will cover the following topics.

  • Define custom Task class
  • Passing arguments to custom plugin task
  • Nested arguments
  • Testing the custom plugin

Project info :
Project name : Gradle custom plugin
Gradle version : 1.1
OS platform : Ubuntu 12.10
Prerequisite : Basic understanding of Gradle script.
Here, we will follow the same directory hierarchy listed in the first part.

  1. Define custom Task

    Let’s define a custom class named Code4ReferenceTask which extends DefaultTask class and put this file in the same folder where Code4ReferencePlugin.groovy is kept. This class contains a method named showMessage() which is annotated with @TaskAction. Gradle calls this method when the task is executed.

    package com.code4reference.gradle;
    
    import org.gradle.api.DefaultTask
    import org.gradle.api.tasks.TaskAction
    
    class Code4ReferenceTask extends DefaultTask {
    
        @TaskAction
        def showMessage() {
            println "----------showMessage-------------"
        }
    }
    

    Now we need to do some minor modifications in the Code4ReferencePlugin.groovy to include the custom task. The modified Code4ReferencePlugin class is as following.

    package com.code4reference.gradle;
    
    import org.gradle.api.*;
    
    class Code4ReferencePlugin implements Plugin {
        def void apply(Project project) {
               //Define the task named c4rTask of type Code4ReferenceTask
               project.task('c4rTask', type: Code4ReferenceTask)
        }
    }
    

    You may notice that only the highlighted line has been changed from the past implementation. Now the “c4rTask” is of Code4ReferenceTask type. Execute the gradle uploadArchives command in the plugin directory. This will update the jar file in Maven repo. Now execute the command below in user directory with the same old build.gradle. We will get the following output.

    $gradle c4rTask
    :c4rTask
    ----------showMessage-------------
    BUILD SUCCESSFUL
    
    Total time: 14.057 secs
    
  2. Passing arguments to custom plugin task

    The above implementation is the simplest one and doesn’t do much. What if we want to pass the arguments from Gradle script to this task? We can achieve it by accessing extension object. The Gradle Project has an associated ExtensionContainer object that helps keep track of all the settings and properties being passed to plugins class. Let’s define an extension class which can hold the arguments and pass those to the Task class. The highlighted lines in the Code4ReferencePlugin class help to pass the arguments to the Task class.

    package com.code4reference.gradle;
    
    import org.gradle.api.*;
    
    //For passing arguments from gradle script.
    class Code4ReferencePluginExtension {
        String message = 'Hello from Code4Reference'
        String sender = 'Code4Reference'
    }
    class Code4ReferencePlugin implements Plugin {
        def void apply(Project project) {
               project.extensions.create("c4rArgs", Code4ReferencePluginExtension)
               project.task('c4rTask', type: Code4ReferenceTask)
        }
    }
    

    We have defined Code4ReferencePluginExtension as Extension class which contains two variables message and sender. These serve as the arguments for the custom defined task. We need to modify the Code4RefernceTask class to access the arguments. The highlighted lines have been added to the previous Code4ReferenceTask class implementation.

    package com.code4reference.gradle;
    
    import org.gradle.api.DefaultTask
    import org.gradle.api.tasks.TaskAction
    
    class Code4ReferenceTask extends DefaultTask {
    
        @TaskAction
        def showMessage() {
            println "------------showMessage-------------------"
            println "From : ${project.c4rArgs.sender},\
                      message : ${project.c4rArgs.message}"
        }
    }
    

    Execute the gradle uploadArchives command in the plugin directory. This will update the jar file in Maven repo. Also, we need to update the build.gradle in the user directory.

    //custom-plugin-2/user
    buildscript {
        repositories {
            maven {
                url uri('../repo')
            }
        }
        dependencies {
            classpath group: 'com.code4reference',
                      name: 'code4ReferencePlugin',
                      version: '1.2-SNAPSHOT'
        }
    }
    
    apply plugin: 'code4reference'
    
    c4rArgs {
        sender = 'Rakesh'
        message = 'Hello there !!!!'
    }
    
    

    You may have noticed that c4rArgs closure has been added and sender and message variables are set in the closure. These two variables are accessible in the showMessage() method. Now run the build.gradle present in user directory. we get the following output.

    $gradle c4rTask
    :c4rTask
    -------------------------showMessage-----------------------------
    From : Rakesh, message : Hello there !!!!
    
    BUILD SUCCESSFUL
    
    Total time: 15.817 secs
    
  3. Nested arguments

    What if we want to pass the nested arguments? We can achieve this by nesting the Extension objects. Here is the code for Code4ReferencePlugin class. Only highlighted lines have been added in this class.

    package com.code4reference.gradle;
    
    import org.gradle.api.*;
    
    //Extension class for nested argumetns
    class C4RNestedPluginExtention {
         String receiver = "Admin"
         String email = "admin@code4reference.com"
    
     }
    //For keeping passing arguments from gradle script.
    class Code4ReferencePluginExtension {
        String message = 'Hello from Code4Reference'
        String sender = 'Code4Reference'
        C4RNestedPluginExtention nested = new C4RNestedPluginExtention()
    }
    class Code4ReferencePlugin implements Plugin {
        def void apply(Project project) {
               project.extensions.create("c4rArgs", Code4ReferencePluginExtension)
               project.c4rArgs.extensions.create("nestedArgs",C4RNestedPluginExtention)
               project.task('c4rTask', type: Code4ReferenceTask)
        }
    }
    
    

    It’s time to modify the Code4ReferenceTask class as well. Highlighted lines have been added in this class to access the nested arguments.

    package com.code4reference.gradle;
    
    import org.gradle.api.DefaultTask
    import org.gradle.api.tasks.TaskAction
    
    class Code4ReferenceTask extends DefaultTask {
    
        @TaskAction
        def showMessage() {
            println "------------showMessage-------------------"
            println "From : ${project.c4rArgs.sender},\
                     message : ${project.c4rArgs.message}"
            println "To : ${project.c4rArgs.nestedArgs.receiver},\
                     email : ${project.c4rArgs.nestedArgs.email}"
        }
    }
    

    Execute the gradle uploadArchives command again in the plugin directory to update the jar file in Maven repo. Now modify the build.gradle file present in user directory to pass the nested arguments.

    buildscript {
        repositories {
            maven {
                url uri('../repo')
            }
        }
        dependencies {
            classpath group: 'com.code4reference',
                      name: 'code4ReferencePlugin',
                      version: '1.2-SNAPSHOT'
        }
    }
    
    apply plugin: 'code4reference'
    
    c4rArgs {
        sender = 'Rakesh'
        message = 'Hello there !!!!'
    
        nestedArgs{
           receiver = "gradleAdmin"
           email = "gradleAdmin@code4reference.com"
        }
    }
    
    

    We have added the highlighted line in the build.gradle file.

  4. Testing plugin and task

    Testing of code is an important aspect of code development. Now we are going to add the unit test for the custom task and plugin. For this, we need to create the directory structure for the test classes. We need to put the test folder in the src directory. Execute the command below in plugin directory to create the test directories.

    $mkdir -p src/test/groovy/com/code4reference/gradle/
    

    Test directory structure follows the same package directory structure which has been used for source code package directory. In this directory, put the test classes for Code4ReferencePlugin and Code4ReferenceTask. In test class, ProjectBuilder is used to access the project object. These test cases are easy to write, similar to the Junit test cases. The code of test classes is as following:

    package com.code4reference.gradle;
    
    import org.junit.Test
    import org.gradle.testfixtures.ProjectBuilder
    import org.gradle.api.Project
    import static org.junit.Assert.*
    
    class Code4ReferenceTaskTest {
        @Test
        public void canAddTaskToProject() {
            Project project = ProjectBuilder.builder().build()
            def task = project.task('c4rtakstest', type: Code4ReferenceTask)
            assertTrue(task instanceof Code4ReferenceTask)
        }
    }
    
    package com.code4reference.gradle;
    
    import org.junit.Test
    import org.gradle.testfixtures.ProjectBuilder
    import org.gradle.api.Project
    import static org.junit.Assert.*
    
    class Code4ReferencePluginTest {
        @Test
        public void code4referencePluginAddsCode4ReferenceTaskToProject() {
            Project project = ProjectBuilder.builder().build()
            project.apply plugin: 'code4reference'
            println "code4referencePluginAddsCode4ReferenceTaskToProject"
            assertTrue(project.tasks.c4rTask instanceof Code4ReferenceTask)
        }
    }
    

    To run the test, execute the following command in plugin folder.

    $gradle test                #For success test cases.
    :compileJava UP-TO-DATE
    :compileGroovy UP-TO-DATE
    :processResources UP-TO-DATE
    :classes UP-TO-DATE
    :compileTestJava UP-TO-DATE
    :compileTestGroovy
    :processTestResources UP-TO-DATE
    :testClasses
    :test
    
    BUILD SUCCESSFUL
    
    Total time: 42.799 secs
    
    $gradle test    #In case of test case failure,
                    #you can expect output similar to given below.
    :compileJava UP-TO-DATE
    :compileGroovy UP-TO-DATE
    :processResources UP-TO-DATE
    :classes UP-TO-DATE
    :compileTestJava UP-TO-DATE
    :compileTestGroovy
    :processTestResources UP-TO-DATE
    :testClasses
    :test
    
    com.code4reference.gradle.Code4ReferencePluginTest > code4referencePluginAddsCode4ReferenceTaskToProject FAILED
        java.lang.AssertionError at Code4ReferencePluginTest.groovy:14
    
    2 tests completed, 1 failed
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':test'.
    > There were failing tests. See the report at: file:///home/rakesh/programming/mygitrepo/Code4Reference/GradleExample/custom-plugin-2/plugin/build/reports/tests/index.html
    
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
    
    BUILD FAILED
    
    

    Gradle test provides the test report and its location. This file can be opened using any browser to examine the stack trace.

you can find the custom-plugin part 2 source code here.
Please feel free to comment on the post or the website.

,
Trackback

4 comments untill now

  1. Tim Goeke @ 2012-09-05 12:23

    Thanks Rakesh, very helpful samples!

  2. Hi Rakesh,

    many thanks for this comprehensive series! Are you planning to write some more gradle plugin episodes?

    Kind regards,
    Sebastian

  3. Ramesh Pasham @ 2013-04-25 09:18

    Clearly explained Rakesh ..

    Regards,
    Ramesh Pasham

  4. I am working on the gradle.

    But i want to know if i can combine the task and extension in the 2 step?

    project.extensions.create(“c4rArgs”,Code4ReferencePluginExtension);
    project.task(‘c4rTask’, type: Code4ReferenceTask);

    I want to pass the argument via c4rTask instead of using c4rArgs.

Add your comment now