From d535686f89484af334723467ed820a685fba4fb0 Mon Sep 17 00:00:00 2001 From: Guillaume Jambet Date: Thu, 15 Feb 2018 14:54:15 +0100 Subject: [PATCH] SONAR-10347 Add pagination to webhook deliveries search ws. --- .../sonar/db/webhook/WebhookDeliveryDao.java | 25 ++++-- .../db/webhook/WebhookDeliveryMapper.java | 13 ++- .../db/webhook/WebhookDeliveryMapper.xml | 21 +++++ .../db/webhook/WebhookDeliveryDaoTest.java | 86 +++++++++++++++---- .../org/sonar/db/webhook/WebhookTesting.java | 5 ++ .../webhook/ws/WebhookDeliveriesAction.java | 71 +++++++++++---- .../server/webhook/ws/example-delivery.json | 32 ++++--- .../ws/WebhookDeliveriesActionTest.java | 2 +- .../org/sonar/api/server/ws/WebService.java | 19 ++++ sonar-ws/src/main/protobuf/ws-webhooks.proto | 7 +- 10 files changed, 223 insertions(+), 58 deletions(-) diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDeliveryDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDeliveryDao.java index 2060cad60f7a..e8e63d856af7 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDeliveryDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDeliveryDao.java @@ -21,6 +21,7 @@ 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 Optional selectByUuid(DbSession dbSession, String uui 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 selectByWebhookUuid(DbSession dbSession, String webhookUuid) { - return mapper(dbSession).selectByWebhookUuid(webhookUuid); + public List 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 selectOrderedByComponentUuid(DbSession dbSession, String componentUuid) { - return mapper(dbSession).selectOrderedByComponentUuid(componentUuid); + public List 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 selectOrderedByCeTaskUuid(DbSession dbSession, String ceTaskUuid) { - return mapper(dbSession).selectOrderedByCeTaskUuid(ceTaskUuid); + public List 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) { diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDeliveryMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDeliveryMapper.java index f14eb163d1e8..6436922de6cb 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDeliveryMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDeliveryMapper.java @@ -22,17 +22,24 @@ 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 selectByWebhookUuid(@Param("webhookUuid") String webhookUuid); + int countByWebhookUuid(@Param("webhookUuid") String webhookUuid); - List selectOrderedByComponentUuid(@Param("componentUuid") String componentUuid); + List selectByWebhookUuid(@Param("webhookUuid") String webhookUuid, RowBounds rowBounds); - List selectOrderedByCeTaskUuid(@Param("ceTaskUuid") String ceTaskUuid); + int countByComponentUuid(@Param("componentUuid") String componentUuid); + + List selectOrderedByComponentUuid(@Param("componentUuid") String componentUuid, RowBounds rowBounds); + + int countByCeTaskUuid(@Param("ceTaskUuid") String ceTaskId); + + List selectOrderedByCeTaskUuid(@Param("ceTaskUuid") String ceTaskUuid, RowBounds rowBounds); void insert(WebhookDeliveryDto dto); diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/webhook/WebhookDeliveryMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/webhook/WebhookDeliveryMapper.xml index 0612c9712939..1321fe21148a 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/webhook/WebhookDeliveryMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/webhook/WebhookDeliveryMapper.xml @@ -26,6 +26,13 @@ where uuid = #{uuid,jdbcType=VARCHAR} + + + + + + insert into webhook_deliveries ( uuid, diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookDeliveryDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookDeliveryDaoTest.java index 025f04b196fd..5b5470358766 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookDeliveryDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookDeliveryDaoTest.java @@ -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 void selectByUuid_returns_empty_if_uuid_does_not_exist() { @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 deliveries = underTest.selectOrderedByComponentUuid(dbSession, "ANOTHER_COMPONENT"); + List 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 deliveries = underTest.selectOrderedByComponentUuid(dbSession, "COMPONENT_1"); + List 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 deliveries = underTest.selectOrderedByCeTaskUuid(dbSession, "ANOTHER_TASK"); + List 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 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 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 deliveries = underTest.selectOrderedByCeTaskUuid(dbSession, "TASK_1"); + List 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 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 void insert_row_with_only_mandatory_columns() { @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 void insert_row_with_all_columns() { @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 void deleteComponentBeforeDate_does_nothing_on_empty_table() { @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 @@ private void verifyMandatoryFields(WebhookDeliveryDto expected, WebhookDeliveryD * 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); } diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookTesting.java b/server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookTesting.java index 0c56b9ae85e3..4568a1378699 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookTesting.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookTesting.java @@ -36,6 +36,11 @@ public static WebhookDto newWebhook(ComponentDto project) { .setProjectUuid(project.uuid()); } + public static WebhookDto newProjectWebhook(String projectUuid) { + return getWebhookDto() + .setProjectUuid(projectUuid); + } + public static WebhookDto newWebhook(OrganizationDto organizationDto) { return getWebhookDto() .setOrganizationUuid(organizationDto.getUuid()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhookDeliveriesAction.java b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhookDeliveriesAction.java index 685d384a9f9b..ee5e469f57ab 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhookDeliveriesAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhookDeliveriesAction.java @@ -34,12 +34,16 @@ 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 void define(WebService.NewController controller) { 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 void handle(Request request, Response response) throws Exception { 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 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 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 deliveries) { + Optional 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 deliveryDtos; + private int pageIndex; + private int pageSize; + private int totalElements; + Data(@Nullable ComponentDto component, List deliveries) { this.deliveryDtos = deliveries; if (deliveries.isEmpty()) { @@ -150,7 +174,24 @@ void writeTo(Request request, Response response) { 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; + } } } diff --git a/server/sonar-server/src/main/resources/org/sonar/server/webhook/ws/example-delivery.json b/server/sonar-server/src/main/resources/org/sonar/server/webhook/ws/example-delivery.json index d4da8033df5b..d95c99d3ba35 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/webhook/ws/example-delivery.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/webhook/ws/example-delivery.json @@ -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 diff --git a/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/WebhookDeliveriesActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/WebhookDeliveriesActionTest.java index e8b9c9c9ca8d..6d3d3327dff1 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/WebhookDeliveriesActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/WebhookDeliveriesActionTest.java @@ -68,7 +68,7 @@ public void setUp() { @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(); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java b/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java index 900f5c0b29be..cdd5d5b25f4e 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java @@ -393,6 +393,25 @@ public NewParam createPageSize(int defaultPageSize, int maxPageSize) { .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. diff --git a/sonar-ws/src/main/protobuf/ws-webhooks.proto b/sonar-ws/src/main/protobuf/ws-webhooks.proto index 0569208bc312..ea616f84955b 100644 --- a/sonar-ws/src/main/protobuf/ws-webhooks.proto +++ b/sonar-ws/src/main/protobuf/ws-webhooks.proto @@ -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