Remote builds with Gradle

If you have more bandwidth than processing power and memory, it's very convenient to be able to compile Gradle projects and even run tests on a remote server. I've written a simple script called gradle-remote that you can use in place of the gradle command.

It will transparently upload your project to the remote server, run the specified Gradle command and then download the results back to your local build directory. Since it uses rsync to transfer files, the file changes will be delta compressed – in practice the uploads are very fast even for large projects.

#!/bin/bash
# we need bash, not just posix shell for some types of expansions

# search upwards in file hierarchy for build.gradle
while [ "$PWD" != / ] && [ ! -f build.gradle ]; do
	cd "$(dirname "$PWD")"
done

if ! [ -f build.gradle ]; then
	printf '%s\n' 'No build.gradle file found'
	exit 1
fi

remote="$GRADLE_REMOTE_SSH"
if [ -z "$remote" ]; then
	printf '%s\n' 'Set GRADLE_REMOTE_SSH to a valid ssh login on your build server'
	exit 1
fi

remotehome="$GRADLE_REMOTE_DIR"
if [ -z "$remotehome" ]; then
	printf '%s\n' 'Set GRADLE_REMOTE_DIR to the place where projects will be stored on the server'
	exit 1
fi

remotedir="$remotehome/${PWD////_}"

set -e
rsync -ircu --exclude build --exclude .gradle --exclude '**.swp' --delete . "$remote:$remotedir"
# https://stackoverflow.com/questions/6592376/prevent-ssh-from-breaking-up-shell-script-parameters
# ssh argument expansion is pure unfiltered cancer
ssh -t "$remote" "source .profile; " gradle -p "$remotedir" "${@@Q}" " && mkdir -p $remotedir/build"
rsync --delete -ircuq "$remote:$remotedir/build" . | (grep -v '/$' || true)

Configuration

The script is configured through environment variables.

Set GRADLE_REMOTE_SSH to a valid ssh login target. For example myserver.net or gradle_builder@example.com.

Set GRADLE_REMOTE_DIR to the base directory in which projects will be stored. You probably want a dedicated user on the server for running the builds, so something like "/home/gradle/projects" will work.

To prevent unused projects using up the disk space, I use a cron job which deletes all project directories older than the specified time.

0 * * * * find /home/gradle/projects -mindepth 1 -maxdepth 1 -type d -mmin +720 -print0 | xargs -0 rm -rf

I have aliased gradle to gradle-remote for my shell. If you ever want to use the real gradle command, you can invoke it as command gradle which will bypass alias expansion.

TODO