nxrocks
nxrocks copied to clipboard
Executors not working in a multi-module project with more than one level of folders
First of all, thank you for this amazing work.
This plugin is very useful for managing monorepos with Nx and Spring Boot :clap: :1st_place_medal:
Plugin Name
@nxrocks/nx-spring-boot
Nx Report
Node : 16.20.1
OS : linux-x64
npm : 8.19.4
nx : 17.0.2
@nx/js : 17.0.2
@nx/workspace : 17.0.2
@nx/devkit : 17.0.2
@nrwl/tao : 17.0.2
typescript : 5.2.2
---------------------------------------
Community plugins:
@nxrocks/nx-spring-boot : 9.0.1
Expected Behaviour
Executor option "runFromParentModule": true should locate the parent module (if using a multi-module project) when the submodules are located in a subfolder (with more than one level of nesting).
Actual Behaviour
Executors for submodules (in a multi-module project) are not working when using the option runFromParentModule option and the maven wrapper if the submodules are located in a folder with more than 1 level of nesting, e.g.
.
├── nx.json
├── package.json
├── package-lock.json
├── packages
│ └── demo-parent
│ ├── apps
│ │ └── demo
│ │ ├── pom.xml
│ │ ├── project.json
│ │ └── src
│ ├── mvnw
│ ├── mvnw.cmd
│ ├── pom.xml
│ ├── project.json
│ └── target
├── README.md
└── target
Note the demo module folder which is not a direct folder of demo-parent. The demo-parent contains the maven wrapper.
When running a task (e.g. nx run demo:clean it seems like the executor cannot find the parent module and never ends.
Steps to reproduce the behaviour
- Create an empty Nx workspace and install the
@nxrocks/nx-spring-bootplugin - Add a new Spring Boot application as a multi-module project (e.g.
demoanddemo-parent) - Move the generated child module
demointo an intermediary subfolder (modifying itsproject.jsonfile according) - Try to run a task, e.g.
nx run demo:clean
I will try to create a sample repo later today.
Hi @datenciadedalus
Thanks for using the plugin and for your kudos! Don't hesitate to star ⭐ the project on GitHub ;-)
Regarding the issue, it looks indeed like a bug, as when the runFromParentModule is set to true, the executor is already supposed to search the child module folder hierarchy, until the parent pom.xml (or build.gradle) that does contain the child module is found...
I'll have a look into it, stay tune!
:love_you_gesture: Great!
Yes, I've been digging through the code and I've seen the loop causing this that tries to locate the parent pom.xml.
Thank you for your quick response :star: :star: :star:
:tada: This issue has been resolved in version 9.0.2 :tada:
The release is available on:
Your semantic-release bot :package::rocket:
Thank you :love_you_gesture:
I've been testing the new release but it is still not working because it is not taking into consideration the path of the submodule when looking for it in the parent pom.xml file. I've created a PR fixing it.
Hi @datencia, thanks for trying out the multi-module feature and for your PR
But unfortunately, I think your proposed implementation is not correct either...
There is a misconception on how the structure of a true nested multi-modules project should look like. As the result, my initial implementation was "limited" in that regard, and your is not really solving the problem.
I looked at Spring Boot own project on Github, which is imho, a very good example of how a truly nested multi-modules project should be structured.
This is what I learned:
For Maven
(Until 2.2.x, Spring Boot project was using Maven as build system) https://github.com/spring-projects/spring-boot/tree/2.2.x
├── spring-boot-tests/
│ ├── spring-boot-deployment-tests
│ ├── spring-boot-integration-tests
│ ├── spring-boot-smoke-tests-invoker
│ ├── spring-boot-smoke-tests
│ └── pom.xml (intermediary pom.xml listing direct children modules in this folder)
│
├── spring-boot-project/
│ ├── spring-boot-actuator
│ ├── spring-boot-devtools
│ ├── spring-boot-starters/
│ │ ├── spring-boot-starter-activemq
│ │ ├── spring-boot-starter-actuator
│ │ ├── spring-boot-starter-jpa
│ │ └── pom.xml (intermediary pom.xml listing direct children modules in this folder)
│ │
│ └── pom.xml
│
└── pom.xml (THE root module)
Main Takeaways
- one additional
pom.xmlat each intermediary level - the intermediary
pom.xmllists direct children modules in the folder
For Gradle
(Since 2.3.x, Spring Boot project now uses Gradle as build system) https://github.com/spring-projects/spring-boot/tree/main
├── spring-boot-tests/
│ ├── spring-boot-deployment-tests
│ ├── spring-boot-integration-tests
│ ├── spring-boot-smoke-tests-invoker
│ └── spring-boot-smoke-tests
│
├── spring-boot-project/
│ ├── spring-boot-actuator
│ ├── spring-boot-devtools
│ └── spring-boot-starters/
│ ├── spring-boot-starter-activemq
│ ├── spring-boot-starter-actuator
│ └── spring-boot-starter-jpa
├── build.gradle
└── settings.gradle (THE root module listing all modules using their full path , with ":" as separator)
Main Takeaways
- no need for additional
settings.gradleat each intermediary level - the root module
settings.gradlelists all modules using their full path , with ":" as separator
So based on that, I will rework/improve and better document the nested mutli-module support, following the best practices from Spring Boot project, as described above.
Stay tuned!
mmm I see, but imho it is merely a way of organizing the modules and not a good practice itself.
This organization may make sense within the scope of a project that requires it, but other projects do not need to create an intermediate pom.xml.
I'm going to try to use this workaround of an intermediate pom.xml but I guess I'll have to add another maven wrapper there for it to work, right?
Suggestion: make the root module path configurable at the plugin level to avoid these problems by locating the Maven wrapper so you don't have to search by code for its location.
Hi @datencia
This organization may make sense within the scope of a project that requires it, but other projects do not need to create an intermediate pom.xml.
OK, granted that the intermediary pom.xml might not be always necessary (depending on if there is an actual need to gather common configuration, dependencies or plugins at that level).
But, I'm curious... in your case:
- why would you have an intermediary
appsfolder (demo-parent/apps/demo/) to begin with? - how does your
demo-parent/**pom.xml**look like? do you refer to the demo child module from there (using the relative path<module>./apps/demo</module>?
I'm going to try to use this workaround of an intermediate pom.xml but I guess I'll have to add another maven wrapper there for it to work, right?
Yes that right, The current code expect the parent module to declare the child module as a direct module (i.e <module>child-module</module> and also to contain the Maven Wrapper files.
Regarding the issue, it looks indeed like a bug, as when the runFromParentModule is set to true, the executor is already supposed to search the child module folder hierarchy, until the parent pom.xml (or build.gradle) that does contain the child module is found...
I would like the plugin to ease/automate that as much as possible, to avoid yet another config to manage for end-users. Not sure if most of them will ever need such detail of customization...
But, I'm curious... in your case:
In my case, I have an structure like this (reduced for simplicity, the names are for guidance only) managing 3 independent apps, e.g. 2 spring boot applications and one angular/react app:
.
├── mvnw
├── mvnw.cmd
├── nx.json
├── package.json
├── package-lock.json
├── apps
│ ├── backend
│ │ ├── pom.xml
│ │ ├── project.json
│ │ └── src
│ ├── api-rest
│ │ ├── pom.xml
│ │ ├── project.json
│ │ └── src
│ └── frontend
│ ├── package.json
│ └── src
├── pom.xml
└── README.md
The parent pom.xml file (at the project root folder, note also the Maven wrapper there) manages the common properties/dependencies for the 2 spring boot applications and declares them as modules:
<modules>
<module>apps/backend</module>
<module>apps/rest-api</module>
</modules>
I would like the plugin to ease/automate that as much as possible, to avoid yet another config to manage for end-users. Not sure if most of them will ever need such detail of customization...
I have thinking about it, reading the Maven docs (I have not been able to look at gradle) I think that if the plugin offered a way to indicate the path to the maven wrapper (or by default use the root folder of the project as it usually happens) you could avoid having to locate it manually, and combining it with the use of the ArtifactId instead of using the path would avoid having to calculate/locate the module that contains it.
Inspecting the Maven help mvn --help I read this
-pl,--projects <arg> Comma-delimited list of specified
reactor projects to build instead
of all projects. A project can be
specified by [groupId]:artifactId
or by its relative path
Note the point A project can be specified by [groupId]:artifactId or by its relative path.
I have been testing a while this approach (to be honest, I didn't know about it) and works, e.g.
./mvnw clean -pl :backend`
Where backend (in this example) is the artifactId for the apps/backend application as declared in apps/backend/pom.xml.
By using the artifactId I don't need to know the path of the module.
Thanks for your Input @datencia
I like the idea of using the :artifactId :-)
I thought about it at the beginning, don't remember why I discarded the idea at the time... but it seems the best solution.
I will dig a little more and gather knowledge for Gradle as well, to provide the most unified and simple solution for users.
Don't hesitate to continue sharing your feedback, much appreciated 👍🏾
Running into the same issue after wondering why my CI timeouted after 40 minutes.
I'm using Gradle and @nxrocks/nx-quarkus.
Is there any progress on this issue so far?
Hi @mklueh
I'm currently improving the support for multi-modules projects to accommodate this use case( Initial PR is here: https://github.com/tinesoft/nxrocks/pull/210)
It should be fixed very shortly.
So stay tuned! ;-)