public void describe(SensorDescriptor descriptor) {
descriptor
.name("Xoo Coverage Per Test Sensor")
- .workOnLanguages(Xoo.KEY)
- .workOnFileTypes(InputFile.Type.TEST);
+ .onlyOnLanguages(Xoo.KEY)
+ .onlyOnFileType(InputFile.Type.TEST);
}
@Override
public void describe(SensorDescriptor descriptor) {
descriptor
.name("Xoo Dependency Sensor")
- .workOnLanguages(Xoo.KEY)
- .workOnFileTypes(InputFile.Type.MAIN);
+ .onlyOnLanguages(Xoo.KEY)
+ .onlyOnFileType(InputFile.Type.MAIN);
}
@Override
descriptor
.name("Xoo Measure Sensor")
.provides(CoreMetrics.LINES)
- .workOnLanguages(Xoo.KEY)
- .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST);
+ .onlyOnLanguages(Xoo.KEY)
+ .onOnFileType(InputFile.Type.MAIN, InputFile.Type.TEST);
}
@Override
public void describe(SensorDescriptor descriptor) {
descriptor
.name("Xoo Symbol Reference Sensor")
- .workOnLanguages(Xoo.KEY)
- .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST);
+ .onlyOnLanguages(Xoo.KEY)
+ .onOnFileType(InputFile.Type.MAIN, InputFile.Type.TEST);
}
@Override
public void describe(SensorDescriptor descriptor) {
descriptor
.name("Xoo Highlighting Sensor")
- .workOnLanguages(Xoo.KEY)
- .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST);
+ .onlyOnLanguages(Xoo.KEY)
+ .onOnFileType(InputFile.Type.MAIN, InputFile.Type.TEST);
}
@Override
public void describe(SensorDescriptor descriptor) {
descriptor
.name("Xoo TestPlan Sensor")
- .workOnLanguages(Xoo.KEY)
- .workOnFileTypes(InputFile.Type.TEST);
+ .onlyOnLanguages(Xoo.KEY)
+ .onlyOnFileType(InputFile.Type.TEST);
}
@Override
public void describe(SensorDescriptor descriptor) {
descriptor
.name("Xoo Tokenizer Sensor")
- .workOnLanguages(Xoo.KEY)
- .workOnFileTypes(InputFile.Type.MAIN);
+ .onlyOnLanguages(Xoo.KEY)
+ .onlyOnFileType(InputFile.Type.MAIN);
}
@Override
public void describe(SensorDescriptor descriptor) {
descriptor
.name("CreateIssueByInternalKeySensor")
- .workOnLanguages(Xoo.KEY)
+ .onlyOnLanguages(Xoo.KEY)
.createIssuesForRuleRepositories(XooRulesDefinition.XOO_REPOSITORY)
- .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST);
+ .onOnFileType(InputFile.Type.MAIN, InputFile.Type.TEST);
}
@Override
public void describe(SensorDescriptor descriptor) {
descriptor
.name("One Issue On Dir Per File")
- .workOnLanguages(Xoo.KEY)
+ .onlyOnLanguages(Xoo.KEY)
.createIssuesForRuleRepositories(XooRulesDefinition.XOO_REPOSITORY)
- .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST);
+ .onOnFileType(InputFile.Type.MAIN, InputFile.Type.TEST);
}
@Override
descriptor
.name("One Issue Per Line")
.dependsOn(CoreMetrics.LINES)
- .workOnLanguages(Xoo.KEY)
+ .onlyOnLanguages(Xoo.KEY)
.createIssuesForRuleRepositories(XooRulesDefinition.XOO_REPOSITORY)
- .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST);
+ .onOnFileType(InputFile.Type.MAIN, InputFile.Type.TEST);
}
@Override
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.DependedUpon;
-import org.sonar.api.batch.DependsUpon;
-import org.sonar.api.batch.measure.Metric;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
import org.sonar.api.resources.Project;
import org.sonar.batch.scan2.AnalyzerOptimizer;
-import java.util.Arrays;
-import java.util.List;
-
public class SensorWrapper implements org.sonar.api.batch.Sensor {
private static final Logger LOG = LoggerFactory.getLogger(SensorWrapper.class);
return wrappedSensor;
}
- @DependedUpon
- public List<Metric> provides() {
- return Arrays.asList(descriptor.provides());
- }
-
- @DependsUpon
- public List<Metric> depends() {
- return Arrays.asList(descriptor.dependsOn());
- }
-
@Override
public boolean shouldExecuteOnProject(Project project) {
return optimizer.shouldExecute(descriptor);
import org.sonar.api.BatchComponent;
import org.sonar.api.batch.fs.FilePredicate;
import org.sonar.api.batch.fs.FileSystem;
-import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
+import org.sonar.api.config.Settings;
public class AnalyzerOptimizer implements BatchComponent {
private final FileSystem fs;
private final ActiveRules activeRules;
+ private final Settings settings;
- public AnalyzerOptimizer(FileSystem fs, ActiveRules activeRules) {
+ public AnalyzerOptimizer(FileSystem fs, ActiveRules activeRules, Settings settings) {
this.fs = fs;
this.activeRules = activeRules;
+ this.settings = settings;
}
/**
LOG.debug("'{}' skipped because there is no related rule activated in the quality profile", descriptor.name());
return false;
}
+ if (!settingsCondition(descriptor)) {
+ LOG.debug("'{}' skipped because one of the required properties is missing", descriptor.name());
+ return false;
+ }
+ return true;
+ }
+
+ private boolean settingsCondition(DefaultSensorDescriptor descriptor) {
+ if (!descriptor.properties().isEmpty()) {
+ for (String propertyKey : descriptor.properties()) {
+ if (!settings.hasKey(propertyKey)) {
+ return false;
+ }
+ }
+ }
return true;
}
}
private boolean fsCondition(DefaultSensorDescriptor descriptor) {
- if (!descriptor.languages().isEmpty() || !descriptor.types().isEmpty()) {
+ if (!descriptor.languages().isEmpty() || descriptor.type() != null) {
FilePredicate langPredicate = descriptor.languages().isEmpty() ? fs.predicates().all() : fs.predicates().hasLanguages(descriptor.languages());
- FilePredicate typePredicate = descriptor.types().isEmpty() ? fs.predicates().all() : fs.predicates().none();
- for (InputFile.Type type : descriptor.types()) {
- typePredicate = fs.predicates().or(
- typePredicate,
- fs.predicates().hasType(type));
- }
+ FilePredicate typePredicate = descriptor.type() == null ? fs.predicates().all() : fs.predicates().hasType(descriptor.type());
return fs.hasFiles(fs.predicates().and(langPredicate, typePredicate));
}
return true;
@Override
public void describe(SensorDescriptor descriptor) {
- descriptor
- .name("SCM Sensor")
- .provides(CoreMetrics.SCM_AUTHORS_BY_LINE,
- CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE,
- CoreMetrics.SCM_REVISIONS_BY_LINE);
+ descriptor.name("SCM Sensor");
}
@Override
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
+import org.sonar.api.config.Settings;
import org.sonar.api.rule.RuleKey;
import static org.assertj.core.api.Assertions.assertThat;
public ExpectedException thrown = ExpectedException.none();
private AnalyzerOptimizer optimizer;
+ private Settings settings;
+
@Before
public void prepare() {
- optimizer = new AnalyzerOptimizer(fs, new ActiveRulesBuilder().build());
+ settings = new Settings();
+ optimizer = new AnalyzerOptimizer(fs, new ActiveRulesBuilder().build(), settings);
}
@Test
@Test
public void should_optimize_on_language() throws Exception {
DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor()
- .workOnLanguages("java", "php");
+ .onlyOnLanguages("java", "php");
assertThat(optimizer.shouldExecute(descriptor)).isFalse();
fs.add(new DefaultInputFile("foo", "src/Foo.java").setLanguage("java"));
@Test
public void should_optimize_on_type() throws Exception {
DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor()
- .workOnFileTypes(InputFile.Type.MAIN);
+ .onlyOnFileType(InputFile.Type.MAIN);
assertThat(optimizer.shouldExecute(descriptor)).isFalse();
fs.add(new DefaultInputFile("foo", "tests/FooTest.java").setType(InputFile.Type.TEST));
@Test
public void should_optimize_on_both_type_and_language() throws Exception {
DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor()
- .workOnLanguages("java", "php")
- .workOnFileTypes(InputFile.Type.MAIN);
+ .onlyOnLanguages("java", "php")
+ .onlyOnFileType(InputFile.Type.MAIN);
assertThat(optimizer.shouldExecute(descriptor)).isFalse();
fs.add(new DefaultInputFile("foo", "tests/FooTest.java").setLanguage("java").setType(InputFile.Type.TEST));
.create(RuleKey.of("repo1", "foo"))
.activate()
.build();
- optimizer = new AnalyzerOptimizer(fs, activeRules);
+ optimizer = new AnalyzerOptimizer(fs, activeRules, settings);
assertThat(optimizer.shouldExecute(descriptor)).isFalse();
.create(RuleKey.of("squid", "rule"))
.activate()
.build();
- optimizer = new AnalyzerOptimizer(fs, activeRules);
+ optimizer = new AnalyzerOptimizer(fs, activeRules, settings);
+ assertThat(optimizer.shouldExecute(descriptor)).isTrue();
+ }
+
+ @Test
+ public void should_optimize_on_settings() throws Exception {
+ DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor()
+ .requireProperty("sonar.foo.reportPath");
+ assertThat(optimizer.shouldExecute(descriptor)).isFalse();
+
+ settings.setProperty("sonar.foo.reportPath", "foo");
assertThat(optimizer.shouldExecute(descriptor)).isTrue();
}
}
import org.sonar.api.BatchExtension;
import org.sonar.api.batch.maven.DependsUponMavenPlugin;
import org.sonar.api.batch.maven.MavenPluginHandler;
-import org.sonar.api.batch.sensor.Sensor;
-import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
import org.sonar.api.platform.ComponentContainer;
import org.sonar.api.resources.Project;
import org.sonar.api.utils.AnnotationUtils;
private <T> List<Object> getDependencies(T extension) {
List<Object> result = new ArrayList<Object>();
result.addAll(evaluateAnnotatedClasses(extension, DependsUpon.class));
- if (ClassUtils.isAssignable(extension.getClass(), Sensor.class)) {
- DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor();
- ((Sensor) extension).describe(descriptor);
- result.addAll(Arrays.asList(descriptor.dependsOn()));
- }
return result;
}
public <T> List<Object> getDependents(T extension) {
List<Object> result = new ArrayList<Object>();
result.addAll(evaluateAnnotatedClasses(extension, DependedUpon.class));
- if (ClassUtils.isAssignable(extension.getClass(), Sensor.class)) {
- DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor();
- ((Sensor) extension).describe(descriptor);
- result.addAll(Arrays.asList(descriptor.provides()));
- }
return result;
}
package org.sonar.api.batch.sensor;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.measure.Metric;
/**
- * Describe what an {@link Sensor} is doing. Information may be used by the platform
+ * Describe what a {@link Sensor} is doing. Information may be used by the platform
* to log interesting information or perform some optimization.
* See {@link Sensor#describe(SensorDescriptor)}
- * @since 5.0
+ * @since 5.1
*/
public interface SensorDescriptor {
/**
- * Name of the {@link Sensor}. Will be displayed in logs.
+ * Displayable name of the {@link Sensor}. Will be displayed in logs.
*/
- SensorDescriptor name(String name);
+ SensorDescriptor name(String sensorName);
/**
- * List {@link Metric} this {@link Sensor} depends on. Will be used to execute sensors in correct order.
+ * Language this {@link Sensor} work on. Used by the platform to skip execution of the {@link Sensor} when
+ * no file for given languages are present in the project.
+ * Default is to execute sensor for all languages.
*/
- SensorDescriptor dependsOn(Metric<?>... metrics);
+ SensorDescriptor onlyOnLanguage(String languageKey);
/**
- * List {@link Metric} this {@link Sensor} provides. Will be used to execute sensors in correct order.
+ * List languages this {@link Sensor} work on. Used by the platform to skip execution of the {@link Sensor} when
+ * no file for given languages are present in the project.
+ * Default is to execute sensor for all languages.
*/
- SensorDescriptor provides(Metric<?>... metrics);
+ SensorDescriptor onlyOnLanguages(String... languageKeys);
/**
- * List languages this {@link Sensor} work on. May be used by the platform to skip execution of the {@link Sensor} when
- * no file for given languages are present in the project.
- * If no language is provided then it will be executed for all languages.
+ * {@link InputFile.Type} this {@link Sensor} work on. Used by the platform to skip execution of the {@link Sensor} when
+ * no file for given type are present in the project.
+ * Default is to execute sensor whatever are the available file types.
*/
- SensorDescriptor workOnLanguages(String... languageKeys);
+ SensorDescriptor onlyOnFileType(InputFile.Type type);
/**
- * List {@link InputFile.Type} this {@link Sensor} work on. May be used by the platform to skip execution of the {@link Sensor} when
- * no file for given type are present in the project.
- * If you don't call this method then it means sensor is working on all input file types.
+ * Rule repository this {@link Sensor} create issues for. Used by the platform to skip execution of the {@link Sensor} when
+ * no rule is activated for the given repository.
*/
- SensorDescriptor workOnFileTypes(InputFile.Type... types);
+ SensorDescriptor createIssuesForRuleRepository(String... repositoryKey);
/**
- * List {@link InputFile.Type} this {@link Sensor} work on. May be used by the platform to skip execution of the {@link Sensor} when
- * no file for given type are present in the project.
- * If not type is provided then it will be executed for all types.
+ * List rule repositories this {@link Sensor} create issues for. Used by the platform to skip execution of the {@link Sensor} when
+ * no rule is activated for the given repositories.
*/
SensorDescriptor createIssuesForRuleRepositories(String... repositoryKeys);
+ /**
+ * Property this {@link Sensor} depends on. Used by the platform to skip execution of the {@link Sensor} when
+ * property is not set.
+ */
+ SensorDescriptor requireProperty(String... propertyKey);
+
+ /**
+ * List properties this {@link Sensor} depends on. Used by the platform to skip execution of the {@link Sensor} when
+ * property is not set.
+ */
+ SensorDescriptor requireProperties(String... propertyKeys);
+
}
*/
package org.sonar.api.batch.sensor.internal;
+import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.sensor.SensorDescriptor;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.measure.Metric;
+import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Collection;
public class DefaultSensorDescriptor implements SensorDescriptor {
private String name;
- private Metric<?>[] dependsOn = new Metric<?>[0];
- private Metric<?>[] provides = new Metric<?>[0];
private String[] languages = new String[0];
- private InputFile.Type[] types = new InputFile.Type[0];
+ private InputFile.Type type = null;
private String[] ruleRepositories = new String[0];
+ private String[] properties = new String[0];
public String name() {
return name;
}
- public Metric[] dependsOn() {
- return dependsOn;
- }
-
- public Metric[] provides() {
- return provides;
- }
-
public Collection<String> languages() {
return Arrays.asList(languages);
}
- public Collection<InputFile.Type> types() {
- return Arrays.asList(types);
+ @Nullable
+ public InputFile.Type type() {
+ return type;
}
public Collection<String> ruleRepositories() {
return Arrays.asList(ruleRepositories);
}
+ public Collection<String> properties() {
+ return Arrays.asList(properties);
+ }
+
@Override
public DefaultSensorDescriptor name(String name) {
this.name = name;
}
@Override
- public DefaultSensorDescriptor dependsOn(Metric<?>... metrics) {
- this.dependsOn = metrics;
- return this;
+ public DefaultSensorDescriptor onlyOnLanguage(String languageKey) {
+ return onlyOnLanguages(languageKey);
}
@Override
- public DefaultSensorDescriptor provides(Metric<?>... metrics) {
- this.provides = metrics;
+ public DefaultSensorDescriptor onlyOnLanguages(String... languageKeys) {
+ this.languages = languageKeys;
return this;
}
@Override
- public DefaultSensorDescriptor workOnLanguages(String... languageKeys) {
- this.languages = languageKeys;
+ public DefaultSensorDescriptor onlyOnFileType(InputFile.Type type) {
+ this.type = type;
return this;
}
@Override
- public DefaultSensorDescriptor workOnFileTypes(InputFile.Type... types) {
- this.types = types;
- return this;
+ public DefaultSensorDescriptor createIssuesForRuleRepository(String... repositoryKey) {
+ return createIssuesForRuleRepositories(repositoryKey);
}
@Override
return this;
}
+ @Override
+ public DefaultSensorDescriptor requireProperty(String... propertyKey) {
+ return requireProperties(propertyKey);
+ }
+
+ @Override
+ public DefaultSensorDescriptor requireProperties(String... propertyKeys) {
+ this.properties = propertyKeys;
+ return this;
+ }
+
}
*/
package org.sonar.api.batch.sensor.internal;
-import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
-
import org.junit.Test;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.measures.CoreMetrics;
+
import static org.assertj.core.api.Assertions.assertThat;
public class DefaultSensorDescriptorTest {
DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor();
descriptor
.name("Foo")
- .dependsOn(CoreMetrics.NCLOC)
- .provides(CoreMetrics.BLOCKER_VIOLATIONS)
- .workOnLanguages("java", "php")
- .workOnFileTypes(InputFile.Type.MAIN);
+ .onlyOnLanguage("java")
+ .onlyOnFileType(InputFile.Type.MAIN)
+ .requireProperty("sonar.foo.reportPath")
+ .createIssuesForRuleRepository("squid-java");
assertThat(descriptor.name()).isEqualTo("Foo");
- assertThat(descriptor.dependsOn()).containsOnly(CoreMetrics.NCLOC);
- assertThat(descriptor.provides()).containsOnly(CoreMetrics.BLOCKER_VIOLATIONS);
- assertThat(descriptor.languages()).containsOnly("java", "php");
- assertThat(descriptor.types()).containsOnly(InputFile.Type.MAIN);
+ assertThat(descriptor.languages()).containsOnly("java");
+ assertThat(descriptor.type()).isEqualTo(InputFile.Type.MAIN);
+ assertThat(descriptor.properties()).containsOnly("sonar.foo.reportPath");
+ assertThat(descriptor.ruleRepositories()).containsOnly("squid-java");
}
}