]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-11856 Store the "true" target branch in the scanner report to display it properly
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Mon, 1 Apr 2019 09:28:19 +0000 (11:28 +0200)
committerSonarTech <sonartech@sonarsource.com>
Tue, 23 Apr 2019 18:21:07 +0000 (20:21 +0200)
48 files changed:
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/Branch.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImpl.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/DefaultBranchImpl.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/MergeBranchComponentUuids.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/SiblingComponentsWithOpenIssues.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoader.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStep.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutorTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImplTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/MergeBranchComponentUuidsTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/SiblingComponentsWithOpenIssuesTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/SiblingsIssueMergerTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoaderTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/LoadPeriodsStepTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ReportPersistComponentsStepTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStepTest.java
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java
server/sonar-db-dao/src/main/protobuf/db-project-branches.proto
server/sonar-server/src/main/java/org/sonar/server/branch/pr/ws/ListAction.java
server/sonar-server/src/main/resources/org/sonar/server/branch/pr/ws/list-example.json
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/StatusPredicate.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ChangedLinesPublisher.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultQualityProfileLoader.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositoriesProvider.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositoriesSupplier.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/QualityProfileLoader.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/QualityProfilesProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/BranchConfiguration.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/DefaultBranchConfiguration.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/StatusDetection.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFiles.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFilesProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmPublisher.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ChangedLinesPublisherTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/DefaultQualityProfileLoaderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/ProjectRepositoriesProviderTest.java [deleted file]
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/ProjectRepositoriesSupplierTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/QualityProfileProviderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/branch/BranchConfigurationProviderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/StatusDetectionTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesProviderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesTest.java
sonar-scanner-protocol/src/main/protobuf/scanner_report.proto
sonar-ws/src/main/protobuf/ws-projectpullrequests.proto

index e9eb4c21914ddff303a33d008c05eebcf28740b9..22c0702dd150958b8d171d2d964f9deea5fe516c 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.ce.task.projectanalysis.analysis;
 
-import java.util.Optional;
 import javax.annotation.concurrent.Immutable;
 import org.sonar.ce.task.projectanalysis.component.ComponentKeyGenerator;
 import org.sonar.db.component.BranchType;
@@ -43,10 +42,11 @@ public interface Branch extends ComponentKeyGenerator {
   String getName();
 
   /**
-   * Indicates the branch from which it was forked.
-   * It will be empty for main branches or legacy branches.
+   * Indicates the first LLB branch from which it was forked.
+   *
+   * @throws IllegalStateException for main branches or legacy branches.
    */
-  Optional<String> getMergeBranchUuid();
+  String getMergeBranchUuid();
 
   /**
    * Whether the cross-project duplication tracker must be enabled
@@ -58,4 +58,13 @@ public interface Branch extends ComponentKeyGenerator {
    * @throws IllegalStateException if this branch configuration is not a pull request.
    */
   String getPullRequestKey();
+
+  /**
+   * The target/base branch name of a SLB or PR.
+   * Correspond to <pre>sonar.pullrequest.base</pre> or <pre>sonar.branch.target</pre>
+   * It's not guaranteed to exist.
+   *
+   * @throws IllegalStateException if this branch configuration is not a pull request or SLB.
+   */
+  String getTargetBranchName();
 }
index cde9d00d1c6ab689eafbcc186f651b04d76532ca..a8bfb52aab22f98ed9f4cd9e736a6870caea824e 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.ce.task.projectanalysis.component;
 
 import javax.annotation.Nullable;
+import org.sonar.api.resources.Qualifiers;
 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
 import org.sonar.ce.task.projectanalysis.analysis.Branch;
 import org.sonar.db.DbClient;
@@ -62,8 +63,10 @@ public class BranchPersisterImpl implements BranchPersister {
     dto.setProjectUuid(firstNonNull(componentDto.getMainBranchProjectUuid(), componentDto.projectUuid()));
     dto.setBranchType(branch.getType());
 
-    // merge branch is only present if it's a short living branch
-    dto.setMergeBranchUuid(branch.getMergeBranchUuid().orElse(null));
+    // merge branch is only present if it's not a main branch and not an application
+    if (!branch.isMain() && !Qualifiers.APP.equals(componentDto.qualifier())) {
+      dto.setMergeBranchUuid(branch.getMergeBranchUuid());
+    }
 
     if (branch.getType() == BranchType.PULL_REQUEST) {
       dto.setKey(analysisMetadataHolder.getPullRequestKey());
@@ -71,6 +74,7 @@ public class BranchPersisterImpl implements BranchPersister {
       DbProjectBranches.PullRequestData pullRequestData = DbProjectBranches.PullRequestData.newBuilder()
         .setBranch(branch.getName())
         .setTitle(branch.getName())
+        .setTarget(branch.getTargetBranchName())
         .build();
       dto.setPullRequestData(pullRequestData);
     } else {
index ae137aa4743b544757803a37be339f4d9357a0ba..1a15ad8e243514fbbcb782c042b9303091084605 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.ce.task.projectanalysis.component;
 
-import java.util.Optional;
 import javax.annotation.Nullable;
 import org.sonar.api.utils.MessageException;
 import org.sonar.ce.task.projectanalysis.analysis.Branch;
@@ -64,8 +63,8 @@ public class DefaultBranchImpl implements Branch {
   }
 
   @Override
-  public Optional<String> getMergeBranchUuid() {
-    return Optional.empty();
+  public String getMergeBranchUuid() {
+    throw new IllegalStateException("Not valid for the main branch");
   }
 
   @Override
@@ -89,6 +88,11 @@ public class DefaultBranchImpl implements Branch {
     throw new IllegalStateException("Only a branch of type PULL_REQUEST can have a pull request id.");
   }
 
+  @Override
+  public String getTargetBranchName() {
+    throw new IllegalStateException("Only on a short lived branch or pull request");
+  }
+
   @Override
   public String generateKey(String projectKey, @Nullable String fileOrDirPath) {
     if (isLegacyBranch) {
index 84d5d066f0fd74ba17a490103fa38e6be1ddc068..888e0c181b132d8e721c41c45ccb5c1d8b4f2ef2 100644 (file)
@@ -50,7 +50,7 @@ public class MergeBranchComponentUuids {
 
   private void lazyInit() {
     if (uuidsByKey == null) {
-      String mergeBranchUuid = analysisMetadataHolder.getBranch().getMergeBranchUuid().get();
+      String mergeBranchUuid = analysisMetadataHolder.getBranch().getMergeBranchUuid();
 
       uuidsByKey = new HashMap<>();
       try (DbSession dbSession = dbClient.openSession(false)) {
index cce1c2d09dc1edbdd63c764651f60f5e77c78f69..6d7defeccb6ab095cbe8fee0c4cc59069c4335af 100644 (file)
@@ -34,7 +34,6 @@ import static org.sonar.db.component.ComponentDto.removeBranchAndPullRequestFrom
 
 /**
  * Cache a map of component key -> set&lt;uuid&gt; in sibling branches/PR that have open issues
- *
  */
 public class SiblingComponentsWithOpenIssues {
   private final DbClient dbClient;
@@ -50,11 +49,19 @@ public class SiblingComponentsWithOpenIssues {
   }
 
   private void loadUuidsByKey() {
-    uuidsByKey = new HashMap<>();
     String currentBranchUuid = treeRootHolder.getRoot().getUuid();
+    String longLivingReferenceBranchUuid;
+
+    if (metadataHolder.isSLBorPR()) {
+      longLivingReferenceBranchUuid = metadataHolder.getBranch().getMergeBranchUuid();
+    } else {
+      longLivingReferenceBranchUuid = currentBranchUuid;
+    }
+
+    uuidsByKey = new HashMap<>();
     try (DbSession dbSession = dbClient.openSession(false)) {
       List<KeyWithUuidDto> components = dbClient.componentDao().selectAllSiblingComponentKeysHavingOpenIssues(dbSession,
-        metadataHolder.getBranch().getMergeBranchUuid().orElse(currentBranchUuid), currentBranchUuid);
+        longLivingReferenceBranchUuid, currentBranchUuid);
       for (KeyWithUuidDto dto : components) {
         uuidsByKey.computeIfAbsent(removeBranchAndPullRequestFromKey(dto.key()), s -> new HashSet<>()).add(dto.uuid());
       }
index 6f9b8b5442b9d6ee6acc516a686b98a40ddb6bc2..e553e40f8a65371b83449f0ff7bee324999a7762 100644 (file)
@@ -66,7 +66,7 @@ public class ScmInfoDbLoader {
 
     // at this point, it's the first analysis but had copyFromPrevious flag true
     Branch branch = analysisMetadataHolder.getBranch();
-    if (branch.getMergeBranchUuid().isPresent()) {
+    if (!branch.isMain()) {
       return Optional.ofNullable(mergeBranchComponentUuid.getUuid(file.getDbKey()));
     }
 
index fab944e408d0ab7f7741ea04bef763773ba406a5..441e9eefbb80ccc9bfc659a946107d21ab0470fc 100644 (file)
@@ -91,7 +91,7 @@ public class ValidateProjectStep implements ComputationStep {
     if (!analysisMetadataHolder.isSLBorPR()) {
       return;
     }
-    String mergeBranchUuid = analysisMetadataHolder.getBranch().getMergeBranchUuid().get();
+    String mergeBranchUuid = analysisMetadataHolder.getBranch().getMergeBranchUuid();
     int moduleCount = dbClient.componentDao().countEnabledModulesByProjectUuid(session, mergeBranchUuid);
     if (moduleCount > 0) {
       Optional<BranchDto> opt = dbClient.branchDao().selectByUuid(session, mergeBranchUuid);
index e275c6dffacb6cf63f5ffbf897a1541d7fe876f1..adc120665a2037ceaab9b1a1822278f4890b6d2e 100644 (file)
@@ -25,7 +25,6 @@ import com.tngtech.java.junit.dataprovider.DataProviderRunner;
 import com.tngtech.java.junit.dataprovider.UseDataProvider;
 import java.util.Date;
 import java.util.List;
-import java.util.Optional;
 import java.util.Random;
 import javax.annotation.Nullable;
 import org.apache.commons.lang.RandomStringUtils;
@@ -135,7 +134,7 @@ public class PostProjectAnalysisTasksExecutorTest {
     new PostProjectAnalysisTasksExecutor(
       ceTask, analysisMetadataHolder, qualityGateHolder, qualityGateStatusHolder, reportReader,
       system2, new PostProjectAnalysisTask[] {postProjectAnalysisTask1, postProjectAnalysisTask2})
-        .finished(allStepsExecuted);
+      .finished(allStepsExecuted);
 
     inOrder.verify(postProjectAnalysisTask1).finished(projectAnalysisArgumentCaptor.capture());
     inOrder.verify(postProjectAnalysisTask2).finished(projectAnalysisArgumentCaptor.capture());
@@ -289,8 +288,8 @@ public class PostProjectAnalysisTasksExecutorTest {
       }
 
       @Override
-      public Optional<String> getMergeBranchUuid() {
-        return Optional.empty();
+      public String getMergeBranchUuid() {
+        throw new UnsupportedOperationException();
       }
 
       @Override
@@ -308,6 +307,10 @@ public class PostProjectAnalysisTasksExecutorTest {
         throw new UnsupportedOperationException();
       }
 
+      @Override public String getTargetBranchName() {
+        throw new UnsupportedOperationException();
+      }
+
       @Override
       public String generateKey(String projectKey, @Nullable String fileOrDirPath) {
         throw new UnsupportedOperationException();
@@ -372,7 +375,7 @@ public class PostProjectAnalysisTasksExecutorTest {
     new PostProjectAnalysisTasksExecutor(
       ceTask, analysisMetadataHolder, qualityGateHolder, qualityGateStatusHolder, reportReader,
       system2, new PostProjectAnalysisTask[] {postProjectAnalysisTask1, postProjectAnalysisTask2, postProjectAnalysisTask3})
-        .finished(allStepsExecuted);
+      .finished(allStepsExecuted);
 
     inOrder.verify(postProjectAnalysisTask1).finished(projectAnalysisArgumentCaptor.capture());
     inOrder.verify(postProjectAnalysisTask2).finished(projectAnalysisArgumentCaptor.capture());
index 8b98135f33d205f66020e94e08c75f742a5d989d..cb4764c1b7ba883ac5c91cacc071574c6b9b4f4f 100644 (file)
@@ -142,8 +142,7 @@ public class BranchPersisterImplTest {
   }
 
   @Test
-  @UseDataProvider("nullOrNotNullString")
-  public void persist_creates_row_in_PROJECTS_BRANCHES_for_pull_request(@Nullable String mergeBranchUuid) {
+  public void persist_creates_row_in_PROJECTS_BRANCHES_for_pull_request() {
     String pullRequestId = "pr-123";
 
     // add project and branch in table PROJECTS
@@ -153,7 +152,7 @@ public class BranchPersisterImplTest {
     dbTester.commit();
     // set project in metadata
     treeRootHolder.setRoot(BRANCH);
-    analysisMetadataHolder.setBranch(createBranch(PULL_REQUEST, false, pullRequestId, mergeBranchUuid));
+    analysisMetadataHolder.setBranch(createBranch(PULL_REQUEST, false, pullRequestId, "mergeBanchUuid"));
     analysisMetadataHolder.setProject(Project.from(mainComponent));
     analysisMetadataHolder.setPullRequestKey(pullRequestId);
 
@@ -166,10 +165,11 @@ public class BranchPersisterImplTest {
     assertThat(branchDto).isPresent();
     assertThat(branchDto.get().getBranchType()).isEqualTo(PULL_REQUEST);
     assertThat(branchDto.get().getKey()).isEqualTo(pullRequestId);
-    assertThat(branchDto.get().getMergeBranchUuid()).isEqualTo(mergeBranchUuid);
+    assertThat(branchDto.get().getMergeBranchUuid()).isEqualTo("mergeBanchUuid");
     assertThat(branchDto.get().getProjectUuid()).isEqualTo(MAIN.getUuid());
     assertThat(branchDto.get().getPullRequestData()).isEqualTo(DbProjectBranches.PullRequestData.newBuilder()
       .setBranch(pullRequestId)
+      .setTarget("mergeBanchUuid")
       .setTitle(pullRequestId)
       .build());
   }
@@ -183,7 +183,8 @@ public class BranchPersisterImplTest {
     when(branch.getType()).thenReturn(type);
     when(branch.getName()).thenReturn(name);
     when(branch.isMain()).thenReturn(isMain);
-    when(branch.getMergeBranchUuid()).thenReturn(Optional.ofNullable(mergeBranchUuid));
+    when(branch.getMergeBranchUuid()).thenReturn(mergeBranchUuid);
+    when(branch.getTargetBranchName()).thenReturn(mergeBranchUuid);
     return branch;
   }
 
index 5fe2b5e950b50fa0ae81878bd6098f7e073dad47..a0409c6a56e941a93c3efea77d45fc6e8687a867 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.ce.task.projectanalysis.component;
 
-import java.util.Optional;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -62,19 +61,19 @@ public class MergeBranchComponentUuidsTest {
 
   @Test
   public void should_support_db_key() {
-    when(branch.getMergeBranchUuid()).thenReturn(Optional.of(mergeBranch.uuid()));
+    when(branch.getMergeBranchUuid()).thenReturn(mergeBranch.uuid());
     assertThat(underTest.getUuid(branchFile.getDbKey())).isEqualTo(mergeBranchFile.uuid());
   }
 
   @Test
   public void should_support_key() {
-    when(branch.getMergeBranchUuid()).thenReturn(Optional.of(mergeBranch.uuid()));
+    when(branch.getMergeBranchUuid()).thenReturn(mergeBranch.uuid());
     assertThat(underTest.getUuid(branchFile.getKey())).isEqualTo(mergeBranchFile.uuid());
   }
 
   @Test
   public void return_null_if_file_doesnt_exist() {
-    when(branch.getMergeBranchUuid()).thenReturn(Optional.of(mergeBranch.uuid()));
+    when(branch.getMergeBranchUuid()).thenReturn(mergeBranch.uuid());
     assertThat(underTest.getUuid("doesnt exist")).isNull();
   }
 }
index dc73d0cb075fd5084dc9bdf8e27c57064405ba70..acb41e57fe4065a9f72a89b7f9aee41d4f5e0598 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.ce.task.projectanalysis.component;
 
-import java.util.Optional;
 import javax.annotation.Nullable;
 import org.junit.Before;
 import org.junit.Rule;
@@ -110,14 +109,14 @@ public class SiblingComponentsWithOpenIssuesTest {
     fileWithOneResolvedIssueOnLong2Short1 = db.components().insertComponent(ComponentTesting.newFileDto(long2short1, null));
     db.issues().insertIssue(IssueTesting.newIssue(rule, long2short1, fileWithOneResolvedIssueOnLong2Short1).setStatus("RESOLVED"));
 
-    setCurrentBranchUuid(long1.uuid());
+    setRoot(long1);
     underTest = new SiblingComponentsWithOpenIssues(treeRootHolder, metadataHolder, db.getDbClient());
   }
 
   @Test
   public void should_find_sibling_components_with_open_issues_for_long1() {
-    setCurrentBranchUuid(long1.uuid());
-    setReferenceBranchUuid(null);
+    setRoot(long1);
+    setBranch(BranchType.LONG);
 
     assertThat(underTest.getUuids(fileWithNoIssuesOnLong1.getKey())).isEmpty();
     assertThat(underTest.getUuids(fileWithOneOpenIssueOnLong1Short1.getKey())).containsOnly(fileWithOneOpenIssueOnLong1Short1.uuid());
@@ -132,8 +131,8 @@ public class SiblingComponentsWithOpenIssuesTest {
 
   @Test
   public void should_find_sibling_components_with_open_issues_for_short1() {
-    setCurrentBranchUuid(long1short1.uuid());
-    setReferenceBranchUuid(long1.uuid());
+    setRoot(long1short1);
+    setBranch(BranchType.SHORT, long1.uuid());
 
     assertThat(underTest.getUuids(fileWithNoIssuesOnLong1.getKey())).isEmpty();
     assertThat(underTest.getUuids(fileWithOneOpenIssueOnLong1Short1.getKey())).isEmpty();
@@ -146,8 +145,9 @@ public class SiblingComponentsWithOpenIssuesTest {
 
   @Test
   public void should_find_sibling_components_with_open_issues_for_long2() {
-    setCurrentBranchUuid(long2.uuid());
-    setReferenceBranchUuid(null);
+    setRoot(long2);
+    setBranch(BranchType.LONG);
+
     underTest = new SiblingComponentsWithOpenIssues(treeRootHolder, metadataHolder, db.getDbClient());
 
     assertThat(underTest.getUuids(fileWithOneResolvedIssueOnLong1Short1.getKey())).isEmpty();
@@ -158,8 +158,8 @@ public class SiblingComponentsWithOpenIssuesTest {
   @Test
   public void should_find_sibling_components_with_open_issues_from_short() {
     ComponentDto project = db.components().insertMainBranch();
-    setCurrentBranchUuid(project.uuid());
-    setReferenceBranchUuid(null);
+    setRoot(project);
+    setBranch(BranchType.LONG);
 
     ComponentDto branch = db.components().insertProjectBranch(project,
       b -> b.setBranchType(BranchType.SHORT),
@@ -178,8 +178,8 @@ public class SiblingComponentsWithOpenIssuesTest {
   @Test
   public void should_find_sibling_components_with_open_issues_from_pullrequest() {
     ComponentDto project = db.components().insertMainBranch();
-    setCurrentBranchUuid(project.uuid());
-    setReferenceBranchUuid(null);
+    setRoot(project);
+    setBranch(BranchType.LONG);
 
     ComponentDto pullRequest = db.components().insertProjectBranch(project,
       b -> b.setBranchType(BranchType.PULL_REQUEST),
@@ -198,8 +198,8 @@ public class SiblingComponentsWithOpenIssuesTest {
   @Test
   public void should_not_find_sibling_components_on_derived_long() {
     ComponentDto project = db.components().insertMainBranch();
-    setCurrentBranchUuid(project.uuid());
-    setReferenceBranchUuid(null);
+    setRoot(project);
+    setBranch(BranchType.LONG);
 
     ComponentDto derivedLongBranch = db.components().insertProjectBranch(project,
       b -> b.setBranchType(BranchType.LONG),
@@ -215,15 +215,20 @@ public class SiblingComponentsWithOpenIssuesTest {
     assertThat(underTest.getUuids(fileWithResolvedIssueOnDerivedLongBranch.getKey())).isEmpty();
   }
 
-  private void setCurrentBranchUuid(String uuid) {
+  private void setRoot(ComponentDto componentDto) {
     Component root = mock(Component.class);
-    when(root.getUuid()).thenReturn(uuid);
+    when(root.getUuid()).thenReturn(componentDto.uuid());
     treeRootHolder.setRoot(root);
   }
 
-  private void setReferenceBranchUuid(@Nullable String uuid) {
+  private void setBranch(BranchType currentBranchType) {
+    setBranch(currentBranchType, null);
+  }
+
+  private void setBranch(BranchType currentBranchType, @Nullable String mergeBranchUuid) {
     Branch branch = mock(Branch.class);
-    when(branch.getMergeBranchUuid()).thenReturn(Optional.ofNullable(uuid));
+    when(branch.getType()).thenReturn(currentBranchType);
+    when(branch.getMergeBranchUuid()).thenReturn(mergeBranchUuid);
     metadataHolder.setBranch(branch);
   }
 }
index e595aa04b69e2ad0e88e59e188dc25bafeb25ff5..4272c9f6981d73eae9e8bc74d3b06c1e38b6624a 100644 (file)
@@ -23,7 +23,6 @@ import java.time.Instant;
 import java.time.temporal.ChronoUnit;
 import java.util.Collections;
 import java.util.Date;
-import java.util.Optional;
 import javax.annotation.Nullable;
 import org.junit.Before;
 import org.junit.Rule;
@@ -87,9 +86,9 @@ public class SiblingsIssueMergerTest {
 
   private static final org.sonar.ce.task.projectanalysis.component.Component FILE_1 = builder(
     org.sonar.ce.task.projectanalysis.component.Component.Type.FILE, FILE_1_REF)
-      .setKey(FILE_1_KEY)
-      .setUuid(FILE_1_UUID)
-      .build();
+    .setKey(FILE_1_KEY)
+    .setUuid(FILE_1_UUID)
+    .build();
 
   private SimpleTracker<DefaultIssue, SiblingIssue> tracker = new SimpleTracker<>();
   private SiblingsIssueMerger copier;
@@ -105,11 +104,10 @@ public class SiblingsIssueMergerTest {
   @Before
   public void setUp() {
     MockitoAnnotations.initMocks(this);
-    when(branch.getMergeBranchUuid()).thenReturn(Optional.empty());
-    metadataHolder.setBranch(branch);
     DbClient dbClient = db.getDbClient();
     ComponentIssuesLoader componentIssuesLoader = new ComponentIssuesLoader(dbClient, null, null, new MapSettings().asConfig(), System2.INSTANCE);
-    copier = new SiblingsIssueMerger(new SiblingsIssuesLoader(new SiblingComponentsWithOpenIssues(treeRootHolder, metadataHolder, dbClient), dbClient, componentIssuesLoader), tracker,
+    copier = new SiblingsIssueMerger(new SiblingsIssuesLoader(new SiblingComponentsWithOpenIssues(treeRootHolder, metadataHolder, dbClient), dbClient, componentIssuesLoader),
+      tracker,
       issueLifecycle);
     projectDto = db.components().insertMainBranch(p -> p.setDbKey(PROJECT_KEY).setUuid(PROJECT_UUID));
     branch1Dto = db.components().insertProjectBranch(projectDto, b -> b.setKey("myBranch1")
@@ -125,6 +123,8 @@ public class SiblingsIssueMergerTest {
     fileOnBranch2Dto = db.components().insertComponent(newFileDto(branch2Dto).setDbKey(FILE_1_KEY + ":BRANCH:myBranch2"));
     fileOnBranch3Dto = db.components().insertComponent(newFileDto(branch3Dto).setDbKey(FILE_1_KEY + ":BRANCH:myBranch3"));
     rule = db.rules().insert();
+    when(branch.getMergeBranchUuid()).thenReturn(projectDto.uuid());
+    metadataHolder.setBranch(branch);
   }
 
   @Test
index 0e9d474ecb6259f37165435d7b531aebe919baff..159f82d34bfbb33caae995d6e9b0abd4c5692b0a 100644 (file)
@@ -93,7 +93,7 @@ public class ScmInfoDbLoaderTest {
 
     String mergeFileUuid = "mergeFileUuid";
     String hash = computeSourceHash(1);
-    when(branch.getMergeBranchUuid()).thenReturn(Optional.of("mergeBranchUuid"));
+    when(branch.getMergeBranchUuid()).thenReturn("mergeBranchUuid");
 
     when(mergeBranchComponentUuids.getUuid(FILE.getDbKey())).thenReturn(mergeFileUuid);
     addFileSourceInDb("henry", DATE_1, "rev-1", hash, mergeFileUuid);
@@ -118,7 +118,6 @@ public class ScmInfoDbLoaderTest {
   @Test
   public void do_not_read_from_db_on_first_analysis_and_no_merge_branch() {
     Branch branch = mock(Branch.class);
-    when(branch.getMergeBranchUuid()).thenReturn(Optional.empty());
     analysisMetadataHolder.setBaseAnalysis(null);
     analysisMetadataHolder.setBranch(branch);
 
index a1ad8c75e3d0480d2eaf2be0eb29b7e102e5ed08..2d219d0825cf0bf5774070de67d1106031aa66a8 100644 (file)
@@ -25,7 +25,6 @@ import com.tngtech.java.junit.dataprovider.UseDataProvider;
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.Date;
-import java.util.Optional;
 import java.util.Random;
 import java.util.stream.Stream;
 import javax.annotation.Nullable;
@@ -447,7 +446,7 @@ public class LoadPeriodsStepTest extends BaseStepTest {
       }
 
       @Override
-      public Optional<String> getMergeBranchUuid() {
+      public String getMergeBranchUuid() {
         throw new UnsupportedOperationException("getMergeBranchUuid not implemented");
       }
 
@@ -461,6 +460,11 @@ public class LoadPeriodsStepTest extends BaseStepTest {
         throw new UnsupportedOperationException("getPullRequestKey not implemented");
       }
 
+      @Override
+      public String getTargetBranchName() {
+        throw new UnsupportedOperationException();
+      }
+
       @Override
       public String generateKey(String projectKey, @Nullable String fileOrDirPath) {
         throw new UnsupportedOperationException("generateKey not implemented");
index 605a3005bd6f24b9f47da9a851ece9d0e5698484..d19eb51ad1436c54ce5dbafeb211862d73e97504 100644 (file)
@@ -671,8 +671,8 @@ public class ReportPersistComponentsStepTest extends BaseStepTest {
     }
 
     @Override
-    public java.util.Optional<String> getMergeBranchUuid() {
-      return java.util.Optional.empty();
+    public String getMergeBranchUuid() {
+      throw new UnsupportedOperationException();
     }
 
     @Override
@@ -695,6 +695,11 @@ public class ReportPersistComponentsStepTest extends BaseStepTest {
       throw new UnsupportedOperationException();
     }
 
+    @Override
+    public String getTargetBranchName() {
+      throw new UnsupportedOperationException();
+    }
+
     @Override
     public String generateKey(String projectKey, @Nullable String fileOrDirPath) {
       if (isEmpty(fileOrDirPath)) {
index ccfc54e67087bdf6b51658bc6cd86f844adb16fe..05e3136e39f01164cd0f6e08f1673ef9fa4ef5cb 100644 (file)
@@ -20,7 +20,6 @@
 package org.sonar.ce.task.projectanalysis.step;
 
 import java.util.Date;
-import java.util.Optional;
 import javax.annotation.Nullable;
 import org.junit.Rule;
 import org.junit.Test;
@@ -129,11 +128,10 @@ public class ValidateProjectStepTest {
     underTest.execute(new TestComputationStepContext());
   }
 
-
   private void setBranch(BranchType type, @Nullable String mergeBranchUuid) {
     Branch branch = mock(Branch.class);
     when(branch.getType()).thenReturn(type);
-    when(branch.getMergeBranchUuid()).thenReturn(Optional.ofNullable(mergeBranchUuid));
+    when(branch.getMergeBranchUuid()).thenReturn(mergeBranchUuid);
     analysisMetadataHolder.setBranch(branch);
   }
 
index d065136abab6e36b72919123f1efc380aefb12a2..7914cec53e648dfe57ef1a3901b04b1fd30da1e3 100644 (file)
@@ -364,6 +364,10 @@ public class ComponentDao implements Dao {
     return mapper(dbSession).selectProjectsByNameQuery(nameQueryForSql, includeModules);
   }
 
+  /**
+   * Returns components with open issues from branches that use a certain long living branch as reference (merge branch).
+   * Excludes components from the current branch.
+   */
   public List<KeyWithUuidDto> selectAllSiblingComponentKeysHavingOpenIssues(DbSession dbSession, String referenceBranchUuid, String currentBranchUuid) {
     return mapper(dbSession).selectAllSiblingComponentKeysHavingOpenIssues(referenceBranchUuid, currentBranchUuid);
   }
index ac6f5047f4a0fd65016b9f79aa8dcd9b2bf3bcb1..f3d5fcd49f05fa8390094f83c6f179805f4abeb1 100644 (file)
@@ -35,4 +35,6 @@ message PullRequestData {
   string url = 3;
 
   map<string, string> attributes = 4;
+
+  string target = 5;
 }
index 281ba36202dbb3198704cd5481c3adb9f9b2da6e..4ee21954cdbb18c7f660c249035bd49cfa0176b1 100644 (file)
@@ -25,6 +25,7 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Function;
 import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
@@ -150,6 +151,13 @@ public class ListAction implements PullRequestWsAction {
     } else {
       builder.setIsOrphan(true);
     }
+
+    if (StringUtils.isNotEmpty(pullRequestData.getTarget())) {
+      builder.setTarget(pullRequestData.getTarget());
+    } else if (mergeBranch.isPresent()) {
+      builder.setTarget(mergeBranch.get().getKey());
+    }
+
     ofNullable(analysisDate).ifPresent(builder::setAnalysisDate);
     setQualityGate(builder, qualityGateMeasure, branchStatistics);
     response.addPullRequests(builder);
index 4fef887dc826e610ec42367287ac1dc4bdea1222..877d25c17efab4f038ffeb2096f05e50a166dff8 100644 (file)
@@ -12,7 +12,8 @@
         "codeSmells": 0
       },
       "analysisDate": "2017-04-01T02:15:42+0200",
-      "url": "https://github.com/SonarSource/sonar-core-plugins/pull/32"
+      "url": "https://github.com/SonarSource/sonar-core-plugins/pull/32",
+      "target": "feature/foo"
     }
   ]
 }
index 6317707f6f82405bd6e725db6a4956576146589e..d6c17571facc10f8548a712d8981aea6ed282056 100644 (file)
@@ -22,6 +22,10 @@ package org.sonar.api.batch.fs.internal;
 import javax.annotation.Nullable;
 import org.sonar.api.batch.fs.InputFile;
 
+@Deprecated
+/**
+ * @deprecated since 7.8
+ */
 public class StatusPredicate extends AbstractFilePredicate {
 
   private final InputFile.Status status;
index 8bc978109b67b63d7260e599a31a4345df372b73..ff393c42773f8fce249ddb73dae99ab7eeadfc54 100644 (file)
@@ -57,8 +57,8 @@ public class ChangedLinesPublisher implements ReportPublisherStep {
 
   @Override
   public void publish(ScannerReportWriter writer) {
-    String targetScmBranch = branchConfiguration.targetScmBranch();
-    if (scmConfiguration.isDisabled() || !branchConfiguration.isShortOrPullRequest() || targetScmBranch == null) {
+    String targetBranchName = branchConfiguration.targetBranchName();
+    if (scmConfiguration.isDisabled() || !branchConfiguration.isShortOrPullRequest() || targetBranchName == null) {
       return;
     }
 
@@ -68,7 +68,7 @@ public class ChangedLinesPublisher implements ReportPublisherStep {
     }
 
     Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
-    int count = writeChangedLines(provider, writer, targetScmBranch);
+    int count = writeChangedLines(provider, writer, targetBranchName);
     LOG.debug("SCM reported changed lines for {} {} in the branch", count, ScannerUtils.pluralize("file", count));
     profiler.stopInfo();
   }
index 69891747295eba28533a91e8fd792e2cde7a3080..9bf40f4a94e6ac6a65cd5f0dea8063648bd19660 100644 (file)
@@ -160,6 +160,10 @@ public class MetadataPublisher implements ReportPublisherStep {
     if (referenceBranch != null) {
       builder.setMergeBranchName(referenceBranch);
     }
+    String targetBranchName = branchConfiguration.targetBranchName();
+    if (targetBranchName != null) {
+      builder.setTargetBranchName(targetBranchName);
+    }
     if (branchType == BranchType.PULL_REQUEST) {
       builder.setPullRequestKey(branchConfiguration.pullRequestKey());
     }
index 6c3c2f93da242324d7caaa08b59cdf2f1876350b..361eeab3e6d1629c2c8103b41b5174f0539d4f8e 100644 (file)
@@ -50,24 +50,27 @@ public class DefaultQualityProfileLoader implements QualityProfileLoader {
     this.wsClient = wsClient;
   }
 
-  @Override
-  public List<QualityProfile> loadDefault() {
+  private List<QualityProfile> loadDefault() {
     StringBuilder url = new StringBuilder(WS_URL + "?defaults=true");
-    return handleErrors(url, () -> "Failed to load the default quality profiles");
+    return handleErrors(url, () -> "Failed to load the default quality profiles", false);
   }
 
   @Override
   public List<QualityProfile> load(String projectKey) {
     StringBuilder url = new StringBuilder(WS_URL + "?projectKey=").append(encodeForUrl(projectKey));
-    return handleErrors(url, () -> String.format("Failed to load the quality profiles of project '%s'", projectKey));
+    return handleErrors(url, () -> String.format("Failed to load the quality profiles of project '%s'", projectKey), true);
   }
 
-  private List<QualityProfile> handleErrors(StringBuilder url, Supplier<String> errorMsg) {
+  private List<QualityProfile> handleErrors(StringBuilder url, Supplier<String> errorMsg, boolean tryLoadDefault) {
     try {
       return doLoad(url);
     } catch (HttpException e) {
       if (e.code() == 404) {
-        throw MessageException.of(errorMsg.get() + ": " + ScannerWsClient.createErrorMessage(e));
+        if (tryLoadDefault) {
+          return loadDefault();
+        } else {
+          throw MessageException.of(errorMsg.get() + ": " + ScannerWsClient.createErrorMessage(e));
+        }
       }
       throw new IllegalStateException(errorMsg.get() + ": " + ScannerWsClient.createErrorMessage(e));
     } catch (MessageException e) {
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositoriesProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositoriesProvider.java
deleted file mode 100644 (file)
index d2f7bfe..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.repository;
-
-import org.picocontainer.injectors.ProviderAdapter;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.api.utils.log.Profiler;
-import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
-import org.sonar.scanner.scan.branch.BranchConfiguration;
-
-public class ProjectRepositoriesProvider extends ProviderAdapter {
-  private static final Logger LOG = Loggers.get(ProjectRepositoriesProvider.class);
-  private static final String LOG_MSG = "Load project repositories";
-  private ProjectRepositories project = null;
-
-  public ProjectRepositories provide(ProjectRepositoriesLoader loader, ProcessedScannerProperties scannerProperties, BranchConfiguration branchConfig) {
-    if (project == null) {
-      Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
-      project = loader.load(scannerProperties.getKeyWithBranch(), branchConfig.longLivingSonarReferenceBranch());
-      profiler.stopInfo();
-    }
-
-    return project;
-  }
-}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositoriesSupplier.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositoriesSupplier.java
new file mode 100644 (file)
index 0000000..f0fda87
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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.repository;
+
+import java.util.function.Supplier;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.api.utils.log.Profiler;
+import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
+import org.sonar.scanner.scan.branch.BranchConfiguration;
+
+public class ProjectRepositoriesSupplier implements Supplier<ProjectRepositories> {
+  private static final Logger LOG = Loggers.get(ProjectRepositoriesSupplier.class);
+  private static final String LOG_MSG = "Load project repositories";
+  private final ProjectRepositoriesLoader loader;
+  private final ProcessedScannerProperties scannerProperties;
+  private final BranchConfiguration branchConfig;
+
+  private ProjectRepositories project = null;
+
+  public ProjectRepositoriesSupplier(ProjectRepositoriesLoader loader, ProcessedScannerProperties scannerProperties, BranchConfiguration branchConfig) {
+    this.loader = loader;
+    this.scannerProperties = scannerProperties;
+    this.branchConfig = branchConfig;
+  }
+
+  public ProjectRepositories get() {
+    if (project == null) {
+      Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
+      project = loader.load(scannerProperties.getKeyWithBranch(), branchConfig.longLivingSonarReferenceBranch());
+      profiler.stopInfo();
+    }
+
+    return project;
+  }
+}
index 202cc6389e1d33258ac1a8a52bf01b6ab8241108..df17a1f2247e350965067feda7a0387ee23b1739 100644 (file)
@@ -24,6 +24,4 @@ import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
 
 public interface QualityProfileLoader {
   List<QualityProfile> load(String projectKey);
-
-  List<QualityProfile> loadDefault();
 }
index 267d0c0172976bd31e86cadcc4467ddf3d4dbf95..e78e4d7457fbb8426702cacaab6b6f96554f4abd 100644 (file)
  */
 package org.sonar.scanner.repository;
 
-import java.util.List;
 import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
 import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
 import org.sonar.scanner.rule.QualityProfiles;
-import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
 
 public class QualityProfilesProvider extends ProviderAdapter {
   private static final Logger LOG = Loggers.get(QualityProfilesProvider.class);
   private static final String LOG_MSG = "Load quality profiles";
   private QualityProfiles profiles = null;
 
-  public QualityProfiles provide(QualityProfileLoader loader, ProjectRepositories projectRepositories, ProcessedScannerProperties props) {
+  public QualityProfiles provide(QualityProfileLoader loader, ProcessedScannerProperties props) {
     if (this.profiles == null) {
-      List<QualityProfile> profileList;
       Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
-      if (!projectRepositories.exists()) {
-        profileList = loader.loadDefault();
-      } else {
-        profileList = loader.load(props.getKeyWithBranch());
-      }
+      profiles = new QualityProfiles(loader.load(props.getKeyWithBranch()));
       profiler.stopInfo();
-      profiles = new QualityProfiles(profileList);
     }
 
     return profiles;
index dc242a2b4bd448c59cbdbaf0afb6e22ffca6c43f..548a477c7d0543a1d77f96d93dea294faa80eddd 100644 (file)
@@ -77,7 +77,7 @@ import org.sonar.scanner.repository.ContextPropertiesCache;
 import org.sonar.scanner.repository.DefaultProjectRepositoriesLoader;
 import org.sonar.scanner.repository.DefaultQualityProfileLoader;
 import org.sonar.scanner.repository.ProjectRepositoriesLoader;
-import org.sonar.scanner.repository.ProjectRepositoriesProvider;
+import org.sonar.scanner.repository.ProjectRepositoriesSupplier;
 import org.sonar.scanner.repository.QualityProfileLoader;
 import org.sonar.scanner.repository.QualityProfilesProvider;
 import org.sonar.scanner.repository.language.DefaultLanguagesRepository;
@@ -157,7 +157,7 @@ public class ProjectScanContainer extends ComponentContainer {
       new ProjectBranchesProvider(),
       new ProjectPullRequestsProvider(),
       DefaultAnalysisMode.class,
-      new ProjectRepositoriesProvider(),
+      ProjectRepositoriesSupplier.class,
       new ProjectServerSettingsProvider(),
 
       // temp
@@ -304,7 +304,7 @@ public class ProjectScanContainer extends ComponentContainer {
 
     BranchConfiguration branchConfig = getComponentByType(BranchConfiguration.class);
     if (branchConfig.branchType() == BranchType.PULL_REQUEST) {
-      LOG.info("Pull request {} for merge into {} from {}", branchConfig.pullRequestKey(), pullRequestBaseToDisplayName(branchConfig.targetScmBranch()), branchConfig.branchName());
+      LOG.info("Pull request {} for merge into {} from {}", branchConfig.pullRequestKey(), pullRequestBaseToDisplayName(branchConfig.targetBranchName()), branchConfig.branchName());
     } else if (branchConfig.branchName() != null) {
       LOG.info("Branch name: {}, type: {}", branchConfig.branchName(), branchTypeToDisplayName(branchConfig.branchType()));
     }
index 87dedb54d11f675e87bf1994d6235d045805f14a..d3f51049c0d0d42489e20d3b9f344dd811340281 100644 (file)
@@ -27,7 +27,6 @@ public interface BranchConfiguration {
 
   /**
    * The type of the branch we're on, determined by:
-   *
    * - If the specified branch exists on the server, then its type
    * - If the branch name matches the pattern of long-lived branches, then it's long-lived
    * - Otherwise it's short-lived
@@ -43,7 +42,8 @@ public interface BranchConfiguration {
   /**
    * For long/short living branches, this is the value of sonar.branch.name, and fallback on the default branch name configured in SQ
    * For PR: the name of the branch containing PR changes (sonar.pullrequest.branch)
-   * Only @null if the branch feature is not available.
+   *
+   * @return null if the branch feature is not available or no branch was specified.
    */
   @CheckForNull
   String branchName();
@@ -56,17 +56,20 @@ public interface BranchConfiguration {
    * transitively use its own target.
    * For PR, we look at sonar.pullrequest.base (default to default branch). If it exists but is a short living branch or PR, we will
    * transitively use its own target. If base is not analyzed, we will use default branch.
-   * Only @null if the branch feature is not available.
+   *
+   * @return null if the branch feature is not available or no branch was specified.
    */
   @CheckForNull
   String longLivingSonarReferenceBranch();
 
   /**
-   * Raw value of sonar.branch.target or sonar.pullrequest.base (fallback to the default branch), will be used by the SCM to compute changed files and changed lines.
-   * @null for long living branches and if the branch feature is not available
+   * Raw value of sonar.branch.target or sonar.pullrequest.base (fallback to the default branch).
+   * In the scanner side, it will be used by the SCM to compute changed files and changed lines.
+   *
+   * @return null if the branch feature is not available, the branch being analyzed is the main branch or no branch was specified.
    */
   @CheckForNull
-  String targetScmBranch();
+  String targetBranchName();
 
   /**
    * The key of the pull request.
index 436afec909ed5f5583d56ab76bac272ad24364ba..7314597a8283989aa0619e10c75d8d02da2c749c 100644 (file)
@@ -37,7 +37,7 @@ public class DefaultBranchConfiguration implements BranchConfiguration {
 
   @CheckForNull
   @Override
-  public String targetScmBranch() {
+  public String targetBranchName() {
     return null;
   }
 
index 8f33e02ea2cb16e8a9599957a8c1d54fb2e47402..09561999935295f3218abfcbce6b9434fcf4483f 100644 (file)
@@ -24,7 +24,7 @@ import org.apache.commons.lang.StringUtils;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.scanner.repository.FileData;
-import org.sonar.scanner.repository.ProjectRepositories;
+import org.sonar.scanner.repository.ProjectRepositoriesSupplier;
 import org.sonar.scanner.scm.ScmChangedFiles;
 
 import static org.sonar.api.batch.fs.InputFile.Status.ADDED;
@@ -33,33 +33,40 @@ import static org.sonar.api.batch.fs.InputFile.Status.SAME;
 
 @Immutable
 public class StatusDetection {
-  private final ProjectRepositories projectRepositories;
+  private final ProjectRepositoriesSupplier projectSettingsSupplier;
   private final ScmChangedFiles scmChangedFiles;
 
-  public StatusDetection(ProjectRepositories projectSettings, ScmChangedFiles scmChangedFiles) {
-    this.projectRepositories = projectSettings;
+  public StatusDetection(ProjectRepositoriesSupplier projectSettingsSupplier, ScmChangedFiles scmChangedFiles) {
+    this.projectSettingsSupplier = projectSettingsSupplier;
     this.scmChangedFiles = scmChangedFiles;
   }
 
   InputFile.Status status(String moduleKeyWithBranch, DefaultInputFile inputFile, String hash) {
-    FileData fileDataPerPath = projectRepositories.fileData(moduleKeyWithBranch, inputFile);
+    if (scmChangedFiles.isValid()) {
+      return checkChangedWithScm(inputFile);
+    }
+    return checkChangedWithProjectRepositories(moduleKeyWithBranch, inputFile, hash);
+  }
+
+  private InputFile.Status checkChangedWithProjectRepositories(String moduleKeyWithBranch, DefaultInputFile inputFile, String hash) {
+    FileData fileDataPerPath = projectSettingsSupplier.get().fileData(moduleKeyWithBranch, inputFile);
     if (fileDataPerPath == null) {
-      return checkChanged(ADDED, inputFile);
+      return ADDED;
     }
     String previousHash = fileDataPerPath.hash();
     if (StringUtils.equals(hash, previousHash)) {
       return SAME;
     }
     if (StringUtils.isEmpty(previousHash)) {
-      return checkChanged(ADDED, inputFile);
+      return ADDED;
     }
-    return checkChanged(CHANGED, inputFile);
+    return CHANGED;
   }
 
-  private InputFile.Status checkChanged(InputFile.Status status, DefaultInputFile inputFile) {
-    if (!scmChangedFiles.verifyChanged(inputFile.path())) {
+  private InputFile.Status checkChangedWithScm(DefaultInputFile inputFile) {
+    if (!scmChangedFiles.isChanged(inputFile.path())) {
       return SAME;
     }
-    return status;
+    return CHANGED;
   }
 }
index dfb078ecccb535cd68dbb2155ab00464cab35ab3..380c65c32a2d87350eeaabb19a9d933e8acceac5 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.scanner.scm;
 
 import java.nio.file.Path;
 import java.util.Collection;
+import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.Immutable;
 
@@ -33,10 +34,19 @@ public class ScmChangedFiles {
     this.fileCollection = changedFiles;
   }
 
-  public boolean verifyChanged(Path file) {
-    return fileCollection == null || fileCollection.contains(file);
+  public boolean isChanged(Path file) {
+    if (!isValid()) {
+      throw new IllegalStateException("Scm didn't provide valid data");
+    }
+
+    return fileCollection.contains(file);
+  }
+
+  public boolean isValid() {
+    return fileCollection != null;
   }
 
+  @CheckForNull
   Collection<Path> get() {
     return fileCollection;
   }
index 63f30c85f2c70b760694b72e225aa230f19d73e4..b7fd4c8bf76c112dfbae388449f20702d86e02ec 100644 (file)
@@ -22,7 +22,6 @@ package org.sonar.scanner.scm;
 import java.nio.file.Path;
 import java.util.Collection;
 import javax.annotation.CheckForNull;
-import org.picocontainer.annotations.Nullable;
 import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.batch.fs.internal.DefaultInputProject;
 import org.sonar.api.batch.scm.ScmProvider;
@@ -38,19 +37,12 @@ public class ScmChangedFilesProvider extends ProviderAdapter {
 
   private ScmChangedFiles scmBranchChangedFiles;
 
-  /*
-   * ScmConfiguration is not available in issues mode
-   */
-  public ScmChangedFiles provide(@Nullable ScmConfiguration scmConfiguration, BranchConfiguration branchConfiguration, DefaultInputProject project) {
+  public ScmChangedFiles provide(ScmConfiguration scmConfiguration, BranchConfiguration branchConfiguration, DefaultInputProject project) {
     if (scmBranchChangedFiles == null) {
-      if (scmConfiguration == null) {
-        scmBranchChangedFiles = new ScmChangedFiles(null);
-      } else {
-        Path rootBaseDir = project.getBaseDir();
-        Collection<Path> changedFiles = loadChangedFilesIfNeeded(scmConfiguration, branchConfiguration, rootBaseDir);
-        validatePaths(changedFiles);
-        scmBranchChangedFiles = new ScmChangedFiles(changedFiles);
-      }
+      Path rootBaseDir = project.getBaseDir();
+      Collection<Path> changedFiles = loadChangedFilesIfNeeded(scmConfiguration, branchConfiguration, rootBaseDir);
+      validatePaths(changedFiles);
+      scmBranchChangedFiles = new ScmChangedFiles(changedFiles);
     }
     return scmBranchChangedFiles;
   }
@@ -63,12 +55,12 @@ public class ScmChangedFilesProvider extends ProviderAdapter {
 
   @CheckForNull
   private static Collection<Path> loadChangedFilesIfNeeded(ScmConfiguration scmConfiguration, BranchConfiguration branchConfiguration, Path rootBaseDir) {
-    String targetScmBranch = branchConfiguration.targetScmBranch();
-    if (branchConfiguration.isShortOrPullRequest() && targetScmBranch != null) {
+    final String targetBranchName = branchConfiguration.targetBranchName();
+    if (branchConfiguration.isShortOrPullRequest() && targetBranchName != null) {
       ScmProvider scmProvider = scmConfiguration.provider();
       if (scmProvider != null) {
         Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
-        Collection<Path> changedFiles = scmProvider.branchChangedFiles(targetScmBranch, rootBaseDir);
+        Collection<Path> changedFiles = scmProvider.branchChangedFiles(targetBranchName, rootBaseDir);
         profiler.stopInfo();
         if (changedFiles != null) {
           LOG.debug("SCM reported {} {} changed in the branch", changedFiles.size(), ScannerUtils.pluralize("file", changedFiles.size()));
index 4abb86427d5c238e779e324547bdc1903d300ddf..819abc8adcec209130d8d4c6280cf105b88202fb 100644 (file)
@@ -35,7 +35,7 @@ import org.sonar.scanner.protocol.output.ScannerReport.Changesets.Builder;
 import org.sonar.scanner.protocol.output.ScannerReportWriter;
 import org.sonar.scanner.report.ReportPublisher;
 import org.sonar.scanner.repository.FileData;
-import org.sonar.scanner.repository.ProjectRepositories;
+import org.sonar.scanner.repository.ProjectRepositoriesSupplier;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
 import org.sonar.scanner.scan.filesystem.InputComponentStore;
 
@@ -44,16 +44,16 @@ public final class ScmPublisher {
   private static final Logger LOG = Loggers.get(ScmPublisher.class);
 
   private final ScmConfiguration configuration;
-  private final ProjectRepositories projectRepositories;
+  private final ProjectRepositoriesSupplier projectRepositoriesSupplier;
   private final InputComponentStore componentStore;
   private final FileSystem fs;
   private final ScannerReportWriter writer;
   private final BranchConfiguration branchConfiguration;
 
-  public ScmPublisher(ScmConfiguration configuration, ProjectRepositories projectRepositories,
-                      InputComponentStore componentStore, FileSystem fs, ReportPublisher reportPublisher, BranchConfiguration branchConfiguration) {
+  public ScmPublisher(ScmConfiguration configuration, ProjectRepositoriesSupplier projectRepositoriesSupplier,
+    InputComponentStore componentStore, FileSystem fs, ReportPublisher reportPublisher, BranchConfiguration branchConfiguration) {
     this.configuration = configuration;
-    this.projectRepositories = projectRepositories;
+    this.projectRepositoriesSupplier = projectRepositoriesSupplier;
     this.componentStore = componentStore;
     this.fs = fs;
     this.branchConfiguration = branchConfiguration;
@@ -96,12 +96,11 @@ public final class ScmPublisher {
       if (configuration.forceReloadAll() || f.status() != Status.SAME) {
         addIfNotEmpty(filesToBlame, f);
       } else if (!branchConfiguration.isShortOrPullRequest()) {
-        // File status is SAME so that mean fileData exists
-        FileData fileData = projectRepositories.fileData(componentStore.findModule(f).getKeyWithBranch(), f);
-        if (StringUtils.isEmpty(fileData.revision())) {
+        FileData fileData = projectRepositoriesSupplier.get().fileData(componentStore.findModule(f).getKeyWithBranch(), f);
+        if (fileData == null || StringUtils.isEmpty(fileData.revision())) {
           addIfNotEmpty(filesToBlame, f);
         } else {
-          askToCopyDataFromPreviousAnalysis((DefaultInputFile) f, writer);
+          askToCopyDataFromPreviousAnalysis(f, writer);
         }
       }
     }
index 49df27855675d96cd94efe4718e178bbb961343c..28cb9ba3ed8b79b6cecf2753f74d3f50f4ccef22 100644 (file)
@@ -74,7 +74,6 @@ import org.sonarqube.ws.Rules.ListResponse.Rule;
 
 /**
  * Main utility class for writing scanner medium tests.
- * 
  */
 public class ScannerMediumTester extends ExternalResource {
 
@@ -389,7 +388,7 @@ public class ScannerMediumTester extends ExternalResource {
 
     @CheckForNull
     @Override
-    public String targetScmBranch() {
+    public String targetBranchName() {
       return branchTarget;
     }
 
@@ -449,11 +448,6 @@ public class ScannerMediumTester extends ExternalResource {
     public List<QualityProfile> load(String projectKey) {
       return qualityProfiles;
     }
-
-    @Override
-    public List<QualityProfile> loadDefault() {
-      return qualityProfiles;
-    }
   }
 
   private static class FakeGlobalSettingsLoader implements GlobalSettingsLoader {
index b45964ecad6bcbc0f63e13326d3b8ad7a98902ce..2d155cea75600004294d38415990d07279affa21 100644 (file)
@@ -69,7 +69,7 @@ public class ChangedLinesPublisherTest {
     when(branchConfiguration.isShortOrPullRequest()).thenReturn(true);
     when(scmConfiguration.isDisabled()).thenReturn(false);
     when(scmConfiguration.provider()).thenReturn(provider);
-    when(branchConfiguration.targetScmBranch()).thenReturn(TARGET_BRANCH);
+    when(branchConfiguration.targetBranchName()).thenReturn(TARGET_BRANCH);
     when(project.getBaseDir()).thenReturn(BASE_DIR);
   }
 
@@ -91,7 +91,7 @@ public class ChangedLinesPublisherTest {
 
   @Test
   public void skip_if_target_branch_is_null() {
-    when(branchConfiguration.targetScmBranch()).thenReturn(null);
+    when(branchConfiguration.targetBranchName()).thenReturn(null);
     publisher.publish(writer);
     verifyZeroInteractions(inputComponentStore, inputModuleHierarchy, provider);
     assertNotPublished();
index f7df36536d944c951d11d3e8d993f033266d91ec..2c90a1a8eed3f07624fe26b5536fe62c1a9c05a5 100644 (file)
@@ -260,9 +260,11 @@ public class MetadataPublisherTest {
   @Test
   public void write_short_lived_branch_info() throws Exception {
     String branchName = "feature";
-    String branchTarget = "short-lived";
+    String targetBranchName = "short-lived";
+    String longLivingSonarReferenceBranch = "long-lived";
     when(branches.branchName()).thenReturn(branchName);
-    when(branches.longLivingSonarReferenceBranch()).thenReturn(branchTarget);
+    when(branches.targetBranchName()).thenReturn(targetBranchName);
+    when(branches.longLivingSonarReferenceBranch()).thenReturn(longLivingSonarReferenceBranch);
 
     File outputDir = temp.newFolder();
     underTest.publish(new ScannerReportWriter(outputDir));
@@ -271,7 +273,8 @@ public class MetadataPublisherTest {
     ScannerReport.Metadata metadata = reader.readMetadata();
     assertThat(metadata.getBranchName()).isEqualTo(branchName);
     assertThat(metadata.getBranchType()).isEqualTo(ScannerReport.Metadata.BranchType.SHORT);
-    assertThat(metadata.getMergeBranchName()).isEqualTo(branchTarget);
+    assertThat(metadata.getMergeBranchName()).isEqualTo(longLivingSonarReferenceBranch);
+    assertThat(metadata.getTargetBranchName()).isEqualTo(targetBranchName);
   }
 
   @Test
index 757bd52ab3a1ccf683d5d619bf3e473912ba7df3..95e38e4520eb670602c3c9f47809e20f9336e0c4 100644 (file)
@@ -70,17 +70,27 @@ public class DefaultQualityProfileLoaderTest {
   }
 
   @Test
-  public void loadDefault_gets_all_default_profiles() throws IOException {
-    prepareCallWithResults();
-    underTest.loadDefault();
+  public void load_tries_default_if_no_profiles_found_for_project() throws IOException {
+    HttpException e = new HttpException("", 404, "{\"errors\":[{\"msg\":\"No project found with key 'foo'\"}]}");
+    WsTestUtil.mockException(wsClient, "/api/qualityprofiles/search.protobuf?projectKey=foo", e);
+    WsTestUtil.mockStream(wsClient, "/api/qualityprofiles/search.protobuf?defaults=true", createStreamOfProfiles("qp"));
+
+    underTest.load("foo");
+
+    verifyCalledPath("/api/qualityprofiles/search.protobuf?projectKey=foo");
     verifyCalledPath("/api/qualityprofiles/search.protobuf?defaults=true");
   }
 
   @Test
   public void loadDefault_sets_organization_parameter_if_defined_in_settings() throws IOException {
     when(properties.organizationKey()).thenReturn(Optional.of("my-org"));
+
+    HttpException e = new HttpException("", 404, "{\"errors\":[{\"msg\":\"No organization with key 'myorg'\"}]}");
+    WsTestUtil.mockException(wsClient, "/api/qualityprofiles/search.protobuf?projectKey=foo&organization=my-org", e);
     WsTestUtil.mockStream(wsClient, "/api/qualityprofiles/search.protobuf?defaults=true&organization=my-org", createStreamOfProfiles("qp"));
-    underTest.loadDefault();
+
+    underTest.load("foo");
+
     verifyCalledPath("/api/qualityprofiles/search.protobuf?defaults=true&organization=my-org");
   }
 
@@ -96,12 +106,12 @@ public class DefaultQualityProfileLoaderTest {
   }
 
   @Test
-  public void load_throws_MessageException_if_organization_is_not_found() throws IOException {
+  public void load_throws_MessageException_if_organization_is_not_found_after_trying_default() throws IOException {
     HttpException e = new HttpException("", 404, "{\"errors\":[{\"msg\":\"No organization with key 'myorg'\"}]}");
     WsTestUtil.mockException(wsClient, e);
 
     exception.expect(MessageException.class);
-    exception.expectMessage("Failed to load the quality profiles of project 'project': No organization with key 'myorg'");
+    exception.expectMessage("Failed to load the default quality profiles: No organization with key 'myorg'");
 
     underTest.load("project");
     verifyNoMoreInteractions(wsClient);
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/ProjectRepositoriesProviderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/ProjectRepositoriesProviderTest.java
deleted file mode 100644 (file)
index 2fb5056..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.repository;
-
-import com.google.common.collect.Maps;
-import java.util.Map;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
-import org.sonar.scanner.scan.branch.BranchConfiguration;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-public class ProjectRepositoriesProviderTest {
-  private ProjectRepositoriesProvider provider;
-  private ProjectRepositories project;
-
-  @Mock
-  private ProjectRepositoriesLoader loader;
-  @Mock
-  private ProcessedScannerProperties props;
-  @Mock
-  private BranchConfiguration branchConfiguration;
-
-  @Before
-  public void setUp() {
-    MockitoAnnotations.initMocks(this);
-
-    Map<String, FileData> fileMap = Maps.newHashMap();
-
-    project = new SingleProjectRepository(fileMap);
-    provider = new ProjectRepositoriesProvider();
-
-    when(props.getKeyWithBranch()).thenReturn("key");
-  }
-
-  @Test
-  public void testValidation() {
-    when(loader.load(eq("key"), any())).thenReturn(project);
-
-    provider.provide(loader, props, branchConfiguration);
-  }
-
-  @Test
-  public void testAssociated() {
-    when(loader.load(eq("key"), any())).thenReturn(project);
-
-    ProjectRepositories repo = provider.provide(loader, props, branchConfiguration);
-
-    assertThat(repo.exists()).isEqualTo(true);
-
-    verify(props).getKeyWithBranch();
-    verify(loader).load(eq("key"), eq(null));
-    verifyNoMoreInteractions(loader, props);
-  }
-}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/ProjectRepositoriesSupplierTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/ProjectRepositoriesSupplierTest.java
new file mode 100644 (file)
index 0000000..72c58dc
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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.repository;
+
+import com.google.common.collect.Maps;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
+import org.sonar.scanner.scan.branch.BranchConfiguration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+public class ProjectRepositoriesSupplierTest {
+  private ProjectRepositoriesSupplier underTest;
+  private ProjectRepositories project;
+
+  private ProjectRepositoriesLoader loader = mock(ProjectRepositoriesLoader.class);
+  private ProcessedScannerProperties props = mock(ProcessedScannerProperties.class);
+  private BranchConfiguration branchConfiguration = mock(BranchConfiguration.class);
+
+  @Before
+  public void setUp() {
+    underTest = new ProjectRepositoriesSupplier(loader, props, branchConfiguration);
+    Map<String, FileData> fileMap = Maps.newHashMap();
+    project = new SingleProjectRepository(fileMap);
+    when(props.getKeyWithBranch()).thenReturn("key");
+  }
+
+  @Test
+  public void testValidation() {
+    when(loader.load(eq("key"), any())).thenReturn(project);
+    underTest.get();
+  }
+
+  @Test
+  public void testAssociated() {
+    when(loader.load(eq("key"), any())).thenReturn(project);
+    ProjectRepositories repo = underTest.get();
+
+    assertThat(repo.exists()).isEqualTo(true);
+
+    verify(props).getKeyWithBranch();
+    verify(loader).load(eq("key"), eq(null));
+    verifyNoMoreInteractions(loader, props);
+  }
+}
index a318a6e9b5964e46bf43cef2da5d120fb60e178e..94bc1b6f10c7c3dd3cdda2b75d7263ac44d3f53d 100644 (file)
  */
 package org.sonar.scanner.repository;
 
-import com.google.common.collect.ImmutableMap;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 import org.sonar.api.utils.DateUtils;
 import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
 import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
 import org.sonar.scanner.rule.QualityProfiles;
 import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
@@ -49,22 +45,16 @@ public class QualityProfileProviderTest {
 
   private QualityProfilesProvider qualityProfileProvider;
 
-  @Mock
-  private QualityProfileLoader loader;
-  @Mock
-  private ProcessedScannerProperties props;
-  @Mock
-  private ProjectRepositories projectRepo;
+  private QualityProfileLoader loader = mock(QualityProfileLoader.class);
+  private ProcessedScannerProperties props = mock(ProcessedScannerProperties.class);
 
   private List<QualityProfile> response;
 
   @Before
   public void setUp() {
-    MockitoAnnotations.initMocks(this);
     qualityProfileProvider = new QualityProfilesProvider();
 
     when(props.getKeyWithBranch()).thenReturn("project");
-    when(projectRepo.exists()).thenReturn(true);
 
     response = new ArrayList<>(1);
     response.add(QualityProfile.newBuilder().setKey("profile").setName("profile").setLanguage("lang").setRulesUpdatedAt(DateUtils.formatDateTime(new Date())).build());
@@ -73,47 +63,24 @@ public class QualityProfileProviderTest {
   @Test
   public void testProvide() {
     when(loader.load("project")).thenReturn(response);
-    QualityProfiles qps = qualityProfileProvider.provide(loader, projectRepo, props);
+    QualityProfiles qps = qualityProfileProvider.provide(loader, props);
     assertResponse(qps);
 
     verify(loader).load("project");
     verifyNoMoreInteractions(loader);
   }
 
-  @Test
-  public void testProjectDoesntExist() {
-    when(projectRepo.exists()).thenReturn(false);
-    when(loader.loadDefault()).thenReturn(response);
-    QualityProfiles qps = qualityProfileProvider.provide(loader, projectRepo, props);
-    assertResponse(qps);
-
-    verify(loader).loadDefault();
-    verifyNoMoreInteractions(loader);
-  }
-
   @Test
   public void testProfileProp() {
     when(loader.load(eq("project"))).thenReturn(response);
 
-    QualityProfiles qps = qualityProfileProvider.provide(loader, projectRepo, props);
+    QualityProfiles qps = qualityProfileProvider.provide(loader, props);
     assertResponse(qps);
 
     verify(loader).load(eq("project"));
     verifyNoMoreInteractions(loader);
   }
 
-  @Test
-  public void testProfilePropDefault() {
-    when(projectRepo.exists()).thenReturn(false);
-    when(loader.loadDefault()).thenReturn(response);
-
-    QualityProfiles qps = qualityProfileProvider.provide(loader, projectRepo, props);
-    assertResponse(qps);
-
-    verify(loader).loadDefault();
-    verifyNoMoreInteractions(loader);
-  }
-
   private void assertResponse(QualityProfiles qps) {
     assertThat(qps.findAll()).extracting("key").containsExactly("profile");
 
index 8863e9c1a35cdb78e46c7dc995ce300c8819c2a6..6b79b11276e8fa7572f7d82c18a7ccfd184d3e78 100644 (file)
@@ -96,7 +96,7 @@ public class BranchConfigurationProviderTest {
   public void should_return_default_if_no_loader() {
     BranchConfiguration result = provider.provide(null, globalConfiguration, reactor, globalServerSettings, projectServerSettings, branches, pullRequests);
 
-    assertThat(result.targetScmBranch()).isNull();
+    assertThat(result.targetBranchName()).isNull();
     assertThat(result.branchType()).isEqualTo(BranchType.LONG);
   }
 }
index b5ed22c270f7e73d8cfd64573d481e652de81f8d..857f12e9f69e9d8af4151374a5f202c5d4dd2671 100644 (file)
@@ -23,22 +23,32 @@ import java.nio.file.Paths;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
 import org.sonar.scanner.repository.FileData;
+import org.sonar.scanner.repository.ProjectRepositoriesSupplier;
 import org.sonar.scanner.repository.SingleProjectRepository;
 import org.sonar.scanner.scm.ScmChangedFiles;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 public class StatusDetectionTest {
+  private ProjectRepositoriesSupplier projectRepositoriesSupplier = mock(ProjectRepositoriesSupplier.class);
+
+  @Before
+  public void setUp() {
+    when(projectRepositoriesSupplier.get()).thenReturn(new SingleProjectRepository(createFileDataPerPathMap()));
+  }
+
   @Test
   public void detect_status() {
-    SingleProjectRepository ref = new SingleProjectRepository(createFileDataPerPathMap());
     ScmChangedFiles changedFiles = new ScmChangedFiles(null);
-    StatusDetection statusDetection = new StatusDetection(ref, changedFiles);
+    StatusDetection statusDetection = new StatusDetection(projectRepositoriesSupplier, changedFiles);
 
     assertThat(statusDetection.status("foo", createFile("src/Foo.java"), "ABCDE")).isEqualTo(InputFile.Status.SAME);
     assertThat(statusDetection.status("foo", createFile("src/Foo.java"), "XXXXX")).isEqualTo(InputFile.Status.CHANGED);
@@ -47,9 +57,8 @@ public class StatusDetectionTest {
 
   @Test
   public void detect_status_branches_exclude() {
-    SingleProjectRepository ref = new SingleProjectRepository(createFileDataPerPathMap());
     ScmChangedFiles changedFiles = new ScmChangedFiles(Collections.emptyList());
-    StatusDetection statusDetection = new StatusDetection(ref, changedFiles);
+    StatusDetection statusDetection = new StatusDetection(projectRepositoriesSupplier, changedFiles);
 
     // normally changed
     assertThat(statusDetection.status("foo", createFile("src/Foo.java"), "XXXXX")).isEqualTo(InputFile.Status.SAME);
@@ -60,9 +69,8 @@ public class StatusDetectionTest {
 
   @Test
   public void detect_status_branches_confirm() {
-    SingleProjectRepository ref = new SingleProjectRepository(createFileDataPerPathMap());
     ScmChangedFiles changedFiles = new ScmChangedFiles(Collections.singletonList(Paths.get("module", "src", "Foo.java")));
-    StatusDetection statusDetection = new StatusDetection(ref, changedFiles);
+    StatusDetection statusDetection = new StatusDetection(projectRepositoriesSupplier, changedFiles);
 
     assertThat(statusDetection.status("foo", createFile("src/Foo.java"), "XXXXX")).isEqualTo(InputFile.Status.CHANGED);
   }
index 7d0795eb2dea6f3c41f393ffef3e080032ab000c..4b81bb45f5ea29ffb8deb1664e14134d076620fe 100644 (file)
@@ -66,7 +66,7 @@ public class ScmChangedFilesProviderTest {
   @Test
   public void testNoScmProvider() {
     when(branchConfiguration.isShortOrPullRequest()).thenReturn(true);
-    when(branchConfiguration.targetScmBranch()).thenReturn("target");
+    when(branchConfiguration.targetBranchName()).thenReturn("target");
 
     ScmChangedFiles scmChangedFiles = provider.provide(scmConfiguration, branchConfiguration, project);
 
@@ -76,7 +76,7 @@ public class ScmChangedFilesProviderTest {
 
   @Test
   public void testFailIfRelativePath() {
-    when(branchConfiguration.targetScmBranch()).thenReturn("target");
+    when(branchConfiguration.targetBranchName()).thenReturn("target");
     when(branchConfiguration.isShortOrPullRequest()).thenReturn(true);
     when(scmConfiguration.provider()).thenReturn(scmProvider);
     when(scmProvider.branchChangedFiles("target", rootBaseDir)).thenReturn(Collections.singleton(Paths.get("changedFile")));
@@ -88,7 +88,7 @@ public class ScmChangedFilesProviderTest {
 
   @Test
   public void testProviderDoesntSupport() {
-    when(branchConfiguration.targetScmBranch()).thenReturn("target");
+    when(branchConfiguration.targetBranchName()).thenReturn("target");
     when(branchConfiguration.isShortOrPullRequest()).thenReturn(true);
     when(scmConfiguration.provider()).thenReturn(scmProvider);
     when(scmProvider.branchChangedFiles("target", rootBaseDir)).thenReturn(null);
@@ -118,7 +118,7 @@ public class ScmChangedFilesProviderTest {
 
     when(scmConfiguration.provider()).thenReturn(legacy);
     when(branchConfiguration.isShortOrPullRequest()).thenReturn(true);
-    when(branchConfiguration.targetScmBranch()).thenReturn("target");
+    when(branchConfiguration.targetBranchName()).thenReturn("target");
 
     ScmChangedFiles scmChangedFiles = provider.provide(scmConfiguration, branchConfiguration, project);
 
@@ -128,7 +128,7 @@ public class ScmChangedFilesProviderTest {
 
   @Test
   public void testReturnChangedFiles() {
-    when(branchConfiguration.targetScmBranch()).thenReturn("target");
+    when(branchConfiguration.targetBranchName()).thenReturn("target");
     when(branchConfiguration.isShortOrPullRequest()).thenReturn(true);
     when(scmConfiguration.provider()).thenReturn(scmProvider);
     when(scmProvider.branchChangedFiles("target", rootBaseDir)).thenReturn(Collections.singleton(Paths.get("changedFile").toAbsolutePath()));
index bd0e0d21d1a7bbaf2dce1ecc2b9d21a1a627b854..2e2f493302b8a242b23303c31887121fce70c640 100644 (file)
@@ -23,13 +23,18 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Collection;
 import java.util.Collections;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class ScmChangedFilesTest {
   private ScmChangedFiles scmChangedFiles;
 
+  @Rule
+  public ExpectedException exception = ExpectedException.none();
+
   @Test
   public void testGetter() {
     Collection<Path> files = Collections.singletonList(Paths.get("files"));
@@ -40,15 +45,19 @@ public class ScmChangedFilesTest {
   @Test
   public void testNullable() {
     scmChangedFiles = new ScmChangedFiles(null);
+    assertThat(scmChangedFiles.isValid()).isFalse();
     assertThat(scmChangedFiles.get()).isNull();
-    assertThat(scmChangedFiles.verifyChanged(Paths.get("files2"))).isTrue();
+
+    exception.expect(IllegalStateException.class);
+    assertThat(scmChangedFiles.isChanged(Paths.get("files2"))).isTrue();
   }
 
   @Test
   public void testConfirm() {
     Collection<Path> files = Collections.singletonList(Paths.get("files"));
     scmChangedFiles = new ScmChangedFiles(files);
-    assertThat(scmChangedFiles.verifyChanged(Paths.get("files"))).isTrue();
-    assertThat(scmChangedFiles.verifyChanged(Paths.get("files2"))).isFalse();
+    assertThat(scmChangedFiles.isValid()).isTrue();
+    assertThat(scmChangedFiles.isChanged(Paths.get("files"))).isTrue();
+    assertThat(scmChangedFiles.isChanged(Paths.get("files2"))).isFalse();
   }
 }
index 2d63cc866dd7d8d2883f4b0ba401d51491b90133..381824cc9ea3cd2d71f0fd0a814e4755123676bf 100644 (file)
@@ -39,6 +39,7 @@ message Metadata {
   bool cross_project_duplication_activated = 6;
   map<string, QProfile> qprofiles_per_language = 7;
   map<string, Plugin> plugins_by_key = 8;
+
   string branch_name = 9;
   BranchType branch_type = 10;
   string merge_branch_name = 11;
@@ -52,6 +53,8 @@ message Metadata {
   string projectVersion = 16;
   string buildString = 17;
 
+  string target_branch_name = 18;
+
   message QProfile {
     string key = 1;
     string name = 2;
index 2420312149611f442d21478afb9465a455f0fda7..cad1acf8e583cb922c5de413db35c62d9c782345 100644 (file)
@@ -40,6 +40,7 @@ message PullRequest {
   optional bool isOrphan = 6;
   optional string analysisDate = 7;
   optional string url = 8;
+  optional string target = 9;
 }
 
 message Status {