Gradle
From Evgeny Goldin
Contents |
Resources
- http://gradle.org/
- pinboard.in/u:evgenyg/t:gradle
- Documentation:
- Videos
- Presentations:
- Ken Sipe (@kensipe) - Gradle - A Better Way to Build + Labs
- Baruch Sadogursky (@jbaruch) - Gradle - A Better Way To Build
- Evgeny Goldin (@evgeny_goldin) - 10 Cool Facts about Gradle
- Sources:
- Plugins:
- Books:
-
org.gradle.api.Project -
org.gradle.api.Task - Mailing Lists / Forums:
- Articles:
Command-line
gradle : // root project gradle :clean // the clean task of the root project gradle :api // the api project gradle :services:webservice // the webservice project gradle :services:webservice:clean // the clean task of webservice gradle :shared:build gradle :api:classes gradle tasks -i gradle test -i gradle properties gradle tasks gradle tasks --all gradle dependencies // mvn dependency:tree gradle build gradle buildDependents gradle buildNeeded
-?, -h, --help Shows this help message. -a, --no-rebuild Do not rebuild project dependencies. -b, --build-file Specifies the build file. -C, --cache Specifies how compiled build scripts should be cached. Possible values are: 'rebuild' and 'on'. Default value is 'on' [deprecated - Use '--rerun-tasks' or '--recompile-scripts' instead] -c, --settings-file Specifies the settings file. --continue Continues task execution after a task failure. -D, --system-prop Set system property of the JVM (e.g. -Dmyprop=myvalue). -d, --debug Log in debug mode (includes normal stacktrace). --daemon Uses the Gradle daemon to run the build. Starts the daemon if not running. --foreground Starts the Gradle daemon in the foreground. [incubating] -g, --gradle-user-home Specifies the gradle user home directory. --gui Launches the Gradle GUI. -I, --init-script Specifies an initialization script. -i, --info Set log level to info. -m, --dry-run Runs the builds with all task actions disabled. --no-color Do not use color in the console output. --no-daemon Do not use the Gradle daemon to run the build. --no-opt Ignore any task optimization. [deprecated - Use '--rerun-tasks' instead] --offline The build should operate without accessing network resources. -P, --project-prop Set project property for the build script (e.g. -Pmyprop=myvalue). -p, --project-dir Specifies the start directory for Gradle. Defaults to current directory. --parallel Build projects in parallel. Gradle will attempt to determine the optimal number of executor threads to use. [incubating] --parallel-threads Build projects in parallel, using the specified number of executor threads. [incubating] --profile Profiles build execution time and generates a report in the <build_dir>/reports/profile directory. --project-cache-dir Specifies the project-specific cache directory. Defaults to .gradle in the root project directory. -q, --quiet Log errors only. --recompile-scripts Force build script recompiling. --refresh Refresh the state of resources of the type(s) specified. Currently only 'dependencies' is supported. [deprecated - Use '--refresh-dependencies' instead.] --refresh-dependencies Refresh the state of dependencies. --rerun-tasks Ignore previously cached task results. -S, --full-stacktrace Print out the full (very verbose) stacktrace for all exceptions. -s, --stacktrace Print out the stacktrace for all exceptions. --stop Stops the Gradle daemon if it is running. -u, --no-search-upward Don't search in parent folders for a settings.gradle file. -v, --version Print version info. -x, --exclude-task Specify a task to be excluded from execution.
"apply"
apply from: 'otherScript.gradle' apply from: 'file:../emma.gradle' apply from: 'http://mycomp.com/otherScript.gradle' apply from: 'http://github.com/breskeby/gradleplugins/raw/master/emmaPlugin/emma.gradle' apply from: 'https://raw.github.com/evgeny-goldin/gradle-plugins/master/src/main/groovy/CodeNarc.gradle' apply plugin: org.gradle.api.plugins.JavaPlugin apply plugin: 'java'
Configurations and Dependencies
-
DependencyHandler - Java Plugin - dependency management
- Repository
- Dependency
- Configuration
- Artifact
configurations { myConf.extendsFrom compile compile.exclude module: 'commons' all*.exclude group: 'org.gradle.test.excludes', module: 'reports' } dependencies { // Groovy Plugin: http://gradle.org/groovy_plugin.html groovy 'org.codehaus.groovy:groovy-all:1.9.0-beta-2' // Scala Plugin: http://gradle.org/scala_plugin.html scalaTools 'org.scala-lang:scala-compiler:2.9.1.RC4', 'org.scala-lang:scala-library:2.9.1.RC4' compile 'org.scala-lang:scala-library:2.9.1.RC4' // Gradle plugins groovy localGroovy() compile gradleApi(), fileTree( dir: "${gradle.gradleHomeDir}/lib/plugins", include: 'gradle-*.jar' ) // Dependency configurations added by Java Plugin // http://gradle.org/java_plugin.html#sec:java_plugin_and_dependency_management compile ' ... ' runtime ' ... ' testCompile ' ... ' testRuntime ' ... ' archives ' ... ' default ' ... ' // Source-level dependency compile project( ':moduleA' ) compile project( ':moduleB' ) // Third-party dependency compile 'org.gcontracts:gcontracts-core:1.2.4' // Artifact only notation // http://gradle.org/current/docs/userguide/dependency_management.html#ssub:artifact_dependencies runtime "org.groovy:groovy:1.5.6@jar" // Local files dependency compile files('file.jar'), fileTree( dir: 'lib', includes: ['*.jar']) // Excluding transitive dependencies compile( 'org.gradle.test.excludes:api:1.0' ) { exclude group : 'groupId' exclude module: 'artifactId' exclude group : 'org.codehaus.groovy', module: 'artifactId' } myConf 'gId:aId:v' compile 'gId:aId:v' { force = true // Sets whether or not the version of this dependency should be enforced in the case of version conflicts transitive = false // Sets the transitivity of this configuration } } configurations.myConf.transitive = false task printDeps( dependsOn: build ) << { configurations*.dependencies.each { println it } } configurations { provided } sourceSets { main { compileClasspath += configurations.provided } } // http://gradle.1045684.n5.nabble.com/Test-dependencies-not-keeped-at-test-runtime-td4773771.html task listTestRuntime(dependsOn: configurations.testRuntime) << { configurations.testRuntime.files.each { file -> println file.name } }
Repositories
repositories { mavenLocal() mavenCentral() maven { credentials { username '..'; password '..' } url 'http://evgenyg.artifactoryonline.com/evgenyg/repo/' } ivy { credentials { username '..'; password '..' } artifactPattern 'http://repo/[organisation]/[module]/[revision]/[module]-[revision].[ext]' artifactPattern 'http://repo/[module]-[revision].[ext]' } flatDir( dirs: [ 'dir1', 'dir2' ] ) ivy { name = 'ivyRepo' artifactPattern "http://repo.gradleware.org/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" } add(new FileSystemResolver()) { name = "repo" addArtifactPattern("$rootDir/repo/[organization]/[module]-[revision].[ext]") addIvyPattern("$rootDir/repo/[organization]/ivy-[module]-[revision].xml") checkmodified = true } } uploadArchives { repositories { mavenDeployer { repository( url: deploymentRepoUrl ) { authentication( .. ) } } } } // http://en.appsatori.eu/2011/08/using-gradle-with-cloudbees-maven.html uploadArchives { repositories { deployer = mavenDeployer { // you might use this configuration not to generate // date based artefact names // uniqueVersion = false configureAuth = { authentication(userName: cloudbeesUsername, password: cloudbeesPassword) } configuration = configurations.deployerJars snapshotRepository(url: "dav:https://repository-${cloudbeesAccountName}.forge.cloudbees.com/snapshot/", configureAuth) repository(url: "dav:https://repository-${cloudbeesAccountName}.forge.cloudbees.com/release/", configureAuth) } } }
Tasks
-
org.gradle.api.Task -
Projectmethods
taskName { .. configure it .. } clean { delete 'fooDir', 'bar.txt', fileTree( 'texts' ).matching { ... } } task copySomething << { copy { from configurations.runtime into 'build/deploy/lib' } copy { into 'build/webroot' exclude '**/.svn/**' from('src/main/webapp') { include '**/*.jsp' filter(ReplaceTokens, tokens:[copyright:'2009', version:'2.3.1']) } from('src/main/js') { include '**/*.js' } } }
Task Dependencies
task loadTestData { dependsOn createSchema dependsOn compileTestClasses, createSchema dependsOn << createSchema dependsOn << compileTestClasses dependsOn 'createSchema' } task hello ( dependsOn: taskA ) { .. } task hello ( dependsOn: [ taskA, taskB ] ) { .. } task buildAllJars( dependsOn: allJars ) hello { dependsOn taskA } hello.dependsOn taskA hello.dependsOn taskA, taskB task emailMe( dependsOn: compileJava ) << { if( tasks.compileJava.didWork ) { println 'SEND EMAIL ANNOUNCING SUCCESS' } }
Configuring Tasks
task hello { ... } // Configuring task task hello << { ... } // Adding doLast() action to the task hello.doFirst { ... } // Adding doFirst() action to the task task "$taskName" { … } // Dynamically named task task helloWorld( description: 'Says hello to the world' ) << { ... } task hello { description = 'Says hello to the world' onlyIf { 3 < 4 } dependsOn otherTask doFirst { .. } doLast { copy { from '..'; into '..' }} doLast { logging.level = level // 'DEBUG', 'INFO', 'LIFECYCLE', 'QUIET', 'WARN', 'ERROR' logger.debug '...' logger.info '...' logger.lifecycle '...' logger.quiet '...' logger.warn '...' logger.error '...' } hello { .. config .. } hello.dependsOn otherTask hello.onlyIf { 3 > 2 } hello.doFisrt { .. } hello.enabled = true/false project.tasks.add.( 'someTask' ).doFirst { .. } /** * Dynamic Property */ task myDocs { destDir = "$buildDir/myDocs" doFirst { copy { from 'someDir' into destDir } } } /** * Dynamic Method */ task bar { serviceUrl = ... domainGroup = { getGroup(serviceUrl) } } task foo { fooProp = bar.domainGroup() }
Conventions
task show << { // Access the convention property as a project property println relativePath(sourceSets.main.classesDir) println relativePath(project.sourceSets.main.classesDir) // Access the convention property via the convention object println relativePath(project.convention.sourceSets.main.classesDir) println relativePath(project.convention.plugins.java.sourceSets.main.classesDir) }
Custom Tasks
- Four options for where to put custom Gradle build code:
- The build script itself, in a task action block.
-
"buildSrc"directory. - Separate build script file imported into the main build script.
- Custom plug-in written in Java or Groovy.
class FtpTask extends DefaultTask { String host = 'docs.mycompany.com' String user String password @TaskAction def ftp() { println host } } task something( type: FtpTask, dependsOn: ... ) { user = '...' password = '...' }
Typed Tasks
/** * Copy */ task copyFiles( type: Copy ) { from 'resources' into 'target' include '**/*.xml', '**/*.txt', '**/*.properties' } /** * Jar */ task customJar( type: Jar ) { manifest { attributes firstKey: 'firstValue', secondKey: 'secondValue' } archiveName = 'hello.jar' destinationDir = file( "${buildDir}/jars" ) from sourceSets.main.classes } /** * Zip */ task zip( type: Zip ) { from myDocsDestDir } task zip( type: Zip ) { from jar.outputs.files from('scripts/') { fileMode = 0755 include '**/*.sh' include '**/*.bat' } from('lib/') { include '**/*.jar' into('lib') } from('.') { include 'project.config' } } /** * JavaExec */ task encode( type: JavaExec, dependsOn: classes ) { main = 'org.gradle.example.commandline.MetaphoneEncoder' args = "The rain in Spain falls mainly in the plain".split().toList() classpath sourceSets.main.classesDir classpath configurations.runtime } [ 'shakespeare', 'williams', 'shelley', 'chesterton' ].each { poet -> task "$poet"( type: JavaExec ) { group = 'Encoded Poetry' args = [ poet ] main = 'org.gradle.example.codedpoet.CommandLine' classpath sourceSets.main.runtimeClasspath, project(':codec').sourceSets.main.runtimeClasspath } } /** * Wrapper */ task wrapper( type: Wrapper ) { gradleVersion = '1.0-milestone-3' jarPath = 'gradle' }
Selecting Tasks
allJars = tasks.withType( Jar ) webTasks = tasks.matching { task -> task.name.startsWith( 'web' ) } compJars = tasks.withType( Jar ).matching { task -> task.name.startsWith( 'comp' ) } tasks.allObjects{ task -> task.doFirst { .. }} tasks.whenAdded { task -> ... } tasks.withType( Jar ).allObjects { jar -> jar.destinationDir = 'somePath' jar.doLast { ... }} task myJar( type: Jar ) // Contained in all Jars task buildAllJars( dependsOn: allJars ) gradle.taskGraph.whenReady { taskGraph -> version = versionBase + ( taskGraph.hasTask( ':release' ) ? '' : '-SNAPSHOT' ) }
Compile Task
// Input sourceSets.main(test).java configurations.compile(testCompile) sourceSets.main.java.srcDir = 'src' sourceSets.main.java.srcDirs = ['src/main/java', 'srcAdditional/main/java' sourceSets.main.java.srcDirs 'srcAdditionalTwo/main/java' compileJava { // http://gradle.org/current/docs/groovydoc/org/gradle/api/tasks/compile/CompileOptions.html // https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/groovy/org/gradle/api/tasks/compile/ForkOptions.groovy options.fork { memoryMaximumSize = '512M' } }
Test Task
gradle -Dtest.single=ThisUniquelyNamedTest test gradle -Dtest.single=*IntegrationTest test gradle -Dtest.debug sourceSets.test.java.srcDirs = [ 'src/test/java', 'srcAdditional/test/java' ] sourceSets.test.java.srcDirs 'srcAdditionalTwo/test/java' // Input sourceSets.test.classes configurations.testRuntime test.useJUnit() test.useTestNG() test { useJUnit() useTestNG() jvmArgs ['-Xmx512M'] include '**/tests/special/**/*Test.class' exclude '**/Old*Test.class' forkEvery = 30 maxParallelForks = Runtime.runtime.availableProcessors() } test { beforeTest { descr -> .. } afterTest { descr, result -> .. } beforeSuite{ descr -> .. } afterSuite { descr, result -> .. } }
Multi-project Builds
"settings.gradle":
include 'moduleA', 'moduleB'
Root "build.gradle":
// Declares that this project has an evaulation dependency on the project with the given path evaluationDependsOn( ':moduleA' ) // Declares that this project have an execution dependency on each of its child projects dependsOnChildren() apply plugin: 'java' dependencies { compile project( ':moduleA' ) compile project( ':moduleB' ) }
allprojects { apply plugin: 'java' } project( ':moduleA' ) { repositories { mavenCentral() } dependencies { compile 'commons-codec:commons-codec:1.5' } } subprojects { ... } dependencies { compile project( ':moduleA' ) compile project( ':moduleB' ) } ...
Cookbook
Publishing the JAR file
uploadArchives { repositories.mavenDeployer { repository(url: releaseUrl) { ... } snapshotRepository(url: snapshotUrl) { ... } } } uploadArchives { repositories { flatDir( dirs: file('repos')) } }
Deploying source jar with Gradle
configurations { extra } task sourcesJar(type: Jar) { classifier = 'sources' from sourceSets.main.java } artifacts { extra sourceJar } // Or task sourcesJar( type: Jar, dependsOn: classes ) { classifier = 'sources' from sourceSets.main.allSource } artifacts { archives sourcesJar } // Or // http://en.appsatori.eu/2011/08/using-gradle-with-cloudbees-maven.html task packageJavadoc( type: Jar, dependsOn: 'javadoc' ) { from javadoc.destinationDir classifier = 'javadoc' } task packageSources( type: Jar ) { from sourceSets.main.allSource classifier = 'sources' } artifacts { archives( packageJavadoc ) { type = 'javadoc' extension = 'jar' } archives( packageSources ) }
Setting the repository URL at the time the DAG is ready
uploadArchives { repositories { mavenDeployer { repository(url: deploymentRepoUrl) { authentication(...) } } } } gradle.taskGraph.whenReady { taskGraph -> if ( ! taskGraph.hasTask( ':release' )) { version += '-SNAPSHOT' uploadArchives.repositories['mavenDeployer'].repository.url = 'http://myrepo.org' } }
Using Ant
ant.delete dir: 'someDir' ant { ftp( server: 'ftp.comp.org', userid: 'me', ... ) { fileset( dir: 'htdocs/manual' ) { include name: '**/*.html' } myFileTree.addToAntBuilder( ant, 'fileset' ) } mkdir dir: 'someDir' }
