Skip to content

Commit

Permalink
Merge pull request #1050 from fellahi-ali/#1015
Browse files Browse the repository at this point in the history
#1015 Add Bitbucket.webhooks()
  • Loading branch information
amihaiemil authored Mar 10, 2021
2 parents 998fd7f + ce32bdd commit 36dbcb4
Show file tree
Hide file tree
Showing 3 changed files with 215 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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().
*/
Expand Down Expand Up @@ -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
Expand Down
200 changes: 200 additions & 0 deletions self-core-impl/src/main/java/com/selfxdsd/core/BitbucketWebhooks.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/**
* Copyright (c) 2020-2021, Self XDSD Contributors
* All rights reserved.
* <p>
* 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.
* <p>
* 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<Webhook> iterator() {
final Iterator<Webhook> iterator;
LOG.debug(
"Fetching Bitbucket webhooks [" + this.hooksUri + "]..."
);
final Resource response = this.resources.get(
URI.create(this.hooksUri.toString() + "?per_page=100")
);
if(response.statusCode() == HttpURLConnection.HTTP_OK) {
LOG.debug("Webhooks fetched successfully!");
final List<Webhook> list = new ArrayList<>();
final JsonArray hooks = response.asJsonObject()
.getJsonArray("values");
for(final JsonValue hook : hooks) {
list.add(
new Webhook() {
/**
* Hook in JSON.
*/
private final JsonObject json = hook.asJsonObject();

@Override
public String id() {
return this.json.getString("uuid");
}

@Override
public String url() {
return this.json.getString("url");
}
}
);
}
iterator = list.iterator();
} else {
LOG.error(
"Problem when fetching webhooks. Expected 200 OK, "
+ " but got " + response.statusCode()
+ ". Returning empty iterable."
);
iterator = Collections.emptyIterator();
}
return iterator;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -185,14 +185,21 @@ public void returnsCollaborators() {
/**
* BitbucketRepo.webhooks() returns its webhooks.
*/
@Test(expected = UnsupportedOperationException.class)
@Test
public void returnsWebhooks() {
new BitbucketRepo(
final BitbucketRepo repo = new BitbucketRepo(
Mockito.mock(JsonResources.class),
URI.create("https://bitbucket.org/api/2.0/repositories/john/test"),
Mockito.mock(User.class),
Mockito.mock(Storage.class)
).webhooks();
);
MatcherAssert.assertThat(
repo.webhooks(),
Matchers.allOf(
Matchers.notNullValue(),
Matchers.instanceOf(BitbucketWebhooks.class)
)
);
}

/**
Expand Down

0 comments on commit 36dbcb4

Please sign in to comment.