diff options
author | Michal Duda <michalno1@gmail.com> | 2018-11-13 11:00:42 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2019-01-16 09:43:00 +0100 |
commit | 6dd294b1f5af7c74191db30101e3721d00102204 (patch) | |
tree | 372dbc219371a610c32fb8b723869291a7148c5f /sonar-plugin-api | |
parent | b44c75c2b93ca2d91d6ce559a08a0d994c73bd85 (diff) | |
download | sonarqube-6dd294b1f5af7c74191db30101e3721d00102204.tar.gz sonarqube-6dd294b1f5af7c74191db30101e3721d00102204.zip |
SONAR-11459 move dir and module issues to root
Diffstat (limited to 'sonar-plugin-api')
6 files changed, 138 insertions, 38 deletions
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java index a316dc2fbe8..58286e136e7 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java @@ -108,7 +108,7 @@ public class SensorContextTester implements SensorContext { private DefaultFileSystem fs; private ActiveRules activeRules; private InMemorySensorStorage sensorStorage; - private InputModule module; + private DefaultInputModule module; private SonarRuntime runtime; private boolean cancelled; @@ -220,7 +220,7 @@ public class SensorContextTester implements SensorContext { @Override public NewIssue newIssue() { - return new DefaultIssue(sensorStorage); + return new DefaultIssue(module, sensorStorage); } public Collection<Issue> allIssues() { @@ -229,7 +229,7 @@ public class SensorContextTester implements SensorContext { @Override public NewExternalIssue newExternalIssue() { - return new DefaultExternalIssue(sensorStorage); + return new DefaultExternalIssue(module, sensorStorage); } @Override diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/AbstractDefaultIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/AbstractDefaultIssue.java index 79a62e03cc4..c993ee62d07 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/AbstractDefaultIssue.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/AbstractDefaultIssue.java @@ -20,32 +20,42 @@ package org.sonar.api.batch.sensor.issue.internal; import com.google.common.base.Preconditions; +import java.nio.file.Path; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.Optional; import javax.annotation.Nullable; +import org.sonar.api.batch.fs.InputComponent; +import org.sonar.api.batch.fs.internal.DefaultInputDir; +import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.sensor.internal.DefaultStorable; import org.sonar.api.batch.sensor.internal.SensorStorage; import org.sonar.api.batch.sensor.issue.Issue.Flow; import org.sonar.api.batch.sensor.issue.IssueLocation; import org.sonar.api.batch.sensor.issue.NewIssueLocation; +import org.sonar.api.utils.PathUtils; import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Strings.isNullOrEmpty; import static java.util.Collections.unmodifiableList; import static java.util.stream.Collectors.toList; -public abstract class AbstractDefaultIssue<T extends AbstractDefaultIssue> extends DefaultStorable { +public abstract class AbstractDefaultIssue<T extends AbstractDefaultIssue> extends DefaultStorable { protected IssueLocation primaryLocation; protected List<List<IssueLocation>> flows = new ArrayList<>(); - - protected AbstractDefaultIssue() { - super(null); + protected DefaultInputModule projectRoot; + + protected AbstractDefaultIssue(DefaultInputModule projectRoot) { + this(projectRoot, null); } - - public AbstractDefaultIssue(@Nullable SensorStorage storage) { + + public AbstractDefaultIssue(DefaultInputModule projectRoot, @Nullable SensorStorage storage) { super(storage); + this.projectRoot = projectRoot; } - + public IssueLocation primaryLocation() { return primaryLocation; } @@ -55,7 +65,7 @@ public abstract class AbstractDefaultIssue<T extends AbstractDefaultIssue> exte .<Flow>map(l -> () -> unmodifiableList(new ArrayList<>(l))) .collect(toList()); } - + public NewIssueLocation newLocation() { return new DefaultIssueLocation(); } @@ -63,23 +73,50 @@ public abstract class AbstractDefaultIssue<T extends AbstractDefaultIssue> exte public T at(NewIssueLocation primaryLocation) { Preconditions.checkArgument(primaryLocation != null, "Cannot use a location that is null"); checkState(this.primaryLocation == null, "at() already called"); - this.primaryLocation = (DefaultIssueLocation) primaryLocation; + this.primaryLocation = rewriteLocation((DefaultIssueLocation) primaryLocation); Preconditions.checkArgument(this.primaryLocation.inputComponent() != null, "Cannot use a location with no input component"); return (T) this; } public T addLocation(NewIssueLocation secondaryLocation) { - flows.add(Arrays.asList((IssueLocation) secondaryLocation)); + flows.add(Collections.singletonList(rewriteLocation((DefaultIssueLocation) secondaryLocation))); return (T) this; } public T addFlow(Iterable<NewIssueLocation> locations) { List<IssueLocation> flowAsList = new ArrayList<>(); for (NewIssueLocation issueLocation : locations) { - flowAsList.add((DefaultIssueLocation) issueLocation); + flowAsList.add(rewriteLocation((DefaultIssueLocation) issueLocation)); } flows.add(flowAsList); return (T) this; } - + + private DefaultIssueLocation rewriteLocation(DefaultIssueLocation location) { + InputComponent component = location.inputComponent(); + Optional<Path> dirOrModulePath = Optional.empty(); + + if (component instanceof DefaultInputDir) { + DefaultInputDir dirComponent = (DefaultInputDir) component; + dirOrModulePath = Optional.of(projectRoot.getBaseDir().relativize(dirComponent.path())); + } else if (component instanceof DefaultInputModule && !Objects.equals(projectRoot.key(), component.key())) { + DefaultInputModule moduleComponent = (DefaultInputModule) component; + dirOrModulePath = Optional.of(projectRoot.getBaseDir().relativize(moduleComponent.getBaseDir())); + } + + if (dirOrModulePath.isPresent()) { + String path = PathUtils.sanitize(dirOrModulePath.get().toString()); + DefaultIssueLocation fixedLocation = new DefaultIssueLocation(); + fixedLocation.on(projectRoot); + StringBuilder fullMessage = new StringBuilder(); + if (!isNullOrEmpty(path)) { + fullMessage.append("[").append(path).append("] "); + } + fullMessage.append(location.message()); + fixedLocation.message(fullMessage.toString()); + return fixedLocation; + } else { + return location; + } + } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssue.java index facceda9c6c..a9b9cc1051d 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssue.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssue.java @@ -21,6 +21,7 @@ package org.sonar.api.batch.sensor.issue.internal; import com.google.common.base.Preconditions; import javax.annotation.Nullable; +import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.rule.Severity; import org.sonar.api.batch.sensor.internal.SensorStorage; import org.sonar.api.batch.sensor.issue.ExternalIssue; @@ -39,12 +40,12 @@ public class DefaultExternalIssue extends AbstractDefaultIssue<DefaultExternalIs private String engineId; private String ruleId; - public DefaultExternalIssue() { - super(null); + public DefaultExternalIssue(DefaultInputModule projectRoot) { + this(projectRoot, null); } - public DefaultExternalIssue(@Nullable SensorStorage storage) { - super(storage); + public DefaultExternalIssue(DefaultInputModule projectRoot, @Nullable SensorStorage storage) { + super(projectRoot, storage); } @Override diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java index d936ba09371..1b7de9d9ab0 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java @@ -21,6 +21,7 @@ package org.sonar.api.batch.sensor.issue.internal; import com.google.common.base.Preconditions; import javax.annotation.Nullable; +import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.rule.Severity; import org.sonar.api.batch.sensor.internal.SensorStorage; import org.sonar.api.batch.sensor.issue.Issue; @@ -37,12 +38,12 @@ public class DefaultIssue extends AbstractDefaultIssue<DefaultIssue> implements private Double gap; private Severity overriddenSeverity; - public DefaultIssue() { - super(null); + public DefaultIssue(DefaultInputModule projectRoot) { + this(projectRoot, null); } - public DefaultIssue(@Nullable SensorStorage storage) { - super(storage); + public DefaultIssue(DefaultInputModule projectRoot, @Nullable SensorStorage storage) { + super(projectRoot, storage); } public DefaultIssue forRule(RuleKey ruleKey) { @@ -54,7 +55,6 @@ public class DefaultIssue extends AbstractDefaultIssue<DefaultIssue> implements return this.ruleKey; } - @Override public DefaultIssue gap(@Nullable Double gap) { Preconditions.checkArgument(gap == null || gap >= 0, format("Gap must be greater than or equal 0 (got %s)", gap)); diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssueTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssueTest.java index 33da8b1a2c1..6ef27d97f3c 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssueTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssueTest.java @@ -19,11 +19,16 @@ */ package org.sonar.api.batch.sensor.issue.internal; +import java.io.IOException; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.fs.InputComponent; import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.TestInputFileBuilder; import org.sonar.api.batch.rule.Severity; import org.sonar.api.batch.sensor.internal.SensorStorage; @@ -35,6 +40,20 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; public class DefaultExternalIssueTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + private DefaultInputModule projectRoot; + + @Before + public void setup() throws IOException { + projectRoot = new DefaultInputModule(ProjectDefinition.create() + .setKey("foo") + .setBaseDir(temp.newFolder()) + .setWorkDir(temp.newFolder())); + } + @Rule public ExpectedException exception = ExpectedException.none(); @@ -45,7 +64,7 @@ public class DefaultExternalIssueTest { @Test public void build_file_issue() { SensorStorage storage = mock(SensorStorage.class); - DefaultExternalIssue issue = new DefaultExternalIssue(storage) + DefaultExternalIssue issue = new DefaultExternalIssue(projectRoot, storage) .at(new DefaultIssueLocation() .on(inputFile) .at(inputFile.selectLine(1)) @@ -73,7 +92,7 @@ public class DefaultExternalIssueTest { @Test public void fail_to_store_if_no_type() { SensorStorage storage = mock(SensorStorage.class); - DefaultExternalIssue issue = new DefaultExternalIssue(storage) + DefaultExternalIssue issue = new DefaultExternalIssue(projectRoot, storage) .at(new DefaultIssueLocation() .on(inputFile) .at(inputFile.selectLine(1)) @@ -90,7 +109,7 @@ public class DefaultExternalIssueTest { @Test public void fail_to_store_if_primary_location_is_not_a_file() { SensorStorage storage = mock(SensorStorage.class); - DefaultExternalIssue issue = new DefaultExternalIssue(storage) + DefaultExternalIssue issue = new DefaultExternalIssue(projectRoot, storage) .at(new DefaultIssueLocation() .on(mock(InputComponent.class)) .message("Wrong way!")) @@ -102,11 +121,11 @@ public class DefaultExternalIssueTest { exception.expectMessage("External issues must be located in files"); issue.save(); } - + @Test public void fail_to_store_if_primary_location_has_no_message() { SensorStorage storage = mock(SensorStorage.class); - DefaultExternalIssue issue = new DefaultExternalIssue(storage) + DefaultExternalIssue issue = new DefaultExternalIssue(projectRoot, storage) .at(new DefaultIssueLocation() .on(inputFile) .at(inputFile.selectLine(1))) @@ -123,7 +142,7 @@ public class DefaultExternalIssueTest { @Test public void fail_to_store_if_no_severity() { SensorStorage storage = mock(SensorStorage.class); - DefaultExternalIssue issue = new DefaultExternalIssue(storage) + DefaultExternalIssue issue = new DefaultExternalIssue(projectRoot, storage) .at(new DefaultIssueLocation() .on(inputFile) .at(inputFile.selectLine(1)) diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java index 37664b90cc3..5d36dcd2a9c 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java @@ -19,7 +19,9 @@ */ package org.sonar.api.batch.sensor.issue.internal; +import java.io.File; import java.io.IOException; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -41,14 +43,24 @@ public class DefaultIssueTest { @Rule public TemporaryFolder temp = new TemporaryFolder(); + private DefaultInputModule projectRoot; + private DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.php") .initMetadata("Foo\nBar\n") .build(); + @Before + public void prepare() throws IOException { + projectRoot = new DefaultInputModule(ProjectDefinition.create() + .setKey("foo") + .setBaseDir(temp.newFolder()) + .setWorkDir(temp.newFolder())); + } + @Test public void build_file_issue() { SensorStorage storage = mock(SensorStorage.class); - DefaultIssue issue = new DefaultIssue(storage) + DefaultIssue issue = new DefaultIssue(projectRoot, storage) .at(new DefaultIssueLocation() .on(inputFile) .at(inputFile.selectLine(1)) @@ -68,19 +80,50 @@ public class DefaultIssueTest { } @Test - public void build_directory_issue() { + public void move_directory_issue_to_project_root() { SensorStorage storage = mock(SensorStorage.class); - DefaultIssue issue = new DefaultIssue(storage) + DefaultIssue issue = new DefaultIssue(projectRoot, storage) .at(new DefaultIssueLocation() - .on(new DefaultInputDir("foo", "src")) + .on(new DefaultInputDir("foo", "src/main").setModuleBaseDir(projectRoot.getBaseDir())) .message("Wrong way!")) .forRule(RuleKey.of("repo", "rule")) .overrideSeverity(Severity.BLOCKER); - assertThat(issue.primaryLocation().inputComponent()).isEqualTo(new DefaultInputDir("foo", "src")); + assertThat(issue.primaryLocation().inputComponent()).isEqualTo(projectRoot); assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule")); assertThat(issue.primaryLocation().textRange()).isNull(); - assertThat(issue.primaryLocation().message()).isEqualTo("Wrong way!"); + assertThat(issue.primaryLocation().message()).isEqualTo("[src/main] Wrong way!"); + assertThat(issue.overriddenSeverity()).isEqualTo(Severity.BLOCKER); + + issue.save(); + + verify(storage).store(issue); + } + + @Test + public void move_submodule_issue_to_project_root() { + File subModuleDirectory = new File(projectRoot.getBaseDir().toString(), "bar"); + subModuleDirectory.mkdir(); + + ProjectDefinition subModuleDefinition = ProjectDefinition.create() + .setKey("foo/bar") + .setBaseDir(subModuleDirectory) + .setWorkDir(subModuleDirectory); + projectRoot.definition().addSubProject(subModuleDefinition); + DefaultInputModule subModule = new DefaultInputModule(subModuleDefinition); + + SensorStorage storage = mock(SensorStorage.class); + DefaultIssue issue = new DefaultIssue(projectRoot, storage) + .at(new DefaultIssueLocation() + .on(subModule) + .message("Wrong way!")) + .forRule(RuleKey.of("repo", "rule")) + .overrideSeverity(Severity.BLOCKER); + + assertThat(issue.primaryLocation().inputComponent()).isEqualTo(projectRoot); + assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule")); + assertThat(issue.primaryLocation().textRange()).isNull(); + assertThat(issue.primaryLocation().message()).isEqualTo("[bar] Wrong way!"); assertThat(issue.overriddenSeverity()).isEqualTo(Severity.BLOCKER); issue.save(); @@ -92,7 +135,7 @@ public class DefaultIssueTest { public void build_project_issue() throws IOException { SensorStorage storage = mock(SensorStorage.class); DefaultInputModule inputModule = new DefaultInputModule(ProjectDefinition.create().setKey("foo").setBaseDir(temp.newFolder()).setWorkDir(temp.newFolder())); - DefaultIssue issue = new DefaultIssue(storage) + DefaultIssue issue = new DefaultIssue(projectRoot, storage) .at(new DefaultIssueLocation() .on(inputModule) .message("Wrong way!")) |