aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2017-08-11 11:23:31 +0200
committerJanos Gyerik <janos.gyerik@sonarsource.com>2017-09-12 10:59:55 +0200
commit0a5d420a59a1660327ce9d132f4e57e2fcbe76f6 (patch)
treea67419f6800fdb077343fcf9bb9e7f7db14f60b8
parent09a2697f50fd4cf2895c7d62957fcb1f4852fe52 (diff)
downloadsonarqube-0a5d420a59a1660327ce9d132f4e57e2fcbe76f6.tar.gz
sonarqube-0a5d420a59a1660327ce9d132f4e57e2fcbe76f6.zip
SONAR-9616 Return merge branch in api/projectbranches/list
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java7
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java3
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml11
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java17
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDbTester.java7
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ListAction.java19
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/projectbranch/ws/list-example.json3
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ListActionTest.java35
-rw-r--r--sonar-ws/src/main/protobuf/ws-projectbranches.proto2
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 {