IntelliJ Module structure after Gradle import - gradle

I a (common) Gradle multi-project build I have a root with four sub-projects. Each with their own build.gradle and a common build.gradle, settings.gradle and gradle.properties in the root folder.
It all builds an works as expected - except for one thing I can't figure out:
When importing the gradle-build into IntelliJ (import from external model) IntelliJ creates two separate modules at root-level. One is marked as a normal Module and one as a Grouped module. It is the latter that surprises me - why is this created? It makes no sense to have in as a module in IntelliJ since it only points to some downloaded jar-files in my .gradle folder. See below picture.
I've create several gradle multi-project builds and worked with IntelliJ for several years - yet I have never seen this nor do I know how to get rid of it..

Andrey said in the comments:
Try 2019.1 RC from jetbrains.com/idea/nextversion The related issue (youtrack.jetbrains.com/issue/IDEA-187917) has been fixed there. See also stackoverflow.com/questions/54036569 as a duplicate.
Which fixes the issue.

Related

Why refresh of Maven repository is not enough for IntelliJ?

I had a NoClassDefFoundError problem with some test, launched from IntelliJ. In order to repair the situation, I had to make several changes in many poms of the project - adding new packages and excluding some old ones for to escape the overlapping of them. Also, I reapired the situation with different versions. But the situation did not improve. Again, some package, declared in pom, was not found where it should be.
I refreshed the maven repository by
mvn -e clean install -U
, as is advised in https://stackoverflow.com/a/9697970/715269 - so old and upvoted answer, that it surely looks as Santa.
The problem remained unchanged.
I output the maven map. It was correct and it contained all needed.
I looked at the list of the External Libraries of the project. It was the old uncorrected list of overlapping jars with same names and different versions, and without good packages I added just now, and well seen in maven tree output!
Already hapless,
I reimported packages in IntelliJ
by:
Ctrl+Shift+A, Reimport All Maven Projects.
Ho! The list of libraries got repaired. And the problem, mentioned in subj, disappeared.
The question is: How it could happen, that the same project has that very pom for everything, but gets packages differently being launched in maven and in IntelliJ?
I know about that feature "delegate IDE build to Maven". And I keep it turned off. But I am NOT talking about the different SW for building. Whether they are different or not, they should be up to the actual pom's. And whereas maven, if turned off from the automatic building won't know about changes in poms, IntelliJ KNOWS about them. It could have jars up to pom, or up to maven - it has sense, but it simply has some old rubbish. Was there some deep thought under that construction?
Every time you manually change the pom.xml file, including the dependencies you need to load these changes into IDE. IDE does it on Reload from Maven action. See also Import Maven dependencies.
Intellij doesn't use maven to bulid and run a project except you are delegating build and run action to maven:
Since, IDEA doen't really use maven to run and build, it uses the pom.xml to import the project structure and "tries" to build the project the same way was maven does.
Actually, there are quite a few differences between these to build processes.
Generating sources or filtering resources (don't know if this is still an issue) aren't done during building the project with Intellij IDEA.
In case you are using code generation you have to build the project via maven first and then - when all the resouces are filtered and additional sources are generated - you are able to run, debug aso. the project with Inellij IDEA.
That's an important thing to be aware of and that's the reason why maven and IntelliJ IDEA project structures might get out of sync.
You can enable the "Reload project after changes in build scripts" feature and select the Any changes checkbox to keep your project structure updated:
Why should you disable this feature anyway
If you are working on a build file (gradle or maven is not important) reloading the structure on any change can be very anoying. It's cpu intense, dependcies are fetched aso.
Therefore, I prefer to reload project structure only in case of an external change. This happens when pulling an updated version of the build file for example.

Tell intelliJ to make 1 single module instead of multiple modules for Gradle

I am working on a gradle project, and IntelliJ makes a sub module for each source set. The problem is, if this is done, then each source set needs to be dependent on one another, resulting in circular dependencies.
If I manually setup the modules to be one single module, everything works and there are no circular dependencies. But then the next time the build.gradle is changed, I have to spend 10 minutes redoing everything.
Is there any way to make intelliJ build this as one single module when it reads the gradle file? I looked at the documentation of Idea Module, but it doesn't seem to be of much help.
IntelliJ can be set to only generate a single module per gradle project. Go into your gradle preferences in IntelliJ, and uncheck the option "Create separate module per source set"
Edit: This has been removed in later versions of IntelliJ. My main issue involving dependencies has been resolved, and now I can use different modules just fine.

IntelliJ: Excluding a set of folders across multiple Gradle modules in an IntelliJ Gradle project

I need to figure out a quick/scripted way of excluding a set of folders across multiple IntelliJ gradle modules in an IntelliJ project imported from Gradle.
I have a Gradle multi-module project that I have imported into IntelliJ. The project is a refactoring of a legacy codebase into modules. Part of the resulted refactoring is that there are multiple copies of the same class across multiples modules (this was done to break dependency cycles in code): there is the original class and a number of "mock" copies
I'm trying to exclude a bunch of folders containing copies of classes in these "mock" sourcesets in a scripted manner.
I've imported the Gradle project into InteliJ. To begin excluding the folders I started by excluding one of the folders in one of the modules... ...
I then tried to determine where in my .idea folder this particular setting is persisted... I have been unable to find it...
My question is: can someone point me to the IntelliJ file (e.g. .idea/workspace.xml) that stores this setting? Alternatively can someone point me to the folder that stores this setting?
Update
I manually went and excluded all the folders that contain mock copies of my classes. Those settings appear to be persisted (still not sure where those settings are being stored).
The second problem I need to solve is that I need to declare custom dependencies between Gradle imported modules that are different from those configured in the Gradle project. I can add dependencies within the project, but whenever I refresh my Gradle project or import any changes, my changes are lost.

Gradle composite build with custom gradle plugin fails in IntelliJ: "Could not find method api() for arguments"

I have a Gradle composite build project which contains a custom Gradle plugin. This project builds fine when using Gradle CLI, but IntelliJ fails.
I tried a few different variations on the plugin version within the resolutionStrategy block: org.test:test-plugin:0.0.1 and test-plugin:test-plugin.gradle.plugin:0.0.1 as described here: https://docs.gradle.org/current/userguide/plugins.html#sec:plugin_markers - both of those work from the CLI; changing to invalid values ("blah:blah") causes a failure.
I've made a sample Github project that contains the code to reproduce, here: https://github.com/mwmitchell/intellij-gradle-plugin-composite-build-bug along with instructions to reproduce and a workaround. The workaround is something that's not really feasible for me, as it requires repeating configuration code (dependencies, plugins etc.) and I have many, many projects that require the same/common configuration.
I would expect IntelliJ to load the project successfully, just like the CLI does. It seems like IntelliJ is loading the sub-project (:project-1:library-a) before the parent (:project-1), such that the java-library is not actually applied to the sub-project when it's evaluated.
Thanks for the sample project! Indeed, it is an issue in IntelliJ IDEA, see this ticket.
Gradle projects can have only one settings.gradle. You can include subproject "library-a" with include 'project-1:library-a' in the main settings.gradle.

How can I add gradle project dependencies without modifying settings.gradle

Background
(Please keep in mind I've simplified the problem for purposes of discussion here)
I've got a set of applications and dependent libraries, something like this (each with a src/ directory and build.gradle):
appa/
appb/
libx/
liby/
libz/
In build.gradle, the dependencies are currently declared like this:
appa/build.gradle:
compile "com.asdf:libx:1.0"
compile "com.asdf:liby:1.0"
appb/build.gradle:
compile "com.asdf:liby:1.0"
liby/build.gradle:
compile "com.asdf:libz:1.0"
What problem am I trying to solve
Say I'm working on appa, and I need to make changes to libx. I need to do multiple steps:
Pull libx from source control and make changes locally
Rebuild and push changes to some repo (not prod!)
Rebuild appa (pulling the recently updated libx from repo)
If my testing reveals a bug in libx, I've got to repeat that over again.
This is super-annoying when working in IDEs like Eclipse, where even though my projects are logically using other projects, I've got to still use the artifacts as dependencies.
Wouldn't it be great if I can just pull the project locally, and projects that logically depend on it will automatically use the source project instead of artifact for building?
What I've done so far
I've written a small gradle plugin (referenced in each project's build.gradle) that identifies com.asdf dependencies, and uses dependency substitution to replace the artifact dependency with a project dependency if that project exists locally.
configurations.all {
resolutionStrategy.dependencySubstitution {
all { DependencySubstitution dependency ->
if (dependency.requested instanceof ModuleComponentSelector && dependency.requested.group == 'com.asdf') {
def targetProject = findProject(":${dependency.requested.module}")
if (targetProject != null) {
dependency.useTarget targetProject
}
}
}
}
}
Yay! With a few modifications to settings.gradle (see below), I've accomplished my goal... Except...
Where I'm stuck
I need to modify settings.gradle to include lines like this for every dependency (otherwise findProject doesn't resolve the dependent project during build):
include ':libx'
project(':libx').projectDir = new File(settingsDir, '../libx')
While it's possible to go through all the settings.gradle files and do this (I've done it for a handful as my proof-of-concept), it's ugly, repetitive, and is logically the same information that is being passed to compile arguments for the build.gradle dependencies.
It's also error-prone when someone adds a new dependency but doesn't update settings.gradle, or introduces a typo between them.
I've also tried making settings.gradle just define projects for all directories it finds at that level, but then building any project turns into a mega-build of all projects.
(I've tried several other things, but my question is getting long in the tooth already)
My question
What's a better way to do this, without duplicating information between settings.gradle and build.gradle? I want to make it so adding new dependencies is still just as easy as adding the compile reference in build.gradle, without touching settings.gradle...
I'm still rather new to groovy/gradle, so maybe I'm missing something that's obvious to the more experienced gradle master?
I believe your use-case is the motivation for Composite Builds.
I have a demo here, which writes to a jars folder as a mock publishing of artifacts. Be sure to check-out the README.md as the demo is a mini-laboratory for trying out the use-case before and after composite builds.
In the demo mainBuild is appa; utils is libx. The key syntax in mainBuild/settings.gradle (here) is:
includeBuild '../utils'
This tells Gradle to use the local codebase instead of the published artifact. Of course, one would not commit this line to source-control.

Resources