From ee3a17fa0f5a597f7f8d76562cb8d15fc6b3b342 Mon Sep 17 00:00:00 2001 From: Guillaume Jambet Date: Tue, 30 Jan 2018 16:02:22 +0100 Subject: [PATCH] SONAR-10344 add service api/webhooks/search interface. --- .../sonar/server/webhook/ws/SearchAction.java | 75 +++++++++++++++++++ .../server/webhook/ws/WebhookSearchDTO.java | 26 +++++++ .../sonar/server/webhook/ws/WebhooksWs.java | 6 +- .../server/webhook/ws/WebhooksWsModule.java | 1 + .../webhook/ws/WebhooksWsParameters.java | 14 ++++ .../webhook/ws/example-webhooks-search.json | 28 +++++++ .../server/webhook/ws/SearchActionTest.java | 49 ++++++++++++ .../webhook/ws/WebhooksWsModuleTest.java | 2 +- sonar-ws/src/main/protobuf/ws-webhooks.proto | 21 ++++++ 9 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/webhook/ws/SearchAction.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhookSearchDTO.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsParameters.java create mode 100644 server/sonar-server/src/main/resources/org/sonar/server/webhook/ws/example-webhooks-search.json create mode 100644 server/sonar-server/src/test/java/org/sonar/server/webhook/ws/SearchActionTest.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/SearchAction.java new file mode 100644 index 00000000000..c31b49b92e3 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/SearchAction.java @@ -0,0 +1,75 @@ +package org.sonar.server.webhook.ws; + +import com.google.common.io.Resources; +import java.util.ArrayList; +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; +import org.sonar.db.DbClient; +import org.sonar.server.user.UserSession; +import org.sonarqube.ws.Webhooks; + +import static org.sonar.server.webhook.ws.WebhooksWsParameters.ORGANIZATION_KEY_PARAM; +import static org.sonar.server.webhook.ws.WebhooksWsParameters.PROJECT_KEY_PARAM; +import static org.sonar.server.webhook.ws.WebhooksWsParameters.SEARCH_ACTION; +import static org.sonar.server.ws.KeyExamples.KEY_ORG_EXAMPLE_001; +import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; +import static org.sonar.server.ws.WsUtils.writeProtobuf; + +public class SearchAction implements WebhooksWsAction { + + private final DbClient dbClient; + private final UserSession userSession; + + public SearchAction(DbClient dbClient, UserSession userSession) { + this.dbClient = dbClient; + this.userSession = userSession; + } + + @Override + public void define(WebService.NewController controller) { + + WebService.NewAction action = controller.createAction(SEARCH_ACTION) + .setDescription("Search for webhooks associated to an organization or a project.
") + .setSince("7.1") + .setResponseExample(Resources.getResource(this.getClass(), "example-webhooks-search.json")) + .setHandler(this); + + action.createParam(ORGANIZATION_KEY_PARAM) + .setDescription("Organization key. If no organization is provided, the default organization is used.") + .setInternal(true) + .setRequired(false) + .setExampleValue(KEY_ORG_EXAMPLE_001); + + action.createParam(PROJECT_KEY_PARAM) + .setDescription("Project key") + .setRequired(false) + .setExampleValue(KEY_PROJECT_EXAMPLE_001); + + } + + @Override + public void handle(Request request, Response response) throws Exception { + + Webhooks.SearchWsResponse.Builder searchResponse = Webhooks.SearchWsResponse.newBuilder(); + + // FIXME : hard coded to test plumbing + ArrayList webhookSearchDTOS = new ArrayList<>(); + webhookSearchDTOS.add(new WebhookSearchDTO("UUID-1", "my first webhook", "http://www.my-webhook-listener.com/sonarqube")); + webhookSearchDTOS.add(new WebhookSearchDTO("UUID-2", "my 2nd webhook", "https://www.my-other-webhook-listener.com/fancy-listner")); + + for (WebhookSearchDTO dto : webhookSearchDTOS) { + searchResponse.addWebhooksBuilder() + .setKey(dto.getKey()) + .setName(dto.getName()) + .setUrl(dto.getUrl()); + } + + writeProtobuf(searchResponse.build(), request, response); + } + +} + +// {"key":"UUID-1","name":,"url":,"latestDelivery":{"id":"d1","at":"2017-07-14T04:40:00+0200","success":true,"httpStatus":200,"durationMs":10}}, +// {"key":"UUID-2","name":"my 2nd +// webhook","url":"https://www.my-other-webhook-listener.com/fancy-listner","latestDelivery":{"id":"d2","at":"2017-07-14T04:40:00+0200","success":true,"httpStatus":200,"durationMs":10}} diff --git a/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhookSearchDTO.java b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhookSearchDTO.java new file mode 100644 index 00000000000..617ef66fec0 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhookSearchDTO.java @@ -0,0 +1,26 @@ +package org.sonar.server.webhook.ws; + +public class WebhookSearchDTO { + + private final String key; + private final String name; + private final String url; + + public WebhookSearchDTO(String key, String name, String url) { + this.key = key; + this.name = name; + this.url = url; + } + + public String getKey() { + return key; + } + + public String getName() { + return name; + } + + public String getUrl() { + return url; + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWs.java b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWs.java index d41a0ae3b07..a61fc3b6d75 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWs.java +++ b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWs.java @@ -21,9 +21,9 @@ package org.sonar.server.webhook.ws; import org.sonar.api.server.ws.WebService; -public class WebhooksWs implements WebService { +import static org.sonar.server.webhook.ws.WebhooksWsParameters.WEBHOOKS_CONTROLLER; - public static final String API_ENDPOINT = "api/webhooks"; +public class WebhooksWs implements WebService { private final WebhooksWsAction[] actions; @@ -33,7 +33,7 @@ public class WebhooksWs implements WebService { @Override public void define(Context context) { - NewController controller = context.createController(API_ENDPOINT); + NewController controller = context.createController(WEBHOOKS_CONTROLLER); controller.setDescription("Webhooks allow to notify external services when a project analysis is done"); controller.setSince("6.2"); for (WebhooksWsAction action : actions) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsModule.java index dd7092f8234..3f589d19b60 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsModule.java @@ -26,6 +26,7 @@ public class WebhooksWsModule extends Module { protected void configureModule() { add( WebhooksWs.class, + SearchAction.class, WebhookDeliveryAction.class, WebhookDeliveriesAction.class); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsParameters.java b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsParameters.java new file mode 100644 index 00000000000..3a8d18acf66 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsParameters.java @@ -0,0 +1,14 @@ +package org.sonar.server.webhook.ws; + +class WebhooksWsParameters { + + static final String WEBHOOKS_CONTROLLER = "api/webhooks"; + + + static final String SEARCH_ACTION = "search"; + + + static final String ORGANIZATION_KEY_PARAM = "organization"; + static final String PROJECT_KEY_PARAM = "project"; + +} diff --git a/server/sonar-server/src/main/resources/org/sonar/server/webhook/ws/example-webhooks-search.json b/server/sonar-server/src/main/resources/org/sonar/server/webhook/ws/example-webhooks-search.json new file mode 100644 index 00000000000..0f5d3befe28 --- /dev/null +++ b/server/sonar-server/src/main/resources/org/sonar/server/webhook/ws/example-webhooks-search.json @@ -0,0 +1,28 @@ +{ + "webhooks": [ + { + "key": "UUID-1", + "name": "my first webhook", + "url": "http://www.my-webhook-listener.com/sonarqube", + "latestDelivery": { + "id": "d1", + "at": "2017-07-14T04:40:00+0200", + "success": true, + "httpStatus": 200, + "durationMs": 10 + } + }, + { + "key": "UUID-2", + "name": "my 2nd webhook", + "url": "https://www.my-other-webhook-listener.com/fancy-listner", + "latestDelivery": { + "id": "d2", + "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/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/SearchActionTest.java new file mode 100644 index 00000000000..68264390abd --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/SearchActionTest.java @@ -0,0 +1,49 @@ +package org.sonar.server.webhook.ws; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.server.ws.WebService; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.WsActionTester; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.tuple; + +public class SearchActionTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + + @Rule + public DbTester db = DbTester.create(); + + private DbClient dbClient = db.getDbClient(); + private DbSession dbSession = db.getSession(); + + private org.sonar.server.webhook.ws.SearchAction underTest = new SearchAction(dbClient, userSession); + private WsActionTester wsActionTester = new WsActionTester(underTest); + + @Test + public void definition() { + + WebService.Action action = wsActionTester.getDef(); + + assertThat(action).isNotNull(); + assertThat(action.isInternal()).isFalse(); + assertThat(action.isPost()).isFalse(); + assertThat(action.responseExampleAsString()).isNotEmpty(); + assertThat(action.params()) + .extracting(WebService.Param::key, WebService.Param::isRequired) + .containsExactlyInAnyOrder( + tuple("organization", false), + tuple("project", false)); + } + +} \ No newline at end of file diff --git a/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/WebhooksWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/WebhooksWsModuleTest.java index 96dc9eb6577..a361235f99c 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/WebhooksWsModuleTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/WebhooksWsModuleTest.java @@ -32,7 +32,7 @@ public class WebhooksWsModuleTest { public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); underTest.configure(container); - assertThat(container.size()).isEqualTo(2 + 3); + assertThat(container.size()).isEqualTo(3 + 3); } } diff --git a/sonar-ws/src/main/protobuf/ws-webhooks.proto b/sonar-ws/src/main/protobuf/ws-webhooks.proto index a7ef3a9ab2b..30ae14d8a4d 100644 --- a/sonar-ws/src/main/protobuf/ws-webhooks.proto +++ b/sonar-ws/src/main/protobuf/ws-webhooks.proto @@ -24,6 +24,27 @@ option java_package = "org.sonarqube.ws"; option java_outer_classname = "Webhooks"; option optimize_for = SPEED; +// WS api/webhooks/search +message SearchWsResponse { + repeated Search webhooks = 1; +} + +message Search { + optional string key = 1; + optional string name = 2; + optional string url = 3; + optional LatestDelivery latestDelivery = 4; +} + +message LatestDelivery { + optional string id = 1; + optional string at = 2; + optional string success = 3; + optional string httpStatus = 4; + optional string durationMs = 5; +} + + // WS api/webhooks/deliveries message DeliveriesWsResponse { repeated Delivery deliveries = 1; -- 2.39.5