Gradle Plugin Goodness
@BRWNGRLDEV
@BRWNGRLDEV
apply plugin: 'checkstyle'

apply plugin: 'findbugs'

apply plugin: 'pmd'



task checkstyle(type: Checkstyle) {

description 'Checks if the code is somewhat acceptable'

group 'verification'



configFile file('./qa-check/checkstyle.xml')

source 'src'

include '**/*.java'

exclude '**/gen/**'



classpath = files()

ignoreFailures = false

}



task findbugs(type: FindBugs) {

apply plugin: 'checkstyle'

apply plugin: 'findbugs'

apply plugin: 'pmd'



task checkstyle(type: Checkstyle) {

description 'Checks if the code is somewhat acceptable'

group 'verification'



configFile file('./qa-check/checkstyle.xml')

source 'src'

include '**/*.java'

exclude '**/gen/**'



classpath = files()

ignoreFailures = false

}



task findbugs(type: FindBugs) {

description 'Run findbugs'

group 'verification'



classes = files("$project.buildDir/intermediates/classes")

source 'src'

classpath = files()



effort 'max'

excludeFilter file('./qa-check/findbugs-exclude.xml')



reports {

xml.enabled = true

html.enabled = false

}



ignoreFailures = true

}



task pmd(type: Pmd) {

description 'Run PMD'

group 'verification'



ruleSetFiles = files("./qa-check/pmd-ruleset.xml")

ruleSets = []



source 'src'

include '**/*.java'

exclude '**/gen/**'



reports {

xml.enabled = false

html.enabled = true

}



ignoreFailures = true

}
apply plugin: 'info.adavis.qualitychecks'
OVERVIEW
▸Plugin Skeleton
▸Dependencies
▸Plugin.groovy
▸CustomTask.groovy
▸Publishing
@BRWNGRLDEV
PLUGIN SKELETON
@BRWNGRLDEV
PLUGIN SKELETON
@BRWNGRLDEV
PLUGIN SKELETON
@BRWNGRLDEV
PLUGIN SKELETON
How Gradle finds the Plugin Implementation
@BRWNGRLDEV
PLUGIN SKELETON
implementation-class=info.adavis.qualitychecks.QualityChecksPlugin
@BRWNGRLDEV
DEPENDENCIES
@BRWNGRLDEV
DEPENDENCIES
apply plugin: ‘groovy'
dependencies {
compile gradleApi()
compile localGroovy()
}
@BRWNGRLDEV
DEPENDENCIES
dependencies {
…
testCompile 'junit:junit:4.12'

testCompile ('org.spockframework:spock-core:1.0-groovy-2.4') {

exclude module: 'groovy-all'

}
}
@BRWNGRLDEV
THE CODE
@BRWNGRLDEV
BUT FIRST…
@BRWNGRLDEV
GRADLE BUILD
@BRWNGRLDEV
PROJECT
TASK TASK TASK
BUILD
GRADLE BUILD
@BRWNGRLDEV
PROJECT
TASK TASK TASK
BUILD
PROJECT
TASK TASK TASK
PLUGIN.GROOVY
class CustomPlugin implements Plugin<Project> {
}
@BRWNGRLDEV
PLUGIN.GROOVY
class CustomPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
}
}
@BRWNGRLDEV
QUALITYCHECKSPLUGIN.GROOVY
@BRWNGRLDEV
APPLY METHOD
@BRWNGRLDEV
void apply(Project project) {

this.project = project



}
APPLY METHOD
@BRWNGRLDEV
void apply(Project project) {

this.project = project



project.extensions.create('qualityChecks', QualityChecksExtension)



}
APPLY METHOD
@BRWNGRLDEV
void apply(Project project) {

this.project = project



project.extensions.create('qualityChecks', QualityChecksExtension)



createConfigFilesIfNeeded()

createConfigFileTasks()

createQualityChecksTasks()

}
PROJECT EXTENSION
@BRWNGRLDEV
class QualityChecksExtension {



String pmdConfigFile = 'quality-checks/pmd-ruleset.xml'



String checkstyleConfigFile = 'quality-checks/checkstyle.xml'



String findBugsExclusionFile = 'quality-checks/findbugs-exclude.xml'



}
PROJECT EXTENSION
@BRWNGRLDEV
class QualityChecksExtension {



String pmdConfigFile = 'quality-checks/pmd-ruleset.xml'



String checkstyleConfigFile = 'quality-checks/checkstyle.xml'



String findBugsExclusionFile = 'quality-checks/findbugs-exclude.xml'



}
PROJECT EXTENSION
Back in the application’s build.gradle file…
@BRWNGRLDEV
qualityChecks {

pmdConfigFile = ‘checks/pmd.xml’
checkstyleConfigFile = ‘checks/checkstyle.xml’

}
PROJECT EXTENSION
Back in the application’s build.gradle file…
@BRWNGRLDEV
qualityChecks {

pmdConfigFile = ‘checks/pmd.xml’
checkstyleConfigFile = ‘checks/checkstyle.xml’

}
TASKS
@BRWNGRLDEV
CREATING TASKS
Give it a name and a type
@BRWNGRLDEV
CREATING TASKS
@BRWNGRLDEV
▸Build on existing task
▸Extend the DefaultTask
BUILD ON EXISTING TASK
@BRWNGRLDEV
BUILD ON EXISTING
@BRWNGRLDEV
EXTEND DEFAULT TASK
@BRWNGRLDEV
CUSTOMTASK.GROOVY
class CustomTask extends DefaultTask {
CustomTask() {
group: ‘verification’
}
}
@BRWNGRLDEV
CUSTOMTASK.GROOVY
class CustomTask extends DefaultTask {
CustomTask() {
group: ‘verification’
}
}
@BRWNGRLDEV
CUSTOMTASK.GROOVY
CustomTask() {
group: ‘verification’
onlyIf {
// skip under certain conditions
}
}
@BRWNGRLDEV
CUSTOMTASK.GROOVY
@TaskAction
def defaultAction() {
description: ‘What my task does’
}
@BRWNGRLDEV
CUSTOMTASK.GROOVY
@BRWNGRLDEV
@TaskAction
def defaultAction() {
description: ‘What my task does’
<do your cool stuff here>
}
GRADLE TASK DOCUMENTATION
@BRWNGRLDEV
SO FAR…
▸Plugin Skeleton
▸Dependencies
▸Plugin.groovy
▸CustomTask.groovy
@BRWNGRLDEV
PUBLISHING
@BRWNGRLDEV
PUBLISHING
@BRWNGRLDEV
PUBLISHING
buildscript {
…
dependencies {
classpath "com.gradle.publish:plugin-publish-plugin:0.9.4"
}
}
apply plugin: 'com.gradle.plugin-publish'
@BRWNGRLDEV
PUBLISHING
version = "0.1.3"
group = "info.adavis"
@BRWNGRLDEV
PUBLISHING
pluginBundle {
website = 'https://github.com/adavis/quality-checks'
vcsUrl = 'https://github.com/adavis/quality-checks.git'
description = 'Gradle Plugin for…’
tags = ['Checkstyle', 'FindBugs', 'PMD']
}
@BRWNGRLDEV
PUBLISHING
pluginBundle {
…
plugins {
qualityChecksPlugin {
id = 'info.adavis.qualitychecks'
displayName = 'Quality Checks Plugin'
}
}
@BRWNGRLDEV
@BRWNGRLDEV
@BRWNGRLDEV
WE’RE DONE…
WRONG!
@BRWNGRLDEV
WE’RE DONE…
TESTS
@BRWNGRLDEV
TESTING - WITH JUNIT
@Before

void setUp() {

projectDir = temporaryFolder.root

projectDir.mkdirs()





}
@BRWNGRLDEV
TESTING - WITH JUNIT
@Before

void setUp() {

projectDir = temporaryFolder.root

projectDir.mkdirs()



project = ProjectBuilder.builder().withProjectDir(projectDir).build()

task = project.tasks.create('writeConfigFile', WriteConfigFileTask)

}
@BRWNGRLDEV
TESTING - WITH JUNIT
@Test
void shouldBeAbleToCreateTask() {
assertTrue(task instanceof WriteConfigFileTask)
}
@BRWNGRLDEV
TESTING - WITH JUNIT
@Test
void pluginShouldBeApplied() {
project.apply(plugin: QualityChecksPlugin)
assertNotNull(project.tasks.findByName(‘mytask’))
}
@BRWNGRLDEV
SPOCK
@BRWNGRLDEV
TESTING - WITH SPOCK
def createCheckstyleTask() {

given: "we have a project"

def project = ProjectBuilder.builder().build()


}
TESTING - WITH SPOCK
def createCheckstyleTask() {



and: "we apply the extension"

project.extensions.create('qualityChecks', QualityChecksExtension)



and: "we supply an existing checkstyle config file"

project.qualityChecks.checkstyleConfigFile = File.createTempFile('temp', '.xml').path

}
TESTING - WITH SPOCK
def createCheckstyleTask() {



when: "we create a checkstyle task"

def checkstyleTask = project.tasks.create('checkstyle', CheckstyleTask)





}
TESTING - WITH SPOCK
def createCheckstyleTask() {



then: "it should not replace our previous file"

checkstyleTask.configFile.name.startsWith('temp')

}
TESTING - WITH SPOCK
@BRWNGRLDEV
TESTING - REPORT
@BRWNGRLDEV
TESTING - SPOCK-REPORT
dependencies {
…
testCompile( 'com.athaydes:spock-reports:1.2.12' ) {

transitive = false
}
}
@BRWNGRLDEV
TESTING - SPOCK-REPORT
@BRWNGRLDEV
@BRWNGRLDEV
BONUS: README
@BRWNGRLDEV
BONUS: README
@BRWNGRLDEV
BONUS: README
@BRWNGRLDEV
SUMMARY
▸Helps avoid copy/paste horror
▸Simple project structure
▸Extending DefaultTask
▸Testing techniques
▸Easy to publish
@BRWNGRLDEV
THANKS!
@brwngrldev
+AnnyceDavis
www.adavis.info
@BRWNGRLDEV

Creating Gradle Plugins - GR8Conf US