Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,22 @@
package org.sonar.java.checks.verifier;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.sonar.api.rule.RuleKey;
import org.sonar.plugins.java.api.ProfileRegistrar;

public class TestProfileRegistrarContext implements ProfileRegistrar.RegistrarContext {

public final Set<RuleKey> defaultQualityProfileRules = new HashSet<>();
public final Map<String, Set<RuleKey>> rulesByQualityProfile = new HashMap<>();

@Override
public void registerDefaultQualityProfileRules(Collection<RuleKey> ruleKeys) {
defaultQualityProfileRules.addAll(ruleKeys);
public void registerRules(String qualityProfileName, Collection<RuleKey> ruleKeys) {
rulesByQualityProfile
.computeIfAbsent(qualityProfileName, k -> new HashSet<>())
.addAll(ruleKeys);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ class TestProfileRegistrarContextTest {
void store_registration() {
TestProfileRegistrarContext context = new TestProfileRegistrarContext();
context.registerDefaultQualityProfileRules(List.of(RuleKey.of("java", "S1234")));
assertThat(context.defaultQualityProfileRules).containsExactly(RuleKey.of("java", "S1234"));
context.registerRules("Sonar way", List.of(RuleKey.of("java", "S1235")));
context.registerRules("Sonar agentic AI", List.of(RuleKey.of("java", "S4321")));
assertThat(context.rulesByQualityProfile.get("Sonar way")).containsOnly(RuleKey.of("java", "S1234"), RuleKey.of("java", "S1235"));
assertThat(context.rulesByQualityProfile.get("Sonar agentic AI")).containsExactly(RuleKey.of("java", "S4321"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@
import org.sonarsource.api.sonarlint.SonarLintSide;

/**
* This class can be extended to provide additional rule keys in the builtin default quality profile.
* This class can be extended to provide additional rule keys in builtin quality profiles.
*
* <pre>
* {@code
* public void register(RegistrarContext registrarContext) {
* registrarContext.registerDefaultQualityProfileRules(ruleKeys);
* registrarContext.registerRules("Sonar agentic AI", ruleKeys);
* }
* }
* </pre>
Expand All @@ -46,16 +47,27 @@
public interface ProfileRegistrar {

/**
* This method is called on server side and during an analysis to modify the builtin default quality profile for java.
* This method is called on server side and during an analysis to modify builtin quality profiles for Java.
*/
void register(RegistrarContext registrarContext);

interface RegistrarContext {

/**
* Registers additional rules into the "Sonar Way" default quality profile for the language "java".
* Registers additional rules into the "Sonar way" default quality profile for the language "java".
*/
void registerDefaultQualityProfileRules(Collection<RuleKey> ruleKeys);
default void registerDefaultQualityProfileRules(Collection<RuleKey> ruleKeys) {
registerRules("Sonar way", ruleKeys);
}

/**
* Registers additional rules into a builtin quality profile for the language "java".
*
* <p>
* The profile name is expected to match the profile string coming from RSPEC metadata ({@code defaultQualityProfiles}).
* </p>
*/
void registerRules(String qualityProfileName, Collection<RuleKey> ruleKeys);

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ abstract class BuiltInJavaQualityProfile implements BuiltInQualityProfilesDefini
static final String GET_REPOSITORY_KEY = "getRepositoryKey";
static final String SECURITY_REPOSITORY_KEY = "javasecurity";
static final String DBD_REPOSITORY_KEY = "javabugs";
static final String SONAR_WAY_PROFILE = "Sonar way";
static final String SONAR_AGENTIC_PROFILE = "Sonar agentic AI";

private static final Set<String> BUILTIN_PROFILES = Set.of(SONAR_WAY_PROFILE, SONAR_AGENTIC_PROFILE);

protected final ProfileRegistrar[] profileRegistrars;

Expand Down Expand Up @@ -83,11 +86,17 @@ public void define(Context context) {
profile.done();
}

static Set<RuleKey> registerRulesFromJson(String pathToJsonProfile, @Nullable ProfileRegistrar[] profileRegistrars) {
Set<RuleKey> registerRulesFromJson(String pathToJsonProfile, @Nullable ProfileRegistrar[] profileRegistrars) {
Set<RuleKey> ruleKeys = new HashSet<>(loadRuleKeys(pathToJsonProfile));
if (profileRegistrars != null) {
for (ProfileRegistrar profileRegistrar : profileRegistrars) {
profileRegistrar.register(ruleKeys::addAll);
profileRegistrar.register((qualityProfileName, registrarRuleKeys) -> {
if (qualityProfileName.equals(getProfileName())) {
ruleKeys.addAll(registrarRuleKeys);
} else if (!BUILTIN_PROFILES.contains(qualityProfileName)) {
LOG.debug("No builtin quality profile called '{}' was found: skipping rules registration.", qualityProfileName);
}
});
Comment thread
gitar-bot[bot] marked this conversation as resolved.
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@

@SonarLintSide
public class JavaAgenticAIProfile extends BuiltInJavaQualityProfile {
static final String PROFILE_NAME = "Sonar agentic AI";
static final String PROFILE_NAME = SONAR_AGENTIC_PROFILE;
static final String SONAR_AGENTIC_PATH = "/org/sonar/l10n/java/rules/java/Sonar_agentic_AI_profile.json";

public JavaAgenticAIProfile() {
this(null);
Expand All @@ -39,7 +40,7 @@ String getProfileName() {

@Override
String getPathToJsonProfile() {
return "/org/sonar/l10n/java/rules/java/Sonar_agentic_AI_profile.json";
return SONAR_AGENTIC_PATH;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
*/
@SonarLintSide
public class JavaSonarWayProfile extends BuiltInJavaQualityProfile {
static final String PROFILE_NAME = SONAR_WAY_PROFILE;
static final String SONAR_WAY_PATH = "/org/sonar/l10n/java/rules/java/Sonar_way_profile.json";

/**
Expand All @@ -42,7 +43,7 @@ public JavaSonarWayProfile(@Nullable ProfileRegistrar[] profileRegistrars) {

@Override
String getProfileName() {
return "Sonar way";
return PROFILE_NAME;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
import org.sonar.plugins.java.api.ProfileRegistrar;

import static org.assertj.core.api.Assertions.assertThat;

Expand All @@ -42,7 +44,12 @@ class JavaAgenticWayProfileTest {

@Test
void profile_is_registered_as_expected() {
JavaAgenticAIProfile profile = new JavaAgenticAIProfile();
ProfileRegistrar agenticCustomRules = registrarContext ->
registrarContext.registerRules("Sonar agentic AI", List.of(RuleKey.of("java", "S1107")));
ProfileRegistrar sonarWayCustomRules = registrarContext ->
registrarContext.registerDefaultQualityProfileRules(List.of(RuleKey.of("java", "S1108")));

JavaAgenticAIProfile profile = new JavaAgenticAIProfile(new ProfileRegistrar[]{agenticCustomRules, sonarWayCustomRules});
BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
profile.define(context);

Expand All @@ -53,7 +60,7 @@ void profile_is_registered_as_expected() {
BuiltInQualityProfilesDefinition.BuiltInQualityProfile actualProfile = profilesPerLanguages.get("java").get("Sonar agentic AI");
assertThat(actualProfile.isDefault()).isFalse();
assertThat(actualProfile.rules())
.hasSize(465)
.hasSize(466)
.extracting(BuiltInQualityProfilesDefinition.BuiltInActiveRule::ruleKey)
.doesNotContainAnyElementsOf(List.of(
"S101",
Expand Down Expand Up @@ -113,6 +120,7 @@ void profile_is_registered_as_expected() {
"S6242",
"S6244",
"S6246",
"S1108",
"S6548",
"S6804",
"S6813",
Expand All @@ -125,7 +133,10 @@ void profile_is_registered_as_expected() {
"S8491",
"S8692",
"S8714"
));
))
.contains(
"S1107"
);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,14 @@ void should_create_sonar_way_profile() {
RuleKey.of("javasecurity", "S6287")));
ProfileRegistrar barCustomRules = registrarContext -> registrarContext.registerDefaultQualityProfileRules(List.of(
RuleKey.of("javabugs", "S6466")));
ProfileRegistrar bazCustomRules = registrarContext ->
registrarContext.registerRules("Sonar agentic AI", List.of(RuleKey.of("java", "S1107")));

JavaSonarWayProfile profileDef = new JavaSonarWayProfile(new ProfileRegistrar[] {
fooCustomRules,
barCustomRules});
barCustomRules,
bazCustomRules
});
BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
profileDef.define(context);
BuiltInQualityProfilesDefinition.BuiltInQualityProfile profile = context.profile("java", "Sonar way");
Expand All @@ -72,7 +76,8 @@ void should_create_sonar_way_profile() {
.doesNotContain(RuleKey.of("java", "S00116"))
.contains(RuleKey.of("java", "S116"))
.doesNotContain(RuleKey.of("java", "S6549"))
.doesNotContain(RuleKey.of("javasecurity", "S116"))
.doesNotContain(RuleKey.of("java", "S1107"))
.doesNotContain(RuleKey.of("javabugs", "S116"))
.contains(RuleKey.of("javasecurity", "S6549"))
.contains(RuleKey.of("javasecurity", "S6287"))
.contains(RuleKey.of("javabugs", "S6466"));
Expand Down
Loading