From 0ce71ddd4933fca7f4b909e108b9ea26fc25a22c Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Mon, 14 Aug 2017 09:56:19 +0200 Subject: [PATCH] SONAR-9711 Skip duplications and coverage in short living branches --- .../org/sonar/scanner/cpd/CpdExecutor.java | 11 +++- .../deprecated/DeprecatedSensorContext.java | 7 ++- .../scanner/report/MetadataPublisher.java | 8 +-- .../scanner/scan/BranchConfiguration.java | 6 ++ .../scan/BranchConfigurationProvider.java | 4 +- .../scan/DefaultBranchConfiguration.java | 6 ++ .../scanner/sensor/DefaultSensorContext.java | 16 ++++-- .../scanner/sensor/noop/NoOpNewCoverage.java | 56 +++++++++++++++++++ .../sonar/scanner/cpd/CpdExecutorTest.java | 18 +++++- .../scanner/report/MetadataPublisherTest.java | 7 +-- .../sensor/DefaultSensorContextTest.java | 11 +++- 11 files changed, 129 insertions(+), 21 deletions(-) create mode 100644 sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/noop/NoOpNewCoverage.java diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java index e8e1d804b36..1ce8033e270 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java @@ -45,6 +45,8 @@ import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.scanner.protocol.output.ScannerReport.Duplicate; import org.sonar.scanner.protocol.output.ScannerReport.Duplication; import org.sonar.scanner.report.ReportPublisher; +import org.sonar.scanner.scan.BranchConfiguration; +import org.sonar.scanner.scan.BranchConfiguration.BranchType; import org.sonar.scanner.scan.filesystem.InputComponentStore; import org.sonar.scanner.util.ProgressReport; @@ -69,18 +71,25 @@ public class CpdExecutor { private final InputComponentStore componentStore; private final ProgressReport progressReport; private final CpdSettings settings; + private final BranchConfiguration branchConfiguration; private int count; private int total; - public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache) { + public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache, + BranchConfiguration branchConfiguration) { this.settings = settings; this.index = index; this.publisher = publisher; this.componentStore = inputComponentCache; + this.branchConfiguration = branchConfiguration; this.progressReport = new ProgressReport("CPD computation", TimeUnit.SECONDS.toMillis(10)); } public void execute() { + if (branchConfiguration.branchType() == BranchType.SHORT) { + LOG.info("Skipping CPD calculation for short living branch"); + return; + } execute(TIMEOUT); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/deprecated/DeprecatedSensorContext.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/deprecated/DeprecatedSensorContext.java index 25439a3f923..8f4a0c420d6 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/deprecated/DeprecatedSensorContext.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/deprecated/DeprecatedSensorContext.java @@ -40,6 +40,7 @@ import org.sonar.api.resources.Resource; import org.sonar.api.resources.ResourceUtils; import org.sonar.core.component.ComponentKeys; import org.sonar.scanner.index.DefaultIndex; +import org.sonar.scanner.scan.BranchConfiguration; import org.sonar.scanner.sensor.DefaultSensorContext; public class DeprecatedSensorContext extends DefaultSensorContext implements SensorContext { @@ -47,9 +48,9 @@ public class DeprecatedSensorContext extends DefaultSensorContext implements Sen private final InputModule module; public DeprecatedSensorContext(InputModule module, DefaultIndex index, Configuration config, org.sonar.api.config.Settings mutableSettings, - FileSystem fs, ActiveRules activeRules, - AnalysisMode analysisMode, SensorStorage sensorStorage, SonarRuntime sonarRuntime) { - super(module, config, mutableSettings, fs, activeRules, analysisMode, sensorStorage, sonarRuntime); + FileSystem fs, ActiveRules activeRules, AnalysisMode analysisMode, SensorStorage sensorStorage, SonarRuntime sonarRuntime, + BranchConfiguration branchConfiguration) { + super(module, config, mutableSettings, fs, activeRules, analysisMode, sensorStorage, sonarRuntime, branchConfiguration); this.index = index; this.module = module; } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java index f74ca356c4f..9d9d62328f9 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java @@ -37,7 +37,6 @@ import org.sonar.scanner.rule.ModuleQProfiles; import org.sonar.scanner.rule.QProfile; import org.sonar.scanner.scan.BranchConfiguration; -import static org.sonar.core.config.ScannerProperties.BRANCH_NAME; import static org.sonar.core.config.ScannerProperties.ORGANIZATION; public class MetadataPublisher implements ReportPublisherStep { @@ -76,14 +75,15 @@ public class MetadataPublisher implements ReportPublisherStep { .setIncremental(mode.isIncremental()); settings.get(ORGANIZATION).ifPresent(builder::setOrganizationKey); - settings.get(BRANCH_NAME).ifPresent(branch -> { - builder.setBranchName(branch); + + if (branchConfiguration.branchName() != null) { + builder.setBranchName(branchConfiguration.branchName()); builder.setBranchType(toProtobufBranchType(branchConfiguration.branchType())); String branchTarget = branchConfiguration.branchTarget(); if (branchTarget != null) { builder.setMergeBranchName(branchTarget); } - }); + } Optional.ofNullable(rootDef.getBranch()).ifPresent(builder::setDeprecatedBranch); for (QProfile qp : qProfiles.findAll()) { diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfiguration.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfiguration.java index 786744fcf5d..415b6840342 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfiguration.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfiguration.java @@ -47,4 +47,10 @@ public interface BranchConfiguration { */ @CheckForNull String branchTarget(); + + /** + * The name of the branch. + */ + @CheckForNull + String branchName(); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfigurationProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfigurationProvider.java index 46e182672a7..db35c12ca80 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfigurationProvider.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfigurationProvider.java @@ -36,13 +36,13 @@ public class BranchConfigurationProvider extends ProviderAdapter { public BranchConfiguration provide(@Nullable BranchConfigurationLoader loader, ProjectKey projectKey, GlobalConfiguration globalConfiguration) { if (branchConfiguration == null) { - Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); if (loader == null) { branchConfiguration = new DefaultBranchConfiguration(); } else { + Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); branchConfiguration = loader.load(projectKey.get(), globalConfiguration); + profiler.stopInfo(); } - profiler.stopInfo(); } return branchConfiguration; } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/DefaultBranchConfiguration.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/DefaultBranchConfiguration.java index 2bcd480d003..f81bc572063 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/DefaultBranchConfiguration.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/DefaultBranchConfiguration.java @@ -34,4 +34,10 @@ public class DefaultBranchConfiguration implements BranchConfiguration { public String branchTarget() { return null; } + + @CheckForNull + @Override + public String branchName() { + return null; + } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorContext.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorContext.java index af4b631149b..f6575cfea60 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorContext.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorContext.java @@ -48,7 +48,10 @@ import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable; import org.sonar.api.config.Configuration; import org.sonar.api.config.Settings; import org.sonar.api.utils.Version; +import org.sonar.scanner.scan.BranchConfiguration; +import org.sonar.scanner.scan.BranchConfiguration.BranchType; import org.sonar.scanner.sensor.noop.NoOpNewAnalysisError; +import org.sonar.scanner.sensor.noop.NoOpNewCoverage; import org.sonar.scanner.sensor.noop.NoOpNewCpdTokens; import org.sonar.scanner.sensor.noop.NoOpNewHighlighting; import org.sonar.scanner.sensor.noop.NoOpNewSymbolTable; @@ -58,8 +61,9 @@ public class DefaultSensorContext implements SensorContext { private static final NoOpNewHighlighting NO_OP_NEW_HIGHLIGHTING = new NoOpNewHighlighting(); private static final NoOpNewSymbolTable NO_OP_NEW_SYMBOL_TABLE = new NoOpNewSymbolTable(); - private static final NoOpNewCpdTokens NO_OP_NEW_CPD_TOKENS = new NoOpNewCpdTokens(); + static final NoOpNewCpdTokens NO_OP_NEW_CPD_TOKENS = new NoOpNewCpdTokens(); private static final NoOpNewAnalysisError NO_OP_NEW_ANALYSIS_ERROR = new NoOpNewAnalysisError(); + static final NoOpNewCoverage NO_OP_NEW_COVERAGE = new NoOpNewCoverage(); private final Settings mutableSettings; private final FileSystem fs; @@ -69,10 +73,10 @@ public class DefaultSensorContext implements SensorContext { private final InputModule module; private final SonarRuntime sonarRuntime; private final Configuration config; + private final BranchConfiguration branchConfiguration; public DefaultSensorContext(InputModule module, Configuration config, Settings mutableSettings, FileSystem fs, ActiveRules activeRules, - AnalysisMode analysisMode, SensorStorage sensorStorage, - SonarRuntime sonarRuntime) { + AnalysisMode analysisMode, SensorStorage sensorStorage, SonarRuntime sonarRuntime, BranchConfiguration branchConfiguration) { this.module = module; this.config = config; this.mutableSettings = mutableSettings; @@ -81,6 +85,7 @@ public class DefaultSensorContext implements SensorContext { this.analysisMode = analysisMode; this.sensorStorage = sensorStorage; this.sonarRuntime = sonarRuntime; + this.branchConfiguration = branchConfiguration; } @Override @@ -146,12 +151,15 @@ public class DefaultSensorContext implements SensorContext { @Override public NewCoverage newCoverage() { + if (branchConfiguration.branchType() == BranchType.SHORT) { + return NO_OP_NEW_COVERAGE; + } return new DefaultCoverage(sensorStorage); } @Override public NewCpdTokens newCpdTokens() { - if (analysisMode.isIssues()) { + if (analysisMode.isIssues() || branchConfiguration.branchType() == BranchType.SHORT) { return NO_OP_NEW_CPD_TOKENS; } return new DefaultCpdTokens(config, sensorStorage); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/noop/NoOpNewCoverage.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/noop/NoOpNewCoverage.java new file mode 100644 index 00000000000..881e0b7b560 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/noop/NoOpNewCoverage.java @@ -0,0 +1,56 @@ +/* + * 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.scanner.sensor.noop; + +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.sensor.coverage.CoverageType; +import org.sonar.api.batch.sensor.coverage.NewCoverage; + +public class NoOpNewCoverage implements NewCoverage { + + @Override + public NewCoverage onFile(InputFile inputFile) { + // no op + return this; + } + + @Override + public NewCoverage ofType(CoverageType type) { + // no op + return this; + } + + @Override + public NewCoverage lineHits(int line, int hits) { + // no op + return this; + } + + @Override + public NewCoverage conditions(int line, int conditions, int coveredConditions) { + // no op + return this; + } + + @Override + public void save() { + // no op + } +} diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java index 71d060e2f46..b8bdfa48233 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java @@ -48,10 +48,13 @@ import org.sonar.scanner.protocol.output.ScannerReport.Duplication; import org.sonar.scanner.protocol.output.ScannerReportReader; import org.sonar.scanner.protocol.output.ScannerReportWriter; import org.sonar.scanner.report.ReportPublisher; +import org.sonar.scanner.scan.BranchConfiguration; +import org.sonar.scanner.scan.BranchConfiguration.BranchType; import org.sonar.scanner.scan.filesystem.InputComponentStore; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; public class CpdExecutorTest { @@ -64,6 +67,7 @@ public class CpdExecutorTest { @Rule public ExpectedException thrown = ExpectedException.none(); + private BranchConfiguration branchConfig; private CpdExecutor executor; private CpdSettings settings; private SonarCpdBlockIndex index; @@ -80,6 +84,7 @@ public class CpdExecutorTest { File outputDir = temp.newFolder(); baseDir = temp.newFolder(); + branchConfig = mock(BranchConfiguration.class); settings = mock(CpdSettings.class); publisher = mock(ReportPublisher.class); when(publisher.getWriter()).thenReturn(new ScannerReportWriter(outputDir)); @@ -87,7 +92,7 @@ public class CpdExecutorTest { index = new SonarCpdBlockIndex(publisher, settings); DefaultInputModule inputModule = TestInputFileBuilder.newDefaultInputModule("foo", baseDir); componentStore = new InputComponentStore(inputModule, mock(AnalysisMode.class)); - executor = new CpdExecutor(settings, index, publisher, componentStore); + executor = new CpdExecutor(settings, index, publisher, componentStore, branchConfig); reader = new ScannerReportReader(outputDir); batchComponent1 = createComponent("src/Foo.php", 5); @@ -95,6 +100,17 @@ public class CpdExecutorTest { batchComponent3 = createComponent("src/Foo3.php", 5); } + @Test + public void skipIfShortBranch() { + when(branchConfig.branchType()).thenReturn(BranchType.SHORT); + index = mock(SonarCpdBlockIndex.class); + executor = new CpdExecutor(settings, index, publisher, componentStore, branchConfig); + + executor.execute(); + + verifyZeroInteractions(index); + } + private DefaultInputFile createComponent(String relativePath, int lines) { DefaultInputFile file = new TestInputFileBuilder("foo", relativePath) .setModuleBaseDir(baseDir.toPath()) diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java index 456221d91cd..3bc70f9c875 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java @@ -167,8 +167,7 @@ public class MetadataPublisherTest { @Test public void write_long_lived_branch_info() throws Exception { String branchName = "long-lived"; - settings.setProperty(ScannerProperties.BRANCH_NAME, branchName); - + when(branches.branchName()).thenReturn(branchName); when(branches.branchType()).thenReturn(BranchConfiguration.BranchType.LONG); File outputDir = temp.newFolder(); @@ -184,9 +183,7 @@ public class MetadataPublisherTest { public void write_short_lived_branch_info() throws Exception { String branchName = "feature"; String branchTarget = "short-lived"; - settings.setProperty(ScannerProperties.BRANCH_NAME, branchName); - settings.setProperty(ScannerProperties.BRANCH_TARGET, branchTarget); - + when(branches.branchName()).thenReturn(branchName); when(branches.branchTarget()).thenReturn(branchTarget); File outputDir = temp.newFolder(); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorContextTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorContextTest.java index c73b0636e67..92c62a33436 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorContextTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorContextTest.java @@ -37,6 +37,7 @@ import org.sonar.api.config.internal.MapSettings; import org.sonar.api.internal.SonarRuntimeImpl; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.utils.Version; +import org.sonar.scanner.scan.BranchConfiguration; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -57,6 +58,7 @@ public class DefaultSensorContextTest { private SensorStorage sensorStorage; private AnalysisMode analysisMode; private SonarRuntime runtime; + private BranchConfiguration branchConfig; @Before public void prepare() throws Exception { @@ -66,10 +68,11 @@ public class DefaultSensorContextTest { when(metricFinder.findByKey(CoreMetrics.NCLOC_KEY)).thenReturn(CoreMetrics.NCLOC); when(metricFinder.findByKey(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION_KEY)).thenReturn(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION); settings = new MapSettings(); + branchConfig = mock(BranchConfiguration.class); sensorStorage = mock(SensorStorage.class); analysisMode = mock(AnalysisMode.class); runtime = SonarRuntimeImpl.forSonarQube(Version.parse("5.5"), SonarQubeSide.SCANNER); - adaptor = new DefaultSensorContext(mock(InputModule.class), settings.asConfig(), settings, fs, activeRules, analysisMode, sensorStorage, runtime); + adaptor = new DefaultSensorContext(mock(InputModule.class), settings.asConfig(), settings, fs, activeRules, analysisMode, sensorStorage, runtime, branchConfig); } @Test @@ -86,4 +89,10 @@ public class DefaultSensorContextTest { assertThat(adaptor.isCancelled()).isFalse(); } + @Test + public void shouldSkipDupsAndCoverageOnShortBranches() { + when(branchConfig.branchType()).thenReturn(BranchConfiguration.BranchType.SHORT); + assertThat(adaptor.newCpdTokens()).isEqualTo(DefaultSensorContext.NO_OP_NEW_CPD_TOKENS); + assertThat(adaptor.newCoverage()).isEqualTo(DefaultSensorContext.NO_OP_NEW_COVERAGE); + } } -- 2.39.5