building a continuous delivery with gradle and jenkins

137
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission. Continuous Delivery with Gradle and Jenkins By Peter Niederwieser

Upload: spring-io

Post on 14-Jun-2015

2.469 views

Category:

Software


7 download

DESCRIPTION

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 with Gradle and Jenkins

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Continuous Delivery with Gradle and Jenkins

By Peter Niederwieser

Page 2: Building a Continuous Delivery with Gradle and Jenkins

Releases  don’t  have  to  be  painful

Page 3: Building a Continuous Delivery with Gradle and Jenkins

Con4nuous  Delivery

Deliver  so8ware  fast  and  frequently

Page 4: Building a Continuous Delivery with Gradle and Jenkins

#1  Every  commit  can  result  in  a  release

Page 5: Building a Continuous Delivery with Gradle and Jenkins

#1  Every  commit  can  result  in  a  release

#2  Automate  everything!  

Page 6: Building a Continuous Delivery with Gradle and Jenkins

#1  Every  commit  can  result  in  a  release

#2  Automate  everything!  

#3  Automated  tests  are  essen4al

Page 7: Building a Continuous Delivery with Gradle and Jenkins

#1  Every  commit  can  result  in  a  release

#2  Automate  everything!  

#3  Automated  tests  are  essen4al

#4  Done  means  released

Page 8: Building a Continuous Delivery with Gradle and Jenkins

Build  pipeline

Automated  manifesta4on  of  delivery  process

Page 9: Building a Continuous Delivery with Gradle and Jenkins

Build  quality  in!

Establish  automated  quality  gates

Page 10: Building a Continuous Delivery with Gradle and Jenkins

Compile/Unit  Tests

Page 11: Building a Continuous Delivery with Gradle and Jenkins

Compile/Unit  Tests

Integra4on  Tests

Page 12: Building a Continuous Delivery with Gradle and Jenkins

Compile/Unit  Tests

Integra4on  Tests

Code  Analysis

Page 13: Building a Continuous Delivery with Gradle and Jenkins

Test

Compile/Unit  Tests

Integra4on  Tests

Code  Analysis

Package/Deploy

Page 14: Building a Continuous Delivery with Gradle and Jenkins

Test

Compile/Unit  Tests

Integra4on  Tests

Code  Analysis

Package/Deploy

Acceptance  Tests

Page 15: Building a Continuous Delivery with Gradle and Jenkins

Test

Compile/Unit  Tests

Integra4on  Tests

Code  Analysis

Package/Deploy

UAT

Acceptance  Tests

Page 16: Building a Continuous Delivery with Gradle and Jenkins

Test

Compile/Unit  Tests

Integra4on  Tests

Code  Analysis

Package/Deploy

UAT Prod

Acceptance  Tests

Page 17: Building a Continuous Delivery with Gradle and Jenkins

!

Page 18: Building a Continuous Delivery with Gradle and Jenkins

!  But    how?

Page 19: Building a Continuous Delivery with Gradle and Jenkins

The  “revolu4onary”  sample  applica4on

Internet To Do applicationBrowser Data

store

Writes

Reads

Page 20: Building a Continuous Delivery with Gradle and Jenkins

Mul4-­‐project  dependencies

Model

Web Repository

dependdepend

depend

Page 21: Building a Continuous Delivery 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 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 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 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 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  Wrapper  to  execute  the  build!

Page 26: Building a Continuous Delivery 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  plugins  and  organize  them  in  dedicated  directory

Page 27: Building a Continuous Delivery 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  plugins  and  organize  them  in  dedicated  directory

Examples:  !! Versioning  strategy  ! Integra4on  and  func4onal  test  setup  ! Deployment  func4onality  ! ...

Page 28: Building a Continuous Delivery with Gradle and Jenkins

Project  ar4facts

rootproject

modelproject

repositoryproject

webproject

JAR

JAR

WAR

Page 29: Building a Continuous Delivery with Gradle and Jenkins

Project  ar4facts

rootproject

modelproject

repositoryproject

webproject

JAR

JAR

WAR

Deployable  ar4fact

Page 30: Building a Continuous Delivery 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 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  func4onal/non-­‐func4onal  level

Page 32: Building a Continuous Delivery 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 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 with Gradle and Jenkins

Commit  stage:  Integra4on  tests

Longer  running  tests

Require  environment  setup

Harder  to  maintain

PublishBinaries

Commit stage

CompileUnit Tests

IntegrationTests

Code Analysis

AssembleDistribution

Page 35: Building a Continuous Delivery with Gradle and Jenkins

Separate  tests  in  project  layout

todo

model

repository

web

src

integTest

java

main

java

test

java

Produc4on  Java  sources

Unit  test  Java  sources

Page 36: Building a Continuous Delivery with Gradle and Jenkins

Separate  tests  in  project  layout

todo

model

repository

web

src

integTest

java

main

java

test

java

Integra4on  test  Java  sources

Produc4on  Java  sources

Unit  test  Java  sources

Page 37: Building a Continuous Delivery 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 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 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    run4me  classpath

Page 40: Building a Continuous Delivery 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    run4me  classpath

Page 41: Building a Continuous Delivery 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    run4me  classpath

gradlew integrationTest

Page 42: Building a Continuous Delivery with Gradle and Jenkins

Database  integra4on  tests

stopDatabasetest start

Databasebuild

Schemaintegration

Test check build...

Page 43: Building a Continuous Delivery with Gradle and Jenkins

Database  integra4on  tests

stopDatabasetest start

Databasebuild

Schemaintegration

Test check build...

Page 44: Building a Continuous Delivery with Gradle and Jenkins

Database  integra4on  tests

apply from: "$rootDir/gradle/databaseSetup.gradle"  !integrationTest.dependsOn startAndPrepareDatabase integrationTest.finalizedBy stopDatabase  !check.dependsOn integrationTest

stopDatabasetest start

Databasebuild

Schemaintegration

Test check build...

Page 45: Building a Continuous Delivery with Gradle and Jenkins

Database  integra4on  tests

apply from: "$rootDir/gradle/databaseSetup.gradle"  !integrationTest.dependsOn startAndPrepareDatabase integrationTest.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 with Gradle and Jenkins

Database  integra4on  tests

apply from: "$rootDir/gradle/databaseSetup.gradle"  !integrationTest.dependsOn startAndPrepareDatabase integrationTest.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 with Gradle and Jenkins

Picking  the  “right”  code  coverage  tool

Page 48: Building a Continuous Delivery with Gradle and Jenkins

Picking  the  “right”  code  coverage  tool

Cobertura Offline  bytecode      instrumenta4on

Page 49: Building a Continuous Delivery with Gradle and Jenkins

Picking  the  “right”  code  coverage  tool

Cobertura Offline  bytecode      instrumenta4on

Offline  bytecode      instrumenta4on

Page 50: Building a Continuous Delivery with Gradle and Jenkins

Picking  the  “right”  code  coverage  tool

Cobertura Offline  bytecode      instrumenta4on

       Source  code      instrumenta4on

Offline  bytecode      instrumenta4on

Page 51: Building a Continuous Delivery with Gradle and Jenkins

Picking  the  “right”  code  coverage  tool

Cobertura Offline  bytecode      instrumenta4on

       Source  code      instrumenta4on

Offline  bytecode      instrumenta4on

On-­‐the-­‐fly  bytecode            instrumenta4on

Page 52: Building a Continuous Delivery with Gradle and Jenkins

On-­‐the-­‐fly  bytecode  instrumenta4on

No  modifica4on  to  source  or  bytecode

Page 53: Building a Continuous Delivery 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 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 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  integra4on  tests

Page 56: Building a Continuous Delivery with Gradle and Jenkins

Genera4ng  coverage  reports

test integrationTest

... ... .exec

Page 57: Building a Continuous Delivery with Gradle and Jenkins

Genera4ng  coverage  reports

test integrationTest

... ... .exec

jacocoTestReport

jacocoIntegrationTestReport

.exec .html

Page 58: Building a Continuous Delivery with Gradle and Jenkins

Genera4ng  coverage  reports

test integrationTest

... ... .exec

jacocoTestReport

jacocoIntegrationTestReport

.exec .html

.html

Page 59: Building a Continuous Delivery 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  4me

Page 60: Building a Continuous Delivery with Gradle and Jenkins

Sta4c  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 with Gradle and Jenkins

Measure  quality  over  4me  with  Sonar

Sonardatabase

Gradle

Sonar Runner

root

model

repo.

web

analyzes

publishes reads / writes

Gradle project

Page 62: Building a Continuous Delivery 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 with Gradle and Jenkins
Page 64: Building a Continuous Delivery with Gradle and Jenkins

Commit  stage:  Assemble  distribu4on

Exclude  env.  configura4on

Include  build  informa4on

Choose  versioning  strategy

PublishBinaries

Commit stage

CompileUnit Tests

IntegrationTests

Code Analysis

AssembleDistribution

Page 65: Building a Continuous Delivery 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 with Gradle and Jenkins

Versioning  strategy

1.0.134 1.0.134

during  development when  released

…the  Con4nuous  Delivery  way

1.0.134Jenkins  build  numberProject  version  number

Page 67: Building a Continuous Delivery 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  implementa4on

Page 68: Building a Continuous Delivery 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 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 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  representa4on

Page 71: Building a Continuous Delivery with Gradle and Jenkins

Packaging  the  deployable  ar4fact

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 with Gradle and Jenkins

Packaging  the  deployable  ar4fact

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  informa4on

Page 73: Building a Continuous Delivery with Gradle and Jenkins

Packaging  the  deployable  ar4fact

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  informa4on

Include  build  info  file  Into  WAR  distribu4on

Page 74: Building a Continuous Delivery with Gradle and Jenkins

Packaging  the  deployable  ar4fact

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  informa4on

Include  build  info  file  Into  WAR  distribu4on

gradlew assemble

Page 75: Building a Continuous Delivery with Gradle and Jenkins

Commit  stage:  Publish  binaries

Version  ar4fact(s)

Use  binary  repository

Publish  once,  then  reuse

PublishBinaries

Commit stage

CompileUnit Tests

IntegrationTests

Code Analysis

AssembleDistribution

Page 76: Building a Continuous Delivery with Gradle and Jenkins

Publishing  the  deployable  ar4fact

1.0.34

1.0.32 1.0.33 1.0.34

Page 77: Building a Continuous Delivery with Gradle and Jenkins

Defining  build  configura4onbinaryRepository { 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 with Gradle and Jenkins

Defining  build  configura4onbinaryRepository { 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    configura4on

Page 79: Building a Continuous Delivery with Gradle and Jenkins

Defining  build  configura4onbinaryRepository { 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-­‐specific  configura4on

       Common    configura4on

Page 80: Building a Continuous Delivery with Gradle and Jenkins

Defining  build  configura4onbinaryRepository { 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-­‐specific  configura4on

       Common    configura4on          Read  creden4als  

 from  gradle.proper4es

         Read  creden4als    from  gradle.proper4es

         Read  creden4als    from  gradle.proper4es

Page 81: Building a Continuous Delivery with Gradle and Jenkins

Reading  build  configura4on

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()) ext.config = parsedConfig

Initializationphase

Congurationphase

Executionphase

Page 82: Building a Continuous Delivery with Gradle and Jenkins

Reading  build  configura4on

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()) ext.config = parsedConfig

Initializationphase

Congurationphase

Executionphase

Assign  configura4on  to                  extra  property

Page 83: Building a Continuous Delivery with Gradle and Jenkins

Reading  build  configura4on

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()) ext.config = parsedConfig

Initializationphase

Congurationphase

Executionphase

Assign  configura4on  to                  extra  property

gradlew –Penv=uat ...

Page 84: Building a Continuous Delivery with Gradle and Jenkins

Using  the  Maven  Publishing  plugin

apply plugin: 'maven-publish'

def 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 with Gradle and Jenkins

Using  the  Maven  Publishing  plugin

apply plugin: 'maven-publish'

def 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  URL  from  configura4on

Page 86: Building a Continuous Delivery with Gradle and Jenkins

Using  the  Maven  Publishing  plugin

apply plugin: 'maven-publish'

def 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  URL  from  configura4on

Assign  publica4on  name                  and  component

Page 87: Building a Continuous Delivery with Gradle and Jenkins

Using  the  Maven  Publishing  plugin

apply plugin: 'maven-publish'

def 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  URL  from  configura4on

gradlew publish

Assign  publica4on  name                  and  component

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

Acceptance  stage:  Retrieve  binaries

Request  versioned  ar4fact

Store  in  temp.  directory

Acceptance stage

DeployBinaries

Functional Tests

RetrieveBinaries

Page 90: Building a Continuous Delivery with Gradle and Jenkins

Downloading  the  deployable  ar4fact

1.0.34

1.0.32 1.0.33 1.0.34

1.0.34

Test

UAT

Prod

Page 91: Building a Continuous Delivery with Gradle and Jenkins

Task  for  downloading  ar4fact

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 with Gradle and Jenkins

Task  for  downloading  ar4fact

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  loca4on  for  downloaded  ar4fact

gradlew downloadBinaryArchive

Page 93: Building a Continuous Delivery 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 with Gradle and Jenkins

Deploying  to  mul4ple  environments

Test

UAT

Prod

–Penv=prod

–Penv=uat

–Penv=test

Page 95: Building a Continuous Delivery 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 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  ar4fact  from  binary  repository  and  undeploy  exis4ng  one

Page 97: Building a Continuous Delivery 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  ar4fact  from  binary  repository  and  undeploy  exis4ng  one

 Only  undeploy  if  URL  context  exists

Page 98: Building a Continuous Delivery 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  ar4fact  from  binary  repository  and  undeploy  exis4ng  one

 Only  undeploy  if  URL  context  exists

Use  environment-­‐specific                                  configura4on

Page 99: Building a Continuous Delivery 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  ar4fact  from  binary  repository  and  undeploy  exis4ng  one

 Only  undeploy  if  URL  context  exists

Use  environment-­‐specific                                  configura4on

gradlew –Penv=uat cargoDeploy

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

Acceptance  stage:  Func4onal  tests

Test  UI  permuta4ons

Test  important  use  cases

Acceptance stage

DeployBinaries

Functional Tests

RetrieveBinaries

Run  against  different  envs

Page 102: Building a Continuous Delivery with Gradle and Jenkins

Execu4ng  func4onal  tests

def functionalTestReportDir = file("$testReportDir/functional") def functionalTestResultsDir = file("$testResultsDir/functional") def functionalCommonSystemProperties =   ['geb.env': 'firefox',   'geb.build.reportsDir': reporting.file("$name/geb")]  !task functionalTest(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 103: Building a Continuous Delivery with Gradle and Jenkins

Execu4ng  func4onal  tests

def functionalTestReportDir = file("$testReportDir/functional") def functionalTestResultsDir = file("$testResultsDir/functional") def functionalCommonSystemProperties =   ['geb.env': 'firefox',   'geb.build.reportsDir': reporting.file("$name/geb")]  !task functionalTest(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          proper4es

Page 104: Building a Continuous Delivery with Gradle and Jenkins

Execu4ng  func4onal  tests

def functionalTestReportDir = file("$testReportDir/functional") def functionalTestResultsDir = file("$testResultsDir/functional") def functionalCommonSystemProperties =   ['geb.env': 'firefox',   'geb.build.reportsDir': reporting.file("$name/geb")]  !task functionalTest(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.  configura4on

Reuse  setup          proper4es

Page 105: Building a Continuous Delivery with Gradle and Jenkins

Execu4ng  func4onal  tests

def functionalTestReportDir = file("$testReportDir/functional") def functionalTestResultsDir = file("$testResultsDir/functional") def functionalCommonSystemProperties =   ['geb.env': 'firefox',   'geb.build.reportsDir': reporting.file("$name/geb")]  !task functionalTest(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.  configura4on

Reuse  setup          proper4es

Page 106: Building a Continuous Delivery with Gradle and Jenkins

Let’s  bring  Jenkins  into  play!

Test

UAT

Prod

     Deployment  Acceptance  Tests

Publish

Download

Trigger  Build

Pull  Source  Code

Page 107: Building a Continuous Delivery with Gradle and Jenkins

Model  pipeline  as  series  of  jobs

Page 108: Building a Continuous Delivery with Gradle and Jenkins

Model  pipeline  as  series  of  jobs

Triggered  job  when  change              to  SCM  is  detected

Page 109: Building a Continuous Delivery with Gradle and Jenkins

Ini4al  Jenkins  Build  Job

Page 110: Building a Continuous Delivery with Gradle and Jenkins

Build  Name  Seker  Plugin

Page 111: Building a Continuous Delivery with Gradle and Jenkins

JaCoCo  Plugin

Page 112: Building a Continuous Delivery with Gradle and Jenkins

Parameterized  Trigger  Plugin

Page 113: Building a Continuous Delivery with Gradle and Jenkins

Gradle  Plugin

Page 114: Building a Continuous Delivery with Gradle and Jenkins

Always  use  the  Wrapper!

Gradle  Plugin

Page 115: Building a Continuous Delivery with Gradle and Jenkins

Always  use  the  Wrapper!

Gradle  Plugin

Run  clean  task  to  remove              exis4ng  ar4facts

Page 116: Building a Continuous Delivery with Gradle and Jenkins

Build  Name  Seker  Plugin

Page 117: Building a Continuous Delivery with Gradle and Jenkins

Clearly  iden4fy  a  build  through  an  expressive                    build  name

Build  Name  Seker  Plugin

Page 118: Building a Continuous Delivery with Gradle and Jenkins

Use  Jenkins  environment  variable

Clearly  iden4fy  a  build  through  an  expressive                    build  name

Build  Name  Seker  Plugin

Page 119: Building a Continuous Delivery with Gradle and Jenkins

Parameterized  Trigger  Plugin

Page 120: Building a Continuous Delivery with Gradle and Jenkins

Next  job  to  trigger  if            build  is  stable

Parameterized  Trigger  Plugin

Page 121: Building a Continuous Delivery with Gradle and Jenkins

Next  job  to  trigger  if            build  is  stable

Defines  build  number  parameter  provided  to  subsequent  jobs

Parameterized  Trigger  Plugin

Page 122: Building a Continuous Delivery with Gradle and Jenkins

Clone  Workspace  SCM  Plugin

Page 123: Building a Continuous Delivery with Gradle and Jenkins

Archive  all  files

Clone  Workspace  SCM  Plugin

Page 124: Building a Continuous Delivery with Gradle and Jenkins

Archive  all  files

Only  archive  if  build          was  successful

Clone  Workspace  SCM  Plugin

Page 125: Building a Continuous Delivery with Gradle and Jenkins

JaCoCo  Plugin

Page 126: Building a Continuous Delivery with Gradle and Jenkins

Point  to  separated  test  results

JaCoCo  Plugin

Page 127: Building a Continuous Delivery with Gradle and Jenkins

Point  to  separated  test  results

JaCoCo  Plugin

Point  to  JaCoCo  files  as  well        as  source  and  class  files

Page 128: Building a Continuous Delivery 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 129: Building a Continuous Delivery with Gradle and Jenkins

Clone  Workspace  SCM  Plugin Build  Name  Seker  Plugin

Page 130: Building a Continuous Delivery with Gradle and Jenkins

Reuse  ini4al  workspace

Clone  Workspace  SCM  Plugin Build  Name  Seker  Plugin

Page 131: Building a Continuous Delivery with Gradle and Jenkins

Reuse  ini4al  workspace

Reuse  ini4al  build  number

Clone  Workspace  SCM  Plugin Build  Name  Seker  Plugin

Page 132: Building a Continuous Delivery with Gradle and Jenkins

Build  Pipeline  Plugin

Page 133: Building a Continuous Delivery with Gradle and Jenkins

Define  the  target  environment

Build  Pipeline  Plugin

Page 134: Building a Continuous Delivery with Gradle and Jenkins

Define  the  target  environment

Downstream  job  that  requires  manual  execu4on

Build  Pipeline  Plugin

Page 135: Building a Continuous Delivery with Gradle and Jenkins

Build  Pipeline  Plugin

Visualiza4on  of  chained  pipeline  jobs

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

> gradle qa  

:askQuestions  

!

BUILD SUCCESSFUL  

!

Total time: 300 secs