From d9b502eb1f50437f06aeafde6bf0a4ff0694e0aa Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Wed, 16 Aug 2017 20:06:36 +0200 Subject: [PATCH] SONAR-9616 Return branch info in api/ce ws --- .../sonar/db/ce/CeTaskCharacteristicDto.java | 2 + .../sonar/server/ce/ws/ActivityAction.java | 3 +- .../sonar/server/ce/ws/ComponentAction.java | 29 +++++- .../org/sonar/server/ce/ws/TaskAction.java | 4 +- .../org/sonar/server/ce/ws/TaskFormatter.java | 64 ++++++++++-- .../server/ce/ws/ActivityActionTest.java | 46 ++++++++- .../server/ce/ws/ComponentActionTest.java | 98 +++++++++++++++++-- .../sonar/server/ce/ws/TaskActionTest.java | 48 +++++++++ .../ws/client/ce/CeWsParameters.java | 1 + sonar-ws/src/main/protobuf/ws-ce.proto | 2 + 10 files changed, 270 insertions(+), 27 deletions(-) diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskCharacteristicDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskCharacteristicDto.java index 06fbcfac5c8..7a60a07f986 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskCharacteristicDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskCharacteristicDto.java @@ -22,6 +22,8 @@ package org.sonar.db.ce; public class CeTaskCharacteristicDto { public static final String INCREMENTAL_KEY = "incremental"; + public static final String BRANCH_KEY = "branch"; + public static final String BRANCH_TYPE_KEY = "branchType"; private String uuid; private String taskUuid; diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityAction.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityAction.java index 928a4bdc80e..598a574e6fa 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityAction.java @@ -101,7 +101,8 @@ public class ActivityAction implements CeWsAction { .setChangelog( new Change("5.5", "it's no more possible to specify the page parameter.<"), new Change("6.1", "field \"logs\" is deprecated and its value is always false"), - new Change("6.6", "field \"incremental\" is added")) + new Change("6.6", "field \"incremental\" is added"), + new Change("6.6", "fields \"branch\" and \"branchType\" added")) .setSince("5.2"); action.createParam(PARAM_COMPONENT_ID) diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ComponentAction.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ComponentAction.java index ae371a6b37c..a842073aaba 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ComponentAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ComponentAction.java @@ -36,16 +36,18 @@ import org.sonar.server.component.ComponentFinder; import org.sonar.server.user.UserSession; import org.sonar.server.ws.KeyExamples; +import static com.google.common.base.Preconditions.checkArgument; import static org.sonar.db.Pagination.forPage; import static org.sonar.server.component.ComponentFinder.ParamNames.COMPONENT_ID_AND_KEY; +import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; import static org.sonar.server.ws.WsUtils.writeProtobuf; import static org.sonarqube.ws.WsCe.ProjectResponse; +import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_BRANCH; +import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_ID; +import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_KEY; public class ComponentAction implements CeWsAction { - public static final String PARAM_COMPONENT_ID = "componentId"; - public static final String PARAM_COMPONENT_KEY = "componentKey"; - private final UserSession userSession; private final DbClient dbClient; private final TaskFormatter formatter; @@ -69,7 +71,8 @@ public class ComponentAction implements CeWsAction { .setResponseExample(getClass().getResource("component-example.json")) .setChangelog( new Change("6.1", "field \"logs\" is deprecated and its value is always false"), - new Change("6.6", "field \"incremental\" is added")) + new Change("6.6", "field \"incremental\" is added"), + new Change("6.6", "fields \"branch\" and \"branchType\" added")) .setHandler(this); action.createParam(PARAM_COMPONENT_ID) @@ -79,12 +82,17 @@ public class ComponentAction implements CeWsAction { action.createParam(PARAM_COMPONENT_KEY) .setRequired(false) .setExampleValue(KeyExamples.KEY_PROJECT_EXAMPLE_001); + + action.createParam(PARAM_BRANCH) + .setDescription("Branch key") + .setInternal(true) + .setExampleValue(KEY_BRANCH_EXAMPLE_001); } @Override public void handle(Request wsRequest, Response wsResponse) throws Exception { try (DbSession dbSession = dbClient.openSession(false)) { - ComponentDto component = componentFinder.getByUuidOrKey(dbSession, wsRequest.param(PARAM_COMPONENT_ID), wsRequest.param(PARAM_COMPONENT_KEY), COMPONENT_ID_AND_KEY); + ComponentDto component = loadComponent(dbSession, wsRequest); userSession.checkComponentPermission(UserRole.USER, component); List queueDtos = dbClient.ceQueueDao().selectByComponentUuid(dbSession, component.uuid()); CeTaskQuery activityQuery = new CeTaskQuery() @@ -100,4 +108,15 @@ public class ComponentAction implements CeWsAction { writeProtobuf(wsResponseBuilder.build(), wsRequest, wsResponse); } } + + private ComponentDto loadComponent(DbSession dbSession, Request wsRequest) { + String componentKey = wsRequest.param(PARAM_COMPONENT_KEY); + String componentId = wsRequest.param(PARAM_COMPONENT_ID); + String branch = wsRequest.param(PARAM_BRANCH); + checkArgument(componentId == null || branch == null, "'%s' and '%s' parameters cannot be used at the same time", PARAM_COMPONENT_ID, + PARAM_BRANCH); + return branch == null + ? componentFinder.getByUuidOrKey(dbSession, componentId, componentKey, COMPONENT_ID_AND_KEY) + : componentFinder.getByKeyAndBranch(dbSession, componentKey, branch); + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskAction.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskAction.java index ed086869839..40b7b408928 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskAction.java @@ -73,7 +73,9 @@ public class TaskAction implements CeWsAction { "Since 6.1, field \"logs\" is deprecated and its value is always false.") .setResponseExample(getClass().getResource("task-example.json")) .setSince("5.2") - .setChangelog(new Change("6.6", "field \"incremental\" is added")) + .setChangelog( + new Change("6.6", "field \"incremental\" is added"), + new Change("6.6", "fields \"branch\" and \"branchType\" added")) .setHandler(this); action diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskFormatter.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskFormatter.java index a148896ab15..6e218184800 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskFormatter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskFormatter.java @@ -27,6 +27,7 @@ import java.util.Date; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import javax.annotation.CheckForNull; @@ -39,12 +40,15 @@ import org.sonar.db.DbSession; import org.sonar.db.ce.CeActivityDto; import org.sonar.db.ce.CeQueueDto; import org.sonar.db.ce.CeTaskCharacteristicDto; +import org.sonar.db.component.BranchDto; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.SnapshotDto; import org.sonar.db.organization.OrganizationDto; +import org.sonarqube.ws.Common; import org.sonarqube.ws.WsCe; import static com.google.common.base.Preconditions.checkState; +import static java.lang.String.format; import static java.util.Collections.singletonList; import static org.sonar.api.utils.DateUtils.formatDateTime; import static org.sonar.core.util.Protobuf.setNullable; @@ -79,7 +83,7 @@ public class TaskFormatter { setNullable(organizationKey, builder::setOrganization); if (dto.getComponentUuid() != null) { builder.setComponentId(dto.getComponentUuid()); - buildComponent(builder, componentDtoCache.getComponent(dto.getComponentUuid())); + buildComponent(builder, dto.getComponentUuid(), componentDtoCache); } builder.setId(dto.getUuid()); builder.setStatus(WsCe.TaskStatus.valueOf(dto.getStatus().name())); @@ -90,6 +94,12 @@ public class TaskFormatter { setNullable(dto.getStartedAt(), builder::setStartedAt, DateUtils::formatDateTime); setNullable(computeExecutionTimeMs(dto), builder::setExecutionTimeMs); builder.setIncremental(componentDtoCache.hasIncrementalCharacteristic(dto.getUuid())); + componentDtoCache.getBranchName(dto.getUuid()).ifPresent( + b -> { + builder.setBranch(b); + builder.setBranchType(componentDtoCache.getBranchType(dto.getUuid()) + .orElseThrow(() -> new IllegalStateException(format("Could not find branch type of '%s'", dto.getUuid())))); + }); return builder.build(); } @@ -113,7 +123,7 @@ public class TaskFormatter { builder.setStatus(WsCe.TaskStatus.valueOf(dto.getStatus().name())); builder.setType(dto.getTaskType()); builder.setLogs(false); - setNullable(dto.getComponentUuid(), uuid -> buildComponent(builder, componentDtoCache.getComponent(uuid)).setComponentId(uuid)); + setNullable(dto.getComponentUuid(), uuid -> buildComponent(builder, uuid, componentDtoCache).setComponentId(uuid)); String analysisUuid = dto.getAnalysisUuid(); if (analysisUuid != null) { builder.setAnalysisId(analysisUuid); @@ -133,12 +143,20 @@ public class TaskFormatter { return builder.build(); } - private static WsCe.Task.Builder buildComponent(WsCe.Task.Builder builder, @Nullable ComponentDto componentDto) { - if (componentDto != null) { - builder.setComponentKey(componentDto.getDbKey()); - builder.setComponentName(componentDto.name()); - builder.setComponentQualifier(componentDto.qualifier()); + private static WsCe.Task.Builder buildComponent(WsCe.Task.Builder builder, @Nullable String componentUuid, DtoCache componentDtoCache) { + ComponentDto componentDto = componentDtoCache.getComponent(componentUuid); + if (componentDto == null) { + return builder; } + builder.setComponentKey(componentDto.getKey()); + builder.setComponentName(componentDto.name()); + builder.setComponentQualifier(componentDto.qualifier()); + String branch = componentDto.getBranch(); + if (branch == null) { + return builder; + } + builder.setBranch(branch); + builder.setBranchType(Common.BranchType.valueOf(componentDtoCache.getBranch(componentUuid).getBranchType().name())); return builder; } @@ -146,14 +164,16 @@ public class TaskFormatter { private final Map componentsByUuid; private final Map organizationsByUuid; private final Map analysisByUuid; + private final Map branchesByUuid; private final Multimap characteristicsByTaskUuid; private DtoCache(Map componentsByUuid, Map organizationsByUuid, Map analysisByUuid, - Multimap characteristicsByTaskUuid) { + Multimap characteristicsByTaskUuid, Map branchesByUuid) { this.componentsByUuid = componentsByUuid; this.organizationsByUuid = organizationsByUuid; this.analysisByUuid = analysisByUuid; this.characteristicsByTaskUuid = characteristicsByTaskUuid; + this.branchesByUuid = branchesByUuid; } static DtoCache forQueueDtos(DbClient dbClient, DbSession dbSession, Collection ceQueueDtos) { @@ -163,7 +183,10 @@ public class TaskFormatter { Multimap characteristicsByTaskUuid = dbClient.ceTaskCharacteristicsDao() .selectByTaskUuids(dbSession, ceQueueDtos.stream().map(CeQueueDto::getUuid).collect(Collectors.toList())) .stream().collect(MoreCollectors.index(CeTaskCharacteristicDto::getTaskUuid)); - return new DtoCache(componentsByUuid, buildOrganizationsByUuid(dbClient, dbSession, componentsByUuid), Collections.emptyMap(), characteristicsByTaskUuid); + Map branchesByUuid = dbClient.branchDao().selectByUuids(dbSession, componentsByUuid.keySet()).stream() + .collect(MoreCollectors.uniqueIndex(BranchDto::getUuid)); + return new DtoCache(componentsByUuid, buildOrganizationsByUuid(dbClient, dbSession, componentsByUuid), Collections.emptyMap(), characteristicsByTaskUuid, + branchesByUuid); } private static Set uuidOfCeQueueDtos(Collection ceQueueDtos) { @@ -182,8 +205,10 @@ public class TaskFormatter { .collect(MoreCollectors.uniqueIndex(ComponentDto::uuid)); Set analysisUuids = ceActivityDtos.stream().map(CeActivityDto::getAnalysisUuid).filter(Objects::nonNull).collect(MoreCollectors.toSet()); Map analysisByUuid = dbClient.snapshotDao().selectByUuids(dbSession, analysisUuids).stream().collect(MoreCollectors.uniqueIndex(SnapshotDto::getUuid)); + Map branchesByUuid = dbClient.branchDao().selectByUuids(dbSession, componentsByUuid.keySet()).stream() + .collect(MoreCollectors.uniqueIndex(BranchDto::getUuid)); return new DtoCache(componentsByUuid, buildOrganizationsByUuid(dbClient, dbSession, componentsByUuid), analysisByUuid, - ImmutableMultimap.builder().build()); + ImmutableMultimap.builder().build(), branchesByUuid); } private static Set uuidOfCeActivityDtos(Collection ceActivityDtos) { @@ -232,11 +257,30 @@ public class TaskFormatter { return analysisByUuid.get(analysisUuid); } + @CheckForNull + BranchDto getBranch(String componentUuid) { + return branchesByUuid.get(componentUuid); + } + boolean hasIncrementalCharacteristic(String taskUuid) { return characteristicsByTaskUuid.get(taskUuid).stream() .filter(c -> c.getKey().equals(CeTaskCharacteristicDto.INCREMENTAL_KEY)) .anyMatch(c -> c.getValue().equals("true")); } + + Optional getBranchName(String taskUuid) { + return characteristicsByTaskUuid.get(taskUuid).stream() + .filter(c -> c.getKey().equals(CeTaskCharacteristicDto.BRANCH_KEY)) + .map(CeTaskCharacteristicDto::getValue) + .findAny(); + } + + Optional getBranchType(String taskUuid) { + return characteristicsByTaskUuid.get(taskUuid).stream() + .filter(c -> c.getKey().equals(CeTaskCharacteristicDto.BRANCH_TYPE_KEY)) + .map(c -> Common.BranchType.valueOf(c.getValue())) + .findAny(); + } } /** diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java index 590ccb33ce0..57e4354b7e4 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java @@ -50,6 +50,7 @@ import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.TestResponse; import org.sonar.server.ws.WsActionTester; import org.sonar.test.JsonAssert; +import org.sonarqube.ws.Common; import org.sonarqube.ws.MediaTypes; import org.sonarqube.ws.WsCe; import org.sonarqube.ws.WsCe.ActivityResponse; @@ -65,7 +66,10 @@ import static org.sonar.db.ce.CeActivityDto.Status.FAILED; import static org.sonar.db.ce.CeActivityDto.Status.SUCCESS; import static org.sonar.db.ce.CeQueueDto.Status.IN_PROGRESS; import static org.sonar.db.ce.CeQueueDto.Status.PENDING; +import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_KEY; +import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_TYPE_KEY; import static org.sonar.db.ce.CeTaskCharacteristicDto.INCREMENTAL_KEY; +import static org.sonar.db.component.BranchType.LONG; import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_ID; import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_QUERY; import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_MAX_EXECUTED_AT; @@ -405,8 +409,46 @@ public class ActivityActionTest { .extracting(Task::getId, Task::getIncremental) .containsExactlyInAnyOrder( tuple("T1", true), - tuple("T2", true) - ); + tuple("T2", true)); + } + + @Test + public void long_living_branch_in_past_activity() { + logInAsSystemAdministrator(); + ComponentDto project = db.components().insertMainBranch(); + userSession.addProjectPermission(UserRole.USER, project); + ComponentDto longLivingBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(LONG)); + SnapshotDto analysis = db.components().insertSnapshot(longLivingBranch); + insertActivity("T1", longLivingBranch, SUCCESS, analysis); + + ActivityResponse response = ws.newRequest().executeProtobuf(ActivityResponse.class); + + assertThat(response.getTasksList()) + .extracting(Task::getId, WsCe.Task::getBranch, WsCe.Task::getBranchType, WsCe.Task::getStatus, WsCe.Task::getComponentKey) + .containsExactlyInAnyOrder( + tuple("T1", longLivingBranch.getBranch(), Common.BranchType.LONG, WsCe.TaskStatus.SUCCESS, longLivingBranch.getKey())); + } + + @Test + public void long_living_branch_in_queue_analysis() { + logInAsSystemAdministrator(); + String branch = "ny_branch"; + CeQueueDto queue1 = insertQueue("T1", null, IN_PROGRESS); + insertCharacteristic(queue1, BRANCH_KEY, branch); + insertCharacteristic(queue1, BRANCH_TYPE_KEY, LONG.name()); + CeQueueDto queue2 = insertQueue("T2", null, PENDING); + insertCharacteristic(queue2, BRANCH_KEY, branch); + insertCharacteristic(queue2, BRANCH_TYPE_KEY, LONG.name()); + + ActivityResponse response = ws.newRequest() + .setParam("status", "FAILED,IN_PROGRESS,PENDING") + .executeProtobuf(ActivityResponse.class); + + assertThat(response.getTasksList()) + .extracting(Task::getId, WsCe.Task::getBranch, WsCe.Task::getBranchType, WsCe.Task::getStatus) + .containsExactlyInAnyOrder( + tuple("T1", branch, Common.BranchType.LONG, WsCe.TaskStatus.IN_PROGRESS), + tuple("T2", branch, Common.BranchType.LONG, WsCe.TaskStatus.PENDING)); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ComponentActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ComponentActionTest.java index afecd31d24a..9672520e1eb 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ComponentActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ComponentActionTest.java @@ -40,15 +40,23 @@ import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsActionTester; +import org.sonarqube.ws.Common; import org.sonarqube.ws.MediaTypes; import org.sonarqube.ws.WsCe; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Java6Assertions.tuple; import static org.sonar.db.ce.CeActivityDto.Status.SUCCESS; +import static org.sonar.db.ce.CeQueueDto.Status.IN_PROGRESS; +import static org.sonar.db.ce.CeQueueDto.Status.PENDING; +import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_KEY; +import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_TYPE_KEY; import static org.sonar.db.ce.CeTaskCharacteristicDto.INCREMENTAL_KEY; -import static org.sonar.server.ce.ws.ComponentAction.PARAM_COMPONENT_ID; -import static org.sonar.server.ce.ws.ComponentAction.PARAM_COMPONENT_KEY; +import static org.sonar.db.component.BranchType.LONG; +import static org.sonar.db.component.ComponentTesting.newFileDto; +import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_ID; +import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_KEY; +import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_BRANCH; public class ComponentActionTest { @@ -86,8 +94,8 @@ public class ComponentActionTest { insertActivity("T1", project1, CeActivityDto.Status.SUCCESS, analysisProject1); insertActivity("T2", project2, CeActivityDto.Status.FAILED, null); insertActivity("T3", project1, CeActivityDto.Status.FAILED, null); - insertQueue("T4", project1, CeQueueDto.Status.IN_PROGRESS); - insertQueue("T5", project1, CeQueueDto.Status.PENDING); + insertQueue("T4", project1, IN_PROGRESS); + insertQueue("T5", project1, PENDING); WsCe.ProjectResponse response = ws.newRequest() .setParam("componentId", project1.uuid()) @@ -177,9 +185,9 @@ public class ComponentActionTest { OrganizationDto organization = db.organizations().insert(); ComponentDto project = db.components().insertPrivateProject(organization); userSession.addProjectPermission(UserRole.USER, project); - CeQueueDto queue1 = insertQueue("T1", project, CeQueueDto.Status.IN_PROGRESS); + CeQueueDto queue1 = insertQueue("T1", project, IN_PROGRESS); insertCharacteristic(queue1, INCREMENTAL_KEY, "true"); - CeQueueDto queue2 = insertQueue("T2", project, CeQueueDto.Status.PENDING); + CeQueueDto queue2 = insertQueue("T2", project, PENDING); insertCharacteristic(queue2, INCREMENTAL_KEY, "true"); WsCe.ProjectResponse response = ws.newRequest() @@ -190,8 +198,50 @@ public class ComponentActionTest { .extracting(WsCe.Task::getId, WsCe.Task::getIncremental) .containsOnly( tuple("T1", true), - tuple("T2", true) - ); + tuple("T2", true)); + } + + @Test + public void long_living_branch_in_activity() { + ComponentDto project = db.components().insertMainBranch(); + userSession.addProjectPermission(UserRole.USER, project); + ComponentDto longLivingBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(LONG)); + SnapshotDto analysis = db.components().insertSnapshot(longLivingBranch); + insertActivity("T1", longLivingBranch, SUCCESS, analysis); + + WsCe.ProjectResponse response = ws.newRequest() + .setParam("componentKey", longLivingBranch.getKey()) + .setParam("branch", longLivingBranch.getBranch()) + .executeProtobuf(WsCe.ProjectResponse.class); + + assertThat(response.getCurrent()) + .extracting(WsCe.Task::getId, WsCe.Task::getBranch, WsCe.Task::getBranchType, WsCe.Task::getStatus, WsCe.Task::getComponentKey) + .containsOnly( + "T1", longLivingBranch.getBranch(), Common.BranchType.LONG, WsCe.TaskStatus.SUCCESS, longLivingBranch.getKey()); + } + + @Test + public void long_living_branch_in_queue_analysis() { + ComponentDto project = db.components().insertMainBranch(); + userSession.addProjectPermission(UserRole.USER, project); + ComponentDto longLivingBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(LONG)); + CeQueueDto queue1 = insertQueue("T1", longLivingBranch, IN_PROGRESS); + insertCharacteristic(queue1, BRANCH_KEY, longLivingBranch.getBranch()); + insertCharacteristic(queue1, BRANCH_TYPE_KEY, LONG.name()); + CeQueueDto queue2 = insertQueue("T2", longLivingBranch, PENDING); + insertCharacteristic(queue2, BRANCH_KEY, longLivingBranch.getBranch()); + insertCharacteristic(queue2, BRANCH_TYPE_KEY, LONG.name()); + + WsCe.ProjectResponse response = ws.newRequest() + .setParam("componentKey", longLivingBranch.getKey()) + .setParam("branch", longLivingBranch.getBranch()) + .executeProtobuf(WsCe.ProjectResponse.class); + + assertThat(response.getQueueList()) + .extracting(WsCe.Task::getId, WsCe.Task::getBranch, WsCe.Task::getBranchType, WsCe.Task::getStatus, WsCe.Task::getComponentKey) + .containsOnly( + tuple("T1", longLivingBranch.getBranch(), Common.BranchType.LONG, WsCe.TaskStatus.IN_PROGRESS, longLivingBranch.getKey()), + tuple("T2", longLivingBranch.getBranch(), Common.BranchType.LONG, WsCe.TaskStatus.PENDING, longLivingBranch.getKey())); } @Test @@ -224,6 +274,38 @@ public class ComponentActionTest { ws.newRequest().execute(); } + @Test + public void fail_if_branch_does_not_exist() { + ComponentDto project = db.components().insertPrivateProject(); + ComponentDto file = db.components().insertComponent(newFileDto(project)); + userSession.addProjectPermission(UserRole.USER, project); + db.components().insertProjectBranch(project, b -> b.setKey("my_branch")); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage(String.format("Component '%s' on branch '%s' not found", file.getKey(), "another_branch")); + + ws.newRequest() + .setParam(PARAM_COMPONENT_KEY, file.getKey()) + .setParam(PARAM_BRANCH, "another_branch") + .execute(); + } + + @Test + public void fail_when_componentId_and_branch_params_are_used_together() { + ComponentDto project = db.components().insertPrivateProject(); + ComponentDto file = db.components().insertComponent(newFileDto(project)); + userSession.addProjectPermission(UserRole.USER, project); + db.components().insertProjectBranch(project, b -> b.setKey("my_branch")); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("'componentId' and 'branch' parameters cannot be used at the same time"); + + ws.newRequest() + .setParam(PARAM_COMPONENT_ID, file.uuid()) + .setParam(PARAM_BRANCH, "my_branch") + .execute(); + } + private void logInWithBrowsePermission(ComponentDto project) { userSession.logIn().addProjectPermission(UserRole.USER, project); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskActionTest.java index 038f227104b..efee0ee2c4d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskActionTest.java @@ -26,6 +26,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.utils.System2; +import org.sonar.api.web.UserRole; import org.sonar.core.permission.GlobalPermissions; import org.sonar.core.util.CloseableIterator; import org.sonar.core.util.Uuids; @@ -41,10 +42,14 @@ import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsActionTester; +import org.sonarqube.ws.Common; import org.sonarqube.ws.WsCe; import static java.util.Collections.singleton; import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_KEY; +import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_TYPE_KEY; +import static org.sonar.db.component.BranchType.LONG; import static org.sonar.db.permission.OrganizationPermission.SCAN; public class TaskActionTest { @@ -159,6 +164,49 @@ public class TaskActionTest { assertThat(taskResponse.getTask().getIncremental()).isTrue(); } + @Test + public void long_living_branch_in_past_activity() { + logInAsRoot(); + ComponentDto project = db.components().insertMainBranch(); + userSession.addProjectPermission(UserRole.USER, project); + ComponentDto longLivingBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(LONG)); + SnapshotDto analysis = db.components().insertSnapshot(longLivingBranch); + CeQueueDto queueDto = new CeQueueDto() + .setTaskType(CeTaskTypes.REPORT) + .setUuid(SOME_TASK_UUID) + .setComponentUuid(longLivingBranch.uuid()); + CeActivityDto activityDto = new CeActivityDto(queueDto) + .setStatus(CeActivityDto.Status.FAILED) + .setExecutionTimeMs(500L) + .setAnalysisUuid(analysis.getUuid()); + persist(activityDto); + + WsCe.TaskResponse taskResponse = ws.newRequest() + .setParam("id", SOME_TASK_UUID) + .executeProtobuf(WsCe.TaskResponse.class); + + assertThat(taskResponse.getTask()) + .extracting(WsCe.Task::getId, WsCe.Task::getBranch, WsCe.Task::getBranchType, WsCe.Task::getComponentKey) + .containsExactlyInAnyOrder(SOME_TASK_UUID, longLivingBranch.getBranch(), Common.BranchType.LONG, longLivingBranch.getKey()); + } + + @Test + public void long_living_branch_in_queue_analysis() { + logInAsRoot(); + String branch = "my_branch"; + CeQueueDto queueDto = createAndPersistQueueTask(null); + insertCharacteristic(queueDto, BRANCH_KEY, branch); + insertCharacteristic(queueDto, BRANCH_TYPE_KEY, LONG.name()); + + WsCe.TaskResponse taskResponse = ws.newRequest() + .setParam("id", SOME_TASK_UUID) + .executeProtobuf(WsCe.TaskResponse.class); + + assertThat(taskResponse.getTask()) + .extracting(WsCe.Task::getId, WsCe.Task::getBranch, WsCe.Task::getBranchType, WsCe.Task::hasComponentKey) + .containsExactlyInAnyOrder(SOME_TASK_UUID, branch, Common.BranchType.LONG, false); + } + @Test public void return_stacktrace_of_failed_activity_with_stacktrace_when_additionalField_is_set() { logInAsRoot(); diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeWsParameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeWsParameters.java index 77cbbd673e0..680051f2dd2 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeWsParameters.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeWsParameters.java @@ -31,6 +31,7 @@ public class CeWsParameters { public static final String PARAM_ONLY_CURRENTS = "onlyCurrents"; public static final String PARAM_MIN_SUBMITTED_AT = "minSubmittedAt"; public static final String PARAM_MAX_EXECUTED_AT = "maxExecutedAt"; + public static final String PARAM_BRANCH = "branch"; private CeWsParameters() { // prevent instantiation diff --git a/sonar-ws/src/main/protobuf/ws-ce.proto b/sonar-ws/src/main/protobuf/ws-ce.proto index a268b7bcbd6..87ec36a7fcf 100644 --- a/sonar-ws/src/main/protobuf/ws-ce.proto +++ b/sonar-ws/src/main/protobuf/ws-ce.proto @@ -90,6 +90,8 @@ message Task { optional bool hasScannerContext = 19; optional string organization = 20; optional bool incremental = 21; + optional string branch = 22; + optional sonarqube.ws.commons.BranchType branchType = 23; } enum TaskStatus { -- 2.39.5