diff options
author | Duarte Meneses <duarte.meneses@sonarsource.com> | 2019-06-04 10:41:54 -0500 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-07-12 20:21:13 +0200 |
commit | 65c61f5006221de77fff2c314d07df8fb73ddc45 (patch) | |
tree | f63e2dc7d046f421ec67ef00fb71144eb683e877 /sonar-scanner-engine | |
parent | be4e3879670cfe7c26bd1cfed28e29a7b20d2e2a (diff) | |
download | sonarqube-65c61f5006221de77fff2c314d07df8fb73ddc45.tar.gz sonarqube-65c61f5006221de77fff2c314d07df8fb73ddc45.zip |
Extract implementation from plugin API - Scanner Sensor
Diffstat (limited to 'sonar-scanner-engine')
19 files changed, 899 insertions, 29 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java index eecbbd15e84..be5b715891f 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java @@ -28,7 +28,7 @@ import java.util.Map.Entry; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.measure.MetricFinder; import org.sonar.api.batch.sensor.internal.SensorStorage; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; +import org.sonar.scanner.sensor.DefaultMeasure; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.FileLinesContext; import org.sonar.api.utils.KeyValueFormat; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/postjob/DefaultPostJobDescriptor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/postjob/DefaultPostJobDescriptor.java new file mode 100644 index 00000000000..c3c23969ac6 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/postjob/DefaultPostJobDescriptor.java @@ -0,0 +1,56 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.api.batch.postjob.internal; + +import java.util.Arrays; +import java.util.Collection; +import org.sonar.api.batch.postjob.PostJobDescriptor; + +public class DefaultPostJobDescriptor implements PostJobDescriptor { + + private String name; + private String[] properties = new String[0]; + + public String name() { + return name; + } + + public Collection<String> properties() { + return Arrays.asList(properties); + } + + @Override + public DefaultPostJobDescriptor name(String name) { + this.name = name; + return this; + } + + @Override + public DefaultPostJobDescriptor requireProperty(String... propertyKey) { + return requireProperties(propertyKey); + } + + @Override + public DefaultPostJobDescriptor requireProperties(String... propertyKeys) { + this.properties = propertyKeys; + return this; + } + +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/TestExecutionPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/TestExecutionPublisher.java index 9c19a887d68..ad4ac749120 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/TestExecutionPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/TestExecutionPublisher.java @@ -26,7 +26,7 @@ import org.sonar.api.batch.fs.InputComponent; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.internal.DefaultInputComponent; import org.sonar.api.batch.fs.internal.DefaultInputFile; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; +import org.sonar.scanner.sensor.DefaultMeasure; import org.sonar.api.test.MutableTestPlan; import org.sonar.api.test.TestCase; import org.sonar.api.test.TestCase.Status; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/AbstractDefaultIssue.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/AbstractDefaultIssue.java new file mode 100644 index 00000000000..b77d1141911 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/AbstractDefaultIssue.java @@ -0,0 +1,122 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.scanner.sensor; + +import java.nio.file.Path; +import java.util.ArrayList; +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.fs.internal.DefaultInputProject; +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 java.util.Collections.unmodifiableList; +import static java.util.stream.Collectors.toList; +import static org.sonar.api.utils.Preconditions.checkArgument; +import static org.sonar.api.utils.Preconditions.checkState; + +public abstract class AbstractDefaultIssue<T extends AbstractDefaultIssue> extends DefaultStorable { + protected IssueLocation primaryLocation; + protected List<List<IssueLocation>> flows = new ArrayList<>(); + protected DefaultInputProject project; + + protected AbstractDefaultIssue(DefaultInputProject project) { + this(project, null); + } + + public AbstractDefaultIssue(DefaultInputProject project, @Nullable SensorStorage storage) { + super(storage); + this.project = project; + } + + public IssueLocation primaryLocation() { + return primaryLocation; + } + + public List<Flow> flows() { + return this.flows.stream() + .<Flow>map(l -> () -> unmodifiableList(new ArrayList<>(l))) + .collect(toList()); + } + + public NewIssueLocation newLocation() { + return new DefaultIssueLocation(); + } + + public T at(NewIssueLocation primaryLocation) { + checkArgument(primaryLocation != null, "Cannot use a location that is null"); + checkState(this.primaryLocation == null, "at() already called"); + this.primaryLocation = rewriteLocation((DefaultIssueLocation) primaryLocation); + checkArgument(this.primaryLocation.inputComponent() != null, "Cannot use a location with no input component"); + return (T) this; + } + + public T addLocation(NewIssueLocation 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(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(project.getBaseDir().relativize(dirComponent.path())); + } else if (component instanceof DefaultInputModule && !Objects.equals(project.key(), component.key())) { + DefaultInputModule moduleComponent = (DefaultInputModule) component; + dirOrModulePath = Optional.of(project.getBaseDir().relativize(moduleComponent.getBaseDir())); + } + + if (dirOrModulePath.isPresent()) { + String path = PathUtils.sanitize(dirOrModulePath.get().toString()); + DefaultIssueLocation fixedLocation = new DefaultIssueLocation(); + fixedLocation.on(project); + StringBuilder fullMessage = new StringBuilder(); + if (path != null && !path.isEmpty()) { + fullMessage.append("[").append(path).append("] "); + } + fullMessage.append(location.message()); + fixedLocation.message(fullMessage.toString()); + return fixedLocation; + } else { + return location; + } + } +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/AbstractSensorOptimizer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/AbstractSensorOptimizer.java index f9dae8328e6..95b473e05ce 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/AbstractSensorOptimizer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/AbstractSensorOptimizer.java @@ -24,7 +24,6 @@ import org.slf4j.LoggerFactory; import org.sonar.api.batch.fs.FilePredicate; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.rule.ActiveRules; -import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor; import org.sonar.api.config.Configuration; public abstract class AbstractSensorOptimizer { diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/AbstractSensorWrapper.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/AbstractSensorWrapper.java index 43773f1eb1d..caba9bc9101 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/AbstractSensorWrapper.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/AbstractSensorWrapper.java @@ -20,7 +20,6 @@ package org.sonar.scanner.sensor; import org.sonar.api.batch.sensor.SensorContext; -import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor; import org.sonar.api.scanner.sensor.ProjectSensor; public abstract class AbstractSensorWrapper<G extends ProjectSensor> { diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultAdHocRule.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultAdHocRule.java new file mode 100644 index 00000000000..23dbd341c36 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultAdHocRule.java @@ -0,0 +1,127 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.scanner.sensor; + +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; +import org.sonar.api.batch.rule.Severity; +import org.sonar.api.batch.sensor.internal.DefaultStorable; +import org.sonar.api.batch.sensor.internal.SensorStorage; +import org.sonar.api.batch.sensor.rule.AdHocRule; +import org.sonar.api.batch.sensor.rule.NewAdHocRule; +import org.sonar.api.rules.RuleType; + +import static org.apache.commons.lang.StringUtils.isNotBlank; +import static org.sonar.api.utils.Preconditions.checkState; + +public class DefaultAdHocRule extends DefaultStorable implements AdHocRule, NewAdHocRule { + private Severity severity; + private RuleType type; + private String name; + private String description; + private String engineId; + private String ruleId; + + public DefaultAdHocRule() { + super(null); + } + + public DefaultAdHocRule(@Nullable SensorStorage storage) { + super(storage); + } + + @Override + public DefaultAdHocRule severity(Severity severity) { + this.severity = severity; + return this; + } + + @Override + public String engineId() { + return engineId; + } + + @Override + public String ruleId() { + return ruleId; + } + + @Override + public String name() { + return name; + } + + @CheckForNull + @Override + public String description() { + return description; + } + + @Override + public Severity severity() { + return this.severity; + } + + @Override + public void doSave() { + checkState(isNotBlank(engineId), "Engine id is mandatory on ad hoc rule"); + checkState(isNotBlank(ruleId), "Rule id is mandatory on ad hoc rule"); + checkState(isNotBlank(name), "Name is mandatory on every ad hoc rule"); + checkState(severity != null, "Severity is mandatory on every ad hoc rule"); + checkState(type != null, "Type is mandatory on every ad hoc rule"); + storage.store(this); + } + + @Override + public RuleType type() { + return type; + } + + @Override + public DefaultAdHocRule engineId(String engineId) { + this.engineId = engineId; + return this; + } + + @Override + public DefaultAdHocRule ruleId(String ruleId) { + this.ruleId = ruleId; + return this; + } + + @Override + public DefaultAdHocRule name(String name) { + this.name = name; + return this; + } + + @Override + public DefaultAdHocRule description(@Nullable String description) { + this.description = description; + return this; + } + + @Override + public DefaultAdHocRule type(RuleType type) { + this.type = type; + return this; + } + +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultExternalIssue.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultExternalIssue.java new file mode 100644 index 00000000000..3c09a40aceb --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultExternalIssue.java @@ -0,0 +1,134 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.scanner.sensor; + +import javax.annotation.Nullable; +import org.sonar.api.batch.fs.internal.DefaultInputProject; +import org.sonar.api.batch.rule.Severity; +import org.sonar.api.batch.sensor.internal.SensorStorage; +import org.sonar.api.batch.sensor.issue.ExternalIssue; +import org.sonar.api.batch.sensor.issue.NewExternalIssue; +import org.sonar.api.rule.RuleKey; +import org.sonar.api.rules.RuleType; + +import static java.lang.String.format; +import static java.util.Objects.requireNonNull; +import static org.sonar.api.utils.Preconditions.checkArgument; +import static org.sonar.api.utils.Preconditions.checkState; + +public class DefaultExternalIssue extends AbstractDefaultIssue<DefaultExternalIssue> implements ExternalIssue, NewExternalIssue { + private Long effort; + private Severity severity; + private RuleType type; + private String engineId; + private String ruleId; + + public DefaultExternalIssue(DefaultInputProject project) { + this(project, null); + } + + public DefaultExternalIssue(DefaultInputProject project, @Nullable SensorStorage storage) { + super(project, storage); + } + + @Override + public DefaultExternalIssue remediationEffortMinutes(@Nullable Long effort) { + checkArgument(effort == null || effort >= 0, format("effort must be greater than or equal 0 (got %s)", effort)); + this.effort = effort; + return this; + } + + @Override + public DefaultExternalIssue severity(Severity severity) { + this.severity = severity; + return this; + } + + @Override + public String engineId() { + return engineId; + } + + @Override + public String ruleId() { + return ruleId; + } + + @Override + public Severity severity() { + return this.severity; + } + + @Override + public Long remediationEffort() { + return this.effort; + } + + @Override + public void doSave() { + requireNonNull(this.engineId, "Engine id is mandatory on external issue"); + requireNonNull(this.ruleId, "Rule id is mandatory on external issue"); + checkState(primaryLocation != null, "Primary location is mandatory on every external issue"); + checkState(primaryLocation.inputComponent().isFile(), "External issues must be located in files"); + checkState(primaryLocation.message() != null, "External issues must have a message"); + checkState(severity != null, "Severity is mandatory on every external issue"); + checkState(type != null, "Type is mandatory on every external issue"); + storage.store(this); + } + + @Override + public RuleType type() { + return type; + } + + @Override + public NewExternalIssue engineId(String engineId) { + this.engineId = engineId; + return this; + } + + @Override + public NewExternalIssue ruleId(String ruleId) { + this.ruleId = ruleId; + return this; + } + + @Override + public DefaultExternalIssue forRule(RuleKey ruleKey) { + this.engineId = ruleKey.repository(); + this.ruleId = ruleKey.rule(); + return this; + } + + @Override + public RuleKey ruleKey() { + if (engineId != null && ruleId != null) { + return RuleKey.of(RuleKey.EXTERNAL_RULE_REPO_PREFIX + engineId, ruleId); + } + return null; + } + + @Override + public DefaultExternalIssue type(RuleType type) { + this.type = type; + return this; + } + +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultIssue.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultIssue.java new file mode 100644 index 00000000000..369d7314c2f --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultIssue.java @@ -0,0 +1,93 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.scanner.sensor; + +import javax.annotation.Nullable; +import org.sonar.api.batch.fs.internal.DefaultInputProject; +import org.sonar.api.batch.rule.Severity; +import org.sonar.api.batch.sensor.internal.SensorStorage; +import org.sonar.api.batch.sensor.issue.Issue; +import org.sonar.api.batch.sensor.issue.IssueLocation; +import org.sonar.api.batch.sensor.issue.NewIssue; +import org.sonar.api.rule.RuleKey; + +import static java.lang.String.format; +import static java.util.Objects.requireNonNull; +import static org.sonar.api.utils.Preconditions.checkArgument; +import static org.sonar.api.utils.Preconditions.checkState; + +public class DefaultIssue extends AbstractDefaultIssue<DefaultIssue> implements Issue, NewIssue { + private RuleKey ruleKey; + private Double gap; + private Severity overriddenSeverity; + + public DefaultIssue(DefaultInputProject project) { + this(project, null); + } + + public DefaultIssue(DefaultInputProject project, @Nullable SensorStorage storage) { + super(project, storage); + } + + public DefaultIssue forRule(RuleKey ruleKey) { + this.ruleKey = ruleKey; + return this; + } + + public RuleKey ruleKey() { + return this.ruleKey; + } + + @Override + public DefaultIssue gap(@Nullable Double gap) { + checkArgument(gap == null || gap >= 0, format("Gap must be greater than or equal 0 (got %s)", gap)); + this.gap = gap; + return this; + } + + @Override + public DefaultIssue overrideSeverity(@Nullable Severity severity) { + this.overriddenSeverity = severity; + return this; + } + + @Override + public Severity overriddenSeverity() { + return this.overriddenSeverity; + } + + @Override + public Double gap() { + return this.gap; + } + + @Override + public IssueLocation primaryLocation() { + return primaryLocation; + } + + @Override + public void doSave() { + requireNonNull(this.ruleKey, "ruleKey is mandatory on issue"); + checkState(primaryLocation != null, "Primary location is mandatory on every issue"); + storage.store(this); + } + +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultIssueLocation.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultIssueLocation.java new file mode 100644 index 00000000000..b08d093c261 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultIssueLocation.java @@ -0,0 +1,92 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.scanner.sensor; + +import javax.annotation.Nullable; +import org.sonar.api.batch.fs.InputComponent; +import org.sonar.api.batch.fs.TextRange; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.sensor.issue.IssueLocation; +import org.sonar.api.batch.sensor.issue.NewIssueLocation; + +import static java.util.Objects.requireNonNull; +import static org.apache.commons.lang.StringUtils.abbreviate; +import static org.apache.commons.lang.StringUtils.trim; +import static org.sonar.api.utils.Preconditions.checkArgument; +import static org.sonar.api.utils.Preconditions.checkState; + +public class DefaultIssueLocation implements NewIssueLocation, IssueLocation { + + private InputComponent component; + private TextRange textRange; + private String message; + + @Override + public DefaultIssueLocation on(InputComponent component) { + checkArgument(component != null, "Component can't be null"); + checkState(this.component == null, "on() already called"); + this.component = component; + return this; + } + + @Override + public DefaultIssueLocation at(TextRange location) { + checkState(this.component != null, "at() should be called after on()"); + checkState(this.component.isFile(), "at() should be called only for an InputFile."); + DefaultInputFile file = (DefaultInputFile) this.component; + file.validate(location); + this.textRange = location; + return this; + } + + @Override + public DefaultIssueLocation message(String message) { + requireNonNull(message, "Message can't be null"); + if (message.contains("\u0000")) { + throw new IllegalArgumentException(unsupportedCharacterError(message, component)); + } + this.message = abbreviate(trim(message), MESSAGE_MAX_SIZE); + return this; + } + + private static String unsupportedCharacterError(String message, @Nullable InputComponent component) { + String error = "Character \\u0000 is not supported in issue message '" + message + "'"; + if (component != null) { + error += ", on component: " + component.toString(); + } + return error; + } + + @Override + public InputComponent inputComponent() { + return this.component; + } + + @Override + public TextRange textRange() { + return textRange; + } + + @Override + public String message() { + return this.message; + } + +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultMeasure.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultMeasure.java new file mode 100644 index 00000000000..87d1aa18c1d --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultMeasure.java @@ -0,0 +1,140 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.scanner.sensor; + +import java.io.Serializable; +import javax.annotation.Nullable; +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; +import org.sonar.api.batch.fs.InputComponent; +import org.sonar.api.batch.measure.Metric; +import org.sonar.api.batch.sensor.internal.DefaultStorable; +import org.sonar.api.batch.sensor.internal.SensorStorage; +import org.sonar.api.batch.sensor.measure.Measure; +import org.sonar.api.batch.sensor.measure.NewMeasure; + +import static java.util.Objects.requireNonNull; +import static org.sonar.api.utils.Preconditions.checkArgument; +import static org.sonar.api.utils.Preconditions.checkState; + +public class DefaultMeasure<G extends Serializable> extends DefaultStorable implements Measure<G>, NewMeasure<G> { + + private InputComponent component; + private Metric<G> metric; + private G value; + private boolean fromCore = false; + + public DefaultMeasure() { + super(); + } + + public DefaultMeasure(@Nullable SensorStorage storage) { + super(storage); + } + + @Override + public DefaultMeasure<G> on(InputComponent component) { + checkArgument(component != null, "Component can't be null"); + checkState(this.component == null, "on() already called"); + this.component = component; + return this; + } + + @Override + public DefaultMeasure<G> forMetric(Metric<G> metric) { + checkState(this.metric == null, "Metric already defined"); + requireNonNull(metric, "metric should be non null"); + this.metric = metric; + return this; + } + + @Override + public DefaultMeasure<G> withValue(G value) { + checkState(this.value == null, "Measure value already defined"); + requireNonNull(value, "Measure value can't be null"); + this.value = value; + return this; + } + + /** + * For internal use. + */ + public boolean isFromCore() { + return fromCore; + } + + /** + * For internal use. Used by core components to bypass check that prevent a plugin to store core measures. + */ + public DefaultMeasure<G> setFromCore() { + this.fromCore = true; + return this; + } + + @Override + public void doSave() { + requireNonNull(this.value, "Measure value can't be null"); + requireNonNull(this.metric, "Measure metric can't be null"); + checkState(this.metric.valueType().equals(this.value.getClass()), "Measure value should be of type %s", this.metric.valueType()); + storage.store(this); + } + + @Override + public Metric<G> metric() { + return metric; + } + + @Override + public InputComponent inputComponent() { + return component; + } + + @Override + public G value() { + return value; + } + + // For testing purpose + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj == this) { + return true; + } + if (obj.getClass() != getClass()) { + return false; + } + DefaultMeasure<?> rhs = (DefaultMeasure<?>) obj; + return new EqualsBuilder() + .append(component, rhs.component) + .append(metric, rhs.metric) + .append(value, rhs.value) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(27, 45).append(component).append(metric).append(value).toHashCode(); + } + +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorDescriptor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorDescriptor.java new file mode 100644 index 00000000000..1bb74666aaf --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorDescriptor.java @@ -0,0 +1,123 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.scanner.sensor; + +import java.util.Arrays; +import java.util.Collection; +import java.util.function.Predicate; +import javax.annotation.Nullable; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.sensor.SensorDescriptor; +import org.sonar.api.config.Configuration; + +import static java.util.Arrays.asList; + +public class DefaultSensorDescriptor implements SensorDescriptor { + + private String name; + private String[] languages = new String[0]; + private InputFile.Type type = null; + private String[] ruleRepositories = new String[0]; + private boolean global = false; + private Predicate<Configuration> configurationPredicate; + + public String name() { + return name; + } + + public Collection<String> languages() { + return Arrays.asList(languages); + } + + @Nullable + public InputFile.Type type() { + return type; + } + + public Collection<String> ruleRepositories() { + return Arrays.asList(ruleRepositories); + } + + public Predicate<Configuration> configurationPredicate() { + return configurationPredicate; + } + + public boolean isGlobal() { + return global; + } + + @Override + public DefaultSensorDescriptor name(String name) { + this.name = name; + return this; + } + + @Override + public DefaultSensorDescriptor onlyOnLanguage(String languageKey) { + return onlyOnLanguages(languageKey); + } + + @Override + public DefaultSensorDescriptor onlyOnLanguages(String... languageKeys) { + this.languages = languageKeys; + return this; + } + + @Override + public DefaultSensorDescriptor onlyOnFileType(InputFile.Type type) { + this.type = type; + return this; + } + + @Override + public DefaultSensorDescriptor createIssuesForRuleRepository(String... repositoryKey) { + return createIssuesForRuleRepositories(repositoryKey); + } + + @Override + public DefaultSensorDescriptor createIssuesForRuleRepositories(String... repositoryKeys) { + this.ruleRepositories = repositoryKeys; + return this; + } + + @Override + public DefaultSensorDescriptor requireProperty(String... propertyKey) { + return requireProperties(propertyKey); + } + + @Override + public DefaultSensorDescriptor requireProperties(String... propertyKeys) { + this.configurationPredicate = config -> asList(propertyKeys).stream().allMatch(config::hasKey); + return this; + } + + @Override + public SensorDescriptor global() { + this.global = true; + return this; + } + + @Override + public SensorDescriptor onlyWhenConfiguration(Predicate<Configuration> configurationPredicate) { + this.configurationPredicate = configurationPredicate; + return this; + } + +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java index 75a7806beab..415a884380b 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java @@ -43,11 +43,10 @@ import org.sonar.api.batch.sensor.cpd.internal.DefaultCpdTokens; import org.sonar.api.batch.sensor.error.AnalysisError; import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting; import org.sonar.api.batch.sensor.internal.SensorStorage; +import org.sonar.api.batch.sensor.issue.ExternalIssue; import org.sonar.api.batch.sensor.issue.Issue; -import org.sonar.api.batch.sensor.issue.internal.DefaultExternalIssue; import org.sonar.api.batch.sensor.measure.Measure; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; -import org.sonar.api.batch.sensor.rule.internal.DefaultAdHocRule; +import org.sonar.api.batch.sensor.rule.AdHocRule; import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable; import org.sonar.api.config.Configuration; import org.sonar.api.measures.CoreMetrics; @@ -231,7 +230,7 @@ public class DefaultSensorStorage implements SensorStorage { * Thread safe assuming that each issues for each file are only written once. */ @Override - public void store(DefaultExternalIssue externalIssue) { + public void store(ExternalIssue externalIssue) { if (externalIssue.primaryLocation().inputComponent() instanceof DefaultInputFile) { DefaultInputFile defaultInputFile = (DefaultInputFile) externalIssue.primaryLocation().inputComponent(); defaultInputFile.setPublished(true); @@ -240,7 +239,7 @@ public class DefaultSensorStorage implements SensorStorage { } @Override - public void store(DefaultAdHocRule adHocRule) { + public void store(AdHocRule adHocRule) { ScannerReportWriter writer = reportPublisher.getWriter(); final ScannerReport.AdHocRule.Builder builder = ScannerReport.AdHocRule.newBuilder(); builder.setEngineId(adHocRule.engineId()); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/InMemorySensorStorage.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/InMemorySensorStorage.java index c0ec11759ed..887f1d02c66 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/InMemorySensorStorage.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/InMemorySensorStorage.java @@ -33,10 +33,8 @@ import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting; import org.sonar.api.batch.sensor.internal.SensorStorage; import org.sonar.api.batch.sensor.issue.ExternalIssue; import org.sonar.api.batch.sensor.issue.Issue; -import org.sonar.api.batch.sensor.issue.internal.DefaultExternalIssue; import org.sonar.api.batch.sensor.measure.Measure; import org.sonar.api.batch.sensor.rule.AdHocRule; -import org.sonar.api.batch.sensor.rule.internal.DefaultAdHocRule; import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable; import static org.sonar.api.utils.Preconditions.checkArgument; @@ -74,7 +72,7 @@ class InMemorySensorStorage implements SensorStorage { } @Override - public void store(DefaultAdHocRule adHocRule) { + public void store(AdHocRule adHocRule) { allAdHocRules.add(adHocRule); } @@ -127,7 +125,7 @@ class InMemorySensorStorage implements SensorStorage { } @Override - public void store(DefaultExternalIssue issue) { + public void store(ExternalIssue issue) { allExternalIssues.add(issue); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorContext.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorContext.java index 0fe743dfbe2..21e6d2b8f70 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorContext.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorContext.java @@ -41,12 +41,8 @@ import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting; import org.sonar.api.batch.sensor.internal.SensorStorage; import org.sonar.api.batch.sensor.issue.NewExternalIssue; import org.sonar.api.batch.sensor.issue.NewIssue; -import org.sonar.api.batch.sensor.issue.internal.DefaultExternalIssue; -import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; import org.sonar.api.batch.sensor.measure.NewMeasure; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; import org.sonar.api.batch.sensor.rule.NewAdHocRule; -import org.sonar.api.batch.sensor.rule.internal.DefaultAdHocRule; import org.sonar.api.batch.sensor.symbol.NewSymbolTable; import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable; import org.sonar.api.config.Configuration; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/SensorContextTester.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/SensorContextTester.java index 21e5a8271ca..26777fc0a99 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/SensorContextTester.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/SensorContextTester.java @@ -65,14 +65,10 @@ import org.sonar.api.batch.sensor.issue.ExternalIssue; import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.batch.sensor.issue.NewExternalIssue; import org.sonar.api.batch.sensor.issue.NewIssue; -import org.sonar.api.batch.sensor.issue.internal.DefaultExternalIssue; -import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; import org.sonar.api.batch.sensor.measure.Measure; import org.sonar.api.batch.sensor.measure.NewMeasure; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; import org.sonar.api.batch.sensor.rule.AdHocRule; import org.sonar.api.batch.sensor.rule.NewAdHocRule; -import org.sonar.api.batch.sensor.rule.internal.DefaultAdHocRule; import org.sonar.api.batch.sensor.symbol.NewSymbolTable; import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable; import org.sonar.api.config.Configuration; diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/DefaultFileLinesContextTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/DefaultFileLinesContextTest.java index 6bd3a77f43c..19ce32d686c 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/DefaultFileLinesContextTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/DefaultFileLinesContextTest.java @@ -29,7 +29,7 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.TestInputFileBuilder; import org.sonar.api.batch.measure.MetricFinder; import org.sonar.api.batch.sensor.internal.SensorStorage; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; +import org.sonar.scanner.sensor.DefaultMeasure; import org.sonar.api.measures.CoreMetrics; import static org.assertj.core.api.Assertions.assertThat; diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java index 9a89d6ad18b..50ea80aceb7 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/IssuePublisherTest.java @@ -38,9 +38,9 @@ import org.sonar.api.batch.fs.internal.TestInputFileBuilder; import org.sonar.scanner.rule.ActiveRulesBuilder; import org.sonar.scanner.rule.NewActiveRule; import org.sonar.scanner.rule.RulesBuilder; -import org.sonar.api.batch.sensor.issue.internal.DefaultExternalIssue; -import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; -import org.sonar.api.batch.sensor.issue.internal.DefaultIssueLocation; +import org.sonar.scanner.sensor.DefaultExternalIssue; +import org.sonar.scanner.sensor.DefaultIssue; +import org.sonar.scanner.sensor.DefaultIssueLocation; import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.Severity; import org.sonar.api.rules.RuleType; diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorStorageTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorStorageTest.java index 264e666429f..bdefb6f3436 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorStorageTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorStorageTest.java @@ -40,10 +40,6 @@ import org.sonar.api.batch.sensor.highlighting.TypeOfText; import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting; import org.sonar.api.batch.sensor.issue.ExternalIssue; import org.sonar.api.batch.sensor.issue.Issue; -import org.sonar.api.batch.sensor.issue.internal.DefaultExternalIssue; -import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; -import org.sonar.api.batch.sensor.issue.internal.DefaultIssueLocation; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable; import org.sonar.api.config.internal.MapSettings; import org.sonar.api.measures.CoreMetrics; |