Skip to content

Commit 6656768

Browse files
Extend the ProfileRegistrar interface to register rules for specific quality profiles
1 parent 5f084ca commit 6656768

8 files changed

Lines changed: 64 additions & 18 deletions

File tree

java-checks-testkit/src/main/java/org/sonar/java/checks/verifier/TestProfileRegistrarContext.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,22 @@
1717
package org.sonar.java.checks.verifier;
1818

1919
import java.util.Collection;
20+
import java.util.HashMap;
2021
import java.util.HashSet;
22+
import java.util.Map;
2123
import java.util.Set;
2224
import org.sonar.api.rule.RuleKey;
2325
import org.sonar.plugins.java.api.ProfileRegistrar;
2426

2527
public class TestProfileRegistrarContext implements ProfileRegistrar.RegistrarContext {
2628

27-
public final Set<RuleKey> defaultQualityProfileRules = new HashSet<>();
29+
public final Map<String, Set<RuleKey>> rulesByQualityProfile = new HashMap<>();
2830

2931
@Override
30-
public void registerDefaultQualityProfileRules(Collection<RuleKey> ruleKeys) {
31-
defaultQualityProfileRules.addAll(ruleKeys);
32+
public void registerRules(String qualityProfileName, Collection<RuleKey> ruleKeys) {
33+
rulesByQualityProfile
34+
.computeIfAbsent(qualityProfileName, k -> new HashSet<>())
35+
.addAll(ruleKeys);
3236
}
3337

3438
}

java-checks-testkit/src/test/java/org/sonar/java/checks/verifier/TestProfileRegistrarContextTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ class TestProfileRegistrarContextTest {
2828
void store_registration() {
2929
TestProfileRegistrarContext context = new TestProfileRegistrarContext();
3030
context.registerDefaultQualityProfileRules(List.of(RuleKey.of("java", "S1234")));
31-
assertThat(context.defaultQualityProfileRules).containsExactly(RuleKey.of("java", "S1234"));
31+
context.registerRules("Sonar way", List.of(RuleKey.of("java", "S1235")));
32+
context.registerRules("Sonar agentic AI", List.of(RuleKey.of("java", "S4321")));
33+
assertThat(context.rulesByQualityProfile.get("Sonar way")).containsOnly(RuleKey.of("java", "S1234"), RuleKey.of("java", "S1235"));
34+
assertThat(context.rulesByQualityProfile.get("Sonar agentic AI")).containsExactly(RuleKey.of("java", "S4321"));
3235
}
3336

3437
}

java-frontend/src/main/java/org/sonar/plugins/java/api/ProfileRegistrar.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,13 @@
2323
import org.sonarsource.api.sonarlint.SonarLintSide;
2424

2525
/**
26-
* This class can be extended to provide additional rule keys in the builtin default quality profile.
26+
* This class can be extended to provide additional rule keys in builtin quality profiles.
2727
*
2828
* <pre>
2929
* {@code
3030
* public void register(RegistrarContext registrarContext) {
3131
* registrarContext.registerDefaultQualityProfileRules(ruleKeys);
32+
* registrarContext.registerRules("Sonar agentic AI", ruleKeys);
3233
* }
3334
* }
3435
* </pre>
@@ -46,16 +47,27 @@
4647
public interface ProfileRegistrar {
4748

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

5354
interface RegistrarContext {
5455

5556
/**
56-
* Registers additional rules into the "Sonar Way" default quality profile for the language "java".
57+
* Registers additional rules into the "Sonar way" default quality profile for the language "java".
5758
*/
58-
void registerDefaultQualityProfileRules(Collection<RuleKey> ruleKeys);
59+
default void registerDefaultQualityProfileRules(Collection<RuleKey> ruleKeys) {
60+
registerRules("Sonar way", ruleKeys);
61+
}
62+
63+
/**
64+
* Registers additional rules into a builtin quality profile for the language "java".
65+
*
66+
* <p>
67+
* The profile name is expected to match the profile string coming from RSPEC metadata ({@code defaultQualityProfiles}).
68+
* </p>
69+
*/
70+
void registerRules(String qualityProfileName, Collection<RuleKey> ruleKeys);
5971

6072
}
6173

sonar-java-plugin/src/main/java/org/sonar/plugins/java/BuiltInJavaQualityProfile.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ abstract class BuiltInJavaQualityProfile implements BuiltInQualityProfilesDefini
4545
static final String GET_REPOSITORY_KEY = "getRepositoryKey";
4646
static final String SECURITY_REPOSITORY_KEY = "javasecurity";
4747
static final String DBD_REPOSITORY_KEY = "javabugs";
48+
static final String SONAR_WAY_PROFILE = "Sonar way";
49+
static final String SONAR_AGENTIC_PROFILE = "Sonar agentic AI";
4850

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

5053
protected final ProfileRegistrar[] profileRegistrars;
5154

@@ -83,11 +86,17 @@ public void define(Context context) {
8386
profile.done();
8487
}
8588

86-
static Set<RuleKey> registerRulesFromJson(String pathToJsonProfile, @Nullable ProfileRegistrar[] profileRegistrars) {
89+
Set<RuleKey> registerRulesFromJson(String pathToJsonProfile, @Nullable ProfileRegistrar[] profileRegistrars) {
8790
Set<RuleKey> ruleKeys = new HashSet<>(loadRuleKeys(pathToJsonProfile));
8891
if (profileRegistrars != null) {
8992
for (ProfileRegistrar profileRegistrar : profileRegistrars) {
90-
profileRegistrar.register(ruleKeys::addAll);
93+
profileRegistrar.register((qualityProfileName, registrarRuleKeys) -> {
94+
if (qualityProfileName.equals(getProfileName())) {
95+
ruleKeys.addAll(registrarRuleKeys);
96+
} else if (!BUILTIN_PROFILES.contains(qualityProfileName)) {
97+
LOG.debug("No builtin quality profile called '{}' was found: skipping rules registration.", qualityProfileName);
98+
}
99+
});
91100
}
92101
}
93102

sonar-java-plugin/src/main/java/org/sonar/plugins/java/JavaAgenticAIProfile.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222

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

2728
public JavaAgenticAIProfile() {
2829
this(null);
@@ -39,7 +40,7 @@ String getProfileName() {
3940

4041
@Override
4142
String getPathToJsonProfile() {
42-
return "/org/sonar/l10n/java/rules/java/Sonar_agentic_AI_profile.json";
43+
return SONAR_AGENTIC_PATH;
4344
}
4445

4546
@Override

sonar-java-plugin/src/main/java/org/sonar/plugins/java/JavaSonarWayProfile.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
*/
2828
@SonarLintSide
2929
public class JavaSonarWayProfile extends BuiltInJavaQualityProfile {
30+
static final String PROFILE_NAME = SONAR_WAY_PROFILE;
3031
static final String SONAR_WAY_PATH = "/org/sonar/l10n/java/rules/java/Sonar_way_profile.json";
3132

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

4344
@Override
4445
String getProfileName() {
45-
return "Sonar way";
46+
return PROFILE_NAME;
4647
}
4748

4849
@Override

sonar-java-plugin/src/test/java/org/sonar/plugins/java/JavaAgenticWayProfileTest.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@
3232
import org.junit.jupiter.api.Assertions;
3333
import org.junit.jupiter.api.Disabled;
3434
import org.junit.jupiter.api.Test;
35+
import org.sonar.api.rule.RuleKey;
3536
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
37+
import org.sonar.plugins.java.api.ProfileRegistrar;
3638

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

@@ -42,7 +44,12 @@ class JavaAgenticWayProfileTest {
4244

4345
@Test
4446
void profile_is_registered_as_expected() {
45-
JavaAgenticAIProfile profile = new JavaAgenticAIProfile();
47+
ProfileRegistrar agenticCustomRules = registrarContext ->
48+
registrarContext.registerRules("Sonar agentic AI", List.of(RuleKey.of("java", "S1107")));
49+
ProfileRegistrar sonarWayCustomRules = registrarContext ->
50+
registrarContext.registerDefaultQualityProfileRules(List.of(RuleKey.of("java", "S1108")));
51+
52+
JavaAgenticAIProfile profile = new JavaAgenticAIProfile(new ProfileRegistrar[]{agenticCustomRules, sonarWayCustomRules});
4653
BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
4754
profile.define(context);
4855

@@ -53,7 +60,7 @@ void profile_is_registered_as_expected() {
5360
BuiltInQualityProfilesDefinition.BuiltInQualityProfile actualProfile = profilesPerLanguages.get("java").get("Sonar agentic AI");
5461
assertThat(actualProfile.isDefault()).isFalse();
5562
assertThat(actualProfile.rules())
56-
.hasSize(465)
63+
.hasSize(466)
5764
.extracting(BuiltInQualityProfilesDefinition.BuiltInActiveRule::ruleKey)
5865
.doesNotContainAnyElementsOf(List.of(
5966
"S101",
@@ -113,6 +120,7 @@ void profile_is_registered_as_expected() {
113120
"S6242",
114121
"S6244",
115122
"S6246",
123+
"S1108",
116124
"S6548",
117125
"S6804",
118126
"S6813",
@@ -125,7 +133,10 @@ void profile_is_registered_as_expected() {
125133
"S8491",
126134
"S8692",
127135
"S8714"
128-
));
136+
))
137+
.contains(
138+
"S1107"
139+
);
129140
}
130141

131142

sonar-java-plugin/src/test/java/org/sonar/plugins/java/JavaSonarWayProfileTest.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,14 @@ void should_create_sonar_way_profile() {
5050
RuleKey.of("javasecurity", "S6287")));
5151
ProfileRegistrar barCustomRules = registrarContext -> registrarContext.registerDefaultQualityProfileRules(List.of(
5252
RuleKey.of("javabugs", "S6466")));
53+
ProfileRegistrar bazCustomRules = registrarContext ->
54+
registrarContext.registerRules("Sonar agentic AI", List.of(RuleKey.of("java", "S1107")));
5355

5456
JavaSonarWayProfile profileDef = new JavaSonarWayProfile(new ProfileRegistrar[] {
5557
fooCustomRules,
56-
barCustomRules});
58+
barCustomRules,
59+
bazCustomRules
60+
});
5761
BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
5862
profileDef.define(context);
5963
BuiltInQualityProfilesDefinition.BuiltInQualityProfile profile = context.profile("java", "Sonar way");
@@ -72,7 +76,8 @@ void should_create_sonar_way_profile() {
7276
.doesNotContain(RuleKey.of("java", "S00116"))
7377
.contains(RuleKey.of("java", "S116"))
7478
.doesNotContain(RuleKey.of("java", "S6549"))
75-
.doesNotContain(RuleKey.of("javasecurity", "S116"))
79+
.doesNotContain(RuleKey.of("java", "S1107"))
80+
.doesNotContain(RuleKey.of("javabugs", "S116"))
7681
.contains(RuleKey.of("javasecurity", "S6549"))
7782
.contains(RuleKey.of("javasecurity", "S6287"))
7883
.contains(RuleKey.of("javabugs", "S6466"));

0 commit comments

Comments
 (0)