Gradle projects depending on artifacts created by sibling projects

stolsvik picture stolsvik · Jul 26, 2013 · Viewed 10.6k times · Source

I have this Gradle setup with four projects, a parent with three children, where a Java Servlet JSON 'backend' is built into a war-file, and then a static HTML5 'frontend' consuming this is built into a zip. Both these "installs" their artifcats to the local maven repo.

The third sibling project 'merger' depends on these two artifacts, to build a "merged" war by simply "zipping them together".

However, once I had this up and running as intended, I obviously had to test the bootstrap-scenario by deleting the artifacts from the local repo.

Now I suddenly get "Artifact 'no.company:frontend:1.0-SNAPSHOT@zip' not found".

Is it not possible to depend on artifacts which will be produced by the current build?

Edit:

Based on another idea (and the reply from Peter discouraging this Maven logic), this version looks promising, not traversing Maven (note: it works!):

// ## From frontend's build.gradle:
task zipFrontend(dependsOn: 'buildFrontend',  type: Zip) {
    from ('dist/')
}

// ## From backend's build.gradle:
apply plugin: 'war'

// ## From merger's build.gradle:
task mergeFrontAndBack(dependsOn: [':backend:war', 
                                   ':frontend:zipFrontend'], type: War) {
    from zipTree(project(':frontend').tasks['zipFrontend'].archivePath)
    from zipTree(project(':backend').tasks['war'].archivePath)
    destinationDir(buildDir)
}

Edit 2:

Based upon Peter's comment about not reaching into siblings' project structure and his concrete suggestions, here's the resulting piece (note: it works!):

// ## From frontend's build.gradle:
task zipFrontend(dependsOn: 'buildFrontend',  type: Zip) {
    from ('dist/')
}
configurations { zip }
artifacts { zip zipFrontend }

// ## From backend's build.gradle:
apply plugin: 'war'
configurations { jsonOnlyWar }
artifacts { jsonOnlyWar war }

// ## From merger's build.gradle:
configurations { merge }
dependencies {
    merge project(path: ':backend', configuration: 'jsonOnlyWar')
    merge project(path: ':frontend', configuration: 'zip')
}
task mergeFrontAndBack(dependsOn: configurations.merge, type: War) {
    from { configurations.merge.collect { zipTree(it) } }
    destinationDir(buildDir)
}

Answer

Peter Niederwieser picture Peter Niederwieser · Jul 26, 2013

The local Maven repository (and Gradle's install task) should only be used when exchanging artifacts with Maven builds. It's not meant to be used for exchanging artifacts between projects of a Gradle build, and installing into the local Maven repository won't happen automatically.

Instead, merger needs to declare project dependencies on the other two projects. For example:

configurations {
     merge
}

dependencies {
    merge project(":frontend"), project(":backend")
}

task merge(type: Zip) {
    from { configurations.merge.collect { zipTree(it) } }
}

This assumes that frontend and backend correctly declare their artifacts. (This may happen automatically, for example if the war plugin is used.)

You'll find much more on this in the Gradle User Guide, in particular the multi-project builds chapter.