Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Lightweight Developer Provisioning with Gradle

Lightweight Developer Provisioning with Gradle

Every software project starts with the setup of a local development environment: a JDK, a preferred IDE and build tool, a local database and application server and so forth. Everything you and your team needs to be productive from day one. Time is valuable, so you take the quick route and reuse a development environment from a previous project. Broken windows from day one! With the first required changes things usually start to go wrong, the individual environments start to diverge and problems during the build or local execution of your software are inevitable. So how can you do better? The short answer is: with SEU-as-code, a lightweight approach and tool based on Gradle that helps to alleviate and automate the provisioning of developers. This session has been presented at the #JavaOne 2016 conference. (c) @LeanderReimer @qaware

M.-Leander Reimer

September 19, 2016
Tweet

More Decks by M.-Leander Reimer

Other Decks in Programming

Transcript

  1. Lightweight Developer Provisioning with Gradle and SEU-as-code | JavaOne 2016

    | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 1
  2. About me Mario-Leander Reimer Chief Technologist, QAware GmbH [email protected] twitter://@LeanderReimer

    http://speakerdeck.com/lreimer http://github.com/lreimer http://github.com/seu-as-code http://seu-as-code.io http://www.qaware.de | JavaOne 2016 | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 2
  3. | JavaOne 2016 | task seuAsCode() << { println "created

    with ❤ and ☕ by @LeanderReimer" } 3
  4. SEU: a German acronym; software development environment | JavaOne 2016

    | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 4
  5. 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
  6. | JavaOne 2016 | task seuAsCode() << { println "created

    with ❤ and ☕ by @LeanderReimer" } 6
  7. The ideal. | JavaOne 2016 | task seuAsCode() << {

    println "created with ❤ and ☕ by @LeanderReimer" } 7
  8. | JavaOne 2016 | task seuAsCode() << { println "created

    with ❤ and ☕ by @LeanderReimer" } 8
  9. The reality? | JavaOne 2016 | task seuAsCode() << {

    println "created with ❤ and ☕ by @LeanderReimer" } 9
  10. 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
  11. 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
  12. Demo. | JavaOne 2016 | task seuAsCode() << { println

    "created with ❤ and ☕ by @LeanderReimer" } 12
  13. 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
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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
  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.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
  20. 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
  21. 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
  22. Example 1: Init and delete Derby DB ext.derbyHome = System.env['DERBY_HOME']

    // import SQL file via the provided Derby command line tool task 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
  23. 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
  24. 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
  25. Don't use shell scripts. Use Gradle instead! | JavaOne 2016

    | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 25
  26. 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
  27. Let's build our first package using Gradle! | JavaOne 2016

    | task seuAsCode() << { println "created with ❤ and ☕ by @LeanderReimer" } 27
  28. | JavaOne 2016 | task seuAsCode() << { println "created

    with ❤ and ☕ by @LeanderReimer" } 28
  29. 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
  30. 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
  31. 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
  32. 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
  33. 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
  34. What's next? | JavaOne 2016 | task seuAsCode() << {

    println "created with ❤ and ☕ by @LeanderReimer" } 34
  35. 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
  36. 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
  37. Q & A | JavaOne 2016 | task seuAsCode() <<

    { println "created with ❤ and ☕ by @LeanderReimer" } 37