Skip to content

Commit

Permalink
jira: enable tests, remove Gson usage, prep for okhttp 2.X removal (#159
Browse files Browse the repository at this point in the history
)
  • Loading branch information
benbroadaway authored Jul 19, 2024
1 parent b7b68a3 commit 7ecfb40
Show file tree
Hide file tree
Showing 20 changed files with 1,541 additions and 288 deletions.
40 changes: 36 additions & 4 deletions tasks/jira/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<packaging>takari-jar</packaging>

<properties>
<skipTests>true</skipTests>
<skipTests>false</skipTests>
</properties>

<dependencies>
Expand All @@ -32,6 +32,11 @@
<artifactId>concord-common</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.walmartlabs.concord</groupId>
<artifactId>concord-client2</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
Expand All @@ -43,10 +48,31 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>okhttp</artifactId>
Expand All @@ -68,6 +94,12 @@
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>4.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.walmartlabs.concord.plugins.jira;

/*-
* *****
* Concord
* -----
* Copyright (C) 2017 - 2024 Walmart Inc., Concord Authors
* -----
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =====
*/

import java.util.UUID;

public class Constants {

private Constants() {
throw new IllegalStateException("instantiation is not allowed");
}

static final String BOUNDARY = UUID.randomUUID().toString();

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,106 +20,122 @@
* =====
*/

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.squareup.okhttp.*;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.MultipartBuilder;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Type;
import java.net.URI;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class JiraClient {
public class JiraClient implements JiraHttpClient {

private static final OkHttpClient client = new OkHttpClient();
private static final Gson gson = new GsonBuilder().create();

private static final TypeToken<Map<String, Object>> MAP_TYPE_TOKEN = new TypeToken<Map<String, Object>>() {
};
private static final TypeToken<List<Map<String, Object>>> LIST_OF_MAPS_TYPE_TOKEN = new TypeToken<List<Map<String, Object>>>() {
};
private static final ObjectMapper MAPPER = new ObjectMapper()
.registerModule(new Jdk8Module());
static final JavaType MAP_TYPE = MAPPER.getTypeFactory()
.constructMapType(HashMap.class, String.class, Object.class);
private static final JavaType LIST_OF_MAPS_TYPE = MAPPER.getTypeFactory()
.constructCollectionType(List.class, MAP_TYPE);

private static final OkHttpClient client = new OkHttpClient();
private final JiraClientCfg cfg;
private String url;
private URI uri;
private int successCode;
private String auth;

public JiraClient(JiraClientCfg cfg) {
this.cfg = cfg;
}

public JiraClient url(String url) {
this.url = url;
@Override
public JiraHttpClient url(String url) {
this.uri = URI.create(url);
return this;
}

public JiraClient successCode(int successCode) {
@Override
public JiraHttpClient successCode(int successCode) {
this.successCode = successCode;
return this;
}

public JiraClient jiraAuth(String auth) {
@Override
public JiraHttpClient jiraAuth(String auth) {
this.auth = auth;
return this;
}

@Override
public Map<String, Object> get() throws IOException {
Request request = requestBuilder(auth)
.url(url)
.url(uri.toURL())
.get()
.build();

return call(request, MAP_TYPE_TOKEN.getType());
return call(request, MAP_TYPE);
}

@Override
public Map<String, Object> post(Map<String, Object> data) throws IOException {
RequestBody body = RequestBody.create(
MediaType.parse("application/json; charset=utf-8"), gson.toJson(data));
MediaType.parse("application/json; charset=utf-8"), MAPPER.writeValueAsString(data));
Request request = requestBuilder(auth)
.url(url)
.url(uri.toURL())
.post(body)
.build();

return call(request, MAP_TYPE_TOKEN.getType());
return call(request, MAP_TYPE);
}

@Override
public void post(File file) throws IOException {
MultipartBuilder b = new MultipartBuilder().type(MultipartBuilder.FORM);
MultipartBuilder b = new MultipartBuilder(Constants.BOUNDARY).type(MultipartBuilder.FORM);
b.addFormDataPart("file", file.getName(),
RequestBody.create(MediaType.parse("application/octet-stream"), Files.readAllBytes(file.toPath())));

RequestBody body = b.build();
Request request = requestBuilder(auth)
.header("X-Atlassian-Token", "nocheck")
.url(url)
.url(uri.toURL())
.post(body)
.build();

call(request, LIST_OF_MAPS_TYPE_TOKEN.getType());
call(request, LIST_OF_MAPS_TYPE);
}

@Override
public void put(Map<String, Object> data) throws IOException {
RequestBody body = RequestBody.create(
MediaType.parse("application/json; charset=utf-8"), gson.toJson(data));
MediaType.parse("application/json; charset=utf-8"), MAPPER.writeValueAsString(data));
Request request = requestBuilder(auth)
.url(url)
.url(uri.toURL())
.put(body)
.build();

call(request, MAP_TYPE_TOKEN.getType());
call(request, MAP_TYPE);
}

@Override
public void delete() throws IOException {
Request request = requestBuilder(auth)
.url(url)
.url(uri.toURL())
.delete()
.build();

call(request, MAP_TYPE_TOKEN.getType());
call(request, MAP_TYPE);
}

private static Request.Builder requestBuilder(String auth) {
Expand All @@ -128,7 +144,8 @@ private static Request.Builder requestBuilder(String auth) {
.addHeader("Accept", "application/json");
}

private <T> T call(Request request, Type returnType) throws IOException {

<T> T call(Request request, JavaType returnType) throws IOException {
setClientTimeoutParams(cfg);

Call call = client.newCall(request);
Expand All @@ -141,29 +158,13 @@ private <T> T call(Request request, Type returnType) throws IOException {
}

int statusCode = response.code();
assertResponseCode(statusCode, results, successCode);

return gson.fromJson(results, returnType);
}
}
JiraHttpClient.assertResponseCode(statusCode, results, successCode);

private static void assertResponseCode(int code, String result, int successCode) {
if (code == successCode) {
return;
}

if (code == 400) {
throw new RuntimeException("input is invalid (e.g. missing required fields, invalid values). Here are the full error details: " + result);
} else if (code == 401) {
throw new RuntimeException("User is not authenticated. Here are the full error details: " + result);
} else if (code == 403) {
throw new RuntimeException("User does not have permission to perform request. Here are the full error details: " + result);
} else if (code == 404) {
throw new RuntimeException("Issue does not exist. Here are the full error details: " + result);
} else if (code == 500) {
throw new RuntimeException("Internal Server Error. Here are the full error details" + result);
} else {
throw new RuntimeException("Error: " + result);
if (results == null || statusCode == 204) {
return null;
} else {
return MAPPER.readValue(results, returnType);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,36 @@ default long readTimeout() {
default long writeTimeout() {
return 30L;
}

default HttpVersion httpProtocolVersion() {
return HttpVersion.DEFAULT;
}

enum HttpVersion {
HTTP_1_1("HTTP/1.1"),
HTTP_2("HTTP/2.0"),
DEFAULT("DEFAULT");

private final String value;

HttpVersion(String value) {
this.value = value;
}

public static HttpVersion from(String val) {
if (val == null || val.isBlank()) {
return DEFAULT;
}

var sanitizedVal = val.toUpperCase();

for (HttpVersion version : HttpVersion.values()) {
if (version.value.equals(sanitizedVal)) {
return version;
}
}

throw new IllegalArgumentException("Unsupported HTTP version: " + val);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
* =====
*/

import java.util.Base64;

public class JiraCredentials {

private final String username;
Expand All @@ -37,4 +39,8 @@ public String username() {
public String password() {
return password;
}

public String authHeaderValue() {
return "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes());
}
}
Loading

0 comments on commit 7ecfb40

Please sign in to comment.