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; | ||||
.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 |
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); | ||||
} | } |
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 |
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() |
.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 |
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)) { |
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 |
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.") |
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) |
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) |
{ | { | ||||
"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" | |||||
} | |||||
] | |||||
} | } | ||||
} | } |
"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": "<p><br/>The tree produced by the <code>firstOf()</code> matcher is hard to work with from checks when alternatives are not named.<br/></p><br/><br/><p><br/>Consider the following rule:<br/></p><br/><br/><pre><br/>b.rule(COMPILATION_UNIT).is(<br/> b.firstOf( /* Non-Compliant */<br/> "FOO",<br/> "BAR"));<br/></pre><br/><br/><p><br/>If, from a check, one wants to forbid the usage of the "BAR" alternative,<br/>the easiest option will be to verify that the value of the first token is "BAR",<br/>i.e. <code>"BAR".equals(compilationUnitNode.getTokenValue())</code>.<br/></p><br/><br/><p><br/>This is not maintainable, for at least two reasons:<br/></p><br/><br/><ul><br/> <li>The grammar might evolve to also accept "bar" in lowercase, which will break <code>"BAR".equals(...)</code></li><br/> <li>The grammar might evolve to optionally accept "hello" before the <code>firstOf()</code>, which will break <code>compilationUnitNode.getTokenValue()</code></li><br/></ul><br/><br/><p><br/>Instead, it is much better to rewrite the grammar as:<br/></p><br/><br/><pre><br/>b.rule(COMPILATION_UNIT).is(<br/> firstOf( /* Compliant */<br/> FOO,<br/> BAR));<br/>b.rule(FOO).is("FOO");<br/>b.rule(BAR).is("BAR");<br/></pre><br/><br/><p><br/>The same check which forbids "BAR" would be written as: <code>compilationUnitNode.hasDirectChildren(BAR)</code>.<br/>This allows both of the previous grammar evolutions to be made without impacting the check at all.<br/></p>", | "htmlNote": "<p><br/>The tree produced by the <code>firstOf()</code> matcher is hard to work with from checks when alternatives are not named.<br/></p><br/><br/><p><br/>Consider the following rule:<br/></p><br/><br/><pre><br/>b.rule(COMPILATION_UNIT).is(<br/> b.firstOf( /* Non-Compliant */<br/> "FOO",<br/> "BAR"));<br/></pre><br/><br/><p><br/>If, from a check, one wants to forbid the usage of the "BAR" alternative,<br/>the easiest option will be to verify that the value of the first token is "BAR",<br/>i.e. <code>"BAR".equals(compilationUnitNode.getTokenValue())</code>.<br/></p><br/><br/><p><br/>This is not maintainable, for at least two reasons:<br/></p><br/><br/><ul><br/> <li>The grammar might evolve to also accept "bar" in lowercase, which will break <code>"BAR".equals(...)</code></li><br/> <li>The grammar might evolve to optionally accept "hello" before the <code>firstOf()</code>, which will break <code>compilationUnitNode.getTokenValue()</code></li><br/></ul><br/><br/><p><br/>Instead, it is much better to rewrite the grammar as:<br/></p><br/><br/><pre><br/>b.rule(COMPILATION_UNIT).is(<br/> firstOf( /* Compliant */<br/> FOO,<br/> BAR));<br/>b.rule(FOO).is("FOO");<br/>b.rule(BAR).is("BAR");<br/></pre><br/><br/><p><br/>The same check which forbids "BAR" would be written as: <code>compilationUnitNode.hasDirectChildren(BAR)</code>.<br/>This allows both of the previous grammar evolutions to be made without impacting the check at all.<br/></p>", | ||||
"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", | ||||
} | } | ||||
] | ] | ||||
} | } | ||||
] | ] | ||||
} | } |
{"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" | |||||
} | |||||
] | |||||
} | } | ||||
]} | |||||
] | |||||
} |
{ | { | ||||
"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" | |||||
} | |||||
] | |||||
} | } | ||||
} | } |
// 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; | ||||
} | } |