gradle plugin best practices by example
TRANSCRIPT
![Page 1: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/1.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
SPRINGONE2GXWASHINGTON, DC
Gradle plugin best practices by example
By Benjamin Muschko Gradle Inc.
![Page 2: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/2.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
The dark past of build logic
2
Unstructured spaghetti code
Copy & paste of code snippets
The build tool tells you how to structure code
Build can only be understood by build guru™
Testing through manual execution
![Page 3: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/3.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Build logic “-ilities”
Typical non-functional software requirements also apply to build code…
• Reusability
• Testability
• Maintainability
• Extensibility
• Configurability
3
![Page 4: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/4.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Reusability
Avoid copy/paste! Allow code to be shared among independent projects.
4
![Page 5: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/5.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Testability
Build code is no different from application code. Test it on multiple levels!
5
![Page 6: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/6.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Maintainability
Avoid the big ball of mud! Cohesion and separation of concerns are important.
6
![Page 7: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/7.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Extensibility
Extend Gradle's build language by your own declarative & expressive language constructs.
7
![Page 8: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/8.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Configurability
Don't box in your users! Implement convention over configuration with ease.
8
![Page 9: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/9.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
The end goal
9
Maintainable, reusable & tested code
Consumers only configure the code
Complex implement. details are hidden
![Page 10: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/10.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
How to get there?
Concepts that help implement these requirements…
• Good software engineering practices
• Custom tasks
• Plugins
• Gradle's extension mechanisms
• Testing capabilities
10
![Page 11: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/11.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Techniques covered in talk
• Declarative vs. imperative logic
• Convention over configuration
• Capabilities vs. conventions
• Gradle's extension mechanisms
• Testing plugin logic
• Publishing the plugin artifacts
• Writing and generating documentation
• Setting up Continuous Integration/Delivery
11
![Page 12: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/12.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Case study: Gradle Docker plugin
Serves as showcase plugin project.
• Plugin for managing Docker images and containers through Docker remote API
• API communication via Docker Java library
• Written in Groovy
• Source code available on GitHub (https://github.com/bmuschko/gradle-docker-plugin)
12
![Page 13: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/13.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Always check in the Wrapper
Project becomes instantly buildable for every developer and on the CI machine.
13
Check in Wrapper files into VCS repository.
![Page 14: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/14.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Hiding complex, imperative logic
Concept applies to tasks and plugins.
• Reusable and configurable
• Easy to structure, refactor and test
• Avoid global properties and methods
14
![Page 15: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/15.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Task type > ad-hoc task
Prefer implementing task types to implementing ad-hoc tasks.
15
task createDockerfile(type: Dockerfile) { destFile = file("$buildDir/mydockerfile/Dockerfile") from 'ubuntu:12.04' maintainer 'Benjamin Muschko "[email protected]"' }
task buildImage(type: DockerBuildImage) { dependsOn createDockerfile inputDir = createDockerfile.destFile.parentFile tag = 'bmuschko/myimage' }
![Page 16: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/16.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Binary plugin > script plugin
Use script plugins to organize build logic based on functional boundaries in project.
16
apply from: "$rootDir/gradle/dependencies.gradle" apply from: "$rootDir/gradle/test-setup.gradle" apply from: "$rootDir/gradle/integration-test.gradle" apply from: "$rootDir/gradle/functional-test.gradle" apply from: "$rootDir/gradle/additional-artifacts.gradle" apply from: "$rootDir/gradle/publishing.gradle" apply from: "$rootDir/gradle/documentation.gradle" apply from: "$rootDir/gradle/release.gradle"
![Page 17: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/17.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Convention over configuration
Provide sensible defaults and standards. Expose a way to re-configure them to user’s needs.
Examples:
• src/main/java for Java-based applications
• Project name derived from directory name
• Output directory is build
17
![Page 18: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/18.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Convention
Plugin consumers will be most comfortable with using convention plugins. Pick sensible defaults for the user.
Good indicator:
The less a consumer has to re-configure defaults the better.
18
![Page 19: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/19.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Configuration
Real-world project might need to re-configure the defaults. Make it convenient to change defaults.
Reason:
Their view of the world might look different than yours.
19
![Page 20: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/20.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Users only declare the “what”
Expose a custom DSL from your binary plugin to configure runtime behavior. The “how” is the responsibility of the plugin implementation.
20
apply plugin: 'com.bmuschko.docker-remote-api'
docker { url = 'https://192.168.59.103:2376' certPath = new File(System.properties['user.home'], '.boot2docker/certs/boot2docker-vm') }
![Page 21: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/21.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Example: Providing default dependencies
Plugins often rely on external libraries. Automatically resolve default version, but make it configurable.
21
![Page 22: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/22.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Customizing Docker Java library
Introduce custom configuration in plugin.
22
project.configurations.create('docker') .setVisible(false) .setTransitive(true) .setDescription('The Docker Java libraries
to be used.') }
Setting dependency from consuming build.
dependencies { docker 'com.github.docker-
java:docker-java:2.0.0' }
![Page 23: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/23.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Providing default (but customizable) dependency
Only use defaults, if no dependencies are assigned to custom configuration.
23
Configuration config = project.configurations.create('docker')
project.tasks.withType(AbstractDockerRemoteApiTask) { config.defaultDependencies { deps -> deps.add(project.dependencies .create('com.github.docker-java:docker-java:2.1.0')) deps.add(project.dependencies .create('org.slf4j:slf4j-simple:1.7.5')) } conventionMapping.classpath = { config } } }
![Page 24: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/24.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Capabilities vs. conventions
Separating general-purpose functionality from pre-configured, opinionated functionality.
Finding the right balance between both aspects is key.
24
![Page 25: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/25.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Capabilities
• Un-opinionated functionality
• Provide general-purpose concepts
Examples:
• Custom task types without creating an actual task instance
• Add new concepts without configuring them (e.g. source sets, build types and flavors)
25
![Page 26: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/26.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Conventions
• Opinionated functionality
• Instantiate and/or pre-configure concepts
Examples:
• Standardized directory layouts
• Enhanced tasks created by a plugin
• Adding default values to extensions
• Declaring task dependencies to form a lifecycle
26
![Page 27: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/27.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Plugin composition
Plugins can build upon other plugins. This is a common pattern.
27
A base plugin provides generic capabilities
Another plugin builds on the base, adding opinionated conventions
![Page 28: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/28.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Example: Docker plugins
Allows users to pick functionality they need in their projects.
28
Plugin that adds task types for interacting with Docker remote API
Plugin for creating & pushing Docker image for Java applications
![Page 29: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/29.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Example: Docker Java application plugin
Applying plugin by identifier or type.
29
import org.gradle.api.Plugin import org.gradle.api.Project
class DockerJavaApplicationPlugin implements Plugin<Project> { @Override void apply(Project project) { project.apply(plugin: DockerRemoteApiPlugin) } }
![Page 30: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/30.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Build for further extension
• Anticipate more specific extensions to your plugin
• Implemented through plugin composition
• Base plugin act as enablers for custom convention plugins
• Enterprise build convention plugins re-configure your plugins
30
![Page 31: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/31.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Put yourself in the shoes of consumer
Do not automatically apply plugins in your plugin!
Reason:
• Makes your plugin highly opinionated.
31
![Page 32: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/32.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Reacting to plugins
React to plugins that might be applied in consuming build script. Only then logic is executed.
The same concept applies to tasks.
32
![Page 33: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/33.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Using configuration rules
33
project.plugins.withType(IdeaPlugin) { // configure Idea plugin in the
context of your plugin }
Reacting to task types
project.tasks.withType(War) { // configure all War tasks in the
context of your plugin }
Reacting to plugins
![Page 34: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/34.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Testing build logic
34
Build logic needs to be testable on multiple levels.
![Page 35: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/35.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Implementing test types with Gradle
35
Unit testing:
No Gradle tooling needed
Integration testing:
Use ProjectBuilder to create pseudo Project instance
Functional testing:
Nebula Test, Gradle TestKit
![Page 36: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/36.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Example: Writing unit test with Spock
36
package com.bmuschko.gradle.docker.tasks.image import spock.lang.Specification import static com.bmuschko.gradle.docker.tasks.image.Dockerfile.*
class DockerfileTest extends Specification { def "Instruction String representation is built correctly"() { expect: instructionInstance.keyword == keyword instructionInstance.build() == builtInstruction where: instructionInstance | keyword | builtInstruction new FromInstruction('ubuntu:14.04') | 'FROM' | 'FROM ubuntu:14.04' new FromInstruction({ 'ubuntu:14.04' }) | 'FROM' | 'FROM ubuntu:14.04' } }
![Page 37: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/37.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Separating test type source code
37
Default unit test directory
Custom integration test directory
Custom functional test directory
![Page 38: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/38.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Example: Integration test source set and task
38
sourceSets { integrationTest { groovy.srcDir file('src/integTest/groovy') resources.srcDir file('src/integTest/resources') compileClasspath += sourceSets.main.output + configurations.testRuntime runtimeClasspath += output + compileClasspath } }
task integrationTest(type: Test) { description = 'Runs the integration tests.' group = 'verification' testClassesDir = sourceSets.integrationTest.output.classesDir classpath = sourceSets.integrationTest.runtimeClasspath mustRunAfter test }
![Page 39: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/39.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Example: Writing integration test with Spock
39
import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder
class DockerJavaApplicationPluginIntegrationTest extends Specification { @Rule TemporaryFolder temporaryFolder = new TemporaryFolder() Project project = ProjectBuilder.builder().withProjectDir(temporaryFolder.root).build()
def "Creates tasks out-of-the-box when application plugin is applied"() { when: project.apply(plugin: DockerJavaApplicationPlugin) project.apply(plugin: 'application') then: project.tasks.findByName(DockerJavaApplicationPlugin.DOCKERFILE_TASK_NAME) } }
![Page 40: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/40.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Functional testing
40
Testing the build logic from the end user’s perspective.
• Exercising build logic as part of a programmatically executed build.
• Make assertions about build outcome.
![Page 41: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/41.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Using the Gradle TestKit
41
Functional testing support in Gradle core.
• Uses Tooling API as test execution harness.
• Agnostic of test framework.
• Assertions made based on build output, build logging or test of tasks + their result.
![Page 42: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/42.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
TestKit usage
42
Declaring TestKit dependency
Declaring the Spock dependency
dependencies { testCompile gradleTestKit() }
dependencies { testCompile
'org.spockframework:spock-core:1.0-groovy-2.3'
}
![Page 43: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/43.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Example: Writing functional tests with TestKit
43
def "can successfully create Dockerfile"() { given: buildFile << """ import com.bmuschko.gradle.docker.tasks.image.Dockerfile task dockerfile(type: Dockerfile) { from 'ubuntu:14.04' maintainer 'Benjamin Muschko "[email protected]"' } “”"
when: def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments('dockerfile').build() then: result.task(":dockerfile").outcome == SUCCESS testProjectDir.file('Dockerfile').exists() }
![Page 44: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/44.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
DEMO
44
Functional testing with TestKit
![Page 45: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/45.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Roadmap for TestKit
45
Gradle 2.6
Mechanics for executing tests
Functional tests can query build result
Gradle 2.7
Isolation of test environment, dedicated daemons
Gradle 2.8
Convenient injection of code under test
![Page 46: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/46.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Cross-version compatibility tests
46
Forward and backward compatibility independent of Gradle version used to build plugin artifact.
2.4 2.5 2.62.32.2
Version used to build plugin
![Page 47: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/47.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Implementing compatibility tests
47
No built-in support in Gradle yet. On the roadmap for TestKit.
Intermediate options:
Custom implementation using Tooling API.
Community plugins like https://github.com/ysb33r/gradleTest
![Page 48: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/48.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Importance of documentation
48
Plugins are not self-documenting.
Thorough documentation is crucial for plugin consumers.
![Page 49: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/49.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Answer questions for consumers
49
How can I use the plugin and configure it?
What tasks & extensions are provided?
What impact does the plugin have on my project?
![Page 50: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/50.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Impact on consumers
50
De-mystify added functionality.
Give consumers the feeling that they are under control.
![Page 51: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/51.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
What should be documented?
51
• Purpose of plugin, the repository that hosts the plugin
• Plugins: Identifier, type and description bundled in a JAR
• Enhanced tasks: their name, type and dependencies
• Custom task types: Javadocs, Groovydocs
• Conventions, custom extensions (e.g. DSLs)
• Extension properties/methods
• Usage examples in textual form
• A good set of functional tests that demonstrate the use of the plugin
![Page 52: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/52.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Example: Plugin description & usage
52
![Page 53: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/53.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Example: Extension usage and properties
53
![Page 54: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/54.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Example: Textual usage & functional tests
54
![Page 55: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/55.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Example: Linking custom tasks to API docs
55
![Page 56: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/56.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Example: Publishing API docs to GitHub pages
56
Javadocs/Groovydocs are essential to allow users discover API classes exposed by plugin.
• Create new branch gh-pages
• Remove all files from working tree and index
• Push new branch
Available under
http(s)://<username>.github.io/<projectname>
![Page 57: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/57.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Example: Publishing Javadocs to GitHub pages
57
Use gradle-git plugin to push to automatically publish Javadocs.
apply plugin: 'org.ajoberstar.github-pages'
githubPages { repoUri = '[email protected]:bmuschko/gradle-docker-plugin.git' pages { from(javadoc.outputs.files) { into 'docs/javadoc' } } }
![Page 58: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/58.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
DEMO
58
Publishing changed API documentation
![Page 59: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/59.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Publishing the plugin binaries
59
Make artifact(s) available to consumers by uploading them to one or many binary repositories.
![Page 60: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/60.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Provide appropriate metadata
60
apply plugin: 'maven-publish'
publishing { publications { mavenJava(MavenPublication) { pom.withXml { def root = asNode() root.appendNode('name', 'Gradle Docker plugin') root.appendNode('description', 'Gradle plugin for managing Docker images & containers.') root.appendNode('url', 'https://github.com/bmuschko/gradle-docker-plugin') root.appendNode('inceptionYear', '2014') } } } }
![Page 61: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/61.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Publishing doesn’t stop with plugin JAR
61
task sourcesJar(type: Jar) { classifier 'sources' from sourceSets.main.allSource }
task groovydocJar(type: Jar, dependsOn: groovydoc) { classifier 'groovydoc' from groovydoc.destinationDir }
task javadocJar(type: Jar, dependsOn: javadoc) { classifier 'javadoc' from javadoc.destinationDir }
![Page 62: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/62.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Share Open Source plugins on the portal
62
https://plugins.gradle.org/
![Page 63: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/63.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Publishing to the Gradle plugin portal
63
Requires use of the “Plugin Publishing Plugin”buildscript { repositories { maven { url 'https://plugins.gradle.org/m2/' } } dependencies { classpath 'com.gradle.publish:plugin-publish-plugin:0.9.1' } }
apply plugin: 'com.gradle.plugin-publish'
![Page 64: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/64.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Declaring required portal plugin metadata
64
Requires use of the “Plugin Publishing Plugin”pluginBundle { website = 'https://github.com/bmuschko/gradle-docker-plugin' vcsUrl = 'https://github.com/bmuschko/gradle-docker-plugin.git' description = 'Gradle plugin for managing Docker images and containers.' tags = ['gradle', 'docker', 'container', 'image', 'lightweight', 'vm', 'linux'] plugins { dockerRemoteApi { id = 'com.bmuschko.docker-remote-api' displayName = 'Provides custom tasks for interacting with Docker remote API.' } } }
![Page 65: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/65.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Continuous Integration
65
A plugin might start small but will grow in complexity over time. Avoid integration hell!
• Fast feedback with every code integration
• Always execute (an assorted set of) tests
• Use CI cloud-based product or host in-house
![Page 66: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/66.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Adding a CI badge
66
Give consumers and contributor a chance to see the build status.
![Page 67: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/67.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Working towards Continuous Delivery
67
Make sure your plugin is always production ready.
• End goal: avoid manual steps
• Build and visualize suitable delivery pipeline
• Go the extra mile - model push-button release capabilities
![Page 68: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/68.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Example: Potential release steps
68
PubliAssemble artifact(s)
Tag VCS repository
Publish artifact(s)
Plugin JAR Sources JAR
Docs JAR
Create tag Push tag
Create metadata Upload artifact(s) Update API docs
![Page 69: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/69.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
DEMO
69
Implementing a plugin release process
![Page 70: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/70.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Example: Build pipeline with Snap CI
70
Build, test and deploy in the cloud.
• Free of charge for public Github repos
• Model build pipelines with automatic and/or manual execution steps
• Execute build for pull requests
![Page 71: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/71.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Example: Snap CI pipeline for Docker plugin
71
Compilation Unit tests
Integration tests
Functional tests
Release
https://snap-ci.com/bmuschko/gradle-docker-plugin/branch/master
![Page 72: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/72.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
DEMO
72
Showcasing build pipeline on Snap CI
![Page 73: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/73.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Other aspects
73
• Be mindful of the performance impact your plugin might have on consuming build
• Avoid using internal Gradle APIs as much as possible
![Page 74: Gradle Plugin Best Practices by Example](https://reader034.vdocument.in/reader034/viewer/2022042723/58720e291a28ab176b8b7f37/html5/thumbnails/74.jpg)
Unless otherwise indicated, these s l ides are © 2013-2015 Pivotal Software, Inc. and l icensed under a Creat ive Commons Attr ibut ion-NonCommercial l icense: ht tp: / /creat ivecommons.org/ l icenses/by-nc/3.0/
Thank You!
74
Please ask questions…
https://www.github.com/bmuschko
@bmuschko