Browse Source

SONAR-20198 - add clean code fields in rules endpoints

tags/10.2.0.77647
Benjamin Campomenosi 9 months ago
parent
commit
04fc6db186
16 changed files with 347 additions and 153 deletions
  1. 3
    0
      server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleIndex.java
  2. 39
    24
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/CreateActionIT.java
  3. 28
    9
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/SearchActionIT.java
  4. 19
    3
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/ShowActionIT.java
  5. 24
    0
      server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/UpdateActionIT.java
  6. 3
    1
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/CreateAction.java
  7. 24
    0
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleMapper.java
  8. 2
    1
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RulesWsParameters.java
  9. 13
    2
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/SearchAction.java
  10. 2
    2
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/ShowAction.java
  11. 3
    0
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/UpdateAction.java
  12. 32
    24
      server/sonar-webserver-webapi/src/main/resources/org/sonar/server/rule/ws/create-example.json
  13. 45
    8
      server/sonar-webserver-webapi/src/main/resources/org/sonar/server/rule/ws/search-example.json
  14. 59
    46
      server/sonar-webserver-webapi/src/main/resources/org/sonar/server/rule/ws/show-example.json
  15. 34
    25
      server/sonar-webserver-webapi/src/main/resources/org/sonar/server/rule/ws/update-example.json
  16. 17
    8
      sonar-ws/src/main/protobuf/ws-rules.proto

+ 3
- 0
server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleIndex.java View File

public static final String FACET_OWASP_TOP_10 = "owaspTop10"; public static final String FACET_OWASP_TOP_10 = "owaspTop10";
public static final String FACET_OWASP_TOP_10_2021 = "owaspTop10-2021"; public static final String FACET_OWASP_TOP_10_2021 = "owaspTop10-2021";
public static final String FACET_SONARSOURCE_SECURITY = "sonarsourceSecurity"; public static final String FACET_SONARSOURCE_SECURITY = "sonarsourceSecurity";
public static final String FACET_CLEAN_CODE_ATTRIBUTE_CATEGORY = "cleanCodeAttributeCategories";
public static final String FACET_IMPACT_SOFTWARE_QUALITY = "impactSoftwareQualities";
public static final String FACET_IMPACT_SEVERITY = "impactSeverities";


private static final int MAX_FACET_SIZE = 100; private static final int MAX_FACET_SIZE = 100;



+ 39
- 24
server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/CreateActionIT.java View File

.setParam("params", "regex=a.*") .setParam("params", "regex=a.*")
.execute().getInput(); .execute().getInput();


assertJson(result).isSimilarTo("{\n" +
" \"rule\": {\n" +
" \"key\": \"java:MY_CUSTOM\",\n" +
" \"repo\": \"java\",\n" +
" \"name\": \"My custom rule\",\n" +
" \"htmlDesc\": \"Description\",\n" +
" \"severity\": \"MAJOR\",\n" +
" \"status\": \"BETA\",\n" +
" \"type\": \"BUG\",\n" +
" \"internalKey\": \"configKey_S001\",\n" +
" \"isTemplate\": false,\n" +
" \"templateKey\": \"java:S001\",\n" +
" \"sysTags\": [\"systag1\", \"systag2\"],\n" +
" \"lang\": \"js\",\n" +
" \"params\": [\n" +
" {\n" +
" \"key\": \"regex\",\n" +
" \"htmlDesc\": \"Reg ex\",\n" +
" \"defaultValue\": \"a.*\",\n" +
" \"type\": \"STRING\"\n" +
" }\n" +
" ]\n" +
" }\n" +
"}\n");
String expetedResult = """
{
"rule": {
"key": "java:MY_CUSTOM",
"repo": "java",
"name": "My custom rule",
"htmlDesc": "Description",
"severity": "MAJOR",
"status": "BETA",
"type": "BUG",
"internalKey": "configKey_S001",
"isTemplate": false,
"templateKey": "java:S001",
"sysTags": [
"systag1",
"systag2"
],
"lang": "js",
"params": [
{
"key": "regex",
"htmlDesc": "Reg ex",
"defaultValue": "a.*",
"type": "STRING"
}
],
"cleanCodeAttribute": "CONVENTIONAL",
"cleanCodeAttributeCategory": "CONSISTENT",
"impacts": [
{
"softwareQuality": "RELIABILITY",
"severity": "MEDIUM"
}
]
}
}
""";

assertJson(result).isSimilarTo(expetedResult);
} }


@Test @Test

+ 28
- 9
server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/SearchActionIT.java View File

import static org.sonar.db.rule.RuleTesting.newRuleWithoutDescriptionSection; import static org.sonar.db.rule.RuleTesting.newRuleWithoutDescriptionSection;
import static org.sonar.db.rule.RuleTesting.setSystemTags; import static org.sonar.db.rule.RuleTesting.setSystemTags;
import static org.sonar.db.rule.RuleTesting.setTags; import static org.sonar.db.rule.RuleTesting.setTags;
import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_CLEAN_CODE_ATTRIBUTE;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ACTIVATION; import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ACTIVATION;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_COMPARE_TO_PROFILE; import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_COMPARE_TO_PROFILE;
import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_QPROFILE; import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_QPROFILE;
r -> r.setName("Name"), r -> r.setName("Name"),
r -> r.setRepositoryKey("repo_key"), r -> r.setRepositoryKey("repo_key"),
r -> r.setSeverity("MINOR"), r -> r.setSeverity("MINOR"),
r -> r.setLanguage("java")
);
r -> r.setLanguage("java"));
indexRules(); indexRules();


Rules.SearchResponse response = ws.newRequest().executeProtobuf(Rules.SearchResponse.class); Rules.SearchResponse response = ws.newRequest().executeProtobuf(Rules.SearchResponse.class);
.containsExactly(rule.getTags().toArray(new String[0])); .containsExactly(rule.getTags().toArray(new String[0]));
} }


@Test
public void returnRuleCleanCodeFields_whenEndpointIsCalled() {
RuleDto rule = db.rules()
.insert();
indexRules();

SearchResponse result = ws.newRequest()
.setParam(WebService.Param.FIELDS, FIELD_CLEAN_CODE_ATTRIBUTE)
.executeProtobuf(SearchResponse.class);

// mandatory fields
assertThat(result.getRulesList())
.extracting(r -> r.getImpacts().getImpactsList().stream().findFirst().orElseThrow(() -> new IllegalStateException("Impact is a mandatory field in the response.")))
.extracting(Common.Impact::getSoftwareQuality, Common.Impact::getSeverity)
.containsExactly(tuple(Common.SoftwareQuality.MAINTAINABILITY, Common.ImpactSeverity.HIGH));

// selected fields
assertThat(result.getRulesList()).extracting(Rule::getCleanCodeAttribute).containsExactly(Common.CleanCodeAttribute.CLEAR);
assertThat(result.getRulesList()).extracting(Rule::getCleanCodeAttributeCategory).containsExactly(Common.CleanCodeAttributeCategory.INTENTIONAL);
}

@Test @Test
public void should_return_specified_fields() { public void should_return_specified_fields() {
when(macroInterpreter.interpret(anyString())).thenAnswer(invocation -> invocation.getArgument(0)); when(macroInterpreter.interpret(anyString())).thenAnswer(invocation -> invocation.getArgument(0));
checkField(rule, "gapDescription", Rule::getGapDescription, rule.getGapDescription()); checkField(rule, "gapDescription", Rule::getGapDescription, rule.getGapDescription());
checkDescriptionSections(rule, rule.getRuleDescriptionSectionDtos().stream() checkDescriptionSections(rule, rule.getRuleDescriptionSectionDtos().stream()
.map(SearchActionIT::toProtobufDto) .map(SearchActionIT::toProtobufDto)
.collect(Collectors.toSet())
);
.collect(Collectors.toSet()));
} }


private RuleDescriptionSectionDto createRuleDescriptionSectionWithContext(String key, String content, @Nullable String contextKey) { private RuleDescriptionSectionDto createRuleDescriptionSectionWithContext(String key, String content, @Nullable String contextKey) {
indexRules(); indexRules();


ws.newRequest() ws.newRequest()
.setParam(WebService.Param.PAGE, "2")
.setParam(WebService.Param.PAGE_SIZE, "9")
.execute()
.assertJson(this.getClass(), "paging.json");
.setParam(WebService.Param.PAGE, "2")
.setParam(WebService.Param.PAGE_SIZE, "9")
.execute()
.assertJson(this.getClass(), "paging.json");
} }


@Test @Test
assertThat(actualSections).hasSameElementsAs(expected); assertThat(actualSections).hasSameElementsAs(expected);
} }



private void verifyNoResults(Consumer<TestRequest> requestPopulator) { private void verifyNoResults(Consumer<TestRequest> requestPopulator) {
verify(requestPopulator); verify(requestPopulator);
} }

+ 19
- 3
server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/ShowActionIT.java View File

assertThat(resultRule.getParams().getParamsList()) assertThat(resultRule.getParams().getParamsList())
.extracting(Rule.Param::getKey, Rule.Param::getHtmlDesc, Rule.Param::getDefaultValue) .extracting(Rule.Param::getKey, Rule.Param::getHtmlDesc, Rule.Param::getDefaultValue)
.containsExactlyInAnyOrder(tuple(ruleParam.getName(), ruleParam.getDescription(), ruleParam.getDefaultValue())); .containsExactlyInAnyOrder(tuple(ruleParam.getName(), ruleParam.getDescription(), ruleParam.getDefaultValue()));
assertThat(resultRule.getImpacts().getImpactsList())
.extracting(Common.Impact::getSoftwareQuality, Common.Impact::getSeverity)
.containsExactly(tuple(Common.SoftwareQuality.MAINTAINABILITY, Common.ImpactSeverity.HIGH));

assertThat(resultRule.getEducationPrinciples().getEducationPrinciplesList()).containsExactlyElementsOf(rule.getEducationPrinciples()); assertThat(resultRule.getEducationPrinciples().getEducationPrinciplesList()).containsExactlyElementsOf(rule.getEducationPrinciples());
} }


.containsExactly(rule.getTags().toArray(new String[0])); .containsExactly(rule.getTags().toArray(new String[0]));
} }


//<test case name>_when<conditionInCamelCase>_should<assertionInCamelCase>
@Test
public void returnRuleCleanCodeFields_whenEndpointIsCalled() {
RuleDto rule = db.rules().insert(setTags("tag1", "tag2"), r -> r.setNoteData(null).setNoteUserUuid(null));

ShowResponse result = ws.newRequest()
.setParam(PARAM_KEY, rule.getKey().toString())
.executeProtobuf(ShowResponse.class);

assertThat(result.getRule().getCleanCodeAttribute()).isEqualTo(Common.CleanCodeAttribute.CLEAR);
assertThat(result.getRule().getCleanCodeAttributeCategory()).isEqualTo(Common.CleanCodeAttributeCategory.INTENTIONAL);
}

@Test @Test
public void show_rule_with_note_login() { public void show_rule_with_note_login() {
UserDto user = db.users().insertUser(); UserDto user = db.users().insertUser();


@Test @Test
public void show_adhoc_rule() { public void show_adhoc_rule() {
//Ad-hoc description has no description sections defined
// Ad-hoc description has no description sections defined
RuleDto externalRule = db.rules().insert(newRuleWithoutDescriptionSection() RuleDto externalRule = db.rules().insert(newRuleWithoutDescriptionSection()
.setIsExternal(true) .setIsExternal(true)
.setIsAdHoc(true) .setIsAdHoc(true)
tuple(ASSESS_THE_PROBLEM_SECTION_KEY, "<div>This is not a problem</div>", "", ""), tuple(ASSESS_THE_PROBLEM_SECTION_KEY, "<div>This is not a problem</div>", "", ""),
tuple(HOW_TO_FIX_SECTION_KEY, "<div>I don't want to fix</div>", "", ""), tuple(HOW_TO_FIX_SECTION_KEY, "<div>I don't want to fix</div>", "", ""),
tuple(RESOURCES_SECTION_KEY, "<div>I want to fix with Spring</div>", section4context1.getContext().getKey(), section4context1.getContext().getDisplayName()), tuple(RESOURCES_SECTION_KEY, "<div>I want to fix with Spring</div>", section4context1.getContext().getKey(), section4context1.getContext().getDisplayName()),
tuple(RESOURCES_SECTION_KEY, "<div>I want to fix with Servlet</div>", section4context2.getContext().getKey(), section4context2.getContext().getDisplayName())
);
tuple(RESOURCES_SECTION_KEY, "<div>I want to fix with Servlet</div>", section4context2.getContext().getKey(), section4context2.getContext().getDisplayName()));
} }


@Test @Test

+ 24
- 0
server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/UpdateActionIT.java View File

import org.sonar.server.ws.TestResponse; import org.sonar.server.ws.TestResponse;
import org.sonar.server.ws.WsAction; import org.sonar.server.ws.WsAction;
import org.sonar.server.ws.WsActionTester; import org.sonar.server.ws.WsActionTester;
import org.sonarqube.ws.Common;
import org.sonarqube.ws.Rules; import org.sonarqube.ws.Rules;


import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
.isInstanceOf(UnauthorizedException.class); .isInstanceOf(UnauthorizedException.class);
} }


@Test
public void returnRuleCleanCodeFields_whenEndpointIsCalled() {
UserDto userAuthenticated = db.users().insertUser();
userSession.logIn(userAuthenticated).addPermission(ADMINISTER_QUALITY_PROFILES);

RuleDto rule = db.rules()
.insert();

Rules.UpdateResponse updateResponse = ws.newRequest().setMethod("POST")
.setParam("key", rule.getKey().toString())
.executeProtobuf(Rules.UpdateResponse.class);

// mandatory fields
assertThat(updateResponse.getRule())
.extracting(r -> r.getImpacts().getImpactsList().stream().findFirst().orElseThrow(() -> new IllegalStateException("Impact is a mandatory field in the response.")))
.extracting(Common.Impact::getSoftwareQuality, Common.Impact::getSeverity)
.containsExactly(Common.SoftwareQuality.MAINTAINABILITY, Common.ImpactSeverity.HIGH);

// selected fields
assertThat(updateResponse.getRule()).extracting(Rules.Rule::getCleanCodeAttribute).isEqualTo(Common.CleanCodeAttribute.CLEAR);
assertThat(updateResponse.getRule()).extracting(Rules.Rule::getCleanCodeAttributeCategory).isEqualTo(Common.CleanCodeAttributeCategory.INTENTIONAL);
}

private void logInAsQProfileAdministrator() { private void logInAsQProfileAdministrator() {
userSession userSession
.logIn() .logIn()

+ 3
- 1
server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/CreateAction.java View File

.setResponseExample(Resources.getResource(getClass(), "create-example.json")) .setResponseExample(Resources.getResource(getClass(), "create-example.json"))
.setSince("4.4") .setSince("4.4")
.setChangelog( .setChangelog(
new Change("5.5", "Creating manual rule is not more possible"),
new Change("10.0","Drop deprecated keys: 'custom_key', 'template_key', 'markdown_description', 'prevent_reactivation'"), new Change("10.0","Drop deprecated keys: 'custom_key', 'template_key', 'markdown_description', 'prevent_reactivation'"),
new Change("5.5", "Creating manual rule is not more possible"))
new Change("10.2", "Add 'impacts', 'cleanCodeAttribute', 'cleanCodeAttributeCategory' fields to the response")
)
.setHandler(this); .setHandler(this);


action action

+ 24
- 0
server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleMapper.java View File

import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.debt.DebtRemediationFunction; import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction; import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction;
import org.sonar.db.issue.ImpactDto;
import org.sonar.db.rule.DeprecatedRuleKeyDto; import org.sonar.db.rule.DeprecatedRuleKeyDto;
import org.sonar.db.rule.RuleDescriptionSectionContextDto; import org.sonar.db.rule.RuleDescriptionSectionContextDto;
import org.sonar.db.rule.RuleDescriptionSectionDto; import org.sonar.db.rule.RuleDescriptionSectionDto;


import static org.sonar.api.utils.DateUtils.formatDateTime; import static org.sonar.api.utils.DateUtils.formatDateTime;
import static org.sonar.db.rule.RuleDto.Format.MARKDOWN; import static org.sonar.db.rule.RuleDto.Format.MARKDOWN;
import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_CLEAN_CODE_ATTRIBUTE;
import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_CREATED_AT; import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_CREATED_AT;
import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_DEBT_REM_FUNCTION; import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_DEBT_REM_FUNCTION;
import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_DEFAULT_DEBT_REM_FUNCTION; import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_DEFAULT_DEBT_REM_FUNCTION;
// Mandatory fields // Mandatory fields
ruleResponse.setKey(ruleDto.getKey().toString()); ruleResponse.setKey(ruleDto.getKey().toString());
ruleResponse.setType(Common.RuleType.forNumber(ruleDto.getType())); ruleResponse.setType(Common.RuleType.forNumber(ruleDto.getType()));
setImpacts(ruleResponse, ruleDto);


// Optional fields // Optional fields
setName(ruleResponse, ruleDto, fieldsToReturn); setName(ruleResponse, ruleDto, fieldsToReturn);
setAdHocType(ruleResponse, ruleDto); setAdHocType(ruleResponse, ruleDto);
} }
setEducationPrinciples(ruleResponse, ruleDto, fieldsToReturn); setEducationPrinciples(ruleResponse, ruleDto, fieldsToReturn);
setCleanCodeAttributes(ruleResponse, ruleDto, fieldsToReturn);

return ruleResponse; return ruleResponse;
} }


private static void setImpacts(Rules.Rule.Builder ruleResponse, RuleDto ruleDto) {
Rules.Impacts.Builder impactsBuilder = Rules.Impacts.newBuilder();
ruleDto.getDefaultImpacts().forEach(impactDto -> impactsBuilder.addImpacts(toImpact(impactDto)));
ruleResponse.setImpacts(impactsBuilder.build());
}

private static Common.Impact toImpact(ImpactDto impactDto) {
Common.ImpactSeverity severity = Common.ImpactSeverity.valueOf(impactDto.getSeverity().name());
Common.SoftwareQuality softwareQuality = Common.SoftwareQuality.valueOf(impactDto.getSoftwareQuality().name());
return Common.Impact.newBuilder().setSeverity(severity).setSoftwareQuality(softwareQuality).build();
}

private static void setAdHocName(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) { private static void setAdHocName(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
String adHocName = ruleDto.getAdHocName(); String adHocName = ruleDto.getAdHocName();
if (adHocName != null && shouldReturnField(fieldsToReturn, FIELD_NAME)) { if (adHocName != null && shouldReturnField(fieldsToReturn, FIELD_NAME)) {
} }
} }


private static void setCleanCodeAttributes(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn) {
if(shouldReturnField(fieldsToReturn, FIELD_CLEAN_CODE_ATTRIBUTE)){
ruleResponse.setCleanCodeAttribute(Common.CleanCodeAttribute.valueOf(ruleDto.getCleanCodeAttribute().name()));
ruleResponse.setCleanCodeAttributeCategory(Common.CleanCodeAttributeCategory.valueOf(ruleDto.getCleanCodeAttribute().getAttributeCategory().name()));
}
}

private static void setDeprecatedKeys(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn, private static void setDeprecatedKeys(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Set<String> fieldsToReturn,
Map<String, List<DeprecatedRuleKeyDto>> deprecatedRuleKeysByRuleUuid) { Map<String, List<DeprecatedRuleKeyDto>> deprecatedRuleKeysByRuleUuid) {
if (shouldReturnField(fieldsToReturn, FIELD_DEPRECATED_KEYS)) { if (shouldReturnField(fieldsToReturn, FIELD_DEPRECATED_KEYS)) {

+ 2
- 1
server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RulesWsParameters.java View File

public static final String FIELD_NOTE_LOGIN = "noteLogin"; public static final String FIELD_NOTE_LOGIN = "noteLogin";
public static final String FIELD_MARKDOWN_NOTE = "mdNote"; public static final String FIELD_MARKDOWN_NOTE = "mdNote";
public static final String FIELD_HTML_NOTE = "htmlNote"; public static final String FIELD_HTML_NOTE = "htmlNote";
public static final String FIELD_CLEAN_CODE_ATTRIBUTE = "cleanCodeAttribute";


/** /**
* Value for 'f' parameter which is used to return all the "defaultDebtRemFn" fields. * Value for 'f' parameter which is used to return all the "defaultDebtRemFn" fields.
FIELD_MARKDOWN_DESCRIPTION, FIELD_DESCRIPTION_SECTIONS, FIELD_NOTE_LOGIN, FIELD_MARKDOWN_NOTE, FIELD_HTML_NOTE, FIELD_MARKDOWN_DESCRIPTION, FIELD_DESCRIPTION_SECTIONS, FIELD_NOTE_LOGIN, FIELD_MARKDOWN_NOTE, FIELD_HTML_NOTE,
FIELD_DEFAULT_DEBT_REM_FUNCTION, FIELD_DEBT_REM_FUNCTION, FIELD_DEFAULT_DEBT_REM_FUNCTION, FIELD_DEBT_REM_FUNCTION,
FIELD_DEFAULT_REM_FUNCTION, FIELD_GAP_DESCRIPTION, FIELD_REM_FUNCTION_OVERLOADED, FIELD_REM_FUNCTION, FIELD_DEFAULT_REM_FUNCTION, FIELD_GAP_DESCRIPTION, FIELD_REM_FUNCTION_OVERLOADED, FIELD_REM_FUNCTION,
FIELD_PARAMS, FIELD_ACTIVES, FIELD_SCOPE, FIELD_DEPRECATED_KEYS, FIELD_EDUCATION_PRINCIPLES);
FIELD_PARAMS, FIELD_ACTIVES, FIELD_SCOPE, FIELD_DEPRECATED_KEYS, FIELD_EDUCATION_PRINCIPLES, FIELD_CLEAN_CODE_ATTRIBUTE);


private RulesWsParameters() { private RulesWsParameters() {
// prevent instantiation // prevent instantiation

+ 13
- 2
server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/SearchAction.java View File

import static org.sonar.server.es.SearchOptions.MAX_PAGE_SIZE; import static org.sonar.server.es.SearchOptions.MAX_PAGE_SIZE;
import static org.sonar.server.rule.index.RuleIndex.ALL_STATUSES_EXCEPT_REMOVED; import static org.sonar.server.rule.index.RuleIndex.ALL_STATUSES_EXCEPT_REMOVED;
import static org.sonar.server.rule.index.RuleIndex.FACET_ACTIVE_SEVERITIES; import static org.sonar.server.rule.index.RuleIndex.FACET_ACTIVE_SEVERITIES;
import static org.sonar.server.rule.index.RuleIndex.FACET_CLEAN_CODE_ATTRIBUTE_CATEGORY;
import static org.sonar.server.rule.index.RuleIndex.FACET_CWE; import static org.sonar.server.rule.index.RuleIndex.FACET_CWE;
import static org.sonar.server.rule.index.RuleIndex.FACET_IMPACT_SEVERITY;
import static org.sonar.server.rule.index.RuleIndex.FACET_IMPACT_SOFTWARE_QUALITY;
import static org.sonar.server.rule.index.RuleIndex.FACET_LANGUAGES; import static org.sonar.server.rule.index.RuleIndex.FACET_LANGUAGES;
import static org.sonar.server.rule.index.RuleIndex.FACET_OLD_DEFAULT; import static org.sonar.server.rule.index.RuleIndex.FACET_OLD_DEFAULT;
import static org.sonar.server.rule.index.RuleIndex.FACET_OWASP_TOP_10; import static org.sonar.server.rule.index.RuleIndex.FACET_OWASP_TOP_10;
FACET_OWASP_TOP_10, FACET_OWASP_TOP_10,
FACET_OWASP_TOP_10_2021, FACET_OWASP_TOP_10_2021,
FACET_SANS_TOP_25, FACET_SANS_TOP_25,
FACET_SONARSOURCE_SECURITY};
FACET_SONARSOURCE_SECURITY,
FACET_CLEAN_CODE_ATTRIBUTE_CATEGORY,
FACET_IMPACT_SEVERITY,
FACET_IMPACT_SOFTWARE_QUALITY
};


private final RuleQueryFactory ruleQueryFactory; private final RuleQueryFactory ruleQueryFactory;
private final DbClient dbClient; private final DbClient dbClient;
new Change("10.0", "The value 'defaultDebtRemFn' for the 'f' parameter has been deprecated, use 'defaultRemFn' instead"), new Change("10.0", "The value 'defaultDebtRemFn' for the 'f' parameter has been deprecated, use 'defaultRemFn' instead"),
new Change("10.0", "The value 'sansTop25' for the parameter 'facets' has been deprecated"), new Change("10.0", "The value 'sansTop25' for the parameter 'facets' has been deprecated"),
new Change("10.0", "Parameter 'sansTop25' is deprecated"), new Change("10.0", "Parameter 'sansTop25' is deprecated"),
new Change("10.2", format("Parameters '%s', '%s', and '%s' are now deprecated.", PARAM_SEVERITIES, PARAM_TYPES, PARAM_ACTIVE_SEVERITIES)));
new Change("10.2", format("Parameters '%s', '%s', and '%s' are now deprecated.", PARAM_SEVERITIES, PARAM_TYPES, PARAM_ACTIVE_SEVERITIES)),
new Change("10.2", "Add 'impacts', 'cleanCodeAttribute', 'cleanCodeAttributeCategory' fields to the response"),
new Change("10.2", "The field 'cleanCodeAttribute' has been added to the 'f' parameter"),
new Change("10.2", format("add '%s', '%s' and '%s' to the 'facets' parameter.",FACET_CLEAN_CODE_ATTRIBUTE_CATEGORY, FACET_IMPACT_SOFTWARE_QUALITY, FACET_IMPACT_SEVERITY))
);


action.createParam(FACETS) action.createParam(FACETS)
.setDescription("Comma-separated list of the facets to be computed. No facet is computed by default.") .setDescription("Comma-separated list of the facets to be computed. No facet is computed by default.")

+ 2
- 2
server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/ShowAction.java View File

new Change("10.0", "The deprecated field 'defaultDebtRemFnOffset' has been removed, use 'defaultRemFnBaseEffort' instead."), new Change("10.0", "The deprecated field 'defaultDebtRemFnOffset' has been removed, use 'defaultRemFnBaseEffort' instead."),
new Change("10.0", "The deprecated field 'debtOverloaded' has been removed, use 'remFnOverloaded' instead."), new Change("10.0", "The deprecated field 'debtOverloaded' has been removed, use 'remFnOverloaded' instead."),
new Change("10.0", "The field 'defaultDebtRemFnType' has been deprecated, use 'defaultRemFnType' instead"), new Change("10.0", "The field 'defaultDebtRemFnType' has been deprecated, use 'defaultRemFnType' instead"),
new Change("10.0", "The field 'debtRemFnType' has been deprecated, use 'remFnType' instead")
);
new Change("10.0", "The field 'debtRemFnType' has been deprecated, use 'remFnType' instead"),
new Change("10.2", "Add 'impacts', 'cleanCodeAttribute', 'cleanCodeAttributeCategory' fields to the response"));


action action
.createParam(PARAM_KEY) .createParam(PARAM_KEY)

+ 3
- 0
server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/UpdateAction.java View File

import org.sonar.api.rule.Severity; import org.sonar.api.rule.Severity;
import org.sonar.api.server.debt.DebtRemediationFunction; import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction; import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction;
import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService;
.setDescription("Update an existing rule.<br>" + .setDescription("Update an existing rule.<br>" +
"Requires the 'Administer Quality Profiles' permission") "Requires the 'Administer Quality Profiles' permission")
.setSince("4.4") .setSince("4.4")
.setChangelog(
new Change("10.2", "Add 'impacts', 'cleanCodeAttribute', 'cleanCodeAttributeCategory' fields to the response"))
.setHandler(this); .setHandler(this);


action.createParam(PARAM_KEY) action.createParam(PARAM_KEY)

+ 32
- 24
server/sonar-webserver-webapi/src/main/resources/org/sonar/server/rule/ws/create-example.json View File

{ {
"rule":{
"key":"squid:forbidSonar",
"repo":"squid",
"name":"forbidSonar",
"createdAt":"2018-06-06T16:04:28+0200",
"htmlDesc":"Forbid classes with name starting with Sonar",
"mdDesc":"Forbid classes with name starting with Sonar",
"severity":"MAJOR",
"status":"READY",
"isTemplate":false,
"templateKey":"squid:S3688",
"sysTags":[],
"lang":"java",
"langName":"Java",
"params":[
{
"key":"className",
"htmlDesc":"Fully qualified name of the forbidden class. Use a regex to forbid a package.",
"defaultValue":"**/Sonar*",
"type":"STRING"
}
"rule": {
"key": "squid:forbidSonar",
"repo": "squid",
"name": "forbidSonar",
"createdAt": "2018-06-06T16:04:28+0200",
"htmlDesc": "Forbid classes with name starting with Sonar",
"mdDesc": "Forbid classes with name starting with Sonar",
"severity": "MAJOR",
"status": "READY",
"isTemplate": false,
"templateKey": "squid:S3688",
"sysTags": [],
"lang": "java",
"langName": "Java",
"params": [
{
"key": "className",
"htmlDesc": "Fully qualified name of the forbidden class. Use a regex to forbid a package.",
"defaultValue": "**/Sonar*",
"type": "STRING"
}
], ],
"scope":"MAIN",
"isExternal":false,
"type":"CODE_SMELL"
"scope": "MAIN",
"isExternal": false,
"type": "CODE_SMELL",
"cleanCodeAttributeCategory": "INTENTIONAL",
"cleanCodeAttribute": "CLEAR",
"impacts": [
{
"softwareQuality": "MAINTAINABILITY",
"severity": "HIGH"
}
]
} }
} }

+ 45
- 8
server/sonar-webserver-webapi/src/main/resources/org/sonar/server/rule/ws/search-example.json View File

"internalKey": "S1067", "internalKey": "S1067",
"isTemplate": false, "isTemplate": false,
"tags": [], "tags": [],
"sysTags": ["brain-overload"],
"sysTags": [
"brain-overload"
],
"lang": "java", "lang": "java",
"langName": "Java", "langName": "Java",
"scope": "MAIN", "scope": "MAIN",
"isExternal": false, "isExternal": false,
"type": "CODE_SMELL", "type": "CODE_SMELL",
"cleanCodeAttributeCategory": "INTENTIONAL",
"cleanCodeAttribute": "CLEAR",
"impacts": [
{
"softwareQuality": "MAINTAINABILITY",
"severity": "HIGH"
}
],
"descriptionSections": [ "descriptionSections": [
{ {
"key": "root_cause", "key": "root_cause",
"internalKey": "ClassCyclomaticComplexity", "internalKey": "ClassCyclomaticComplexity",
"isTemplate": false, "isTemplate": false,
"tags": [], "tags": [],
"sysTags": ["brain-overload"],
"sysTags": [
"brain-overload"
],
"lang": "java", "lang": "java",
"langName": "Java", "langName": "Java",
"scope": "MAIN", "scope": "MAIN",
"isExternal": false, "isExternal": false,
"type": "BUG", "type": "BUG",
"cleanCodeAttributeCategory": "INTENTIONAL",
"cleanCodeAttribute": "CLEAR",
"impacts": [
{
"softwareQuality": "RELIABILITY",
"severity": "HIGH"
}
],
"params": [ "params": [
{ {
"key": "max", "key": "max",
"internalKey": "MethodCyclomaticComplexity", "internalKey": "MethodCyclomaticComplexity",
"isTemplate": false, "isTemplate": false,
"tags": [], "tags": [],
"sysTags": ["brain-overload"],
"sysTags": [
"brain-overload"
],
"lang": "java", "lang": "java",
"langName": "Java", "langName": "Java",
"scope": "MAIN", "scope": "MAIN",
"isExternal": false, "isExternal": false,
"type": "VULNERABILITY", "type": "VULNERABILITY",
"cleanCodeAttributeCategory": "INTENTIONAL",
"cleanCodeAttribute": "CLEAR",
"impacts": [
{
"softwareQuality": "SECURITY",
"severity": "HIGH"
}
],
"params": [ "params": [
{ {
"key": "max", "key": "max",
"status": "READY", "status": "READY",
"internalKey": "XPath", "internalKey": "XPath",
"isTemplate": true, "isTemplate": true,
"tags": [ ],
"sysTags": [ ],
"tags": [],
"sysTags": [],
"mdNote": "<p>\nThe tree produced by the <code>firstOf()</code> matcher is hard to work with from checks when alternatives are not named.\n</p>\n\n<p>\nConsider the following rule:\n</p>\n\n<pre>\nb.rule(COMPILATION_UNIT).is(\n b.firstOf( /* Non-Compliant */\n \"FOO\",\n \"BAR\"));\n</pre>\n\n<p>\nIf, from a check, one wants to forbid the usage of the \"BAR\" alternative,\nthe easiest option will be to verify that the value of the first token is \"BAR\",\ni.e. <code>\"BAR\".equals(compilationUnitNode.getTokenValue())</code>.\n</p>\n\n<p>\nThis is not maintainable, for at least two reasons:\n</p>\n\n<ul>\n <li>The grammar might evolve to also accept \"bar\" in lowercase, which will break <code>\"BAR\".equals(...)</code></li>\n <li>The grammar might evolve to optionally accept \"hello\" before the <code>firstOf()</code>, which will break <code>compilationUnitNode.getTokenValue()</code></li>\n</ul>\n\n<p>\nInstead, it is much better to rewrite the grammar as:\n</p>\n\n<pre>\nb.rule(COMPILATION_UNIT).is(\n firstOf( /* Compliant */\n FOO,\n BAR));\nb.rule(FOO).is(\"FOO\");\nb.rule(BAR).is(\"BAR\");\n</pre>\n\n<p>\nThe same check which forbids \"BAR\" would be written as: <code>compilationUnitNode.hasDirectChildren(BAR)</code>.\nThis allows both of the previous grammar evolutions to be made without impacting the check at all.\n</p>", "mdNote": "<p>\nThe tree produced by the <code>firstOf()</code> matcher is hard to work with from checks when alternatives are not named.\n</p>\n\n<p>\nConsider the following rule:\n</p>\n\n<pre>\nb.rule(COMPILATION_UNIT).is(\n b.firstOf( /* Non-Compliant */\n \"FOO\",\n \"BAR\"));\n</pre>\n\n<p>\nIf, from a check, one wants to forbid the usage of the \"BAR\" alternative,\nthe easiest option will be to verify that the value of the first token is \"BAR\",\ni.e. <code>\"BAR\".equals(compilationUnitNode.getTokenValue())</code>.\n</p>\n\n<p>\nThis is not maintainable, for at least two reasons:\n</p>\n\n<ul>\n <li>The grammar might evolve to also accept \"bar\" in lowercase, which will break <code>\"BAR\".equals(...)</code></li>\n <li>The grammar might evolve to optionally accept \"hello\" before the <code>firstOf()</code>, which will break <code>compilationUnitNode.getTokenValue()</code></li>\n</ul>\n\n<p>\nInstead, it is much better to rewrite the grammar as:\n</p>\n\n<pre>\nb.rule(COMPILATION_UNIT).is(\n firstOf( /* Compliant */\n FOO,\n BAR));\nb.rule(FOO).is(\"FOO\");\nb.rule(BAR).is(\"BAR\");\n</pre>\n\n<p>\nThe same check which forbids \"BAR\" would be written as: <code>compilationUnitNode.hasDirectChildren(BAR)</code>.\nThis allows both of the previous grammar evolutions to be made without impacting the check at all.\n</p>",
"htmlNote": "&lt;p&gt;<br/>The tree produced by the &lt;code&gt;firstOf()&lt;/code&gt; matcher is hard to work with from checks when alternatives are not named.<br/>&lt;/p&gt;<br/><br/>&lt;p&gt;<br/>Consider the following rule:<br/>&lt;/p&gt;<br/><br/>&lt;pre&gt;<br/>b.rule(COMPILATION_UNIT).is(<br/> b.firstOf( /* Non-Compliant */<br/> &quot;FOO&quot;,<br/> &quot;BAR&quot;));<br/>&lt;/pre&gt;<br/><br/>&lt;p&gt;<br/>If, from a check, one wants to forbid the usage of the &quot;BAR&quot; alternative,<br/>the easiest option will be to verify that the value of the first token is &quot;BAR&quot;,<br/>i.e. &lt;code&gt;&quot;BAR&quot;.equals(compilationUnitNode.getTokenValue())&lt;/code&gt;.<br/>&lt;/p&gt;<br/><br/>&lt;p&gt;<br/>This is not maintainable, for at least two reasons:<br/>&lt;/p&gt;<br/><br/>&lt;ul&gt;<br/> &lt;li&gt;The grammar might evolve to also accept &quot;bar&quot; in lowercase, which will break &lt;code&gt;&quot;BAR&quot;.equals(...)&lt;/code&gt;&lt;/li&gt;<br/> &lt;li&gt;The grammar might evolve to optionally accept &quot;hello&quot; before the &lt;code&gt;firstOf()&lt;/code&gt;, which will break &lt;code&gt;compilationUnitNode.getTokenValue()&lt;/code&gt;&lt;/li&gt;<br/>&lt;/ul&gt;<br/><br/>&lt;p&gt;<br/>Instead, it is much better to rewrite the grammar as:<br/>&lt;/p&gt;<br/><br/>&lt;pre&gt;<br/>b.rule(COMPILATION_UNIT).is(<br/> firstOf( /* Compliant */<br/> FOO,<br/> BAR));<br/>b.rule(FOO).is(&quot;FOO&quot;);<br/>b.rule(BAR).is(&quot;BAR&quot;);<br/>&lt;/pre&gt;<br/><br/>&lt;p&gt;<br/>The same check which forbids &quot;BAR&quot; would be written as: &lt;code&gt;compilationUnitNode.hasDirectChildren(BAR)&lt;/code&gt;.<br/>This allows both of the previous grammar evolutions to be made without impacting the check at all.<br/>&lt;/p&gt;", "htmlNote": "&lt;p&gt;<br/>The tree produced by the &lt;code&gt;firstOf()&lt;/code&gt; matcher is hard to work with from checks when alternatives are not named.<br/>&lt;/p&gt;<br/><br/>&lt;p&gt;<br/>Consider the following rule:<br/>&lt;/p&gt;<br/><br/>&lt;pre&gt;<br/>b.rule(COMPILATION_UNIT).is(<br/> b.firstOf( /* Non-Compliant */<br/> &quot;FOO&quot;,<br/> &quot;BAR&quot;));<br/>&lt;/pre&gt;<br/><br/>&lt;p&gt;<br/>If, from a check, one wants to forbid the usage of the &quot;BAR&quot; alternative,<br/>the easiest option will be to verify that the value of the first token is &quot;BAR&quot;,<br/>i.e. &lt;code&gt;&quot;BAR&quot;.equals(compilationUnitNode.getTokenValue())&lt;/code&gt;.<br/>&lt;/p&gt;<br/><br/>&lt;p&gt;<br/>This is not maintainable, for at least two reasons:<br/>&lt;/p&gt;<br/><br/>&lt;ul&gt;<br/> &lt;li&gt;The grammar might evolve to also accept &quot;bar&quot; in lowercase, which will break &lt;code&gt;&quot;BAR&quot;.equals(...)&lt;/code&gt;&lt;/li&gt;<br/> &lt;li&gt;The grammar might evolve to optionally accept &quot;hello&quot; before the &lt;code&gt;firstOf()&lt;/code&gt;, which will break &lt;code&gt;compilationUnitNode.getTokenValue()&lt;/code&gt;&lt;/li&gt;<br/>&lt;/ul&gt;<br/><br/>&lt;p&gt;<br/>Instead, it is much better to rewrite the grammar as:<br/>&lt;/p&gt;<br/><br/>&lt;pre&gt;<br/>b.rule(COMPILATION_UNIT).is(<br/> firstOf( /* Compliant */<br/> FOO,<br/> BAR));<br/>b.rule(FOO).is(&quot;FOO&quot;);<br/>b.rule(BAR).is(&quot;BAR&quot;);<br/>&lt;/pre&gt;<br/><br/>&lt;p&gt;<br/>The same check which forbids &quot;BAR&quot; would be written as: &lt;code&gt;compilationUnitNode.hasDirectChildren(BAR)&lt;/code&gt;.<br/>This allows both of the previous grammar evolutions to be made without impacting the check at all.<br/>&lt;/p&gt;",
"noteLogin": "eric.hartmann", "noteLogin": "eric.hartmann",
"internalKey": "XPath", "internalKey": "XPath",
"isTemplate": false, "isTemplate": false,
"templateKey": "squid:XPath", "templateKey": "squid:XPath",
"tags": [ ],
"sysTags": [ ],
"tags": [],
"sysTags": [],
"lang": "java", "lang": "java",
"langName": "Java", "langName": "Java",
"scope": "MAIN", "scope": "MAIN",
"isExternal": false, "isExternal": false,
"type": "CODE_SMELL", "type": "CODE_SMELL",
"cleanCodeAttributeCategory": "INTENTIONAL",
"cleanCodeAttribute": "CLEAR",
"impacts": [
{
"softwareQuality": "MAINTAINABILITY",
"severity": "HIGH"
}
],
"params": [ "params": [
{ {
"key": "xpathQuery", "key": "xpathQuery",
} }
] ]
} }

] ]
} }

+ 59
- 46
server/sonar-webserver-webapi/src/main/resources/org/sonar/server/rule/ws/show-example.json View File

{"rule": {
{
"rule": {
"key": "squid:ClassCyclomaticComplexity", "key": "squid:ClassCyclomaticComplexity",
"repo": "squid", "repo": "squid",
"name": "Avoid too complex class", "name": "Avoid too complex class",
"internalKey": "ClassCyclomaticComplexity", "internalKey": "ClassCyclomaticComplexity",
"template": false, "template": false,
"tags": [], "tags": [],
"sysTags": ["brain-overload"],
"sysTags": [
"brain-overload"
],
"remFnType": "LINEAR_OFFSET", "remFnType": "LINEAR_OFFSET",
"remFnGapMultiplier": "5d", "remFnGapMultiplier": "5d",
"remFnBaseEffort": "10h", "remFnBaseEffort": "10h",
"scope": "MAIN", "scope": "MAIN",
"isExternal": false, "isExternal": false,
"type": "CODE_SMELL", "type": "CODE_SMELL",
"cleanCodeAttributeCategory": "INTENTIONAL",
"cleanCodeAttribute": "CLEAR",
"impacts": [
{
"softwareQuality": "MAINTAINABILITY",
"severity": "HIGH"
}
],
"descriptionSections": [ "descriptionSections": [
{
"key": "root_cause",
"content": "<h3 class=\"page-title coding-rules-detail-header\"><big>Unnecessary imports should be removed</big></h3>"
},
{
"key": "how_to_fix",
"content": "<h2>Recommended Secure Coding Practices</h2><ul><li> activate Spring Security's CSRF protection. </li></ul>",
"context": {
"displayName": "Spring",
"key": "spring"
}
},
{
"key": "how_to_fix",
"content": "<h2>Recommended Secure Coding Practices</h2><ul><li> activate hibernate protection. </li></ul>",
"context": {
"displayName": "Hibernate",
"key": "hibernate"
}
{
"key": "root_cause",
"content": "<h3 class=\"page-title coding-rules-detail-header\"><big>Unnecessary imports should be removed</big></h3>"
},
{
"key": "how_to_fix",
"content": "<h2>Recommended Secure Coding Practices</h2><ul><li> activate Spring Security's CSRF protection. </li></ul>",
"context": {
"displayName": "Spring",
"key": "spring"
}
},
{
"key": "how_to_fix",
"content": "<h2>Recommended Secure Coding Practices</h2><ul><li> activate hibernate protection. </li></ul>",
"context": {
"displayName": "Hibernate",
"key": "hibernate"
} }
}
], ],
"params": [ "params": [
{
"key": "max",
"desc": "Maximum complexity allowed.",
"defaultValue": "200"
}
{
"key": "max",
"desc": "Maximum complexity allowed.",
"defaultValue": "200"
}
] ]
}, "actives": [
},
"actives": [
{ {
"qProfile": "Sonar way with Findbugs:java",
"inherit": "NONE",
"severity": "MAJOR",
"params": [
{
"key": "max",
"value": "200"
}
]
"qProfile": "Sonar way with Findbugs:java",
"inherit": "NONE",
"severity": "MAJOR",
"params": [
{
"key": "max",
"value": "200"
}
]
}, },
{ {
"qProfile": "Sonar way:java",
"inherit": "NONE",
"severity": "MAJOR",
"params": [
{
"key": "max",
"value": "200"
}
]
"qProfile": "Sonar way:java",
"inherit": "NONE",
"severity": "MAJOR",
"params": [
{
"key": "max",
"value": "200"
}
]
} }
]}
]
}

+ 34
- 25
server/sonar-webserver-webapi/src/main/resources/org/sonar/server/rule/ws/update-example.json View File

{ {
"rule":{
"key":"squid:forbidSonar",
"repo":"squid",
"name":"forbidSonar",
"createdAt":"2018-06-06T16:09:09+0200",
"htmlDesc":"Forbid classes with name starting with Sonar",
"mdDesc":"Forbid classes with name starting with Sonar",
"severity":"MAJOR",
"status":"READY",
"isTemplate":false,
"templateKey":"squid:S3688",
"tags":[],
"sysTags":[],
"lang":"java",
"langName":"Java",
"params":[
{
"key":"className",
"htmlDesc":"Fully qualified name of the forbidden class. Use a regex to forbid a package.",
"defaultValue":"**/Sonar*","type":"STRING"
}
"rule": {
"key": "squid:forbidSonar",
"repo": "squid",
"name": "forbidSonar",
"createdAt": "2018-06-06T16:09:09+0200",
"htmlDesc": "Forbid classes with name starting with Sonar",
"mdDesc": "Forbid classes with name starting with Sonar",
"severity": "MAJOR",
"status": "READY",
"isTemplate": false,
"templateKey": "squid:S3688",
"tags": [],
"sysTags": [],
"lang": "java",
"langName": "Java",
"params": [
{
"key": "className",
"htmlDesc": "Fully qualified name of the forbidden class. Use a regex to forbid a package.",
"defaultValue": "**/Sonar*",
"type": "STRING"
}
], ],
"remFnOverloaded":false,
"scope":"MAIN",
"isExternal":false,
"type":"CODE_SMELL"
"remFnOverloaded": false,
"scope": "MAIN",
"isExternal": false,
"type": "CODE_SMELL",
"cleanCodeAttributeCategory": "INTENTIONAL",
"cleanCodeAttribute": "CLEAR",
"impacts": [
{
"softwareQuality": "MAINTAINABILITY",
"severity": "HIGH"
}
]
} }
} }

+ 17
- 8
sonar-ws/src/main/protobuf/ws-rules.proto View File



// WS api/rules/search // WS api/rules/search
message SearchResponse { message SearchResponse {
optional int64 total = 1 [deprecated=true];
optional int32 p = 2 [deprecated=true];
optional int64 ps = 3 [deprecated=true];
optional int64 total = 1 [deprecated = true];
optional int32 p = 2 [deprecated = true];
optional int64 ps = 3 [deprecated = true];


repeated Rule rules = 4; repeated Rule rules = 4;
optional Actives actives = 5; optional Actives actives = 5;
optional string repo = 2; optional string repo = 2;
optional string name = 3; optional string name = 3;
optional string createdAt = 4; optional string createdAt = 4;
optional string htmlDesc = 5 [deprecated=true];
optional string htmlDesc = 5 [deprecated = true];
optional string htmlNote = 6; optional string htmlNote = 6;
optional string mdDesc = 7; optional string mdDesc = 7;
optional string mdNote = 8; optional string mdNote = 8;
optional string noteLogin = 9; optional string noteLogin = 9;
optional string severity = 10;
// Deprecated since 10.2, replace by impacts
optional string severity = 10 [deprecated = true];
optional sonarqube.ws.commons.RuleStatus status = 11; optional sonarqube.ws.commons.RuleStatus status = 11;
optional string internalKey = 12; optional string internalKey = 12;
optional bool isTemplate = 13; optional bool isTemplate = 13;
optional string unusedDebtSubCharName = 28; optional string unusedDebtSubCharName = 28;


// Deprecated since 10.0, replaced by defaultRemFnType // Deprecated since 10.0, replaced by defaultRemFnType
optional string defaultDebtRemFnType = 29 [deprecated=true];
optional string defaultDebtRemFnType = 29 [deprecated = true];
reserved 30; reserved 30;
reserved 31; reserved 31;
reserved 32; reserved 32;
reserved 33; reserved 33;
// Deprecated since 10.0, replaced by remFnType // Deprecated since 10.0, replaced by remFnType
optional string debtRemFnType = 34 [deprecated=true];
optional string debtRemFnType = 34 [deprecated = true];
reserved 35; reserved 35;
reserved 36; reserved 36;
optional sonarqube.ws.commons.RuleType type = 37;
// Deprecated since 10.2, replace by impacts
optional sonarqube.ws.commons.RuleType type = 37 [deprecated = true];
optional string defaultRemFnType = 38; optional string defaultRemFnType = 38;
optional string defaultRemFnGapMultiplier = 39; optional string defaultRemFnGapMultiplier = 39;
optional string defaultRemFnBaseEffort = 40; optional string defaultRemFnBaseEffort = 40;
optional DescriptionSections descriptionSections = 49; optional DescriptionSections descriptionSections = 49;
optional EducationPrinciples educationPrinciples = 50; optional EducationPrinciples educationPrinciples = 50;
optional string updatedAt = 51; optional string updatedAt = 51;
optional sonarqube.ws.commons.CleanCodeAttribute cleanCodeAttribute = 52;
optional sonarqube.ws.commons.CleanCodeAttributeCategory cleanCodeAttributeCategory = 53;
optional Impacts impacts = 54;


message DescriptionSections { message DescriptionSections {
repeated DescriptionSection descriptionSections = 1; repeated DescriptionSection descriptionSections = 1;
} }
} }


message Impacts{
repeated sonarqube.ws.commons.Impact impacts = 1;
}

message DeprecatedKeys { message DeprecatedKeys {
repeated string deprecatedKey = 1; repeated string deprecatedKey = 1;
} }

Loading…
Cancel
Save