Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Gradle - the Enterprise Automation Tool

Here are slides from basic training for Gradle.
This training is aimed to help Java Developers to get hands-on experience to use Gradle as a primary build tool for Java source code starting from simple compilation continuing with different kinds of tests and finishing with code quality analysis and artefacts publishing.

Gradle - the Enterprise Automation Tool

  1. 1. Gradle The Enterprise Automation Tool
  2. 2. ● SA at EPAM Systems ● primary skill is Java ● hands-on-coding with Groovy, Ruby ● exploring FP with Erlang/Elixir ● passionate about agile, clean code and devops
  3. 3. Agenda ● Introduction ● Gradle ● Step by step by features ● Alternatives ● References ● Q&A
  4. 4. Introduction
  5. 5. Build tools usage trend
  6. 6. Continuous Integration
  7. 7. Principles #1 Each change auto. built and deployed
  8. 8. #2 Test on closed to prod environment Principles #1 Each change auto. built and deployed
  9. 9. #2 Test on closed to prod environment #1 Each change auto. built and deployed #3 Integrate as frequently as possible Principles
  10. 10. #2 Test on closed to prod environment #1 Each change auto. built and deployed #3 Integrate as frequently as possible Principles #4 The highest priority is to fix failed build
  11. 11. Benefits ● Each change guarantees working code ● Each update should guarantee working code ;) ● There is no delay for epic merge ● Less bugs - depends on your tests efficiency* ● Allows to have code ready to go live
  12. 12. Challenges ● Need to build infrastructure ● Need to build team culture ● Need to support/enhance infrastructure ● Overhead with writing different kinds of tests
  13. 13. Continuous D*
  14. 14. Principles #1 Every commit should result in a release
  15. 15. Principles #1 Every commit should result in a release #2 Automated tests are essential
  16. 16. Principles #1 Every commit should result in a release #2 Automated tests are essential #3 Automate everything!
  17. 17. Principles #1 Every commit should result in a release #2 Automated tests are essential #3 Automate everything! #4 Done means release/live in prod
  18. 18. Benefits ● Speed of delivery of business idea to customer ● Easy going live deployment ● Less time spent on delivery - more profit ● More motivation to do more as you can see what you can change/improve
  19. 19. Challenges ● Big effort to implement changes for: ○ database increment/rollback ○ infrastructure rollout/rollback ○ decrease down time … ● Need to get customers to buy in ● Security policies
  20. 20. Gradle
  21. 21. 2.14.1
  22. 22. Gradle - General purpose build system
  23. 23. Gradle - General purpose build system - Comes with a rich DSL based on Groovy
  24. 24. Gradle - General purpose build system - Comes with a rich DSL based on Groovy - Follows ”build-by-convention” principles
  25. 25. Gradle - General purpose build system - Comes with a rich DSL based on Groovy - Follows ”build-by-convention” principles - Built-in plug-ins for JVM languages, etc
  26. 26. Gradle - General purpose build system - Comes with a rich DSL based on Groovy - Follows ”build-by-convention” principles - Built-in plug-ins for JVM languages, etc - Derives all the best from Ivy, Ant & Maven
  27. 27. Features
  28. 28. 1. JDK 8 2. Gradle 2.2+ 3. Git Prerequisites
  29. 29. 1. Change directory to D:ImagesGradle folder 2. Open Command Window in dir D:ImagesGradle 3. Execute ​ Gitbingit clone https://github.com/webdizz/sbs-gradle.git 4. Change directory to sbs-gradle 5. Execute set_env.bat gradle -v java -version #0 Installation
  30. 30. Groovy is under the hood
  31. 31. 1. Reset code base to initial state git reset --hard 3a2ed47 git clean -df​ 2. Create file build.gradle 3. Type ​ println 'Hello, World!​​​​​​​​​​​'​ 4. Run gradle #1 Hello World!
  32. 32. Declarative
  33. 33. 1. Run to see default tasks list gradle tasks 2. Replace build.gradle file content with ​ apply plugin: 'java'​ 3. Run to see new available tasks gradle tasks 4. Checkout step s3_apply_plugin 5. Run to build Java source code gradle build 6. Explore directory build #2 Create simple build
  34. 34. Flexible Execution
  35. 35. 1. Run task with part of name gradle ta 2. Run task with part of name to clean and compile ​ gradle cle tC 3. Run task with part of name to clean and compile and exclude processTestResources gradle cle tC -x pTR 4. Get details for task gradle -q help --task clean #3 Execute tasks
  36. 36. 1. Run task gradle tasks 2. Run task to generate wrapper ​ gradle wrapper 3. Run tasks using wrapper ./gradlew tasks 4. Customize task wrapper to use another Gradle version ​task wrapper(type: Wrapper) { gradleVersion = '2.2.1' }​ 5. Check Gradle version ./gradlew -v #4 Use wrapper
  37. 37. Multi-module Structure
  38. 38. 1. Checkout step s5_prepare 2. Add directory common 3. Move src to common 4. Create common/build.gradle for Java 5. Add new module to settings.gradle include ':common'​ 6. Run build ./gradlew clean build 7. Run task for module ./gradlew :com:compJ #5 Create multi-module build
  39. 39. Dependency Management
  40. 40. Gradle - compile - to compile source
  41. 41. Gradle - compile - to compile source - runtime - required by classes at runtime
  42. 42. Gradle - compile - to compile source - runtime - required by classes at runtime - testCompile - to compile test sources
  43. 43. Gradle - compile - to compile source - runtime - required by classes at runtime - testCompile - to compile test sources - testRuntime - required to run the tests
  44. 44. 1. Add repositories to download dependencies from to build.gradle allprojects { currProject -> repositories { mavenLocal() mavenCentral() jcenter() maven {url 'http://repo.mycompany.com/’} } }​ #6 Dependencies
  45. 45. 1. Add common dependencies for all subprojects in build.gradle subprojects { apply plugin: 'java' dependencies { compile 'org.slf4j:slf4j-api:1.7.7' testCompile 'org.mockito:mockito-core:1.10.19', 'junit:junit:4.12' } }​ #6.1 Dependencies
  46. 46. 1. Add dependencies for concrete module in common/build.gradle dependencies { compile 'org.projectlombok:lombok:1.14.4' }​ #6.2 Dependencies
  47. 47. 1. List project dependencies ./gradlew :common:dependencies #6.3 Dependencies
  48. 48. Configuration
  49. 49. 1. Extract common configuration parameters to gradle .properties file lombokVersion = 1.14.4 build.gradle file dependencies { compile “org.projectlombok:lombok:$lombokVersion” }​ #7 Configuration
  50. 50. 1. Parameterise execution for custom task :printParameter in build.gradle task printParameter { println givenParameter }​ 2. Add parameter default value to gradle.properties 3. Execute task ./gradlew -q :printParameter -PgivenParameter=hello #7.1 Configuration
  51. 51. Rich API
  52. 52. #8 Rich API
  53. 53. ● Lifecycle ● Create a Settings instance for the build. ● Evaluate the settings.gradle script, if present, against the Settings object to configure it. ● Use the configured Settings object to create the hierarchy of Project instances. ● Finally, evaluate each Project by executing its build.gradle file, if present, against the project. The project are evaluated in such order that a project is evaluated before its child projects.
  54. 54. ● Tasks ● A project is essentially a collection of Task objects. ● Each task performs some basic piece of work. ● Dependencies ● A project generally has a number of dependencies. ● Project generally produces a number of artifacts, which other projects can use.
  55. 55. ● Plugins ● Plugins can be used to modularise and reuse project configuration. ● Properties ● Any property or method which your script uses is delegated through to the associated Project object. ● A project has 5 property 'scopes'. ● Dynamic Methods ● A project has 5 method 'scopes'.
  56. 56. More Tests
  57. 57. 1. Add integration test source sets in file gradle/integTest.gradle sourceSets { integTest { compileClasspath += main.output + test.output runtimeClasspath += main.output + test.output } } #8.1 Rich API
  58. 58. 2. Add integration test configurations in file gradle/integTest.gradle configurations { integTestCompile.extendsFrom testCompile integTestRuntime.extendsFrom testRuntime } 3. Include extension for subprojects in file build.gradle apply from: file("${rootProject.projectDir}/gradle/integ Test.gradle")​ #8.1 Rich API
  59. 59. 3. Add integration test task in file gradle/integTest.gradle task integTest(type: Test){ testClassesDir = sourceSets.integTest.output.classesDir classpath = sourceSets.integTest.runtimeClasspath shouldRunAfter 'test' } check.dependsOn(integTest) 4. Execute integration tests ./gradlew integTest #8.1 Rich API
  60. 60. 1. Open build.gradle to add dependency for one task from another ​ printParameter.dependsOn 'help'​ 2. Run printParameter task ./gradlew printParameter #8.2 Tasks Dependencies
  61. 61. 1. Open build.gradle to add ordering for one task from another task areTestsExist { if ([ file("${projectDir}/src/test/java").listFiles() ].isEmpty()) { println 'Test directory is empty' } else { println 'Test directory is not empty, will execute tests' } } test.mustRunAfter areTestsExist #8.3 Tasks Ordering*
  62. 62. 2. Run test task ./gradlew test #8.3 Tasks Ordering*
  63. 63. 1. Add rule to validate running of integration tests task tasks.addRule('Check correctness of running tests'){ String taskName -> gradle.taskGraph.whenReady{ Map<String, String> args = gradle.startParameter.systemPropertiesArgs gradle.taskGraph.allTasks.each { Task task -> if (task.name.contains('integTest') && !args.containsKey('profile')) { throw new org.gradle.api.tasks.StopExecutionException("Profile was not specified to run tests (-Dprofile=ci).") } } } } #8.4 Rules
  64. 64. 2. Run check task to have failure ./gradlew check 3. Run check task with expected parameter ./gradlew check -Dprofile=ci ​ #8.4 Rules
  65. 65. Parallel Execution
  66. 66. 1. Switch to 9th step and execute next command ./gradlew test --parallel 2. Try to modify amount of executable threads ./gradlew test --parallel --parallel-threads=3 ​ #9 Parallel builds
  67. 67. Incremental Builds
  68. 68. 1. Create file gradle/releaseNotes.gradle to add task for release notes ext.destDir = new File(buildDir, 'releaseNotes') ext.releaseNotesTemplate = file('releaseNotes.tmpl.txt') tasks.create(name: 'copyTask', type: org.gradle.api.tasks.Copy) { from releaseNotesTemplate into destDir doFirst { if (!destDir.exists()) { destDir.mkdir() } } rename { String fileName -> fileName.replace('.tmpl', '') } } #10 Custom Inputs/Outputs
  69. 69. tasks.create('releaseNotes') { inputs.file copyTask outputs.dir destDir } 2. Add releaseNotes.tmpl.txt file as a template for release notes 3. Apply configuration from gradle/releaseNotes.gradle in build.gradle 4. Let’s run releaseNotes task ./gradlew releaseNotes #10 Custom Inputs/Outputs
  70. 70. 1. Enhance release notes task to prepare nice release notes file ​ ext.changesFile = file('changes.txt') ext.bugs = [] ext.features = [] changesFile.eachLine { String line -> String bugSymbol = '#bug:' String featureSymbol = '#feature:' if (line.contains(bugSymbol)) { bugs << line.replace(bugSymbol, '') } else if (line.contains(featureSymbol)) { features << line.replace(featureSymbol, '') } } filter(org.apache.tools.ant.filters.ReplaceTokens, tokens: [bugs: bugs.join("n"), features: features.join("n")])​ #10.1 Files filtering
  71. 71. Test Coverage
  72. 72. 1. Add JaCoCo configuration in gradle/coverage.gradle apply plugin: "jacoco" jacoco { toolVersion = "0.7.7.201606060606" } check.dependsOn jacocoTestReport jacocoTestReport { dependsOn 'test' reports { xml.enabled true csv.enabled false html.enabled true } } #11 Test Coverage
  73. 73. 2. Apply configuration from gradle/coverage.gradle in build.gradle 3. Implement proper test for proper method 4. Let’s run check task to collect coverage metrics ./gradlew check -Dprofile=ci 5. Open common/build/reports/jacoco/test/html/index.html file to overview coverage #11 Test Coverage
  74. 74. 1. Add JaCoCo configuration in gradle/coverage.gradle for integration tests ​task jacocoIntegrationTestReport(type: JacocoReport) { dependsOn integTest sourceSets sourceSets.main executionData integTest reports { xml { enabled true destination "$buildDir/reports/jacoco/integTest/jacocoIntegTestReport.xml" } csv.enabled false html { destination "$buildDir/reports/jacoco/integTest/html" } } } #11.1 Integration Test Coverage
  75. 75. check.dependsOn jacocoIntegrationTestReport jacocoIntegrationTestReport.mustRunAfter jacocoTestReport 2. Let’s run check task to collect coverage metrics for integration tests as well ./gradlew check -Dprofile=ci ​ #11.1 Integration Test Coverage
  76. 76. Static Code Analysis
  77. 77. Ad-hoc, fast feedback
  78. 78. Ad-hoc, fast feedback Over time
  79. 79. 1. Add configuration in gradle/codeQuality.gradle for code quality analysis and apply configuration in build.gradle subprojects { apply plugin: 'findbugs' findbugs { ignoreFailures = true toolVersion = '3.0.0' } apply plugin: 'pmd' pmd { toolVersion = '5.1.3' } } ​ #12 Static Code Analysis
  80. 80. 2. Let’s run check task to collect code quality metrics ./gradlew check -Dprofile=ci 3. Open common/build/reports/pmd|findbugs/*.html ​ ​ #12 Static Code Analysis
  81. 81. Artefacts Publishing
  82. 82. 1. Add configuration in gradle/publishing.gradle for artefacts publishing and apply configuration in build.gradle apply plugin: 'maven-publish' publishing { repositories { maven { url "http://artifactory.vagrantshare.com/artifactory/libs-release-local" credentials { username 'admin' password 'password' } } } publications { mavenJava(MavenPublication) { groupId "name.webdizz.${rootProject.name}" version = uploadVersion from components.java } } } #13 Artefacts Publishing
  83. 83. 2. Let’s run publish task to publish artefacts ./gradlew publish -PuploadVersion=1.1.1.[YourName] 3. Check artefact was uploaded at http://artifactory.vagrantshare.com/artifactory ​ ​ #13 Artefacts Publishing
  84. 84. Plugable Architecture
  85. 85. ● Build script Visible for build file ● buildSrc/src/main/groovy Visible for project ● Standalone project Could be shared between projects using binary artefact
  86. 86. 1. Create file PluginsPrinterPlugin.groovy in buildSrc/src/main/groovy ​import org.gradle.api.Plugin import org.gradle.api.Project public class PluginsPrinterPlugin implements Plugin<Project> { void apply(Project project) { project.task('printPlugins') << { println 'Current project has next list of plugins:' ext.plugins = project.plugins.collect { plugin -> plugin.class.simpleName } println plugins } } } #14 Plugins Printer
  87. 87. 2. Apply plugin for all projects in build.gradle file allprojects { apply plugin: PluginsPrinterPlugin } 3. Let’s run printPlugins task to print plugins activated for project ./gradlew printPlugins ​ ​ #14 Plugins Printer
  88. 88. Alternatives
  89. 89. - build like you code
  90. 90. - a software project management and comprehension tool
  91. 91. References
  92. 92. ● http://www.gradle.org/ ● http://www.gradle.org/books ● https://plugins.gradle.org/ ● http://groovy-lang.org/ ● https://github.com/webdizz/sbs-gradle ● https://nebula-plugins.github.io/ References
  93. 93. Q&A
  94. 94. Izzet Mustafayev@EPAM Systems @webdizz webdizz izzetmustafaiev http://webdizz.name

×