Gradle projects depending on artifacts created by sibling projects

10,970

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.

Share:
10,970

Related videos on Youtube

stolsvik
Author by

stolsvik

Merge KEEP! Java coder. Check LinkedIn page for more info.

Updated on June 04, 2022

Comments

  • stolsvik
    stolsvik about 2 years

    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)
    }
    
  • stolsvik
    stolsvik almost 11 years
    Thanks! Okay, because this was how I did it with Maven (and I do install the artifacts to local Maven repo - this works!). However, I've tried the project dependency route you here suggest, but then I only get the JAR from the java-war-project (not the war), and not the zip from the static HTML-files project at all. Also, if I do the merge-task you define, won't I also merge in all the jar's from the java-war project? See, I only want the WAR-structure merged with the ZIP file of static HTML files (the resulting beast is servlet-container-deployable as a proper war due to the nature of war's).
  • stolsvik
    stolsvik almost 11 years
    Also - now I am trying another route: In the merger-project, I simply define a type:War task, which sets from-properties to the output of the "war" task in backend, and on the "zipFrontend" task of frontend. Is this possible? How? The tasks-property doesn't seem to hold sibling references?
  • Peter Niederwieser
    Peter Niederwieser almost 11 years
    Reaching out into the project model of other projects is discouraged. Instead, declare the necessary artifacts for the other two projects, e.g. configurations { zip }; artifacts { zip taskThatProducesZip }. Then adapt the project dependencies (e.g. dependencies { merge project(path: ":frontend", configuration: "zip") }.
  • stolsvik
    stolsvik almost 11 years
    Excellent, this approach seems nice! How do I now get hold of the war from the 'backend' project with the same logic? There is already a war-task, since I apply the war plugin. But apparently that is not a "configuration", and I have problems defining it as such.
  • Peter Niederwieser
    Peter Niederwieser almost 11 years
    Should work exactly the same as my code for "frontend" above.
  • stolsvik
    stolsvik almost 11 years
    What I just realized when reading that, was that I could maybe hack it. Because this doesn't cut it: configurations { war }; artifacts { war war } and then dependencies { merge project(path: ":backend", configuration: "war") } (I actually expected the "war" to be an "implicit configuration", so that only the dependency would be needed..). But then I tried configurations { theWar }; artifacts { theWar war } and dep on "theWar", and this works! The question is updated with the results.
  • Peter Niederwieser
    Peter Niederwieser almost 11 years
    It's safer to make` mergeFrontAndBack` a Zip task, as otherwise you might end up with some duplicated War behavior (e.g. duplicated descriptors). Another improvement is to make mergeFrontAndBack depend on configurations.merge, rather than on individual tasks.