* @throws IllegalStateException if baseProjectSnapshot has not been set
*/
boolean isFirstAnalysis();
-
+
/**
* Whether this is an incremental analysis or a full analysis.
*/
Map<String, QualityProfile> getQProfilesByLanguage();
+ /**
+ * Plugins used during the analysis on scanner side
+ */
+ Map<String, ScannerPlugin> getScannerPluginsByKey();
+
}
private final InitializedProperty<String> branch = new InitializedProperty<>();
private final InitializedProperty<Integer> rootComponentRef = new InitializedProperty<>();
private final InitializedProperty<Map<String, QualityProfile>> qProfilesPerLanguage = new InitializedProperty<>();
+ private final InitializedProperty<Map<String, ScannerPlugin>> pluginsByKey = new InitializedProperty<>();
@Override
public MutableAnalysisMetadataHolder setOrganization(Organization organization) {
return qProfilesPerLanguage.getProperty();
}
+ @Override
+ public MutableAnalysisMetadataHolder setScannerPluginsByKey(Map<String, ScannerPlugin> pluginsByKey) {
+ checkState(!this.pluginsByKey.isInitialized(), "Plugins by key has already been set");
+ this.pluginsByKey.setProperty(ImmutableMap.copyOf(pluginsByKey));
+ return this;
+ }
+
+ @Override
+ public Map<String, ScannerPlugin> getScannerPluginsByKey() {
+ checkState(pluginsByKey.isInitialized(), "Plugins by key has not been set");
+ return pluginsByKey.getProperty();
+ }
+
}
* @throws IllegalStateException if it has already been set
*/
MutableAnalysisMetadataHolder setIncrementalAnalysis(boolean isIncrementalAnalysis);
-
+
/**
* @throws IllegalStateException if baseAnalysis has already been set
*/
*/
MutableAnalysisMetadataHolder setQProfilesByLanguage(Map<String, QualityProfile> qprofilesByLanguage);
+ /**
+ * @throws IllegalStateException if Plugins by key has already been set
+ */
+ MutableAnalysisMetadataHolder setScannerPluginsByKey(Map<String, ScannerPlugin> pluginsByKey);
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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.server.computation.task.projectanalysis.analysis;
+
+import javax.annotation.concurrent.Immutable;
+
+import static java.util.Objects.requireNonNull;
+
+@Immutable
+public class ScannerPlugin {
+ private final String key;
+ private final long updatedAt;
+
+ public ScannerPlugin(String key, long updatedAt) {
+ this.key = requireNonNull(key, "key can't be null");
+ this.updatedAt = updatedAt;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public long getUpdatedAt() {
+ return updatedAt;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ScannerPlugin that = (ScannerPlugin) o;
+ return key.equals(that.key);
+ }
+
+ @Override
+ public int hashCode() {
+ return key.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "ScannerPlugin{" +
+ "key='" + key + '\'' +
+ ", updatedAt='" + updatedAt + '\'' +
+ '}';
+ }
+
+}
import org.sonar.server.computation.task.projectanalysis.analysis.Analysis;
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.server.computation.task.projectanalysis.component.Component;
+import org.sonar.server.computation.task.projectanalysis.qualityprofile.ActiveRule;
import org.sonar.server.computation.task.projectanalysis.qualityprofile.ActiveRulesHolder;
import org.sonar.server.computation.task.projectanalysis.scm.Changeset;
import org.sonar.server.computation.task.projectanalysis.scm.ScmInfo;
@Override
public void onIssue(Component component, DefaultIssue issue) {
- if (issue.isNew() && ruleIsNew(issue)) {
+ if (!issue.isNew()) {
+ return;
+ }
+ Optional<Long> lastAnalysisOptional = lastAnalysis();
+ boolean firstAnalysis = !lastAnalysisOptional.isPresent();
+ ActiveRule activeRule = toJavaUtilOptional(activeRulesHolder.get(issue.getRuleKey()))
+ .orElseThrow(illegalStateException("The rule %s raised an issue, but is not one of the active rules.", issue.getRuleKey()));
+ if (firstAnalysis
+ || ruleIsNew(activeRule, lastAnalysisOptional.get())
+ || pluginIsNew(activeRule, lastAnalysisOptional.get())) {
getScmChangeDate(component, issue)
.ifPresent(changeDate -> updateDate(issue, changeDate));
}
}
+ private boolean pluginIsNew(ActiveRule activeRule, Long lastAnalysisDate) {
+ String pluginKey = activeRule.getPluginKey();
+ long pluginUpdateDate = Optional.ofNullable(analysisMetadataHolder.getScannerPluginsByKey().get(pluginKey))
+ .orElseThrow(illegalStateException("The rule %s is declared to come from plugin %s, but this plugin was not used by scanner.", activeRule.getRuleKey(), pluginKey))
+ .getUpdatedAt();
+ return lastAnalysisDate < pluginUpdateDate;
+ }
+
+ private static boolean ruleIsNew(ActiveRule activeRule, Long lastAnalysisDate) {
+ long ruleCreationDate = activeRule.getCreatedAt();
+ return lastAnalysisDate < ruleCreationDate;
+ }
+
private Optional<Date> getScmChangeDate(Component component, DefaultIssue issue) {
return getScmInfo(component)
.flatMap(scmInfo -> getChangeset(scmInfo, issue))
.map(IssueCreationDateCalculator::getChangeDate);
}
- private boolean ruleIsNew(DefaultIssue issue) {
- long ruleCreation = ruleCreation(issue);
- Optional<Long> lastAnalysisOptional = lastAnalysis();
-
- if (lastAnalysisOptional.isPresent()) {
- return lastAnalysisOptional.get() < ruleCreation;
- }
-
- // special case: this is the first analysis of the project: use scm dates for all issues
- return true;
- }
-
private Optional<Long> lastAnalysis() {
return Optional.ofNullable(analysisMetadataHolder.getBaseAnalysis()).map(Analysis::getCreatedAt);
}
- private long ruleCreation(DefaultIssue issue) {
- return toJavaUtilOptional(activeRulesHolder.get(issue.getRuleKey()))
- .orElseThrow(illegalStateException("The rule %s raised an issue, but is not one of the active rules.", issue.getRuleKey().rule()))
- .getCreatedAt();
- }
-
private Optional<ScmInfo> getScmInfo(Component component) {
return toJavaUtilOptional(scmInfoRepository.getScmInfo(component));
}
@CheckForNull
DebtRemediationFunction getRemediationFunction();
+
+ String getPluginKey();
}
private final Set<String> tags;
private final DebtRemediationFunction remediationFunction;
private final RuleType type;
+ private final String pluginKey;
public RuleImpl(RuleDto dto) {
this.id = dto.getId();
this.tags = union(dto.getSystemTags(), dto.getTags());
this.remediationFunction = effectiveRemediationFunction(dto);
this.type = RuleType.valueOf(dto.getType());
+ this.pluginKey = dto.getPluginKey();
}
@Override
return type;
}
+ @Override
+ public String getPluginKey() {
+ return pluginKey;
+ }
+
@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
.add("name", name)
.add("status", status)
.add("tags", tags)
+ .add("pluginKey", pluginKey)
.toString();
}
private final String severity;
private final Map<String, String> params;
private final long createdAt;
+ private final String pluginKey;
- public ActiveRule(RuleKey ruleKey, String severity, Map<String, String> params, long createdAt) {
+ public ActiveRule(RuleKey ruleKey, String severity, Map<String, String> params, long createdAt, String pluginKey) {
this.ruleKey = ruleKey;
this.severity = severity;
+ this.pluginKey = pluginKey;
this.params = ImmutableMap.copyOf(params);
this.createdAt = createdAt;
}
public long getCreatedAt() {
return createdAt;
}
+
+ public String getPluginKey() {
+ return pluginKey;
+ }
}
package org.sonar.server.computation.task.projectanalysis.step;
import com.google.common.base.Optional;
-import com.google.common.base.Predicate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import javax.annotation.Nonnull;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.core.util.CloseableIterator;
import org.sonar.server.computation.task.projectanalysis.qualityprofile.ActiveRulesHolderImpl;
import org.sonar.server.computation.task.step.ComputationStep;
-import static com.google.common.collect.FluentIterable.from;
-
public class LoadQualityProfilesStep implements ComputationStep {
private final BatchReportReader batchReportReader;
List<ActiveRule> activeRules = new ArrayList<>();
try (CloseableIterator<ScannerReport.ActiveRule> batchActiveRules = batchReportReader.readActiveRules()) {
while (batchActiveRules.hasNext()) {
- ScannerReport.ActiveRule batchActiveRule = batchActiveRules.next();
- activeRules.add(convert(batchActiveRule));
+ ScannerReport.ActiveRule scannerReportActiveRule = batchActiveRules.next();
+ Optional<Rule> rule = ruleRepository.findByKey(RuleKey.of(scannerReportActiveRule.getRuleRepository(), scannerReportActiveRule.getRuleKey()));
+ if (rule.isPresent() && rule.get().getStatus() != RuleStatus.REMOVED) {
+ ActiveRule activeRule = convert(scannerReportActiveRule, rule.get());
+ activeRules.add(activeRule);
+ }
}
}
- List<ActiveRule> validActiveRules = from(activeRules).filter(new IsValid()).toList();
- activeRulesHolder.set(validActiveRules);
- }
-
- private class IsValid implements Predicate<ActiveRule> {
- @Override
- public boolean apply(@Nonnull ActiveRule input) {
- Optional<Rule> rule = ruleRepository.findByKey(input.getRuleKey());
- return rule.isPresent() && rule.get().getStatus() != RuleStatus.REMOVED;
- }
+ activeRulesHolder.set(activeRules);
}
@Override
return "Load quality profiles";
}
- private static ActiveRule convert(ScannerReport.ActiveRule input) {
+ private static ActiveRule convert(ScannerReport.ActiveRule input, Rule rule) {
RuleKey key = RuleKey.of(input.getRuleRepository(), input.getRuleKey());
Map<String, String> params = new HashMap<>(input.getParamsByKey());
- return new ActiveRule(key, input.getSeverity().name(), params, input.getCreatedAt());
+ return new ActiveRule(key, input.getSeverity().name(), params, input.getCreatedAt(), rule.getPluginKey());
}
}
*/
package org.sonar.server.computation.task.projectanalysis.step;
-import com.google.common.base.Function;
import com.google.common.base.Joiner;
import java.util.Date;
import java.util.List;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.scanner.protocol.output.ScannerReport;
+import org.sonar.scanner.protocol.output.ScannerReport.Metadata.Plugin;
import org.sonar.scanner.protocol.output.ScannerReport.Metadata.QProfile;
import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolder;
import org.sonar.server.computation.task.projectanalysis.analysis.Organization;
+import org.sonar.server.computation.task.projectanalysis.analysis.ScannerPlugin;
import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReader;
import org.sonar.server.computation.task.step.ComputationStep;
import org.sonar.server.organization.BillingValidations;
import org.sonar.server.qualityprofile.QualityProfile;
import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.Maps.transformValues;
import static java.lang.String.format;
+import static java.util.stream.Collectors.toMap;
import static org.apache.commons.lang.StringUtils.isNotEmpty;
import static org.sonar.core.util.stream.MoreCollectors.toList;
*/
public class LoadReportAnalysisMetadataHolderStep implements ComputationStep {
- private static final ToComputeQProfile TO_COMPUTE_QPROFILE = new ToComputeQProfile();
-
- private static final class ToComputeQProfile implements Function<QProfile, QualityProfile> {
- @Override
- public QualityProfile apply(QProfile input) {
- return new QualityProfile(input.getKey(), input.getName(), input.getLanguage(), new Date(input.getRulesUpdatedAt()));
- }
- }
-
private final CeTask ceTask;
private final BatchReportReader reportReader;
private final MutableAnalysisMetadataHolder mutableAnalysisMetadataHolder;
mutableAnalysisMetadataHolder.setBranch(isNotEmpty(reportMetadata.getBranch()) ? reportMetadata.getBranch() : null);
mutableAnalysisMetadataHolder.setCrossProjectDuplicationEnabled(reportMetadata.getCrossProjectDuplicationActivated());
mutableAnalysisMetadataHolder.setIncrementalAnalysis(reportMetadata.getIncremental());
- mutableAnalysisMetadataHolder.setQProfilesByLanguage(transformValues(reportMetadata.getQprofilesPerLanguage(), TO_COMPUTE_QPROFILE));
+ mutableAnalysisMetadataHolder.setQProfilesByLanguage(reportMetadata.getQprofilesPerLanguage().values().stream()
+ .collect(toMap(
+ QProfile::getLanguage,
+ qp -> new QualityProfile(qp.getKey(), qp.getName(), qp.getLanguage(), new Date(qp.getRulesUpdatedAt())))));
+ mutableAnalysisMetadataHolder.setScannerPluginsByKey(reportMetadata.getPluginsByKey().values().stream()
+ .collect(toMap(
+ Plugin::getKey,
+ p -> new ScannerPlugin(p.getKey(), p.getUpdatedAt()))));
mutableAnalysisMetadataHolder.setOrganization(organization);
}
private final InitializedProperty<Map<String, QualityProfile>> qProfilesPerLanguage = new InitializedProperty<>();
+ private final InitializedProperty<Map<String, ScannerPlugin>> pluginsByKey = new InitializedProperty<>();
+
@Override
public AnalysisMetadataHolderRule setOrganization(Organization organization) {
requireNonNull(organization, "organization can't be null");
return qProfilesPerLanguage.getProperty();
}
+ @Override
+ public AnalysisMetadataHolderRule setScannerPluginsByKey(Map<String, ScannerPlugin> plugins) {
+ this.pluginsByKey.setProperty(plugins);
+ return this;
+ }
+
+ @Override
+ public Map<String, ScannerPlugin> getScannerPluginsByKey() {
+ checkState(pluginsByKey.isInitialized(), "Plugins per key has not been set");
+ return pluginsByKey.getProperty();
+ }
+
@Override
public boolean isIncrementalAnalysis() {
checkState(incremental.isInitialized(), "Incremental mode flag has not been set");
return delegate.getQProfilesByLanguage();
}
+ @Override
+ public MutableAnalysisMetadataHolder setScannerPluginsByKey(Map<String, ScannerPlugin> plugins) {
+ delegate.setScannerPluginsByKey(plugins);
+ return this;
+ }
+
+ @Override
+ public Map<String, ScannerPlugin> getScannerPluginsByKey() {
+ return delegate.getScannerPluginsByKey();
+ }
+
@Override
public boolean isIncrementalAnalysis() {
return delegate.isIncrementalAnalysis();
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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.server.computation.task.projectanalysis.analysis;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ScannerPluginTest {
+
+ @Test
+ public void verify_getters() {
+ ScannerPlugin plugin = new ScannerPlugin("key", 12345L);
+
+ assertThat(plugin.getKey()).isEqualTo("key");
+ assertThat(plugin.getUpdatedAt()).isEqualTo(12345L);
+ }
+
+ @Test
+ public void verify_toString() {
+ ScannerPlugin plugin = new ScannerPlugin("key", 12345L);
+
+ assertThat(plugin.toString()).isEqualTo("ScannerPlugin{key='key', updatedAt='12345'}");
+ }
+
+ @Test
+ public void equals_is_based_on_key_only() {
+ ScannerPlugin plugin = new ScannerPlugin("key", 12345L);
+
+ assertThat(plugin).isEqualTo(plugin);
+ assertThat(plugin).isEqualTo(new ScannerPlugin("key", 45678L));
+ assertThat(plugin).isNotEqualTo(new ScannerPlugin("key2", 12345L));
+ assertThat(plugin).isNotEqualTo(null);
+ assertThat(plugin).isNotEqualTo("toto");
+ }
+
+ @Test
+ public void hashcode_is_based_on_key_only() {
+ ScannerPlugin plugin = new ScannerPlugin("key", 12345L);
+
+ assertThat(plugin.hashCode()).isEqualTo("key".hashCode());
+ }
+}
private RuleType type = RuleType.CODE_SMELL;
private Set<String> tags = new HashSet<>();
private DebtRemediationFunction function;
+ private String pluginKey;
public DumbRule(RuleKey key) {
this.key = key;
return function;
}
+ @Override
+ public String getPluginKey() {
+ return pluginKey;
+ }
+
public DumbRule setId(Integer id) {
this.id = id;
return this;
return this;
}
- public void setTags(Set<String> tags) {
+ public DumbRule setTags(Set<String> tags) {
this.tags = tags;
+ return this;
}
- public void setType(RuleType type) {
+ public DumbRule setType(RuleType type) {
this.type = type;
+ return this;
}
+
+ public DumbRule setPluginKey(String pluginKey) {
+ this.pluginKey = pluginKey;
+ return this;
+ }
+
}
import com.google.common.base.Optional;
import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.sonar.api.rule.RuleKey;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.server.computation.task.projectanalysis.analysis.Analysis;
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder;
+import org.sonar.server.computation.task.projectanalysis.analysis.ScannerPlugin;
import org.sonar.server.computation.task.projectanalysis.component.Component;
import org.sonar.server.computation.task.projectanalysis.qualityprofile.ActiveRule;
import org.sonar.server.computation.task.projectanalysis.qualityprofile.ActiveRulesHolder;
private ActiveRule activeRule;
private IssueCreationDateCalculator calculator;
private Analysis baseAnalysis;
+ private Map<String, ScannerPlugin> scannerPlugins;
@Before
public void before() {
analysisMetadataHolder = mock(AnalysisMetadataHolder.class);
+ scannerPlugins = new HashMap<>();
+ when(analysisMetadataHolder.getScannerPluginsByKey()).thenReturn(scannerPlugins);
scmInfoRepository = mock(ScmInfoRepository.class);
issueUpdater = mock(IssueFieldsSetter.class);
activeRulesHolder = mock(ActiveRulesHolder.class);
baseAnalysis = mock(Analysis.class);
calculator = new IssueCreationDateCalculator(analysisMetadataHolder, scmInfoRepository, issueUpdater, activeRulesHolder);
+ when(activeRulesHolder.get(any(RuleKey.class)))
+ .thenReturn(Optional.absent());
when(activeRulesHolder.get(ruleKey))
.thenReturn(Optional.of(activeRule));
when(issue.getRuleKey())
newIssue();
noScm();
- rule(2800L);
+ ruleCreatedAt(2800L);
run();
newIssue();
withScm(1200L);
- rule(1500L);
+ ruleCreatedAt(1500L);
+ rulePlugin("java");
+ pluginUpdatedAt("java", 1700L);
run();
existingIssue();
withScm(1200L);
- rule(2800L);
+ ruleCreatedAt(2800L);
+
+ run();
+
+ assertNoChangeOfCreationDate();
+ }
+
+ @Test
+ public void should_not_fail_for_issue_about_to_be_closed() {
+ previousAnalysisWas(2000L);
+ currentAnalysisIs(3000L);
+
+ existingIssue();
+ when(issue.getRuleKey())
+ .thenReturn(RuleKey.of("repo", "disabled"));
run();
newIssue();
withScm(1200L);
- rule(2800L);
+ ruleCreatedAt(2800L);
+
+ run();
+
+ assertChangeOfCreationDateTo(1200L);
+ }
+
+ @Test
+ public void should_change_date_if_scm_is_available_and_first_analysis() {
+ currentAnalysisIs(3000L);
+
+ newIssue();
+ withScm(1200L);
+
+ run();
+
+ assertChangeOfCreationDateTo(1200L);
+ }
+
+ @Test
+ public void should_change_date_if_scm_is_available_and_plugin_is_new() {
+ previousAnalysisWas(2000L);
+ currentAnalysisIs(3000L);
+
+ newIssue();
+ withScm(1200L);
+ ruleCreatedAt(1500L);
+ rulePlugin("java");
+ pluginUpdatedAt("java", 2500L);
run();
.thenReturn(analysisDate);
}
+ private void pluginUpdatedAt(String pluginKey, long updatedAt) {
+ scannerPlugins.put(pluginKey, new ScannerPlugin(pluginKey, updatedAt));
+ }
+
private void currentAnalysisIs(long analysisDate) {
when(analysisMetadataHolder.getAnalysisDate()).thenReturn(analysisDate);
}
when(scmInfo.getLatestChangeset()).thenReturn(changeset);
}
- private void rule(long createdAt) {
+ private void ruleCreatedAt(long createdAt) {
when(activeRule.getCreatedAt()).thenReturn(createdAt);
}
+ private void rulePlugin(String pluginKey) {
+ when(activeRule.getPluginKey()).thenReturn(pluginKey);
+ }
+
private void run() {
calculator.beforeComponent(component);
calculator.onIssue(component, issue);
public class CommentDensityRuleTest {
- static RuleKey RULE_KEY = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY);
+ private static final String PLUGIN_KEY = "java";
+
+ static RuleKey RULE_KEY = RuleKey.of(CommonRuleKeys.commonRepositoryForLang(PLUGIN_KEY), CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY);
static ReportComponent FILE = ReportComponent.builder(Component.Type.FILE, 1)
- .setFileAttributes(new FileAttributes(false, "java", 1))
+ .setFileAttributes(new FileAttributes(false, PLUGIN_KEY, 1))
.build();
@Rule
@Test
public void no_issues_if_enough_comments() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "25"), 1_000L));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "25"), 1_000L, PLUGIN_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(90.0, 1));
- DefaultIssue issue = underTest.processFile(FILE, "java");
+ DefaultIssue issue = underTest.processFile(FILE, PLUGIN_KEY);
assertThat(issue).isNull();
}
@Test
public void issue_if_not_enough_comments() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "25"), 1_000L));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "25"), 1_000L, PLUGIN_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(10.0, 1));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_KEY, Measure.newMeasureBuilder().create(40));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.NCLOC_KEY, Measure.newMeasureBuilder().create(360));
- DefaultIssue issue = underTest.processFile(FILE, "java");
+ DefaultIssue issue = underTest.processFile(FILE, PLUGIN_KEY);
assertThat(issue.ruleKey()).isEqualTo(RULE_KEY);
assertThat(issue.severity()).isEqualTo(Severity.CRITICAL);
@Test
public void issue_if_not_enough_comments__test_ceil() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "25"), 1_000L));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "25"), 1_000L, PLUGIN_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(0.0, 1));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_KEY, Measure.newMeasureBuilder().create(0));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.NCLOC_KEY, Measure.newMeasureBuilder().create(1));
- DefaultIssue issue = underTest.processFile(FILE, "java");
+ DefaultIssue issue = underTest.processFile(FILE, PLUGIN_KEY);
assertThat(issue.ruleKey()).isEqualTo(RULE_KEY);
assertThat(issue.severity()).isEqualTo(Severity.CRITICAL);
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Minimum density of rule [common-java:InsufficientCommentDensity] is incorrect. Got [100] but must be strictly less than 100.");
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "100"), 1_000L));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "100"), 1_000L, PLUGIN_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(0.0, 1));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_KEY, Measure.newMeasureBuilder().create(0));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.NCLOC_KEY, Measure.newMeasureBuilder().create(1));
- underTest.processFile(FILE, "java");
+ underTest.processFile(FILE, PLUGIN_KEY);
}
}
public class CommonRuleTest {
+ private static final String PLUGIN_KEY = "java";
+
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void test_getMinDensityParam() throws Exception {
- ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "30.5"), 1_000L);
+ ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "30.5"), 1_000L, PLUGIN_KEY);
double minDensity = CommonRule.getMinDensityParam(activeRule, "minDensity");
assertThat(minDensity).isEqualTo(30.5);
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Required parameter [minDensity] is missing on rule [xoo:x1]");
- ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.<String, String>of(), 1_000L);
+ ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.<String, String>of(), 1_000L, PLUGIN_KEY);
CommonRule.getMinDensityParam(activeRule, "minDensity");
}
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Minimum density of rule [xoo:x1] is incorrect. Got [-30.5] but must be between 0 and 100.");
- ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "-30.5"), 1_000L);
+ ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "-30.5"), 1_000L, PLUGIN_KEY);
CommonRule.getMinDensityParam(activeRule, "minDensity");
}
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Minimum density of rule [xoo:x1] is incorrect. Got [305] but must be between 0 and 100.");
- ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "305"), 1_000L);
+ ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "305"), 1_000L, PLUGIN_KEY);
CommonRule.getMinDensityParam(activeRule, "minDensity");
}
}
public abstract class CoverageRuleTest {
+ private static final String PLUGIN_KEY = "java";
+
static ReportComponent FILE = ReportComponent.builder(Component.Type.FILE, 1)
.setFileAttributes(new FileAttributes(false, "java", 1))
.build();
@Test
public void no_issue_if_enough_coverage() {
- activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"), 1_000L));
+ activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"), 1_000L, PLUGIN_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getCoverageMetricKey(), Measure.newMeasureBuilder().create(90.0, 1));
DefaultIssue issue = underTest.processFile(FILE, "java");
@Test
public void issue_if_coverage_is_too_low() {
- activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"), 1_000L));
+ activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"), 1_000L, PLUGIN_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getCoverageMetricKey(), Measure.newMeasureBuilder().create(20.0, 1));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getUncoveredMetricKey(), Measure.newMeasureBuilder().create(40));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getToCoverMetricKey(), Measure.newMeasureBuilder().create(50));
@Test
public void no_issue_if_coverage_is_not_set() {
- activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"), 1_000L));
+ activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"), 1_000L, PLUGIN_KEY));
DefaultIssue issue = underTest.processFile(FILE, "java");
public class DuplicatedBlockRuleTest {
+ private static final String PLUGIN_KEY = "java";
+
static RuleKey RULE_KEY = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), CommonRuleKeys.DUPLICATED_BLOCKS);
static ReportComponent FILE = ReportComponent.builder(Component.Type.FILE, 1)
@Test
public void no_issue_if_no_duplicated_blocks() throws Exception {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap(), 1_000L));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap(), 1_000L, PLUGIN_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.DUPLICATED_BLOCKS_KEY, Measure.newMeasureBuilder().create(0));
DefaultIssue issue = underTest.processFile(FILE, "java");
@Test
public void issue_if_duplicated_blocks() throws Exception {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap(), 1_000L));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap(), 1_000L, PLUGIN_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.DUPLICATED_BLOCKS_KEY, Measure.newMeasureBuilder().create(3));
DefaultIssue issue = underTest.processFile(FILE, "java");
public class SkippedTestRuleTest {
+ private static final String PLUGIN_KEY = "java";
+
static RuleKey RULE_KEY = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), CommonRuleKeys.SKIPPED_UNIT_TESTS);
static ReportComponent FILE = ReportComponent.builder(Component.Type.FILE, 1)
@Test
public void issue_if_skipped_tests() throws Exception {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap(), 1_000L));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap(), 1_000L, PLUGIN_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.SKIPPED_TESTS_KEY, Measure.newMeasureBuilder().create(2));
DefaultIssue issue = underTest.processFile(FILE, "java");
@Test
public void no_issues_if_zero_skipped_tests() throws Exception {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap(), 1_000L));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap(), 1_000L, PLUGIN_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.SKIPPED_TESTS_KEY, Measure.newMeasureBuilder().create(0));
DefaultIssue issue = underTest.processFile(FILE, "java");
@Test
public void no_issues_if_measure_is_absent() throws Exception {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap(), 1_000L));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap(), 1_000L, PLUGIN_KEY));
DefaultIssue issue = underTest.processFile(FILE, "java");
public class TestErrorRuleTest {
+ private static final String PLUGIN_KEY = "java";
+
static RuleKey RULE_KEY = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), CommonRuleKeys.FAILED_UNIT_TESTS);
static ReportComponent FILE = ReportComponent.builder(Component.Type.FILE, 1)
@Test
public void issue_if_errors_or_failures() throws Exception {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap(), 1_000L));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap(), 1_000L, PLUGIN_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.TEST_ERRORS_KEY, Measure.newMeasureBuilder().create(2));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.TEST_FAILURES_KEY, Measure.newMeasureBuilder().create(1));
@Test
public void no_issues_if_zero_errors_and_failures() throws Exception {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap(), 1_000L));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap(), 1_000L, PLUGIN_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.TEST_ERRORS_KEY, Measure.newMeasureBuilder().create(0));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.TEST_FAILURES_KEY, Measure.newMeasureBuilder().create(0));
@Test
public void no_issues_if_test_measures_are_absent() throws Exception {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap(), 1_000L));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap(), 1_000L, PLUGIN_KEY));
DefaultIssue issue = underTest.processFile(FILE, "java");
public class ActiveRulesHolderImplTest {
+ private static final String PLUGIN_KEY = "java";
+
private static final long SOME_DATE = 1_000L;
- static final RuleKey RULE_KEY = RuleKey.of("java", "S001");
+ static final RuleKey RULE_KEY = RuleKey.of("squid", "S001");
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void get_active_rule() throws Exception {
- underTest.set(asList(new ActiveRule(RULE_KEY, Severity.BLOCKER, Collections.<String, String>emptyMap(), SOME_DATE)));
+ underTest.set(asList(new ActiveRule(RULE_KEY, Severity.BLOCKER, Collections.<String, String>emptyMap(), SOME_DATE, PLUGIN_KEY)));
Optional<ActiveRule> activeRule = underTest.get(RULE_KEY);
assertThat(activeRule.isPresent()).isTrue();
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Active rules have already been initialized");
- underTest.set(asList(new ActiveRule(RULE_KEY, Severity.BLOCKER, Collections.<String, String>emptyMap(), 1_000L)));
+ underTest.set(asList(new ActiveRule(RULE_KEY, Severity.BLOCKER, Collections.<String, String>emptyMap(), 1_000L, PLUGIN_KEY)));
underTest.set(Collections.<ActiveRule>emptyList());
}
@Test
public void can_not_set_duplicated_rules() throws Exception {
thrown.expect(IllegalArgumentException.class);
- thrown.expectMessage("Active rule must not be declared multiple times: java:S001");
+ thrown.expectMessage("Active rule must not be declared multiple times: squid:S001");
underTest.set(asList(
- new ActiveRule(RULE_KEY, Severity.BLOCKER, Collections.<String, String>emptyMap(), 1_000L),
- new ActiveRule(RULE_KEY, Severity.MAJOR, Collections.<String, String>emptyMap(), 1_000L)));
+ new ActiveRule(RULE_KEY, Severity.BLOCKER, Collections.<String, String>emptyMap(), 1_000L, PLUGIN_KEY),
+ new ActiveRule(RULE_KEY, Severity.MAJOR, Collections.<String, String>emptyMap(), 1_000L, PLUGIN_KEY)));
}
}
@Test
public void feed_active_rules() throws Exception {
- ruleRepository.add(XOO_X1);
- ruleRepository.add(XOO_X2);
+ ruleRepository.add(XOO_X1)
+ .setPluginKey("xoo");
+ ruleRepository.add(XOO_X2)
+ .setPluginKey("xoo");
ScannerReport.ActiveRule.Builder batch1 = ScannerReport.ActiveRule.newBuilder()
.setRuleRepository(XOO_X1.repository()).setRuleKey(XOO_X1.rule())
Optional<ActiveRule> ar1 = activeRulesHolder.get(XOO_X1);
assertThat(ar1.get().getSeverity()).isEqualTo(Severity.BLOCKER);
assertThat(ar1.get().getParams()).containsExactly(MapEntry.entry("p1", "v1"));
+ assertThat(ar1.get().getPluginKey()).isEqualTo("xoo");
Optional<ActiveRule> ar2 = activeRulesHolder.get(XOO_X2);
assertThat(ar2.get().getSeverity()).isEqualTo(Severity.MAJOR);
assertThat(ar2.get().getParams()).isEmpty();
+ assertThat(ar2.get().getPluginKey()).isEqualTo("xoo");
}
@Test
import org.sonar.server.organization.TestDefaultOrganizationProvider;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
assertThat(analysisMetadataHolder.isCrossProjectDuplicationEnabled()).isEqualTo(false);
}
-
+
@Test
public void set_incremental_analysis_to_true() {
reportReader.setMetadata(
assertThat(analysisMetadataHolder.isIncrementalAnalysis()).isTrue();
}
-
+
@Test
public void set_incremental_analysis_to_false() {
reportReader.setMetadata(
newBatchReportBuilder()
- .setIncremental(false)
+ .setIncremental(false)
.build());
underTest.execute();
assertThat(analysisMetadataHolder.isIncrementalAnalysis()).isFalse();
}
-
@Test
public void set_cross_project_duplication_to_false_when_nothing_in_the_report() {
reportReader.setMetadata(
assertThat(argumentCaptor.getValue().getUuid()).isEqualTo(organization.getUuid());
}
+ @Test
+ public void execute_read_plugins_from_report() {
+ ScannerReport.Metadata.Builder metadataBuilder = newBatchReportBuilder();
+ metadataBuilder.getMutablePluginsByKey().put("java", ScannerReport.Metadata.Plugin.newBuilder().setKey("java").setUpdatedAt(12345L).build());
+ metadataBuilder.getMutablePluginsByKey().put("php", ScannerReport.Metadata.Plugin.newBuilder().setKey("php").setUpdatedAt(678910L).build());
+ reportReader.setMetadata(metadataBuilder.build());
+
+ underTest.execute();
+
+ assertThat(analysisMetadataHolder.getScannerPluginsByKey()).containsOnlyKeys("java", "php");
+ assertThat(analysisMetadataHolder.getScannerPluginsByKey().values()).extracting("key", "updatedAt").containsOnly(
+ tuple("java", 12345L),
+ tuple("php", 678910L));
+ }
+
private LoadReportAnalysisMetadataHolderStep createStep(CeTask ceTask) {
return new LoadReportAnalysisMetadataHolderStep(ceTask, reportReader, analysisMetadataHolder, defaultOrganizationProvider, dbClient, billingValidations);
}