Gradle

Cheatsheet

Specify location of Gradle user home to reuse local cache

export GRADLE_USER_HOME=$location

Stop daemons

gradle --stop

Check daemons status

gradle --status

Only show Daemons for the version of Gradle being invoked and not for any other versions.

List build dependencies

gradle buildEnvironment

Display attributes for different configurations

gradle resolvableConfigurations

Display detected JDKs

gradle javaToolchains

Print Gradle system properties

gradle properties

Check which Java is used for build

gradle properties | grep 'org.gradle.java.home'

Run a specific test case - test filtering

  • From CLI
gradle test --tests $TEST_CLASS_NAME.$TEST_CASE_NAME
  • In build script
tasks.test {
    filter {
        //include specific method in any of the tests
        includeTestsMatching("*UiCheck")
 
        //include all tests from package
        includeTestsMatching("org.gradle.internal.*")
 
        //include all integration tests
        includeTestsMatching("*IntegTest")
    }
}

build execution - dry run

Run the builds with all task actions disabled, suitable for testing build config

From CLI

gradle test -m

Useful when want to see the tasks that would be executed without actually executing them.

gradle clean build -m
# Output
:clean SKIPPED
:bootBuildInfo SKIPPED
:compileJava SKIPPED
:cyclonedxBom SKIPPED
:processResources SKIPPED
:classes SKIPPED
:resolveMainClassName SKIPPED
:bootJar SKIPPED
:jar SKIPPED
:assemble SKIPPED
:compileTestJava SKIPPED
:processTestResources SKIPPED
:testClasses SKIPPED
:test SKIPPED
:check SKIPPED
:build SKIPPED

build execution - parallel execution

  • From CLI
gradle test --parallel
  • In build script
tasks.test {
    // capped at Runtime.getRuntime().availableProcessors()
    // watch for java.net.BindException: Address already in use: JVM_Bind
    // presumably due to port conflict
    // rule of thumb: (Runtime.getRuntime().availableProcessors() / 2).coerceAtLeast(1)
    maxParallelForks = 2
}

Specify default tasks

// build.gradle.kts
defaultTasks("clean", "build")

Maven vs Gradle

MavenGradle
mvn clean installgradle clean build
mvn clean install -DskipTestsgradle clean build -x test
mvn test -Dtest=$TestClassNamegradle test --tests $TestClassName
mvn test -Dtest=$TestClassName#$TestCaseNamegradle test --tests $TestClassName.$TestCaseName
mvn dependency:treegradle dependencies
project.build.directoryproject.layout.buildDirectory.asFile.get()
project.basedirproject.layout.projectDirectory.asFile.get()

CLI Options Reference

 gradle --help
 
To see help contextual to the project, use gradle help
 
USAGE: gradle [option...] [task...]
 
-?, -h, --help                     Shows this help message.
-a, --no-rebuild                   Do not rebuild project dependencies.
-b, --build-file                   Specify the build file. [deprecated]
--build-cache                      Enables the Gradle build cache. Gradle will try to reuse outputs from previous builds.
--no-build-cache                   Disables the Gradle build cache.
-c, --settings-file                Specify the settings file. [deprecated]
--configuration-cache              Enables the configuration cache. Gradle will try to reuse the build configuration from previous builds.
--no-configuration-cache           Disables the configuration cache.
--configuration-cache-problems     Configures how the configuration cache handles problems (fail or warn). Defaults to fail.
--configure-on-demand              Configure necessary projects only. Gradle will attempt to reduce configuration time for large multi-project builds. [incubating]
--no-configure-on-demand           Disables the use of configuration on demand. [incubating]
--console                          Specifies which type of console output to generate. Values are 'plain', 'auto' (default), 'rich' or 'verbose'.
--continue                         Continue task execution after a task failure.
--no-continue                      Stop 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.
--no-daemon                        Do not use the Gradle daemon to run the build. Useful occasionally if you have configured Gradle to always run with the daemon by default.
--export-keys                      Exports the public keys used for dependency verification.
-F, --dependency-verification      Configures the dependency verification mode. Values are 'strict', 'lenient' or 'off'.
--foreground                       Starts the Gradle daemon in the foreground.
-g, --gradle-user-home             Specifies the Gradle user home directory. Defaults to ~/.gradle
-I, --init-script                  Specify an initialization script.
-i, --info                         Set log level to info.
--include-build                    Include the specified build in the composite.
-M, --write-verification-metadata  Generates checksums for dependencies used in the project (comma-separated list)
-m, --dry-run                      Run the builds with all task actions disabled.
--max-workers                      Configure the number of concurrent workers Gradle is allowed to use.
--offline                          Execute the build 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.
--no-parallel                      Disables parallel execution to build projects.
--priority                         Specifies the scheduling priority for the Gradle daemon and all processes launched by it. Values are 'normal' (default) or 'low'
--profile                          Profile build execution time and generates a report in the <build_dir>/reports/profile directory.
--project-cache-dir                Specify the project-specific cache directory. Defaults to .gradle in the root project directory.
-q, --quiet                        Log errors only.
--refresh-keys                     Refresh the public keys used for dependency verification.
--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.
--scan                             Creates a build scan. Gradle will emit a warning if the build scan plugin has not been applied. (https://gradle.com/build-scans)
--no-scan                          Disables the creation of a build scan. For more information about build scans, please visit https://gradle.com/build-scans.
--status                           Shows status of running and recently stopped Gradle daemon(s).
--stop                             Stops the Gradle daemon if it is running.
-t, --continuous                   Enables continuous build. Gradle does not exit and will re-execute tasks when task file inputs change.
-U, --refresh-dependencies         Refresh the state of dependencies.
--update-locks                     Perform a partial update of the dependency lock, letting passed in module notations change version. [incubating]
-V, --show-version                 Print version info and continue.
-v, --version                      Print version info and exit.
-w, --warn                         Set log level to warn.
--warning-mode                     Specifies which mode of warnings to generate. Values are 'all', 'fail', 'summary'(default) or 'none'
--watch-fs                         Enables watching the file system for changes, allowing data about the file system to be re-used for the next build.
--no-watch-fs                      Disables watching the file system.
--write-locks                      Persists dependency resolution for locked configurations, ignoring existing locking information if it exists
-x, --exclude-task                 Specify a task to be excluded from execution.
--                                 Signals the end of built-in options. Gradle parses subsequent parameters as only tasks or task options.

Settings

Build

  • Project

    One build script file is backed by an instance of org.gradle.api.Project (opens in a new tab)

    Other elements of the build script are also backed by their corresponding objects.

    Check DSL Reference for details

Dependency Management

Unmanaged Dependencies

// build.gradle
dependencies {
    implementation files('libs/mnist-tools.jar', 'libs/gson-2.2.4.jar')
    implementation fileTree(dir: 'libs', include: ['*.jar'])
}

Enforce dependency version

  • Enforce a strict version (opens in a new tab)

    dependencies {
        // short-hand notation with !!
        implementation("org.slf4j:slf4j-api:1.7.15!!")
        // is equivalent to
        implementation("org.slf4j:slf4j-api") {
            version {
              strictly("1.7.15")
            }
        }
     
        // or...
        implementation("org.slf4j:slf4j-api:[1.7, 1.8[!!1.7.25")
        // is equivalent to
        implementation("org.slf4j:slf4j-api") {
            version {
              strictly("[1.7, 1.8[")
              prefer("1.7.25")
            }
        }
    }

Exclude transitive dependencies

implementation("io.confluent:kafka-json-schema-serializer:7.5.1") {
    exclude("commons-logging", "commons-logging")
}

Declaring Versions and Ranges

Dynamic versions

dependencies {
    implementation("org.springframework:spring-web:5.+")
}

Dependency Resolution

Artifact Transforms

  • Gradle Docs - Artifact Transforms (opens in a new tab)

    With Artifact Transforms, you can modify, add to, remove from the set files (or artifacts) - like JAR files - contained in a dependency. This is done as the last step when resolving artifacts, before tasks or tools like the IDE can consume the artifacts.

Build Environment

  • Properties

    • Properties resolution precedence

      • Gradle command line
      • JVM system properties
      • Environment variables
      • gradle.properties file ($HOME/.gradle/gradle.properties)
      • gradle.properties file (under project root)
    • Command-line flags > System properties > Gradle properties > Environment variables

  • Resource

Environment variable

Extending Gradle

Writing Custom Task Classes

Using buildSrc

  • You can put the source code for the task class in the $rootProjectDir/buildSrc/src/main/{groovy/java/kotlin}, depending on the language you use to implement the custom task class. It will be compiled while the task is being invoked. For example:

    package gradle
     
    import org.gradle.api.DefaultTask
    import org.gradle.api.Project
    import org.gradle.api.tasks.TaskAction
     
    /**
    * The class is located in rootProjectDir/buildSrc/src/main/groovy/gradle/PrepareTask.groovy
    */
    class PrepareTask extends DefaultTask {
        @TaskAction
        def prepare() {
            println 'Prepare assignment zip file to be uploaded to Coursera.'
            println Project.GRADLE_PROPERTIES
        }
    }
  • Use the task in the build.gradle:

    // build.gradle
    task prepare(type: gradle.PrepareTask)

Multi-projects build

  • The allprojects block is used to add configuration items that will apply to all sub-projects as well as the root project.
  • In a similar fashion, the subprojects block can be used to add configurations items for all sub-projects only.
  • You can use these two blocks as many times as you want in the root project.

Testing

Display test result in the console

// Kotlin DSL
import org.gradle.api.tasks.testing.TestResult.ResultType
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent.*
 
tasks.test {
    systemProperty("spring.profiles.active", "test,kafka")    // Active Spring profiles
    useJUnitPlatform()
    testLogging {
        events(FAILED, SKIPPED)
        exceptionFormat = TestExceptionFormat.FULL
        showExceptions = true
        showCauses = true
        showStackTraces = true
        showStandardStreams = true                  // Show stdout and stderr
 
        debug {
            events(STARTED, FAILED, PASSED, SKIPPED, STANDARD_ERROR, STANDARD_OUT)
            exceptionFormat = TestExceptionFormat.FULL
            showExceptions = true
            showCauses = true
            showStackTraces = true
        }
        info.events = debug.events
        info.exceptionFormat = debug.exceptionFormat
 
        val failedTests = mutableListOf<TestDescriptor>()
        val skippedTests = mutableListOf<TestDescriptor>()
 
        addTestListener(object : TestListener {
            override fun beforeSuite(suite: TestDescriptor) {}
            override fun beforeTest(testDescriptor: TestDescriptor) {}
            override fun afterTest(testDescriptor: TestDescriptor, result: TestResult) {
                when (result.resultType) {
                    ResultType.FAILURE -> failedTests.add(testDescriptor)
                    ResultType.SKIPPED -> skippedTests.add(testDescriptor)
                    else -> Unit
                }
            }
 
            override fun afterSuite(suite: TestDescriptor, result: TestResult) {
                if (suite.parent == null) { // root suite
                    logger.lifecycle("----")
                    logger.lifecycle("Test result: ${result.resultType}")
                    logger.lifecycle("""Test summary: ${result.testCount} tests, ${result.successfulTestCount} succeeded, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped""")
                    failedTests.takeIf { it.isNotEmpty() }?.prefixedSummary("\tFailed Tests")
                    skippedTests.takeIf { it.isNotEmpty() }?.prefixedSummary("\tSkipped Tests:")
                }
            }
 
            private infix fun List<TestDescriptor>.prefixedSummary(subject: String) {
                logger.lifecycle(subject)
                forEach { test -> logger.lifecycle("\t\t${test.displayName()}") }
            }
 
            private fun TestDescriptor.displayName() = parent?.let { "${it.name} - $name" } ?: name
        })
    }
}

API

Plugin

Spring Boot

// Kotlin DSL
tasks.bootRun {
    systemProperty("spring.profiles.active", "no-security,kafka")
    jvmArgs(
        "-XX:+UnlockDiagnosticVMOptions",
        "-XX:+UnlockExperimentalVMOptions",
        "-XX:+DisableExplicitGC",
        "-Xms1g",
        "-Xmx1g",
        "-XX:MetaspaceSize=70000000",
        "-XX:ErrorFile=${layout.buildDirectory.get().asFile}/hs_err_%p.log",
        "-XX:+HeapDumpOnOutOfMemoryError",
        "-XX:HeapDumpPath=${layout.buildDirectory.get().asFile}/heapDump.log",
        "-XX:+IgnoreUnrecognizedVMOptions",
        "-XX:LogFile=${layout.buildDirectory.get().asFile}/jvm.log",
        "-XX:+LogVMOutput",
        "-XX:NativeMemoryTracking=detail",
        "-XX:+PrintCommandLineFlags",
        "-XX:+PrintFlagsFinal",
        "-XX:+PrintNMTStatistics",
        "-XX:StartFlightRecording=settings=default,filename=${layout.buildDirectory.get().asFile}/${project.name}.jfr,dumponexit=true,maxsize=100M",
        "-XX:+UseZGC",
        "-XX:+ZGenerational",
        "-Xlog:gc*=info,gc+heap=debug,gc+ref*=debug,gc+ergo*=trace,gc+age*=trace:file=${layout.buildDirectory.get().asFile}/gc-%t.log:utctime,pid,level,tags:filecount=2,filesize=100m"
    )
}

Resources