@SafeVarargs private final void createRule(RulesDefinition.Context context, String language, String repositoryKey, String ruleKey, Consumer<NewRule>... consumers) { NewRepository repo = context.createRepository(repositoryKey, language); NewRule newRule = repo.createRule(ruleKey) .setName(ruleKey) .setHtmlDescription("Description of One") .setSeverity(BLOCKER) .setType(RuleType.CODE_SMELL) .setStatus(RuleStatus.BETA); Arrays.stream(consumers).forEach(c -> c.accept(newRule)); repo.done(); }
@Test public void fail_if_bad_rule_severity() { try { context.createRepository("findbugs", "java").createRule("NPE").setSeverity("VERY HIGH"); fail(); } catch (IllegalArgumentException e) { assertThat(e).hasMessage("Severity of rule [repository=findbugs, key=NPE] is not correct: VERY HIGH"); } }
.setName("Detect NPE") .setHtmlDescription("Detect <code>java.lang.NullPointerException</code>") .setSeverity(Severity.BLOCKER) .setInternalKey("/something") .setStatus(RuleStatus.BETA)
.setName("One") .setHtmlDescription("Description of One") .setSeverity(BLOCKER) .setInternalKey("config1") .setTags("tag1", "tag2", "tag3") .setName("One") .setHtmlDescription("Description of One") .setSeverity(BLOCKER) .setInternalKey("config1") .setTags("tag1", "tag2", "tag3")
newRule.setInternalKey(rule.getConfigKey()); newRule.setTemplate(rule.isTemplate()); newRule.setSeverity(rule.getSeverity().toString()); newRule.setStatus(rule.getStatus() == null ? RuleStatus.defaultStatus() : RuleStatus.valueOf(rule.getStatus())); newRule.setTags(rule.getTags());
@Override public void define(Context context) { NewRepository repo = context.createRepository("fake", "java"); NewRule rule1 = repo.createRule(RULE_KEY1.rule()) .setName("One") .setHtmlDescription("Description of One") .setSeverity(BLOCKER) .setInternalKey("config1") .setTags("tag1", "tag2", "tag3") .setScope(RuleScope.ALL) .setType(RuleType.CODE_SMELL) .setStatus(RuleStatus.BETA) .setGapDescription("squid.S115.effortToFix"); rule1.setDebtRemediationFunction(rule1.debtRemediationFunctions().linearWithOffset("5d", "10h")); rule1.createParam("param1").setDescription("parameter one").setDefaultValue("default1"); rule1.createParam("param2").setDescription("parameter two").setDefaultValue("default2"); repo.createRule(HOTSPOT_RULE_KEY.rule()) .setName("Hotspot") .setHtmlDescription("Minimal hotspot") .setType(RuleType.SECURITY_HOTSPOT) .addOwaspTop10(OwaspTop10.A1, OwaspTop10.A3) .addCwe(1, 123, 863); repo.createRule(RULE_KEY2.rule()) .setName("Two") .setHtmlDescription("Minimal rule"); repo.done(); } }
@Test public void declaring_a_rule_with_an_existing_RuleKey_still_used_should_throw_IAE() { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("The rule 'newKey1' of repository 'fake' is declared several times"); execute(context -> { NewRepository repo = context.createRepository("fake", "java"); repo.createRule("newKey1") .setName("One") .setHtmlDescription("Description of One") .setSeverity(BLOCKER) .setInternalKey("config1") .setTags("tag1", "tag2", "tag3") .setType(RuleType.CODE_SMELL) .setStatus(RuleStatus.BETA); repo.createRule("newKey1") .setName("One") .setHtmlDescription("Description of One") .setSeverity(BLOCKER) .setInternalKey("config1") .setTags("tag1", "tag2", "tag3") .setType(RuleType.CODE_SMELL) .addDeprecatedRuleKey("fake", "newKey1") .setStatus(RuleStatus.BETA); repo.done(); }); }
@Test public void declaring_a_rule_with_a_deprecated_RuleKey_still_used_should_throw_ISE() { expectedException.expect(IllegalStateException.class); expectedException.expectMessage("The following rule keys are declared both as deprecated and used key [fake:newKey1]"); execute(context -> { NewRepository repo = context.createRepository("fake", "java"); repo.createRule("newKey1") .setName("One") .setHtmlDescription("Description of One") .setSeverity(BLOCKER) .setInternalKey("config1") .setTags("tag1", "tag2", "tag3") .setType(RuleType.CODE_SMELL) .setStatus(RuleStatus.BETA); repo.createRule("newKey2") .setName("One") .setHtmlDescription("Description of One") .setSeverity(BLOCKER) .setInternalKey("config1") .setTags("tag1", "tag2", "tag3") .setType(RuleType.CODE_SMELL) .addDeprecatedRuleKey("fake", "newKey1") .setStatus(RuleStatus.BETA); repo.done(); }); }
@Test public void declaring_two_rules_with_same_deprecated_RuleKey_should_throw_ISE() { expectedException.expect(IllegalStateException.class); expectedException.expectMessage("The following deprecated rule keys are declared at least twice [fake:old]"); execute(context -> { NewRepository repo = context.createRepository("fake", "java"); repo.createRule("newKey1") .setName("One") .setHtmlDescription("Description of One") .setSeverity(BLOCKER) .setInternalKey("config1") .setTags("tag1", "tag2", "tag3") .setType(RuleType.CODE_SMELL) .addDeprecatedRuleKey("fake", "old") .setStatus(RuleStatus.BETA); repo.createRule("newKey2") .setName("One") .setHtmlDescription("Description of One") .setSeverity(BLOCKER) .setInternalKey("config1") .setTags("tag1", "tag2", "tag3") .setType(RuleType.CODE_SMELL) .addDeprecatedRuleKey("fake", "old") .setStatus(RuleStatus.BETA); repo.done(); }); }
@Override public void define(Context context) { NewRepository repo = context.createRepository("fake", "java"); // almost all the attributes of rule1 are changed NewRule rule1 = repo.createRule(RULE_KEY1.rule()) .setName("One v2") .setHtmlDescription("Description of One v2") .setSeverity(INFO) .setInternalKey("config1 v2") // tag2 and tag3 removed, tag4 added .setTags("tag1", "tag4") .setType(RuleType.BUG) .setStatus(READY) .setGapDescription("squid.S115.effortToFix.v2"); rule1.setDebtRemediationFunction(rule1.debtRemediationFunctions().linearWithOffset("6d", "2h")); rule1.createParam("param1").setDescription("parameter one v2").setDefaultValue("default1 v2"); rule1.createParam("param2").setDescription("parameter two v2").setDefaultValue("default2 v2"); // rule2 is dropped, rule3 is new repo.createRule(RULE_KEY3.rule()) .setName("Three") .setHtmlDescription("Rule Three"); repo.done(); } }
@Override public void define(Context context) { NewRepository repo = context.createExternalRepository("eslint", "js"); repo.createRule(RULE_KEY1.rule()) .setName("One") .setHtmlDescription("Description of One") .setSeverity(BLOCKER) .setInternalKey("config1") .setTags("tag1", "tag2", "tag3") .setScope(RuleScope.ALL) .setType(RuleType.CODE_SMELL) .setStatus(RuleStatus.BETA); repo.createRule(EXTERNAL_HOTSPOT_RULE_KEY.rule()) .setName("Hotspot") .setHtmlDescription("Minimal hotspot") .setType(RuleType.SECURITY_HOTSPOT) .addOwaspTop10(OwaspTop10.A1, OwaspTop10.A3) .addCwe(1, 123, 863); repo.done(); } }
@Test public void define_rules_with_remediation_function() { RulesDefinition.NewRepository newRepo = context.createRepository("common-java", "java"); RulesDefinition.NewRule newRule = newRepo.createRule("InsufficientBranchCoverage") .setName("Insufficient condition coverage") .setHtmlDescription("Insufficient condition coverage by unit tests") .setSeverity(Severity.MAJOR) .setGapDescription("Effort to test one uncovered branch"); newRule.setDebtRemediationFunction(newRule.debtRemediationFunctions().linearWithOffset("1h", "10min")); newRepo.done(); RulesDefinition.Repository repo = context.repository("common-java"); assertThat(repo.rules()).hasSize(1); RulesDefinition.Rule rule = repo.rule("InsufficientBranchCoverage"); assertThat(rule.debtRemediationFunction().type()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET); assertThat(rule.debtRemediationFunction().gapMultiplier()).isEqualTo("1h"); assertThat(rule.debtRemediationFunction().baseEffort()).isEqualTo("10min"); assertThat(rule.gapDescription()).isEqualTo("Effort to test one uncovered branch"); }
private static RulesDefinition.NewRule loadRule(RulesDefinition.NewExtendedRepository repo, Class clazz, org.sonar.check.Rule ruleAnnotation) { String ruleKey = StringUtils.defaultIfEmpty(ruleAnnotation.key(), clazz.getCanonicalName()); String ruleName = StringUtils.defaultIfEmpty(ruleAnnotation.name(), null); String description = StringUtils.defaultIfEmpty(ruleAnnotation.description(), null); RulesDefinition.NewRule rule = repo.createRule(ruleKey); rule.setName(ruleName).setHtmlDescription(description); rule.setSeverity(ruleAnnotation.priority().name()); rule.setTemplate(ruleAnnotation.cardinality() == Cardinality.MULTIPLE); rule.setStatus(RuleStatus.valueOf(ruleAnnotation.status())); rule.setTags(ruleAnnotation.tags()); List<Field> fields = FieldUtils2.getFields(clazz, true); for (Field field : fields) { loadParameters(rule, field); } return rule; }
private static void defineBranchCoverageRule(RulesDefinition.NewRepository repo) { RulesDefinition.NewRule rule = repo.createRule(CommonRuleKeys.INSUFFICIENT_BRANCH_COVERAGE); rule.setName("Branches should have sufficient coverage by tests") .addTags("bad-practice") .setHtmlDescription("An issue is created on a file as soon as the branch coverage on this file is less than the required threshold. " + "It gives the number of branches to be covered in order to reach the required threshold.") .setDebtRemediationFunction(rule.debtRemediationFunctions().linear("5min")) .setGapDescription("number of uncovered conditions") .setSeverity(Severity.MAJOR); rule.createParam(CommonRuleKeys.INSUFFICIENT_BRANCH_COVERAGE_PROPERTY) .setName("The minimum required branch coverage ratio") .setDefaultValue("65") .setType(RuleParamType.FLOAT); }
private static void defineCommentDensityRule(RulesDefinition.NewRepository repo) { RulesDefinition.NewRule rule = repo.createRule(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY); rule.setName("Source files should have a sufficient density of comment lines") .addTags("convention") .setHtmlDescription("An issue is created on a file as soon as the density of comment lines on this file is less than the required threshold. " + "The number of comment lines to be written in order to reach the required threshold is provided by each issue message.") .setDebtRemediationFunction(rule.debtRemediationFunctions().linear("2min")) .setGapDescription("number of lines required to meet minimum density") .setSeverity(Severity.MAJOR); rule.createParam(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY) .setName("The minimum required comment density") .setDefaultValue("25") .setType(RuleParamType.FLOAT); }
private static void defineLineCoverageRule(RulesDefinition.NewRepository repo) { RulesDefinition.NewRule rule = repo.createRule(CommonRuleKeys.INSUFFICIENT_LINE_COVERAGE); rule.setName("Lines should have sufficient coverage by tests") .addTags("bad-practice") .setHtmlDescription("An issue is created on a file as soon as the line coverage on this file is less than the required threshold. " + "It gives the number of lines to be covered in order to reach the required threshold.") .setDebtRemediationFunction(rule.debtRemediationFunctions().linear("2min")) .setGapDescription("number of lines under the coverage threshold") .setSeverity(Severity.MAJOR); rule.createParam(CommonRuleKeys.INSUFFICIENT_LINE_COVERAGE_PROPERTY) .setName("The minimum required line coverage ratio") .setDefaultValue("65") .setType(RuleParamType.FLOAT); }
private static void defineFailedUnitTestRule(RulesDefinition.NewRepository repo) { RulesDefinition.NewRule rule = repo.createRule(CommonRuleKeys.FAILED_UNIT_TESTS); rule .setName("Failed unit tests should be fixed") .addTags("bug") .setHtmlDescription( "Test failures or errors generally indicate that regressions have been introduced. Those tests should be handled as soon as possible to reduce the cost to fix the corresponding regressions.") .setDebtRemediationFunction(rule.debtRemediationFunctions().linear("10min")) .setGapDescription("number of failed tests") .setSeverity(Severity.MAJOR); }
private static void defineDuplicatedBlocksRule(RulesDefinition.NewRepository repo) { RulesDefinition.NewRule rule = repo.createRule(CommonRuleKeys.DUPLICATED_BLOCKS); rule.setName("Source files should not have any duplicated blocks") .addTags("pitfall") .setHtmlDescription("An issue is created on a file as soon as there is at least one block of duplicated code on this file") .setDebtRemediationFunction(rule.debtRemediationFunctions().linearWithOffset("10min", "10min")) .setGapDescription("number of duplicate blocks") .setSeverity(Severity.MAJOR); }
private static void defineRulesXooExternal(Context context) { NewRepository repo = context.createExternalRepository(OneExternalIssuePerLineSensor.ENGINE_ID, Xoo.KEY).setName(OneExternalIssuePerLineSensor.ENGINE_ID); repo.createRule(OnePredefinedRuleExternalIssuePerLineSensor.RULE_ID) .setSeverity(OnePredefinedRuleExternalIssuePerLineSensor.SEVERITY) .setType(OnePredefinedRuleExternalIssuePerLineSensor.TYPE) .setScope(RuleScope.ALL) .setHtmlDescription("Generates one external issue in each line") .setName("One external issue per line"); repo.done(); }
private static void defineSkippedUnitTestRule(RulesDefinition.NewRepository repo) { RulesDefinition.NewRule rule = repo.createRule(CommonRuleKeys.SKIPPED_UNIT_TESTS); rule.setName("Skipped unit tests should be either removed or fixed") .addTags("pitfall") .setHtmlDescription("Skipped unit tests are considered as dead code. Either they should be activated again (and updated) or they should be removed.") .setDebtRemediationFunction(rule.debtRemediationFunctions().linear("10min")) .setGapDescription("number of skipped tests") .setSeverity(Severity.MAJOR); } }