*/
package org.sonar.batch.protocol.input;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
public class Rule {
private final String key;
private final String repo;
private final String internalKey;
private final String name;
- private final String severity;
- private final String lang;
- public Rule(String ruleKey, String repositoryKey, String internalKey, String name, @Nullable String severity, @Nullable String language) {
+ public Rule(String ruleKey, String repositoryKey, String internalKey, String name) {
this.key = ruleKey;
this.repo = repositoryKey;
this.internalKey = internalKey;
this.name = name;
- this.severity = severity;
- this.lang = language;
}
public String ruleKey() {
return name;
}
- /**
- * Is null on manual rules
- */
- @CheckForNull
- public String severity() {
- return severity;
- }
-
- /**
- * Is null on manual rules
- */
- @CheckForNull
- public String language() {
- return lang;
- }
-
}
public class RulesSearchResultTest {
@Test
public void testJsonParsing() {
- Rule rule1 = new Rule("squid:S1194", "squid", "S1194", "\"java.lang.Error\" should not be extended", "MAJOR", "java");
+ Rule rule1 = new Rule("squid:S1194", "squid", "S1194", "\"java.lang.Error\" should not be extended");
Rule rule2 = new Rule("squid:ObjectFinalizeOverridenCallsSuperFinalizeCheck", "squid", "ObjectFinalizeOverridenCallsSuperFinalizeCheck",
- "super.finalize() should be called at the end of Object.finalize() implementations", "BLOCKER", "java");
+ "super.finalize() should be called at the end of Object.finalize() implementations");
RulesSearchResult rules = new RulesSearchResult();
rules.setRules(Lists.newArrayList(rule1, rule2));
* @since 4.4
*/
public Batch executeTask(Map<String, String> analysisProperties, Object... components) {
- if (!started) {
- throw new IllegalStateException("Batch is not started. Unable to execute task.");
- }
+ checkStarted();
+ bootstrapContainer.executeAnalysis(analysisProperties, components);
+ return this;
+ }
+ /**
+ * @since 5.2
+ */
+ public Batch executeTask(Map<String, String> analysisProperties) {
+ checkStarted();
bootstrapContainer.executeAnalysis(analysisProperties, components);
return this;
}
+ /**
+ * @since 5.2
+ */
+ public Batch executeTask(Map<String, String> analysisProperties, IssueListener issueListener) {
+ checkStarted();
+ components.add(issueListener);
+ bootstrapContainer.executeAnalysis(analysisProperties, components);
+ return this;
+ }
+
+ private void checkStarted() {
+ if (!started) {
+ throw new IllegalStateException("Batch is not started. Unable to execute task.");
+ }
+ }
+
/**
* @since 4.4
*/
}
private void doStop(boolean swallowException) {
- if (!started) {
- throw new IllegalStateException("Batch is not started.");
- }
-
+ checkStarted();
bootstrapContainer.stopComponents(swallowException);
-
this.started = false;
}
--- /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.bootstrapper;
+
+import org.sonar.api.issue.Issue;
+
+public interface IssueListener {
+ void handle(Issue issue);
+}
--- /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.issue;
+
+import org.sonar.batch.bootstrapper.IssueListener;
+
+import org.sonar.core.issue.DefaultIssue;
+
+public class DefaultIssueCallback implements IssueCallback {
+ private final IssueCache issues;
+ private final IssueListener listener;
+
+ public DefaultIssueCallback(IssueCache issues, IssueListener listener) {
+ this.issues = issues;
+ this.listener = listener;
+ }
+
+ /**
+ * If no listener exists, this constructor will be used by pico.
+ */
+ public DefaultIssueCallback(IssueCache issues) {
+ this(issues, null);
+ }
+
+ @Override
+ public void execute() {
+ if (listener == null) {
+ return;
+ }
+
+ for (DefaultIssue issue : issues.all()) {
+ listener.handle(issue);
+ }
+ }
+}
@Override
public boolean apply(@Nullable DefaultIssue issue) {
if (issue != null) {
- return resolved ? issue.resolution() != null : issue.resolution() == null;
+ return resolved ? (issue.resolution() != null) : (issue.resolution() == null);
}
return false;
}
--- /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.issue;
+
+public interface IssueCallback {
+ void execute();
+}
*/
package org.sonar.batch.mediumtest;
-import org.sonar.api.server.rule.RulesDefinition.Repository;
+import org.sonar.batch.bootstrapper.IssueListener;
+import org.sonar.api.server.rule.RulesDefinition.Repository;
import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.batch.protocol.input.RulesSearchResult;
import org.sonar.batch.rule.RulesLoader;
List<Repository> repositories = context.repositories();
for (Repository repo : repositories) {
for (RulesDefinition.Rule rule : repo.rules()) {
- this.addRule(new Rule(rule.repository().key() + ":" + rule.key(), rule.repository().key(), rule.internalKey(), rule.name(), rule.severity(), repo.language()));
+ this.addRule(new Rule(rule.repository().key() + ":" + rule.key(), rule.repository().key(), rule.internalKey(), rule.name()));
}
}
return this;
public static class TaskBuilder {
private final Map<String, String> taskProperties = new HashMap<>();
private BatchMediumTester tester;
+ private IssueListener issueListener = null;
public TaskBuilder(BatchMediumTester tester) {
this.tester = tester;
TaskResult result = new TaskResult();
Map<String, String> props = new HashMap<>();
props.putAll(taskProperties);
- tester.batch.executeTask(props, result);
+ if (issueListener != null) {
+ tester.batch.executeTask(props, result, issueListener);
+ } else {
+ tester.batch.executeTask(props, result);
+ }
return result;
}
taskProperties.put(key, value);
return this;
}
+
+ public TaskBuilder setIssueListener(IssueListener issueListener) {
+ this.issueListener = issueListener;
+ return this;
+ }
}
private static class FakeRulesLoader implements RulesLoader {
*/
package org.sonar.batch.phases;
-import org.sonar.batch.scan.ProjectAnalysisMode;
+import org.sonar.batch.issue.IssueCallback;
+import org.sonar.batch.scan.ProjectAnalysisMode;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.resources.Project;
import org.sonar.batch.events.BatchStepEvent;
private final IssuesReports issuesReport;
private final ProjectAnalysisMode analysisMode;
private final LocalIssueTracking localIssueTracking;
+ private final IssueCallback issueCallback;
public PhaseExecutor(InitializersExecutor initializersExecutor, PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
SensorContext sensorContext, DefaultIndex index,
EventBus eventBus, ReportPublisher reportPublisher, ProjectInitializer pi,
FileSystemLogger fsLogger, IssuesReports jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
- IssueExclusionsLoader issueExclusionsLoader, ProjectAnalysisMode analysisMode, LocalIssueTracking localIssueTracking) {
+ IssueExclusionsLoader issueExclusionsLoader, ProjectAnalysisMode analysisMode, LocalIssueTracking localIssueTracking, IssueCallback issueCallback) {
this.postJobsExecutor = postJobsExecutor;
this.initializersExecutor = initializersExecutor;
this.sensorsExecutor = sensorsExecutor;
this.issueExclusionsLoader = issueExclusionsLoader;
this.analysisMode = analysisMode;
this.localIssueTracking = localIssueTracking;
+ this.issueCallback = issueCallback;
}
/**
if (module.isRoot()) {
if (analysisMode.isPreview()) {
localIssueTracking();
+ issuesCallback();
}
issuesReport();
publishReportJob();
eventBus.fireEvent(new BatchStepEvent(stepName, false));
}
+ private void issuesCallback() {
+ String stepName = "Issues Callback";
+ eventBus.fireEvent(new BatchStepEvent(stepName, true));
+ issueCallback.execute();
+ eventBus.fireEvent(new BatchStepEvent(stepName, false));
+ }
+
private void issuesReport() {
String stepName = "Issues Reports";
eventBus.fireEvent(new BatchStepEvent(stepName, true));
import org.sonar.batch.bootstrap.WSLoader;
public class DefaultRulesLoader implements RulesLoader {
- private static final String RULES_SEARCH_URL = "/api/rules/search?ps=500&f=repo,name,internalKey,severity,lang";
+ private static final String RULES_SEARCH_URL = "/api/rules/search?ps=500&f=repo,name,internalKey";
private final WSLoader wsLoader;
for (Rule inputRule : ref.load().getRules()) {
NewRule newRule = builder.add(RuleKey.parse(inputRule.ruleKey()));
newRule.setName(inputRule.name());
- newRule.setSeverity(inputRule.severity());
newRule.setInternalKey(inputRule.internalKey());
}
*/
package org.sonar.batch.scan;
+import org.sonar.batch.issue.DefaultIssueCallback;
+
import com.google.common.annotations.VisibleForTesting;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.InstantiationStrategy;
DefaultFileLinesContextFactory.class,
Caches.class,
BatchComponentCache.class,
+ DefaultIssueCallback.class,
// temp
new ProjectTempFolderProvider(),
private void exportResults(String exportPath) {
File exportFile = new File(fileSystem.workDir(), exportPath);
- LOG.info("Export issues to " + exportFile.getAbsolutePath());
+ LOG.info("Export issues to {}", exportFile.getAbsolutePath());
try (Writer output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(exportFile), StandardCharsets.UTF_8))) {
writeJson(output);
json.endArray();
}
- private void writeJsonModuleComponents(JsonWriter json, Project module) {
+ private static void writeJsonModuleComponents(JsonWriter json, Project module) {
json
.beginObject()
.prop("key", module.getEffectiveKey())
@BatchSide
public interface Reporter {
- public void execute();
+ void execute();
}
--- /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.issue;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import org.sonar.batch.bootstrapper.IssueListener;
+import org.junit.Before;
+import com.google.common.collect.ImmutableList;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.api.issue.Issue;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+
+public class DefaultIssueCallbackTest {
+ private IssueCache issueCache;
+ private DefaultIssue issue;
+
+ @Before
+ public void setUp() {
+ issue = new DefaultIssue();
+ issue.setKey("key");
+
+ issueCache = mock(IssueCache.class);
+ when(issueCache.all()).thenReturn(ImmutableList.of(issue));
+ }
+
+ @Test
+ public void testWithoutListener() {
+ DefaultIssueCallback issueCallback = new DefaultIssueCallback(issueCache);
+ issueCallback.execute();
+ }
+
+ @Test
+ public void testWithListener() {
+ final List<Issue> issueList = new LinkedList<>();
+ IssueListener listener = new IssueListener() {
+ @Override
+ public void handle(Issue issue) {
+ issueList.add(issue);
+ }
+ };
+
+ DefaultIssueCallback issueCallback = new DefaultIssueCallback(issueCache, listener);
+ issueCallback.execute();
+
+ assertThat(issueList).containsExactly(issue);
+ }
+
+}
.registerPlugin("xoo", new XooPlugin())
.addRules(new XooRulesDefinition())
.addDefaultQProfile("xoo", "Sonar Way")
- .addRule(new Rule("xoo:TemplateRule_1234", "xoo", "TemplateRule_1234", "A template rule", "MAJOR", "xoo"))
- .addRule(new Rule("xoo:TemplateRule_1235", "xoo", "TemplateRule_1235", "Another template rule", "MAJOR", "xoo"))
+ .addRule(new Rule("xoo:TemplateRule_1234", "xoo", "TemplateRule_1234", "A template rule"))
+ .addRule(new Rule("xoo:TemplateRule_1235", "xoo", "TemplateRule_1235", "Another template rule"))
.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"))
.build();
*/
package org.sonar.batch.mediumtest.issues;
+import org.sonar.api.issue.Issue;
+import org.sonar.batch.bootstrapper.IssueListener;
import org.sonar.xoo.rule.XooRulesDefinition;
-
import com.google.common.collect.ImmutableMap;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import java.io.File;
import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
.addRules(new XooRulesDefinition())
.activateRule(new ActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "OneIssuePerLine.internal", "xoo"))
.build();
+
+ public BatchMediumTester testerPreview = BatchMediumTester.builder()
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way")
+ .bootstrapProperties(ImmutableMap.of("sonar.analysis.mode", "preview"))
+ .addRules(new XooRulesDefinition())
+ .activateRule(new ActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "OneIssuePerLine.internal", "xoo"))
+ .build();
@Before
public void prepare() {
tester.start();
+ testerPreview.start();
}
@After
public void stop() {
tester.stop();
+ testerPreview.stop();
+ }
+
+ @Test
+ public void testIssueCallback() throws Exception {
+ File projectDir = new File(IssuesMediumTest.class.getResource("/mediumtest/xoo/sample").toURI());
+ File tmpDir = temp.newFolder();
+ FileUtils.copyDirectory(projectDir, tmpDir);
+ IssueRecorder issueListener = new IssueRecorder();
+
+ TaskResult result = testerPreview
+ .newScanTask(new File(tmpDir, "sonar-project.properties"))
+ .setIssueListener(issueListener)
+ .property("sonar.analysis.mode", "preview")
+ .start();
+
+ assertThat(result.issues()).hasSize(14);
+ assertThat(issueListener.issueList).hasSize(14);
+
+ assertThat(result.issues()).containsExactlyElementsOf(issueListener.issueList);
+ }
+
+ @Test
+ public void testNoIssueCallbackInNonPreview() throws Exception {
+ File projectDir = new File(IssuesMediumTest.class.getResource("/mediumtest/xoo/sample").toURI());
+ File tmpDir = temp.newFolder();
+ FileUtils.copyDirectory(projectDir, tmpDir);
+ IssueRecorder issueListener = new IssueRecorder();
+
+ TaskResult result = tester
+ .newScanTask(new File(tmpDir, "sonar-project.properties"))
+ .setIssueListener(issueListener)
+ .start();
+
+ assertThat(result.issues()).hasSize(14);
+ assertThat(issueListener.issueList).hasSize(0);
}
@Test
assertThat(foundIssueAtLine1).isTrue();
}
+ private class IssueRecorder implements IssueListener {
+ List<Issue> issueList = new LinkedList<>();
+
+ @Override
+ public void handle(Issue issue) {
+ issueList.add(issue);
+ }
+ }
}
public BatchMediumTester tester = BatchMediumTester.builder()
.registerPlugin("xoo", new XooPlugin())
.addRules(new XooRulesDefinition())
- .addRule(new Rule("xoo:MultilineIssue", "xoo", null, "Multinile Issue", "MAJOR", "xoo"))
+ .addRule(new Rule("xoo:MultilineIssue", "xoo", null, "Multinile Issue"))
.addDefaultQProfile("xoo", "Sonar Way")
.activateRule(new ActiveRule("xoo", "MultilineIssue", null, "Multinile Issue", "MAJOR", null, "xoo"))
.build();
.registerPlugin("xoo", new XooPlugin())
.addDefaultQProfile("xoo", "Sonar Way")
.addRules(new XooRulesDefinition())
- .addRule(new Rule("manual:MyManualIssue", "manual", "MyManualIssue", "My manual issue", "MAJOR", null))
- .addRule(new Rule("manual:MyManualIssueDup", "manual", "MyManualIssue", "My manual issue", "MAJOR", null))
+ .addRule(new Rule("manual:MyManualIssue", "manual", "MyManualIssue", "My manual issue"))
+ .addRule(new Rule("manual:MyManualIssueDup", "manual", "MyManualIssue", "My manual issue"))
.activateRule(new ActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", null, "xoo"))
.activateRule(new ActiveRule("manual", "MyManualIssue", null, "My manual issue", "MAJOR", null, null))
.setPreviousAnalysisDate(new Date())
public class DefaultRulesLoaderTest {
@Test
public void testLoadingJson() throws IOException {
- Rule rule1 = new Rule("squid:S1194", "squid", "S1194", "\"java.lang.Error\" should not be extended", "MAJOR", "java");
+ Rule rule1 = new Rule("squid:S1194", "squid", "S1194", "\"java.lang.Error\" should not be extended");
Rule rule2 = new Rule("squid:ObjectFinalizeOverridenCallsSuperFinalizeCheck", "squid", "ObjectFinalizeOverridenCallsSuperFinalizeCheck",
- "super.finalize() should be called at the end of Object.finalize() implementations", "BLOCKER", "java");
+ "super.finalize() should be called at the end of Object.finalize() implementations");
// generate json
RulesSearchResult rulesSearch = new RulesSearchResult();
public class RulesProviderTest {
@Test
public void testRuleTranslation() {
- final Rule testRule = new Rule("repo1:key1", "repo1", "key1", "name", "severity", "language");
+ final Rule testRule = new Rule("repo1:key1", "repo1", "key1", "name");
RulesSearchResult loadResult = new RulesSearchResult();
loadResult.setRules(Arrays.asList(testRule));
return value.key().rule().equals(testRule.internalKey()) &&
value.internalKey().equals(testRule.internalKey()) &&
value.name().equals(testRule.name()) &&
- value.severity().equals(testRule.severity()) &&
value.key().repository().equals(testRule.repositoryKey());
}
});