Search

Dark theme | Light theme

February 29, 2016

Gradle Goodness: Inter-Project Artifact Dependencies

When we define dependencies in Gradle we usually define them to compile source files. For example we create a Java project and need the Spring framework, then we define a dependencies configuration block with a dependency to the Spring libraries for the compile configuration. We can also use the dependencies configuration block to define dependencies on artifacts used in other tasks than the compiling source files. For example we might have a multi-module project where we want to aggregate artifacts from several projects into one place with the Copy task.

In the following example we have a multi-module project where projects projectA and projectB have a dist task to create a Tar file. In the project docker we want to copy the Tar files from those projects into the build directory. To achieve this we first apply the Gradle base plugin, because then we can use the artifacts configuration block. Inside the artifacts configuration we define that our dist task that creates the Tar file is assigned to the dockerDist configuration as artifact. This sets up our projects that create the artifact. The docker project uses these artifacts in the task prepare. The prepare task copies the artifacts of projectA and projectB to the build directory of the docker project.

configure(
    subprojects
        .findAll {
            it.name.startsWith('project') }) {

    // We need to base plugin for artifacts support.
    apply plugin: 'base'

    // Archive task where the archive file
    // is the artifact for our project we want
    // to use in aonther project.
    task dist(type: Tar) {
        compression 'gzip'
        from 'src/data'
    }

    configurations {
        // New configuration to associate
        // dist task output with.
        dockerDist
    }

    artifacts {
        // Declare output of dist task
        // as artifact for the dockerDist
        // configuration.
        dockerDist dist
    }
}

// Project with dependencies on the artifacts
// of projectA and projectB.
project('docker') {

    configurations {
        // Configuration needed to use
        // in the dependencies.
        dockerSource
    }

    dependencies {
        // Define that we depend on the artifacts
        // of projectA and projectB assigned to the
        // dockerDist configuration.
        dockerSource project(path: ':projectA', configuration: 'dockerDist')
        dockerSource project(path: ':projectB', configuration: 'dockerDist')
    }

    task prepare(type: Copy) {
        into "$buildDir/docker"

        // Use the artifacts from the other projects.
        // Gradle knows that tasks that created the artifacts
        // and will invoke them for us.
        from configurations.dockerSource
    }

}

Now let's run the :docker:prepare task from the command line:

$ gradle :docker:prepare

:projectA:dist
:projectB:dist
:docker:prepare

BUILD SUCCESSFUL

Total time: 0.796 secs
$ tree docker/build/
docker/build
└── docker
    ├── projectA.tgz
    └── projectB.tgz

1 directory, 2 files
$

Notice we didn't define a task dependency on the dist tasks, but Gradle knows by using the dependencies configuration which tasks need to be executed to fulfil all dependencies for the prepare task.

Written with Gradle 2.11.