creating gradle plugins - oredev

77
Gradle Plugin Goodness

Upload: annyce-davis

Post on 17-Jan-2017

218 views

Category:

Software


0 download

TRANSCRIPT

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) { description 'Run 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

▸Gradle Task

▸Plugin Skeleton

▸Dependencies

▸Plugin Classes

▸Publishing

@BRWNGRLDEV

GRADLE TASKS@BRWNGRLDEV

GRADLE BUILD

@BRWNGRLDEV

PROJECT

TASK TASK TASK

BUILD

GRADLE BUILD LIFECYCLE

@BRWNGRLDEV

TASK

TASK TASK

TASK TASK

EXAMPLE TASK

@BRWNGRLDEV

I want to ask you for your name.

1. Say Hello 2. Ask for your name

DEFINING A TASK

@BRWNGRLDEV

task sayHello { doLast {

println “Hello.” }

}

DEFINING A TASK

@BRWNGRLDEV

task askYourName { dependsOn “sayHello” doLast {

println “What is your name?” }

}

task sayHello { doLast {

println “Hello.” }

}

EXECUTING A TASK

@BRWNGRLDEV

PLUGIN

@BRWNGRLDEV

PROJECT

TASK TASK TASK

BUILD

TASK TASK

TASK

PLUGIN

CREATING PLUGINS

▸build.gradle file

▸buildSrc directory

▸separate project

PLUGIN - BUILD.GRADLE FILE

@BRWNGRLDEV

PLUGIN - BUILD.GRADLE FILE

@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) { 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'

PLUGIN SKELETON@BRWNGRLDEV

PLUGIN SKELETON

@BRWNGRLDEV

PLUGIN SKELETON

@BRWNGRLDEV

PLUGIN SKELETON

How Gradle finds the Plugin Implementation

@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

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…

▸Gradle Tasks

▸Plugin Skeleton

▸Dependencies

▸Plugin Classes

@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

@Beforevoid setUp() { project = ProjectBuilder.builder().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 SPOCKdef 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 SPOCKdef 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

▸Gradle Build Basics

▸Creating Task

▸Benefits of Plugins

▸Testing techniques

▸Easy to publish

@BRWNGRLDEV

THANKS!

@brwngrldev

+AnnyceDavis

www.adavis.info

@BRWNGRLDEV