]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10347 Add pagination to webhook deliveries search ws.
authorGuillaume Jambet <guillaume.jambet@sonarsource.com>
Thu, 15 Feb 2018 13:54:15 +0000 (14:54 +0100)
committerGuillaume Jambet <guillaume.jambet@gmail.com>
Thu, 1 Mar 2018 14:21:05 +0000 (15:21 +0100)
server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDeliveryDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDeliveryMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/webhook/WebhookDeliveryMapper.xml
server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookDeliveryDaoTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookTesting.java
server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhookDeliveriesAction.java
server/sonar-server/src/main/resources/org/sonar/server/webhook/ws/example-delivery.json
server/sonar-server/src/test/java/org/sonar/server/webhook/ws/WebhookDeliveriesActionTest.java
sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java
sonar-ws/src/main/protobuf/ws-webhooks.proto

index 2060cad60f7afb1a9a5aae860a3b68bbd97426e2..e8e63d856af7d845b0f4a6aeb715754b92b5886a 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.db.webhook;
 
 import java.util.List;
 import java.util.Optional;
+import org.apache.ibatis.session.RowBounds;
 import org.sonar.db.Dao;
 import org.sonar.db.DbSession;
 
@@ -30,25 +31,37 @@ public class WebhookDeliveryDao implements Dao {
     return Optional.ofNullable(mapper(dbSession).selectByUuid(uuid));
   }
 
+  public int countDeliveriesByWebhookUuid(DbSession dbSession, String webhookUuid) {
+    return mapper(dbSession).countByWebhookUuid(webhookUuid);
+  }
+
   /**
    * All the deliveries for the specified webhook. Results are ordered by descending date.
    */
-  public List<WebhookDeliveryLiteDto> selectByWebhookUuid(DbSession dbSession, String webhookUuid) {
-    return mapper(dbSession).selectByWebhookUuid(webhookUuid);
+  public List<WebhookDeliveryLiteDto> selectByWebhookUuid(DbSession dbSession, String webhookUuid, int offset, int limit) {
+    return mapper(dbSession).selectByWebhookUuid(webhookUuid, new RowBounds(offset, limit));
+  }
+
+  public int countDeliveriesByComponentUuid(DbSession dbSession, String componentUuid) {
+    return mapper(dbSession).countByComponentUuid(componentUuid);
   }
 
   /**
    * All the deliveries for the specified component. Results are ordered by descending date.
    */
-  public List<WebhookDeliveryLiteDto> selectOrderedByComponentUuid(DbSession dbSession, String componentUuid) {
-    return mapper(dbSession).selectOrderedByComponentUuid(componentUuid);
+  public List<WebhookDeliveryLiteDto> selectOrderedByComponentUuid(DbSession dbSession, String componentUuid, int offset, int limit) {
+    return mapper(dbSession).selectOrderedByComponentUuid(componentUuid, new RowBounds(offset, limit));
+  }
+
+  public int countDeliveriesByCeTaskUuid(DbSession dbSession, String ceTaskId) {
+    return mapper(dbSession).countByCeTaskUuid(ceTaskId);
   }
 
   /**
    * All the deliveries for the specified CE task. Results are ordered by descending date.
    */
-  public List<WebhookDeliveryLiteDto> selectOrderedByCeTaskUuid(DbSession dbSession, String ceTaskUuid) {
-    return mapper(dbSession).selectOrderedByCeTaskUuid(ceTaskUuid);
+  public List<WebhookDeliveryLiteDto> selectOrderedByCeTaskUuid(DbSession dbSession, String ceTaskUuid, int offset, int limit) {
+    return mapper(dbSession).selectOrderedByCeTaskUuid(ceTaskUuid, new RowBounds(offset, limit));
   }
 
   public void insert(DbSession dbSession, WebhookDeliveryDto dto) {
index f14eb163d1e89ab8c28358b807d763a46a911b87..6436922de6cb2fffe0aee7640da75b2714fac309 100644 (file)
@@ -22,17 +22,24 @@ package org.sonar.db.webhook;
 import java.util.List;
 import javax.annotation.CheckForNull;
 import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.session.RowBounds;
 
 public interface WebhookDeliveryMapper {
 
   @CheckForNull
   WebhookDeliveryDto selectByUuid(@Param("uuid") String uuid);
 
-  List<WebhookDeliveryLiteDto> selectByWebhookUuid(@Param("webhookUuid") String webhookUuid);
+  int countByWebhookUuid(@Param("webhookUuid") String webhookUuid);
 
-  List<WebhookDeliveryLiteDto> selectOrderedByComponentUuid(@Param("componentUuid") String componentUuid);
+  List<WebhookDeliveryLiteDto> selectByWebhookUuid(@Param("webhookUuid") String webhookUuid, RowBounds rowBounds);
 
-  List<WebhookDeliveryLiteDto> selectOrderedByCeTaskUuid(@Param("ceTaskUuid") String ceTaskUuid);
+  int countByComponentUuid(@Param("componentUuid") String componentUuid);
+
+  List<WebhookDeliveryLiteDto> selectOrderedByComponentUuid(@Param("componentUuid") String componentUuid, RowBounds rowBounds);
+
+  int countByCeTaskUuid(@Param("ceTaskUuid") String ceTaskId);
+
+  List<WebhookDeliveryLiteDto> selectOrderedByCeTaskUuid(@Param("ceTaskUuid") String ceTaskUuid, RowBounds rowBounds);
 
   void insert(WebhookDeliveryDto dto);
 
index 0612c9712939dcc269deea9e075926274b9a5e00..1321fe21148a1b480c1484be833683e27c3300af 100644 (file)
     where uuid = #{uuid,jdbcType=VARCHAR}
   </select>
 
+  <select id="countByWebhookUuid" parameterType="String" resultType="int">
+    select
+    count(1)
+    from webhook_deliveries
+    where webhook_uuid = #{webhookUuid,jdbcType=VARCHAR}
+  </select>
+
   <select id="selectByWebhookUuid" parameterType="String" resultType="org.sonar.db.webhook.WebhookDeliveryLiteDto">
     select <include refid="sqlLiteColumns" />
     from webhook_deliveries
     order by created_at desc
   </select>
 
+  <select id="countByComponentUuid" parameterType="String" resultType="int">
+    select
+    count(1)
+    from webhook_deliveries
+    where component_uuid = #{componentUuid,jdbcType=VARCHAR}
+  </select>
+
   <select id="selectOrderedByComponentUuid" parameterType="String" resultType="org.sonar.db.webhook.WebhookDeliveryLiteDto">
     select <include refid="sqlLiteColumns" />
     from webhook_deliveries
     order by created_at desc
   </select>
 
+  <select id="countByCeTaskUuid" parameterType="String" resultType="int">
+    select
+    count(1)
+    from webhook_deliveries
+    where ce_task_uuid = #{ceTaskUuid,jdbcType=VARCHAR}
+  </select>
+
   <insert id="insert" parameterType="org.sonar.db.webhook.WebhookDeliveryDto" useGeneratedKeys="false">
     insert into webhook_deliveries (
     uuid,
index 025f04b196fd9f2bef6ace646ac1a340ddc8cf58..5b5470358766c6f9f33428c6f48b2b392d7bc1ba 100644 (file)
@@ -46,6 +46,8 @@ public class WebhookDeliveryDaoTest {
 
   private final DbClient dbClient = dbTester.getDbClient();
   private final DbSession dbSession = dbTester.getSession();
+  private final WebhookDbTester dbWebhooks = dbTester.webhooks();
+
   private final WebhookDeliveryDao underTest = dbClient.webhookDeliveryDao();
 
   @Test
@@ -55,53 +57,97 @@ public class WebhookDeliveryDaoTest {
 
   @Test
   public void selectOrderedByComponentUuid_returns_empty_if_no_records() {
-    underTest.insert(dbSession, newDto("D1", "COMPONENT_1", "TASK_1"));
+    underTest.insert(dbSession, newDto("D1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1"));
 
-    List<WebhookDeliveryLiteDto> deliveries = underTest.selectOrderedByComponentUuid(dbSession, "ANOTHER_COMPONENT");
+    List<WebhookDeliveryLiteDto> deliveries = underTest.selectOrderedByComponentUuid(dbSession, "ANOTHER_COMPONENT", 0, 10);
 
     assertThat(deliveries).isEmpty();
   }
 
   @Test
   public void selectOrderedByComponentUuid_returns_records_ordered_by_date() {
-    WebhookDeliveryDto dto1 = newDto("D1", "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE);
-    WebhookDeliveryDto dto2 = newDto("D2", "COMPONENT_1", "TASK_1").setCreatedAt(NOW);
-    WebhookDeliveryDto dto3 = newDto("D3", "COMPONENT_2", "TASK_1").setCreatedAt(NOW);
+    WebhookDeliveryDto dto1 = newDto("D1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE);
+    WebhookDeliveryDto dto2 = newDto("D2", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(NOW);
+    WebhookDeliveryDto dto3 = newDto("D3", "WEBHOOK_UUID_1", "COMPONENT_2", "TASK_1").setCreatedAt(NOW);
     underTest.insert(dbSession, dto3);
     underTest.insert(dbSession, dto2);
     underTest.insert(dbSession, dto1);
 
-    List<WebhookDeliveryLiteDto> deliveries = underTest.selectOrderedByComponentUuid(dbSession, "COMPONENT_1");
+    List<WebhookDeliveryLiteDto> deliveries = underTest.selectOrderedByComponentUuid(dbSession, "COMPONENT_1", 0, 10);
 
     assertThat(deliveries).extracting(WebhookDeliveryLiteDto::getUuid).containsExactly("D2", "D1");
   }
 
   @Test
   public void selectOrderedByCeTaskUuid_returns_empty_if_no_records() {
-    underTest.insert(dbSession, newDto("D1", "COMPONENT_1", "TASK_1"));
+    underTest.insert(dbSession, newDto("D1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1"));
 
-    List<WebhookDeliveryLiteDto> deliveries = underTest.selectOrderedByCeTaskUuid(dbSession, "ANOTHER_TASK");
+    List<WebhookDeliveryLiteDto> deliveries = underTest.selectOrderedByCeTaskUuid(dbSession, "ANOTHER_TASK", 0, 10);
 
     assertThat(deliveries).isEmpty();
   }
 
   @Test
   public void selectOrderedByCeTaskUuid_returns_records_ordered_by_date() {
-    WebhookDeliveryDto dto1 = newDto("D1", "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE);
-    WebhookDeliveryDto dto2 = newDto("D2", "COMPONENT_1", "TASK_1").setCreatedAt(NOW);
-    WebhookDeliveryDto dto3 = newDto("D3", "COMPONENT_2", "TASK_2").setCreatedAt(NOW);
+    WebhookDeliveryDto dto1 = newDto("D1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE);
+    WebhookDeliveryDto dto2 = newDto("D2", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(NOW);
+    WebhookDeliveryDto dto3 = newDto("D3", "WEBHOOK_UUID_1", "COMPONENT_2", "TASK_2").setCreatedAt(NOW);
+    underTest.insert(dbSession, dto3);
+    underTest.insert(dbSession, dto2);
+    underTest.insert(dbSession, dto1);
+
+    List<WebhookDeliveryLiteDto> deliveries = underTest.selectOrderedByCeTaskUuid(dbSession, "TASK_1", 0, 10);
+
+    assertThat(deliveries).extracting(WebhookDeliveryLiteDto::getUuid).containsExactly("D2", "D1");
+  }
+
+  @Test
+  public void selectByWebhookUuid_returns_empty_if_no_records() {
+
+    underTest.insert(dbSession, newDto("D1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1"));
+
+    List<WebhookDeliveryLiteDto> deliveries = underTest.selectByWebhookUuid(dbSession, "a-webhook-uuid", 0, 10);
+
+    assertThat(deliveries).isEmpty();
+  }
+
+  @Test
+  public void selectByWebhookUuid_returns_records_ordered_by_date() {
+    WebhookDto webhookDto = dbWebhooks.insert(WebhookTesting.newProjectWebhook("COMPONENT_1"));
+    WebhookDeliveryDto dto1 = newDto("D1", webhookDto.getUuid(), "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE);
+    WebhookDeliveryDto dto2 = newDto("D2", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW);
+    WebhookDeliveryDto dto3 = newDto("D3", "fake-webhook-uuid", "COMPONENT_2", "TASK_1").setCreatedAt(NOW);
     underTest.insert(dbSession, dto3);
     underTest.insert(dbSession, dto2);
     underTest.insert(dbSession, dto1);
 
-    List<WebhookDeliveryLiteDto> deliveries = underTest.selectOrderedByCeTaskUuid(dbSession, "TASK_1");
+    List<WebhookDeliveryLiteDto> deliveries = underTest.selectByWebhookUuid(dbSession, webhookDto.getUuid(), 0, 10);
 
     assertThat(deliveries).extracting(WebhookDeliveryLiteDto::getUuid).containsExactly("D2", "D1");
   }
 
+  @Test
+  public void selectByWebhookUuid_returns_records_according_to_pagination() {
+    WebhookDto webhookDto = dbWebhooks.insert(WebhookTesting.newProjectWebhook("COMPONENT_1"));
+    WebhookDeliveryDto dto1 = newDto("D1", webhookDto.getUuid(), "COMPONENT_1", "TASK_1").setCreatedAt(BEFORE);
+    underTest.insert(dbSession, dto1);
+    WebhookDeliveryDto dto2 = newDto("D2", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW);
+    underTest.insert(dbSession, dto2);
+    underTest.insert(dbSession, newDto("D3", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW));
+    underTest.insert(dbSession, newDto("D4", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW));
+    underTest.insert(dbSession, newDto("D5", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW));
+    underTest.insert(dbSession, newDto("D6", webhookDto.getUuid(), "COMPONENT_1", "TASK_2").setCreatedAt(NOW));
+
+    List<WebhookDeliveryLiteDto> deliveries = underTest.selectByWebhookUuid(dbSession, webhookDto.getUuid(), 1, 3);
+
+    assertThat(deliveries).extracting(WebhookDeliveryLiteDto::getUuid).containsExactlyInAnyOrder("D3", "D4", "D5");
+  }
+
+
+
   @Test
   public void insert_row_with_only_mandatory_columns() {
-    WebhookDeliveryDto dto = newDto("DELIVERY_1", "COMPONENT_1", "TASK_1")
+    WebhookDeliveryDto dto = newDto("DELIVERY_1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1")
       .setHttpStatus(null)
       .setDurationMs(null)
       .setErrorStacktrace(null);
@@ -119,12 +165,13 @@ public class WebhookDeliveryDaoTest {
 
   @Test
   public void insert_row_with_all_columns() {
-    WebhookDeliveryDto dto = newDto("DELIVERY_1", "COMPONENT_1", "TASK_1");
+    WebhookDeliveryDto dto = newDto("DELIVERY_1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1");
 
     underTest.insert(dbSession, dto);
 
     WebhookDeliveryDto stored = selectByUuid(dto.getUuid());
     verifyMandatoryFields(dto, stored);
+    assertThat(stored.getWebhookUuid()).isEqualTo(dto.getWebhookUuid());
     assertThat(stored.getHttpStatus()).isEqualTo(dto.getHttpStatus());
     assertThat(stored.getDurationMs()).isEqualTo(dto.getDurationMs());
     assertThat(stored.getErrorStacktrace()).isEqualTo(dto.getErrorStacktrace());
@@ -132,9 +179,9 @@ public class WebhookDeliveryDaoTest {
 
   @Test
   public void deleteComponentBeforeDate_deletes_rows_before_date() {
-    underTest.insert(dbSession, newDto("DELIVERY_1", "COMPONENT_1", "TASK_1").setCreatedAt(1_000_000L));
-    underTest.insert(dbSession, newDto("DELIVERY_2", "COMPONENT_1", "TASK_2").setCreatedAt(2_000_000L));
-    underTest.insert(dbSession, newDto("DELIVERY_3", "COMPONENT_2", "TASK_3").setCreatedAt(1_000_000L));
+    underTest.insert(dbSession, newDto("DELIVERY_1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(1_000_000L));
+    underTest.insert(dbSession, newDto("DELIVERY_2", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_2").setCreatedAt(2_000_000L));
+    underTest.insert(dbSession, newDto("DELIVERY_3", "WEBHOOK_UUID_1", "COMPONENT_2", "TASK_3").setCreatedAt(1_000_000L));
 
     // should delete the old delivery on COMPONENT_1 and keep the one of COMPONENT_2
     underTest.deleteComponentBeforeDate(dbSession, "COMPONENT_1", 1_500_000L);
@@ -152,7 +199,7 @@ public class WebhookDeliveryDaoTest {
 
   @Test
   public void deleteComponentBeforeDate_does_nothing_on_invalid_uuid() {
-    underTest.insert(dbSession, newDto("DELIVERY_1", "COMPONENT_1", "TASK_1").setCreatedAt(1_000_000L));
+    underTest.insert(dbSession, newDto("DELIVERY_1", "WEBHOOK_UUID_1", "COMPONENT_1", "TASK_1").setCreatedAt(1_000_000L));
 
     underTest.deleteComponentBeforeDate(dbSession, "COMPONENT_2", 1_500_000L);
 
@@ -174,9 +221,10 @@ public class WebhookDeliveryDaoTest {
    * Build a {@link WebhookDeliveryDto} with all mandatory fields.
    * Optional fields are kept null.
    */
-  private static WebhookDeliveryDto newDto(String uuid, String componentUuid, String ceTaskUuid) {
+  private static WebhookDeliveryDto newDto(String uuid, String webhookUuid, String componentUuid, String ceTaskUuid) {
     return newWebhookDeliveryDto()
       .setUuid(uuid)
+      .setWebhookUuid(webhookUuid)
       .setComponentUuid(componentUuid)
       .setCeTaskUuid(ceTaskUuid);
   }
index 0c56b9ae85e332f3bc7ad7a655a59ef3654e1513..4568a13786995be74b08f0a2c555910ed4140d17 100644 (file)
@@ -36,6 +36,11 @@ public class WebhookTesting {
       .setProjectUuid(project.uuid());
   }
 
+  public static WebhookDto newProjectWebhook(String projectUuid) {
+    return getWebhookDto()
+      .setProjectUuid(projectUuid);
+  }
+
   public static WebhookDto newWebhook(OrganizationDto organizationDto) {
     return getWebhookDto()
       .setOrganizationUuid(organizationDto.getUuid());
index 685d384a9f9b6dbcfc160e99e41b698f945cf427..ee5e469f57ab792cc45a7e80e29bc142f8438adc 100644 (file)
@@ -34,12 +34,16 @@ import org.sonar.db.component.ComponentDto;
 import org.sonar.db.webhook.WebhookDeliveryLiteDto;
 import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.user.UserSession;
+import org.sonarqube.ws.Common;
 import org.sonarqube.ws.Webhooks;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.Objects.requireNonNull;
 import static org.apache.commons.lang.StringUtils.isNotBlank;
+import static org.sonar.api.server.ws.WebService.Param.PAGE;
+import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
 import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02;
+import static org.sonar.server.es.SearchOptions.MAX_LIMIT;
 import static org.sonar.server.webhook.ws.WebhookWsSupport.copyDtoToProtobuf;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
 
@@ -79,9 +83,11 @@ public class WebhookDeliveriesAction implements WebhooksWsAction {
 
     action.createParam(PARAM_WEBHOOK)
       .setSince("7.1")
-      .setDescription("Key of the webhook that triggered those deliveries,"+
+      .setDescription("Key of the webhook that triggered those deliveries," +
         "auto-generated value that can be obtained through api/webhooks/create or api/webhooks/list")
       .setExampleValue(UUID_EXAMPLE_02);
+
+    action.addPagingParamsSince(10, MAX_LIMIT, "7.1");
   }
 
   @Override
@@ -92,42 +98,60 @@ public class WebhookDeliveriesAction implements WebhooksWsAction {
     String ceTaskId = request.param(PARAM_TASK);
     String componentKey = request.param(PARAM_COMPONENT);
     String webhookUuid = request.param(PARAM_WEBHOOK);
+    int page = request.mandatoryParamAsInt(PAGE);
+    int pageSize = request.mandatoryParamAsInt(PAGE_SIZE);
 
     checkArgument(webhookUuid != null ^ (ceTaskId != null ^ componentKey != null),
       "Either '%s' or '%s' or '%s' must be provided", PARAM_TASK, PARAM_COMPONENT, PARAM_WEBHOOK);
 
-    Data data = loadFromDatabase(webhookUuid, ceTaskId, componentKey);
+    Data data = loadFromDatabase(webhookUuid, ceTaskId, componentKey, page, pageSize);
     data.ensureAdminPermission(userSession);
     data.writeTo(request, response);
   }
 
-  private Data loadFromDatabase(@Nullable String webhookUuid, @Nullable String ceTaskId, @Nullable String componentKey) {
-    ComponentDto component = null;
+  private Data loadFromDatabase(@Nullable String webhookUuid, @Nullable String ceTaskId, @Nullable String componentKey, int page, int pageSize) {
+    ComponentDto component;
     List<WebhookDeliveryLiteDto> deliveries;
+    int totalElements;
     try (DbSession dbSession = dbClient.openSession(false)) {
       if (isNotBlank(webhookUuid)) {
-        deliveries = dbClient.webhookDeliveryDao().selectByWebhookUuid(dbSession, webhookUuid);
+        deliveries = dbClient.webhookDeliveryDao().selectByWebhookUuid(dbSession, webhookUuid, page - 1, pageSize);
+        component = getComponentDto(dbSession, deliveries);
+        totalElements = dbClient.webhookDeliveryDao().countDeliveriesByWebhookUuid(dbSession, webhookUuid);
       } else if (componentKey != null) {
         component = componentFinder.getByKey(dbSession, componentKey);
-        deliveries = dbClient.webhookDeliveryDao().selectOrderedByComponentUuid(dbSession, component.uuid());
+        deliveries = dbClient.webhookDeliveryDao().selectOrderedByComponentUuid(dbSession, component.uuid(), page - 1, pageSize);
+        totalElements = dbClient.webhookDeliveryDao().countDeliveriesByComponentUuid(dbSession, component.uuid());
       } else {
-        deliveries = dbClient.webhookDeliveryDao().selectOrderedByCeTaskUuid(dbSession, ceTaskId);
-        Optional<String> deliveredComponentUuid = deliveries
-          .stream()
-          .map(WebhookDeliveryLiteDto::getComponentUuid)
-          .findFirst();
-        if (deliveredComponentUuid.isPresent()) {
-          component = componentFinder.getByUuid(dbSession, deliveredComponentUuid.get());
-        }
+        deliveries = dbClient.webhookDeliveryDao().selectOrderedByCeTaskUuid(dbSession, ceTaskId, page - 1, pageSize);
+        component = getComponentDto(dbSession, deliveries);
+        totalElements = dbClient.webhookDeliveryDao().countDeliveriesByCeTaskUuid(dbSession, ceTaskId);
       }
     }
-    return new Data(component, deliveries);
+    return new Data(component, deliveries).withPagingInfo(page, pageSize, totalElements);
+  }
+
+  private ComponentDto getComponentDto(DbSession dbSession, List<WebhookDeliveryLiteDto> deliveries) {
+    Optional<String> deliveredComponentUuid = deliveries
+      .stream()
+      .map(WebhookDeliveryLiteDto::getComponentUuid)
+      .findFirst();
+
+    if (deliveredComponentUuid.isPresent()) {
+      return componentFinder.getByUuid(dbSession, deliveredComponentUuid.get());
+    } else {
+      return null;
+    }
   }
 
   private static class Data {
     private final ComponentDto component;
     private final List<WebhookDeliveryLiteDto> deliveryDtos;
 
+    private int pageIndex;
+    private int pageSize;
+    private int totalElements;
+
     Data(@Nullable ComponentDto component, List<WebhookDeliveryLiteDto> deliveries) {
       this.deliveryDtos = deliveries;
       if (deliveries.isEmpty()) {
@@ -150,7 +174,24 @@ public class WebhookDeliveriesAction implements WebhooksWsAction {
         copyDtoToProtobuf(component, dto, deliveryBuilder);
         responseBuilder.addDeliveries(deliveryBuilder);
       }
+
+      responseBuilder.setPaging(buildPaging(pageIndex, pageSize, totalElements));
       writeProtobuf(responseBuilder.build(), request, response);
     }
+
+    static Common.Paging buildPaging(int pageIndex, int pageSize, int totalElements) {
+      return Common.Paging.newBuilder()
+        .setPageIndex(pageIndex)
+        .setPageSize(pageSize)
+        .setTotal(totalElements)
+        .build();
+    }
+
+    public Data withPagingInfo(int pageIndex, int pageSize, int totalElements) {
+      this.pageIndex = pageIndex;
+      this.pageSize = pageSize;
+      this.totalElements = totalElements;
+      return this;
+    }
   }
 }
index d4da8033df5b1b9a505f19b7ac0d7199f669794c..d95c99d3ba356243fab40b9f99f9b128d681ec1e 100644 (file)
@@ -1,14 +1,20 @@
 {
-  "delivery": {
-    "id": "d1",
-    "componentKey": "my-project",
-    "ceTaskId": "task-1",
-    "name": "Jenkins",
-    "url": "http://jenkins",
-    "at": "2017-07-14T04:40:00+0200",
-    "success": true,
-    "httpStatus": 200,
-    "durationMs": 10,
-    "payload": "{\"status\"=\"SUCCESS\"}"
-  }
-}
+  "paging": {
+    "pageIndex": 1,
+    "pageSize": 10,
+    "total": 1
+  },
+  "deliveries": [
+    {
+      "id": "d1",
+      "componentKey": "my-project",
+      "ceTaskId": "task-1",
+      "name": "Jenkins",
+      "url": "http://jenkins",
+      "at": "2017-07-14T04:40:00+0200",
+      "success": true,
+      "httpStatus": 200,
+      "durationMs": 10
+    }
+  ]
+}
\ No newline at end of file
index e8b9c9c9ca8d21c15989a509602f79f74d7d46d3..6d3d3327dff1ecd434396e6dff552c709bedcaa2 100644 (file)
@@ -68,7 +68,7 @@ public class WebhookDeliveriesActionTest {
 
   @Test
   public void test_definition() {
-    assertThat(ws.getDef().params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("componentKey", "ceTaskId", "webhook");
+    assertThat(ws.getDef().params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("componentKey", "ceTaskId", "webhook", "p", "ps");
     assertThat(ws.getDef().isPost()).isFalse();
     assertThat(ws.getDef().isInternal()).isFalse();
     assertThat(ws.getDef().responseExampleAsString()).isNotEmpty();
index 900f5c0b29be61350b3fe24f50a08f1897d0ae9b..cdd5d5b25f4ecf0b341dbad087181731ab9ff81e 100644 (file)
@@ -393,6 +393,25 @@ public interface WebService extends Definable<WebService.Context> {
         .setExampleValue("20");
     }
 
+    /**
+     * Add predefined parameters related to pagination of results with a maximum page size.
+     * Note the maximum is a documentation only feature. It does not check anything.
+     */
+    public NewAction addPagingParamsSince(int defaultPageSize, int maxPageSize, String version) {
+      createParam(Param.PAGE)
+        .setDescription("1-based page number")
+        .setExampleValue("42")
+        .setDefaultValue("1")
+        .setSince(version);
+      createParam(Param.PAGE_SIZE)
+        .setDescription("Page size. Must be greater than 0 and less than " + maxPageSize)
+        .setDefaultValue(String.valueOf(defaultPageSize))
+        .setMaximumValue(maxPageSize)
+        .setExampleValue("20")
+        .setSince(version);
+      return this;
+    }
+
     /**
      * Creates the parameter {@link org.sonar.api.server.ws.WebService.Param#FIELDS}, which is
      * used to restrict the number of fields returned in JSON response.
index 0569208bc312080f724568ab04c89513e72a5f3a..ea616f84955ba5ea8bf16f0fe9bd805832be10e2 100644 (file)
@@ -20,6 +20,8 @@ syntax = "proto2";
 
 package sonarqube.ws.webhooks;
 
+import "ws-commons.proto";
+
 option java_package = "org.sonarqube.ws";
 option java_outer_classname = "Webhooks";
 option optimize_for = SPEED;
@@ -57,7 +59,10 @@ message CreateWsResponse {
 
 // WS api/webhooks/deliveries
 message DeliveriesWsResponse {
-  repeated Delivery deliveries = 1;
+
+  optional sonarqube.ws.commons.Paging paging = 1;
+
+  repeated Delivery deliveries = 2;
 }
 
 // WS api/webhooks/delivery