import org.sonar.batch.maven.MavenProjectBootstrapper;
import org.sonar.batch.maven.MavenProjectBuilder;
import org.sonar.batch.maven.MavenProjectConverter;
+import org.sonar.batch.scan.report.ConsoleReport;
import org.sonar.batch.scm.ScmConfiguration;
import org.sonar.batch.scm.ScmSensor;
import org.sonar.batch.source.LinesSensor;
LinesSensor.class,
+ // Reports
+ ConsoleReport.class,
+
// dbcleaner
DefaultPeriodCleaner.class,
DefaultPurgeTask.class
import org.sonar.batch.referential.GlobalReferentialsLoader;
import org.sonar.batch.referential.GlobalReferentialsProvider;
import org.sonar.batch.referential.ProjectReferentialsLoader;
+import org.sonar.batch.user.UserRepository;
import org.sonar.core.cluster.NullQueue;
import org.sonar.core.config.Logback;
import org.sonar.core.i18n.DefaultI18n;
UriReader.class,
new FileCacheProvider(),
System2.INSTANCE,
- new GlobalReferentialsProvider());
+ new GlobalReferentialsProvider(),
+ UserRepository.class);
if (getComponentByType(PluginsReferential.class) == null) {
add(DefaultPluginsReferential.class);
}
import org.sonar.batch.scan.filesystem.DefaultModuleFileSystem;
import org.sonar.batch.scan.filesystem.FileSystemLogger;
import org.sonar.batch.scan.maven.MavenPluginsConfigurator;
-import org.sonar.batch.scan.report.JsonReport;
+import org.sonar.batch.scan.report.IssuesReports;
import java.util.ArrayList;
import java.util.Arrays;
private final ProjectInitializer pi;
private final ScanPersister[] persisters;
private final FileSystemLogger fsLogger;
- private final JsonReport jsonReport;
+ private final IssuesReports jsonReport;
private final DefaultModuleFileSystem fs;
private final QProfileVerifier profileVerifier;
private final IssueExclusionsLoader issueExclusionsLoader;
PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
SensorContext sensorContext, DefaultIndex index,
EventBus eventBus, PublishReportJob publishReportJob, ProjectInitializer pi,
- ScanPersister[] persisters, FileSystemLogger fsLogger, JsonReport jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
+ ScanPersister[] persisters, FileSystemLogger fsLogger, IssuesReports jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
IssueExclusionsLoader issueExclusionsLoader, AnalysisMode analysisMode, DatabaseSession session, ResourcePersister resourcePersister) {
this.phases = phases;
this.decoratorsExecutor = decoratorsExecutor;
import org.sonar.batch.scan.filesystem.DefaultModuleFileSystem;
import org.sonar.batch.scan.filesystem.FileSystemLogger;
import org.sonar.batch.scan.maven.MavenPluginsConfigurator;
-import org.sonar.batch.scan.report.JsonReport;
+import org.sonar.batch.scan.report.IssuesReports;
public final class PreviewPhaseExecutor implements PhaseExecutor {
private final DefaultModuleFileSystem fs;
private final QProfileVerifier profileVerifier;
private final IssueExclusionsLoader issueExclusionsLoader;
- private final JsonReport jsonReport;
+ private final IssuesReports issuesReport;
public PreviewPhaseExecutor(Phases phases,
MavenPluginsConfigurator mavenPluginsConfigurator, InitializersExecutor initializersExecutor,
SensorsExecutor sensorsExecutor,
SensorContext sensorContext, DefaultIndex index,
- EventBus eventBus, ProjectInitializer pi, FileSystemLogger fsLogger, JsonReport jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
+ EventBus eventBus, ProjectInitializer pi, FileSystemLogger fsLogger, IssuesReports jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
IssueExclusionsLoader issueExclusionsLoader) {
this.phases = phases;
this.mavenPluginsConfigurator = mavenPluginsConfigurator;
this.eventBus = eventBus;
this.pi = pi;
this.fsLogger = fsLogger;
- this.jsonReport = jsonReport;
+ this.issuesReport = jsonReport;
this.fs = fs;
this.profileVerifier = profileVerifier;
this.issueExclusionsLoader = issueExclusionsLoader;
}
if (module.isRoot()) {
- jsonReport.execute();
+ issuesReport();
}
cleanMemory();
eventBus.fireEvent(new ProjectAnalysisEvent(module, false));
}
+ private void issuesReport() {
+ String stepName = "Issues Reports";
+ eventBus.fireEvent(new BatchStepEvent(stepName, true));
+ issuesReport.execute();
+ eventBus.fireEvent(new BatchStepEvent(stepName, false));
+ }
+
private void initIssueExclusions() {
String stepName = "Init issue exclusions";
eventBus.fireEvent(new BatchStepEvent(stepName, true));
import org.sonar.batch.scan.filesystem.ProjectFileSystemAdapter;
import org.sonar.batch.scan.filesystem.StatusDetectionFactory;
import org.sonar.batch.scan.maven.MavenPluginsConfigurator;
-import org.sonar.batch.scan.report.JsonReport;
+import org.sonar.batch.scan.report.IssuesReports;
import org.sonar.batch.sensor.DefaultSensorContext;
import org.sonar.batch.sensor.DefaultSensorStorage;
import org.sonar.batch.sensor.coverage.CoverageExclusions;
CheckFactory.class,
// report
- JsonReport.class,
+ IssuesReports.class,
// issues
IssuableFactory.class,
import org.sonar.core.test.TestPlanPerspectiveLoader;
import org.sonar.core.test.TestableBuilder;
import org.sonar.core.test.TestablePerspectiveLoader;
-import org.sonar.core.user.DefaultUserFinder;
public class ProjectScanContainer extends ComponentContainer {
private boolean sensorMode;
SourcePersister.class,
ResourceKeyMigration.class,
- DefaultUserFinder.class,
-
// Rules
new RulesProvider(),
new DebtModelProvider(),
--- /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.scan.report;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.Properties;
+import org.sonar.api.Property;
+import org.sonar.api.PropertyType;
+import org.sonar.api.config.Settings;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.rule.Severity;
+import org.sonar.batch.issue.IssueCache;
+
+@Properties({
+ @Property(key = ConsoleReport.CONSOLE_REPORT_ENABLED_KEY, name = "Enable console report", description = "Set this to true to generate a report in console output",
+ type = PropertyType.BOOLEAN, defaultValue = "false")})
+public class ConsoleReport implements Reporter {
+ private static final Logger LOG = LoggerFactory.getLogger(ConsoleReport.class);
+
+ public static final String CONSOLE_REPORT_ENABLED_KEY = "sonar.issuesReport.console.enable";
+ private static final int LEFT_PAD = 10;
+
+ private Settings settings;
+ private Logger logger;
+
+ private IssueCache issueCache;
+
+ public ConsoleReport(Settings settings, IssueCache issueCache) {
+ this(settings, issueCache, LOG);
+ }
+
+ @VisibleForTesting
+ public ConsoleReport(Settings settings, IssueCache issueCache, Logger logger) {
+ this.settings = settings;
+ this.issueCache = issueCache;
+ this.logger = logger;
+ }
+
+ private static class Report {
+ int totalNewIssues = 0;
+ int newBlockerIssues = 0;
+ int newCriticalIssues = 0;
+ int newMajorIssues = 0;
+ int newMinorIssues = 0;
+ int newInfoIssues = 0;
+
+ public void process(DefaultIssue issue) {
+ if (issue.isNew()) {
+ totalNewIssues++;
+ switch (issue.severity()) {
+ case Severity.BLOCKER:
+ newBlockerIssues++;
+ break;
+ case Severity.CRITICAL:
+ newCriticalIssues++;
+ break;
+ case Severity.MAJOR:
+ newMajorIssues++;
+ break;
+ case Severity.MINOR:
+ newMinorIssues++;
+ break;
+ case Severity.INFO:
+ newInfoIssues++;
+ break;
+ default:
+ throw new IllegalStateException("Unknow severity: " + issue.severity());
+ }
+ }
+ }
+ }
+
+ @Override
+ public void execute() {
+ if (settings.getBoolean(CONSOLE_REPORT_ENABLED_KEY)) {
+ Report r = new Report();
+ for (DefaultIssue issue : issueCache.all()) {
+ r.process(issue);
+ }
+ printNewIssues(r);
+ }
+ }
+
+ public void printNewIssues(Report r) {
+ StringBuilder sb = new StringBuilder();
+
+ int newIssues = r.totalNewIssues;
+ sb.append("\n\n------------- Issues Report -------------\n\n");
+ if (newIssues > 0) {
+ sb.append(StringUtils.leftPad("+" + newIssues, LEFT_PAD)).append(" issue" + (newIssues > 1 ? "s" : "")).append("\n\n");
+ printNewIssues(sb, r.newBlockerIssues, Severity.BLOCKER, "blocking");
+ printNewIssues(sb, r.newCriticalIssues, Severity.CRITICAL, "critical");
+ printNewIssues(sb, r.newMajorIssues, Severity.MAJOR, "major");
+ printNewIssues(sb, r.newMinorIssues, Severity.MINOR, "minor");
+ printNewIssues(sb, r.newInfoIssues, Severity.INFO, "info");
+ } else {
+ sb.append(" No new issue").append("\n");
+ }
+ sb.append("\n-------------------------------------------\n\n");
+
+ logger.info(sb.toString());
+ }
+
+ private void printNewIssues(StringBuilder sb, int issueCount, String severity, String severityLabel) {
+ if (issueCount > 0) {
+ sb.append(StringUtils.leftPad("+" + issueCount, LEFT_PAD)).append(" ").append(severityLabel).append("\n");
+ }
+ }
+}
--- /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.scan.report;
+
+import org.sonar.api.BatchComponent;
+import org.sonar.batch.bootstrap.AnalysisMode;
+
+public class IssuesReports implements BatchComponent {
+
+ private final AnalysisMode analysisMode;
+ private final Reporter[] reporters;
+
+ public IssuesReports(AnalysisMode analysisMode, Reporter... reporters) {
+ this.reporters = reporters;
+ this.analysisMode = analysisMode;
+ }
+
+ public void execute() {
+ if (analysisMode.isPreview() || analysisMode.isSensorMode()) {
+ for (Reporter reporter : reporters) {
+ reporter.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.scan.report;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Charsets;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputDir;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputPath;
+import org.sonar.api.batch.fs.internal.DefaultInputDir;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.batch.rule.internal.DefaultActiveRule;
+import org.sonar.api.config.Settings;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.platform.Server;
+import org.sonar.api.resources.Project;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.SonarException;
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.batch.issue.IssueCache;
+import org.sonar.batch.scan.filesystem.InputPathCache;
+import org.sonar.batch.user.User;
+import org.sonar.batch.user.UserRepository;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Set;
+
+import static com.google.common.collect.Sets.newHashSet;
+
+public class JSONReport implements Reporter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JSONReport.class);
+ private final Settings settings;
+ private final FileSystem fileSystem;
+ private final Server server;
+ private final ActiveRules activeRules;
+ private final IssueCache issueCache;
+ private final InputPathCache fileCache;
+ private final Project rootModule;
+ private final UserRepository userRepository;
+
+ public JSONReport(Settings settings, FileSystem fileSystem, Server server, ActiveRules activeRules, IssueCache issueCache,
+ Project rootModule, InputPathCache fileCache, UserRepository userRepository) {
+ this.settings = settings;
+ this.fileSystem = fileSystem;
+ this.server = server;
+ this.activeRules = activeRules;
+ this.issueCache = issueCache;
+ this.rootModule = rootModule;
+ this.fileCache = fileCache;
+ this.userRepository = userRepository;
+ }
+
+ @Override
+ public void execute() {
+ String exportPath = settings.getString("sonar.report.export.path");
+ if (exportPath != null) {
+ exportResults(exportPath);
+ }
+ }
+
+ private void exportResults(String exportPath) {
+ File exportFile = new File(fileSystem.workDir(), exportPath);
+
+ LOG.info("Export issues to " + exportFile.getAbsolutePath());
+ try (Writer output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(exportFile), Charsets.UTF_8))) {
+ writeJson(output);
+
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to write report results in file " + exportFile.getAbsolutePath(), e);
+ }
+ }
+
+ @VisibleForTesting
+ void writeJson(Writer writer) {
+ try {
+ JsonWriter json = JsonWriter.of(writer);
+ json.beginObject();
+ json.prop("version", server.getVersion());
+
+ Set<RuleKey> ruleKeys = newHashSet();
+ Set<String> userLogins = newHashSet();
+ writeJsonIssues(json, ruleKeys, userLogins);
+ writeJsonComponents(json);
+ writeJsonRules(json, ruleKeys);
+ Collection<User> users = userRepository.loadFromWs(new ArrayList<String>(userLogins));
+ writeUsers(json, users);
+ json.endObject().close();
+
+ } catch (IOException e) {
+ throw new SonarException("Unable to write JSON report", e);
+ }
+ }
+
+ private void writeJsonIssues(JsonWriter json, Set<RuleKey> ruleKeys, Set<String> logins) throws IOException {
+ json.name("issues").beginArray();
+ for (DefaultIssue issue : getIssues()) {
+ if (issue.resolution() == null) {
+ json
+ .beginObject()
+ .prop("key", issue.key())
+ .prop("component", issue.componentKey())
+ .prop("line", issue.line())
+ .prop("message", issue.message())
+ .prop("severity", issue.severity())
+ .prop("rule", issue.ruleKey().toString())
+ .prop("status", issue.status())
+ .prop("resolution", issue.resolution())
+ .prop("isNew", issue.isNew())
+ .prop("reporter", issue.reporter())
+ .prop("assignee", issue.assignee())
+ .prop("effortToFix", issue.effortToFix())
+ .propDateTime("creationDate", issue.creationDate())
+ .propDateTime("updateDate", issue.updateDate())
+ .propDateTime("closeDate", issue.closeDate());
+ if (issue.reporter() != null) {
+ logins.add(issue.reporter());
+ }
+ if (issue.assignee() != null) {
+ logins.add(issue.assignee());
+ }
+ json.endObject();
+ ruleKeys.add(issue.ruleKey());
+ }
+ }
+ json.endArray();
+ }
+
+ private void writeJsonComponents(JsonWriter json) throws IOException {
+ json.name("components").beginArray();
+ // Dump modules
+ writeJsonModuleComponents(json, rootModule);
+ for (InputPath inputPath : fileCache.all()) {
+ if (inputPath instanceof InputFile) {
+ InputFile inputFile = (InputFile) inputPath;
+ String key = ((DefaultInputFile) inputFile).key();
+ json
+ .beginObject()
+ .prop("key", key)
+ .prop("path", inputFile.relativePath())
+ .prop("moduleKey", StringUtils.substringBeforeLast(key, ":"))
+ .prop("status", inputFile.status().name())
+ .endObject();
+ } else {
+ InputDir inputDir = (InputDir) inputPath;
+ String key = ((DefaultInputDir) inputDir).key();
+ json
+ .beginObject()
+ .prop("key", key)
+ .prop("path", inputDir.relativePath())
+ .prop("moduleKey", StringUtils.substringBeforeLast(key, ":"))
+ .endObject();
+ }
+
+ }
+ json.endArray();
+ }
+
+ private void writeJsonModuleComponents(JsonWriter json, Project module) {
+ json
+ .beginObject()
+ .prop("key", module.getEffectiveKey())
+ .prop("path", module.getPath())
+ .endObject();
+ for (Project subModule : module.getModules()) {
+ writeJsonModuleComponents(json, subModule);
+ }
+ }
+
+ private void writeJsonRules(JsonWriter json, Set<RuleKey> ruleKeys) throws IOException {
+ json.name("rules").beginArray();
+ for (RuleKey ruleKey : ruleKeys) {
+ json
+ .beginObject()
+ .prop("key", ruleKey.toString())
+ .prop("rule", ruleKey.rule())
+ .prop("repository", ruleKey.repository())
+ .prop("name", getRuleName(ruleKey))
+ .endObject();
+ }
+ json.endArray();
+ }
+
+ private void writeUsers(JsonWriter json, Collection<User> users) throws IOException {
+ json.name("users").beginArray();
+ for (User user : users) {
+ json
+ .beginObject()
+ .prop("login", user.login())
+ .prop("name", user.name())
+ .endObject();
+ }
+ json.endArray();
+ }
+
+ private String getRuleName(RuleKey ruleKey) {
+ DefaultActiveRule rule = (DefaultActiveRule) activeRules.find(ruleKey);
+ return rule != null ? rule.name() : null;
+ }
+
+ @VisibleForTesting
+ Iterable<DefaultIssue> getIssues() {
+ return issueCache.all();
+ }
+}
+++ /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.scan.report;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Charsets;
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.batch.fs.FileSystem;
-import org.sonar.api.batch.fs.InputDir;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.InputPath;
-import org.sonar.api.batch.fs.internal.DefaultInputDir;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.rule.ActiveRules;
-import org.sonar.api.batch.rule.internal.DefaultActiveRule;
-import org.sonar.api.config.Settings;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.platform.Server;
-import org.sonar.api.resources.Project;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.user.User;
-import org.sonar.api.user.UserFinder;
-import org.sonar.api.utils.SonarException;
-import org.sonar.api.utils.text.JsonWriter;
-import org.sonar.batch.bootstrap.AnalysisMode;
-import org.sonar.batch.events.BatchStepEvent;
-import org.sonar.batch.events.EventBus;
-import org.sonar.batch.issue.IssueCache;
-import org.sonar.batch.scan.filesystem.InputPathCache;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-import static com.google.common.collect.Sets.newHashSet;
-
-/**
- * @since 3.6
- */
-
-public class JsonReport implements BatchComponent {
-
- private static final Logger LOG = LoggerFactory.getLogger(JsonReport.class);
- private final Settings settings;
- private final FileSystem fileSystem;
- private final Server server;
- private final ActiveRules activeRules;
- private final IssueCache issueCache;
- private final EventBus eventBus;
- private final AnalysisMode analysisMode;
- private final UserFinder userFinder;
- private final InputPathCache fileCache;
- private final Project rootModule;
-
- public JsonReport(Settings settings, FileSystem fileSystem, Server server, ActiveRules activeRules, IssueCache issueCache,
- EventBus eventBus, AnalysisMode analysisMode, UserFinder userFinder, Project rootModule, InputPathCache fileCache) {
- this.settings = settings;
- this.fileSystem = fileSystem;
- this.server = server;
- this.activeRules = activeRules;
- this.issueCache = issueCache;
- this.eventBus = eventBus;
- this.analysisMode = analysisMode;
- this.userFinder = userFinder;
- this.rootModule = rootModule;
- this.fileCache = fileCache;
- }
-
- public JsonReport(Settings settings, FileSystem fileSystem, Server server, ActiveRules activeRules, IssueCache issueCache,
- EventBus eventBus, AnalysisMode analysisMode, Project rootModule, InputPathCache fileCache) {
- this.settings = settings;
- this.fileSystem = fileSystem;
- this.server = server;
- this.activeRules = activeRules;
- this.issueCache = issueCache;
- this.eventBus = eventBus;
- this.analysisMode = analysisMode;
- this.userFinder = null;
- this.rootModule = rootModule;
- this.fileCache = fileCache;
- }
-
- public void execute() {
- String exportPath = settings.getString("sonar.report.export.path");
- if (exportPath != null && (analysisMode.isPreview() || analysisMode.isSensorMode())) {
- eventBus.fireEvent(new BatchStepEvent("JSON report", true));
- exportResults(exportPath);
- eventBus.fireEvent(new BatchStepEvent("JSON report", false));
- }
- }
-
- private void exportResults(String exportPath) {
- File exportFile = new File(fileSystem.workDir(), exportPath);
-
- LOG.info("Export results to " + exportFile.getAbsolutePath());
- try (Writer output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(exportFile), Charsets.UTF_8))) {
- writeJson(output);
-
- } catch (IOException e) {
- throw new IllegalStateException("Unable to write report results in file " + exportFile.getAbsolutePath(), e);
- }
- }
-
- @VisibleForTesting
- void writeJson(Writer writer) {
- try {
- JsonWriter json = JsonWriter.of(writer);
- json.beginObject();
- json.prop("version", server.getVersion());
-
- Set<RuleKey> ruleKeys = newHashSet();
- Set<String> userLogins = newHashSet();
- writeJsonIssues(json, ruleKeys, userLogins);
- writeJsonComponents(json);
- writeJsonRules(json, ruleKeys);
- List<User> users = userFinder != null ? userFinder.findByLogins(new ArrayList<String>(userLogins)) : Collections.<User>emptyList();
- writeUsers(json, users);
- json.endObject().close();
-
- } catch (IOException e) {
- throw new SonarException("Unable to write JSON report", e);
- }
- }
-
- private void writeJsonIssues(JsonWriter json, Set<RuleKey> ruleKeys, Set<String> logins) throws IOException {
- json.name("issues").beginArray();
- for (DefaultIssue issue : getIssues()) {
- if (issue.resolution() == null) {
- json
- .beginObject()
- .prop("key", issue.key())
- .prop("component", issue.componentKey())
- .prop("line", issue.line())
- .prop("message", issue.message())
- .prop("severity", issue.severity())
- .prop("rule", issue.ruleKey().toString())
- .prop("status", issue.status())
- .prop("resolution", issue.resolution())
- .prop("isNew", issue.isNew())
- .prop("reporter", issue.reporter())
- .prop("assignee", issue.assignee())
- .prop("effortToFix", issue.effortToFix())
- .propDateTime("creationDate", issue.creationDate())
- .propDateTime("updateDate", issue.updateDate())
- .propDateTime("closeDate", issue.closeDate());
- if (issue.reporter() != null) {
- logins.add(issue.reporter());
- }
- if (issue.assignee() != null) {
- logins.add(issue.assignee());
- }
- json.endObject();
- ruleKeys.add(issue.ruleKey());
- }
- }
- json.endArray();
- }
-
- private void writeJsonComponents(JsonWriter json) throws IOException {
- json.name("components").beginArray();
- // Dump modules
- writeJsonModuleComponents(json, rootModule);
- for (InputPath inputPath : fileCache.all()) {
- if (inputPath instanceof InputFile) {
- InputFile inputFile = (InputFile) inputPath;
- String key = ((DefaultInputFile) inputFile).key();
- json
- .beginObject()
- .prop("key", key)
- .prop("path", inputFile.relativePath())
- .prop("moduleKey", StringUtils.substringBeforeLast(key, ":"))
- .prop("status", inputFile.status().name())
- .endObject();
- } else {
- InputDir inputDir = (InputDir) inputPath;
- String key = ((DefaultInputDir) inputDir).key();
- json
- .beginObject()
- .prop("key", key)
- .prop("path", inputDir.relativePath())
- .prop("moduleKey", StringUtils.substringBeforeLast(key, ":"))
- .endObject();
- }
-
- }
- json.endArray();
- }
-
- private void writeJsonModuleComponents(JsonWriter json, Project module) {
- json
- .beginObject()
- .prop("key", module.getEffectiveKey())
- .prop("path", module.getPath())
- .endObject();
- for (Project subModule : module.getModules()) {
- writeJsonModuleComponents(json, subModule);
- }
- }
-
- private void writeJsonRules(JsonWriter json, Set<RuleKey> ruleKeys) throws IOException {
- json.name("rules").beginArray();
- for (RuleKey ruleKey : ruleKeys) {
- json
- .beginObject()
- .prop("key", ruleKey.toString())
- .prop("rule", ruleKey.rule())
- .prop("repository", ruleKey.repository())
- .prop("name", getRuleName(ruleKey))
- .endObject();
- }
- json.endArray();
- }
-
- private void writeUsers(JsonWriter json, List<User> users) throws IOException {
- json.name("users").beginArray();
- for (User user : users) {
- json
- .beginObject()
- .prop("login", user.login())
- .prop("name", user.name())
- .endObject();
- }
- json.endArray();
- }
-
- private String getRuleName(RuleKey ruleKey) {
- DefaultActiveRule rule = (DefaultActiveRule) activeRules.find(ruleKey);
- return rule != null ? rule.name() : null;
- }
-
- @VisibleForTesting
- Iterable<DefaultIssue> getIssues() {
- return issueCache.all();
- }
-}
--- /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.scan.report;
+
+import org.sonar.api.BatchComponent;
+
+public interface Reporter extends BatchComponent {
+
+ public 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.user;
+
+import org.apache.commons.lang.builder.EqualsBuilder;
+
+public class User {
+
+ private final String login;
+ private final String name;
+
+ public User(String login, String name) {
+ this.login = login;
+ this.name = name;
+ }
+
+ public String login() {
+ return login;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ // For testing
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ if (obj.getClass() != getClass()) {
+ return false;
+ }
+ User rhs = (User) obj;
+ return new EqualsBuilder()
+ .append(login, rhs.login)
+ .append(name, rhs.name)
+ .isEquals();
+ }
+
+}
--- /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.user;
+
+import com.google.common.base.Joiner;
+import org.sonar.batch.bootstrap.ServerClient;
+import org.sonar.batch.protocol.GsonHelper;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class UserRepository {
+
+ private ServerClient serverClient;
+
+ public UserRepository(ServerClient serverClient) {
+ this.serverClient = serverClient;
+ }
+
+ private static class Users {
+
+ private List<User> users = new ArrayList<>();
+
+ public List<User> getUsers() {
+ return users;
+ }
+ }
+
+ public Collection<User> loadFromWs(List<String> userLogins) {
+ String url = "/api/users/search?format=json&includeDeactivated=true&logins=" + Joiner.on(',').join(userLogins);
+ String json = serverClient.request(url);
+ Users users = GsonHelper.create().fromJson(json, Users.class);
+ return users.getUsers();
+ }
+
+}
--- /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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.batch.user;
+
+import javax.annotation.ParametersAreNonnullByDefault;
--- /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.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.batch.mediumtest.BatchMediumTester;
+import org.sonar.batch.mediumtest.TaskResult;
+import org.sonar.batch.protocol.input.ActiveRule;
+import org.sonar.xoo.XooPlugin;
+
+import java.io.File;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ReportsMediumTest {
+
+ @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", "OneIssuePerLine", "One issue per line", "MAJOR", "OneIssuePerLine.internal", "xoo"))
+ .bootstrapProperties(ImmutableMap.of("sonar.analysis.mode", "sensor"))
+ .build();
+
+ @Before
+ public void prepare() {
+ tester.start();
+ }
+
+ @After
+ public void stop() {
+ tester.stop();
+ }
+
+ @Test
+ public void testConsoleReport() throws Exception {
+ File projectDir = new File(ReportsMediumTest.class.getResource("/mediumtest/xoo/sample").toURI());
+
+ TaskResult result = tester
+ .newScanTask(new File(projectDir, "sonar-project.properties"))
+ .property("sonar.issuesReport.console.enable", "true")
+ .start();
+
+ assertThat(result.issues()).hasSize(26);
+ }
+
+}
--- /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.scan.report;
+
+import com.google.common.collect.Lists;
+import com.google.common.io.Resources;
+import org.apache.commons.codec.Charsets;
+import org.json.JSONException;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputPath;
+import org.sonar.api.batch.fs.internal.DefaultFileSystem;
+import org.sonar.api.batch.fs.internal.DefaultInputDir;
+import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile;
+import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
+import org.sonar.api.config.Settings;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.platform.Server;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.batch.issue.IssueCache;
+import org.sonar.batch.scan.filesystem.InputPathCache;
+import org.sonar.batch.user.User;
+import org.sonar.batch.user.UserRepository;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.TimeZone;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class JSONReportTest {
+
+ private SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
+
+ @org.junit.Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ JSONReport jsonReport;
+ Resource resource = mock(Resource.class);
+ DefaultFileSystem fs = new DefaultFileSystem();
+ Server server = mock(Server.class);
+ ActiveRules activeRules = mock(ActiveRules.class);
+ Settings settings = new Settings();
+ IssueCache issueCache = mock(IssueCache.class);
+ private UserRepository userRepository;
+
+ @Before
+ public void before() {
+ SIMPLE_DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+02:00"));
+ when(resource.getEffectiveKey()).thenReturn("Action.java");
+ when(server.getVersion()).thenReturn("3.6");
+ userRepository = mock(UserRepository.class);
+ DefaultInputDir inputDir = new DefaultInputDir("struts", "src/main/java/org/apache/struts");
+ DeprecatedDefaultInputFile inputFile = new DeprecatedDefaultInputFile("struts", "src/main/java/org/apache/struts/Action.java");
+ inputFile.setStatus(InputFile.Status.CHANGED);
+ InputPathCache fileCache = mock(InputPathCache.class);
+ when(fileCache.all()).thenReturn(Arrays.<InputPath>asList(inputDir, inputFile));
+ Project rootModule = new Project("struts");
+ Project moduleA = new Project("struts-core");
+ moduleA.setParent(rootModule).setPath("core");
+ Project moduleB = new Project("struts-ui");
+ moduleB.setParent(rootModule).setPath("ui");
+ activeRules = new ActiveRulesBuilder()
+ .create(RuleKey.of("squid", "AvoidCycles")).setName("Avoid Cycles").activate()
+ .build();
+ jsonReport = new JSONReport(settings, fs, server, activeRules, issueCache, rootModule, fileCache, userRepository);
+ }
+
+ @Test
+ public void should_write_json() throws Exception {
+ DefaultIssue issue = new DefaultIssue()
+ .setKey("200")
+ .setComponentKey("struts:src/main/java/org/apache/struts/Action.java")
+ .setRuleKey(RuleKey.of("squid", "AvoidCycles"))
+ .setMessage("There are 2 cycles")
+ .setSeverity("MINOR")
+ .setStatus(Issue.STATUS_OPEN)
+ .setResolution(null)
+ .setLine(1)
+ .setEffortToFix(3.14)
+ .setReporter("julien")
+ .setAssignee("simon")
+ .setCreationDate(SIMPLE_DATE_FORMAT.parse("2013-04-24"))
+ .setUpdateDate(SIMPLE_DATE_FORMAT.parse("2013-04-25"))
+ .setNew(false);
+ when(jsonReport.getIssues()).thenReturn(Lists.newArrayList(issue));
+ User user1 = new User("julien", "Julien");
+ User user2 = new User("simon", "Simon");
+ when(userRepository.loadFromWs(anyListOf(String.class))).thenReturn(Lists.<User>newArrayList(user1, user2));
+
+ StringWriter writer = new StringWriter();
+ jsonReport.writeJson(writer);
+
+ String expected = Resources.toString(Resources.getResource("org/sonar/batch/scan/report/JsonReportTest/report.json"), Charsets.UTF_8);
+ JSONAssert.assertEquals(expected, writer.toString(), false);
+ }
+
+ @Test
+ public void should_exclude_resolved_issues() throws Exception {
+ RuleKey ruleKey = RuleKey.of("squid", "AvoidCycles");
+ DefaultIssue issue = new DefaultIssue()
+ .setKey("200")
+ .setComponentKey("struts:src/main/java/org/apache/struts/Action.java")
+ .setRuleKey(ruleKey)
+ .setStatus(Issue.STATUS_CLOSED)
+ .setResolution(Issue.RESOLUTION_FIXED)
+ .setCreationDate(SIMPLE_DATE_FORMAT.parse("2013-04-24"))
+ .setUpdateDate(SIMPLE_DATE_FORMAT.parse("2013-04-25"))
+ .setCloseDate(SIMPLE_DATE_FORMAT.parse("2013-04-26"))
+ .setNew(false);
+ when(jsonReport.getIssues()).thenReturn(Lists.newArrayList(issue));
+
+ StringWriter writer = new StringWriter();
+ jsonReport.writeJson(writer);
+
+ String expected = Resources.toString(Resources.getResource(
+ "org/sonar/batch/scan/report/JsonReportTest/report-without-resolved-issues.json"), Charsets.UTF_8);
+ JSONAssert.assertEquals(expected, writer.toString(), false);
+ }
+
+ @Test
+ public void should_ignore_components_without_issue() throws JSONException {
+ when(jsonReport.getIssues()).thenReturn(Collections.<DefaultIssue>emptyList());
+
+ StringWriter writer = new StringWriter();
+ jsonReport.writeJson(writer);
+
+ JSONAssert.assertEquals("{\"version\":\"3.6\"}", writer.toString(), false);
+ }
+
+ @Test
+ public void should_export_issues_to_file() throws IOException {
+ File workDir = temporaryFolder.newFolder("sonar");
+ fs.setWorkDir(workDir);
+
+ when(jsonReport.getIssues()).thenReturn(Collections.<DefaultIssue>emptyList());
+
+ settings.setProperty("sonar.report.export.path", "output.json");
+
+ jsonReport.execute();
+
+ assertThat(new File(workDir, "output.json")).exists();
+ }
+
+}
+++ /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.scan.report;
-
-import com.google.common.collect.Lists;
-import com.google.common.io.Resources;
-import org.apache.commons.codec.Charsets;
-import org.json.JSONException;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.skyscreamer.jsonassert.JSONAssert;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.InputPath;
-import org.sonar.api.batch.fs.internal.DefaultFileSystem;
-import org.sonar.api.batch.fs.internal.DefaultInputDir;
-import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile;
-import org.sonar.api.batch.rule.ActiveRules;
-import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
-import org.sonar.api.config.Settings;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.platform.Server;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.Resource;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.user.User;
-import org.sonar.api.user.UserFinder;
-import org.sonar.batch.bootstrap.AnalysisMode;
-import org.sonar.batch.events.EventBus;
-import org.sonar.batch.issue.IssueCache;
-import org.sonar.batch.scan.filesystem.InputPathCache;
-import org.sonar.core.user.DefaultUser;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.text.SimpleDateFormat;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.TimeZone;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.anyListOf;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class JsonReportTest {
-
- private SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
-
- @org.junit.Rule
- public TemporaryFolder temporaryFolder = new TemporaryFolder();
-
- JsonReport jsonReport;
- Resource resource = mock(Resource.class);
- DefaultFileSystem fs = new DefaultFileSystem();
- Server server = mock(Server.class);
- ActiveRules activeRules = mock(ActiveRules.class);
- Settings settings = new Settings();
- IssueCache issueCache = mock(IssueCache.class);
- private UserFinder userFinder;
-
- @Before
- public void before() {
- SIMPLE_DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+02:00"));
- when(resource.getEffectiveKey()).thenReturn("Action.java");
- when(server.getVersion()).thenReturn("3.6");
- AnalysisMode mode = mock(AnalysisMode.class);
- when(mode.isPreview()).thenReturn(true);
- userFinder = mock(UserFinder.class);
- DefaultInputDir inputDir = new DefaultInputDir("struts", "src/main/java/org/apache/struts");
- DeprecatedDefaultInputFile inputFile = new DeprecatedDefaultInputFile("struts", "src/main/java/org/apache/struts/Action.java");
- inputFile.setStatus(InputFile.Status.CHANGED);
- InputPathCache fileCache = mock(InputPathCache.class);
- when(fileCache.all()).thenReturn(Arrays.<InputPath>asList(inputDir, inputFile));
- Project rootModule = new Project("struts");
- Project moduleA = new Project("struts-core");
- moduleA.setParent(rootModule).setPath("core");
- Project moduleB = new Project("struts-ui");
- moduleB.setParent(rootModule).setPath("ui");
- activeRules = new ActiveRulesBuilder()
- .create(RuleKey.of("squid", "AvoidCycles")).setName("Avoid Cycles").activate()
- .build();
- jsonReport = new JsonReport(settings, fs, server, activeRules, issueCache, mock(EventBus.class),
- mode, userFinder, rootModule, fileCache);
- }
-
- @Test
- public void should_write_json() throws Exception {
- DefaultIssue issue = new DefaultIssue()
- .setKey("200")
- .setComponentKey("struts:src/main/java/org/apache/struts/Action.java")
- .setRuleKey(RuleKey.of("squid", "AvoidCycles"))
- .setMessage("There are 2 cycles")
- .setSeverity("MINOR")
- .setStatus(Issue.STATUS_OPEN)
- .setResolution(null)
- .setLine(1)
- .setEffortToFix(3.14)
- .setReporter("julien")
- .setAssignee("simon")
- .setCreationDate(SIMPLE_DATE_FORMAT.parse("2013-04-24"))
- .setUpdateDate(SIMPLE_DATE_FORMAT.parse("2013-04-25"))
- .setNew(false);
- when(jsonReport.getIssues()).thenReturn(Lists.newArrayList(issue));
- DefaultUser user1 = new DefaultUser().setLogin("julien").setName("Julien");
- DefaultUser user2 = new DefaultUser().setLogin("simon").setName("Simon");
- when(userFinder.findByLogins(anyListOf(String.class))).thenReturn(Lists.<User>newArrayList(user1, user2));
-
- StringWriter writer = new StringWriter();
- jsonReport.writeJson(writer);
-
- String expected = Resources.toString(Resources.getResource("org/sonar/batch/scan/report/JsonReportTest/report.json"), Charsets.UTF_8);
- JSONAssert.assertEquals(expected, writer.toString(), false);
- }
-
- @Test
- public void should_exclude_resolved_issues() throws Exception {
- RuleKey ruleKey = RuleKey.of("squid", "AvoidCycles");
- DefaultIssue issue = new DefaultIssue()
- .setKey("200")
- .setComponentKey("struts:src/main/java/org/apache/struts/Action.java")
- .setRuleKey(ruleKey)
- .setStatus(Issue.STATUS_CLOSED)
- .setResolution(Issue.RESOLUTION_FIXED)
- .setCreationDate(SIMPLE_DATE_FORMAT.parse("2013-04-24"))
- .setUpdateDate(SIMPLE_DATE_FORMAT.parse("2013-04-25"))
- .setCloseDate(SIMPLE_DATE_FORMAT.parse("2013-04-26"))
- .setNew(false);
- when(jsonReport.getIssues()).thenReturn(Lists.newArrayList(issue));
-
- StringWriter writer = new StringWriter();
- jsonReport.writeJson(writer);
-
- String expected = Resources.toString(Resources.getResource(
- "org/sonar/batch/scan/report/JsonReportTest/report-without-resolved-issues.json"), Charsets.UTF_8);
- JSONAssert.assertEquals(expected, writer.toString(), false);
- }
-
- @Test
- public void should_ignore_components_without_issue() throws JSONException {
- when(jsonReport.getIssues()).thenReturn(Collections.<DefaultIssue>emptyList());
-
- StringWriter writer = new StringWriter();
- jsonReport.writeJson(writer);
-
- JSONAssert.assertEquals("{\"version\":\"3.6\"}", writer.toString(), false);
- }
-
- @Test
- public void should_export_issues_to_file() throws IOException {
- File workDir = temporaryFolder.newFolder("sonar");
- fs.setWorkDir(workDir);
-
- when(jsonReport.getIssues()).thenReturn(Collections.<DefaultIssue>emptyList());
-
- settings.setProperty("sonar.report.export.path", "output.json");
-
- jsonReport.execute();
-
- assertThat(new File(workDir, "output.json")).exists();
- }
-
-}
--- /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.user;
+
+import org.junit.Test;
+import org.sonar.batch.bootstrap.ServerClient;
+
+import java.util.Arrays;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class UserRepositoryTest {
+
+ @Test
+ public void testLoad() {
+ ServerClient serverClient = mock(ServerClient.class);
+ UserRepository userRepo = new UserRepository(serverClient);
+
+ when(serverClient.request("/api/users/search?format=json&includeDeactivated=true&logins=fmallet,sbrandhof"))
+ .thenReturn(
+ "{ \"users\": [ { \"login\": \"fmallet\", \"name\": \"Freddy Mallet\", \"active\": true, \"email\": \"f@m.com\" }, { \"login\": \"sbrandhof\", \"name\": \"Simon\", \"active\": true } ] }");
+
+ assertThat(userRepo.loadFromWs(Arrays.asList("fmallet", "sbrandhof"))).containsOnly(new User("fmallet", "Freddy Mallet"), new User("sbrandhof", "Simon"));
+ }
+}
*/
package org.sonar.api.user;
-import org.sonar.api.BatchComponent;
import org.sonar.api.ServerComponent;
import javax.annotation.CheckForNull;
/**
* @since 3.6
*/
-public interface UserFinder extends ServerComponent, BatchComponent {
+public interface UserFinder extends ServerComponent {
@CheckForNull
User findByLogin(String login);