diff options
author | Duarte Meneses <duarte.meneses@sonarsource.com> | 2019-04-01 11:28:19 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-04-23 20:21:07 +0200 |
commit | 81638702d68033ca95ddd406aa655fb2bfdab036 (patch) | |
tree | 517407d64df2d9cb95ed27a32aab3c82b8f58092 | |
parent | afe312e4cbf9ac88676d526ff6da0b641aef4ae8 (diff) | |
download | sonarqube-81638702d68033ca95ddd406aa655fb2bfdab036.tar.gz sonarqube-81638702d68033ca95ddd406aa655fb2bfdab036.zip |
SONAR-11856 Store the "true" target branch in the scanner report to display it properly
46 files changed, 287 insertions, 227 deletions
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/Branch.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/Branch.java index e9eb4c21914..22c0702dd15 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/Branch.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/Branch.java @@ -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(); } diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImpl.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImpl.java index cde9d00d1c6..a8bfb52aab2 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImpl.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImpl.java @@ -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 { diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/DefaultBranchImpl.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/DefaultBranchImpl.java index ae137aa4743..1a15ad8e243 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/DefaultBranchImpl.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/DefaultBranchImpl.java @@ -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 @@ -90,6 +89,11 @@ public class DefaultBranchImpl implements Branch { } @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) { projectKey = ComponentKeys.createKey(projectKey, branchName); diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/MergeBranchComponentUuids.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/MergeBranchComponentUuids.java index 84d5d066f0f..888e0c181b1 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/MergeBranchComponentUuids.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/MergeBranchComponentUuids.java @@ -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)) { diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/SiblingComponentsWithOpenIssues.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/SiblingComponentsWithOpenIssues.java index cce1c2d09dc..6d7defeccb6 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/SiblingComponentsWithOpenIssues.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/SiblingComponentsWithOpenIssues.java @@ -34,7 +34,6 @@ import static org.sonar.db.component.ComponentDto.removeBranchAndPullRequestFrom /** * Cache a map of component key -> set<uuid> 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()); } diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoader.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoader.java index 6f9b8b5442b..e553e40f8a6 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoader.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoader.java @@ -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())); } diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStep.java index fab944e408d..441e9eefbb8 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStep.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStep.java @@ -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); diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutorTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutorTest.java index e275c6dffac..adc120665a2 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutorTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutorTest.java @@ -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()); diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImplTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImplTest.java index 8b98135f33d..cb4764c1b7b 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImplTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImplTest.java @@ -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; } diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/MergeBranchComponentUuidsTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/MergeBranchComponentUuidsTest.java index 5fe2b5e950b..a0409c6a56e 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/MergeBranchComponentUuidsTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/MergeBranchComponentUuidsTest.java @@ -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(); } } diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/SiblingComponentsWithOpenIssuesTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/SiblingComponentsWithOpenIssuesTest.java index dc73d0cb075..acb41e57fe4 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/SiblingComponentsWithOpenIssuesTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/SiblingComponentsWithOpenIssuesTest.java @@ -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); } } diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/SiblingsIssueMergerTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/SiblingsIssueMergerTest.java index e595aa04b69..4272c9f6981 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/SiblingsIssueMergerTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/SiblingsIssueMergerTest.java @@ -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 diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoaderTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoaderTest.java index 0e9d474ecb6..159f82d34bf 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoaderTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoaderTest.java @@ -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); diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/LoadPeriodsStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/LoadPeriodsStepTest.java index a1ad8c75e3d..2d219d0825c 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/LoadPeriodsStepTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/LoadPeriodsStepTest.java @@ -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"); } @@ -462,6 +461,11 @@ public class LoadPeriodsStepTest extends BaseStepTest { } @Override + public String getTargetBranchName() { + throw new UnsupportedOperationException(); + } + + @Override public String generateKey(String projectKey, @Nullable String fileOrDirPath) { throw new UnsupportedOperationException("generateKey not implemented"); } diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ReportPersistComponentsStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ReportPersistComponentsStepTest.java index 605a3005bd6..d19eb51ad14 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ReportPersistComponentsStepTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ReportPersistComponentsStepTest.java @@ -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 @@ -696,6 +696,11 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { } @Override + public String getTargetBranchName() { + throw new UnsupportedOperationException(); + } + + @Override public String generateKey(String projectKey, @Nullable String fileOrDirPath) { if (isEmpty(fileOrDirPath)) { return projectKey; diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStepTest.java index ccfc54e6708..05e3136e39f 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStepTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStepTest.java @@ -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); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java index d065136abab..7914cec53e6 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java @@ -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); } diff --git a/server/sonar-db-dao/src/main/protobuf/db-project-branches.proto b/server/sonar-db-dao/src/main/protobuf/db-project-branches.proto index ac6f5047f4a..f3d5fcd49f0 100644 --- a/server/sonar-db-dao/src/main/protobuf/db-project-branches.proto +++ b/server/sonar-db-dao/src/main/protobuf/db-project-branches.proto @@ -35,4 +35,6 @@ message PullRequestData { string url = 3; map<string, string> attributes = 4; + + string target = 5; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/branch/pr/ws/ListAction.java b/server/sonar-server/src/main/java/org/sonar/server/branch/pr/ws/ListAction.java index 281ba36202d..4ee21954cdb 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/branch/pr/ws/ListAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/branch/pr/ws/ListAction.java @@ -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); diff --git a/server/sonar-server/src/main/resources/org/sonar/server/branch/pr/ws/list-example.json b/server/sonar-server/src/main/resources/org/sonar/server/branch/pr/ws/list-example.json index 4fef887dc82..877d25c17ef 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/branch/pr/ws/list-example.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/branch/pr/ws/list-example.json @@ -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" } ] } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/StatusPredicate.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/StatusPredicate.java index 6317707f6f8..d6c17571fac 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/StatusPredicate.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/StatusPredicate.java @@ -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; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ChangedLinesPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ChangedLinesPublisher.java index 8bc978109b6..ff393c42773 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ChangedLinesPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ChangedLinesPublisher.java @@ -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(); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java index 69891747295..9bf40f4a94e 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java @@ -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()); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultQualityProfileLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultQualityProfileLoader.java index 6c3c2f93da2..361eeab3e6d 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultQualityProfileLoader.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultQualityProfileLoader.java @@ -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/ProjectRepositoriesSupplier.java index d2f7bfeb1af..f0fda872182 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositoriesProvider.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositoriesSupplier.java @@ -19,19 +19,29 @@ */ package org.sonar.scanner.repository; -import org.picocontainer.injectors.ProviderAdapter; +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 ProjectRepositoriesProvider extends ProviderAdapter { - private static final Logger LOG = Loggers.get(ProjectRepositoriesProvider.class); +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 ProjectRepositories provide(ProjectRepositoriesLoader loader, ProcessedScannerProperties scannerProperties, BranchConfiguration branchConfig) { + 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()); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/QualityProfileLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/QualityProfileLoader.java index 202cc6389e1..df17a1f2247 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/QualityProfileLoader.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/QualityProfileLoader.java @@ -24,6 +24,4 @@ import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile; public interface QualityProfileLoader { List<QualityProfile> load(String projectKey); - - List<QualityProfile> loadDefault(); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/QualityProfilesProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/QualityProfilesProvider.java index 267d0c01729..e78e4d7457f 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/QualityProfilesProvider.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/QualityProfilesProvider.java @@ -19,31 +19,23 @@ */ 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; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java index dc242a2b4bd..548a477c7d0 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java @@ -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())); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/BranchConfiguration.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/BranchConfiguration.java index 87dedb54d11..d3f51049c0d 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/BranchConfiguration.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/BranchConfiguration.java @@ -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. diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/DefaultBranchConfiguration.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/DefaultBranchConfiguration.java index 436afec909e..7314597a828 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/DefaultBranchConfiguration.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/DefaultBranchConfiguration.java @@ -37,7 +37,7 @@ public class DefaultBranchConfiguration implements BranchConfiguration { @CheckForNull @Override - public String targetScmBranch() { + public String targetBranchName() { return null; } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/StatusDetection.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/StatusDetection.java index 8f33e02ea2c..09561999935 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/StatusDetection.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/StatusDetection.java @@ -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; } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFiles.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFiles.java index dfb078ecccb..380c65c32a2 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFiles.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFiles.java @@ -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; } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFilesProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFilesProvider.java index 63f30c85f2c..b7fd4c8bf76 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFilesProvider.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFilesProvider.java @@ -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())); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmPublisher.java index 4abb86427d5..819abc8adce 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmPublisher.java @@ -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); } } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java index 49df2785567..28cb9ba3ed8 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java @@ -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 { diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ChangedLinesPublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ChangedLinesPublisherTest.java index b45964ecad6..2d155cea756 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ChangedLinesPublisherTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ChangedLinesPublisherTest.java @@ -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(); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java index f7df36536d9..2c90a1a8eed 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java @@ -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 diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/DefaultQualityProfileLoaderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/DefaultQualityProfileLoaderTest.java index 757bd52ab3a..95e38e4520e 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/DefaultQualityProfileLoaderTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/DefaultQualityProfileLoaderTest.java @@ -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/ProjectRepositoriesSupplierTest.java index 2fb5056e0c9..72c58dca71d 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/ProjectRepositoriesProviderTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/ProjectRepositoriesSupplierTest.java @@ -23,53 +23,43 @@ 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.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -public class ProjectRepositoriesProviderTest { - private ProjectRepositoriesProvider provider; +public class ProjectRepositoriesSupplierTest { + private ProjectRepositoriesSupplier underTest; private ProjectRepositories project; - @Mock - private ProjectRepositoriesLoader loader; - @Mock - private ProcessedScannerProperties props; - @Mock - private BranchConfiguration branchConfiguration; + private ProjectRepositoriesLoader loader = mock(ProjectRepositoriesLoader.class); + private ProcessedScannerProperties props = mock(ProcessedScannerProperties.class); + private BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); @Before public void setUp() { - MockitoAnnotations.initMocks(this); - + underTest = new ProjectRepositoriesSupplier(loader, props, branchConfiguration); 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); + underTest.get(); } @Test public void testAssociated() { when(loader.load(eq("key"), any())).thenReturn(project); - - ProjectRepositories repo = provider.provide(loader, props, branchConfiguration); + ProjectRepositories repo = underTest.get(); assertThat(repo.exists()).isEqualTo(true); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/QualityProfileProviderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/QualityProfileProviderTest.java index a318a6e9b59..94bc1b6f10c 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/QualityProfileProviderTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/QualityProfileProviderTest.java @@ -19,25 +19,21 @@ */ 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,7 +63,7 @@ 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"); @@ -81,39 +71,16 @@ public class QualityProfileProviderTest { } @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"); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/branch/BranchConfigurationProviderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/branch/BranchConfigurationProviderTest.java index 8863e9c1a35..6b79b11276e 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/branch/BranchConfigurationProviderTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/branch/BranchConfigurationProviderTest.java @@ -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); } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/StatusDetectionTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/StatusDetectionTest.java index b5ed22c270f..857f12e9f69 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/StatusDetectionTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/StatusDetectionTest.java @@ -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); } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesProviderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesProviderTest.java index 7d0795eb2de..4b81bb45f5e 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesProviderTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesProviderTest.java @@ -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())); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesTest.java index bd0e0d21d1a..2e2f493302b 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesTest.java @@ -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(); } } diff --git a/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto b/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto index 2d63cc866dd..381824cc9ea 100644 --- a/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto +++ b/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto @@ -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; diff --git a/sonar-ws/src/main/protobuf/ws-projectpullrequests.proto b/sonar-ws/src/main/protobuf/ws-projectpullrequests.proto index 24203121496..cad1acf8e58 100644 --- a/sonar-ws/src/main/protobuf/ws-projectpullrequests.proto +++ b/sonar-ws/src/main/protobuf/ws-projectpullrequests.proto @@ -40,6 +40,7 @@ message PullRequest { optional bool isOrphan = 6; optional string analysisDate = 7; optional string url = 8; + optional string target = 9; } message Status { |