import org.sonar.xoo.rule.OneIssuePerFileSensor;
import org.sonar.xoo.rule.OneIssuePerLineSensor;
import org.sonar.xoo.rule.OneIssuePerModuleSensor;
+import org.sonar.xoo.rule.OneIssuePerTestFileSensor;
import org.sonar.xoo.rule.OneIssuePerUnknownFileSensor;
import org.sonar.xoo.rule.OneVulnerabilityIssuePerModuleSensor;
import org.sonar.xoo.rule.RandomAccessSensor;
OneIssuePerLineSensor.class,
OneDayDebtPerFileSensor.class,
OneIssuePerFileSensor.class,
+ OneIssuePerTestFileSensor.class,
OneIssuePerDirectorySensor.class,
OneIssuePerModuleSensor.class,
OneIssueOnDirPerFileSensor.class,
--- /dev/null
+package org.sonar.xoo.rule;
+
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputFile.Type;
+import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.api.batch.sensor.issue.NewIssue;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.xoo.Xoo;
+
+public class OneIssuePerTestFileSensor extends AbstractXooRuleSensor {
+ public static final String RULE_KEY = "OneIssuePerTestFile";
+
+ public OneIssuePerTestFileSensor(FileSystem fs, ActiveRules activeRules) {
+ super(fs, activeRules);
+ }
+
+ @Override
+ protected String getRuleKey() {
+ return RULE_KEY;
+ }
+
+ @Override
+ protected void processFile(InputFile inputFile, SensorContext context, RuleKey ruleKey, String languageKey) {
+ NewIssue newIssue = context.newIssue();
+ newIssue
+ .forRule(ruleKey)
+ .at(newIssue.newLocation().message("This issue is generated on each test file")
+ .on(inputFile))
+ .save();
+ }
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ descriptor
+ .onlyOnLanguage(Xoo.KEY)
+ .onlyOnFileType(Type.TEST)
+ .createIssuesForRuleRepository(XooRulesDefinition.XOO_REPOSITORY);
+ }
+
+}
*/
package org.sonar.xoo.rule;
+import org.sonar.api.rule.RuleScope;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.server.rule.RulesDefinition;
public static final String XOO_REPOSITORY = "xoo";
public static final String XOO2_REPOSITORY = "xoo2";
+ private static final String TEN_MIN = "10min";
+
@Override
public void define(Context context) {
defineRulesXoo(context);
NewRule oneIssuePerFile = repo.createRule(OneIssuePerFileSensor.RULE_KEY).setName("One Issue Per File")
.setHtmlDescription("Generate an issue on each file");
- oneIssuePerFile.setDebtRemediationFunction(oneIssuePerFile.debtRemediationFunctions().linear("10min"));
+ oneIssuePerFile.setDebtRemediationFunction(oneIssuePerFile.debtRemediationFunctions().linear(TEN_MIN));
+
+ NewRule oneIssuePerTestFile = repo.createRule(OneIssuePerTestFileSensor.RULE_KEY).setName("One Issue Per Test File")
+ .setScope(RuleScope.TEST)
+ .setHtmlDescription("Generate an issue on each test file");
+ oneIssuePerTestFile.setDebtRemediationFunction(oneIssuePerTestFile.debtRemediationFunctions().linear(TEN_MIN));
NewRule oneIssuePerDirectory = repo.createRule(OneIssuePerDirectorySensor.RULE_KEY).setName("One Issue Per Directory")
.setHtmlDescription("Generate an issue on each non-empty directory");
- oneIssuePerFile.setDebtRemediationFunction(oneIssuePerDirectory.debtRemediationFunctions().linear("10min"));
+ oneIssuePerDirectory.setDebtRemediationFunction(oneIssuePerDirectory.debtRemediationFunctions().linear(TEN_MIN));
NewRule oneDayDebtPerFile = repo.createRule(OneDayDebtPerFileSensor.RULE_KEY).setName("One Day Debt Per File")
.setHtmlDescription("Generate an issue on each file with a debt of one day");
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.rule.RuleDto.Format;
+import org.sonar.db.rule.RuleDto.Scope;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableSet.copyOf;
.setDefRemediationGapMultiplier(nextInt(10) + "h")
.setDefRemediationFunction("LINEAR_OFFSET")
.setCreatedAt(System.currentTimeMillis())
- .setUpdatedAt(System.currentTimeMillis());
+ .setUpdatedAt(System.currentTimeMillis())
+ .setScope(Scope.MAIN);
}
public static RuleMetadataDto newRuleMetadata() {
.setGapDescription(ruleKey.repository() + "." + ruleKey.rule() + ".effortToFix")
.setType(RuleType.CODE_SMELL)
.setCreatedAt(new Date().getTime())
- .setUpdatedAt(new Date().getTime());
+ .setUpdatedAt(new Date().getTime())
+ .setScope(Scope.MAIN);
if (organization != null) {
res
.setOrganizationUuid(organization.getUuid())
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction;
import org.sonar.db.rule.RuleDefinitionDto;
+import org.sonar.db.rule.RuleDto.Scope;
import org.sonar.db.rule.RuleMetadataDto;
import org.sonar.db.rule.RuleParamDto;
import org.sonar.markdown.Markdown;
import org.sonar.server.rule.ws.SearchAction.SearchResult;
import org.sonar.server.text.MacroInterpreter;
import org.sonarqube.ws.Common;
+import org.sonarqube.ws.Common.RuleScope;
import org.sonarqube.ws.Rules;
import static java.lang.String.format;
import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_SEVERITY;
import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_STATUS;
import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_SYSTEM_TAGS;
+import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_SCOPE;
import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_TAGS;
import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_TEMPLATE_KEY;
setTemplateKey(ruleResponse, ruleDefinitionDto, result, fieldsToReturn);
setDefaultDebtRemediationFunctionFields(ruleResponse, ruleDefinitionDto, fieldsToReturn);
setEffortToFixDescription(ruleResponse, ruleDefinitionDto, fieldsToReturn);
+ setScope(ruleResponse, ruleDefinitionDto, fieldsToReturn);
return ruleResponse;
}
}
}
+ private static void setScope(Rules.Rule.Builder ruleResponse, RuleDefinitionDto ruleDto, Set<String> fieldsToReturn) {
+ if (shouldReturnField(fieldsToReturn, FIELD_SCOPE)) {
+ ruleResponse.setScope(toWsRuleScope(ruleDto.getScope()));
+ }
+ }
+
+ private static RuleScope toWsRuleScope(Scope scope) {
+ switch (scope) {
+ case ALL:
+ return RuleScope.ALL;
+ case MAIN:
+ return RuleScope.MAIN;
+ case TEST:
+ return RuleScope.TEST;
+ default:
+ throw new IllegalArgumentException("Unknown rule scope: " + scope);
+ }
+ }
+
private static void setEffortToFixDescription(Rules.Rule.Builder ruleResponse, RuleDefinitionDto ruleDto, Set<String> fieldsToReturn) {
if ((shouldReturnField(fieldsToReturn, FIELD_EFFORT_TO_FIX_DESCRIPTION) || shouldReturnField(fieldsToReturn, FIELD_GAP_DESCRIPTION))
&& ruleDto.getGapDescription() != null) {
public static final String FIELD_DEBT_OVERLOADED = "debtOverloaded";
public static final String FIELD_REM_FUNCTION_OVERLOADED = "remFnOverloaded";
+ /**
+ * @since 7.1
+ */
+ public static final String FIELD_SCOPE = "scope";
+
public static final String FIELD_PARAMS = "params";
public static final String FIELD_ACTIVES = "actives";
FIELD_MARKDOWN_NOTE, FIELD_HTML_NOTE,
FIELD_DEFAULT_DEBT_REM_FUNCTION, FIELD_EFFORT_TO_FIX_DESCRIPTION, FIELD_DEBT_OVERLOADED, FIELD_DEBT_REM_FUNCTION,
FIELD_DEFAULT_REM_FUNCTION, FIELD_GAP_DESCRIPTION, FIELD_REM_FUNCTION_OVERLOADED, FIELD_REM_FUNCTION,
- FIELD_PARAMS, FIELD_ACTIVES);
+ FIELD_PARAMS, FIELD_ACTIVES, FIELD_SCOPE);
private RulesWsParameters() {
// prevent instantiation
"<li>\"debtRemFn\" becomes \"remFn\"</li>" +
"<li>\"effortToFixDescription\" becomes \"gapDescription\"</li>" +
"<li>\"debtOverloaded\" becomes \"remFnOverloaded\"</li>" +
- "</ul>")
+ "</ul>" +
+ "In 7.1, the field 'scope' has been added.")
.setPossibleValues(Ordering.natural().sortedCopy(OPTIONAL_FIELDS));
Iterator<String> it = OPTIONAL_FIELDS.iterator();
paramFields.setExampleValue(format("%s,%s", it.next(), it.next()));
"<li>\"debtRemFnOffset\" becomes \"remFnBaseEffort\"</li>" +
"<li>\"defaultDebtRemFnOffset\" becomes \"defaultRemFnBaseEffort\"</li>" +
"<li>\"debtOverloaded\" becomes \"remFnOverloaded\"</li>" +
- "</ul>")
+ "</ul>" +
+ "In 7.1, a new field 'scope' has been added to the response.")
.setResponseExample(getClass().getResource("search-example.json"))
.setSince("4.4")
.setHandler(this);
"<li>\"debtRemFnOffset\" becomes \"remFnBaseEffort\"</li>" +
"<li>\"defaultDebtRemFnOffset\" becomes \"defaultRemFnBaseEffort\"</li>" +
"<li>\"debtOverloaded\" becomes \"remFnOverloaded\"</li>" +
- "</ul>")
+ "</ul>" +
+ "In 7.1, the field 'scope' has been added.")
.setSince("4.2")
.setResponseExample(Resources.getResource(getClass(), "example-show.json"))
.setHandler(this);
"gapDescription": "java.S001.effortToFix",
"lang": "java",
"langName": "Java",
+ "scope": "MAIN",
"type": "CODE_SMELL",
"params": [
{
"sysTags": ["brain-overload"],
"lang": "java",
"langName": "Java",
+ "scope": "MAIN",
"type": "CODE_SMELL",
"params": [
{
"sysTags": ["brain-overload"],
"lang": "java",
"langName": "Java",
+ "scope": "MAIN",
"type": "BUG",
"params": [
{
"sysTags": ["brain-overload"],
"lang": "java",
"langName": "Java",
+ "scope": "MAIN",
"type": "VULNERABILITY",
"params": [
{
"noteLogin": "eric.hartmann",
"lang": "java",
"langName": "Java",
+ "scope": "MAIN",
"type": "CODE_SMELL",
"params": [
{
"sysTags": [ ],
"lang": "java",
"langName": "Java",
+ "scope": "MAIN",
"type": "CODE_SMELL",
"params": [
{
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleDto.Format;
+import org.sonar.db.rule.RuleDto.Scope;
import org.sonar.db.rule.RuleMetadataDto;
import org.sonar.db.rule.RuleParamDto;
import org.sonar.db.rule.RuleTesting;
.setLanguage("xoo")
.setTags(newHashSet("tag1", "tag2"))
.setSystemTags(newHashSet("systag1", "systag2"))
- .setType(RuleType.BUG);
+ .setType(RuleType.BUG)
+ .setScope(Scope.ALL);
RuleDefinitionDto definition = ruleDto.getDefinition();
RuleDao ruleDao = dbClient.ruleDao();
DbSession session = dbTester.getSession();
.setDefRemediationBaseEffort("10h")
.setRemediationFunction(null)
.setRemediationGapMultiplier(null)
- .setRemediationBaseEffort(null);
+ .setRemediationBaseEffort(null)
+ .setScope(Scope.ALL);
RuleDao ruleDao = dbClient.ruleDao();
DbSession session = dbTester.getSession();
ruleDao.insert(session, ruleDto.getDefinition());
.setDefRemediationBaseEffort(null)
.setRemediationFunction("LINEAR_OFFSET")
.setRemediationGapMultiplier("5d")
- .setRemediationBaseEffort("10h");
+ .setRemediationBaseEffort("10h")
+ .setScope(Scope.ALL);
RuleDao ruleDao = dbClient.ruleDao();
DbSession session = dbTester.getSession();
ruleDao.insert(session, ruleDto.getDefinition());
.setDefRemediationBaseEffort(null)
.setRemediationFunction("LINEAR_OFFSET")
.setRemediationGapMultiplier("5d")
- .setRemediationBaseEffort("10h");
+ .setRemediationBaseEffort("10h")
+ .setScope(Scope.ALL);
RuleDao ruleDao = dbClient.ruleDao();
DbSession session = dbTester.getSession();
ruleDao.insert(session, ruleDto.getDefinition());
.setLanguage("xoo")
.setDefRemediationFunction(null)
.setDefRemediationGapMultiplier(null)
- .setDefRemediationBaseEffort(null);
+ .setDefRemediationBaseEffort(null)
+ .setScope(Scope.ALL);
RuleDao ruleDao = dbClient.ruleDao();
DbSession session = dbTester.getSession();
ruleDao.insert(session, ruleDto);
.setDefRemediationBaseEffort("11h")
.setRemediationFunction("LINEAR_OFFSET")
.setRemediationGapMultiplier("5d")
- .setRemediationBaseEffort("10h");
+ .setRemediationBaseEffort("10h")
+ .setScope(Scope.ALL);
RuleDao ruleDao = dbClient.ruleDao();
DbSession session = dbTester.getSession();
ruleDao.insert(session, ruleDto.getDefinition());
.setLanguage("xoo")
.setType(RuleType.BUG)
.setCreatedAt(new Date().getTime())
- .setUpdatedAt(new Date().getTime());
+ .setUpdatedAt(new Date().getTime())
+ .setScope(Scope.ALL);
RuleDao ruleDao = dbClient.ruleDao();
DbSession session = dbTester.getSession();
ruleDao.insert(session, ruleDto);
REMOVED = 3;
}
+enum RuleScope {
+ MAIN = 0;
+ TEST = 1;
+ ALL = 2;
+}
+
// Lines start at 1 and line offsets start at 0
message TextRange {
// Start line. Should never be absent
optional string remFnBaseEffort = 43;
optional bool remFnOverloaded = 45;
optional string gapDescription = 44;
+ optional sonarqube.ws.commons.RuleScope scope = 46;
optional sonarqube.ws.commons.RuleType type = 37;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
-import org.sonarqube.tests.Category6Suite;
import org.sonarqube.qa.util.Tester;
+import org.sonarqube.tests.Category6Suite;
+import org.sonarqube.ws.Common.RuleScope;
import org.sonarqube.ws.Organizations.Organization;
import org.sonarqube.ws.Qualityprofiles.CreateWsResponse;
import org.sonarqube.ws.Qualityprofiles.SearchWsResponse;
import org.sonarqube.ws.Rules;
+import org.sonarqube.ws.Rules.ShowResponse;
import org.sonarqube.ws.client.rules.SearchRequest;
+import org.sonarqube.ws.client.rules.ShowRequest;
import static org.assertj.core.api.Assertions.assertThat;
private static final String RULE_HAS_TAG = "xoo:HasTag";
private static final String RULE_ONE_ISSUE_PER_LINE = "xoo:OneIssuePerLine";
private static final String RULE_ONE_ISSUE_PER_FILE = "xoo:OneIssuePerFile";
+ private static final String RULE_ONE_ISSUE_PER_TEST_FILE = "xoo:OneIssuePerTestFile";
private static final String RULE_ONE_BUG_PER_LINE = "xoo:OneBugIssuePerLine";
private static final String PROFILE_SONAR_WAY = "Sonar way";
private static final String LANGUAGE_XOO = "xoo";
.containsExactlyInAnyOrder(RULE_HAS_TAG, RULE_ONE_ISSUE_PER_FILE);
}
+ @Test
+ public void show_rule_with_test_scope() {
+ ShowResponse show = tester.wsClient().rules().show(new ShowRequest().setKey(RULE_ONE_ISSUE_PER_TEST_FILE));
+ assertThat(show.getRule().getScope()).isEqualTo(RuleScope.TEST);
+
+ }
+
private SearchWsResponse.QualityProfile getProfile(Organization organization, Predicate<SearchWsResponse.QualityProfile> filter) {
return tester.qProfiles().service().search(new org.sonarqube.ws.client.qualityprofiles.SearchRequest()
.setOrganization(organization.getKey())).getProfilesList()