continuous delivery with gradle

Post on 26-May-2015

992 Views

Category:

Technology

6 Downloads

Preview:

Click to see full reader

TRANSCRIPT

CONTINUOUS DELIVERYWITH GRADLE

/ / BOB PAULIN @BOBPAULIN BOB@BOBPAULIN.COM

ABOUT MEIndependent ConsultantBusiness EnablementWeb Centric PlatformsAutomation

I LOVE DELIVERING SOFTWARE

I WANT TO DELIVER SOFTWARE ALL THE TIME!

MULTIPLE TIMES A DAY!

WAIT PEOPLE ACTUALLY DO THAT?

SEVERAL MAJOR ECOMMERCE SHOPSETSY.COM DEPLOYS ABOUT 30 TIMES EACH DAY

MY PERSONAL RECORD 5

BENEFITS OF CONTINUOUS DELIVERYShorten the time it takes from conception to customer impactExperiment more frequentlyDo more concurrentlyDelivery becomes a non-event

DELIVERING SOFTWARE CAN BE PAINFUL!Needs to be AssembledNeeds to be DeployedNeeds to be TestedHow can I make sure I don't break existing stuff?What happens if I do break something?What about dependent systems?How do I know what changed?How do I control what goes in and what does not?

ALL THAT'S GOING TO TAKE ME AT LEAST 2WEEKS!

RELEASE MANAGEMENT 101Consistent Build ProcessFunctional/Regression TestingVersioningSource Code ManagementDeployment ProcessRollback

RELEASE MANAGEMENT 501Config SwitchesFeature BranchingModular DeploymentThrottlingAuto ProvisioningAuto-Scaling

TOOLS TO THE RESCUE!

BUILD TOOLS

Dependency ManagementPackagingPlugin ArchitectureLifecycle ManagementVersioning

A RECIPE FOR CONTINUOUS DELIVERYGradleArtifactoryGit

GRADLEBuild ToolGroovyCombines some of the best features of Ant and MavenConventionsPlugins

ARTIFACTORYBinary RepositoryJEE Web AppSupports Maven and IvyOpen Source and Pro Licensed

GITSource Control ManagementDistributedTagging/Branch/Merge

HOW DOES ALL THIS STUFF WORKTOGETHER?

STEPS

SYSTEM INTERACTION

A BRIEF ASIDE ON SEMANTIC VERSIONING

LETS LOOK AT SOME CODE!

GRADLE PLUGINSWar PluginCargo PluginMaven Plugin

GRADLE CONFIGURATIONSCONFIG + CODE!

cargo { containerId = 'tomcat7x' port = Integer.parseInt(getProperty(project.env + ".deployPort"))

deployable { context = artifactId file = project.file(artifactDownloadPath) } remote { hostname = getProperty(project.env + ".deployHostname") username = getProperty(project.env + ".deployUserName") password = getProperty(project.env + ".deployPassword") } }

DON'T EMBED ENVIRONMENT DATA INTO THEBUILD SCRIPT!

CREATE A USER PROPERTIES FILE INSTEAD.

DEPENDENCY MANAGEMENTFOR YOUR APPLICATION AND FOR YOUR BUILD

buildscript { repositories { maven { url "https://oss.sonatype.org/content/groups/public"} mavenCentral() }

dependencies { classpath "javax.servlet:servlet-api:2.5", "org.gradle.api.plugins:gradle-cargo-plugin:0.6.1", "org.ajoberstar:gradle-git:0.6.3" }}

dependencies { def cargoVersion = '1.3.3' def springVersion = '3.2.3.RELEASE' def wro4JVersion = '1.6.3' def aopAllainceVersion = '1.0' cargo "org.codehaus.cargo:cargo-core-uberjar:$cargoVersion", "org.codehaus.cargo:cargo-ant: compile "org.springframework:spring-aop:$springVersion", "org.springframework:spring-beans: "org.springframework:spring-context:$springVersion","org.springframework:spring-context-support: "org.springframework:spring-expression:$springVersion", "org.springframework:spring-tx: "org.springframework:spring-web:$springVersion", "org.springframework:spring-webmvc: "javax.servlet:jstl:1.2","org.slf4j:slf4j-api:1.5.6", "org.slf4j:jcl-over-slf4j:1.5.6" "org.codehaus.jackson:jackson-mapper-asl:1.9.3","aopalliance:aopalliance:$aopAllainceVersion compile("org.springframework.data:spring-data-mongodb:1.0.4.RELEASE"){ exclude module: "slf4j-api" } compile("org.springframework:spring-core:$springVersion"){ exclude module: 'commons-logging' } compile ("ro.isdc.wro4j:wro4j-core:$wro4JVersion") { exclude module: "slf4j-api" } compile("ro.isdc.wro4j:wro4j-extensions:$wro4JVersion") { exclude module: "slf4j-api" exclude module: "slf4j-log4j12" } providedCompile "javax.el:el-api:1.0", "javax.servlet.jsp:jsp-api:2.0", "javax.servlet:servlet-api:2.5" testCompile "junit:junit:3.8.1", "org.springframework:spring-test:$springVersion

}

GRADLE TASKS

task updateUploadedPom(dependsOn: 'getBranchName') << { def pomVersion = project.version if(!project.getGradle().getTaskGraph().hasTask(":release")) pomVersion += ".$branchName" uploadArchives.repositories.mavenDeployer.pom.version = pomVersion}

task tag(type: GitTag) { tagName = version message = "Release of ${version}"}

task pushToRemote(type: GitPush){ pushAll = true}

task qaRelease { dependsOn test, war, getBranchName, updateUploadedPom, uploadArchives, updateVersionNumber, addVersion}

GRADLE TASK DEPENDENCIES

//Task Dependencieswar.mustRunAfter testtag.mustRunAfter warupdateUploadedPom.mustRunAfter taguploadArchives.mustRunAfter updateUploadedPomupdateVersionNumber.mustRunAfter uploadArchivesaddVersionUpdate.mustRunAfter updateVersionNumbercommitVersionUpdate.mustRunAfter addVersionUpdatepushToRemote.mustRunAfter commitVersionUpdate

DEMO TIME!A SIMPLE BOOK REVIEW WEBSITE

ADDING BOOK RATINGS SCORE TO THE SITE

CREATING A FEATURE BRANCH

WRITE THE CODE... WE ALREADY KNOW HOWTO DO THIS!

BUILD PROCESSWhen you say you're code is done the fun is just beginning...

TESTING PROCESSAre you sure you're done?

RELEASE PROCESSYup we're done!

DEPLOYMENT PROCESSOh yeah now we're done

AN ASIDEWhy is deploy separate from release?

DEPLOYMENT PROCESS: TAKE 2Oh ****! What have we done?!?!

KNOW YOUR ROLLBACK STRATEGY BEFOREEVERY DEPLOYMENT

ENTERPRISE ARCHITECTURE

SOME PARTING THOUGHTS ON GRADLE ANDCONTINOUS DELIVERY

BOB PAULIN / / BOB PAULIN @BOBPAULIN BOB@BOBPAULIN.COM

top related