import org.sonar.xoo.lang.SyntaxHighlightingSensor;
import org.sonar.xoo.lang.TestCaseSensor;
import org.sonar.xoo.lang.XooTokenizerSensor;
+import org.sonar.xoo.rule.ChecksSensor;
import org.sonar.xoo.rule.CreateIssueByInternalKeySensor;
import org.sonar.xoo.rule.OneIssueOnDirPerFileSensor;
import org.sonar.xoo.rule.OneIssuePerLineSensor;
TestCaseSensor.class,
CoveragePerTestSensor.class,
DependencySensor.class,
+ ChecksSensor.class,
OneIssuePerLineSensor.class,
OneIssueOnDirPerFileSensor.class,
CreateIssueByInternalKeySensor.class
);
}
-
}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.checks;
+
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.rule.RuleKey;
+
+public interface Check {
+
+ public Class<Check>[] ALL = new Class[] {TemplateRuleCheck.class};
+
+ void execute(SensorContext context, InputFile file, RuleKey ruleKey);
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.checks;
+
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.check.Cardinality;
+import org.sonar.check.Rule;
+import org.sonar.check.RuleProperty;
+
+@Rule(key = TemplateRuleCheck.RULE_KEY, cardinality = Cardinality.MULTIPLE, name = "Template rule", description = "Sample template rule")
+public class TemplateRuleCheck implements Check {
+
+ public static final String RULE_KEY = "TemplateRule";
+
+ @RuleProperty(key = "line")
+ private int line;
+
+ @Override
+ public void execute(SensorContext sensorContext, InputFile file, RuleKey ruleKey) {
+ sensorContext.newIssue()
+ .onFile(file)
+ .ruleKey(ruleKey)
+ .atLine(line)
+ .save();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 org.sonar.api.batch.fs.FilePredicates;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputFile.Type;
+import org.sonar.api.batch.rule.CheckFactory;
+import org.sonar.api.batch.rule.Checks;
+import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.xoo.Xoo;
+import org.sonar.xoo.checks.Check;
+
+public class ChecksSensor implements Sensor {
+
+ private final CheckFactory checkFactory;
+
+ public ChecksSensor(CheckFactory checkFactory) {
+ this.checkFactory = checkFactory;
+ }
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ descriptor
+ .name("ChecksSensor")
+ .workOnLanguages(Xoo.KEY)
+ .createIssuesForRuleRepositories(XooRulesDefinition.XOO_REPOSITORY)
+ .workOnFileTypes(InputFile.Type.MAIN);
+ }
+
+ @Override
+ public void execute(SensorContext context) {
+ Checks<Check> checks = checkFactory.create(XooRulesDefinition.XOO_REPOSITORY);
+ checks.addAnnotatedChecks(Check.ALL);
+ FilePredicates p = context.fileSystem().predicates();
+ for (InputFile file : context.fileSystem().inputFiles(p.and(p.hasLanguages(Xoo.KEY), p.hasType(Type.MAIN)))) {
+ for (Check check : checks.all()) {
+ check.execute(context, file, checks.ruleKey(check));
+ }
+ }
+ }
+
+}
import org.sonar.api.rule.Severity;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.api.server.rule.RulesDefinitionAnnotationLoader;
import org.sonar.xoo.Xoo;
+import org.sonar.xoo.checks.Check;
/**
* Define all the coding rules that are supported on the repository named "xoo".
public void define(Context context) {
NewRepository repository = context.createRepository(XOO_REPOSITORY, Xoo.KEY).setName("Xoo");
+ // Load checks
+ new RulesDefinitionAnnotationLoader().load(repository, Check.ALL);
+
// define a single rule programmatically. Note that rules
// can be loaded from JSON or XML files too.
NewRule x1Rule = repository.createRule("x1")
@Test
public void provide_extensions() {
- assertThat(new XooPlugin().getExtensions()).hasSize(18);
+ assertThat(new XooPlugin().getExtensions()).hasSize(19);
}
}
assertThat(repo).isNotNull();
assertThat(repo.name()).isEqualTo("Xoo");
assertThat(repo.language()).isEqualTo("xoo");
- assertThat(repo.rules()).hasSize(1);
+ assertThat(repo.rules()).hasSize(2);
RulesDefinition.Rule x1 = repo.rule("x1");
assertThat(x1.key()).isEqualTo("x1");
newActiveRule.setSeverity(activeRule.severity());
newActiveRule.setLanguage(activeRule.language());
newActiveRule.setInternalKey(activeRule.internalKey());
+ newActiveRule.setTemplateRuleKey(activeRule.templateRuleKey());
// load parameters
for (Entry<String, String> param : activeRule.params().entrySet()) {
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch.mediumtest.issues;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.commons.io.FileUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.sensor.issue.Issue;
+import org.sonar.batch.mediumtest.BatchMediumTester;
+import org.sonar.batch.mediumtest.BatchMediumTester.TaskResult;
+import org.sonar.batch.protocol.input.ActiveRule;
+import org.sonar.xoo.XooPlugin;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class ChecksMediumTest {
+
+ @org.junit.Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ public BatchMediumTester tester = BatchMediumTester.builder()
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way")
+ .activateRule(new ActiveRule("xoo", "TemplateRule_1234", "TemplateRule", "A template rule", "MAJOR", null, "xoo").addParam("line", "1"))
+ .activateRule(new ActiveRule("xoo", "TemplateRule_1235", "TemplateRule", "Another template rule", "MAJOR", null, "xoo").addParam("line", "2"))
+ .bootstrapProperties(ImmutableMap.of("sonar.analysis.mode", "sensor"))
+ .build();
+
+ @Before
+ public void prepare() {
+ tester.start();
+ }
+
+ @After
+ public void stop() {
+ tester.stop();
+ }
+
+ @Test
+ public void testCheckWithTemplate() throws IOException {
+
+ File baseDir = temp.newFolder();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "foo");
+
+ TaskResult result = tester.newTask()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .build())
+ .start();
+
+ assertThat(result.issues()).hasSize(2);
+
+ boolean foundIssueAtLine1 = false;
+ boolean foundIssueAtLine2 = false;
+ for (Issue issue : result.issues()) {
+ if (issue.line() == 1) {
+ foundIssueAtLine1 = true;
+ assertThat(issue.inputPath()).isEqualTo(new DefaultInputFile("com.foo.project", "src/sample.xoo"));
+ assertThat(issue.message()).isEqualTo("A template rule");
+ }
+ if (issue.line() == 2) {
+ foundIssueAtLine2 = true;
+ assertThat(issue.inputPath()).isEqualTo(new DefaultInputFile("com.foo.project", "src/sample.xoo"));
+ assertThat(issue.message()).isEqualTo("Another template rule");
+ }
+ }
+ assertThat(foundIssueAtLine1).isTrue();
+ assertThat(foundIssueAtLine2).isTrue();
+ }
+
+}
*/
@CheckForNull
String internalKey();
+
+ /**
+ * Optional rule key of the template rule.
+ * @since 4.5.3
+ */
+ @CheckForNull
+ String templateRuleKey();
}
import org.sonar.check.RuleProperty;
import javax.annotation.CheckForNull;
+
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
}
for (ActiveRule activeRule : activeRules.findByRepository(repository)) {
- String engineKey = StringUtils.defaultIfBlank(activeRule.internalKey(), activeRule.ruleKey().rule());
+ String engineKey = StringUtils.defaultIfBlank(activeRule.templateRuleKey(), activeRule.ruleKey().rule());
Object checkClassesOrObject = checksByEngineKey.get(engineKey);
- Object obj = instantiate(activeRule, checkClassesOrObject);
- add(activeRule.ruleKey(), (C) obj);
+ if (checkClassesOrObject != null) {
+ Object obj = instantiate(activeRule, checkClassesOrObject);
+ add(activeRule.ruleKey(), (C) obj);
+ }
}
return this;
}
public class DefaultActiveRule implements ActiveRule {
private final RuleKey ruleKey;
private final String name;
- private final String severity, internalKey, language;
+ private final String severity, internalKey, language, templateRuleKey;
private final Map<String, String> params;
DefaultActiveRule(NewActiveRule newActiveRule) {
this.severity = newActiveRule.severity;
this.name = newActiveRule.name;
this.internalKey = newActiveRule.internalKey;
+ this.templateRuleKey = newActiveRule.templateRuleKey;
this.ruleKey = newActiveRule.ruleKey;
this.params = ImmutableMap.copyOf(newActiveRule.params);
this.language = newActiveRule.language;
public String internalKey() {
return internalKey;
}
+
+ @Override
+ public String templateRuleKey() {
+ return templateRuleKey;
+ }
}
String name;
String severity = Severity.defaultSeverity();
Map<String, String> params = new HashMap<String, String>();
- String internalKey, language;
+ String internalKey, language, templateRuleKey;
private final ActiveRulesBuilder builder;
NewActiveRule(ActiveRulesBuilder builder, RuleKey ruleKey) {
return this;
}
+ public NewActiveRule setTemplateRuleKey(@Nullable String templateRuleKey) {
+ this.templateRuleKey = templateRuleKey;
+ return this;
+ }
+
public NewActiveRule setLanguage(@Nullable String language) {
this.language = language;
return this;
}
@Test
- public void use_engine_key() {
- RuleKey ruleKey = RuleKey.of("squid", "One");
- builder.create(ruleKey).setInternalKey("S0001").activate();
+ public void use_template_rule_key() {
+ RuleKey ruleKey = RuleKey.of("squid", "S0001_123");
+ builder.create(ruleKey).setTemplateRuleKey("S0001").activate();
CheckFactory checkFactory = new CheckFactory(builder.build());
Checks checks = checkFactory.create("squid").addAnnotatedChecks(CheckWithKey.class);