]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9711 Skip duplications and coverage in short living branches
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Mon, 14 Aug 2017 07:56:19 +0000 (09:56 +0200)
committerJanos Gyerik <janos.gyerik@sonarsource.com>
Tue, 12 Sep 2017 08:59:56 +0000 (10:59 +0200)
sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/deprecated/DeprecatedSensorContext.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfiguration.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfigurationProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/DefaultBranchConfiguration.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorContext.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/noop/NoOpNewCoverage.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorContextTest.java

index e8e1d804b3688c21aabf7ff9a66b483909ba7f69..1ce8033e270d4f8cd824937ab7879d413e1252b7 100644 (file)
@@ -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);
   }
 
index 25439a3f923280ecc655b01718c23fcc26371f78..8f4a0c420d667fc160c4a4796f43479c2097ed1b 100644 (file)
@@ -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;
   }
index f74ca356c4fb0f7ba89c9b8b3a3e33f46bcbc610..9d9d62328f9db2af6c505193088df00403efb51e 100644 (file)
@@ -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()) {
index 786744fcf5dea679f7af4420c055fac1a9f213d9..415b68403426590572479732ff5203b5024b4b77 100644 (file)
@@ -47,4 +47,10 @@ public interface BranchConfiguration {
    */
   @CheckForNull
   String branchTarget();
+
+  /**
+   * The name of the branch.
+   */
+  @CheckForNull
+  String branchName();
 }
index 46e182672a74ff1733dea2a815b0e1af47989360..db35c12ca804b3c18b89455d352faefbea5e0d09 100644 (file)
@@ -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;
   }
index 2bcd480d0038ab3f781e49fa7326d360c9853e57..f81bc572063a627f27e0b6688f9e148622eb1523 100644 (file)
@@ -34,4 +34,10 @@ public class DefaultBranchConfiguration implements BranchConfiguration {
   public String branchTarget() {
     return null;
   }
+
+  @CheckForNull
+  @Override
+  public String branchName() {
+    return null;
+  }
 }
index af4b631149be62b9af74a630492d7a2e842d99c4..f6575cfea605bb96616350605ba99f411c753891 100644 (file)
@@ -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 (file)
index 0000000..881e0b7
--- /dev/null
@@ -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
+  }
+}
index 71d060e2f46b5a6b7ed9bcb63ffd0183d00f9609..b8bdfa48233d54fe07dd932eb09431ed86092be1 100644 (file)
@@ -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())
index 456221d91cd155ec72424c430e7995060379a102..3bc70f9c875c09b020fa29a6b3b44cc5b33abe68 100644 (file)
@@ -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();
index c73b0636e67d4df5af94f9a0f5e4c2a567b6fbca..92c62a33436afc7be6b20eab6a4ea2b7e3e40a40 100644 (file)
@@ -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.<Integer>findByKey(CoreMetrics.NCLOC_KEY)).thenReturn(CoreMetrics.NCLOC);
     when(metricFinder.<String>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);
+  }
 }