Gradle Plugin Best Practices by Example

Post on 08-Jan-2017

2.033 views 0 download

Transcript of Gradle Plugin Best Practices by Example

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.

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

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

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

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

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

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

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

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

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

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

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

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.

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

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 "benjamin.muschko@gmail.com"' }

task buildImage(type: DockerBuildImage) { dependsOn createDockerfile inputDir = createDockerfile.destFile.parentFile tag = 'bmuschko/myimage' }

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"

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

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

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

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') }

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

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' }

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 } } }

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

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

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

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

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

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) } }

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

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

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

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

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.

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

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' } }

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

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 }

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) } }

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.

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.

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'

}

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 "benjamin.muschko@gmail.com"' } “”"

when: def result = GradleRunner.create().withProjectDir(testProjectDir.root).withArguments('dockerfile').build() then: result.task(":dockerfile").outcome == SUCCESS testProjectDir.file('Dockerfile').exists() }

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

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

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

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

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.

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?

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.

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

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

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

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

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

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>

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 = 'git@github.com:bmuschko/gradle-docker-plugin.git' pages { from(javadoc.outputs.files) { into 'docs/javadoc' } } }

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

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.

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') } } } }

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 }

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/

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'

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.' } } }

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

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.

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

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

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

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

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

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

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

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