Alright… figured this one out. We have a slightly odd way of building core in the Docker environment where instead of running, e.g.,
mvn clean install, we run
mvn clean install for each subproject, one at a time. This allows us to take advantage of Docker’s layers so that, e.g., if the build fails in one subproject, Docker can effectively “resume” the build from the point that failed, making builds hopefully faster.
However, doing things this way left out one important thing: the root POM. Like most Maven multi-module projects, OpenMRS Core’s root POM is primarily used for configuring shared dependencies, plugins, etc. Importantly, for this case, we heavily use it to ensure all sub-projects use the same versions of shared dependencies.
Recently, a new dependency was added to OpenMRS Core, to allow us to serialise the java.time classes to JSON correctly. This was done, correctly, by adding the dependency and the version to the root POM and then adding the dependency without the version to the child POM (the -api submodule).
This is where things get weird: because we resolve dependencies before running the builds in a project-wide way, a version of the new dependency was downloaded, and Maven seems to have used that to build the
api sub project happily. Unfortunately, the next project,
web, actually depends on
api to provide most of its dependencies (there are a large number of transitive dependencies). At this point, we see this WARNING in the log:
[WARNING] The POM for org.openmrs.api:openmrs-api:jar:2.6.0-SNAPSHOT is invalid, transitive dependencies (if any) will not be available, enable debug logging for more details
api submodule is invalid because there is no version specified for the newly added dependency because, while the parent project is resolved properly from the child project, to resolve the
api POM, Maven looks for the parent POM of the
api method and the last one that has been cached doesn’t have a version provided for that dependency.
Anyway, that’s a very long explanation for why I added this one line which fixes the problem: by building the parent project (again as a separate step) we ensure that these kinds of transitive dependencies are properly resolved.