From 864a8c2617b4fa26f5c941a9bd3877f5c7422cf3 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Tue, 22 Aug 2017 17:43:26 +0200 Subject: [PATCH] SONAR-9616 api/projectbranches returns isOrphan on unknown merge branch --- .../projectbranch/ws/BranchDtoToWsBranch.java | 14 +-- .../server/projectbranch/ws/ListAction.java | 11 +-- .../server/projectbranch/ws/ShowAction.java | 7 +- .../projectbranch/ws/ListActionTest.java | 88 +++++++++++-------- .../projectbranch/ws/ShowActionTest.java | 17 ++++ .../main/protobuf/ws-projectbranches.proto | 1 + 6 files changed, 82 insertions(+), 56 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchDtoToWsBranch.java b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchDtoToWsBranch.java index fa0813568ef..c8df3be78cf 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchDtoToWsBranch.java +++ b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchDtoToWsBranch.java @@ -21,7 +21,7 @@ package org.sonar.server.projectbranch.ws; import java.util.Map; -import javax.annotation.Nullable; +import java.util.Optional; import org.sonar.db.component.BranchDto; import org.sonar.db.measure.MeasureDto; import org.sonarqube.ws.Common; @@ -42,19 +42,19 @@ public class BranchDtoToWsBranch { // static methods only } - public static WsBranches.Branch.Builder toBranchBuilder(BranchDto branch, @Nullable BranchDto mergeBranch, Map measuresByMetricKey) { + static WsBranches.Branch.Builder toBranchBuilder(BranchDto branch, Optional mergeBranch, Map measuresByMetricKey) { WsBranches.Branch.Builder builder = WsBranches.Branch.newBuilder(); String branchKey = branch.getKey(); String effectiveBranchKey = branchKey == null && branch.isMain() ? DEFAULT_MAIN_BRANCH_NAME : branchKey; setNullable(effectiveBranchKey, builder::setName); builder.setIsMain(branch.isMain()); builder.setType(Common.BranchType.valueOf(branch.getBranchType().name())); - if (mergeBranch != null) { - String mergeBranchKey = mergeBranch.getKey(); - if (mergeBranchKey == null && branch.getBranchType().equals(SHORT)) { - builder.setMergeBranch(DEFAULT_MAIN_BRANCH_NAME); + if (branch.getBranchType().equals(SHORT)) { + if (mergeBranch.isPresent()) { + String mergeBranchKey = mergeBranch.get().getKey(); + builder.setMergeBranch(mergeBranchKey == null ? DEFAULT_MAIN_BRANCH_NAME : mergeBranchKey); } else { - setNullable(mergeBranchKey, builder::setMergeBranch); + builder.setIsOrphan(true); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ListAction.java b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ListAction.java index 1291dba44b9..3237961ea26 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ListAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ListAction.java @@ -25,6 +25,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.function.Function; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; @@ -43,7 +44,6 @@ import org.sonar.server.ws.WsUtils; import org.sonarqube.ws.WsBranches; import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkState; import static java.util.Arrays.asList; import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; import static org.sonar.api.measures.CoreMetrics.BUGS_KEY; @@ -116,15 +116,8 @@ public class ListAction implements BranchWsAction { private static void addBranch(WsBranches.ListWsResponse.Builder response, BranchDto branch, Map mergeBranchesByUuid, Map metricsById, Collection measures) { - - BranchDto mergeBranch = null; - String mergeBranchUuid = branch.getMergeBranchUuid(); - if (mergeBranchUuid != null) { - mergeBranch = mergeBranchesByUuid.get(mergeBranchUuid); - checkState(mergeBranch != null, "Component uuid '%s' cannot be found", mergeBranch); - } response.addBranches( - toBranchBuilder(branch, mergeBranch, + toBranchBuilder(branch, Optional.ofNullable(mergeBranchesByUuid.get(branch.getMergeBranchUuid())), measures.stream().collect(uniqueIndex(m -> metricsById.get(m.getMetricId()).getKey(), Function.identity())))); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ShowAction.java b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ShowAction.java index 041611379c8..c8fb9753901 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ShowAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ShowAction.java @@ -116,7 +116,7 @@ public class ShowAction implements BranchWsAction { BranchDto branch = getBranch(dbSession, component.projectUuid()); String mergeBranchUuid = branch.getMergeBranchUuid(); - BranchDto mergeBranch = mergeBranchUuid == null ? null : getBranch(dbSession, mergeBranchUuid); + Optional mergeBranch = mergeBranchUuid == null ? Optional.empty() : dbClient.branchDao().selectByUuid(dbSession, branch.getMergeBranchUuid()); Collection measures = dbClient.measureDao() .selectByComponentsAndMetrics(dbSession, Collections.singletonList(branch.getUuid()), metricsById.keySet()) @@ -131,10 +131,7 @@ public class ShowAction implements BranchWsAction { } private ComponentDto loadComponent(DbSession dbSession, String projectKey, @Nullable String branchName) { - if (branchName == null) { - return componentFinder.getByKey(dbSession, projectKey); - } - return componentFinder.getByKeyAndBranch(dbSession, projectKey, branchName); + return branchName == null ? componentFinder.getByKey(dbSession, projectKey) : componentFinder.getByKeyAndBranch(dbSession, projectKey, branchName); } private BranchDto getBranch(DbSession dbSession, String uuid) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ListActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ListActionTest.java index 7aea4ab3e05..15ddf4440b6 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ListActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ListActionTest.java @@ -95,35 +95,18 @@ public class ListActionTest { } @Test - public void fail_if_missing_project_parameter() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("The 'project' parameter is missing"); - - ws.newRequest().execute(); - } - - @Test - public void fail_if_not_a_reference_on_project() { - ComponentDto project = db.components().insertPrivateProject(); - ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); + public void test_example() { + ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey("sonarqube")); + ComponentDto longLivingBranch = db.components().insertProjectBranch(project, b -> b.setKey("feature/bar").setBranchType(BranchType.LONG)); + db.components().insertProjectBranch(project, b -> b.setKey("feature/foo").setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch.uuid())); userSession.logIn().addProjectPermission(UserRole.USER, project); - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Invalid project key"); - - ws.newRequest() - .setParam("project", file.getDbKey()) - .execute(); - } - - @Test - public void fail_if_project_does_not_exist() { - expectedException.expect(NotFoundException.class); - expectedException.expectMessage("Component key 'foo' not found"); + String json = ws.newRequest() + .setParam("project", project.getDbKey()) + .execute() + .getInput(); - ws.newRequest() - .setParam("project", "foo") - .execute(); + assertJson(json).isSimilarTo(ws.getDef().responseExampleAsString()); } @Test @@ -227,6 +210,24 @@ public class ListActionTest { .containsExactlyInAnyOrder(shortLivingBranch.getBranch(), Common.BranchType.SHORT, "master"); } + @Test + public void short_living_branch_on_removed_branch() { + ComponentDto project = db.components().insertMainBranch(); + userSession.logIn().addProjectPermission(UserRole.USER, project); + ComponentDto shortLivingBranch = db.components().insertProjectBranch(project, + b -> b.setKey("short").setBranchType(BranchType.SHORT).setMergeBranchUuid("unknown")); + + ListWsResponse response = ws.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(ListWsResponse.class); + + assertThat(response.getBranchesList()) + .extracting(Branch::getName, Branch::getType, Branch::hasMergeBranch, Branch::getIsOrphan) + .containsExactlyInAnyOrder( + tuple("master", Common.BranchType.LONG, false, false), + tuple(shortLivingBranch.getBranch(), Common.BranchType.SHORT, false, true)); + } + @Test public void quality_gate_status_on_long_living_branch() { ComponentDto project = db.components().insertMainBranch(); @@ -284,18 +285,35 @@ public class ListActionTest { } @Test - public void test_example() { - ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey("sonarqube")); - ComponentDto longLivingBranch = db.components().insertProjectBranch(project, b -> b.setKey("feature/bar").setBranchType(BranchType.LONG)); - db.components().insertProjectBranch(project, b -> b.setKey("feature/foo").setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch.uuid())); + public void fail_if_missing_project_parameter() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("The 'project' parameter is missing"); + + ws.newRequest().execute(); + } + + @Test + public void fail_if_not_a_reference_on_project() { + ComponentDto project = db.components().insertPrivateProject(); + ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); userSession.logIn().addProjectPermission(UserRole.USER, project); - String json = ws.newRequest() - .setParam("project", project.getDbKey()) - .execute() - .getInput(); + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Invalid project key"); - assertJson(json).isSimilarTo(ws.getDef().responseExampleAsString()); + ws.newRequest() + .setParam("project", file.getDbKey()) + .execute(); + } + + @Test + public void fail_if_project_does_not_exist() { + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Component key 'foo' not found"); + + ws.newRequest() + .setParam("project", "foo") + .execute(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ShowActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ShowActionTest.java index 05c6acc3dbd..56fe5cb61f6 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ShowActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ShowActionTest.java @@ -174,6 +174,23 @@ public class ShowActionTest { .containsExactlyInAnyOrder(shortLivingBranch.getBranch(), Common.BranchType.SHORT, "master"); } + @Test + public void short_living_branch_on_removed_branch() { + ComponentDto project = db.components().insertMainBranch(); + userSession.logIn().addProjectPermission(UserRole.USER, project); + ComponentDto shortLivingBranch = db.components().insertProjectBranch(project, + b -> b.setKey("short").setBranchType(BranchType.SHORT).setMergeBranchUuid("unknown")); + + ShowWsResponse response = ws.newRequest() + .setParam("component", shortLivingBranch.getKey()) + .setParam("branch", shortLivingBranch.getBranch()) + .executeProtobuf(ShowWsResponse.class); + + assertThat(response.getBranch()) + .extracting(Branch::getIsOrphan) + .containsExactlyInAnyOrder(true); + } + @Test public void quality_gate_status_on_long_living_branch() { ComponentDto project = db.components().insertMainBranch(); diff --git a/sonar-ws/src/main/protobuf/ws-projectbranches.proto b/sonar-ws/src/main/protobuf/ws-projectbranches.proto index 59f9e9038f5..a5c67745885 100644 --- a/sonar-ws/src/main/protobuf/ws-projectbranches.proto +++ b/sonar-ws/src/main/protobuf/ws-projectbranches.proto @@ -43,6 +43,7 @@ message Branch { // Merge branch is only present for short living branch optional string mergeBranch = 4; optional Status status = 5; + optional bool isOrphan = 6; message Status { // Quality gate status is only present for long living branch -- 2.39.5