building a continuous delivery pipeline with gradle and jenkins

143
Building a Con,nuous Delivery Pipeline with and Peter Niederwieser Principal Engineer, Gradleware @pniederw

Upload: spring-io

Post on 09-May-2015

16.540 views

Category:

Technology


1 download

DESCRIPTION

Speaker: Peter Niederwieser G&G Special Topics Getting software from a developer's machine to a production environment without a fully automated process is time-consuming and error-prone. Continuous Delivery enables building, testing and deploying of software through build pipelines with well-defined quality gates. In this session, we will discuss how to build such a pipeline with the help of Gradle and Jenkins. With Jenkins as the centerpiece of our build pipeline, we will model our way from build to deployment. We will start by introducing an examplary application and learn how to build it with Gradle. Step by step, we will touch on topics like automating unit, integration and functional tests, incorporating popular code quality tools, as well as packaging, publishing and deploying the deliverable.

TRANSCRIPT

Page 1: Building a Continuous Delivery pipeline with Gradle and Jenkins

Building  a  Con,nuous  Delivery  Pipeline

 with

and

Peter  NiederwieserPrincipal  Engineer,  Gradleware

@pniederw

Page 2: Building a Continuous Delivery pipeline with Gradle and Jenkins

Releases  don’t  have  to  be  painful

Page 3: Building a Continuous Delivery pipeline with Gradle and Jenkins

Con,nuous  Delivery

Deliver  so5ware  fast  and  frequently

Page 4: Building a Continuous Delivery pipeline with Gradle and Jenkins

#1  Every  commit  can  result  in  a  release

 

Page 5: Building a Continuous Delivery pipeline with Gradle and Jenkins

#1  Every  commit  can  result  in  a  release

#2  Automate  everything!  

 

Page 6: Building a Continuous Delivery pipeline with Gradle and Jenkins

#1  Every  commit  can  result  in  a  release

#2  Automate  everything!  

 #3  Automated  tests  are  essenCal

Page 7: Building a Continuous Delivery pipeline with Gradle and Jenkins

#1  Every  commit  can  result  in  a  release

#2  Automate  everything!  

 #3  Automated  tests  are  essenCal

#4  Done  means  released

Page 8: Building a Continuous Delivery pipeline with Gradle and Jenkins

Build  pipeline

Automated  manifestaCon  of  delivery  process

Page 9: Building a Continuous Delivery pipeline with Gradle and Jenkins

Build  quality  in!

Establish  automated  quality  gates

Page 10: Building a Continuous Delivery pipeline with Gradle and Jenkins

Compile/Unit  Tests

Page 11: Building a Continuous Delivery pipeline with Gradle and Jenkins

Compile/Unit  Tests

IntegraCon  Tests

Page 12: Building a Continuous Delivery pipeline with Gradle and Jenkins

Compile/Unit  Tests

IntegraCon  Tests

Code  Analysis

Page 13: Building a Continuous Delivery pipeline with Gradle and Jenkins

Test

Compile/Unit  Tests

IntegraCon  Tests

Code  Analysis

Package/Deploy

Page 14: Building a Continuous Delivery pipeline with Gradle and Jenkins

Test

Compile/Unit  Tests

IntegraCon  Tests

Code  Analysis

Package/Deploy

Acceptance  Tests

Page 15: Building a Continuous Delivery pipeline with Gradle and Jenkins

Test

Compile/Unit  Tests

IntegraCon  Tests

Code  Analysis

Package/Deploy

UAT

Acceptance  Tests

Page 16: Building a Continuous Delivery pipeline with Gradle and Jenkins

Test

Compile/Unit  Tests

IntegraCon  Tests

Code  Analysis

Package/Deploy

UAT Prod

Acceptance  Tests

Page 17: Building a Continuous Delivery pipeline with Gradle and Jenkins

!

Page 18: Building a Continuous Delivery pipeline with Gradle and Jenkins

!  But  how?

Page 19: Building a Continuous Delivery pipeline with Gradle and Jenkins

The  “revolu,onary”  sample  applica,on

Internet To Do applicationBrowser Data

store

Writes

Reads

Page 20: Building a Continuous Delivery pipeline with Gradle and Jenkins

Mul,-­‐project  dependencies

Model

Web Repository

dependdepend

depend

Page 21: Building a Continuous Delivery pipeline with Gradle and Jenkins

Project  hierarchytodo

model

repository

build.gradle

settings.gradle

web

build.gradle

build.gradle

build.gradle

gradle

wrapper

xyz.gradle

gradlew

gradlew.bat

Page 22: Building a Continuous Delivery pipeline with Gradle and Jenkins

Project  hierarchytodo

model

repository

build.gradle

settings.gradle

web

build.gradle

build.gradle

build.gradle

gradle

wrapper

xyz.gradle

gradlew

gradlew.bat

Page 23: Building a Continuous Delivery pipeline with Gradle and Jenkins

Project  hierarchytodo

model

repository

build.gradle

settings.gradle

web

build.gradle

build.gradle

build.gradle

gradle

wrapper

xyz.gradle

gradlew

gradlew.bat

Define  project-­‐specific                          behavior

Page 24: Building a Continuous Delivery pipeline with Gradle and Jenkins

Project  hierarchy

include 'model'include 'repository'include 'web'

settings.gradle

Defines  which  projects  are      taking  part  in  the  build

todo

model

repository

build.gradle

settings.gradle

web

build.gradle

build.gradle

build.gradle

gradle

wrapper

xyz.gradle

gradlew

gradlew.bat

Page 25: Building a Continuous Delivery pipeline with Gradle and Jenkins

Project  hierarchytodo

model

repository

build.gradle

settings.gradle

web

build.gradle

build.gradle

build.gradle

gradle

wrapper

xyz.gradle

gradlew

gradlew.bat

Always  use  Wrapperto  execute  the  build!

Page 26: Building a Continuous Delivery pipeline with Gradle and Jenkins

Project  hierarchytodo

model

repository

build.gradle

settings.gradle

web

build.gradle

build.gradle

build.gradle

gradle

wrapper

xyz.gradle

gradlew

gradlew.bat

   Externalize  concerns  into  script  pluginsand  organize  them  in  dedicated  directory

Page 27: Building a Continuous Delivery pipeline with Gradle and Jenkins

Project  hierarchytodo

model

repository

build.gradle

settings.gradle

web

build.gradle

build.gradle

build.gradle

gradle

wrapper

xyz.gradle

gradlew

gradlew.bat

   Externalize  concerns  into  script  pluginsand  organize  them  in  dedicated  directory

Examples:

Versioning  strategy Integra,on  and  func,onal  test  setup Deployment  func,onality ...

Page 28: Building a Continuous Delivery pipeline with Gradle and Jenkins

Project  ar,facts

rootproject

modelproject

repositoryproject

webproject

JAR

JAR

WAR

Page 29: Building a Continuous Delivery pipeline with Gradle and Jenkins

Project  ar,facts

rootproject

modelproject

repositoryproject

webproject

JAR

JAR

WAR

Deployable  ar,fact

Page 30: Building a Continuous Delivery pipeline with Gradle and Jenkins

Stages  in  build  pipeline

Acceptance stage

Functional tests

PublishBinaries

Commit stage

DeployBinaries

UAT

DeployBinaries

Production

IntegrationTests

Code Analysis

AssembleDistribution

CompileUnit Tests

RetrieveBinaries

DeployBinaries

Asserts  that  system  works              at  a  technical  level

Page 31: Building a Continuous Delivery pipeline with Gradle and Jenkins

Stages  in  build  pipeline

Acceptance stage

Functional tests

PublishBinaries

Commit stage

DeployBinaries

UAT

DeployBinaries

Production

IntegrationTests

Code Analysis

AssembleDistribution

CompileUnit Tests

RetrieveBinaries

DeployBinaries

Asserts  that  system  works  on  a  func,onal/non-­‐func,onal  level

Page 32: Building a Continuous Delivery pipeline with Gradle and Jenkins

Stages  in  build  pipeline

Acceptance stage

Functional tests

PublishBinaries

Commit stage

DeployBinaries

UAT

DeployBinaries

Production

IntegrationTests

Code Analysis

AssembleDistribution

CompileUnit Tests

RetrieveBinaries

DeployBinaries

Trigger  manuallyTrigger  manually

Page 33: Building a Continuous Delivery pipeline with Gradle and Jenkins

Commit  stage:  Compile/unit  tests

Rapid  feedback  (<  5  mins)

Run  on  every  VCS  check-­‐in

Priority:  fix  broken  build

PublishBinaries

Commit stage

CompileUnit Tests

IntegrationTests

Code Analysis

AssembleDistribution

Page 34: Building a Continuous Delivery pipeline with Gradle and Jenkins

Commit  stage:  Integra,on  tests

Long  running  tests

Require  environment  setup

Hard  to  maintain

PublishBinaries

Commit stage

CompileUnit Tests

IntegrationTests

Code Analysis

AssembleDistribution

Page 35: Building a Continuous Delivery pipeline with Gradle and Jenkins

Separate  tests  in  project  layout

todo

model

repository

web

src

integTest

java

main

java

test

java

Produc,on  Java  sources

Unit  test  Java  sources

Page 36: Building a Continuous Delivery pipeline with Gradle and Jenkins

Separate  tests  in  project  layout

todo

model

repository

web

src

integTest

java

main

java

test

java

Integra,on  test  Java  sources

Produc,on  Java  sources

Unit  test  Java  sources

Page 37: Building a Continuous Delivery pipeline with Gradle and Jenkins

Separate  tests  with  SourceSets

sourceSets { integrationTest { java.srcDir file('src/integTest/java') 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 testResultsDir = file("$testResultsDir/integration")}

Page 38: Building a Continuous Delivery pipeline with Gradle and Jenkins

Separate  tests  with  SourceSets

sourceSets { integrationTest { java.srcDir file('src/integTest/java') 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 testResultsDir = file("$testResultsDir/integration")}

Set  source  and  resources  directory

Page 39: Building a Continuous Delivery pipeline with Gradle and Jenkins

Separate  tests  with  SourceSets

sourceSets { integrationTest { java.srcDir file('src/integTest/java') 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 testResultsDir = file("$testResultsDir/integration")}

Set  source  and  resources  directory

 Set  compile  and  run,me  classpath

Page 40: Building a Continuous Delivery pipeline with Gradle and Jenkins

Separate  tests  with  SourceSets

sourceSets { integrationTest { java.srcDir file('src/integTest/java') 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 testResultsDir = file("$testResultsDir/integration")}

       Custom  test  results  directory

Set  source  and  resources  directory

 Set  compile  and  run,me  classpath

Page 41: Building a Continuous Delivery pipeline with Gradle and Jenkins

Separate  tests  with  SourceSets

sourceSets { integrationTest { java.srcDir file('src/integTest/java') 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 testResultsDir = file("$testResultsDir/integration")}

       Custom  test  results  directory

Set  source  and  resources  directory

 Set  compile  and  run,me  classpath

gradlew integrationTest

Page 42: Building a Continuous Delivery pipeline with Gradle and Jenkins

Database  integra,on  tests

stopDatabasetest start

Databasebuild

Schemaintegration

Test check build...

Page 43: Building a Continuous Delivery pipeline with Gradle and Jenkins

Database  integra,on  tests

stopDatabasetest start

Databasebuild

Schemaintegration

Test check build...

Page 44: Building a Continuous Delivery pipeline with Gradle and Jenkins

Database  integra,on  tests

apply from: "$rootDir/gradle/databaseSetup.gradle"

integrationTest.dependsOn startAndPrepareDatabaseintegrationTest.finalizedBy stopDatabase

check.dependsOn integrationTest

stopDatabasetest start

Databasebuild

Schemaintegration

Test check build...

Page 45: Building a Continuous Delivery pipeline with Gradle and Jenkins

Database  integra,on  tests

apply from: "$rootDir/gradle/databaseSetup.gradle"

integrationTest.dependsOn startAndPrepareDatabaseintegrationTest.finalizedBy stopDatabase

check.dependsOn integrationTest

stopDatabasetest start

Databasebuild

Schemaintegration

Test check build...

Separate  complex  setup  logic  into  script  plugin

Page 46: Building a Continuous Delivery pipeline with Gradle and Jenkins

Database  integra,on  tests

apply from: "$rootDir/gradle/databaseSetup.gradle"

integrationTest.dependsOn startAndPrepareDatabaseintegrationTest.finalizedBy stopDatabase

check.dependsOn integrationTest

stopDatabasetest start

Databasebuild

Schemaintegration

Test check build...

Separate  complex  setup  logic  into  script  plugin

Integrate  tasks  into  build  lifecycle

Page 47: Building a Continuous Delivery pipeline with Gradle and Jenkins

Picking  the  “right”  code  coverage  tool

Page 48: Building a Continuous Delivery pipeline with Gradle and Jenkins

Picking  the  “right”  code  coverage  tool

Cobertura Offline  bytecode    instrumenta,on

Page 49: Building a Continuous Delivery pipeline with Gradle and Jenkins

Picking  the  “right”  code  coverage  tool

Cobertura Offline  bytecode    instrumenta,on

Offline  bytecode    instrumenta,on

Page 50: Building a Continuous Delivery pipeline with Gradle and Jenkins

Picking  the  “right”  code  coverage  tool

Cobertura Offline  bytecode    instrumenta,on

       Source  code    instrumenta,on

Offline  bytecode    instrumenta,on

Page 51: Building a Continuous Delivery pipeline with Gradle and Jenkins

Picking  the  “right”  code  coverage  tool

Cobertura Offline  bytecode    instrumenta,on

       Source  code    instrumenta,on

Offline  bytecode    instrumenta,on

On-­‐the-­‐fly  bytecode          instrumenta,on

Page 52: Building a Continuous Delivery pipeline with Gradle and Jenkins

On-­‐the-­‐fly  bytecode  instrumentaCon

No  modificaCon  to  source  or  bytecode

Page 53: Building a Continuous Delivery pipeline with Gradle and Jenkins

Code  coverage  with  JaCoCo

apply plugin: "jacoco"

task jacocoIntegrationTestReport(type: JacocoReport) { sourceSets sourceSets.main executionData integTest}

Page 54: Building a Continuous Delivery pipeline with Gradle and Jenkins

Code  coverage  with  JaCoCo

apply plugin: "jacoco"

task jacocoIntegrationTestReport(type: JacocoReport) { sourceSets sourceSets.main executionData integTest}

Apply  JaCoCo  plugin

Page 55: Building a Continuous Delivery pipeline with Gradle and Jenkins

Code  coverage  with  JaCoCo

apply plugin: "jacoco"

task jacocoIntegrationTestReport(type: JacocoReport) { sourceSets sourceSets.main executionData integTest}

Apply  JaCoCo  plugin

Also  report  code  coverage  for  integra,on  tests

Page 56: Building a Continuous Delivery pipeline with Gradle and Jenkins

Genera,ng  coverage  reports

test integrationTest

... ... .exec

Page 57: Building a Continuous Delivery pipeline with Gradle and Jenkins

Genera,ng  coverage  reports

test integrationTest

... ... .exec

jacocoTestReport

jacocoIntegrationTestReport

.exec .html

Page 58: Building a Continuous Delivery pipeline with Gradle and Jenkins

Genera,ng  coverage  reports

test integrationTest

... ... .exec

jacocoTestReport

jacocoIntegrationTestReport

.exec .html

.html

Page 59: Building a Continuous Delivery pipeline with Gradle and Jenkins

Commit  stage:  Code  analysis

PublishBinaries

Commit stage

CompileUnit Tests

IntegrationTests

Code Analysis

AssembleDistribution

Perform  code  health  check

Fail  build  for  low  quality

Record  progress  over  ,me

Page 60: Building a Continuous Delivery pipeline with Gradle and Jenkins

Sta,c  code  analysis  tools

Checkstyle

FindBugs

apply plugin: 'pmd'

pmd { ignoreFailures = true}

tasks.withType(Pmd) { reports { xml.enabled = false html.enabled = true }}

apply plugin: 'jdepend’

jdepend { toolVersion = '2.9.1' ignoreFailures = true}

gradlew check

Page 61: Building a Continuous Delivery pipeline with Gradle and Jenkins

Measure  quality  over  ,me  with  Sonar

Sonardatabase

Gradle

Sonar Runner

root

model

repo.

web

analyzes

publishes reads / writes

Gradle project

Page 62: Building a Continuous Delivery pipeline with Gradle and Jenkins

Applying  the  Sonar  Runner  plugin

apply plugin: "sonar-runner"

sonarRunner { sonarProperties { property "sonar.host.url", "http://my.server.com" property "sonar.jdbc.url", "jdbc:mysql://my.server.com/sonar" property "sonar.jdbc.driverClassName", "com.mysql.jdbc.Driver" property "sonar.jdbc.username", "Fred Flintstone" property "sonar.jdbc.password", "very clever" }}

subprojects { sonarRunner { sonarProperties { property "sonar.sourceEncoding", "UTF-8" } }}

gradlew sonarRunner

Page 63: Building a Continuous Delivery pipeline with Gradle and Jenkins
Page 64: Building a Continuous Delivery pipeline with Gradle and Jenkins

Commit  stage:  Assemble  distribu,on

Exclude  env.  configura,on

Include  build  informa,on

Choose  versioning  strategy

PublishBinaries

Commit stage

CompileUnit Tests

IntegrationTests

Code Analysis

AssembleDistribution

Page 65: Building a Continuous Delivery pipeline with Gradle and Jenkins

Versioning  strategy

1.0-­‐SNAPSHOT 1.0

during  development when  released

…the  Maven  way

Change  version  with  Maven  Release  plugin

Page 66: Building a Continuous Delivery pipeline with Gradle and Jenkins

Versioning  strategy

1.0.134 1.0.134

during  development when  released

…the  Con,nuous  Delivery  way

1.0.134Jenkins  build  numberProject  version  number

Page 67: Building a Continuous Delivery pipeline with Gradle and Jenkins

Versioning  strategy…implemented  with  Gradle

allprojects { apply from: "$rootDir/gradle/versioning.gradle"}

todo

model

repository

build.gradle

settings.gradle

web

gradle

versioning.gradle Contains  version  implementa,on

Page 68: Building a Continuous Delivery pipeline with Gradle and Jenkins

Versioning  strategy…implemented  with  Gradle

ext.buildTimestamp = new Date().format('yyyy-MM-dd HH:mm:ss')

version = new ProjectVersion(1, 0, System.env.SOURCE_BUILD_NUMBER)

class ProjectVersion { Integer major Integer minor String build

ProjectVersion(Integer major, Integer minor, String build) { this.major = major this.minor = minor this.build = build }

@Override String toString() { String fullVersion = "$major.$minor" if(build) { fullVersion += ".$build” } fullVersion }}

Page 69: Building a Continuous Delivery pipeline with Gradle and Jenkins

Versioning  strategy…implemented  with  Gradle

ext.buildTimestamp = new Date().format('yyyy-MM-dd HH:mm:ss')

version = new ProjectVersion(1, 0, System.env.SOURCE_BUILD_NUMBER)

class ProjectVersion { Integer major Integer minor String build

ProjectVersion(Integer major, Integer minor, String build) { this.major = major this.minor = minor this.build = build }

@Override String toString() { String fullVersion = "$major.$minor" if(build) { fullVersion += ".$build” } fullVersion }}

Jenkins  Build  Number

Page 70: Building a Continuous Delivery pipeline with Gradle and Jenkins

Versioning  strategy…implemented  with  Gradle

ext.buildTimestamp = new Date().format('yyyy-MM-dd HH:mm:ss')

version = new ProjectVersion(1, 0, System.env.SOURCE_BUILD_NUMBER)

class ProjectVersion { Integer major Integer minor String build

ProjectVersion(Integer major, Integer minor, String build) { this.major = major this.minor = minor this.build = build }

@Override String toString() { String fullVersion = "$major.$minor" if(build) { fullVersion += ".$build” } fullVersion }}

Jenkins  Build  Number

             Builds  version  String  representa,on

Page 71: Building a Continuous Delivery pipeline with Gradle and Jenkins

Packaging  the  deployable  ar,fact

project(':web') { apply plugin: 'war'

task createBuildInfoFile << { def buildInfoFile = new File("$buildDir/build-info.properties") Properties props = new Properties() props.setProperty('version', project.version.toString()) props.setProperty('timestamp', project.buildTimestamp) props.store(buildInfoFile.newWriter(), null) } war { dependsOn createBuildInfoFile baseName = 'todo' from(buildDir) { include 'build-info.properties' into('WEB-INF/classes') } }}

Page 72: Building a Continuous Delivery pipeline with Gradle and Jenkins

Packaging  the  deployable  ar,fact

project(':web') { apply plugin: 'war'

task createBuildInfoFile << { def buildInfoFile = new File("$buildDir/build-info.properties") Properties props = new Properties() props.setProperty('version', project.version.toString()) props.setProperty('timestamp', project.buildTimestamp) props.store(buildInfoFile.newWriter(), null) } war { dependsOn createBuildInfoFile baseName = 'todo' from(buildDir) { include 'build-info.properties' into('WEB-INF/classes') } }}

Creates  file  containing            build  informa,on

Page 73: Building a Continuous Delivery pipeline with Gradle and Jenkins

Packaging  the  deployable  ar,fact

project(':web') { apply plugin: 'war'

task createBuildInfoFile << { def buildInfoFile = new File("$buildDir/build-info.properties") Properties props = new Properties() props.setProperty('version', project.version.toString()) props.setProperty('timestamp', project.buildTimestamp) props.store(buildInfoFile.newWriter(), null) } war { dependsOn createBuildInfoFile baseName = 'todo' from(buildDir) { include 'build-info.properties' into('WEB-INF/classes') } }}

Creates  file  containing            build  informa,on

Include  build  info  fileInto  WAR  distribu,on

Page 74: Building a Continuous Delivery pipeline with Gradle and Jenkins

Packaging  the  deployable  ar,fact

project(':web') { apply plugin: 'war'

task createBuildInfoFile << { def buildInfoFile = new File("$buildDir/build-info.properties") Properties props = new Properties() props.setProperty('version', project.version.toString()) props.setProperty('timestamp', project.buildTimestamp) props.store(buildInfoFile.newWriter(), null) } war { dependsOn createBuildInfoFile baseName = 'todo' from(buildDir) { include 'build-info.properties' into('WEB-INF/classes') } }}

Creates  file  containing            build  informa,on

Include  build  info  fileInto  WAR  distribu,on

gradlew assemble

Page 75: Building a Continuous Delivery pipeline with Gradle and Jenkins

Commit  stage:  Publish  binaries

Version  ar,fact(s)

Use  binary  repository

Publish  once,  then  reuse

PublishBinaries

Commit stage

CompileUnit Tests

IntegrationTests

Code Analysis

AssembleDistribution

Page 76: Building a Continuous Delivery pipeline with Gradle and Jenkins

Publishing  the  deployable  ar,fact

1.0.34

1.0.32 1.0.33 1.0.34

Page 77: Building a Continuous Delivery pipeline with Gradle and Jenkins

Defining  build  configura,onbinaryRepository { url = 'http://mycompany.bin.repo:8081/artifactory' username = 'admin' password = 'password' name = 'libs-release-local'}

environments { test { server { hostname = 'mycompany.test' port = 8099 context = 'todo' username = 'manager' password = 'manager' } } uat { server { hostname = 'mycompany.uat' port = 8199 context = 'todo' username = 'manager' password = 'manager' } }

...}

Page 78: Building a Continuous Delivery pipeline with Gradle and Jenkins

Defining  build  configura,onbinaryRepository { url = 'http://mycompany.bin.repo:8081/artifactory' username = 'admin' password = 'password' name = 'libs-release-local'}

environments { test { server { hostname = 'mycompany.test' port = 8099 context = 'todo' username = 'manager' password = 'manager' } } uat { server { hostname = 'mycompany.uat' port = 8199 context = 'todo' username = 'manager' password = 'manager' } }

...}

       Common  configura,on

Page 79: Building a Continuous Delivery pipeline with Gradle and Jenkins

Defining  build  configura,onbinaryRepository { url = 'http://mycompany.bin.repo:8081/artifactory' username = 'admin' password = 'password' name = 'libs-release-local'}

environments { test { server { hostname = 'mycompany.test' port = 8099 context = 'todo' username = 'manager' password = 'manager' } } uat { server { hostname = 'mycompany.uat' port = 8199 context = 'todo' username = 'manager' password = 'manager' } }

...}

Environment-­‐specificconfigura,on

       Common  configura,on

Page 80: Building a Continuous Delivery pipeline with Gradle and Jenkins

Defining  build  configura,onbinaryRepository { url = 'http://mycompany.bin.repo:8081/artifactory' username = 'admin' password = 'password' name = 'libs-release-local'}

environments { test { server { hostname = 'mycompany.test' port = 8099 context = 'todo' username = 'manager' password = 'manager' } } uat { server { hostname = 'mycompany.uat' port = 8199 context = 'todo' username = 'manager' password = 'manager' } }

...}

Environment-­‐specificconfigura,on

       Common  configura,on          Read  creden,als

 from  gradle.proper,es

         Read  creden,als  from  gradle.proper,es

         Read  creden,als  from  gradle.proper,es

Page 81: Building a Continuous Delivery pipeline with Gradle and Jenkins

Reading  build  configura,on

def env = project.hasProperty('env') ? project.getProperty('env') : 'test'logger.quiet "Loading configuration for environment '$env’."

def configFile = file("$rootDir/gradle/config/buildConfig.groovy")def parsedConfig = new ConfigSlurper(env).parse(configFile.toURL()) allprojects { ext.config = parsedConfig}

Initializationphase

Congurationphase

Executionphase

Page 82: Building a Continuous Delivery pipeline with Gradle and Jenkins

Reading  build  configura,on

def env = project.hasProperty('env') ? project.getProperty('env') : 'test'logger.quiet "Loading configuration for environment '$env’."

def configFile = file("$rootDir/gradle/config/buildConfig.groovy")def parsedConfig = new ConfigSlurper(env).parse(configFile.toURL()) allprojects { ext.config = parsedConfig}

Initializationphase

Congurationphase

Executionphase

Assign  configura,on  to                extra  property

Page 83: Building a Continuous Delivery pipeline with Gradle and Jenkins

Reading  build  configura,on

def env = project.hasProperty('env') ? project.getProperty('env') : 'test'logger.quiet "Loading configuration for environment '$env’."

def configFile = file("$rootDir/gradle/config/buildConfig.groovy")def parsedConfig = new ConfigSlurper(env).parse(configFile.toURL()) allprojects { ext.config = parsedConfig}

Initializationphase

Congurationphase

Executionphase

Assign  configura,on  to                extra  property

gradlew –Penv=uat ...

Page 84: Building a Continuous Delivery pipeline with Gradle and Jenkins

Using  the  Maven  Publishing  plugin

apply plugin: 'maven-publish'

ext.fullRepoUrl = "$config.binaryRepository.url/$config.binaryRepository.name”

publishing { publications { webApp(MavenPublication) { from components.web } }

repositories { maven { url fullRepoUrl credentials { username = config.binaryRepository.username password = config.binaryRepository.password } } }}

Page 85: Building a Continuous Delivery pipeline with Gradle and Jenkins

Using  the  Maven  Publishing  plugin

apply plugin: 'maven-publish'

ext.fullRepoUrl = "$config.binaryRepository.url/$config.binaryRepository.name”

publishing { publications { webApp(MavenPublication) { from components.web } }

repositories { maven { url fullRepoUrl credentials { username = config.binaryRepository.username password = config.binaryRepository.password } } }}

Build  repository  URLfrom  configura,on

Page 86: Building a Continuous Delivery pipeline with Gradle and Jenkins

Using  the  Maven  Publishing  plugin

apply plugin: 'maven-publish'

ext.fullRepoUrl = "$config.binaryRepository.url/$config.binaryRepository.name”

publishing { publications { webApp(MavenPublication) { from components.web } }

repositories { maven { url fullRepoUrl credentials { username = config.binaryRepository.username password = config.binaryRepository.password } } }}

Build  repository  URLfrom  configura,on

Assign  publica,on  name                and  component

Page 87: Building a Continuous Delivery pipeline with Gradle and Jenkins

Using  the  Maven  Publishing  plugin

apply plugin: 'maven-publish'

ext.fullRepoUrl = "$config.binaryRepository.url/$config.binaryRepository.name”

publishing { publications { webApp(MavenPublication) { from components.web } }

repositories { maven { url fullRepoUrl credentials { username = config.binaryRepository.username password = config.binaryRepository.password } } }}

Build  repository  URLfrom  configura,on

gradlew publish

Assign  publica,on  name                and  component

Page 88: Building a Continuous Delivery pipeline with Gradle and Jenkins
Page 89: Building a Continuous Delivery pipeline with Gradle and Jenkins

Acceptance  stage:  Retrieve  binaries

Request  versioned  ar,fact

Store  in  temp.  directory

Acceptance stage

DeployBinaries

Functional Tests

RetrieveBinaries

Page 90: Building a Continuous Delivery pipeline with Gradle and Jenkins

Downloading  the  deployable  ar,fact

1.0.34

1.0.32 1.0.33 1.0.34

1.0.34

Test

UAT

Prod

Page 91: Building a Continuous Delivery pipeline with Gradle and Jenkins

Task  for  downloading  ar,fact

repositories { maven { url fullRepoUrl }}

configurations { war}

dependencies { war "$project.group:$project.name:$project.version"}

task downloadBinaryArchive(type: Copy) { from configurations.war into "$buildDir/download" }

Page 92: Building a Continuous Delivery pipeline with Gradle and Jenkins

Task  for  downloading  ar,fact

repositories { maven { url fullRepoUrl }}

configurations { war}

dependencies { war "$project.group:$project.name:$project.version"}

task downloadBinaryArchive(type: Copy) { from configurations.war into "$buildDir/download" }

Target  loca,on  fordownloaded  ar,fact

gradlew downloadBinaryArchive

Page 93: Building a Continuous Delivery pipeline with Gradle and Jenkins

Acceptance  stage:  Deploy  binaries

Deployment  on  request

Make  it  a  reliable  process

Acceptance stage

DeployBinaries

Functional Tests

RetrieveBinaries

Use  process  for  all  envs

Page 94: Building a Continuous Delivery pipeline with Gradle and Jenkins

Deploying  to  mul,ple  environments

Test

UAT

Prod

–Penv=prod

–Penv=uat

–Penv=test

Page 95: Building a Continuous Delivery pipeline with Gradle and Jenkins

Deployment  with  the  Cargo  plugin

cargoDeployRemote.dependsOn downloadBinaryArchive, cargoUndeployRemote

cargoUndeployRemote { onlyIf appContextStatus} cargo { containerId = 'tomcat7x' port = config.server.port

deployable { file = downloadedArtifact context = config.server.context }

remote { hostname = config.server.hostname username = config.server.username password = config.server.password }}

Page 96: Building a Continuous Delivery pipeline with Gradle and Jenkins

Deployment  with  the  Cargo  plugin

cargoDeployRemote.dependsOn downloadBinaryArchive, cargoUndeployRemote

cargoUndeployRemote { onlyIf appContextStatus} cargo { containerId = 'tomcat7x' port = config.server.port

deployable { file = downloadedArtifact context = config.server.context }

remote { hostname = config.server.hostname username = config.server.username password = config.server.password }}

           Download  ar,fact  from  binary  repository  and  undeploy  exis,ng  one

Page 97: Building a Continuous Delivery pipeline with Gradle and Jenkins

Deployment  with  the  Cargo  plugin

cargoDeployRemote.dependsOn downloadBinaryArchive, cargoUndeployRemote

cargoUndeployRemote { onlyIf appContextStatus} cargo { containerId = 'tomcat7x' port = config.server.port

deployable { file = downloadedArtifact context = config.server.context }

remote { hostname = config.server.hostname username = config.server.username password = config.server.password }}

           Download  ar,fact  from  binary  repository  and  undeploy  exis,ng  one

 Only  undeploy  ifURL  context  exists

Page 98: Building a Continuous Delivery pipeline with Gradle and Jenkins

Deployment  with  the  Cargo  plugin

cargoDeployRemote.dependsOn downloadBinaryArchive, cargoUndeployRemote

cargoUndeployRemote { onlyIf appContextStatus} cargo { containerId = 'tomcat7x' port = config.server.port

deployable { file = downloadedArtifact context = config.server.context }

remote { hostname = config.server.hostname username = config.server.username password = config.server.password }}

           Download  ar,fact  from  binary  repository  and  undeploy  exis,ng  one

 Only  undeploy  ifURL  context  exists

Use  environment-­‐specific                                configura,on

Page 99: Building a Continuous Delivery pipeline with Gradle and Jenkins

Deployment  with  the  Cargo  plugin

cargoDeployRemote.dependsOn downloadBinaryArchive, cargoUndeployRemote

cargoUndeployRemote { onlyIf appContextStatus} cargo { containerId = 'tomcat7x' port = config.server.port

deployable { file = downloadedArtifact context = config.server.context }

remote { hostname = config.server.hostname username = config.server.username password = config.server.password }}

           Download  ar,fact  from  binary  repository  and  undeploy  exis,ng  one

 Only  undeploy  ifURL  context  exists

Use  environment-­‐specific                                configura,on

gradlew –Penv=uat cargoDeploy

Page 100: Building a Continuous Delivery pipeline with Gradle and Jenkins
Page 101: Building a Continuous Delivery pipeline with Gradle and Jenkins

Acceptance  stage:  Func,onal  tests

Test  all  UI  permuta,ons

Test  important  use  cases

Acceptance stage

DeployBinaries

Functional Tests

RetrieveBinaries

Run  against  different  envs

Page 102: Building a Continuous Delivery pipeline with Gradle and Jenkins

In-­‐container  func,onal  tests

functionalJettyStop

functionalTestClasses

functionalJettyRun

functionalTest check... ...

Page 103: Building a Continuous Delivery pipeline with Gradle and Jenkins

In-­‐container  func,onal  tests

functionalJettyStop

functionalTestClasses

functionalJettyRun

functionalTest check... ...

task functionalTest(type: Test) { ...}

task functionalJettyRun(type: org.gradle.api.plugins.jetty.JettyRun) { httpPort = functionalJettyHttpPort stopPort = functionalJettyStopPort stopKey = functionalJettyStopKey contextPath = functionalJettyContextPath daemon = true}

task functionalJettyStop(type: org.gradle.api.plugins.jetty.JettyStop) { stopPort = functionalJettyStopPort stopKey = functionalJettyStopKey}

functionalTest.dependsOn functionalJettyRunfunctionalTest.finalizedBy functionalJettyStoptask inContainerFunctionalTest(dependsOn: functionalJettyStop)

Page 104: Building a Continuous Delivery pipeline with Gradle and Jenkins

In-­‐container  func,onal  tests

functionalJettyStop

functionalTestClasses

functionalJettyRun

functionalTest check... ...

task functionalTest(type: Test) { ...}

task functionalJettyRun(type: org.gradle.api.plugins.jetty.JettyRun) { httpPort = functionalJettyHttpPort stopPort = functionalJettyStopPort stopKey = functionalJettyStopKey contextPath = functionalJettyContextPath daemon = true}

task functionalJettyStop(type: org.gradle.api.plugins.jetty.JettyStop) { stopPort = functionalJettyStopPort stopKey = functionalJettyStopKey}

functionalTest.dependsOn functionalJettyRunfunctionalTest.finalizedBy functionalJettyStoptask inContainerFunctionalTest(dependsOn: functionalJettyStop)

Func,onal  test  task

Page 105: Building a Continuous Delivery pipeline with Gradle and Jenkins

In-­‐container  func,onal  tests

functionalJettyStop

functionalTestClasses

functionalJettyRun

functionalTest check... ...

task functionalTest(type: Test) { ...}

task functionalJettyRun(type: org.gradle.api.plugins.jetty.JettyRun) { httpPort = functionalJettyHttpPort stopPort = functionalJettyStopPort stopKey = functionalJettyStopKey contextPath = functionalJettyContextPath daemon = true}

task functionalJettyStop(type: org.gradle.api.plugins.jetty.JettyStop) { stopPort = functionalJettyStopPort stopKey = functionalJettyStopKey}

functionalTest.dependsOn functionalJettyRunfunctionalTest.finalizedBy functionalJettyStoptask inContainerFunctionalTest(dependsOn: functionalJettyStop)

Func,onal  test  task

Custom  Jeiy  Run  task

Page 106: Building a Continuous Delivery pipeline with Gradle and Jenkins

In-­‐container  func,onal  tests

functionalJettyStop

functionalTestClasses

functionalJettyRun

functionalTest check... ...

task functionalTest(type: Test) { ...}

task functionalJettyRun(type: org.gradle.api.plugins.jetty.JettyRun) { httpPort = functionalJettyHttpPort stopPort = functionalJettyStopPort stopKey = functionalJettyStopKey contextPath = functionalJettyContextPath daemon = true}

task functionalJettyStop(type: org.gradle.api.plugins.jetty.JettyStop) { stopPort = functionalJettyStopPort stopKey = functionalJettyStopKey}

functionalTest.dependsOn functionalJettyRunfunctionalTest.finalizedBy functionalJettyStoptask inContainerFunctionalTest(dependsOn: functionalJettyStop)

Func,onal  test  task

Custom  Jeiy  Run  task

Custom  Jeiy  Stop  task

Page 107: Building a Continuous Delivery pipeline with Gradle and Jenkins

Execu,ng  remote  func,onal  tests

ext { functionalTestReportDir = file("$testReportDir/functional") functionalTestResultsDir = file("$testResultsDir/functional") functionalCommonSystemProperties = ['geb.env': 'firefox', 'geb.build.reportsDir': reporting.file("$name/geb")]}

task remoteFunctionalTest(type: Test) { testClassesDir = sourceSets.functionalTest.output.classesDir classpath = sourceSets.functionalTest.runtimeClasspath testReportDir = functionalTestReportDir testResultsDir = functionalTestResultsDir systemProperties functionalCommonSystemProperties systemProperty 'geb.build.baseUrl', "http://$config.server.hostname:$config.server.port/$config.server.context/"}

Page 108: Building a Continuous Delivery pipeline with Gradle and Jenkins

Execu,ng  remote  func,onal  tests

ext { functionalTestReportDir = file("$testReportDir/functional") functionalTestResultsDir = file("$testResultsDir/functional") functionalCommonSystemProperties = ['geb.env': 'firefox', 'geb.build.reportsDir': reporting.file("$name/geb")]}

task remoteFunctionalTest(type: Test) { testClassesDir = sourceSets.functionalTest.output.classesDir classpath = sourceSets.functionalTest.runtimeClasspath testReportDir = functionalTestReportDir testResultsDir = functionalTestResultsDir systemProperties functionalCommonSystemProperties systemProperty 'geb.build.baseUrl', "http://$config.server.hostname:$config.server.port/$config.server.context/"}

Reuse  setup        proper,es

Page 109: Building a Continuous Delivery pipeline with Gradle and Jenkins

Execu,ng  remote  func,onal  tests

ext { functionalTestReportDir = file("$testReportDir/functional") functionalTestResultsDir = file("$testResultsDir/functional") functionalCommonSystemProperties = ['geb.env': 'firefox', 'geb.build.reportsDir': reporting.file("$name/geb")]}

task remoteFunctionalTest(type: Test) { testClassesDir = sourceSets.functionalTest.output.classesDir classpath = sourceSets.functionalTest.runtimeClasspath testReportDir = functionalTestReportDir testResultsDir = functionalTestResultsDir systemProperties functionalCommonSystemProperties systemProperty 'geb.build.baseUrl', "http://$config.server.hostname:$config.server.port/$config.server.context/"}

Build  URL  from  env.  configura,on

Reuse  setup        proper,es

Page 110: Building a Continuous Delivery pipeline with Gradle and Jenkins

Execu,ng  remote  func,onal  tests

ext { functionalTestReportDir = file("$testReportDir/functional") functionalTestResultsDir = file("$testResultsDir/functional") functionalCommonSystemProperties = ['geb.env': 'firefox', 'geb.build.reportsDir': reporting.file("$name/geb")]}

task remoteFunctionalTest(type: Test) { testClassesDir = sourceSets.functionalTest.output.classesDir classpath = sourceSets.functionalTest.runtimeClasspath testReportDir = functionalTestReportDir testResultsDir = functionalTestResultsDir systemProperties functionalCommonSystemProperties systemProperty 'geb.build.baseUrl', "http://$config.server.hostname:$config.server.port/$config.server.context/"}

gradlew –Penv=test remoteFunctionalTest

Build  URL  from  env.  configura,on

Reuse  setup        proper,es

Page 111: Building a Continuous Delivery pipeline with Gradle and Jenkins

Going  further:  Capacity  tes,ng

buildscript { repositories { mavenCentral() }

dependencies { classpath "com.github.kulya:jmeter-gradle-plugin:1.3.1-2.9" }}

apply plugin: com.github.kulya.gradle.plugins.jmeter.JmeterPlugin ext.loadTestResources = "$projectDir/src/loadTest/resources" jmeterRun.configure { jmeterTestFiles = [file("$loadTestResources/todo-test-plan.jmx")] jmeterPropertyFile = file("$loadTestResources/jmeter.properties") jmeterUserProperties = ["hostname=${config.server.hostname}, "port=${config.server.port}", "context=${config.server.context}"] logging.captureStandardError LogLevel.INFO}

gradlew –Penv=uat jmeterRun

Page 112: Building a Continuous Delivery pipeline with Gradle and Jenkins

Let’s  bring  Jenkins  into  play!

Test

UAT

Prod

     DeploymentAcceptance  Tests

Publish

Download

Trigger  Build

Pull  Source  Code

Page 113: Building a Continuous Delivery pipeline with Gradle and Jenkins

Model  pipeline  as  series  of  jobs

Page 114: Building a Continuous Delivery pipeline with Gradle and Jenkins

Model  pipeline  as  series  of  jobs

Triggered  job  when  change            to  SCM  is  detected

Page 115: Building a Continuous Delivery pipeline with Gradle and Jenkins

Ini,al  Jenkins  Build  Job

Page 116: Building a Continuous Delivery pipeline with Gradle and Jenkins

Build  Name  Seier  Plugin

Page 117: Building a Continuous Delivery pipeline with Gradle and Jenkins

JaCoCo  Plugin

Page 118: Building a Continuous Delivery pipeline with Gradle and Jenkins

Parameterized  Trigger  Plugin

Page 119: Building a Continuous Delivery pipeline with Gradle and Jenkins

Gradle  Plugin

Page 120: Building a Continuous Delivery pipeline with Gradle and Jenkins

Always  use  the  Wrapper!

Gradle  Plugin

Page 121: Building a Continuous Delivery pipeline with Gradle and Jenkins

Always  use  the  Wrapper!

Gradle  Plugin

Run  clean  task  to  remove            exis,ng  ar,facts

Page 122: Building a Continuous Delivery pipeline with Gradle and Jenkins

Build  Name  Seier  Plugin

Page 123: Building a Continuous Delivery pipeline with Gradle and Jenkins

Clearly  iden,fy  a  buildthrough  an  expressive                  build  name

Build  Name  Seier  Plugin

Page 124: Building a Continuous Delivery pipeline with Gradle and Jenkins

Use  Jenkins  environment  variable

Clearly  iden,fy  a  buildthrough  an  expressive                  build  name

Build  Name  Seier  Plugin

Page 125: Building a Continuous Delivery pipeline with Gradle and Jenkins

Parameterized  Trigger  Plugin

Page 126: Building a Continuous Delivery pipeline with Gradle and Jenkins

Next  job  to  trigger  if          build  is  stable

Parameterized  Trigger  Plugin

Page 127: Building a Continuous Delivery pipeline with Gradle and Jenkins

Next  job  to  trigger  if          build  is  stable

Defines  build  numberparameter  provided  to  subsequent  jobs

Parameterized  Trigger  Plugin

Page 128: Building a Continuous Delivery pipeline with Gradle and Jenkins

Clone  Workspace  SCM  Plugin

Page 129: Building a Continuous Delivery pipeline with Gradle and Jenkins

Archive  all  files

Clone  Workspace  SCM  Plugin

Page 130: Building a Continuous Delivery pipeline with Gradle and Jenkins

Archive  all  files

Only  archive  if  build        was  successful

Clone  Workspace  SCM  Plugin

Page 131: Building a Continuous Delivery pipeline with Gradle and Jenkins

JaCoCo  Plugin

Page 132: Building a Continuous Delivery pipeline with Gradle and Jenkins

Point  to  separated  test  results

JaCoCo  Plugin

Page 133: Building a Continuous Delivery pipeline with Gradle and Jenkins

Point  to  separated  test  results

JaCoCo  Plugin

Point  to  JaCoCo  files  as  well      as  source  and  class  files

Page 134: Building a Continuous Delivery pipeline with Gradle and Jenkins

Point  to  separated  test  results

Fail  build  of  quality  gate        criteria  are  not  met

JaCoCo  Plugin

Point  to  JaCoCo  files  as  well      as  source  and  class  files

Page 135: Building a Continuous Delivery pipeline with Gradle and Jenkins

Clone  Workspace  SCM  Plugin Build  Name  Seier  Plugin

Page 136: Building a Continuous Delivery pipeline with Gradle and Jenkins

Reuse  ini,al  workspace

Clone  Workspace  SCM  Plugin Build  Name  Seier  Plugin

Page 137: Building a Continuous Delivery pipeline with Gradle and Jenkins

Reuse  ini,al  workspace

Reuse  ini,al  build  number

Clone  Workspace  SCM  Plugin Build  Name  Seier  Plugin

Page 138: Building a Continuous Delivery pipeline with Gradle and Jenkins

Build  Pipeline  Plugin

Page 139: Building a Continuous Delivery pipeline with Gradle and Jenkins

Define  the  target  environment

Build  Pipeline  Plugin

Page 140: Building a Continuous Delivery pipeline with Gradle and Jenkins

Define  the  target  environment

Downstream  job  that  requires  manual  execu,on

Build  Pipeline  Plugin

Page 141: Building a Continuous Delivery pipeline with Gradle and Jenkins

Build  Pipeline  Plugin

Visualiza,on  of  chained  pipeline  jobs

Page 142: Building a Continuous Delivery pipeline with Gradle and Jenkins
Page 143: Building a Continuous Delivery pipeline with Gradle and Jenkins

> gradle qa:askQuestions

BUILD SUCCESSFUL

Total time: 300 secs