Successfully reported this slideshow.

Creating Gradle Plugins - GR8Conf US

3

Share

Loading in …3
×
1 of 70
1 of 70

Creating Gradle Plugins - GR8Conf US

3

Share

Download to read offline

If you find yourself copying and pasting code from your build.gradle file every time you start a new project, then it's time you learn about Gradle Plugins. Come and learn what it takes to create a custom Gradle plugin for use in your Android/Java applications.

We're going to go over the following:

• Plugin Structure
• Key Components
• Testing
• Publishing

Walk away feeling empowered to create your own awesome plugins!

If you find yourself copying and pasting code from your build.gradle file every time you start a new project, then it's time you learn about Gradle Plugins. Come and learn what it takes to create a custom Gradle plugin for use in your Android/Java applications.

We're going to go over the following:

• Plugin Structure
• Key Components
• Testing
• Publishing

Walk away feeling empowered to create your own awesome plugins!

More Related Content

Related Books

Free with a 14 day trial from Scribd

See all

Related Audiobooks

Free with a 14 day trial from Scribd

See all

Creating Gradle Plugins - GR8Conf US

  1. 1. Gradle Plugin Goodness
  2. 2. @BRWNGRLDEV
  3. 3. @BRWNGRLDEV
  4. 4. 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) {

  5. 5. 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'
  6. 6. OVERVIEW ▸Plugin Skeleton ▸Dependencies ▸Plugin.groovy ▸CustomTask.groovy ▸Publishing @BRWNGRLDEV
  7. 7. PLUGIN SKELETON @BRWNGRLDEV
  8. 8. PLUGIN SKELETON @BRWNGRLDEV
  9. 9. PLUGIN SKELETON @BRWNGRLDEV
  10. 10. PLUGIN SKELETON How Gradle finds the Plugin Implementation @BRWNGRLDEV
  11. 11. PLUGIN SKELETON implementation-class=info.adavis.qualitychecks.QualityChecksPlugin @BRWNGRLDEV
  12. 12. DEPENDENCIES @BRWNGRLDEV
  13. 13. DEPENDENCIES apply plugin: ‘groovy' dependencies { compile gradleApi() compile localGroovy() } @BRWNGRLDEV
  14. 14. DEPENDENCIES dependencies { … testCompile 'junit:junit:4.12'
 testCompile ('org.spockframework:spock-core:1.0-groovy-2.4') {
 exclude module: 'groovy-all'
 } } @BRWNGRLDEV
  15. 15. THE CODE @BRWNGRLDEV
  16. 16. BUT FIRST… @BRWNGRLDEV
  17. 17. GRADLE BUILD @BRWNGRLDEV PROJECT TASK TASK TASK BUILD
  18. 18. GRADLE BUILD @BRWNGRLDEV PROJECT TASK TASK TASK BUILD PROJECT TASK TASK TASK
  19. 19. PLUGIN.GROOVY class CustomPlugin implements Plugin<Project> { } @BRWNGRLDEV
  20. 20. PLUGIN.GROOVY class CustomPlugin implements Plugin<Project> { @Override void apply(Project project) { } } @BRWNGRLDEV
  21. 21. QUALITYCHECKSPLUGIN.GROOVY @BRWNGRLDEV
  22. 22. APPLY METHOD @BRWNGRLDEV void apply(Project project) {
 this.project = project
 
 }
  23. 23. APPLY METHOD @BRWNGRLDEV void apply(Project project) {
 this.project = project
 
 project.extensions.create('qualityChecks', QualityChecksExtension)
 
 }
  24. 24. APPLY METHOD @BRWNGRLDEV void apply(Project project) {
 this.project = project
 
 project.extensions.create('qualityChecks', QualityChecksExtension)
 
 createConfigFilesIfNeeded()
 createConfigFileTasks()
 createQualityChecksTasks()
 }
  25. 25. 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'
 
 }
  26. 26. 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'
 
 }
  27. 27. PROJECT EXTENSION Back in the application’s build.gradle file… @BRWNGRLDEV qualityChecks {
 pmdConfigFile = ‘checks/pmd.xml’ checkstyleConfigFile = ‘checks/checkstyle.xml’
 }
  28. 28. PROJECT EXTENSION Back in the application’s build.gradle file… @BRWNGRLDEV qualityChecks {
 pmdConfigFile = ‘checks/pmd.xml’ checkstyleConfigFile = ‘checks/checkstyle.xml’
 }
  29. 29. TASKS @BRWNGRLDEV
  30. 30. CREATING TASKS Give it a name and a type @BRWNGRLDEV
  31. 31. CREATING TASKS @BRWNGRLDEV ▸Build on existing task ▸Extend the DefaultTask
  32. 32. BUILD ON EXISTING TASK @BRWNGRLDEV
  33. 33. BUILD ON EXISTING @BRWNGRLDEV
  34. 34. EXTEND DEFAULT TASK @BRWNGRLDEV
  35. 35. CUSTOMTASK.GROOVY class CustomTask extends DefaultTask { CustomTask() { group: ‘verification’ } } @BRWNGRLDEV
  36. 36. CUSTOMTASK.GROOVY class CustomTask extends DefaultTask { CustomTask() { group: ‘verification’ } } @BRWNGRLDEV
  37. 37. CUSTOMTASK.GROOVY CustomTask() { group: ‘verification’ onlyIf { // skip under certain conditions } } @BRWNGRLDEV
  38. 38. CUSTOMTASK.GROOVY @TaskAction def defaultAction() { description: ‘What my task does’ } @BRWNGRLDEV
  39. 39. CUSTOMTASK.GROOVY @BRWNGRLDEV @TaskAction def defaultAction() { description: ‘What my task does’ <do your cool stuff here> }
  40. 40. GRADLE TASK DOCUMENTATION @BRWNGRLDEV
  41. 41. SO FAR… ▸Plugin Skeleton ▸Dependencies ▸Plugin.groovy ▸CustomTask.groovy @BRWNGRLDEV
  42. 42. PUBLISHING @BRWNGRLDEV
  43. 43. PUBLISHING @BRWNGRLDEV
  44. 44. PUBLISHING buildscript { … dependencies { classpath "com.gradle.publish:plugin-publish-plugin:0.9.4" } } apply plugin: 'com.gradle.plugin-publish' @BRWNGRLDEV
  45. 45. PUBLISHING version = "0.1.3" group = "info.adavis" @BRWNGRLDEV
  46. 46. 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
  47. 47. PUBLISHING pluginBundle { … plugins { qualityChecksPlugin { id = 'info.adavis.qualitychecks' displayName = 'Quality Checks Plugin' } } @BRWNGRLDEV
  48. 48. @BRWNGRLDEV
  49. 49. @BRWNGRLDEV
  50. 50. WE’RE DONE… WRONG! @BRWNGRLDEV
  51. 51. WE’RE DONE… TESTS @BRWNGRLDEV
  52. 52. TESTING - WITH JUNIT @Before
 void setUp() {
 projectDir = temporaryFolder.root
 projectDir.mkdirs()
 
 
 } @BRWNGRLDEV
  53. 53. TESTING - WITH JUNIT @Before
 void setUp() {
 projectDir = temporaryFolder.root
 projectDir.mkdirs()
 
 project = ProjectBuilder.builder().withProjectDir(projectDir).build()
 task = project.tasks.create('writeConfigFile', WriteConfigFileTask)
 } @BRWNGRLDEV
  54. 54. TESTING - WITH JUNIT @Test void shouldBeAbleToCreateTask() { assertTrue(task instanceof WriteConfigFileTask) } @BRWNGRLDEV
  55. 55. TESTING - WITH JUNIT @Test void pluginShouldBeApplied() { project.apply(plugin: QualityChecksPlugin) assertNotNull(project.tasks.findByName(‘mytask’)) } @BRWNGRLDEV
  56. 56. SPOCK @BRWNGRLDEV
  57. 57. TESTING - WITH SPOCK def createCheckstyleTask() {
 given: "we have a project"
 def project = ProjectBuilder.builder().build() 
 }
  58. 58. 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
 }
  59. 59. TESTING - WITH SPOCK def createCheckstyleTask() {
 
 when: "we create a checkstyle task"
 def checkstyleTask = project.tasks.create('checkstyle', CheckstyleTask)
 
 
 }
  60. 60. TESTING - WITH SPOCK def createCheckstyleTask() {
 
 then: "it should not replace our previous file"
 checkstyleTask.configFile.name.startsWith('temp')
 }
  61. 61. TESTING - WITH SPOCK @BRWNGRLDEV
  62. 62. TESTING - REPORT @BRWNGRLDEV
  63. 63. TESTING - SPOCK-REPORT dependencies { … testCompile( 'com.athaydes:spock-reports:1.2.12' ) {
 transitive = false } } @BRWNGRLDEV
  64. 64. TESTING - SPOCK-REPORT @BRWNGRLDEV
  65. 65. @BRWNGRLDEV
  66. 66. BONUS: README @BRWNGRLDEV
  67. 67. BONUS: README @BRWNGRLDEV
  68. 68. BONUS: README @BRWNGRLDEV
  69. 69. SUMMARY ▸Helps avoid copy/paste horror ▸Simple project structure ▸Extending DefaultTask ▸Testing techniques ▸Easy to publish @BRWNGRLDEV
  70. 70. THANKS! @brwngrldev +AnnyceDavis www.adavis.info @BRWNGRLDEV

×