This document provides insight into the inner workings on this JetBrains IDE plugin. For a higher-level, end-user documentation you can refer to the extension's online documentation.
The plugin is a single-module project with the following structure:
jetbrains-plugin
- images <-- Assets for documentation
- src
- main
- graphql <-- GraphQL resources: queries, mutations, schema
- java
- icons <-- IntelliJ Platform specific code to retrieve icons
- io.codiga.plugins.jetbrains <-- Plugin sources
- resources
- icons <-- Icon assets
- inspectionDescriptions <-- Resources to provide inspection descriptions in the IDE settings
- META-INF <-- Plugin configuration files
- schema <-- YAML schema for codiga.yml
- test
- data <-- Test data
- java
- resources
To enable the Rosie service in a project, one has to create and configure a codiga.yml
file in the project's root directory.
This is the file in which you can tell Rosie what rulesets you want to use, or ignore in that given project.
Details on what the configuration can hold can be found at Code Analysis for JetBrains.
The plugin incorporates an internal cache (RosieRulesCache
)
of all the rules from the rulesets that are specified in the rulesets property in codiga.yml
,
along with a periodic update mechanism. This caching makes it possible to provide better performance.
The cache is initialized and the periodic update begins when a new project is opened
(see RosieStartupActivity
and RosieRulesCacheUpdateHandler
).
Each project has its own separate project-level cache (as a project-level service), and background thread to update that cache.
The periodic update is executed in every 10 seconds, and updates the cache if either the codiga.yml
file has changed,
or the configured rulesets (or underlying rules) have changed on Codiga Hub.
The cache is updated according to the content of the codiga.yml
file serialized by Jackson into a CodigaYmlConfig
instance.
The backround thread for a specific project is terminated upon the user closing that project.
RosieApiImpl
is responsible for the communication between the plugin and the Rosie service.
It sends information (document text, document language, Rosie rules cached for the given language, etc.) to Rosie, then processes the returned response (code violations, ranges, severities, etc.) and supplies it to the external annotator functionality.
The model objects for serializing the response data can be found in the io.codiga.plugins.jetbrains.model.rosie
package.
Highlighting of the code violations and providing quick fixes for them is implemented via an external annotator called RosieAnnotator
that consumes RosieAnnotation
objects created by RosieApiImpl
from a RosieResponse
.
The RosieAnnotation
objects are then filtered and mapped to RosieAnnotationJetBrains
instances
so that the editor offset values are resolved from Codiga's start/end line and column values, and can be processed by the IDE.
It provides three different quick fixes:
- Fix: <fix description>: applies an actual code fix for the violation. See
RosieAnnotationFix
. - Remove error '<rule name>': disables Codiga code analysis for the line on which the violation occurred. See
DisableRosieAnalysisFix
. - See rule '<rule name>' on the Codiga Hub: opens the related rule on Codiga Hub. See
AnnotationFixOpenBrowser
.
The plugin uses a GraphQL client to send queries and mutations to Codiga.
The queries are used to fetch timestamp-, snippet- and ruleset related data from Codiga, while mutations are used to send metrics to Codiga of the usage of certain functionality, for example when a Rosie fix is applied.
During building the plugin, the GraphQL Apollo client generates Java classes based on the corresponding schema.json
,
which types are used throughout the plugin for integrating with Codiga.
The User-Agent header is sent in order to identify the client application the GraphQL requests are sent from.
It is in the form <product name>/<major>.<minor>
, e.g. IntelliJ IDEA/2022.1
and
is retrieved in UserAgentUtils
.
In general, the fingerprint is a unique string generated when the plugin is installed.
Having a Codiga account registered, using this token, users can access and use to their private rulesets and rules in the IDE.
The configuration is provided in the Codiga specific application-level IDE settings via AppSettingsState
.
In case testing on different environments is necessary, you can use the following endpoints:
Environment | Codiga | Rosie |
---|---|---|
Production | https://api.codiga.io/graphql | https://analysis.codiga.io/analyze |
Staging | https://api-staging.codiga.io/graphql | https://analysis-staging.codiga.io/analyze |
In this plugin, tests are a mix of unit and integration tests.
There is a base test class called TestBase
that is extended by most,
if not all, test classes.
When you do integration testing that needs a project root folder and documents to interact with, override
the getTestDataRelativePath()
in the specific test class, e.g.:
@Override
protected String getTestDataRelativePath() {
return TEST_DATA_BASE_PATH + "/rosiecacheupdater";
}
and create the corresponding folder under src/test/data
, and add documents to it. That folder will act as
if it was an actual project root directory.
Tests can be executed either individually via gutter icons or invoking the Run Tests run configuration (executes gradle test
).
General IntelliJ Platform related testing instructions can be found in their Plugin SDK documentation.
There are predefined Run Configurations that you can use:
- Run Build Plugin to build the plugin
- Run Plugin to run/debug the plugin
See instructions here
./gradlew :downloadApolloSchema --endpoint='https://api.codiga.io/graphql' --schema=schema.json
This downloads the up-to-date schema.json
file into the project root, with what you have to replace the existing schema.json
to
have it updated.
To simply support a new language:
- Add the new language to the set of languages supported by Rosie in
RosieLanguageSupport#SUPPORTED_LANGUAGES
. - Also in
RosieLanguageSupport
, add a mapping between the language enumeration and the Rosie language id (most probably the all lowercase version of the language enum constant), ingetRosieLanguage(LanguageEnumeration)
.
If default ruleset suggestions are also needed for the language, then:
- Add the new language's file extension(s) to
FILE_EXTENSIONS
inCodigaRulesetConfigs
. - Create a new
DEFAULT_<language>_RULESET_CONFIG
with the appropriate content and add it togetDefaultRulesetsForProject()
. - Depending on the language, and the type of support JetBrains has for that language, custom checks may be implemented to see if a certain SDK is configured, so that querying the files in the project can be avoided.
- Make sure to update the GrahpQL
schema.json
. - Create new
ENTITY_CHECKED_*
constants inRosieRuleAstTypes
and map them toElementCheckedEnumeration
constants inelementCheckedToRosieEntityChecked()
.
To enable debug log statements, and see them in the IDE's idea.log
file, you have two options:
Here, just uncomment the runIde { systemProperty("idea.log.debug.categories", "Codiga") }
section.
For this you need to:
- Run the sandbox IDE,
- Open the Help > Diagnostic Tools > Debug Log Settings... dialog,
- Enter Codiga on the first line. Codiga is the logger category to which our loggers are associated.