diff --git a/src/main/java/de/hftstuttgart/unifiedticketing/core/TicketSystem.java b/src/main/java/de/hftstuttgart/unifiedticketing/core/TicketSystem.java index d3e3658de7ee943cd177dacd9da08d372da5c5c1..b44b57dc5dbcc30da1849f537b8bd419cc6bd997 100644 --- a/src/main/java/de/hftstuttgart/unifiedticketing/core/TicketSystem.java +++ b/src/main/java/de/hftstuttgart/unifiedticketing/core/TicketSystem.java @@ -1,6 +1,7 @@ package de.hftstuttgart.unifiedticketing.core; import de.hftstuttgart.unifiedticketing.exceptions.AssertionException; +import de.hftstuttgart.unifiedticketing.systems.github.GithubTicketSystem; import de.hftstuttgart.unifiedticketing.systems.gitlab.GitlabTicketSystem; import java.util.HashMap; @@ -57,6 +58,9 @@ public abstract class TicketSystem<T extends Ticket, TS extends TicketSystem, TB switch (matcher.group(2)) { + case "github": + return GithubTicketSystem.fromUri(matcher.group(3)); + case "gitlab": return GitlabTicketSystem.fromUri(matcher.group(3)); diff --git a/src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicket.java b/src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicket.java index d7857379e99e2f3046b94d4df599040439fe58ee..01c12b812275187e78fa25a4f10d89d666f9ea8c 100644 --- a/src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicket.java +++ b/src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicket.java @@ -29,7 +29,7 @@ public class GithubTicket extends Ticket<GithubTicketSystem, GithubTicket> GithubTicket ret = new GithubTicket(parent); ret.description = response.body; ret.id = String.valueOf(response.number); - ret.open = response.state.equalsIgnoreCase("open"); + ret.open = response.state == null || response.state.equalsIgnoreCase("open"); ret.title = response.title; if (response.assignees != null) @@ -265,4 +265,22 @@ public class GithubTicket extends Ticket<GithubTicketSystem, GithubTicket> return GithubTicket.fromTicketResponse(this.parent, ticketResponse); } + + /** + * compares a given Object to this one, including all data fields. + * The normal {@link #equals(Object)} method does only compare Ticket Type and id, + * but not the data fields like this one. + * @param o Object to compare to this + * @return true if the given object is equal in terms of type, id and content to this + */ + public boolean deepEquals(Object o) + { + if (!equals(o)) return false; + GithubTicket t = (GithubTicket) o; + + return Objects.equals(title, t.title) + && Objects.equals(description, t.description) + && Objects.equals(labels, t.labels) + && Objects.equals(assignees, t.assignees); + } } diff --git a/src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicketSystem.java b/src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicketSystem.java index f0218285cd217ffd82c0a983cba5020b2b12629d..ac791830060327a71ec65698fbd187b528e19347 100644 --- a/src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicketSystem.java +++ b/src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicketSystem.java @@ -1,10 +1,12 @@ package de.hftstuttgart.unifiedticketing.systems.github; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; import de.hftstuttgart.unifiedticketing.core.*; -import de.hftstuttgart.unifiedticketing.exceptions.AssertionException; -import de.hftstuttgart.unifiedticketing.exceptions.UnifiedticketingException; +import de.hftstuttgart.unifiedticketing.exceptions.*; +import okhttp3.*; -import java.util.List; +import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; @@ -106,21 +108,93 @@ public class GithubTicketSystem extends TicketSystem<GithubTicket, GithubTicketS return new GithubFilter(this); } + protected OkHttpClient getHttpClient() { return new OkHttpClient(); } + @Override public GithubTicket getTicketById(String id) { - logger.log(Level.FINER, "redirecting request to find method"); - List<GithubTicket> ret = this.find() - .withId(id) + ObjectMapper mapper = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + Request.Builder requestBuilder = new Request.Builder() + .url(String.format("%s/%s", baseUrl, id)) + .addHeader("accept", acceptHeader) .get(); - if (ret == null) return null; - else if (ret.size() != 1) + if (username != null && apiKey != null) + { + requestBuilder.addHeader("Authorization", Credentials.basic(username, apiKey)); + logger.log(Level.FINEST, "added token authentication header"); + } + + HttpUrl.Builder urlBuilder = requestBuilder.build().url().newBuilder(); + + requestBuilder.url(urlBuilder.build()); + + OkHttpClient client = getHttpClient(); + Response response; + + try + { + Request request = requestBuilder.build(); + logger.log(Level.FINEST, String.format( + "created request:\n%s", + (apiKey != null) + ? request.toString().replace(apiKey, "SECRET") + : request.toString() + )); + + response = client.newCall(request).execute(); + } + catch (IOException e) + { + logger.log(Level.SEVERE, String.format("get request FAILED with: %s", e.getMessage())); + + if (getConfigTrue(TicketSystem.ConfigurationOptions.RETURN_NULL_ON_ERROR)) return null; + else throw new HttpReqeustException(e); + } + + if (response.code() >= 400) { - if (getConfigTrue(ConfigurationOptions.RETURN_NULL_ON_ERROR)) return null; - else throw new UnifiedticketingException("more or less than 1 dedicated ticket found"); + logger.log(Level.SEVERE, String.format( + "request failed with response code %d", + response.code() + )); + + if (getConfigTrue(TicketSystem.ConfigurationOptions.RETURN_NULL_ON_ERROR)) return null; + else throw new HttpResponseException( + String.format("ticket query failed, error response code: %d", response.code()), + response.code()); } - else return ret.get(0); + + logger.log(Level.FINEST, "response received\n"); + + ResponseBody responseBody; + responseBody = response.body(); + + if (responseBody == null) + { + logger.log(Level.SEVERE, "query didn't deliver a body in response"); + + if (getConfigTrue(TicketSystem.ConfigurationOptions.RETURN_NULL_ON_ERROR)) return null; + else throw new HttpResponseException("ticket query failed, no response body", response.code()); + } + + GithubTicketResponse tr; + try + { + tr = mapper.readValue(responseBody.bytes(), GithubTicketResponse.class); + + logger.log(Level.FINER, "parsed response body to ticketResponse instance"); + } catch (IOException e) + { + logger.log(Level.SEVERE, String.format("parsing query response FAILED with: %s", e.getMessage())); + + if (getConfigTrue(TicketSystem.ConfigurationOptions.RETURN_NULL_ON_ERROR)) return null; + else throw new DeserializationException(e); + } + + return GithubTicket.fromTicketResponse(this, tr); } @Override diff --git a/src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicketSystemBuilder.java b/src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicketSystemBuilder.java index 945f13753438db79f70ef3132a9d9f85368e6a48..1ec93eed92fb4d19a545cd342c903832a5236510 100644 --- a/src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicketSystemBuilder.java +++ b/src/main/java/de/hftstuttgart/unifiedticketing/systems/github/GithubTicketSystemBuilder.java @@ -2,6 +2,7 @@ package de.hftstuttgart.unifiedticketing.systems.github; import de.hftstuttgart.unifiedticketing.core.Logging; import de.hftstuttgart.unifiedticketing.core.TicketSystemBuilder; +import de.hftstuttgart.unifiedticketing.exceptions.AssertionException; import java.util.logging.Level; import java.util.logging.Logger; @@ -69,6 +70,14 @@ public class GithubTicketSystemBuilder extends TicketSystemBuilder<GithubTicketS @Override public GithubTicketSystem build() { + if (baseUrl == null + || owner == null + || repo == null) + { + String msg = "one of mandatory fields 'baseUrl', 'owner' or 'repo' missing!"; + throw new AssertionException(msg); + } + return new GithubTicketSystem( acceptHeader, String.format(