I'm developing a plugin to SonarQube in order to import rules from a .xml file. So far this is done and they really are imported into the SonarQube instance and shown under "Rules". Although the Quality Profile is being created, all the imported rules aren't being added to it and I can't understand why.
I don't want to add them one by one by hand; I'm looking for a way to add them directly to the created profile once they are imported from the .xml file.
The profile is simply created with:
public class MyProfile extends ProfileDefinition {
@Override
public RulesProfile createProfile(ValidationMessages validation) {
return RulesProfile.create("QP", "Java");
}
}
Here is some code of the methods that I suspect would make that happen:
public class MyRules extends RulesDefinition {
public void define(Context context) {
List<RulePack> rulePacks = this.rulePackParser.parse();
parseXml(context);
parseRulePacks(context, rulePacks);
for (NewRepository newRepository : newRepositories.values()) {
newRepository.done();
}
}
private void parseXml(Context context) {
for (Language supportedLanguage : languages.all()) {
InputStream rulesXml = this.getClass().getResourceAsStream("/rules-TESTE.xml");
if (rulesXml != null) {
NewRepository repository = getRepository(context, supportedLanguage.getKey());
xmlLoader.load(repository, new BufferedReader(new InputStreamReader(rulesXml)));
repository.done();
}
}
}
private void parseRulePacks(Context context, List<RulePack> rulePacks) {
for (RulePack rulePack : rulePacks) {
for (AppScanRule rule : rulePack.getRules()) {
String sqLanguageKey = convertToSQ(rulePack.getRuleLanguage(rule));
if (this.languages.get(sqLanguageKey) != null && isAnInterestingRule(rule)) {
processRule(context, rulePack, rule, sqLanguageKey);
}
}
}
}
}
Thanks in advance.
Edit note: the described procedure for actually add the rules to the quality profile can be considered as a workaround because at the time there was an open issue at SonarQube's engine that didn't allow to access all rules at once in order to easily add to the desired quality profile (this issue can be viewed here). So to versions from 5.6 it can be done like this:
- Have yourself implemented a class extending ProfileDefinition;
- Override the method
public RulesProfile createProfile(ValidationMessages messages)
and create the profile object RulesProfile profile = RulesProfile.create();
- On that method, get all rules by
Collection<Rule> rules = ruleFinder.findAll(RuleQuery.create().withRepositoryKey(key-of-the-repository-with-the-desired-rules));
(findAll is the method that was broken)
Activate the rules on the profile with:
for(Rule rule : rules) {
profile.activateRule(rule, null);
}
Finally it is possible to set some definitions, like the language for the profile or it's name. After that return the newly created profile object:
profile.setLanguage("Java");
profile.setName("My Profile");
return profile;
So I was able to solve this problem but with a very different approach. In order to add the quality profile with my new rules, I used SonarQube's REST Web API docs.sonarqube.org/display/DEV/Web+Service+API. The client that I used for sending/receiving requests to/from the API was Postman. The available commands are also documented in nemo.sonarqube.org.
After some failures I found out that this process appears to have some restrictions of use. To get this working I had to:
First, in the plugin code I gave in the question, I have to load the .XML file containing the rules by using the class RulesDefinitionXmlLoader with the method load like this:
xmlLoader.load(repository, new BufferedReader(newInputStreamReader(rulesXml)));
This process I actually very sweet and you can have your rules loaded very easily. All you have to do is to make sure that the .XML file containing the rules follow this standard template:
<rules>
<rule>
<repositoryKey>java-key</repositoryKey>
<key>1</key>
<internalKey> da-rule-name-1</internalKey>
<name> da-rule-name </name>
<description>da-description </description>
</rule>
</rules>
The main concern here is the repositoryKey as the remaining listed fields are mandatory. You have to make sure that the key used here is the same used to add the quality profile (which I'm going to show next). This key is defined in the class extending RulesDefinition (which most important code I provided in the question) while creating a repository.
If it helps, you can also use a request to the Web API in order to list all the repositories, so you can make sure the key used is the right one:
Create a .XML file like the previous one but with the following information. This is the file that will be used by the REST Web API to create the quality profile:
<profile>
<name>da-profile-name</name>
<language>java</language>
<rules>
<rule>
<repositoryKey>java-key</repositoryKey>
<key>1</key>
<internalKey> da-rule-name-1</internalKey>
<name> da-rule-name </name>
<description>da-description </description>
</rule>
</rules>
</profile>
At last, all you have to do is to send the request to the Web API, using this created second file. To do this you can use Postman like I said (if you have less or none knowledge using REST APIs, like I do) or the command prompt (in this case it is needed to install Curl).
In Postman:
Set request as "Post" and add the URL (assuming SonarQube is in the local machine and listening to default port): http://localhost:9000/api/qualityprofiles/restore
Set "Authorization". Default is "admin"/"admin";
At "Body", set one param with "key" = "backup" and the "value" as a file (select the down arrow) and select the second file created (the one with rules and extra tags for profile).
Send the request and if all goes well you should be able to see in the bottom window the number of successfully imported rules!