*/
package org.sonar.api.notifications;
-import org.sonar.api.batch.ScannerSide;
+import org.sonar.api.scanner.ScannerSide;
/**
* Record user-friendly warnings that will be visible on SonarQube
import org.sonar.api.batch.ScannerSide;
import org.sonarsource.api.sonarlint.SonarLintSide;
+/**
+ * @since 5.3
+ * @deprecated since 7.6
+ */
@ScannerSide
@SonarLintSide
@ExtensionPoint
@FunctionalInterface
@ThreadSafe
-/**
- * @since 5.3
- * @deprecated since 7.6
- */
@Deprecated
public interface IssueFilter {
}
return InstantiationStrategy.PER_PROJECT.equals(strategy);
}
-
+
public static boolean isDeprecatedScannerSide(Object extension) {
return AnnotationUtils.getAnnotation(extension, org.sonar.api.batch.ScannerSide.class) != null;
}
return AnnotationUtils.getAnnotation(extension, ScannerSide.class) != null;
}
- public static boolean isType(Object extension, Class<?> extensionClass) {
- Class clazz = extension instanceof Class ? (Class) extension : extension.getClass();
- return extensionClass.isAssignableFrom(clazz);
- }
}
--- /dev/null
+/*
+ * 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.phases;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.function.Function;
+import javax.annotation.concurrent.Immutable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.config.Configuration;
+import org.sonar.api.utils.WildcardPattern;
+
+@Immutable
+public abstract class AbstractCoverageExclusions {
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractCoverageExclusions.class);
+ private final Function<DefaultInputFile, String> pathExtractor;
+ private final String[] coverageExclusionConfig;
+
+ private Collection<WildcardPattern> exclusionPatterns;
+
+ public AbstractCoverageExclusions(Configuration config, Function<DefaultInputFile, String> pathExtractor) {
+ this.pathExtractor = pathExtractor;
+ Builder<WildcardPattern> builder = ImmutableList.builder();
+ coverageExclusionConfig = config.getStringArray(CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY);
+ for (String pattern : coverageExclusionConfig) {
+ builder.add(WildcardPattern.create(pattern));
+ }
+ exclusionPatterns = builder.build();
+ }
+
+ public String[] getCoverageExclusionConfig() {
+ return coverageExclusionConfig;
+ }
+
+ void log() {
+ if (!exclusionPatterns.isEmpty()) {
+ log("Excluded sources for coverage: ", exclusionPatterns);
+ }
+ }
+
+ boolean isExcluded(DefaultInputFile file) {
+ boolean found = false;
+ Iterator<WildcardPattern> iterator = exclusionPatterns.iterator();
+ while (!found && iterator.hasNext()) {
+ found = iterator.next().match(pathExtractor.apply(file));
+ }
+ return found;
+ }
+
+ private static void log(String title, Collection<WildcardPattern> patterns) {
+ if (!patterns.isEmpty()) {
+ LOG.info(title);
+ for (WildcardPattern pattern : patterns) {
+ LOG.info(" {}", pattern);
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.phases;
+
+import java.util.Arrays;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
+import org.sonar.api.notifications.AnalysisWarnings;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
+import org.sonar.scanner.rule.QProfileVerifier;
+import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
+import org.sonar.scanner.scan.filesystem.FileIndexer;
+
+public abstract class AbstractModulePhaseExecutor {
+
+ private static final Logger LOG = Loggers.get(AbstractModulePhaseExecutor.class);
+
+ private final PostJobsExecutor postJobsExecutor;
+ private final SensorsExecutor sensorsExecutor;
+ private final DefaultModuleFileSystem fs;
+ private final QProfileVerifier profileVerifier;
+ private final IssueExclusionsLoader issueExclusionsLoader;
+ private final InputModuleHierarchy hierarchy;
+ private final FileIndexer fileIndexer;
+ private final ModuleCoverageExclusions moduleCoverageExclusions;
+ private final ProjectCoverageExclusions projectCoverageExclusions;
+ private final AnalysisWarnings analysisWarnings;
+ private boolean warnCoverageAlreadyLogged;
+
+ public AbstractModulePhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, InputModuleHierarchy hierarchy, DefaultModuleFileSystem fs,
+ QProfileVerifier profileVerifier, IssueExclusionsLoader issueExclusionsLoader, FileIndexer fileIndexer,
+ ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
+ AnalysisWarnings analysisWarnings) {
+ this.postJobsExecutor = postJobsExecutor;
+ this.sensorsExecutor = sensorsExecutor;
+ this.fs = fs;
+ this.profileVerifier = profileVerifier;
+ this.issueExclusionsLoader = issueExclusionsLoader;
+ this.hierarchy = hierarchy;
+ this.fileIndexer = fileIndexer;
+ this.moduleCoverageExclusions = moduleCoverageExclusions;
+ this.projectCoverageExclusions = projectCoverageExclusions;
+ this.analysisWarnings = analysisWarnings;
+ }
+
+ /**
+ * Executed on each module
+ */
+ public final void execute(DefaultInputModule module) {
+ // Index the filesystem
+ fileIndexer.index();
+
+ // Log detected languages and their profiles after FS is indexed and languages detected
+ profileVerifier.execute();
+
+ // Initialize issue exclusions
+ initIssueExclusions();
+
+ // Initialize coverage exclusions
+ evaluateCoverageExclusions(module);
+
+ sensorsExecutor.execute();
+
+ afterSensors();
+
+ if (hierarchy.isRoot(module)) {
+ executeOnRoot();
+ postJobsExecutor.execute();
+ }
+ }
+
+ private void evaluateCoverageExclusions(DefaultInputModule module) {
+ if (!Arrays.equals(moduleCoverageExclusions.getCoverageExclusionConfig(), projectCoverageExclusions.getCoverageExclusionConfig())) {
+ moduleCoverageExclusions.log();
+ }
+ for (InputFile inputFile : fs.inputFiles(fs.predicates().all())) {
+ boolean excludedByProjectConfiguration = projectCoverageExclusions.isExcluded((DefaultInputFile) inputFile);
+ if (excludedByProjectConfiguration) {
+ ((DefaultInputFile) inputFile).setExcludedForCoverage(true);
+ LOG.debug("File {} excluded for coverage", inputFile);
+ continue;
+ }
+ boolean excludedByModuleConfig = moduleCoverageExclusions.isExcluded((DefaultInputFile) inputFile);
+ if (excludedByModuleConfig) {
+ ((DefaultInputFile) inputFile).setExcludedForCoverage(true);
+ if (Arrays.equals(moduleCoverageExclusions.getCoverageExclusionConfig(), projectCoverageExclusions.getCoverageExclusionConfig())) {
+ warnOnce("File '" + inputFile + "' was excluded from coverage because patterns are still evaluated using module relative paths but this is deprecated. " +
+ "Please update '" + CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY + "' configuration so that patterns refer to project relative paths");
+ } else {
+ warnOnce("Defining coverage exclusions at module level is deprecated. " +
+ "Move '" + CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY + "' from module '" + module.getName() + "' " +
+ "to the root project and update patterns to refer to project relative paths");
+ }
+ LOG.debug("File {} excluded for coverage", inputFile);
+ }
+ }
+
+ }
+
+ private void warnOnce(String msg) {
+ if (!warnCoverageAlreadyLogged) {
+ LOG.warn(msg);
+ analysisWarnings.addUnique(msg);
+ warnCoverageAlreadyLogged = true;
+ }
+ }
+
+ protected void afterSensors() {
+ }
+
+ protected abstract void executeOnRoot();
+
+ private void initIssueExclusions() {
+ if (issueExclusionsLoader.shouldExecute()) {
+ for (InputFile inputFile : fs.inputFiles(fs.predicates().all())) {
+ issueExclusionsLoader.addMulticriteriaPatterns(((DefaultInputFile) inputFile).getModuleRelativePath(), inputFile.key());
+ }
+ }
+ }
+}
+++ /dev/null
-/*
- * 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.phases;
-
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
-import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
-import org.sonar.scanner.rule.QProfileVerifier;
-import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
-import org.sonar.scanner.scan.filesystem.FileIndexer;
-
-public abstract class AbstractPhaseExecutor {
-
- private static final Logger LOG = Loggers.get(AbstractPhaseExecutor.class);
-
- private final PostJobsExecutor postJobsExecutor;
- private final SensorsExecutor sensorsExecutor;
- private final DefaultModuleFileSystem fs;
- private final QProfileVerifier profileVerifier;
- private final IssueExclusionsLoader issueExclusionsLoader;
- private final InputModuleHierarchy hierarchy;
- private final FileIndexer fileIndexer;
- private final CoverageExclusions coverageExclusions;
-
- public AbstractPhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, InputModuleHierarchy hierarchy, DefaultModuleFileSystem fs,
- QProfileVerifier profileVerifier, IssueExclusionsLoader issueExclusionsLoader, FileIndexer fileIndexer, CoverageExclusions coverageExclusions) {
- this.postJobsExecutor = postJobsExecutor;
- this.sensorsExecutor = sensorsExecutor;
- this.fs = fs;
- this.profileVerifier = profileVerifier;
- this.issueExclusionsLoader = issueExclusionsLoader;
- this.hierarchy = hierarchy;
- this.fileIndexer = fileIndexer;
- this.coverageExclusions = coverageExclusions;
- }
-
- /**
- * Executed on each module
- */
- public final void execute(DefaultInputModule module) {
- // Index the filesystem
- fileIndexer.index();
-
- // Log detected languages and their profiles after FS is indexed and languages detected
- profileVerifier.execute();
-
- // Initialize issue exclusions
- initIssueExclusions();
-
- // Initialize coverage exclusions
- initCoverageExclusions();
-
- sensorsExecutor.execute();
-
- afterSensors();
-
- if (hierarchy.isRoot(module)) {
- executeOnRoot();
- postJobsExecutor.execute();
- }
- }
-
- private void initCoverageExclusions() {
- if (coverageExclusions.shouldExecute()) {
- coverageExclusions.log();
-
- for (InputFile inputFile : fs.inputFiles(fs.predicates().all())) {
- boolean excluded = coverageExclusions.isExcluded((DefaultInputFile) inputFile);
- if (excluded) {
- ((DefaultInputFile) inputFile).setExcludedForCoverage(true);
- LOG.debug("File {} excluded for coverage", inputFile);
- }
- }
-
- }
- }
-
- protected void afterSensors() {
- }
-
- protected abstract void executeOnRoot();
-
- private void initIssueExclusions() {
- if (issueExclusionsLoader.shouldExecute()) {
- for (InputFile inputFile : fs.inputFiles(fs.predicates().all())) {
- issueExclusionsLoader.addMulticriteriaPatterns(((DefaultInputFile) inputFile).getModuleRelativePath(), inputFile.key());
- }
- }
- }
-}
+++ /dev/null
-/*
- * 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.phases;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableList.Builder;
-import java.util.Collection;
-import java.util.Iterator;
-import javax.annotation.concurrent.Immutable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.config.Configuration;
-import org.sonar.api.utils.WildcardPattern;
-
-@Immutable
-public class CoverageExclusions {
- private static final Logger LOG = LoggerFactory.getLogger(CoverageExclusions.class);
-
- private Collection<WildcardPattern> exclusionPatterns;
-
- public CoverageExclusions(Configuration settings) {
- Builder<WildcardPattern> builder = ImmutableList.builder();
- for (String pattern : settings.getStringArray(CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY)) {
- builder.add(WildcardPattern.create(pattern));
- }
- exclusionPatterns = builder.build();
- }
-
- void log() {
- log("Excluded sources for coverage: ", exclusionPatterns);
- }
-
- boolean isExcluded(DefaultInputFile file) {
- boolean found = false;
- Iterator<WildcardPattern> iterator = exclusionPatterns.iterator();
- while (!found && iterator.hasNext()) {
- found = iterator.next().match(file.getModuleRelativePath());
- }
- return found;
- }
-
- private static void log(String title, Collection<WildcardPattern> patterns) {
- if (!patterns.isEmpty()) {
- LOG.info(title);
- for (WildcardPattern pattern : patterns) {
- LOG.info(" {}", pattern);
- }
- }
- }
-
- public boolean shouldExecute() {
- return !exclusionPatterns.isEmpty();
- }
-}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
+import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.scanner.issue.tracking.IssueTransition;
import org.sonar.scanner.rule.QProfileVerifier;
import org.sonar.scanner.scan.filesystem.FileIndexer;
import org.sonar.scanner.scan.report.IssuesReports;
-public final class IssuesPhaseExecutor extends AbstractPhaseExecutor {
+public final class IssuesPhaseExecutor extends AbstractModulePhaseExecutor {
private static final Logger LOG = LoggerFactory.getLogger(IssuesPhaseExecutor.class);
private final IssueTransition localIssueTracking;
public IssuesPhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
- IssuesReports jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
- IssueExclusionsLoader issueExclusionsLoader, IssueTransition localIssueTracking, InputModuleHierarchy moduleHierarchy, FileIndexer fileIndexer,
- CoverageExclusions coverageExclusions) {
+ IssuesReports jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
+ IssueExclusionsLoader issueExclusionsLoader, IssueTransition localIssueTracking, InputModuleHierarchy moduleHierarchy, FileIndexer fileIndexer,
+ ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
+ AnalysisWarnings analysisWarnings) {
super(postJobsExecutor, sensorsExecutor, moduleHierarchy, fs, profileVerifier, issueExclusionsLoader, fileIndexer,
- coverageExclusions);
+ moduleCoverageExclusions, projectCoverageExclusions, analysisWarnings);
this.issuesReport = jsonReport;
this.localIssueTracking = localIssueTracking;
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.phases;
+
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.config.Configuration;
+
+@Immutable
+public class ModuleCoverageExclusions extends AbstractCoverageExclusions {
+
+ public ModuleCoverageExclusions(Configuration config) {
+ super(config, DefaultInputFile::getModuleRelativePath);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.phases;
+
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.config.Configuration;
+
+@Immutable
+public class ProjectCoverageExclusions extends AbstractCoverageExclusions {
+
+ public ProjectCoverageExclusions(Configuration projectConfig) {
+ super(projectConfig, DefaultInputFile::getProjectRelativePath);
+ log();
+ }
+}
package org.sonar.scanner.phases;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
+import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.scanner.cpd.CpdExecutor;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.scanner.report.ReportPublisher;
import org.sonar.scanner.scan.filesystem.FileIndexer;
import org.sonar.scanner.scm.ScmPublisher;
-public final class PublishPhaseExecutor extends AbstractPhaseExecutor {
+public final class PublishPhaseExecutor extends AbstractModulePhaseExecutor {
private final ReportPublisher reportPublisher;
private final CpdExecutor cpdExecutor;
private final ScmPublisher scm;
public PublishPhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
- ReportPublisher reportPublisher, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier, IssueExclusionsLoader issueExclusionsLoader,
- CpdExecutor cpdExecutor, ScmPublisher scm, InputModuleHierarchy hierarchy, FileIndexer fileIndexer, CoverageExclusions coverageExclusions) {
- super(postJobsExecutor, sensorsExecutor, hierarchy, fs, profileVerifier, issueExclusionsLoader, fileIndexer, coverageExclusions);
+ ReportPublisher reportPublisher, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier, IssueExclusionsLoader issueExclusionsLoader,
+ CpdExecutor cpdExecutor, ScmPublisher scm, InputModuleHierarchy hierarchy, FileIndexer fileIndexer,
+ ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
+ AnalysisWarnings analysisWarnings) {
+ super(postJobsExecutor, sensorsExecutor, hierarchy, fs, profileVerifier, issueExclusionsLoader, fileIndexer, moduleCoverageExclusions,
+ projectCoverageExclusions, analysisWarnings);
this.reportPublisher = reportPublisher;
this.cpdExecutor = cpdExecutor;
this.scm = scm;
import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
-import org.sonar.scanner.phases.AbstractPhaseExecutor;
-import org.sonar.scanner.phases.CoverageExclusions;
+import org.sonar.scanner.phases.AbstractModulePhaseExecutor;
import org.sonar.scanner.phases.IssuesPhaseExecutor;
+import org.sonar.scanner.phases.ModuleCoverageExclusions;
import org.sonar.scanner.phases.PostJobsExecutor;
import org.sonar.scanner.phases.PublishPhaseExecutor;
import org.sonar.scanner.phases.SensorsExecutor;
DefaultSensorContext.class,
ScannerExtensionDictionnary.class,
ModuleIssueFilters.class,
- CoverageExclusions.class,
+ ModuleCoverageExclusions.class,
// issues
ModuleIssues.class,
@Override
protected void doAfterStart() {
- getComponentByType(AbstractPhaseExecutor.class).execute(module);
+ getComponentByType(AbstractModulePhaseExecutor.class).execute(module);
}
}
import org.sonar.scanner.issue.tracking.ServerLineHashesLoader;
import org.sonar.scanner.mediumtest.ScanTaskObservers;
import org.sonar.scanner.notifications.DefaultAnalysisWarnings;
+import org.sonar.scanner.phases.ProjectCoverageExclusions;
import org.sonar.scanner.report.ActiveRulesPublisher;
import org.sonar.scanner.report.AnalysisContextReportPublisher;
import org.sonar.scanner.report.AnalysisWarningsPublisher;
ScannerProperties.class,
new ProjectConfigurationProvider(),
+ ProjectCoverageExclusions.class,
+
// Report
ScannerMetrics.class,
ReportPublisher.class,
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.FileUtils;
public class CoverageMediumTest {
+ private final List<String> logs = new ArrayList<>();
+
@Rule
public TemporaryFolder temp = new TemporaryFolder();
@Rule
public ScannerMediumTester tester = new ScannerMediumTester()
+ .setLogOutput((msg, level) -> logs.add(msg))
.registerPlugin("xoo", new XooPlugin())
.addDefaultQProfile("xoo", "Sonar Way");
.put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
.put("sonar.sources", "src")
.build())
.execute();
.put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
.put("sonar.sources", "src")
.build())
.execute();
}
@Test
- public void exclusions() throws IOException {
+ public void exclusionsForSimpleProject() throws IOException {
File baseDir = temp.getRoot();
File srcDir = new File(baseDir, "src");
.put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
.put("sonar.sources", "src")
.put("sonar.coverage.exclusions", "**/sample.xoo")
.build())
CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY);
}
+ @Test
+ public void warn_user_for_outdated_inherited_exclusions_for_multi_module_project() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ File xooFileA = new File(srcDirA, "sample.xoo");
+ File xooUtCoverageFileA = new File(srcDirA, "sample.xoo.coverage");
+ FileUtils.write(xooFileA, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ FileUtils.write(xooUtCoverageFileA, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
+
+ File xooFileB = new File(srcDirB, "sample.xoo");
+ File xooUtCoverageFileB = new File(srcDirB, "sample.xoo.coverage");
+ FileUtils.write(xooFileB, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ FileUtils.write(xooUtCoverageFileB, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
+
+ TaskResult result = tester.newTask()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.coverage.exclusions", "src/sample.xoo")
+ .build())
+ .execute();
+
+ InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
+ assertThat(result.coverageFor(fileA, 2)).isNull();
+
+ InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
+ assertThat(result.coverageFor(fileB, 2)).isNull();
+
+ assertThat(logs).contains("File 'moduleA/src/sample.xoo' was excluded from coverage because patterns are still " +
+ "evaluated using module relative paths but this is deprecated. Please update 'sonar.coverage.exclusions' " +
+ "configuration so that patterns refer to project relative paths");
+ }
+
+ @Test
+ public void warn_user_for_outdated_module_exclusions_for_multi_module_project() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ File xooFileA = new File(srcDirA, "sample.xoo");
+ File xooUtCoverageFileA = new File(srcDirA, "sample.xoo.coverage");
+ FileUtils.write(xooFileA, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ FileUtils.write(xooUtCoverageFileA, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
+
+ File xooFileB = new File(srcDirB, "sample.xoo");
+ File xooUtCoverageFileB = new File(srcDirB, "sample.xoo.coverage");
+ FileUtils.write(xooFileB, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}", StandardCharsets.UTF_8);
+ FileUtils.write(xooUtCoverageFileB, "2:2:2:1\n3:1", StandardCharsets.UTF_8);
+
+ TaskResult result = tester.newTask()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("moduleB.sonar.coverage.exclusions", "src/sample.xoo")
+ .build())
+ .execute();
+
+ InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
+ assertThat(result.coverageFor(fileA, 2)).isNotNull();
+
+ InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
+ assertThat(result.coverageFor(fileB, 2)).isNull();
+
+ assertThat(logs).contains("Defining coverage exclusions at module level is deprecated. " +
+ "Move 'sonar.coverage.exclusions' from module 'moduleB' " +
+ "to the root project and update patterns to refer to project relative paths");
+ }
+
@Test
public void fallbackOnExecutableLines() throws IOException {
.put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
- .put("sonar.projectName", "Foo Project")
- .put("sonar.projectVersion", "1.0-SNAPSHOT")
- .put("sonar.projectDescription", "Description of Foo Project")
.put("sonar.sources", "src")
.build())
.execute();
+++ /dev/null
-/*
- * 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.phases;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
-import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.core.config.ExclusionProperties;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class CoverageExclusionsTest {
-
- private MapSettings settings;
- private CoverageExclusions coverageExclusions;
-
- @Before
- public void prepare() {
- settings = new MapSettings(new PropertyDefinitions(ExclusionProperties.all()));
- }
-
- @Test
- public void shouldExcludeFileBasedOnPattern() {
- DefaultInputFile file = new TestInputFileBuilder("foo", "src/org/polop/File.php").build();
- settings.setProperty("sonar.coverage.exclusions", "src/org/polop/*");
- coverageExclusions = new CoverageExclusions(settings.asConfig());
- assertThat(coverageExclusions.isExcluded(file)).isTrue();
- }
-
- @Test
- public void shouldNotExcludeFileBasedOnPattern() {
- DefaultInputFile file = new TestInputFileBuilder("foo", "src/org/polop/File.php").build();
- settings.setProperty("sonar.coverage.exclusions", "src/org/other/*");
- coverageExclusions = new CoverageExclusions(settings.asConfig());
- assertThat(coverageExclusions.isExcluded(file)).isFalse();
- }
-}
--- /dev/null
+/*
+ * 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.phases;
+
+import java.io.File;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.core.config.ExclusionProperties;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ModuleCoverageExclusionsTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private MapSettings settings;
+ private ModuleCoverageExclusions coverageExclusions;
+ private File baseDir;
+
+ @Before
+ public void prepare() throws Exception {
+ settings = new MapSettings(new PropertyDefinitions(ExclusionProperties.all()));
+ baseDir = temp.newFolder();
+ }
+
+ @Test
+ public void shouldExcludeFileBasedOnPattern() {
+ DefaultInputFile file = TestInputFileBuilder.create("foo", new File(baseDir, "moduleA"), new File(baseDir, "moduleA/src/org/polop/File.php"))
+ .setProjectBaseDir(baseDir.toPath())
+ .build();
+ settings.setProperty("sonar.coverage.exclusions", "src/org/polop/*");
+ coverageExclusions = new ModuleCoverageExclusions(settings.asConfig());
+ assertThat(coverageExclusions.isExcluded(file)).isTrue();
+ }
+
+ @Test
+ public void shouldNotExcludeFileBasedOnPattern() {
+ DefaultInputFile file = TestInputFileBuilder.create("foo", new File(baseDir, "moduleA"), new File(baseDir, "moduleA/src/org/polop/File.php"))
+ .setProjectBaseDir(baseDir.toPath())
+ .build();
+ settings.setProperty("sonar.coverage.exclusions", "src/org/other/*");
+ coverageExclusions = new ModuleCoverageExclusions(settings.asConfig());
+ assertThat(coverageExclusions.isExcluded(file)).isFalse();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.phases;
+
+import java.io.File;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.core.config.ExclusionProperties;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ProjectCoverageExclusionsTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private MapSettings settings;
+ private ProjectCoverageExclusions coverageExclusions;
+ private File baseDir;
+
+ @Before
+ public void prepare() throws Exception {
+ settings = new MapSettings(new PropertyDefinitions(ExclusionProperties.all()));
+ baseDir = temp.newFolder();
+ }
+
+ @Test
+ public void shouldExcludeFileBasedOnPattern() {
+ DefaultInputFile file = TestInputFileBuilder.create("foo", new File(baseDir, "moduleA"), new File(baseDir, "moduleA/src/org/polop/File.php"))
+ .setProjectBaseDir(baseDir.toPath())
+ .build();
+ settings.setProperty("sonar.coverage.exclusions", "moduleA/src/org/polop/*");
+ coverageExclusions = new ProjectCoverageExclusions(settings.asConfig());
+ assertThat(coverageExclusions.isExcluded(file)).isTrue();
+ }
+
+ @Test
+ public void shouldNotExcludeFileBasedOnPattern() {
+ DefaultInputFile file = TestInputFileBuilder.create("foo", new File(baseDir, "moduleA"), new File(baseDir, "moduleA/src/org/polop/File.php"))
+ .setProjectBaseDir(baseDir.toPath())
+ .build();
+ settings.setProperty("sonar.coverage.exclusions", "moduleA/src/org/other/*");
+ coverageExclusions = new ProjectCoverageExclusions(settings.asConfig());
+ assertThat(coverageExclusions.isExcluded(file)).isFalse();
+ }
+}