gradle - the enterprise automation tool

Post on 30-Jun-2015

739 Views

Category:

Software

4 Downloads

Preview:

Click to see full reader

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

Q&A

Izzet Mustafayev@EPAM Systems@webdizz webdizz izzetmustafaievhttp://webdizz.name

top related