]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9616 Return branch info in api/ce ws
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 16 Aug 2017 18:06:36 +0000 (20:06 +0200)
committerJanos Gyerik <janos.gyerik@sonarsource.com>
Tue, 12 Sep 2017 08:59:56 +0000 (10:59 +0200)
server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskCharacteristicDto.java
server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityAction.java
server/sonar-server/src/main/java/org/sonar/server/ce/ws/ComponentAction.java
server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskAction.java
server/sonar-server/src/main/java/org/sonar/server/ce/ws/TaskFormatter.java
server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java
server/sonar-server/src/test/java/org/sonar/server/ce/ws/ComponentActionTest.java
server/sonar-server/src/test/java/org/sonar/server/ce/ws/TaskActionTest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeWsParameters.java
sonar-ws/src/main/protobuf/ws-ce.proto

index 06fbcfac5c8c3a8e3a9214ee6173d87dfaecbb89..7a60a07f98634f697ab205de8c92a63b0eb3e196 100644 (file)
@@ -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;
index 928a4bdc80e6a7a15389a785711ee1473af55f84..598a574e6fa271d6f55f1595ec39aa1ada62d903 100644 (file)
@@ -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)
index ae371a6b37ce04e06722d67b383025ce5e3ea625..a842073aabae016b2c1d113dc13e1a4ccf153df5 100644 (file)
@@ -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<CeQueueDto> 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);
+  }
 }
index ed0868698390b032076e450154d39f14d05cd9aa..40b7b4089284b2baa03f7d9dff2ab822dea6160a 100644 (file)
@@ -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
index a148896ab159477b0bca7cf9df058624954be055..6e218184800e3927c467b18e91a822b0bbfc7268 100644 (file)
@@ -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<String, ComponentDto> componentsByUuid;
     private final Map<String, OrganizationDto> organizationsByUuid;
     private final Map<String, SnapshotDto> analysisByUuid;
+    private final Map<String, BranchDto> branchesByUuid;
     private final Multimap<String, CeTaskCharacteristicDto> characteristicsByTaskUuid;
 
     private DtoCache(Map<String, ComponentDto> componentsByUuid, Map<String, OrganizationDto> organizationsByUuid, Map<String, SnapshotDto> analysisByUuid,
-      Multimap<String, CeTaskCharacteristicDto> characteristicsByTaskUuid) {
+      Multimap<String, CeTaskCharacteristicDto> characteristicsByTaskUuid, Map<String, BranchDto> branchesByUuid) {
       this.componentsByUuid = componentsByUuid;
       this.organizationsByUuid = organizationsByUuid;
       this.analysisByUuid = analysisByUuid;
       this.characteristicsByTaskUuid = characteristicsByTaskUuid;
+      this.branchesByUuid = branchesByUuid;
     }
 
     static DtoCache forQueueDtos(DbClient dbClient, DbSession dbSession, Collection<CeQueueDto> ceQueueDtos) {
@@ -163,7 +183,10 @@ public class TaskFormatter {
       Multimap<String, CeTaskCharacteristicDto> 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<String, BranchDto> 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<String> uuidOfCeQueueDtos(Collection<CeQueueDto> ceQueueDtos) {
@@ -182,8 +205,10 @@ public class TaskFormatter {
         .collect(MoreCollectors.uniqueIndex(ComponentDto::uuid));
       Set<String> analysisUuids = ceActivityDtos.stream().map(CeActivityDto::getAnalysisUuid).filter(Objects::nonNull).collect(MoreCollectors.toSet());
       Map<String, SnapshotDto> analysisByUuid = dbClient.snapshotDao().selectByUuids(dbSession, analysisUuids).stream().collect(MoreCollectors.uniqueIndex(SnapshotDto::getUuid));
+      Map<String, BranchDto> branchesByUuid = dbClient.branchDao().selectByUuids(dbSession, componentsByUuid.keySet()).stream()
+        .collect(MoreCollectors.uniqueIndex(BranchDto::getUuid));
       return new DtoCache(componentsByUuid, buildOrganizationsByUuid(dbClient, dbSession, componentsByUuid), analysisByUuid,
-        ImmutableMultimap.<String, CeTaskCharacteristicDto>builder().build());
+        ImmutableMultimap.<String, CeTaskCharacteristicDto>builder().build(), branchesByUuid);
     }
 
     private static Set<String> uuidOfCeActivityDtos(Collection<CeActivityDto> 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<String> getBranchName(String taskUuid) {
+      return characteristicsByTaskUuid.get(taskUuid).stream()
+        .filter(c -> c.getKey().equals(CeTaskCharacteristicDto.BRANCH_KEY))
+        .map(CeTaskCharacteristicDto::getValue)
+        .findAny();
+    }
+
+    Optional<Common.BranchType> 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();
+    }
   }
 
   /**
index 590ccb33ce02d42d3d66b0dceb9d178861c58201..57e4354b7e4f8da263ddcc5110f29cbbb9560081 100644 (file)
@@ -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
index afecd31d24a456e8ed67f747b154208e5b83c8bd..9672520e1eb77a107f16da4169d72258e49a4c67 100644 (file)
@@ -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);
   }
index 038f227104ba9b3a258a60b3e465da00166c348f..efee0ee2c4d2c3f740637625dfaab68dd869dcea 100644 (file)
@@ -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();
index 77cbbd673e032f98f11d6a9d20b73add1cb1b9aa..680051f2dd2395d161cd8c6fcc41a0c61299a832 100644 (file)
@@ -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
index a268b7bcbd6847522845269c670bd67abd1e9014..87ec36a7fcf634974ba83f7481b817d6db655696 100644 (file)
@@ -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 {