You can open the samples inside an IDE using the IntelliJ native importer or Eclipse Buildship.

This sample shows how credentials can be passed to an external tool that normally accepts them via standard input.

Let’s pretend that we have to log in to some system before performing some operation. This could be some external system that requires authentication before allowing us to upload some artifacts.

This sample assumes that the external tool that requires interactive login does not support any form of non-interactive login. In reality, many tools provide options to authenticate without prompting the user for input. Command-line arguments can be passed to the Exec task using the args property.

To demonstrate the concept, we will fake the authentication using a bash script that prompts the user for username and password:

login.sh
#!/bin/bash

echo Enter username:
read username
echo Enter password:
if [ -t 0 ] ; then # if connected to a terminal, do not echo the password input
    stty -echo
    read password
    stty echo
    echo
else
    read password
fi

if [ "$username" = "secret-user" ] && [ "$password" = "secret-password" ] ; then
    echo "Welcome, $username!"
else
    echo "Bad credentials!"
    exit 1
fi

It has a hardcoded username/password pair that will result in successful login. The script can be executed without Gradle - it will mimic a tool that requires an interactive login.

Gradle build file registers two tasks - one performs a login and the other one depends on the login having succeeded:

build.gradle
def login = tasks.register('login', Exec) {
    def USERNAME_PROPERTY = 'username'
    def PASSWORD_PROPERTY = 'password'
    def username = providers.gradleProperty(USERNAME_PROPERTY).forUseAtConfigurationTime()
    def password = providers.gradleProperty(PASSWORD_PROPERTY).forUseAtConfigurationTime()

    doFirst {
        if (!username.present || !password.present) {
            throw new GradleException("login task requires '$USERNAME_PROPERTY' and '$PASSWORD_PROPERTY' properties")
        }
    }

    standardInput = new ByteArrayInputStream("$username.orNull\n$password.orNull".getBytes())
    commandLine = ['sh', 'login.sh']
}

tasks.register('doAuthenticated') {
    dependsOn(login)
    doLast {
        println 'Doing authenticated task'
    }
}
build.gradle.kts
val login = tasks.register<Exec>("login") {
    val USERNAME_PROPERTY = "username"
    val PASSWORD_PROPERTY = "password"
    val username = providers.gradleProperty(USERNAME_PROPERTY).forUseAtConfigurationTime()
    val password = providers.gradleProperty(PASSWORD_PROPERTY).forUseAtConfigurationTime()

    doFirst {
        if (!username.isPresent() || !password.isPresent()) {
            throw GradleException("login task requires '$USERNAME_PROPERTY' and '$PASSWORD_PROPERTY' properties")
        }
    }

    standardInput = java.io.ByteArrayInputStream("${username.orNull}\n${password.orNull}".toByteArray())
    commandLine = listOf("sh", "login.sh")
}

tasks.register("doAuthenticated") {
    dependsOn(login)
    doLast {
        println("Doing authenticated task")
    }
}

The tasks are using project properties to capture the required credentials.

Credentials can be passed to a task in multiple ways now:

  • via command-line properties:

$ ./gradlew doAuthenticated -Pusername=secret-user -Ppassword=secret-password
  • via environment variables:

$ ORG_GRADLE_PROJECT_username=secret-user ORG_GRADLE_PROJECT_password=secret-password ./gradlew doAuthenticated
  • by setting the properties in gradle.properties file:

username=secret-user
password=secret-password

and running

$ ./gradlew doAuthenticated

This way the sensitive data can be kept outside of the project sources - gradle.properties can reside in the user’s ~/.gradle directory. The values are also not echoed anywhere this way. For more information about using Gradle properties, see Gradle Properties user manual chapter.

The output with correct credentials will be:

> Task :login
Enter userame:
Enter password:
Welcome, secret-user!

> Task :doAuthenticated
doAuthenticated

BUILD SUCCESSFUL in 496ms
2 actionable tasks: 2 executed