Description
Consider a multi-module project that uses ci-friendly versions (i.e. the root pom declares <version>${revision}</version>).
While "scanning for projects", the DefaultProjectBuilder (build:347) uses a two-phase approach.
1) build:390 populates a set of interimResults and a projectIndex. The keys of the projectIndex take the form groupId:artifactId:packaging:version and the version always is the interpolated version (i.e. 1.0-SNAPSHOT rather than ${revision}).
2) build:573 calls initProject which in line 638 attempts to retrieve the previously constructed parent project from the projectIndex. However, the key used here still contains the uninterpolated version (i.e. ${revision}) so the parent project is never found. In line 652, the parent project is therefore constructed anew:
parent = build( parentPomFile, projectBuildingRequest ).getProject();
This is not only ineffective but also causes problems, e.g. if the parent imports a bom module from the same reactor, this leads to a warning "Failed to build parent project" and potential follow-up problems. Also, the maven assembly plugin seems to fail on such projects.
Details
- The ModelBuildingResult created in the first phase contains a list of modelIds. They key used to add an entry to the project index always corresponds to the first item in this list:
// DefaultProjectBuilder:436 projectIndex.put( result.getModelIds().get( 0 ), project )
However, the key used to retrieve the entry during the processing of its child is the second element from the modelIds list:
// DefaultProjectBuilder:636 String parentModelId = result.getModelIds().get( 1 ); MavenProject parent = projects.get( parentModelId );
The list items are created by DefaultModelBuilder.build:244. First a "lineage" of the current module is built. Then the first element of the lineage, corresponding to the current module, gets interpolated. The other lineage items do not get interpolated, i.e. they still contain the placeholder version.
The list of modelIds is then constructed from the lineage, leading to the first element having an interpolated version whereas all other elements have a placeholder version.
// DefaultModelBuilder:411 for ( ModelData currentData : lineage ) { String modelId = ( currentData != superData ) ? currentData.getId() : ""; result.addModelId( modelId );
Fix
One way to fix the issue might be to interpolate all elements of the lineage in DefaultModelBuilder.build:244, or to at least replace their versions.
The following modification (hacky and probably faulty, for demonstration purpose only) fixed the issue for my project:
// model interpolation resultModel = interpolateModel( resultModel, request, problems ); resultData.setModel( resultModel ); /* new code starts here */ if ( resultModel.getParent() != null ) { final ModelData parentData = lineage.get( 1 ); final Model interpolatedParent = interpolateModel( parentData.getModel(), request, problems ); // parentData.setModel( interpolatedParent ); parentData.setVersion( interpolatedParent.getVersion() ); }