import org.sonar.api.platform.ComponentContainer;
import org.sonar.api.resources.Project;
import org.sonar.api.scan.filesystem.FileExclusions;
-import org.sonar.batch.*;
+import org.sonar.batch.DefaultProjectClasspath;
+import org.sonar.batch.DefaultSensorContext;
+import org.sonar.batch.DefaultTimeMachine;
+import org.sonar.batch.ProjectTree;
+import org.sonar.batch.ResourceFilters;
+import org.sonar.batch.ViolationFilters;
import org.sonar.batch.bootstrap.BatchExtensionDictionnary;
import org.sonar.batch.bootstrap.ExtensionInstaller;
import org.sonar.batch.bootstrap.ExtensionMatcher;
import org.sonar.batch.rule.ModuleQProfiles;
import org.sonar.batch.rule.QProfileSensor;
import org.sonar.batch.rule.RulesProfileProvider;
-import org.sonar.batch.scan.filesystem.*;
+import org.sonar.batch.scan.filesystem.ComponentIndexer;
+import org.sonar.batch.scan.filesystem.DefaultModuleFileSystem;
+import org.sonar.batch.scan.filesystem.DeprecatedFileFilters;
+import org.sonar.batch.scan.filesystem.ExclusionFilters;
+import org.sonar.batch.scan.filesystem.FileIndex;
+import org.sonar.batch.scan.filesystem.FileSystemLogger;
+import org.sonar.batch.scan.filesystem.InputFileBuilderFactory;
+import org.sonar.batch.scan.filesystem.LanguageDetectionFactory;
+import org.sonar.batch.scan.filesystem.ModuleFileSystemInitializer;
+import org.sonar.batch.scan.filesystem.PreviousFileHashLoader;
+import org.sonar.batch.scan.filesystem.ProjectFileSystemAdapter;
+import org.sonar.batch.scan.filesystem.StatusDetectionFactory;
import org.sonar.batch.scan.language.DefaultModuleLanguages;
-import org.sonar.batch.scan.report.ComponentSelectorFactory;
import org.sonar.batch.scan.report.JsonReport;
import org.sonar.core.component.ScanPerspectives;
import org.sonar.core.measure.MeasurementFilters;
// report
JsonReport.class,
- ComponentSelectorFactory.class,
// issues
IssuableFactory.class,
package org.sonar.batch.scan.report;
import org.sonar.api.issue.Issue;
+import org.sonar.api.scan.filesystem.InputFile;
+import org.sonar.batch.scan.filesystem.InputFileCache;
import java.util.Set;
abstract class ComponentSelector {
+ private final InputFileCache cache;
+
+ ComponentSelector(InputFileCache cache) {
+ this.cache = cache;
+ }
+
+ public InputFileCache getCache() {
+ return cache;
+ }
+
abstract void init();
abstract boolean register(Issue issue);
abstract Set<String> componentKeys();
+ InputFile component(String componentKey) {
+ String moduleKey = org.apache.commons.lang.StringUtils.substringBeforeLast(componentKey, ":");
+ String path = org.apache.commons.lang.StringUtils.substringAfterLast(componentKey, ":");
+ return cache.byPath(moduleKey, path);
+ }
}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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;
-import org.sonar.batch.scan.filesystem.InputFileCache;
-
-public class ComponentSelectorFactory implements BatchComponent {
-
- private final InputFileCache fileCache;
- private final AnalysisMode mode;
-
- public ComponentSelectorFactory(InputFileCache fileCache, AnalysisMode mode) {
- this.fileCache = fileCache;
- this.mode = mode;
- }
-
- public ComponentSelector create() {
- if (mode.isIncremental()) {
- return new IncrementalComponentSelector(fileCache);
- }
- return new DefaultComponentSelector();
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.Sets;
-import org.sonar.api.issue.Issue;
-
-import java.util.Set;
-
-class DefaultComponentSelector extends ComponentSelector {
-
- private final Set<String> componentKeysWithIssue = Sets.newHashSet();
-
- @Override
- void init() {
- }
-
- @Override
- boolean register(Issue issue) {
- componentKeysWithIssue.add(issue.componentKey());
- return true;
- }
-
- @Override
- Set<String> componentKeys() {
- return componentKeysWithIssue;
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.scan.filesystem.InputFile;
-
-import com.google.common.collect.Sets;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.scan.filesystem.internal.DefaultInputFile;
-import org.sonar.batch.scan.filesystem.InputFileCache;
-
-import java.util.Set;
-
-class IncrementalComponentSelector extends ComponentSelector {
-
- private final InputFileCache cache;
- private final Set<String> componentKeys = Sets.newHashSet();
-
- IncrementalComponentSelector(InputFileCache cache) {
- this.cache = cache;
- }
-
- @Override
- void init() {
- for (InputFile inputFile : cache.all()) {
- String status = inputFile.attribute(InputFile.ATTRIBUTE_STATUS);
- if (status != null && !InputFile.STATUS_SAME.equals(status)) {
- String componentKey = inputFile.attribute(DefaultInputFile.ATTRIBUTE_COMPONENT_KEY);
- if (componentKey != null) {
- componentKeys.add(componentKey);
- }
- }
- }
- }
-
- @Override
- boolean register(Issue issue) {
- return componentKeys.contains(issue.componentKey());
- }
-
- @Override
- Set<String> componentKeys() {
- return componentKeys;
- }
-}
import com.google.common.annotations.VisibleForTesting;
import com.google.common.io.Closeables;
+import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.BatchComponent;
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.rules.Rule;
import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.scan.filesystem.InputFile;
import org.sonar.api.scan.filesystem.ModuleFileSystem;
+import org.sonar.api.scan.filesystem.internal.DefaultInputFile;
import org.sonar.api.user.User;
import org.sonar.api.user.UserFinder;
import org.sonar.api.utils.SonarException;
import org.sonar.batch.events.BatchStepEvent;
import org.sonar.batch.events.EventBus;
import org.sonar.batch.issue.IssueCache;
+import org.sonar.batch.scan.filesystem.InputFileCache;
-import java.io.*;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
private final RuleFinder ruleFinder;
private final IssueCache issueCache;
private final EventBus eventBus;
- private final ComponentSelector componentSelector;
- private AnalysisMode analysisMode;
- private UserFinder userFinder;
+ private final AnalysisMode analysisMode;
+ private final UserFinder userFinder;
+ private final InputFileCache fileCache;
+ private final Project rootModule;
public JsonReport(Settings settings, ModuleFileSystem fileSystem, Server server, RuleFinder ruleFinder, IssueCache issueCache,
- EventBus eventBus, ComponentSelectorFactory componentSelectorFactory, AnalysisMode mode, UserFinder userFinder) {
- this(settings, fileSystem, server, ruleFinder, issueCache, eventBus, componentSelectorFactory.create(), mode, userFinder);
- }
-
- @VisibleForTesting
- JsonReport(Settings settings, ModuleFileSystem fileSystem, Server server, RuleFinder ruleFinder, IssueCache issueCache,
- EventBus eventBus, ComponentSelector componentSelector, AnalysisMode analysisMode, UserFinder userFinder) {
+ EventBus eventBus, AnalysisMode analysisMode, UserFinder userFinder, Project rootModule, InputFileCache fileCache) {
this.settings = settings;
this.fileSystem = fileSystem;
this.server = server;
this.ruleFinder = ruleFinder;
this.issueCache = issueCache;
this.eventBus = eventBus;
- this.componentSelector = componentSelector;
this.analysisMode = analysisMode;
this.userFinder = userFinder;
+ this.rootModule = rootModule;
+ this.fileCache = fileCache;
}
public void execute() {
Set<RuleKey> ruleKeys = newHashSet();
Set<String> userLogins = newHashSet();
- componentSelector.init();
writeJsonIssues(json, ruleKeys, userLogins);
writeJsonComponents(json);
writeJsonRules(json, ruleKeys);
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 && componentSelector.register(issue)) {
+ if (issue.resolution() == null) {
json
.beginObject()
.prop("key", issue.key())
private void writeJsonComponents(JsonWriter json) throws IOException {
json.name("components").beginArray();
- for (String componentKey : componentSelector.componentKeys()) {
+ // Dump modules
+ writeJsonModuleComponents(json, rootModule);
+ // TODO we need to dump directories
+ for (InputFile inputFile : fileCache.all()) {
json
.beginObject()
- .prop("key", componentKey)
+ .prop("key", inputFile.attribute(DefaultInputFile.ATTRIBUTE_COMPONENT_KEY))
+ .prop("path", inputFile.path())
+ .prop("moduleKey", StringUtils.substringBeforeLast(inputFile.attribute(DefaultInputFile.ATTRIBUTE_COMPONENT_KEY), ":"))
+ .prop("status", inputFile.attribute(InputFile.ATTRIBUTE_STATUS))
.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) {
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.rules.Rule;
import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.scan.filesystem.InputFile;
import org.sonar.api.scan.filesystem.ModuleFileSystem;
+import org.sonar.api.scan.filesystem.internal.DefaultInputFile;
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.InputFileCache;
import org.sonar.core.user.DefaultUser;
import org.sonar.test.TestUtils;
mode = mock(AnalysisMode.class);
when(mode.isPreview()).thenReturn(true);
userFinder = mock(UserFinder.class);
- jsonReport = new JsonReport(settings, fileSystem, server, ruleFinder, issueCache, mock(EventBus.class), new DefaultComponentSelector(), mode, userFinder);
+ InputFile inputFile = mock(InputFile.class);
+ when(inputFile.path()).thenReturn("src/main/java/org/apache/struts/Action.java");
+ when(inputFile.attribute(DefaultInputFile.ATTRIBUTE_COMPONENT_KEY)).thenReturn("struts:src/main/java/org/apache/struts/Action.java");
+ when(inputFile.attribute(InputFile.ATTRIBUTE_STATUS)).thenReturn(InputFile.STATUS_CHANGED);
+ InputFileCache fileCache = mock(InputFileCache.class);
+ when(fileCache.all()).thenReturn(Arrays.asList(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");
+ jsonReport = new JsonReport(settings, fileSystem, server, ruleFinder, 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")
+ .setComponentKey("struts:src/main/java/org/apache/struts/Action.java")
.setRuleKey(RuleKey.of("squid", "AvoidCycles"))
.setMessage("There are 2 cycles")
.setSeverity("MINOR")
RuleKey ruleKey = RuleKey.of("squid", "AvoidCycles");
DefaultIssue issue = new DefaultIssue()
.setKey("200")
- .setComponentKey("struts:/src/main/java/org/apache/struts/Action.java")
+ .setComponentKey("struts:src/main/java/org/apache/struts/Action.java")
.setRuleKey(ruleKey)
.setStatus(Issue.STATUS_CLOSED)
.setResolution(Issue.RESOLUTION_FIXED)
{
"version": "3.6",
"issues": [],
- "components": [],
+ "components": [
+ {
+ "key": "struts"
+ },
+ {
+ "key": "struts-core",
+ "path": "core"
+ },
+ {
+ "key": "struts-ui",
+ "path": "ui"
+ },
+ {
+ "key": "struts:src/main/java/org/apache/struts/Action.java",
+ "path": "src/main/java/org/apache/struts/Action.java"
+ }
+],
"rules": []
}
{"version": "3.6", "issues": [
{
"key": "200",
- "component": "struts:/src/main/java/org/apache/struts/Action.java",
+ "component": "struts:src/main/java/org/apache/struts/Action.java",
"line": 1,
"message": "There are 2 cycles",
"severity": "MINOR",
}
], "components": [
{
- "key": "struts:/src/main/java/org/apache/struts/Action.java"
+ "key": "struts"
+ },
+ {
+ "key": "struts-core",
+ "path": "core"
+ },
+ {
+ "key": "struts-ui",
+ "path": "ui"
+ },
+ {
+ "key": "struts:src/main/java/org/apache/struts/Action.java",
+ "path": "src/main/java/org/apache/struts/Action.java",
+ "moduleKey": "struts",
+ "status": "CHANGED"
}
], "rules": [
{