gradle - the enterprise automation tool
DESCRIPTION
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.TRANSCRIPT
Gradle The
Enterprise Automation Tool
● SA at EPAM Systems
● primary skill is Java
● hands-on-coding with Groovy, Ruby
● trying to learn some Scala and Erlang/Elixir
● passionate about agile, clean code and devops
Izzet Mustafayev@EPAM Systems@webdizz webdizz izzetmustafaievhttp://webdizz.name
Agenda● Introduction
● Gradle
● Step by step by features
● Alternatives
● References
● Q&A
Introduction
Continuous Integration
Principles
#1 Every change automatically pulled
#2 Every change automatically built
Principles
#1 Every change automatically pulled
#2 Every change automatically built
#1 Every change automatically pulled
#3 Every change in the code base line*
Principles
Benefits● Each change guarantees working code
● Each update should guarantee working
code ;)
● Do not delay epic merge
● Less bugs - depends on your tests
efficiency
● Allows to have code ready to go live
Drawbacks● Need to build infrastructure
● Need to build team culture
● Need to support/enhance infrastructure
● Overhead with writing a lot of different
kind of tests
Continuous Delivery
Principles
#1 Every commit can result in a release
Principles
#1 Every commit can result in a release
#2 Automate everything!
Principles
#1 Every commit can result in a release
#2 Automate everything!
#3 Automate a pain!
Principles
#1 Every commit can result in a release
#2 Automate everything!
#3 Automate a pain!
#4 Done means released
Benefits● Automatic 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
Drawbacks● Big effort to implement changes for:
○ infrastructure rollout/rollback
○ database increment/rollback
○ decrease down time …towards 0
● Need to get customers to buy in
● Security policies
Gradle
2.2
Gradle- General purpose build system
Gradle- General purpose build system
- Comes with a rich DSL based on Groovy
Gradle- General purpose build system
- Comes with a rich DSL based on Groovy
- Follows ”build-by-convention” principles
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
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
Features
1. Download Gradle http://goo.gl/ktu7H6
2. Download zipped JDK from https://db.tt/HKW6GbI9
3. Unzip all above into D:\Images\Gradle folder
4. Open Command Window in dir D:\Images\Gradle
5. Execute
set JAVA_HOME=D:\Images\Gradle\jdk1.8.0_25
6. Execute
gradle-2.1\bin\gradle -v
7. Download and install Git from from http://goo.
gl/rv2G1X into D:\Images\Gradle\Git
#0 Installation
8. Clone Git repository
git\bin\git.exe clone https://github.
com/webdizz/sbs-gradle.git
#0 Installation
Groovy is under the hood
1. Reset code base to initial state
git reset --hard bed2227791
git clean -df
2. Create file build.gradle
3. Type
println 'Hello, World!'
4. Run
gradle
#1 Hello World!
Declarative
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 s2_prepare
5. Run to build Java source code
gradle build
6. Explore directory build
#2 Create simple build
Flexible Execution
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
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-rc-1'
}
5. Check Gradle version
./gradlew -v
#4 Use wrapper
Multi-module Structure
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
Dependency Management
Gradle- compile - to compile source
Gradle- compile - to compile source
- runtime - required by classes at runtime
Gradle- compile - to compile source
- runtime - required by classes at runtime
- testCompile - to compile test sources
Gradle- compile - to compile source
- runtime - required by classes at runtime
- testCompile - to compile test sources
- testRuntime - required to run the tests
1. Add repositories to download dependencies from to
build.gradle
allprojects { currProject ->
repositories {
mavenLocal()
mavenCentral()
jcenter()
maven {url 'http://repo.mycompany.com/’}
}
}
#6 Dependencies
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.9.5',
'junit:junit:4.12-beta-1'
}
}
#6.1 Dependencies
1. Add dependencies for concrete module in
common/build.gradle
dependencies {
compile
'org.projectlombok:lombok:1.14.4'
}
#6.2 Dependencies
1. List project dependencies
./gradlew :common:dependencies
#6.3 Dependencies
Configuration
1. Extract common configuration parameters to gradle .
properties file
lombokVersion = 1.14.4
build.gradle file
dependencies {
compile
“org.projectlombok:lombok:$lombokVersion”
}
#7 Configuration
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
Rich API
#8 Rich API
● 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.
● 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.
● 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'.
More Tests
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
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/integTest.gradle")
#8.1 Rich API
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
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
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
2. Run printParameter task
./gradlew printParameter
#8.3 Tasks Ordering*
2. Run test task
./gradlew test
#8.3 Tasks Ordering*
1. Add rule to validate running of integration tests tasktasks.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
2. Run check task to have failure
./gradlew check
3. Run check task with expected parameter
./gradlew check -Dprofile=ci
#8.4 Rules
Parallel Execution
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
Incremental Builds
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
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
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
Test Coverage
1. Add JaCoCo configuration in gradle/coverage.gradle apply plugin: "jacoco"
jacoco {
toolVersion = "0.7.2.201409121644"
}
check.dependsOn jacocoTestReport
jacocoTestReport {
dependsOn 'test'
reports {
xml.enabled true
csv.enabled false
html.enabled true
}
}
#11 Test Coverage
2. Apply configuration from gradle/coverage.gradle in build.gradle
3. Implement proper test for proper method4. 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
1. Add JaCoCo configuration in gradle/coverage.gradle for integration teststask 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
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
Static Code Analysis
Ad-hoc, fast feedback
Ad-hoc, fast feedback
Over time
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
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
Artefacts Publishing
1. Add configuration in gradle/publishing.gradle for artefacts publishing and apply configuration in build.gradleapply plugin: 'maven-publish'
publishing {
repositories {
maven {
url "http://192.168.56.71:8080/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
2. Let’s run publish task to publish artefacts
./gradlew publish -PuploadVersion=1.1.1
3. Check artefact was uploaded at http://192.168.56.71:8080/artifactory*
#13 Artefacts Publishing
Plugable Architecture
● Build script
Visible for build file
● buildSrc/src/main/groovy
Visible for project
● Standalone project
Could be shared between projects using binary artefact
1. Create file PluginsPrinterPlugin.groovy in buildSrc/src/main/groovyimport org.gradle.api.Pluginimport 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
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
Alternatives
- build like you
code
- a software project management and comprehension tool
References
● http://www.gradle.org/
● http://www.gradle.org/books
● https://plugins.gradle.org/
● http://groovy.codehaus.org
● https://github.com/webdizz/sbs-gradle
● https://github.com/Netflix/gradle-template
● https://github.com/webdizz/gradle-template
References
Q&A
Izzet Mustafayev@EPAM Systems@webdizz webdizz izzetmustafaievhttp://webdizz.name