diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2017-08-11 11:23:31 +0200 |
---|---|---|
committer | Janos Gyerik <janos.gyerik@sonarsource.com> | 2017-09-12 10:59:55 +0200 |
commit | 0a5d420a59a1660327ce9d132f4e57e2fcbe76f6 (patch) | |
tree | a67419f6800fdb077343fcf9bb9e7f7db14f60b8 | |
parent | 09a2697f50fd4cf2895c7d62957fcb1f4852fe52 (diff) | |
download | sonarqube-0a5d420a59a1660327ce9d132f4e57e2fcbe76f6.tar.gz sonarqube-0a5d420a59a1660327ce9d132f4e57e2fcbe76f6.zip |
SONAR-9616 Return merge branch in api/projectbranches/list
9 files changed, 95 insertions, 9 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java index 6519c318411..0d169e35d0a 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java @@ -20,12 +20,15 @@ package org.sonar.db.component; import java.util.Collection; +import java.util.List; import java.util.Optional; import javax.annotation.Nullable; import org.sonar.api.utils.System2; import org.sonar.db.Dao; import org.sonar.db.DbSession; +import static org.sonar.db.DatabaseUtils.executeLargeInputs; + public class BranchDao implements Dao { private final System2 system2; @@ -59,6 +62,10 @@ public class BranchDao implements Dao { return mapper(dbSession).selectByProjectUuid(projectUuid); } + public List<BranchDto> selectByUuids(DbSession session, Collection<String> uuids) { + return executeLargeInputs(uuids, mapper(session)::selectByUuids); + } + private static BranchMapper mapper(DbSession dbSession) { return dbSession.getMapper(BranchMapper.class); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java index 41cf1360f3d..2e4df028bc1 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java @@ -20,6 +20,7 @@ package org.sonar.db.component; import java.util.Collection; +import java.util.List; import org.apache.ibatis.annotations.Param; public interface BranchMapper { @@ -32,4 +33,6 @@ public interface BranchMapper { @Param("keyType") BranchKeyType keyType, @Param("key") String key); Collection<BranchDto> selectByProjectUuid(@Param("projectUuid") String projectUuid); + + List<BranchDto> selectByUuids(@Param("uuids") Collection<String> uuids); } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml index c5a6de69a93..78215959491 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml @@ -61,4 +61,15 @@ where pb.project_uuid = #{projectUuid, jdbcType=VARCHAR} </select> + + <select id="selectByUuids" resultType="org.sonar.db.component.BranchDto"> + select <include refid="columns" /> + from project_branches pb + where + pb.uuid in + <foreach collection="uuids" open="(" close=")" item="uuid" separator=","> + #{uuid,jdbcType=VARCHAR} + </foreach> + </select> + </mapper> diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java index 5133effde68..86dc1db2594 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java @@ -28,6 +28,8 @@ import org.sonar.api.utils.internal.TestSystem2; import org.sonar.db.DbSession; import org.sonar.db.DbTester; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; import static org.apache.commons.lang.StringUtils.repeat; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; @@ -172,4 +174,19 @@ public class BranchDaoTest { assertThat(underTest.selectByKey(dbSession, "U3", BranchKeyType.BRANCH, "feature/foo")).isEmpty(); } + @Test + public void selectByUuids() { + ComponentDto project = db.components().insertPrivateProject(); + ComponentDto branch1 = db.components().insertProjectBranch(project); + ComponentDto branch2 = db.components().insertProjectBranch(project); + ComponentDto branch3 = db.components().insertProjectBranch(project); + + assertThat(underTest.selectByUuids(db.getSession(), asList(branch1.uuid(), branch2.uuid(), branch3.uuid()))) + .extracting(BranchDto::getUuid) + .containsExactlyInAnyOrder(branch1.uuid(), branch2.uuid(), branch3.uuid()); + assertThat(underTest.selectByUuids(db.getSession(), singletonList(branch1.uuid()))) + .extracting(BranchDto::getUuid) + .containsExactlyInAnyOrder(branch1.uuid()); + assertThat(underTest.selectByUuids(db.getSession(), singletonList("unknown"))).isEmpty(); + } } diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDbTester.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDbTester.java index a3a23ec35e1..339ab0f647a 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDbTester.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDbTester.java @@ -207,7 +207,8 @@ public class ComponentDbTester { BranchDto branchDto = new BranchDto() .setKey("branch_" + randomAlphanumeric(248)) .setUuid(uuid) - .setProjectUuid(project.uuid()) + // MainBranchProjectUuid will be null if it's a main branch + .setProjectUuid(firstNonNull(project.getMainBranchProjectUuid(), project.projectUuid())) .setKeeType(BRANCH) .setBranchType(LONG); Arrays.stream(dtoPopulators).forEach(dtoPopulator -> dtoPopulator.accept(branchDto)); @@ -218,4 +219,8 @@ public class ComponentDbTester { return branch; } + private static <T> T firstNonNull(@Nullable T first, T second) { + return (first != null) ? first : second; + } + } 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 5d03096673d..97fb81bbb78 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 @@ -21,6 +21,8 @@ package org.sonar.server.projectbranch.ws; import com.google.common.io.Resources; import java.util.Collection; +import java.util.Map; +import java.util.Objects; import org.sonar.api.resources.Qualifiers; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; @@ -35,7 +37,10 @@ import org.sonar.server.user.UserSession; import org.sonar.server.ws.WsUtils; import org.sonarqube.ws.WsBranches; +import static com.google.common.base.Preconditions.checkState; import static org.sonar.core.util.Protobuf.setNullable; +import static org.sonar.core.util.stream.MoreCollectors.toList; +import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.ACTION_LIST; import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_PROJECT; @@ -80,19 +85,29 @@ public class ListAction implements BranchWsAction { } Collection<BranchDto> branches = dbClient.branchDao().selectByComponent(dbSession, project); + Map<String, BranchDto> mergeBranchesByUuid = dbClient.branchDao() + .selectByUuids(dbSession, branches.stream().map(BranchDto::getMergeBranchUuid).filter(Objects::nonNull).collect(toList())) + .stream().collect(uniqueIndex(BranchDto::getUuid)); + WsBranches.ListWsResponse.Builder protobufResponse = WsBranches.ListWsResponse.newBuilder(); branches.stream() .filter(b -> b.getKeeType().equals(BranchKeyType.BRANCH)) - .forEach(b -> addToProtobuf(protobufResponse, b)); + .forEach(b -> addToProtobuf(protobufResponse, b, mergeBranchesByUuid)); WsUtils.writeProtobuf(protobufResponse.build(), request, response); } } - private static void addToProtobuf(WsBranches.ListWsResponse.Builder response, BranchDto branch) { + private static void addToProtobuf(WsBranches.ListWsResponse.Builder response, BranchDto branch, Map<String, BranchDto> mergeBranchesByUuid) { WsBranches.ListWsResponse.Branch.Builder builder = response.addBranchesBuilder(); setNullable(branch.getKey(), builder::setName); builder.setIsMain(branch.isMain()); builder.setType(WsBranches.ListWsResponse.BranchType.valueOf(branch.getBranchType().name())); + String mergeBranchUuid = branch.getMergeBranchUuid(); + if (mergeBranchUuid != null) { + BranchDto megeBranch = mergeBranchesByUuid.get(mergeBranchUuid); + checkState(megeBranch != null, "Component uuid '%s' cannot be found", megeBranch); + setNullable(megeBranch.getKey(), builder::setMergeBranch); + } builder.build(); } } diff --git a/server/sonar-server/src/main/resources/org/sonar/server/projectbranch/ws/list-example.json b/server/sonar-server/src/main/resources/org/sonar/server/projectbranch/ws/list-example.json index a7db235d028..0078ef5f40b 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/projectbranch/ws/list-example.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/projectbranch/ws/list-example.json @@ -8,7 +8,8 @@ { "name": "feature/foo", "isMain": false, - "type": "LONG" + "type": "SHORT", + "mergeBranch": "feature/bar" } ] } 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 6fd35c9f882..bd7ca61fd0e 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 @@ -26,7 +26,7 @@ import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; import org.sonar.api.web.UserRole; import org.sonar.db.DbTester; -import org.sonar.db.RowNotFoundException; +import org.sonar.db.component.BranchType; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; import org.sonar.server.exceptions.NotFoundException; @@ -34,6 +34,7 @@ import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsActionTester; import org.sonarqube.ws.MediaTypes; import org.sonarqube.ws.WsBranches.ListWsResponse; +import org.sonarqube.ws.WsBranches.ListWsResponse.Branch; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; @@ -118,16 +119,40 @@ public class ListActionTest { .executeProtobuf(ListWsResponse.class); assertThat(response.getBranchesList()) - .extracting(ListWsResponse.Branch::getName, ListWsResponse.Branch::getType) + .extracting(Branch::getName, Branch::getType) .containsExactlyInAnyOrder( - tuple("feature/foo", ListWsResponse.BranchType.LONG), tuple("feature/bar", ListWsResponse.BranchType.LONG)); + tuple("feature/foo", ListWsResponse.BranchType.LONG), + tuple("feature/bar", ListWsResponse.BranchType.LONG)); + } + + @Test + public void short_living_branches() { + ComponentDto project = db.components().insertPrivateProject(); + userSession.logIn().addProjectPermission(UserRole.USER, project); + ComponentDto longLivingBranch = db.components().insertProjectBranch(project, + b -> b.setKey("long").setBranchType(BranchType.LONG)); + ComponentDto shortLivingBranch = db.components().insertProjectBranch(project, + b -> b.setKey("short").setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch.uuid())); + ComponentDto shortLivingBranchOnMaster = db.components().insertProjectBranch(project, + b -> b.setKey("short_on_master").setBranchType(BranchType.SHORT).setMergeBranchUuid(project.uuid())); + + ListWsResponse response = tester.newRequest() + .setParam("project", project.getKey()) + .executeProtobuf(ListWsResponse.class); + + assertThat(response.getBranchesList()) + .extracting(Branch::getName, Branch::getType, Branch::getMergeBranch) + .containsExactlyInAnyOrder( + tuple(longLivingBranch.getBranch(), ListWsResponse.BranchType.LONG, ""), + tuple(shortLivingBranch.getBranch(), ListWsResponse.BranchType.SHORT, longLivingBranch.getBranch()), + tuple(shortLivingBranchOnMaster.getBranch(), ListWsResponse.BranchType.SHORT, "")); } @Test public void test_example() { ComponentDto project = db.components().insertPrivateProject(); - db.components().insertProjectBranch(project, b -> b.setKey("feature/bar")); - db.components().insertProjectBranch(project, b -> b.setKey("feature/foo")); + 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); String json = tester.newRequest() diff --git a/sonar-ws/src/main/protobuf/ws-projectbranches.proto b/sonar-ws/src/main/protobuf/ws-projectbranches.proto index 7b57be2e420..ea51ef7184a 100644 --- a/sonar-ws/src/main/protobuf/ws-projectbranches.proto +++ b/sonar-ws/src/main/protobuf/ws-projectbranches.proto @@ -33,6 +33,8 @@ message ListWsResponse { optional string name = 1; optional bool isMain = 2; optional BranchType type = 3; + // Merge branch is only present if it's a short living branch + optional string mergeBranch = 4; } enum BranchType { |