]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10345 Migrate webhooks from PROPERTIES table to WEBHOOKS table.
authorGuillaume Jambet <guillaume.jambet@sonarsource.com>
Tue, 13 Feb 2018 14:42:38 +0000 (15:42 +0100)
committerGuillaume Jambet <guillaume.jambet@gmail.com>
Thu, 1 Mar 2018 14:21:05 +0000 (15:21 +0100)
16 files changed:
server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDao.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v71/DbVersion71.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v71/MigrateWebhooksToWebhooksTable.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v71/DbVersion71Test.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v71/MigrateWebhooksToWebhooksTableTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v71/MigrateWebhooksToWebhooksTableTest/migrate_webhooks.sql [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/webhook/WebHooks.java
server/sonar-server/src/main/java/org/sonar/server/webhook/WebHooksImpl.java
server/sonar-server/src/main/java/org/sonar/server/webhook/WebhookQGChangeEventListener.java
server/sonar-server/src/main/java/org/sonar/server/webhook/ws/CreateAction.java
server/sonar-server/src/main/java/org/sonar/server/webhook/ws/ListAction.java
server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhookSupport.java
server/sonar-server/src/test/java/org/sonar/server/organization/ws/DeleteActionTest.java
server/sonar-server/src/test/java/org/sonar/server/project/ws/DeleteActionTest.java
server/sonar-server/src/test/java/org/sonar/server/webhook/ws/ListActionTest.java
sonar-ws/src/main/protobuf/ws-webhooks.proto

index 8dafc97939033a2cf060082758da9885c8bc0983..dd6c9300305aef1e49fce5ad165dcd32e6297ff7 100644 (file)
@@ -41,11 +41,15 @@ public class WebhookDao implements Dao {
     return Optional.ofNullable(mapper(dbSession).selectByUuid(uuid));
   }
 
-  public List<WebhookDto> selectByOrganizationUuid(DbSession dbSession, OrganizationDto organizationDto) {
+  public List<WebhookDto> selectByOrganization(DbSession dbSession, OrganizationDto organizationDto) {
     return mapper(dbSession).selectForOrganizationUuidOrderedByName(organizationDto.getUuid());
   }
 
-  public List<WebhookDto> selectByProjectUuid(DbSession dbSession, ComponentDto componentDto) {
+  public List<WebhookDto> selectByOrganizationUuid(DbSession dbSession, String organizationUuid) {
+    return mapper(dbSession).selectForOrganizationUuidOrderedByName(organizationUuid);
+  }
+
+  public List<WebhookDto> selectByProject(DbSession dbSession, ComponentDto componentDto) {
     return mapper(dbSession).selectForProjectUuidOrderedByName(componentDto.uuid());
   }
 
index d786fe7f4af4e038268babca8ed39ca54e8c4e26..abe4af30f23d4d5d76d01a40a4eba3fe3efd611f 100644 (file)
@@ -41,6 +41,7 @@ public class DbVersion71 implements DbVersion {
       .add(2011, "Drop table PROJECT_LINKS", DropTableProjectLinks.class)
       .add(2012, "Rename table PROJECT_LINKS2 to PROJECT_LINKS", RenameTableProjectLinks2ToProjectLinks.class)
       .add(2013, "Create WEBHOOKS Table", CreateWebhooksTable.class)
+      .add(2014, "Migrate webhooks from SETTINGS table to WEBHOOKS table", MigrateWebhooksToWebhooksTable.class)
     ;
   }
 }
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v71/MigrateWebhooksToWebhooksTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v71/MigrateWebhooksToWebhooksTable.java
new file mode 100644 (file)
index 0000000..5e13392
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v71;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import javax.annotation.Nullable;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.step.DataChange;
+import org.sonar.server.platform.db.migration.version.v63.DefaultOrganizationUuidProvider;
+
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toMap;
+
+public class MigrateWebhooksToWebhooksTable extends DataChange {
+
+  private static final Logger LOGGER = Loggers.get(MigrateWebhooksToWebhooksTable.class);
+
+  private DefaultOrganizationUuidProvider defaultOrganizationUuidProvider;
+  private UuidFactory uuidFactory;
+
+  public MigrateWebhooksToWebhooksTable(Database db, DefaultOrganizationUuidProvider defaultOrganizationUuidProvider, UuidFactory uuidFactory) {
+    super(db);
+    this.defaultOrganizationUuidProvider = defaultOrganizationUuidProvider;
+    this.uuidFactory = uuidFactory;
+  }
+
+  @Override
+  public void execute(Context context) throws SQLException {
+    Map<String, PropertyRow> rows = context
+      .prepareSelect("select id, prop_key, resource_id, text_value, created_at from properties where prop_key like 'sonar.webhooks%'")
+      .list(row -> new PropertyRow(
+        row.getLong(1),
+        row.getString(2),
+        row.getLong(3),
+        row.getString(4),
+        row.getLong(5)))
+      .stream()
+      .collect(toMap(PropertyRow::key, Function.identity()));
+
+    if (!rows.isEmpty()) {
+      migrateGlobalWebhooks(context, rows);
+      migrateProjectsWebhooks(context, rows);
+      context
+        .prepareUpsert("delete from properties where prop_key like 'sonar.webhooks.global%' or prop_key like 'sonar.webhooks.project%'")
+        .execute()
+        .commit();
+    }
+  }
+
+  private void migrateProjectsWebhooks(Context context, Map<String, PropertyRow> properties) throws SQLException {
+    PropertyRow index = properties.get("sonar.webhooks.project");
+    if (index != null) {
+      // can't lambda due to checked exception.
+      for (Webhook webhook : extractProjectWebhooksFrom(context, properties, index.value().split(","))) {
+        insert(context, webhook);
+      }
+    }
+  }
+
+  private void migrateGlobalWebhooks(Context context, Map<String, PropertyRow> properties) throws SQLException {
+    PropertyRow index = properties.get("sonar.webhooks.global");
+    if (index != null) {
+      // can't lambda due to checked exception.
+      for (Webhook webhook : extractGlobalWebhooksFrom(context, properties, index.value().split(","))) {
+        insert(context, webhook);
+      }
+    }
+  }
+
+  private void insert(Context context, Webhook webhook) throws SQLException {
+    if (webhook.isValid()) {
+      context.prepareUpsert("insert into webhooks (uuid, name, url, organization_uuid, project_uuid, created_at, updated_at) values (?, ?, ?, ?, ?, ?, ?)")
+        .setString(1, uuidFactory.create())
+        .setString(2, webhook.name())
+        .setString(3, webhook.url())
+        .setString(4, webhook.organisationUuid())
+        .setString(5, webhook.projectUuid())
+        .setLong(6, webhook.createdAt())
+        .setLong(7, webhook.createdAt())
+        .execute()
+        .commit();
+    } else {
+      LOGGER.info("Unable to migrate inconsistent webhook (entry deleted from PROPERTIES) : " + webhook);
+    }
+  }
+
+  private List<Webhook> extractGlobalWebhooksFrom(Context context, Map<String, PropertyRow> properties, String[] values) throws SQLException {
+    String defaultOrganizationUuid = defaultOrganizationUuidProvider.get(context);
+    return Arrays.stream(values)
+      .map(value -> new Webhook(
+        properties.get("sonar.webhooks.global." + value + ".name"),
+        properties.get("sonar.webhooks.global." + value + ".url"),
+        defaultOrganizationUuid, null))
+      .collect(toList());
+  }
+
+  private static List<Webhook> extractProjectWebhooksFrom(Context context, Map<String, PropertyRow> properties, String[] values) throws SQLException {
+    List<Webhook> webhooks = new ArrayList<>();
+    for (String value : values) {
+      PropertyRow name = properties.get("sonar.webhooks.project." + value + ".name");
+      PropertyRow url = properties.get("sonar.webhooks.project." + value + ".url");
+      webhooks.add(new Webhook(name, url, null, projectUuidOf(context, name)));
+    }
+    return webhooks;
+  }
+
+  private static String projectUuidOf(Context context, PropertyRow row) throws SQLException {
+    return context
+      .prepareSelect("select uuid from projects where id = ?")
+      .setLong(1, row.resourceId())
+      .list(row1 -> row1.getString(1)).stream().findFirst().orElse(null);
+  }
+
+  private static class PropertyRow {
+
+    private final Long id;
+    private final String key;
+    private final Long resourceId;
+    private final String value;
+    private final Long createdAt;
+
+    public PropertyRow(long id, String key, Long resourceId, String value, Long createdAt) {
+      this.id = id;
+      this.key = key;
+      this.resourceId = resourceId;
+      this.value = value;
+      this.createdAt = createdAt;
+    }
+
+    public Long id() {
+      return id;
+    }
+
+    public String key() {
+      return key;
+    }
+
+    public Long resourceId() {
+      return resourceId;
+    }
+
+    public String value() {
+      return value;
+    }
+
+    public Long createdAt() {
+      return createdAt;
+    }
+
+    @Override
+    public String toString() {
+      return "{" +
+        "id=" + id +
+        ", key='" + key + '\'' +
+        ", resourceId=" + resourceId +
+        ", value='" + value + '\'' +
+        ", createdAt=" + createdAt +
+        '}';
+    }
+  }
+
+  private static class Webhook {
+
+    private final PropertyRow name;
+    private final PropertyRow url;
+    private String organisationUuid;
+    private String projectUuid;
+
+    public Webhook(@Nullable PropertyRow name, @Nullable PropertyRow url, @Nullable String organisationUuid, @Nullable String projectUuid) {
+      this.name = name;
+      this.url = url;
+      this.organisationUuid = organisationUuid;
+      this.projectUuid = projectUuid;
+    }
+
+    public String name() {
+      return name.value();
+    }
+
+    public String url() {
+      return url.value();
+    }
+
+    public String organisationUuid() {
+      return organisationUuid;
+    }
+
+    public String projectUuid() {
+      return projectUuid;
+    }
+
+    public Long createdAt() {
+      return name.createdAt();
+    }
+
+    public boolean isValid() {
+      return name != null && url != null && name() != null && url() != null && (organisationUuid() != null || projectUuid() != null) && createdAt() != null;
+    }
+
+    @Override
+    public String toString() {
+      final StringBuilder s = new StringBuilder().append("Webhook{").append("name=").append(name);
+      if (name != null) {
+        s.append(name.toString());
+      }
+      s.append(", url=").append(url);
+      if (url != null) {
+        s.append(url.toString());
+      }
+      s.append(", organisationUuid='").append(organisationUuid).append('\'')
+        .append(", projectUuid='").append(projectUuid).append('\'').append('}');
+      return s.toString();
+    }
+  }
+
+}
index bc893e7bd4cd7a26ff92b3d112806473e35fd0e7..70a599f9f6e69a529688be8cc2354bbcb1d84faa 100644 (file)
@@ -36,7 +36,7 @@ public class DbVersion71Test {
 
   @Test
   public void verify_migration_count() {
-    verifyMigrationCount(underTest, 14);
+    verifyMigrationCount(underTest, 15);
   }
 
 }
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v71/MigrateWebhooksToWebhooksTableTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v71/MigrateWebhooksToWebhooksTableTest.java
new file mode 100644 (file)
index 0000000..6145fa7
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v71;
+
+import java.sql.SQLException;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.core.util.UuidFactoryFast;
+import org.sonar.db.CoreDbTester;
+import org.sonar.server.platform.db.migration.version.v63.DefaultOrganizationUuidProviderImpl;
+
+import static java.lang.Long.parseLong;
+import static java.lang.String.valueOf;
+import static org.apache.commons.lang.RandomStringUtils.randomNumeric;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class MigrateWebhooksToWebhooksTableTest {
+
+  @Rule
+  public final CoreDbTester dbTester = CoreDbTester.createForSchema(MigrateWebhooksToWebhooksTableTest.class, "migrate_webhooks.sql");
+  private static final long NOW = 1_500_000_000_000L;
+  private System2 system2 = new TestSystem2().setNow(NOW);
+  private final UuidFactory uuidFactory = UuidFactoryFast.getInstance();
+
+  private MigrateWebhooksToWebhooksTable underTest = new MigrateWebhooksToWebhooksTable(dbTester.database(), new DefaultOrganizationUuidProviderImpl(), uuidFactory);
+
+  @Test
+  public void should_do_nothing_if_no_webhooks() throws SQLException {
+
+    underTest.execute();
+
+    assertThat(dbTester.countRowsOfTable("properties")).isEqualTo(0);
+    assertThat(dbTester.countRowsOfTable("webhooks")).isEqualTo(0);
+  }
+
+  @Test
+  public void should_migrate_one_global_webhook() throws SQLException {
+    String uuid = insertDefaultOrganization();
+    insertProperty("sonar.webhooks.global", "1", null, system2.now());
+    insertProperty("sonar.webhooks.global.1.name", "a webhook", null, system2.now());
+    insertProperty("sonar.webhooks.global.1.url", "http://webhook.com", null, system2.now());
+
+    underTest.execute();
+
+    assertThat(dbTester.countRowsOfTable("properties")).isEqualTo(0);
+    assertThat(dbTester.countRowsOfTable("webhooks")).isEqualTo(1);
+
+    Map<String, Object> migrated = dbTester.selectFirst("select * from webhooks");
+    assertThat(migrated.get("UUID")).isNotNull();
+    assertThat(migrated.get("NAME")).isEqualTo("a webhook");
+    assertThat(migrated.get("URL")).isEqualTo("http://webhook.com");
+    assertThat(migrated.get("PROJECT_UUID")).isNull();
+    assertThat(migrated.get("ORGANIZATION_UUID")).isEqualTo(uuid);
+    assertThat(migrated.get("URL")).isEqualTo("http://webhook.com");
+    assertThat(migrated.get("CREATED_AT")).isEqualTo(system2.now());
+    assertThat(migrated.get("UPDATED_AT")).isEqualTo(system2.now());
+  }
+
+  @Test
+  public void should_migrate_one_project_webhook() throws SQLException {
+    String organization = insertDefaultOrganization();
+    String projectId = "156";
+    String projectUuid = UuidFactoryFast.getInstance().create();
+    ;
+    insertProject(organization, projectId, projectUuid);
+
+    insertProperty("sonar.webhooks.project", "1", projectId, system2.now());
+    insertProperty("sonar.webhooks.project.1.name", "a webhook", projectId, system2.now());
+    insertProperty("sonar.webhooks.project.1.url", "http://webhook.com", projectId, system2.now());
+
+    underTest.execute();
+
+    assertThat(dbTester.countRowsOfTable("properties")).isEqualTo(0);
+    assertThat(dbTester.countRowsOfTable("webhooks")).isEqualTo(1);
+
+    Map<String, Object> migrated = dbTester.selectFirst("select * from webhooks");
+    assertThat(migrated.get("UUID")).isNotNull();
+    assertThat(migrated.get("NAME")).isEqualTo("a webhook");
+    assertThat(migrated.get("URL")).isEqualTo("http://webhook.com");
+    assertThat(migrated.get("PROJECT_UUID")).isEqualTo(projectUuid);
+    assertThat(migrated.get("ORGANIZATION_UUID")).isNull();
+    assertThat(migrated.get("URL")).isEqualTo("http://webhook.com");
+    assertThat(migrated.get("CREATED_AT")).isEqualTo(system2.now());
+    assertThat(migrated.get("UPDATED_AT")).isEqualTo(system2.now());
+  }
+
+  @Test
+  public void should_migrate_global_webhooks() throws SQLException {
+    insertDefaultOrganization();
+    insertProperty("sonar.webhooks.global", "1,2", null, parseLong(randomNumeric(7)));
+    insertProperty("sonar.webhooks.global.1.name", "a webhook", null, parseLong(randomNumeric(7)));
+    insertProperty("sonar.webhooks.global.1.url", "http://webhook.com", null, parseLong(randomNumeric(7)));
+    insertProperty("sonar.webhooks.global.2.name", "a webhook", null, parseLong(randomNumeric(7)));
+    insertProperty("sonar.webhooks.global.2.url", "http://webhook.com", null, parseLong(randomNumeric(7)));
+
+    underTest.execute();
+
+    assertThat(dbTester.countRowsOfTable("properties")).isEqualTo(0);
+    assertThat(dbTester.countRowsOfTable("webhooks")).isEqualTo(2);
+  }
+
+  @Test
+  public void should_migrate_only_valid_webhooks() throws SQLException {
+    insertDefaultOrganization();
+    insertProperty("sonar.webhooks.global", "1,2,3,4", null, parseLong(randomNumeric(7)));
+    insertProperty("sonar.webhooks.global.1.url", "http://webhook.com", null, parseLong(randomNumeric(7)));
+    insertProperty("sonar.webhooks.global.2.name", "a webhook", null, parseLong(randomNumeric(7)));
+    insertProperty("sonar.webhooks.global.3.name", "a webhook", null, parseLong(randomNumeric(7)));
+    insertProperty("sonar.webhooks.global.3.url", "http://webhook.com", null, parseLong(randomNumeric(7)));
+    // nothing for 4
+
+    underTest.execute();
+
+    assertThat(dbTester.countRowsOfTable("properties")).isEqualTo(0);
+    assertThat(dbTester.countRowsOfTable("webhooks")).isEqualTo(1);
+  }
+
+  @Test
+  public void should_migrate_project_webhooks() throws SQLException {
+    String organization = insertDefaultOrganization();
+    String projectId = "156";
+    String projectUuid = UuidFactoryFast.getInstance().create();
+    ;
+    insertProject(organization, projectId, projectUuid);
+
+    insertProperty("sonar.webhooks.project", "1,2", projectId, system2.now());
+    insertProperty("sonar.webhooks.project.1.name", "a webhook", projectId, system2.now());
+    insertProperty("sonar.webhooks.project.1.url", "http://webhook.com", projectId, system2.now());
+    insertProperty("sonar.webhooks.project.2.name", "another webhook", projectId, system2.now());
+    insertProperty("sonar.webhooks.project.2.url", "http://webhookhookhook.com", projectId, system2.now());
+
+    underTest.execute();
+
+    assertThat(dbTester.countRowsOfTable("properties")).isEqualTo(0);
+    assertThat(dbTester.countRowsOfTable("webhooks")).isEqualTo(2);
+  }
+
+  @Test
+  public void should_not_migrate_more_than_10_webhooks_per_project() throws SQLException {
+
+    underTest.execute();
+
+    assertThat(dbTester.countRowsOfTable("properties")).isEqualTo(0);
+    assertThat(dbTester.countRowsOfTable("webhooks")).isEqualTo(0);
+  }
+
+  @Test
+  public void should_not_migrate_more_than_10_global_webhooks() throws SQLException {
+
+    underTest.execute();
+
+    assertThat(dbTester.countRowsOfTable("properties")).isEqualTo(0);
+    assertThat(dbTester.countRowsOfTable("webhooks")).isEqualTo(0);
+  }
+
+  private void insertProperty(String key, @Nullable String value, @Nullable String resourceId, Long date) {
+    dbTester.executeInsert("PROPERTIES",
+      "id", randomNumeric(7),
+      "prop_key", valueOf(key),
+      "text_value", value,
+      "is_empty", value.isEmpty() ? true : false,
+      "resource_id", resourceId == null ? null : valueOf(resourceId),
+      "created_at", valueOf(date));
+  }
+
+  private String insertDefaultOrganization() {
+    String uuid = UuidFactoryFast.getInstance().create();
+    dbTester.executeInsert(
+      "INTERNAL_PROPERTIES",
+      "KEE", "organization.default",
+      "IS_EMPTY", "false",
+      "TEXT_VALUE", uuid);
+    return uuid;
+  }
+
+  private void insertProject(String organizationUuid, String projectId, String projectUuid) {
+    dbTester.executeInsert(
+      "PROJECTS",
+      "ID", projectId,
+      "ORGANIZATION_UUID", organizationUuid,
+      "UUID", projectUuid);
+  }
+}
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v71/MigrateWebhooksToWebhooksTableTest/migrate_webhooks.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v71/MigrateWebhooksToWebhooksTableTest/migrate_webhooks.sql
new file mode 100644 (file)
index 0000000..d551e6c
--- /dev/null
@@ -0,0 +1,76 @@
+CREATE TABLE "INTERNAL_PROPERTIES" (
+  "KEE" VARCHAR(20) NOT NULL PRIMARY KEY,
+  "IS_EMPTY" BOOLEAN NOT NULL,
+  "TEXT_VALUE" VARCHAR(4000),
+  "CLOB_VALUE" CLOB,
+  "CREATED_AT" BIGINT
+);
+
+
+CREATE TABLE "PROJECTS" (
+  "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "ORGANIZATION_UUID" VARCHAR(40) NOT NULL,
+  "KEE" VARCHAR(400),
+  "UUID" VARCHAR(50) NOT NULL,
+--  "UUID_PATH" VARCHAR(1500) NOT NULL,
+--  "ROOT_UUID" VARCHAR(50) NOT NULL,
+--  "PROJECT_UUID" VARCHAR(50) NOT NULL,
+  "MODULE_UUID" VARCHAR(50),
+  "MODULE_UUID_PATH" VARCHAR(1500),
+  "MAIN_BRANCH_PROJECT_UUID" VARCHAR(50),
+  "NAME" VARCHAR(2000),
+  "DESCRIPTION" VARCHAR(2000),
+--  "PRIVATE" BOOLEAN NOT NULL,
+  "TAGS" VARCHAR(500),
+--  "ENABLED" BOOLEAN NOT NULL DEFAULT TRUE,
+  "SCOPE" VARCHAR(3),
+  "QUALIFIER" VARCHAR(10),
+  "DEPRECATED_KEE" VARCHAR(400),
+  "PATH" VARCHAR(2000),
+  "LANGUAGE" VARCHAR(20),
+  "COPY_COMPONENT_UUID" VARCHAR(50),
+  "LONG_NAME" VARCHAR(2000),
+  "DEVELOPER_UUID" VARCHAR(50),
+  "CREATED_AT" TIMESTAMP,
+  "AUTHORIZATION_UPDATED_AT" BIGINT,
+  "B_CHANGED" BOOLEAN,
+  "B_COPY_COMPONENT_UUID" VARCHAR(50),
+  "B_DESCRIPTION" VARCHAR(2000),
+  "B_ENABLED" BOOLEAN,
+  "B_UUID_PATH" VARCHAR(1500),
+  "B_LANGUAGE" VARCHAR(20),
+  "B_LONG_NAME" VARCHAR(500),
+  "B_MODULE_UUID" VARCHAR(50),
+  "B_MODULE_UUID_PATH" VARCHAR(1500),
+  "B_NAME" VARCHAR(500),
+  "B_PATH" VARCHAR(2000),
+  "B_QUALIFIER" VARCHAR(10)
+);
+
+CREATE TABLE "PROPERTIES" (
+  "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "PROP_KEY" VARCHAR(512) NOT NULL,
+  "RESOURCE_ID" INTEGER,
+  "USER_ID" INTEGER,
+  "IS_EMPTY" BOOLEAN NOT NULL,
+  "TEXT_VALUE" VARCHAR(4000),
+  "CLOB_VALUE" CLOB,
+  "CREATED_AT" BIGINT
+);
+CREATE INDEX "PROPERTIES_KEY" ON "PROPERTIES" ("PROP_KEY");
+
+
+CREATE TABLE "WEBHOOKS" (
+  "UUID" VARCHAR(40) NOT NULL PRIMARY KEY,
+  "NAME" VARCHAR(100) NOT NULL,
+  "URL" VARCHAR(2000) NOT NULL,
+  "ORGANIZATION_UUID" VARCHAR(40),
+  "PROJECT_UUID" VARCHAR(40),
+  "CREATED_AT" BIGINT NOT NULL,
+  "UPDATED_AT" BIGINT
+);
+CREATE UNIQUE INDEX "PK_WEBHOOKS" ON "WEBHOOKS" ("UUID");
+CREATE INDEX "ORGANIZATION_WEBHOOK" ON "WEBHOOKS" ("ORGANIZATION_UUID");
+CREATE INDEX "PROJECT_WEBHOOK" ON "WEBHOOKS" ("PROJECT_UUID");
+
+
index 70cb9c858f8ac3cb0363744027f7690156d6f833..b1c339f7b12843eb36e007d73aebe5c632c4528b 100644 (file)
@@ -35,16 +35,10 @@ public interface WebHooks {
    *
    * <p>
    * This can be used to not do consuming operations before calling
-   * {@link #sendProjectAnalysisUpdate(ComponentDto, Analysis, Supplier)}
+   * {@link #sendProjectAnalysisUpdate(Analysis, Supplier)}
    */
   boolean isEnabled(ComponentDto projectDto);
 
-  /**
-   * Calls all WebHooks configured in the specified {@link Configuration} for the specified analysis with the
-   * {@link WebhookPayload} provided by the specified Supplier.
-   */
-  void sendProjectAnalysisUpdate(ComponentDto projectDto, Analysis analysis, Supplier<WebhookPayload> payloadSupplier);
-
   /**
    * Calls all WebHooks configured in the specified {@link Configuration} for the specified analysis with the
    * {@link WebhookPayload} provided by the specified Supplier.
index db41cfeedaa37b13c886aa49b3c5b790909f94a0..76851e8fd00a963e7c3e619b1a48991363f7b44e 100644 (file)
@@ -29,7 +29,6 @@ import org.sonar.core.util.stream.MoreCollectors;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.ComponentDto;
-import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.webhook.WebhookDao;
 import org.sonar.db.webhook.WebhookDto;
 import org.sonar.server.async.AsyncExecution;
@@ -55,25 +54,25 @@ public class WebHooksImpl implements WebHooks {
 
   @Override
   public boolean isEnabled(ComponentDto projectDto) {
-    return readWebHooksFrom(projectDto)
+    return readWebHooksFrom(projectDto.uuid())
       .findAny()
       .isPresent();
   }
 
-  private Stream<WebhookDto> readWebHooksFrom(ComponentDto projectDto) {
+  private Stream<WebhookDto> readWebHooksFrom(String projectUuid) {
     try (DbSession dbSession = dbClient.openSession(false)) {
-      Optional<OrganizationDto> optionalDto = dbClient.organizationDao().selectByUuid(dbSession, projectDto.getOrganizationUuid());
-      OrganizationDto organizationDto = checkStateWithOptional(optionalDto, "the requested organization '%s' was not found", projectDto.getOrganizationUuid());
+      Optional<ComponentDto> componentDto = ofNullable(dbClient.componentDao().selectByUuid(dbSession, projectUuid).orNull());
+      ComponentDto projectDto = checkStateWithOptional(componentDto, "the requested project '%s' was not found", projectUuid);
       WebhookDao dao = dbClient.webhookDao();
       return Stream.concat(
-        dao.selectByProjectUuid(dbSession, projectDto).stream(),
-        dao.selectByOrganizationUuid(dbSession, organizationDto).stream());
+        dao.selectByProject(dbSession, projectDto).stream(),
+        dao.selectByOrganizationUuid(dbSession, projectDto.getOrganizationUuid()).stream());
     }
   }
 
   @Override
-  public void sendProjectAnalysisUpdate(ComponentDto componentDto, Analysis analysis, Supplier<WebhookPayload> payloadSupplier) {
-    List<Webhook> webhooks = readWebHooksFrom(componentDto)
+  public void sendProjectAnalysisUpdate(Analysis analysis, Supplier<WebhookPayload> payloadSupplier) {
+    List<Webhook> webhooks = readWebHooksFrom(analysis.getProjectUuid())
       .map(dto -> new Webhook(analysis.getProjectUuid(), analysis.getCeTaskUuid(), analysis.getAnalysisUuid(), dto.getName(), dto.getUrl()))
       .collect(MoreCollectors.toList());
     if (webhooks.isEmpty()) {
@@ -89,15 +88,6 @@ public class WebHooksImpl implements WebHooks {
     asyncExecution.addToQueue(() -> deliveryStorage.purge(analysis.getProjectUuid()));
   }
 
-  @Override
-  public void sendProjectAnalysisUpdate(Analysis analysis, Supplier<WebhookPayload> payloadSupplier) {
-    try (DbSession dbSession = dbClient.openSession(false)) {
-      Optional<ComponentDto> optionalDto = ofNullable(dbClient.componentDao().selectByUuid(dbSession, analysis.getProjectUuid()).orNull());
-      ComponentDto projectDto = checkStateWithOptional(optionalDto, "the requested project '%s' was not found", analysis.getProjectUuid());
-      sendProjectAnalysisUpdate(projectDto, analysis, payloadSupplier);
-    }
-  }
-
   private static void log(WebhookDelivery delivery) {
     Optional<String> error = delivery.getErrorMessage();
     if (error.isPresent()) {
index a6fb71e4a6efbf1eed010314406b64bc7fb7b755..f7d3310af8bad71288b66fafaa34f098900340bd 100644 (file)
@@ -79,7 +79,6 @@ public class WebhookQGChangeEventListener implements QGChangeEventListener {
 
   private void callWebhook(DbSession dbSession, QGChangeEvent event, @Nullable EvaluatedQualityGate evaluatedQualityGate) {
     webhooks.sendProjectAnalysisUpdate(
-      event.getProject(),
       new WebHooks.Analysis(event.getBranch().getUuid(), event.getAnalysis().getUuid(), null),
       () -> buildWebHookPayload(dbSession, event, evaluatedQualityGate));
   }
index 34d1d76d520b1b2d3ea825e722403108b9e5a6ef..dc584ac28cc18ea501b823f6d1d70d2ed34bfa54 100644 (file)
@@ -198,11 +198,11 @@ public class CreateAction implements WebhooksWsAction {
   }
 
   private int numberOfWebhookOf(DbSession dbSession, OrganizationDto organizationDto) {
-    return dbClient.webhookDao().selectByOrganizationUuid(dbSession, organizationDto).size();
+    return dbClient.webhookDao().selectByOrganization(dbSession, organizationDto).size();
   }
 
   private int numberOfWebhookOf(DbSession dbSession, ComponentDto componentDto) {
-    return dbClient.webhookDao().selectByProjectUuid(dbSession, componentDto).size();
+    return dbClient.webhookDao().selectByProject(dbSession, componentDto).size();
   }
 
   private OrganizationDto defaultOrganizationDto(DbSession dbSession) {
index 70086aa179ed6af9581befa03e8efb1a590118c8..d90f1f0490ce541a2cfd0eaebcaa08fffce6401f 100644 (file)
@@ -33,7 +33,7 @@ import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.webhook.WebhookDto;
 import org.sonar.server.organization.DefaultOrganizationProvider;
 import org.sonar.server.user.UserSession;
-import org.sonarqube.ws.Webhooks.SearchWsResponse.Builder;
+import org.sonarqube.ws.Webhooks.ListWsResponse.Builder;
 
 import static java.util.Optional.ofNullable;
 import static org.apache.commons.lang.StringUtils.isNotBlank;
@@ -45,7 +45,7 @@ import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
 import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
 import static org.sonar.server.ws.WsUtils.checkStateWithOptional;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
-import static org.sonarqube.ws.Webhooks.SearchWsResponse.newBuilder;
+import static org.sonarqube.ws.Webhooks.ListWsResponse.newBuilder;
 
 public class ListAction implements WebhooksWsAction {
 
@@ -115,12 +115,12 @@ public class ListAction implements WebhooksWsAction {
         webhookSupport.checkPermission(componentDto);
         webhookSupport.checkThatProjectBelongsToOrganization(componentDto, organizationDto, "Project '%s' does not belong to organisation '%s'", projectKey, organizationKey);
         webhookSupport.checkPermission(componentDto);
-        return dbClient.webhookDao().selectByProjectUuid(dbSession, componentDto);
+        return dbClient.webhookDao().selectByProject(dbSession, componentDto);
 
       } else {
 
         webhookSupport.checkPermission(organizationDto);
-        return dbClient.webhookDao().selectByOrganizationUuid(dbSession, organizationDto);
+        return dbClient.webhookDao().selectByOrganization(dbSession, organizationDto);
 
       }
 
index 2595850b84083261e4b157b756f7273bc6012766..95f9b54285d0264c14b39b003fc7ff4e87c99cad 100644 (file)
@@ -32,7 +32,7 @@ public class WebhookSupport {
 
   private final UserSession userSession;
 
-  WebhookSupport(UserSession userSession) {
+  public WebhookSupport(UserSession userSession) {
     this.userSession = userSession;
   }
 
index bca1f7ceecde7eb6419d78b47e055f16e6d6b13c..bf99f3a9f5ea7912d7cb3b08f9875dc678a22cc8 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.organization.ws;
 
+import java.util.List;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
@@ -39,6 +40,8 @@ import org.sonar.db.qualitygate.QualityGateDto;
 import org.sonar.db.qualityprofile.QProfileDto;
 import org.sonar.db.user.GroupDto;
 import org.sonar.db.user.UserDto;
+import org.sonar.db.webhook.WebhookDbTester;
+import org.sonar.db.webhook.WebhookDto;
 import org.sonar.server.component.ComponentCleanerService;
 import org.sonar.server.es.EsTester;
 import org.sonar.server.es.ProjectIndexers;
@@ -48,7 +51,6 @@ import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.exceptions.UnauthorizedException;
 import org.sonar.server.organization.TestDefaultOrganizationProvider;
 import org.sonar.server.organization.TestOrganizationFlags;
-import org.sonar.server.qualitygate.QualityGateFinder;
 import org.sonar.server.qualityprofile.QProfileFactory;
 import org.sonar.server.qualityprofile.QProfileFactoryImpl;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
@@ -90,7 +92,7 @@ public class DeleteActionTest {
   private QProfileFactory qProfileFactory = new QProfileFactoryImpl(dbClient, mock(UuidFactory.class), System2.INSTANCE, mock(ActiveRuleIndexer.class));
   private UserIndex userIndex = new UserIndex(es.client(), System2.INSTANCE);
   private UserIndexer userIndexer = new UserIndexer(dbClient, es.client());
-  private QualityGateFinder qualityGateFinder = new QualityGateFinder(dbClient);
+  private final WebhookDbTester webhookDbTester = db.webhooks();
   private WsActionTester wsTester = new WsActionTester(
     new DeleteAction(userSession, dbClient, defaultOrganizationProvider, componentCleanerService, organizationFlags, userIndexer, qProfileFactory));
 
@@ -113,6 +115,23 @@ public class DeleteActionTest {
       .matches(param -> "Organization key".equals(param.description()));
   }
 
+  @Test
+  public void organization_deletion_also_ensure_that_webhooks_of_this_organization_if_they_exist_are_cleared() {
+    OrganizationDto organization = db.organizations().insert();
+    webhookDbTester.insertWebhook(organization);
+    webhookDbTester.insertWebhook(organization);
+    webhookDbTester.insertWebhook(organization);
+
+    userSession.logIn().addPermission(ADMINISTER, organization);
+
+    wsTester.newRequest()
+      .setParam(PARAM_ORGANIZATION, organization.getKey())
+      .execute();
+
+    List<WebhookDto> webhookDtos = dbClient.webhookDao().selectByOrganization(session, organization);
+    assertThat(webhookDtos).isEmpty();
+  }
+
   @Test
   public void organization_deletion_also_ensure_that_homepage_on_this_organization_if_it_exists_is_cleared() {
     OrganizationDto organization = db.organizations().insert();
index 2fd490af276604213d385e81411fd396a0880934..8153b84b9cff34915fddc73a2a2afa35ea0b16a2 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.project.ws;
 
+import java.util.List;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -33,6 +34,8 @@ import org.sonar.db.component.ComponentDbTester;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ResourceTypesRule;
 import org.sonar.db.user.UserDto;
+import org.sonar.db.webhook.WebhookDbTester;
+import org.sonar.db.webhook.WebhookDto;
 import org.sonar.server.component.ComponentCleanerService;
 import org.sonar.server.es.TestProjectIndexers;
 import org.sonar.server.exceptions.ForbiddenException;
@@ -71,6 +74,7 @@ public class DeleteActionTest {
   private WsTester ws;
   private DbClient dbClient = db.getDbClient();
   private DbSession dbSession = db.getSession();
+  private WebhookDbTester webhookDbTester = db.webhooks();
   private ComponentDbTester componentDbTester = new ComponentDbTester(db);
   private ComponentCleanerService componentCleanerService = mock(ComponentCleanerService.class);
 
@@ -136,7 +140,6 @@ public class DeleteActionTest {
 
   @Test
   public void project_deletion_also_ensure_that_homepage_on_this_project_if_it_exists_is_cleared() throws Exception {
-
     ComponentDto project = componentDbTester.insertPrivateProject();
     UserDto insert = dbClient.userDao().insert(dbSession,
       newUserDto().setHomepageType("PROJECT").setHomepageParameter(project.uuid()));
@@ -157,6 +160,28 @@ public class DeleteActionTest {
     assertThat(userReloaded.getHomepageParameter()).isNull();
   }
 
+  @Test
+  public void project_deletion_also_ensure_that_webhooks_on_this_project_if_they_exists_are_deleted() throws Exception {
+    ComponentDto project = componentDbTester.insertPrivateProject();
+    webhookDbTester.insertWebhook(project);
+    webhookDbTester.insertWebhook(project);
+    webhookDbTester.insertWebhook(project);
+    webhookDbTester.insertWebhook(project);
+
+    userSessionRule.logIn().addProjectPermission(ADMIN, project);
+
+    new WsTester(new ProjectsWs(
+      new DeleteAction(
+        new ComponentCleanerService(dbClient, new ResourceTypesRule().setAllQualifiers(PROJECT),
+          new TestProjectIndexers()), from(db), dbClient, userSessionRule)))
+          .newPostRequest(CONTROLLER, ACTION)
+          .setParam(PARAM_PROJECT, project.getDbKey())
+          .execute();
+
+    List<WebhookDto> webhookDtos = dbClient.webhookDao().selectByProject(dbSession, project);
+    assertThat(webhookDtos).isEmpty();
+  }
+
   @Test
   public void return_403_if_not_project_admin_nor_org_admin() throws Exception {
     ComponentDto project = componentDbTester.insertPrivateProject();
index 30679d2c578605a8c3c3cbd5fce639aa91ab1d39..995eb3b106bf0609540da179a338d2de06e84066 100644 (file)
@@ -38,8 +38,8 @@ import org.sonar.server.exceptions.UnauthorizedException;
 import org.sonar.server.organization.DefaultOrganizationProvider;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.WsActionTester;
-import org.sonarqube.ws.Webhooks.SearchWsResponse;
-import org.sonarqube.ws.Webhooks.SearchWsResponse.Search;
+import org.sonarqube.ws.Webhooks.ListWsResponse;
+import org.sonarqube.ws.Webhooks.ListWsResponse.List;
 
 import static java.lang.String.format;
 import static org.assertj.core.api.Assertions.assertThat;
@@ -92,24 +92,24 @@ public class ListActionTest {
   }
 
   @Test
-  public void search_global_webhooks() {
+  public void List_global_webhooks() {
 
     WebhookDto dto1 = webhookDbTester.insertWebhook(db.getDefaultOrganization());
     WebhookDto dto2 = webhookDbTester.insertWebhook(db.getDefaultOrganization());
     userSession.logIn().addPermission(ADMINISTER, db.getDefaultOrganization().getUuid());
 
-    SearchWsResponse response = wsActionTester.newRequest()
-      .executeProtobuf(SearchWsResponse.class);
+    ListWsResponse response = wsActionTester.newRequest()
+      .executeProtobuf(ListWsResponse.class);
 
     assertThat(response.getWebhooksList())
-      .extracting(Search::getName, Search::getUrl)
+      .extracting(List::getName, List::getUrl)
       .contains(tuple(dto1.getName(), dto1.getUrl()),
         tuple(dto2.getName(), dto2.getUrl()));
 
   }
 
   @Test
-  public void search_project_webhooks_when_no_organization_is_provided() {
+  public void List_project_webhooks_when_no_organization_is_provided() {
 
     ComponentDto project1 = componentDbTester.insertPrivateProject();
     userSession.logIn().addProjectPermission(ADMIN, project1);
@@ -117,38 +117,38 @@ public class ListActionTest {
     WebhookDto dto1 = webhookDbTester.insertWebhook(project1);
     WebhookDto dto2 = webhookDbTester.insertWebhook(project1);
 
-    SearchWsResponse response = wsActionTester.newRequest()
+    ListWsResponse response = wsActionTester.newRequest()
       .setParam(PROJECT_KEY_PARAM, project1.getKey())
-      .executeProtobuf(SearchWsResponse.class);
+      .executeProtobuf(ListWsResponse.class);
 
     assertThat(response.getWebhooksList())
-      .extracting(Search::getName, Search::getUrl)
+      .extracting(List::getName, List::getUrl)
       .contains(tuple(dto1.getName(), dto1.getUrl()),
         tuple(dto2.getName(), dto2.getUrl()));
 
   }
 
   @Test
-  public void search_organization_webhooks() {
+  public void List_organization_webhooks() {
 
     OrganizationDto organizationDto = organizationDbTester.insert();
     WebhookDto dto1 = webhookDbTester.insertWebhook(organizationDto);
     WebhookDto dto2 = webhookDbTester.insertWebhook(organizationDto);
     userSession.logIn().addPermission(ADMINISTER, organizationDto.getUuid());
 
-    SearchWsResponse response = wsActionTester.newRequest()
+    ListWsResponse response = wsActionTester.newRequest()
       .setParam(ORGANIZATION_KEY_PARAM, organizationDto.getKey())
-      .executeProtobuf(SearchWsResponse.class);
+      .executeProtobuf(ListWsResponse.class);
 
     assertThat(response.getWebhooksList())
-      .extracting(Search::getName, Search::getUrl)
+      .extracting(List::getName, List::getUrl)
       .contains(tuple(dto1.getName(), dto1.getUrl()),
         tuple(dto2.getName(), dto2.getUrl()));
 
   }
 
   @Test
-  public void search_project_webhooks_when_organization_is_provided() {
+  public void List_project_webhooks_when_organization_is_provided() {
 
     OrganizationDto organization = organizationDbTester.insert();
     ComponentDto project = componentDbTester.insertPrivateProject(organization);
@@ -157,13 +157,13 @@ public class ListActionTest {
     WebhookDto dto1 = webhookDbTester.insertWebhook(project);
     WebhookDto dto2 = webhookDbTester.insertWebhook(project);
 
-    SearchWsResponse response = wsActionTester.newRequest()
+    ListWsResponse response = wsActionTester.newRequest()
       .setParam(ORGANIZATION_KEY_PARAM, organization.getKey())
       .setParam(PROJECT_KEY_PARAM, project.getKey())
-      .executeProtobuf(SearchWsResponse.class);
+      .executeProtobuf(ListWsResponse.class);
 
     assertThat(response.getWebhooksList())
-      .extracting(Search::getName, Search::getUrl)
+      .extracting(List::getName, List::getUrl)
       .contains(tuple(dto1.getName(), dto1.getUrl()),
         tuple(dto2.getName(), dto2.getUrl()));
 
@@ -177,7 +177,7 @@ public class ListActionTest {
 
     wsActionTester.newRequest()
       .setParam(PROJECT_KEY_PARAM, "pipo")
-      .executeProtobuf(SearchWsResponse.class);
+      .executeProtobuf(ListWsResponse.class);
 
   }
 
@@ -189,7 +189,7 @@ public class ListActionTest {
 
     wsActionTester.newRequest()
       .setParam(ORGANIZATION_KEY_PARAM, "pipo")
-      .executeProtobuf(SearchWsResponse.class);
+      .executeProtobuf(ListWsResponse.class);
 
   }
 
@@ -218,7 +218,7 @@ public class ListActionTest {
     expectedException.expect(UnauthorizedException.class);
 
     wsActionTester.newRequest()
-      .executeProtobuf(SearchWsResponse.class);
+      .executeProtobuf(ListWsResponse.class);
 
   }
 
@@ -231,7 +231,7 @@ public class ListActionTest {
     expectedException.expectMessage("Insufficient privileges");
 
     wsActionTester.newRequest()
-      .executeProtobuf(SearchWsResponse.class);
+      .executeProtobuf(ListWsResponse.class);
   }
 
   @Test
@@ -246,7 +246,7 @@ public class ListActionTest {
 
     wsActionTester.newRequest()
       .setParam(PROJECT_KEY_PARAM, project.getKey())
-      .executeProtobuf(SearchWsResponse.class);
+      .executeProtobuf(ListWsResponse.class);
 
   }
 
index b8dc2a859b917ed80d880d40d5ac5b130f77347d..0569208bc312080f724568ab04c89513e72a5f3a 100644 (file)
@@ -24,11 +24,11 @@ option java_package = "org.sonarqube.ws";
 option java_outer_classname = "Webhooks";
 option optimize_for = SPEED;
 
-// GET api/webhooks/search
-message SearchWsResponse {
-  repeated Search webhooks = 1;
+// GET api/webhooks/list
+message ListWsResponse {
+  repeated List webhooks = 1;
 
-  message Search {
+  message List {
     optional string key = 1;
     optional string name = 2;
     optional string url = 3;