]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-926 Export path information for components in JsonReport
authorJulien HENRY <julien.henry@sonarsource.com>
Wed, 12 Feb 2014 09:49:24 +0000 (10:49 +0100)
committerJulien HENRY <julien.henry@sonarsource.com>
Wed, 12 Feb 2014 09:50:57 +0000 (10:50 +0100)
sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
sonar-batch/src/main/java/org/sonar/batch/scan/report/ComponentSelector.java
sonar-batch/src/main/java/org/sonar/batch/scan/report/ComponentSelectorFactory.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/scan/report/DefaultComponentSelector.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/scan/report/IncrementalComponentSelector.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/scan/report/JsonReport.java
sonar-batch/src/test/java/org/sonar/batch/scan/report/JsonReportTest.java
sonar-batch/src/test/resources/org/sonar/batch/scan/report/JsonReportTest/report-without-resolved-issues.json
sonar-batch/src/test/resources/org/sonar/batch/scan/report/JsonReportTest/report.json

index f5112f7c20bc19168e8bdb3cdb56b339bd4f232e..ab7733a95abc51d7f982ca668c3602041cb5c80e 100644 (file)
@@ -28,7 +28,12 @@ import org.sonar.api.batch.rule.CheckFactory;
 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;
@@ -46,9 +51,19 @@ import org.sonar.batch.rule.ActiveRulesProvider;
 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;
@@ -126,7 +141,6 @@ public class ModuleScanContainer extends ComponentContainer {
 
       // report
       JsonReport.class,
-      ComponentSelectorFactory.class,
 
       // issues
       IssuableFactory.class,
index 8542eb6476e21304aa7b99b166aa3f0fc7c2ffe0..277b9c41f69276a12840c42ebf84b9fd75b9cde9 100644 (file)
 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);
+  }
 }
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/report/ComponentSelectorFactory.java b/sonar-batch/src/main/java/org/sonar/batch/scan/report/ComponentSelectorFactory.java
deleted file mode 100644 (file)
index b384130..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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();
-  }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/report/DefaultComponentSelector.java b/sonar-batch/src/main/java/org/sonar/batch/scan/report/DefaultComponentSelector.java
deleted file mode 100644 (file)
index 5b7223a..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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;
-  }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/report/IncrementalComponentSelector.java b/sonar-batch/src/main/java/org/sonar/batch/scan/report/IncrementalComponentSelector.java
deleted file mode 100644 (file)
index 9c18af5..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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;
-  }
-}
index 0d85537d790e10806e8d54af7f91955d0dbf2b2e..7c835ecce71b3d5bcb2fbe1a306d1ab8fef9c381 100644 (file)
@@ -21,16 +21,20 @@ package org.sonar.batch.scan.report;
 
 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;
@@ -39,8 +43,13 @@ 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.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;
@@ -60,27 +69,23 @@ public class JsonReport implements BatchComponent {
   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() {
@@ -116,7 +121,6 @@ public class JsonReport implements BatchComponent {
 
       Set<RuleKey> ruleKeys = newHashSet();
       Set<String> userLogins = newHashSet();
-      componentSelector.init();
       writeJsonIssues(json, ruleKeys, userLogins);
       writeJsonComponents(json);
       writeJsonRules(json, ruleKeys);
@@ -132,7 +136,7 @@ public class JsonReport implements BatchComponent {
   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())
@@ -165,15 +169,32 @@ public class JsonReport implements BatchComponent {
 
   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) {
index 3ed7a9ebfaf897334af9223b406de27f343043d0..e4b8a34850941938d6e1367504b9afc9b893e026 100644 (file)
@@ -29,16 +29,20 @@ 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.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;
 
@@ -82,14 +86,26 @@ public class JsonReportTest {
     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")
@@ -120,7 +136,7 @@ public class JsonReportTest {
     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)
index 12f0bf5fee0ecef57290c38c117812d04abbc770..59c9c3272bb36d16c5b6c668bd1c354a680d1f0c 100644 (file)
@@ -1,6 +1,22 @@
 {
   "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": []
 }
index 62bf4da8a7558acd555eff4f9c11b3ee277c6428..7ff8f67abc0ab83e8f6aca17e1985e2654ebdad9 100644 (file)
@@ -1,7 +1,7 @@
 {"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": [
   {