Upload
qaware-gmbh
View
67
Download
0
Embed Size (px)
Citation preview
Lightweight Developer
Provisioning with Gradle
and SEU-as-code| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 1
About me
Mario-Leander ReimerChief Technologist, QAware [email protected]
twitter://@LeanderReimerhttp://speakerdeck.com/lreimerhttp://github.com/lreimerhttp://github.com/seu-as-codehttp://seu-as-code.iohttp://www.qaware.de
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 2
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 3
SEU: a German acronym;software development environment
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 4
Definition of Software Industrialization
• This has nothing to do with cheap labor!
• Automation of repetitive and laborious tasks
• Better software quality through standardized, streamlined tooling
• Well integrated tool chain leads to a higher productivity and happiness of your team
• Better cost efficiency and competitiveness
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 5
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 6
The ideal.
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 7
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 8
The reality?
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 9
What are the problems?
• Manual and error prone creation and update procedure of individual SEUs
• Individual SEUs produce different results and strange bugs
• Old versions of a SEU can't easily be restored
• The SEU for a new project is often a copy of a
previous project. ! Broken windows! !
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 10
The solution ...
• Use a build tool for the automated creation and update of a SEU
• Software packages are expressed as dependencies
• Gradle tasks and Groovy are used instead of shell scripting
• Everything is version controlled just like ordinary source code
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 11
Demo.
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 12
The most minimalistic SEU
plugins { id 'de.qaware.seu.as.code.base' version '2.4.0'}
seuAsCode { seuHome = 'J:' projectName = 'JavaOne 2016'}
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 13
Multi platform SEUs for mixed teams
plugins { id 'de.qaware.seu.as.code.base' version '2.4.0'}
import static de.qaware.seu.as.code.plugins.base.Platform.isMac
seuAsCode { // use closure or Elvis operator (no syntax highlighting :( seuHome = { if (isMac()) '/Volumes/JavaOne-2016' else 'J:' } projectName = 'JavaOne 2016'}
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 14
Software packages are dependencies
• Gradle has built-in support for dependencies
• Gradle supports different artifact repositories (Maven, Ivy, Directory)
• Transitive dependencies between software packages are supported
• Use dependency configurations to determine installation directory
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 15
Software dependencies and configurations
repositories {
maven { url 'https://dl.bintray.com/seu-as-code/maven' }
jcenter()
}
dependencies {
seuac 'org.codehaus.groovy.modules.scriptom:scriptom:1.6.0'
seuac 'com.h2database:h2:1.4.188'
home 'de.qaware.seu.as.code:seuac-home:2.4.0'
software 'de.qaware.seu.as.code:seuac-environment:2.4.0:jdk8'
software 'org.gradle:gradle:2.14.1'
software "net.java:openjdk8:8u40:$osClassifier"
}
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 16
Secure passwords with Credentials plugin
plugins { id 'de.qaware.seu.as.code.credentials' version '2.4.0' }
repositories {
maven {
url 'https://your.company.com/nexus/repo'
credentials {
// access stored credentials via extra property
username project.credentials['Nexus'].username
password project.credentials['Nexus'].password
}
}
}
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 17
Platform plugin for OS specific builds
plugins { id 'de.qaware.seu.as.code.platform' version '1.0.0' }
platform { win { task helloSeuAsCode(group: 'Example') << { println 'Hello SEU-as-code on Windows.' } } mac { task helloSeuAsCode(group: 'Example') << { println 'Hello SEU-as-code on MacOS.' } }}
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 18
Manage sources with Git or SVN plugin
plugins { id 'de.qaware.seu.as.code.credentials' version '2.4.0' id 'de.qaware.seu.as.code.git' version '2.3.0'}
git { plugins { url 'https://github.com/seu-as-code/seu-as-code.plugins.git' directory file("$seuHome/codebase/plugins/") username project.credentials['Github'].username password project.credentials['Github'].password }}
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 19
Manage sources with Git or SVN plugin
plugins { id 'de.qaware.seu.as.code.credentials' version '2.4.0' id 'de.qaware.seu.as.code.svn' version '2.1.1'}
subversion { usersGuide { url 'https://github.com/seu-as-code/seu-as-code.users-guide.git' directory file("$seuHome/docbase/users-guide/") username project.credentials['Subversion'].username password project.credentials['Subversion'].password }}
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 20
Implement scripts using plain Gradle
• Gradle build scripts are code! Be creative.
• Gradle provides useful predefined tasks: Copy, Exec, Sync, Delete, ...
• Gradle tasks can easily reuse Ant tasks.
• Gradle tasks can be implemented in Groovy code.
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 21
Example 1: Init and delete Derby DB
ext.derbyHome = System.env['DERBY_HOME']
// import SQL file via the provided Derby command line tooltask initDemoDb(type: Exec, group: 'Database') { workingDir "$derbyHome/bin" commandLine 'cmd', '/B', '/C', 'ij.bat', "$rootDir/scripts/init.sql"}
task deleteDemoDb(type: Delete, group: 'Database') { delete "$derbyHome/demo"}
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 22
Example 1: The Groovy SQL way
import groovy.sql.*
task initDemoDb(group: 'Database') << {
def derby = [
url: 'jdbc:derby://localhost:1527/demo;create=true',
driver: 'org.apache.derby.jdbc.ClientDriver',
user: 'admin',
password: 'secret'
]
Sql.withInstance(derby) {
execute file("$rootDir/scripts/database/init.sql").text
}
}
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 23
Example 2: Restore Solr index data
ext.cores = ['de_DE', 'en_GB', 'zh_CN']
task solrRestoreAll(group: 'Solr') { }
cores.each { coreName -> def name = coreName.replaceAll("_", "").capitalize()
task "solrRestore${name}"(type: Sync, group: 'Solr') { from zipTree("$rootDir/scripts/solr/${coreName}.zip") into "$seuHome/software/solr-4.7.2/example/solr/${coreName}" }
solrRestoreAll.dependsOn "solrRestore${name}"}
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 24
Don't use shell scripts. Use
Gradle instead!
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 25
Building software packages is easy
• Software packages are essentially plain JAR files (software + customizations)
• 26 packages available via a Bintray repository https://bintray.com/seu-as-code/maven
• 44 package build blue-prints are available at Github, continuously growing.
• Software packages can be build with Gradle!
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 26
Let's build our first package using Gradle!
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 27
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 28
Download the original binary distribution
plugins {
id 'de.undercouch.download' version '1.2'
}
import de.undercouch.gradle.tasks.download.Download
task downloadArchive(type: Download) {
src 'https://services.gradle.org/distributions/gradle-3.0-all.zip'
dest "$buildDir"
}
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 29
Unpack archive using simple Gradle task
task extractArchive(type: Copy, dependsOn: downloadArchive) { from { zipTree("$buildDir/${project.name}-${version}-all.zip") } into "$buildDir/files"}
// Best practice: directory name matches the package name// optionally rename the extracted directory if required
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 30
Customize with additional files and hooks
// plain Groovy, place as a file under META-INF/hooks/
import org.codehaus.groovy.scriptom.*
Scriptom.inApartment{ def wshShell = new ActiveXObject("WScript.Shell") def shortcut = wshShell.CreateShortcut("$seuHome\\gradle.lnk") shortcut.TargetPath = "${seuLayout.software}\\go-gradle.bat" shortcut.WorkingDirectory = "${seuLayout.codebase}" shortcut.Save()}
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 31
Repackage all files as a normal JAR file
task buildPackage(type: Jar, dependsOn: extractArchive) { baseName project.name version version extension 'jar' // classifier 'x86' destinationDir buildDir from "$buildDir/files" // the extracted files from "files" // some extra files}
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 32
Publish JAR artifact to a repository server
publishing {
publications {
gradle(MavenPublication) {
artifact "${buildDir}/${project.name}-${version}.jar"
}
}
repositories {
maven {
// alternatively, use your private company repository server
url 'https://bintray.com/seu-as-code/maven'
credentials { ... }
}
}
}
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 33
What's next?
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 34
More features to come ...
• Continuously add more software packages
• Create plugin to build software packages
• Support for self-downloading packages
• Add support for other package managers
• Add Vault support for Credentials plugin
• Improve documentation and user’s guide
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 35
Star SEU-as-code on Github!
$ git clone https://github.com/seu-as-code/seu-as-code.archetype.git
$ git clone https://github.com/seu-as-code/seu-as-code.plugins.git
$ git clone https://github.com/seu-as-code/seu-as-code.packages.git
$ git clone https://github.com/seu-as-code/seu-as-code.examples.git
$ git clone https://github.com/seu-as-code/seu-as-code.documentation.git
$ git clone https://github.com/seu-as-code/seu-as-code.users-guide.git
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 36
Q & A
| JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 37