Slide 1

Slide 1 text

Bootstrapping Continuous Integration & Deployment

Slide 2

Slide 2 text

John Engelman • Chief Technologist @ OPI • Ratpack Core Team • Author - Shadow Plugin • @johnrengelman • github.com/johnrengelman

Slide 3

Slide 3 text

What is “bootstrapping”?

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

What is “bootstrapping”? • Going from 0 to 60 in 4.4s • Providing a consistent set of sane configurations • Ensure the important things are ALWAYS there

Slide 6

Slide 6 text

Java Groovy Codenarc Spring Boot Application Shadow Organization Rules/Conventions MyOrg.Service Core & 3rd Party Plugins Organization Plugins

Slide 7

Slide 7 text

Where to start?

Slide 8

Slide 8 text

• Script Plugins • Quickly try new settings • Share using a hosted location • Packaged Library • If you need to include additional resources

Slide 9

Slide 9 text

https://github.com/nebula-plugins

Slide 10

Slide 10 text

Good Things to Bootstrap • Versioning • IDE integration • Dependency Repositories • Testing/Static Analysis • Artifacts/Publishing • Credentials

Slide 11

Slide 11 text

Things you might bootstrap • Common library versions (spock, joda-time, groovy)

Slide 12

Slide 12 text

Gradle Project DSL It’s your friend. Read it. Use it. https://docs.gradle.org/current/dsl/org.gradle.api.Project.html

Slide 13

Slide 13 text

• Make liberal use of PluginContainer • React to other plugins

Slide 14

Slide 14 text


 project.plugins.withType(JavaPlugin) {
 //Do stuff if Java has been added
 }
 
 project.plugins.withId('com.github.johnrengelman.shadow') {
 //Do stuff if Shadow has been added
 }

Slide 15

Slide 15 text


 project.ext.isSnapshot = project.version.toString().endsWith(‘-SNAPSHOT') 
 project.ext.buildNumber = System.getenv('BUILD_NUMBER')
 project.ext.isCI = System.getenv('JENKINS_HOME') != null • Utilize Extra Properties for flags

Slide 16

Slide 16 text


 // Create codenarc.groovy file if missing
 File rules = new File("${project.rootDir}/gradle/codenarc.groovy")
 if (!rules.exists()) {
 rules.parentFile.mkdirs()
 rules.withWriter { BufferedWriter writer ->
 writer.write this.class.getResourceAsStream( "/${rules.name}").text
 }
 }
 } • Template standard files

Slide 17

Slide 17 text

• Determine Version

Slide 18

Slide 18 text


 project.gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph ->
 project.tasks.withType(PublishToMavenRepository).matching { PublishToMavenRepository task ->
 task.repository.name == 'Demo'
 }.each { PublishToMavenRepository publishTask ->
 if (taskGraph.hasTask(publishTask)) {
 PasswordCredentials creds = publishTask.repository.credentials
 Map userCreds = getCredentials(project)
 creds.username = userCreds.username
 creds.password = userCreds.password
 }
 }
 } • Lookup and apply Credentials only when needed

Slide 19

Slide 19 text

Bootstrapping Build Settings • Some things can’t be configured by plugins • buildscript • settings.gradle

Slide 20

Slide 20 text

• Clone a template repo to start • Lazybones • https://github.com/pledbrook/lazybones • Yeoman • http://yeoman.io/ • Init Scripts • https://docs.gradle.org/current/userguide/init_scripts.html • Customized Gradle Distribution using Gradle Wrapper

Slide 21

Slide 21 text

Bootstrapping Plugin Project

Slide 22

Slide 22 text

Plugin Project Applies Defines

Slide 23

Slide 23 text

//buildSrc/build.gradle apply plugin: 'groovy' if (!project.plugins.collect { it.class.name }.any { it.endsWith(‘JetGradlePlugin') }) {
 sourceSets {
 main {
 groovy.srcDirs = ['src/main/groovy', '../src/main/groovy']
 resources.srcDirs = [‘../src/main/resources'] 
 }
 }
 }


Slide 24

Slide 24 text

//buildSrc/build.gradle class ScriptHolder {
 Closure dependencies
 
 void dependencies(Closure c) { this.dependencies = c }
 void apply(Map map) {}
 } 
 ScriptHolder holder = new ScriptHolder()
 CompilerConfiguration cc = new CompilerConfiguration()
 cc.setScriptBaseClass(DelegatingScript.class.name)
 GroovyShell sh = new GroovyShell(Project.class.classLoader, new Binding(), cc)

Slide 25

Slide 25 text

//buildSrc/build.gradle
 
 //Use this parse command because Groovy wants to use the file name as the classname which fails due to the '-'
 DelegatingScript script = (DelegatingScript)sh.parse( file('../gradle-plugins.gradle').text, 'GradlePlugins')
 script.setDelegate(holder)
 script.run()
 
 def closure = holder.dependencies.clone()
 closure.delegate = project.dependencies
 closure()

Slide 26

Slide 26 text

Questions?

Slide 27

Slide 27 text

Thank you!