Search code examples
gradlemulti-project

Gradle multi-project dependencies with snapshots


I have a multiple project build with flat paths, e.g.:

settings.gradle:
includeFlat 'projA','projB','projC'

There are about 20 different sub-projects with all sorts of different interdependencies. I'd like gradle to handle the dependencies but I don't want to tie the entire project together as a monolith, I want to keep these as individual uploads which go into our artifact repository (Nexus) with their individual sub-project versioning. Each sub-project has its group specified in the gradle.properties file.

The problem is, if I call out the dependencies via the compile dependency, i.e.:

projA-build.gradle:
compile project(":projB")

Then everything compiles and the artifacts are uploaded just fine but at runtime I get an error such as:

Could not resolve all dependencies for configuration ':runtime'.
Could not find master:restclient:4.0-SNAPSHOT.

The upload is in the master build.gradle file. The relevant portion of the build script:

subprojects {
  afterEvaluate { Project proj ->
      def is_snap = false
      def reltype = "releases"
      def artifact_name = sprintf("%s-%s.jar" 
                               ,project['name']
                                 ,project['version'])
      def nexus_release_path = sprintf("%s/nexus/content/repositories/releases/%s/%s/%s/%s"
                               ,project['nexus_url']
                               ,project['groupId'].replaceAll("\\.","/")
                               ,project['name']
                               ,project['version']
                               ,artifact_name
                               )

      if(project.version.contains("SNAPSHOT")){
          reltype = "snapshots"
          is_snap = true
      }

      uploadArchives {
        // only try the upload if it's not already there
        onlyIf {
          try {
            def artifact_exists = new URL(nexus_release_path).bytes
            // if we get here then the artifact existed and we only want to
            // build if this is a snapshot version
            is_snap || false
          } catch (FileNotFoundException e) {
            // this means we couldn't find the artifact in nexus
            if(!is_snap){
              println "NOTE ==> Don't forget to create new git tag for $artifact_name!"
            } 
            true
          }
        }

        repositories {
          mavenDeployer {
            repository(url: "${project.nexus_url}/nexus/content/repositories/$reltype") {
              authentication(userName: project.nexus_user, password: project.nexus_password)
            }
            pom.version = "${project['version']}"
            pom.artifactId = "${project.name}"
            pom.groupId = "${groupId}"
          }
        }
      }
...
}

Though it's uploaded to Nexus correctly somehow the dependency is built in with that "master" in the artifact coordinates.

Am I going about this the wrong way or have the wrong expectations?


Solution

  • Gradle Project instances provide default properties for Maven coordinates:

    • Object group

      The group of this project. Gradle always uses the toString() value of the group. The group defaults to the path with dots as separators.

    • String name (read-only)

      The name of this project. The project's name is not necessarily unique within a project hierarchy. You should use the Project.getPath() method for a unique identifier for the project.

    • Object version

      The version of this project. Gradle always uses the toString() value of the version. The version defaults to unspecified.

    You can use these properties in your build.gradle file to specify or use the respective values, e.g.:

    group = 'my.company.group'
    

    Please note that the name property is read-only inside your build.gradle file, but you can set the name of your project inside the settings.gradle file before the Project instance will be created.

    Gradle uses these values to transform project dependencies into module dependencies, which is required when uploading to a repository. When uploading your artifacts, you manually set the Maven coordinates for your project (by setting pom.version, pom.artifactId and pom.groupId). For both version and artifactId you refer to the default properties provided by Gradle. However, for groupId you use your own custom property called groupId. I can't find your defintion of groupId, but I'm sure you specify it somewhere, leaving the default property group at its default value (the property path separated with dots). As a solution I would recommend you to set the default property group and somewhere and, if needed, use it inside your code:

    pom.version = project.version
    pom.artifactId = project.name
    pom.groupId = project.group