Date post: | 26-Jan-2015 |
Category: |
Technology |
Upload: | joachim-baumann |
View: | 114 times |
Download: | 0 times |
Gradle for Beginners
Coding Serbia, 18.10.2013
Joachim Baumann
Gradle for Beginners
• Build-Management – Needs – Wishes
• Gradle - Basics
• Configuration and Execution Phase
• Groovy – Short Overview
• Plug-ins – Basics • Our First Project
– Directory Structure – Dependencies – Manipulating the Jar – Tests – Quality Assurance – Publishing the Artefacts
What do we need from a Build-Management System?
• Translating the Source Code (using a compiler)
• Linking the Results
• Check out the source code from a repository (optional)
• Creating Tags (optional)
• Execution of different types of tests: Examples:
– Unit Tests for single Classes
– Module or Component Tests
– Integration Tests
– Functional and Non-Functional System Tests
– Automated Acceptance Tests
• Detailed Test Reports combining all Test Results (optional)
• Packing the Result (e.g., into a Jar, War or Ear)
• Transfer the Results to the different Stages / Test Systems and Execution of the respective Tests (optional)
• Support for multi-language Projects
• Creation of Documentation and Release Notes
What do we wish for in our Build-Management System?
• Explicit Support of the Workflow implemented by the Build-Management-System
• Simple Modifiability and Extensibility of the Workflow to adapt to local processes
• Readability and self-documentation of the notation in the build script
• Use of sensible conventions (e.g., where to find the sources)
• Simple change of the conventions to adap to local environment
• Incremental Build that can identify artefacts that have already been built
• Parallelisation of independent steps in the workflow to minimize waiting
• Programmatic access to all artefacts being created by the build
• Status reports that summarize the current state of the build
build
assemble
testcompileTest
compile
Gradle - Basics
• Gradle uses build scripts which are named build.gradle
• Every build script is a Groovy script
• Two very important Principles
– Convention over Configuration
– Don’t Repeat Yourself
• Gradle creates a dynamic model of the workflow as a Directed Acyclic Graph (DAG)
• (Nearly) Everything is convention and can be changed
Configuration Phase
• Executes the build script
• The contained Groovy- and DSL-commands configure the underlying object tree
• The root of the object tree is the Project object
– Is directly available in the script (methods and properties)
• Creation of new Tasks that can be used
• Manipulation of the DAG
• Our first script build.gradle println ”Hello from the configuration phase"
Execution Phase
• Executes all tasks that have been called (normally on the command line)
• For a task that is executed every task it depends on is executed beforehand
• Gradle uses the DAG to identify all task relationships
build
assemble
testcompileTest
compile
Task Definition
• Takes an (optional) configuration closure • Alternatively: can be configured directly
• The operator << (left-shift) appends an action (a closure) to this task’s list of actions • Equivalent to doLast()
• Insert at the beginning of the list with doFirst() task halloTask halloTask.doLast { print "from the " } halloTask << { println "execution phase" } halloTask.doFirst { print "Hello " } task postHallo (dependsOn: halloTask) << { println "End" } postHallo { // configuration closure dependsOn halloTask }
Groovy – Short Overview
• Simplified Java Syntax – Semicolon optional – GString – Everything is an Object – Simplification e.g., “println”
• Scripts
• Operator Overloading – Predefined
• Example << • Operator for secure navigation a.?b
– You can provide your own implementations
• Named Parameters
• Closures
• Collection Iterators
Plug-ins - Basics
• Plug-ins encapsulate functionality
• Can be written in any VM-language
– Groovy is a good choice
• Possible Plug-in Sources
– Plug-ins packed with Gradle
– Plug-ins included using URLs (don’t do it)
– Plug-ins provided by repositories (use your own repository)
– Self-written Plug-ins (normally in the directory buildSrc)
• Plug-ins
– Extend objects
– Provide new objects and / or abstractions
– Configure existing objects
• Plug-ins are load with the command apply plugin apply plugin: ‘java’
Our first Project
• We use the Java Plug-in
• Default paths used by the Java Plug-in
– Derived from Maven Conventions
The Class HelloWorld
package de.gradleworkshop; import java.util.ArrayList; import java.util.List; public class HelloWorld {
public static void main(String[] args) { HelloWorld hw = new HelloWorld(); for(String greeting : hw.generateGreetingsData()) System.out.println(greeting); } public List<String> generateGreetingsData() { List <String> greetings = new ArrayList <String>(); greetings.add("Hallo Welt"); return greetings; }
}
Manipulation of the Manifest
• Every Jar-Archive contains a file MANIFEST.MF
• Is generated by Gradle (see directory build/tmp/jar/MANIFEST.MF)
• Contains information e.g., about the main class of the jar
• Can be changed jar { manifest { attributes 'Main-Class': 'de.gradleworkshop.HelloWorld' } }
• Alternatively jar.manifest.attributes 'Main-Class': 'de.gradleworkshop.HelloWorld'
Tests
package de.gradleworkshop; import java.util.List;
import org.junit.*; import static org.junit.Assert.*; public class HelloWorldTest {
HelloWorld oUT;
@Before public void setUp() { oUT = new HelloWorld(); } @Test public void testGenerateGreetingsData() {
List<String> res = oUT.generateGreetingsData(); assertEquals("wrong number of results", 1, res.size()); }
}
Configurations and Dependencies
• Gradle defines Configuration Objects. These encapsulate
– Dependency Information
– Paths to Sources and Targets
– Associated Artefacts
– Additional Configuration Information
• Tasks use these Configurations
• For most pre-defined Task a Configuration exists
– compile, testCompile, runtime, testRuntime
• Dependencies are defined using the key word dependencies
• Maven-like notation for the dependencies dependencies { testCompile group: 'junit', name: 'junit', version: '4.+’ }
Repositories
• Repositories provide libraries (normally jar archives)
• You can define Ivy or Maven Repositories, both public and private
• Predefined Repositories
– JCenter
– Maven Central
– Local Maven Repository (~/.m2/repository)
• Repositories are defined using the keyword repositories repositories { mavenLocal() } repositories { jcenter() mavenCentral() }
• Multiple Repositories can be defined
The Application Plug-in
• The Application-Plug-in
– Adds a Task run
– Creates start scripts, that can be used with the Task run
– Creates a Task distZip, that packs all necessary files into a zip-archive
– Definition of the Main Class mainClassName = "de.gradleworkshop.HelloWorld"
– Usage with apply plugin: 'application'
Using TestNG
• Very Simple
dependencies { testCompile group: 'org.testng', name: 'testng',
version: '6.+' } test {
useTestNG() }
Test Class for TestNG
package de.gradleworkshop; import java.util.List; import static org.junit.Assert.assertEquals; import static org.testng.AssertJUnit.*; import org.testng.annotations.*; public class TestHelloWorld {
HelloWorld oUT; @BeforeTest public void setUp() { oUT = new HelloWorld(); } @Test public void testGenerateGreetingsData() { List<String> res = oUT.generateGreetingsData(); assertEquals("Wrong Number of Entries", 1, res.size()); }
}
Quality Assurance
• Support for PMD, Checkstyle, Findbugs, Emma, Sonar …
• Example PMD apply plugin: 'pmd' pmdMain { ruleSets = [ "basic", "strings" ] ignoreFailures = true }
• Another Example configuring all Tasks of Type Pmd using withType() tasks.withType(Pmd) { ruleSets = [ "basic", "strings" ] ignoreFailures = true ruleSetFiles = files('config/pmd/rulesets.xml') reports { xml.enabled false html.enabled true } }
Publishing the Artefacts
• Gradle defines for every Configuration a Task upload<Configuration>
– Builds and publishes the Artefact belonging to the Configuration
• The Java-Plug-in creates a Configuration archives, which contains all artefacts created in the Task jar
– uploadArchives is the natural choice for publishing the artefacts
• Use of the Maven-Plug-in with apply plugin: ‘maven’
– Doesn’t use the normal repository (intentionally)
apply plugin: 'maven' version = '0.1-SNAPSHOT' group = 'de.gradleworkshop' uploadArchives {
repositories { flatDir { dirs "repo" } mavenDeployer { repository (url : "file://$projectDir/mavenRepo/") } }
}
The whole Script (less than 20 lines)
apply plugin: 'java' apply plugin: 'pmd' jar.manifest.attributes 'Main-Class': 'de.gradleworkshop.HelloWorld' pmdMain {
ruleSets = [ "basic", "strings" ] ignoreFailures = true
} repositories { mavenCentral() } dependencies {
testCompile group: 'junit', name: 'junit', version: '4.+' } apply plugin: ‘maven’ version = '0.1-SNAPSHOT’ group = 'de.gradleworkshop’ uploadArchives {
repositories { flatDir { dirs "repo" } mavenDeployer { repository (url : "file:///gradleWS/myRepo/")
} } }
Recap
• We have, with Gradle
– Built an Application
– Created Tests and executed them
– Used an alternative Test Framework TestNG
– Used Quality Assurance
– Uploaded the Artefacts into two Repositories
• You now know everything to build normal Projects with Gradle
• Gradle
– Is simple
– Easily understood
– Has sensible conventions
– That can be easily changed
• Gradle adapts to your needs
Questions?
Dr. Joachim Baumann
codecentric AG
An der Welle 4
60322 Frankfurt
www.codecentric.de
blog.codecentric.de
24