Introduction to Gradle - JUGS · • A general purpose build system • It comes with a Groovy DSL...

Post on 02-Sep-2018

224 views 0 download

Transcript of Introduction to Gradle - JUGS · • A general purpose build system • It comes with a Groovy DSL...

Introduction to Gradle

Hans Dockter - Gradle Inc.Jan 21, 2010

• A general purpose build system• It comes with a Groovy DSL and a Java core.• Provides build-in support for Java, Groovy,

Scala, Web, OSGi projects.• Gradle provides exciting solutions for many of the

big pain points you often have with current builds.

2

What is Gradle?

What is Gradle?

Gradle is declarative

You specify the WHAT

Gradle figures out the HOW

Source Set Sample

apply: ʻjavaʼ

dependencies { testCompile 'junit:junit:4.7' integrationTestCompile 'commons-collections:commons-collections:3.2'}

sourceSets { integTest { java.srcDir file('src/int-test/java') resources.srcDir file('src/int-test/resources') compileClasspath = sourceSets.main.classes + sourceSets.test.classes + configurations.integrationTestCompile runtimeClasspath = classes + compileClasspath }}

Plugins

apply ʻjavaʼ

dependencies { testCompile 'junit:junit:4.7' integrationTestCompile 'commons-collections:commons-collections:3.2'}

sourceSets {

> gradle classes

> gradle test

> gradle assemble

Dependencies

usePlugin(ʻjavaʼ)configurations { integrationTestCompile.extends testRuntime }dependencies { compile 'org.springframework:spring-core:3.0' testCompile 'junit:junit:4.7' integrationTestCompile 'commons-collections:commons-collections:3.2'}sourceSets { integTest { java.srcDir file('src/int-test/java') resources.srcDir file('src/int-test/resources') compileClasspath = sourceSets.main.classes + sourceSets.test.classes + configurations.integrationTestCompile runtimeClasspath = classes + compileClasspath }}

The how for the source set

> gradle integTestClasses

sourceSets { integTest { java.srcDir file('src/int-test/java') resources.srcDir file('src/int-test/resources') compileClasspath = sourceSets.main.classes + sourceSets.test.classes + configurations.integrationTestCompile runtimeClasspath = classes + compileClasspath }}

Autowiring

sourceSets { integTest { java.srcDir file('src/int-test/java') resources.srcDir file('src/int-test/resources') compileClasspath = sourceSets.main.classes + sourceSets.test.classes + configurations.integrationTestCompile runtimeClasspath = classes + compileClasspath }}

> gradle -t:integTestClasses -> :classes, :testClasses

Typed Tasks

sourceSets { integTest { ... }}

task integrationTest(type: Test, dependsOn: jar) { testClassesDir = sourceSets.integTest.classesDir classpath = sourceSets.integTest.runtimeClasspath options.systemProperties['jar.path'] = jar.archivePath}

> gradle -t:integrationTest -> :classes, :integrationTestClasses, :jar, :testClasses

SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.

Gradle is

declarativewithout

being rigid

The Build Language

Source Sets

Dependencies

Configurations

Archives

ProjectsArtifacts

Custom Tasks

Plugins

• Many source dirs per project• Dependencies per source dir• JDK per source dir• Many artifacts per project• Multiple projects per source directory

12

Build Language Examples

Deep API

tasks.withType(Jar).allObjects { jarTask -> jarTask.manifest.mainAttributes(Provider: "Gradle Inc.") }

tasks.withType(Compile).allObjects { compile -> compile.options.fork.executable = “$pathToJavac” }

sourceSets.allObjects { sourceSet -> // add task with name obfuscate + sourceSet.name // task with name classes + sourceSet.name depends on obfuscate // obfuscate depends on compile + sourceSet.name}

dependencies.allObjects { dependency -> throwExceptionIfDependencyIsGPL(dependency) }

Extensible Domain Objects

tasks.withType(Jar).allObjects { jarTask ->jarTask.osgi = new DefaultOsgiManifest()jarTask.doFirst { task -> importOsgiManifestIntoManifest(task) }

}...task myJar(type: Jar) { osgi.include(...) }

dependencies.allObjects { dependency ->dependency.maven = new DefaultMavenDescriptor()

}...dependencies { compile(“commons-lang:commons-lang:3.2”) { maven.optional = true }}

Rich API

usePlugin ʻjavaʼ

test {whenTestFails { test -> println(ʻTest Failed:ʼ + test.name)}

}

task analyzeFailedTests(dependsOn: test) << {List failedTests = test.failedTests // do something

}

Custom Tasks

task hello(type: HelloTask)

task greeting(type: HelloTask) { greeting = 'greetings from HelloTask'}

class HelloTask extends DefaultTask { def String greeting = 'hello from HelloTask'

@TaskAction def printGreeting() { println greeting }}

Custom Plugins

class GreetingPlugin implements Plugin { def void use(Project project) { project.task('hello') << { println "Hello from the GreetingPlugin" } project.greetingDate = new Date() }}

apply type: org.gradle.GreetingPlugin

apply url: ʻhttp://github.com/hansd/huglins/raw/master/greetings.gradleʼ

task hello << { println "Hello from the GreetingPlugin"}project.greetingDate = new Date()

Custom Declarative Elements

usePlugin ʻeditionsʼ

productEditions {enterprise core, plugins, powerAddonspublic core, plugins, openApi

}

> gradle enterpriseEditionZip> gradle publicEditionTar

SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.

ExtensibleBuild Language

instead of a Build Framework

XML and the What

It does not matter muchwhether a build systemuses XML or Groovy for

declaring things.

SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.

Often not all

aspectsof a build

can be solved with the default

declarative elements.

Simple Imperative Examples

apply id: ʻjavaʼ

task date << { println “Today is ${new Date()}” }

task someTask(dependsOn: compile) << { println ʻCount the number of compiled classesʼ}

compile.doFirst { println ʻCompilation will start nowʼ}

> gradle dateToday is Tue Oct 20 15:27:03 CDT 2009

Imperative/Declarative

usePlugin ʻgroovyʼ

task ide << { copy { from configurations.runtime into ʻmyLibDirʼ }}

task sources << {sourceSets.test.allGroovy.matching {include '**/*Demo*' }.files.each {

println “$it.absolutePath”}

}

SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.

Pleaseno

messybuild scripts

SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.

ExecutionHeaven

• Evaluate the build scripts– They configure the WHAT and HOW of the build.

• Build a DAG of tasks to be executed – Includes test, compile, compileTests, ... tasks

• Execute the tasks of the DAG

26

Build Lifecycle

> gradle test

• Hooks for customizing all phases of the lifecycle• The DAG is exposed to the build script

Deep Execution API

version = ʻ1.0ʼgradle.taskGraph.whenReady { graph ->

if (!graph.hasTask(“release”)) { version += ʻ-ʼ + System.currentTimeMillis()}

}compile.doFirst { compileTask -> println build.taskGraph.allTasks if (gradle.taskGraph.hasTask(ʻcodeGenerationʼ)) { compileTask.include ʻsomePackageʼ } }build.taskGraph.beforeTask { task -> println(“Free memory: “ + Runtime.runtime.freeMemory())}build.taskGraph.afterTask { task, exception -> if (task instanceof Jetty && exception != null) { // do something }}

28

Smart Exclusion

> gradle A -x B Executes A and E

A

B

C

D

E depends on

29

Smart Merging

> gradle clean compile; gradle test

test

compileclean

resources

> gradle clean compile test

depends on

Camel Case Execution

task myNameIsPrettyLong << { println 'Long name'}

task someOtherTask(dependsOn: myNameIsPrettyLong) << { println "Other task"}

> gradle sOtherT -x myNaIPOther task

Rules

tasks.addRule("Pattern: uploadTo<ID>") { String taskName -> if (taskName.startsWith("uploadTo")) { task(taskName) << { // add task println "Uploading to: " + (taskName - 'uploadTo') } }}task groupPing(dependsOn: [uploadTo1, uploadTo2])

> gradle uploadTo545Uploading to 545

> gradle groupUploadUploading to 1Uploading to 2

SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.

Performanceis one of the

biggestpain points

of complex builds.

• No clean required for a reliable build• Based on the input, output and task state, Gradle

decides whether to execute a task or not• This is a generic service that can be easily made

use of by custom tasks.

33

Incremental Builds

jar input: ʻbuild/classesʼjar state: compression ratejar output: ʻbuild/libs/classes.jarʼ

• Specify number of threads• Specify fork frequency• Pipelines for multiple process configurations

(jdk14, jdk15)• Remote Listeners

34

Native Multi-Process Test Runners

SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.

IntegratingwithAntand

Maven

Using Ant tasks

ant { taskdef name: "groovyc", classname: "org.groovy.ant.Groovyc" groovyc srcdir: "src", destdir: "${webinf}/classes", { classpath {# fileset dir: "lib" {# include name: "*.jar" }# pathelement path: "classes" } javac source: "1.5", target: "1.5", debug: "on" }}

Deep Integration withAnt Builds

> gradle helloHello, from Gradle...Here comes Ant...[ant:echo] Hello, from Ant

<project> <target name="hello" depends="intro"> <echo>Hello, from Ant</echo> </target></project>

ant.importBuild 'build.xml'

hello.doFirst { println 'Here comes Ant' }task intro << { println 'Hello, from Gradle'}

• Integration with Maven repositories

– autogeneration of pom.xml

– install to local Maven repo

– deploy to any remote Repo

– full maven metadata generation

• Integration of Maven builds in the future

38

Integrating with Maven

Dependency Management

usePlugin(ʻjavaʼ)

configurations { allJar.extends runtime}

dependencies { compile "commons-lang:commons-lang:3.1", "org.hibernate:hibernate:3.2" runtime “mysql:mysql-connector-java:5.1.6” testCompile "junit:junit:4.4" allJar "commons-io:commons-io:1.4"}

task jarAll(type: Jar) { merge(configurations.allJar.files)}

Dependency Management

dependencies { compile("org.hibernate:hibernate:3.2") { exclude module:cglib }}

• Transitive Dependencies• Excludes per configuration or dependency• Very flexible repository handling• Based on Apache Ivy• Powerful API

• Arbitrary Multiproject Layout• Configuration Injection• Separate Config/Execution Hierarchy• Partial builds

41

Multi-Project Builds

Gradle GUI

> gradle --gui

Gradle Wrapper

>./gradlew assemble

• Very active community (mailing-list, patches, issues)• Apache v2 license.• Excellent user’s guide (200+ pages) + many samples• Frequent releases, multiple commits per day• Quality is king:

– 2800 unit tests, Many hundreds of integration test– Healthy codebase– low defect rate

• Commiter -> Steve Appling, Hans Dockter, Tom Eyckmans, Adam Murdoch, Russel Winder

44

Project Background

45

Commercial Support: www.gradle.biz

Q&A