If your question is about SonarLint in the IntelliJ Platform, VS Code, Visual Studio, or Eclipse, please post it in that sub-category.
Otherwise, please provide:
Operating system: Mac OS Sequoia 15.3
IDE name and flavor/env: Intellij IDEA Ultimate 2024.1.7
And a thorough description of the problem / question:
I’m currently investigating and working on a custom version of the SonarQube for IDE CORE and JetBrains plugin.
My objective is to retrieve the Quality Profiles and Rules from a custom API that works as a proxy between the IDE and the SonarQube Server to obtain metrics and usage information.
From the JetBrains project i can easily obtain the SDKTechnology using the ProjectRootManager but im struggling at finding any kind of option to obtain the project from the Core.
SLCORE is a project acting as a standalone Java application entirely out of context from the IDE platforms. Its role is to factorize all the common logic used by each implementation of SonarLint on IDEs supported by Sonar (IntelliJ, Eclipse, VS Code, and Visual Studio). This means you cannot directly acquire information about the IntelliJ platform from this project.
However, since SLCORE can communicate via RPC with SonarLint clients (such as SonarLint IntelliJ), you should be able to pass the information you want to it.
A simple flow could be the following.
In SLCORE:
Create your service class inside backend > core module
Define the endpoint for the RPC communication inside rpc-protocol module
In SonarLint IntelliJ:
Call the new endpoint you created by using the new service inside BackendService.kt, and pass the required information (from here, you should have access to the IntelliJ platform information)
You can take an example of the existing methods to understand the flow; it should be very similar to what is already existing.
So in order to obtain the information from the JetBrains plugin i need to publish an event and then receive it from the Backend Service?
Yes, from the RPC service point of view, you need to define your endpoint as @JsonNotification (RPC notification), meaning that it’s a one-way discussion; no return value is expected.
From the client side (IntelliJ), you can call your service method with notifyBackend { }.
Again, I think you can take an example of other methods; it should be pretty standard.
One more question, since im modifying and adding files on several sub projects (such as backend-rpc-impl or core-rpc-protocol) is there any easy way to move all generated JARs from SLCORE to a folder to build the folder for “sloop” ?
I’m not sure I understood, but for instance, if I want to build locally, I will do the following.
First, you should be able to build SLCORE with mvn clean install -P dist-no-arch from the root folder (we can also build against specific distributions: dist-no-arch,dist-windows_x64,dist-linux_x64,dist-linux_aarch64,dist-macosx_x64,dist-macosx_aarch64). JARs should be generated for all the modules.
Now, in sonarlint-intellij, you will want to use the artifact you just built before. For this, I usually do the following:
There is no easy way to get this information, so I collected it for you
The Java dependencies you would need for your plugin are:
sonarlint-java-client-utils
sonarlint-rpc-java-client
Transitively, for those 2 you will also need sonarlint-rpc-protocol
sonarlint-rpc-impl is not directly needed, but it brings 3 transitive dependencies that are needed today: sonarlint-commons, sonarlint-plugin-api and sonarlint-analysis-engine. Please note that these dependencies should normally soon be removed.
So you will need 6 dependencies (soon only the first 3). On top of that, as you figured out you need the Sloop distribution, built for various architectures if needed.
Out of curiosity, may I ask 2 things:
are you building this custom plugin because you lack some kind of feature in SonarQube for IDE or SonarQube Server? If yes, could you explain your need? What kind of statistics are you interested into?
why not building a transparent proxy server between SonarQube for IDE and Server using the same API contracts? This way you don’t need a custom plugin but you can intercept the traffic and collect statistics. But maybe I misunderstood your context.
For this proof of concept im trying to obtain the Project name and technology for the opened project (Using ProjectManager and ProjectRootManager) and dont use the Configured project on “Connected mode” since i think it could be better to obtain the latest Quality Profiles and Rules without accessing the Configuration Panel.
If i can do this and redirect those petitions to a custom API that works as a proxy, i could evaluate the traffic generated by all people using the custom Plugin.
– SL CORE: – Backend - Core: Service that calls the SonarLintRpcClient to ask for information and await the response
Backend - RPC Impl:
Added a new Delegate with the following method:
@Override
public CompletableFuture<GetProjectInformationResponse> getProjectInformation() {
return requestAsync(it -> getBean(ProjectInformationService.class).getProjectInformation());
}
Client - RPC Java Client: Added the implementation to a method from SonarLintRPCClientImpl that calls the previous delegate
RPC Protocol: Added CompletableFuture method to SonarLintRPCClient
– SL Intellij –
Implemented the method on SonarLintIntellijClient
Main Question: From the SL CORE → How can i interact with this newly created method to the RPC and obtain this information?
I’ve looked through the other services implemented on the backend (files / issues / hotspots) and i can’t understand how the information is sent or requested through RPC since there is no reference to that methods
Unfortunately we don’t have any documentation for that. We rely on the LSP4J library, you can find some very basic docs in their documentation folder.
Usually, backend services that need to request something from the client get a SonarLintRpcClient instance via constructor injection. For this to work, the service needs to be registered in the Spring context, in SonarLintSpringAppConfig. A similar use case as yours can be found in this class.
Do not hesitate to ask further questions, @Felipe_Lucas_Otero; it’s always appreciated! Also, if you enjoy using SonarQube for IDE, feel free to leave a review on our marketplace page. Thank you!
@nicolas.quinquenel@Damien_Urruty Thanks to both for your help. I’ve finally been able to send and receive information between SLCORE and JetBrains plugin.
I’ll leave all changes that needs to be made in order to achieve this in case someone comes looking for the same thing in the future.
Backend → Core: SonarLintSpringAppConfig: If you need to add a service to be managed by Spring
SonarLintRPCClientDelegate: Add definition of method that will be implemented on JetBrains plugin GetProjectInformationResponse getProjectInformation();
SonarLintRPCClientImpl: Async Request to Delegate to obtain the information from Plugin
@Override
public CompletableFuture<GetProjectInformationResponse> getProjectInformation() {
return requestAsync(cancelChecker -> delegate.getProjectInformation());
}
With all this modifications to SLCORE, whenever you build and import it on SL JetBrains, you will need to implement your new method on SonarLintIntellijClient