diff --git a/self-core-impl/src/main/java/com/selfxdsd/core/BitbucketRepo.java b/self-core-impl/src/main/java/com/selfxdsd/core/BitbucketRepo.java index 42a70a2f..3a9472cf 100644 --- a/self-core-impl/src/main/java/com/selfxdsd/core/BitbucketRepo.java +++ b/self-core-impl/src/main/java/com/selfxdsd/core/BitbucketRepo.java @@ -34,8 +34,6 @@ * @since 0.0.67 * @todo #976:60min Start implement and test BitbucketIssues for * BitbucketRepo#issues(). - * @todo #976:60min Start implement and test BitbucketWebhooks for - * BitbucketRepo#webhooks(). * @todo #976:60min Start implement and test BitbucketStars for * BitbucketRepo#stars(). */ @@ -126,7 +124,11 @@ public Collaborators collaborators() { @Override public Webhooks webhooks() { - throw new UnsupportedOperationException("Not implemented yet"); + return new BitbucketWebhooks( + this.resources(), + URI.create(this.repoUri().toString() + "/hooks"), + this.storage() + ); } @Override diff --git a/self-core-impl/src/main/java/com/selfxdsd/core/BitbucketWebhooks.java b/self-core-impl/src/main/java/com/selfxdsd/core/BitbucketWebhooks.java new file mode 100644 index 00000000..e744b6d5 --- /dev/null +++ b/self-core-impl/src/main/java/com/selfxdsd/core/BitbucketWebhooks.java @@ -0,0 +1,200 @@ +/** + * Copyright (c) 2020-2021, Self XDSD Contributors + * All rights reserved. + *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to read the Software only. Permission is hereby NOT GRANTED to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software. + *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.selfxdsd.core;
+
+import com.selfxdsd.api.Project;
+import com.selfxdsd.api.Webhook;
+import com.selfxdsd.api.Webhooks;
+import com.selfxdsd.api.storage.Storage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.json.JsonValue;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Bitbucket repo webhooks.
+ *
+ * @author Ali FELLAHI (fellahi.ali@gmail.com)
+ * @version $Id$
+ * @since 0.0.68
+ *
+ * @todo #1015:60min Continue writing tests for BitbucketWebhooks class.
+ */
+final class BitbucketWebhooks implements Webhooks {
+
+ /**
+ * Logger.
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(
+ BitbucketWebhooks.class
+ );
+
+ /**
+ * Bitbucket repo Webhooks base uri.
+ */
+ private final URI hooksUri;
+
+ /**
+ * Gitlab's JSON Resources.
+ */
+ private final JsonResources resources;
+
+ /**
+ * Self storage, in case we want to store something.
+ */
+ private final Storage storage;
+
+ /**
+ * Ctor.
+ *
+ * @param resources Gitlab's JSON Resources.
+ * @param hooksUri Hooks base URI.
+ * @param storage Storage.
+ */
+ BitbucketWebhooks(final JsonResources resources,
+ final URI hooksUri,
+ final Storage storage) {
+ this.resources = resources;
+ this.hooksUri = hooksUri;
+ this.storage = storage;
+ }
+
+ @Override
+ public boolean add(final Project project) {
+ LOG.debug("Adding Bitbucket webhook for Project "
+ + project.repoFullName());
+ final boolean added;
+ final Resource response = this.resources.post(
+ this.hooksUri,
+ Json.createObjectBuilder()
+ .add("description", "Self-XDSD PM")
+ .add("url", System.getenv(Env.WEBHOOK_BASE_URL)
+ + "/bitbucket/" + project.repoFullName())
+ .add("active", true)
+ .add("events",
+ Json.createArrayBuilder()
+ .add("repo:push")
+ .add("issue:created")
+ .add("issue:comment_created")
+ .add("pullrequest:created")
+ .add("pullrequest:comment_created")
+ )
+ .build()
+ );
+ if (response.statusCode() == HttpURLConnection.HTTP_CREATED) {
+ added = true;
+ LOG.debug("Webhook added successfully!");
+ } else {
+ added = false;
+ LOG.debug("Problem when adding webhook. Expected 201 CREATED, "
+ + " but got " + response.statusCode());
+ }
+ return added;
+ }
+
+ @Override
+ public boolean remove() {
+ boolean removed = true;
+ for(final Webhook hook : this) {
+ if(hook.url().contains("//self-xdsd.")) {
+ LOG.debug(
+ "Removing Self XDSD Webhook from ["
+ + this.hooksUri + "]..."
+ );
+ final Resource response = this.resources
+ .delete(
+ URI.create(
+ this.hooksUri.toString() + "/" + hook.id()
+ ),
+ Json.createObjectBuilder().build()
+ );
+ final int status = response.statusCode();
+ if(status == HttpURLConnection.HTTP_NO_CONTENT) {
+ LOG.debug("Hook removed successfully!");
+ } else {
+ LOG.debug(
+ "Problem while removing webhook. "
+ + "Expected 204 NO CONTENT, but got " + status + "."
+ );
+ removed = false;
+ }
+ }
+ }
+ return removed;
+ }
+
+ @Override
+ public Iterator