org.sonar.xoo.rule.XooRulesDefinition Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sonar-xoo-plugin Show documentation
Show all versions of sonar-xoo-plugin Show documentation
Open source platform for continuous inspection of code quality
The newest version!
/*
* SonarQube
* Copyright (C) 2009-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.xoo.rule;
import javax.annotation.Nullable;
import org.sonar.api.SonarRuntime;
import org.sonar.api.config.Configuration;
import org.sonar.api.issue.impact.Severity;
import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.rule.RuleScope;
import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.rule.RuleDescriptionSection;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.api.server.rule.RulesDefinitionAnnotationLoader;
import org.sonar.api.utils.Version;
import org.sonar.xoo.Xoo;
import org.sonar.xoo.Xoo2;
import org.sonar.xoo.checks.Check;
import org.sonar.xoo.rule.hotspot.HotspotWithContextsSensor;
import org.sonar.xoo.rule.hotspot.HotspotWithSingleContextSensor;
import org.sonar.xoo.rule.hotspot.HotspotWithoutContextSensor;
import org.sonar.xoo.rule.variant.HotspotWithCodeVariantsSensor;
import org.sonar.xoo.rule.variant.IssueWithCodeVariantsSensor;
import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ASSESS_THE_PROBLEM_SECTION_KEY;
import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.HOW_TO_FIX_SECTION_KEY;
import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.INTRODUCTION_SECTION_KEY;
import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.RESOURCES_SECTION_KEY;
import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ROOT_CAUSE_SECTION_KEY;
import static org.sonar.api.server.rule.RulesDefinition.OwaspTop10Version.Y2017;
import static org.sonar.api.server.rule.RulesDefinition.OwaspTop10Version.Y2021;
/**
* Define all the coding rules that are supported on the repositories named "xoo" and "xoo2"
*/
public class XooRulesDefinition implements RulesDefinition {
public static final String[] AVAILABLE_CONTEXTS = {"javascript", "jquery", "express_js", "react", "axios"};
public static final String XOO_REPOSITORY = "xoo";
public static final String XOO2_REPOSITORY = "xoo2";
private static final String TEN_MIN = "10min";
@Nullable
private final Version version;
@Nullable
private final Configuration configuration;
public XooRulesDefinition() {
this(null, null);
}
public XooRulesDefinition(@Nullable SonarRuntime sonarRuntime, @Nullable Configuration configuration) {
this.version = sonarRuntime != null ? sonarRuntime.getApiVersion() : null;
this.configuration = configuration;
}
@Override
public void define(Context context) {
defineRulesXoo(context);
defineRulesXoo2(context);
defineRulesXooExternal(context);
defineRulesXooExternalWithCct(context);
}
private static void defineRulesXoo2(Context context) {
NewRepository repo = context.createRepository(XOO2_REPOSITORY, Xoo2.KEY).setName("Xoo2");
NewRule hasTag = repo.createRule(HasTagSensor.RULE_KEY).setName("Has Tag");
addAllDescriptionSections(hasTag, "Search for a given tag in Xoo files");
NewRule oneIssuePerLine = repo.createRule(OneIssuePerLineSensor.RULE_KEY).setName("One Issue Per Line");
addAllDescriptionSections(oneIssuePerLine, "Generate an issue on each line of a file. It requires the metric \"lines\".");
oneIssuePerLine
.setDebtRemediationFunction(hasTag.debtRemediationFunctions().linear("1min"))
.setGapDescription("It takes about 1 minute to an experienced software craftsman to remove a line of code");
repo.done();
}
private void defineRulesXoo(Context context) {
NewRepository repo = context.createRepository(XOO_REPOSITORY, Xoo.KEY).setName("Xoo");
new RulesDefinitionAnnotationLoader().load(repo, Check.ALL);
NewRule hasTag = repo.createRule(HasTagSensor.RULE_KEY).setName("Has Tag")
.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.MEDIUM)
.setActivatedByDefault(true)
.addDescriptionSection(howToFixSectionWithContext("single_context"));
addDescriptionSectionsWithoutContexts(hasTag, "Search for a given tag in Xoo files");
hasTag
.setDebtRemediationFunction(hasTag.debtRemediationFunctions().constantPerIssue("2min"));
hasTag.createParam("tag")
.setDefaultValue("xoo")
.setDescription("The tag to search for");
NewRule ruleWithParameters = repo.createRule("RuleWithParameters").setName("Rule with parameters");
addAllDescriptionSections(ruleWithParameters,
"Rule containing parameter of different types : boolean, integer, etc. For information, no issue will be linked to this rule.");
ruleWithParameters.createParam("string").setType(RuleParamType.STRING);
ruleWithParameters.createParam("text").setType(RuleParamType.TEXT);
ruleWithParameters.createParam("boolean").setType(RuleParamType.BOOLEAN);
ruleWithParameters.createParam("integer").setType(RuleParamType.INTEGER);
ruleWithParameters.createParam("float").setType(RuleParamType.FLOAT);
NewRule oneIssuePerLine = repo.createRule(OneIssuePerLineSensor.RULE_KEY).setName("One Issue Per Line")
.setCleanCodeAttribute(CleanCodeAttribute.COMPLETE)
.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.INFO)
.setTags("line");
addDescriptionSectionsWithoutContexts(oneIssuePerLine, "Generate an issue on each line of a file. It requires the metric \"lines\".");
addHowToFixSectionsWithContexts(oneIssuePerLine);
oneIssuePerLine
.setDebtRemediationFunction(oneIssuePerLine.debtRemediationFunctions().linear("1min"))
.setGapDescription("It takes about 1 minute to an experienced software craftsman to remove a line of code")
.addEducationPrincipleKeys("defense_in_depth", "never_trust_user_input");
NewRule oneQuickFixPerLine = repo.createRule(OneQuickFixPerLineSensor.RULE_KEY).setName("One Quick Fix Per Line")
.setCleanCodeAttribute(CleanCodeAttribute.DISTINCT)
.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.BLOCKER)
.setTags("line");
addAllDescriptionSections(oneQuickFixPerLine,
"Generate an issue with quick fix available on each line of a file. It requires the metric \"lines\".");
oneQuickFixPerLine
.setDebtRemediationFunction(oneQuickFixPerLine.debtRemediationFunctions().linear("1min"))
.setGapDescription("It takes about 1 minute to an experienced software craftsman to remove a line of code");
NewRule oneIssueOnDirPerFile = repo.createRule(OneIssueOnDirPerFileSensor.RULE_KEY).setName("One Issue On Dir Per File");
addAllDescriptionSections(oneIssueOnDirPerFile,
"Generate issues on directories");
NewRule oneIssuePerFile = repo.createRule(OneIssuePerFileSensor.RULE_KEY).setName("One Issue Per File");
oneIssuePerFile.setDebtRemediationFunction(oneIssuePerFile.debtRemediationFunctions().linear(TEN_MIN));
addAllDescriptionSections(oneIssuePerFile, "Generate an issue on each file");
NewRule oneIssuePerTestFile = repo.createRule(OneIssuePerTestFileSensor.RULE_KEY).setName("One Issue Per Test File")
.setScope(RuleScope.TEST);
oneIssuePerTestFile.setDebtRemediationFunction(oneIssuePerTestFile.debtRemediationFunctions().linear("8min"));
addAllDescriptionSections(oneIssuePerTestFile, "Generate an issue on each test file");
NewRule oneBugIssuePerTestLine = repo.createRule(OneBugIssuePerTestLineSensor.RULE_KEY).setName("One Bug Issue Per Test Line")
.setScope(RuleScope.TEST)
.setCleanCodeAttribute(CleanCodeAttribute.RESPECTFUL)
.addDefaultImpact(SoftwareQuality.RELIABILITY, Severity.MEDIUM)
.setType(RuleType.BUG);
addAllDescriptionSections(oneBugIssuePerTestLine, "Generate a bug issue on each line of a test file. It requires the metric \"lines\".");
oneBugIssuePerTestLine
.setDebtRemediationFunction(oneBugIssuePerTestLine.debtRemediationFunctions().linear("4min"));
NewRule oneCodeSmellIssuePerTestLine = repo.createRule(OneCodeSmellIssuePerTestLineSensor.RULE_KEY).setName("One Code Smell Issue Per Test Line")
.setScope(RuleScope.TEST)
.setCleanCodeAttribute(CleanCodeAttribute.TESTED)
.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.MEDIUM)
.setType(RuleType.CODE_SMELL);
addAllDescriptionSections(oneCodeSmellIssuePerTestLine, "Generate a code smell issue on each line of a test file. It requires the metric \"lines\".");
oneCodeSmellIssuePerTestLine
.setDebtRemediationFunction(oneCodeSmellIssuePerTestLine.debtRemediationFunctions().linear("3min"));
NewRule oneIssuePerDirectory = repo.createRule(OneIssuePerDirectorySensor.RULE_KEY)
.setName("One Issue Per Directory")
.setCleanCodeAttribute(CleanCodeAttribute.CLEAR)
.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.HIGH);
oneIssuePerDirectory.setDebtRemediationFunction(oneIssuePerDirectory.debtRemediationFunctions().linear(TEN_MIN));
addAllDescriptionSections(oneIssuePerDirectory, "Generate an issue on each non-empty directory");
NewRule oneDayDebtPerFile = repo.createRule(OneDayDebtPerFileSensor.RULE_KEY).setName("One Day Debt Per File")
.setCleanCodeAttribute(CleanCodeAttribute.LAWFUL)
.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.MEDIUM);
oneDayDebtPerFile.setDebtRemediationFunction(oneDayDebtPerFile.debtRemediationFunctions().linear("1d"));
addAllDescriptionSections(oneDayDebtPerFile, "Generate an issue on each file with a debt of one day");
NewRule oneIssuePerProject = repo.createRule(OneIssuePerProjectSensor.RULE_KEY).setName("One Issue Per Project");
oneIssuePerProject
.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.MEDIUM)
.setDebtRemediationFunction(oneIssuePerProject.debtRemediationFunctions().linearWithOffset("25min", "1h"))
.setGapDescription("A certified architect will need roughly half an hour to start working on removal of projects, " +
"then it's about one hour per project.");
addAllDescriptionSections(oneIssuePerProject, "Generate an issue on each project");
NewRule oneBlockerIssuePerFile = repo.createRule(OneBlockerIssuePerFileSensor.RULE_KEY).setName("One Blocker Issue Per File")
.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.MEDIUM);
addAllDescriptionSections(oneBlockerIssuePerFile, "Generate a blocker issue on each file, whatever the severity declared in the Quality profile");
NewRule issueWithCustomMessage = repo.createRule(CustomMessageSensor.RULE_KEY).setName("Issue With Custom Message")
.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.MEDIUM);
addAllDescriptionSections(issueWithCustomMessage, "Generate an issue on each file with a custom message");
NewRule oneIssuePerFileWithRandomAccess = repo.createRule(RandomAccessSensor.RULE_KEY).setName("One Issue Per File with Random Access")
.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.MEDIUM);
addAllDescriptionSections(oneIssuePerFileWithRandomAccess, "This issue is generated on each file");
NewRule issueWithRangeAndMultipleLocations = repo.createRule(MultilineIssuesSensor.RULE_KEY).setName("Creates issues with ranges/multiple locations");
addAllDescriptionSections(issueWithRangeAndMultipleLocations, "Issue with range and multiple locations");
NewRule hotspotWithRangeAndMultipleLocations = repo.createRule(MultilineHotspotSensor.RULE_KEY)
.setName("Creates hotspots with ranges/multiple locations")
.setType(RuleType.SECURITY_HOTSPOT);
addAllDescriptionSections(hotspotWithRangeAndMultipleLocations, "Hotspot with range and multiple locations");
NewRule issueOnEachFileWithExtUnknown = repo.createRule(OneIssuePerUnknownFileSensor.RULE_KEY).setName("Creates issues on each file with extension 'unknown'");
addAllDescriptionSections(issueOnEachFileWithExtUnknown, "This issue is generated on each file with extenstion 'unknown'");
NewRule oneBugIssuePerLine = repo.createRule(OneBugIssuePerLineSensor.RULE_KEY).setName("One Bug Issue Per Line")
.addDefaultImpact(SoftwareQuality.RELIABILITY, Severity.MEDIUM)
.setType(RuleType.BUG);
oneBugIssuePerLine
.setDebtRemediationFunction(oneBugIssuePerLine.debtRemediationFunctions().linear("5min"));
addAllDescriptionSections(oneBugIssuePerLine, "Generate a bug issue on each line of a file. It requires the metric \"lines\".");
NewRule oneCodeSmellIssuePerLine = repo.createRule(OneCodeSmellIssuePerLineSensor.RULE_KEY).setName("One Code Smell Issue Per Line")
.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.MEDIUM)
.addDefaultImpact(SoftwareQuality.RELIABILITY, Severity.LOW)
.setType(RuleType.CODE_SMELL);
oneCodeSmellIssuePerLine
.setDebtRemediationFunction(oneCodeSmellIssuePerLine.debtRemediationFunctions().linear("9min"));
addAllDescriptionSections(oneCodeSmellIssuePerLine, "Generate a code smell issue on each line of a file. It requires the metric \"lines\".");
NewRule oneVulnerabilityIssuePerProject = repo.createRule(OneVulnerabilityIssuePerProjectSensor.RULE_KEY).setName("One Vulnerability Issue Per Project")
.addDefaultImpact(SoftwareQuality.SECURITY, Severity.MEDIUM)
.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.HIGH)
.setCleanCodeAttribute(CleanCodeAttribute.TRUSTWORTHY)
.setType(RuleType.VULNERABILITY);
addAllDescriptionSections(oneVulnerabilityIssuePerProject, "Generate an issue on each project");
if (configuration != null && configuration.get("sonar.xoo.OneVulnerabilityPerLine.securityStandards").isPresent()) {
String[] standards = configuration.get("sonar.xoo.OneVulnerabilityPerLine.securityStandards").get().split(",");
for (String standard : standards) {
NewRule oneVulnerabilityIssuePerSecurityStandard = repo.createRule(OneVulnerabilityPerSecurityStandardSensor.RULE_KEY_PREFIX + standard)
.setName("One Vulnerability per line containing '%s'".formatted(standard))
.addDefaultImpact(SoftwareQuality.SECURITY, Severity.MEDIUM)
.setCleanCodeAttribute(CleanCodeAttribute.TRUSTWORTHY)
.setType(RuleType.VULNERABILITY);
addSecurityStandard(oneVulnerabilityIssuePerSecurityStandard, standard);
addAllDescriptionSections(oneVulnerabilityIssuePerSecurityStandard, "Generate an issue on each line containing '" + standard + "'.");
}
}
oneVulnerabilityIssuePerProject
.setDebtRemediationFunction(oneVulnerabilityIssuePerProject.debtRemediationFunctions().linearWithOffset("25min", "1h"))
.setGapDescription("A certified architect will need roughly half an hour to start working on removal of project, " +
"then it's about one hour per project.");
NewRule templateofRule = repo
.createRule("xoo-template")
.setTemplate(true)
.setName("Template of rule");
addAllDescriptionSections(templateofRule, "Template to be overridden by custom rules");
NewRule hotspot = repo.createRule(HotspotWithoutContextSensor.RULE_KEY)
.setName("Find security hotspots")
.setType(RuleType.SECURITY_HOTSPOT)
.setActivatedByDefault(false);
addAllDescriptionSections(hotspot, "Search for Security Hotspots in Xoo files");
hotspot
.setDebtRemediationFunction(hotspot.debtRemediationFunctions().constantPerIssue("2min"));
NewRule variants = repo.createRule(IssueWithCodeVariantsSensor.RULE_KEY).setName("Find issues with code variants");
addAllDescriptionSections(variants, "Search for a given variant in Xoo files");
if (version != null && version.isGreaterThanOrEqual(Version.create(9, 3))) {
hotspot
.addOwaspTop10(OwaspTop10.A1, OwaspTop10.A3)
.addOwaspTop10(Y2021, OwaspTop10.A3, OwaspTop10.A2)
.addCwe(1, 89, 123, 863);
oneVulnerabilityIssuePerProject
.addOwaspTop10(Y2017, OwaspTop10.A9, OwaspTop10.A10)
.addOwaspTop10(Y2021, OwaspTop10.A6, OwaspTop10.A9)
.addCwe(89, 250, 311, 546, 564, 943);
}
if (version != null && version.isGreaterThanOrEqual(Version.create(9, 5))) {
hotspot
.addPciDss(PciDssVersion.V4_0, "6.5.1", "4.1")
.addPciDss(PciDssVersion.V3_2, "6.5.1", "4.2")
.addPciDss(PciDssVersion.V4_0, "6.5a.1", "4.2c")
.addPciDss(PciDssVersion.V3_2, "6.5a.1b", "4.2b");
oneVulnerabilityIssuePerProject
.addPciDss(PciDssVersion.V4_0, "10.1")
.addPciDss(PciDssVersion.V3_2, "10.2")
.addPciDss(PciDssVersion.V4_0, "10.1a.2b")
.addPciDss(PciDssVersion.V3_2, "10.1a.2c");
}
if (version != null && version.isGreaterThanOrEqual(Version.create(9, 6))) {
hotspot
.addOwaspAsvs(OwaspAsvsVersion.V4_0, "2.8.7", "3.1.1", "4.2.2");
oneVulnerabilityIssuePerProject
.addOwaspAsvs(OwaspAsvsVersion.V4_0, "11.1.2", "14.5.1", "14.5.4");
}
if (version != null && version.isGreaterThanOrEqual(Version.create(10, 7))) {
hotspot
.addStig(StigVersion.ASD_V5R3, "V-222599", "V-222615", "V-222653");
oneVulnerabilityIssuePerProject
.addStig(StigVersion.ASD_V5R3, "V-222596", "V-222608", "V-222653");
}
NewRule hotspotWithContexts = repo.createRule(HotspotWithContextsSensor.RULE_KEY)
.setName("Find security hotspots with contexts")
.setType(RuleType.SECURITY_HOTSPOT)
.setActivatedByDefault(false);
addDescriptionSectionsWithoutContexts(hotspotWithContexts, "Search for Security Hotspots with contexts in Xoo files");
addHowToFixSectionsWithContexts(hotspotWithContexts);
NewRule hotspotWithSingleContext = repo.createRule(HotspotWithSingleContextSensor.RULE_KEY)
.setName("Find security hotspots, how_to_fix with single context")
.setType(RuleType.SECURITY_HOTSPOT)
.setActivatedByDefault(false)
.addDescriptionSection(howToFixSectionWithContext("single_context"));
addDescriptionSectionsWithoutContexts(hotspotWithSingleContext, "Search for Security Hotspots with single context in Xoo files");
NewRule hotspotWithCodeVariants = repo.createRule(HotspotWithCodeVariantsSensor.RULE_KEY)
.setName("Find security hotspots with code variants")
.setType(RuleType.SECURITY_HOTSPOT)
.setActivatedByDefault(false);
addAllDescriptionSections(hotspotWithCodeVariants, "Search for a given variant in Xoo files");
repo.done();
}
private void addSecurityStandard(NewRule rule, String standard) {
String[] splitStandard = standard.split(":");
switch (splitStandard[0]) {
case "cwe":
rule.addCwe(Integer.parseInt(splitStandard[1]));
break;
case "owaspTop10":
rule.addOwaspTop10(Y2017, OwaspTop10.valueOf(splitStandard[1]));
break;
case "owaspTop10-2021":
rule.addOwaspTop10(Y2021, OwaspTop10.valueOf(splitStandard[1]));
break;
case "stig-ASD_V5R3":
if (version != null && version.isGreaterThanOrEqual(Version.create(10, 7))) {
rule.addStig(StigVersion.ASD_V5R3, splitStandard[1]);
}
break;
case "pciDss-3.2":
rule.addPciDss(PciDssVersion.V3_2, splitStandard[1]);
break;
case "pciDss-4.0":
rule.addPciDss(PciDssVersion.V4_0, splitStandard[1]);
break;
default:
throw new IllegalArgumentException("Unknown standard: " + standard);
}
}
private static void defineRulesXooExternalWithCct(Context context) {
NewRepository repo = context.createExternalRepository(OneExternalIssueCctPerLineSensor.ENGINE_ID, Xoo.KEY).setName(OneExternalIssueCctPerLineSensor.ENGINE_ID);
repo.createRule(OnePredefinedRuleExternalIssueCctPerLineSensor.RULE_ID)
.setScope(RuleScope.ALL)
.setHtmlDescription("Generates one external issue in each line")
.addDescriptionSection(descriptionSection(INTRODUCTION_SECTION_KEY, "Generates one external issue in each line"))
.setName("One external issue per line");
repo.done();
}
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")
.addDescriptionSection(descriptionSection(INTRODUCTION_SECTION_KEY, "Generates one external issue in each line"))
.setName("One external issue per line")
.setTags("riri", "fifi", "loulou");
repo.done();
}
private static void addAllDescriptionSections(NewRule rule, String description) {
addDescriptionSectionsWithoutContexts(rule, description);
rule.addDescriptionSection(descriptionSection(HOW_TO_FIX_SECTION_KEY, "How to fix: " + description));
}
private static void addDescriptionSectionsWithoutContexts(NewRule rule, String description) {
rule
.setHtmlDescription(description)
.addDescriptionSection(descriptionSection(INTRODUCTION_SECTION_KEY, "Introduction: " + description))
.addDescriptionSection(descriptionSection(ROOT_CAUSE_SECTION_KEY, "Root cause: " + description))
.addDescriptionSection(descriptionSection(ASSESS_THE_PROBLEM_SECTION_KEY, "Assess the problem: " + description))
.addDescriptionSection(descriptionSection(RESOURCES_SECTION_KEY,
" Google
StackOverflow"))
.addDescriptionSection(descriptionSection("fake_section_to_be_ignored",
"fake_section_to_be_ignored"));
}
private static void addHowToFixSectionsWithContexts(NewRule rule) {
for (String contextName : AVAILABLE_CONTEXTS) {
rule.addDescriptionSection(howToFixSectionWithContext(contextName));
}
}
private static RuleDescriptionSection descriptionSection(String sectionKey, String htmlDescription) {
return RuleDescriptionSection.builder()
.sectionKey(sectionKey)
.htmlContent(htmlDescription)
.build();
}
private static RuleDescriptionSection howToFixSectionWithContext(String contextName) {
return RuleDescriptionSection.builder()
.sectionKey(HOW_TO_FIX_SECTION_KEY)
.htmlContent(String.format("This is 'How to fix?' description section for the %s. " +
"This text can be very long.", contextName))
.context(new org.sonar.api.server.rule.Context(contextName, contextName))
.build();
}
}