Composite Builds and Project Name

buildship
eclipse

(Thomas Küstermann) #1

Let’s say I have two multi-module projects, fooand bar. Both have a sub-project api. In order to have both projects in the Eclipse workspace I followed the advice in the Frequently Asked Questions and added

eclipse.project.name = (rootProject.name + project.path).replaceAll(':', '.')

to the build files. The imported eclipse projects are named foo.api and bar.api now. Good so far.

Now, I have a third projects that consumes the :bar:api project via dependency. In order to have a project dependency I added

includeBuild '../bar/'

to the settings.xml. When I now refresh the project via [Gradle] -> [Refresh Gradle Project] a class path entry for the project api is created which results in a build path error because the correct project name in Eclipse is bar.api.

Is there something wrong in my setup or is this a Buildship or Tooling API issue?


(Stefan Oehme) #2

This should work, but you might have found a bug. Could you provide a reproducible example?


(Thomas Küstermann) #3

Thanks for asking to provide a reproducible example. While testing the example projects I wasn’t able to reproduce my issue. Projects were linked correctly. I searched for differences in the example and production projects and as it turned out it was my Gradle Initialization Script that wasn’t applied to the referenced project.

I use the Gradle Wrapper in conjunction with a customized Gradle distribution. The customization contains init scripts for working with out corporate maven repository, java project defaults and Eclipse settings. Powerful combo by the way. The Eclipse init script contains the setting for hierarchical project names:

projectsEvaluated {
    rootProject.allprojects { project ->
        if (project.plugins.hasPlugin('eclipse')) {
            if (project != rootProject) {
                eclipse.project.name = (rootProject.name + project.path).replaceAll(':', '.')
            }
        }
    }
}

While this works fine for all mulit-module projects on their own, it doesn’t work in conjunction with composite builds. The setting in the init script is ignored completely. The fix was simple and I only had to duplicate the hierarchical project naming setting in the referenced project / included build.

Is this intended behavior?


(Stefan Oehme) #4

I just tried this locally and init scripts are executed for all included builds. Can you make sure that the composing build is using your custom distribution with all the special init scripts? Because that’s the distribution that will be used for all included builds as well.


(Thomas Küstermann) #5

I can confirm that my composing build is using our custom distribution including the mentioned init script. Let me give you an example of what works for me and what’s not:

  1. I create project domain-model with two modules: api and shared. The domain-model project’s wrapper is using the customized distribution. The build script is simple:

     allprojects {
         apply plugin: 'java'
         apply plugin: 'eclipse'
         apply plugin: 'maven'
    
         group = 'thokuest.example'
         version = '0.0.1-SNAPSHOT'
    
         repositories {
             mavenLocal()
         }
     }
    
  2. When I add the Gradle Nature to the project or refresh the existing project, three projects are now present in the workspace. All of them have the correct hierarchical project names:

  • domain-model
  • domain-model.api
  • domain-model.shared
  1. Now I create a new project domain-model-consumer whose wrapper also points to the same distribution and declares a dependency on thokuest.example:api:0.0.1-SNAPSHOT. The settings.xml contains the instruction includeBuild '../domain-model'. When I add the Gradle Nature or refresh the project I get an incomplete build path.

Instead of a dependency to api I expect a dependency to domain-model.api. It only works when I add

if (project != rootProject) {
    eclipse.project.name = (rootProject.name + project.path).replaceAll(':', '.')
}

to the allprojects configuration of the domain-model project and refresh the composing project.

I feel like I’m missing something obvious, so any help is appreciated.


(Stefan Oehme) #6

I can reproduce the problem now. The global projectsEvaluated hook is only called after the tooling model is already built, so the consumer project sees an incomplete configuration of the producer project. Changing the init script to this fixes the issue and is shorter:


allprojects {
  plugins.withId('eclipse') {
    if (project != rootProject) {
        eclipse.project.name = (rootProject.name + project.path).replaceAll(':', '.')
    }
  }
}

In general I’d avoid the global projectsEvaluated hook and instead use either lazy methods like plugins.withId() {} or use project.afterEvaluate {} on the individual projects.


(Thomas Küstermann) #7

Sorry for the late reply. That was exactly what I have missed, works like a charm. Thanks, Stefan!