Unverified Commit c0d17edf authored by Gautier de Saint Martin Lacaze's avatar Gautier de Saint Martin Lacaze Committed by GitHub
Browse files

Merge pull request #776 from alb-i986/upload-InputStream

Upload: accept an InputStream besides a File
parents 15fc264c 1a1c3b21
package org.gitlab4j.api; package org.gitlab4j.api;
import java.io.File; import java.io.File;
import java.io.InputStream;
import java.net.URL; import java.net.URL;
import javax.ws.rs.NotAuthorizedException; import javax.ws.rs.NotAuthorizedException;
...@@ -369,7 +370,7 @@ public abstract class AbstractApi implements Constants { ...@@ -369,7 +370,7 @@ public abstract class AbstractApi implements Constants {
* @param expectedStatus the HTTP status that should be returned from the server * @param expectedStatus the HTTP status that should be returned from the server
* @param name the name for the form field that contains the file name * @param name the name for the form field that contains the file name
* @param fileToUpload a File instance pointing to the file to upload * @param fileToUpload a File instance pointing to the file to upload
* @param mediaType the content-type of the uploaded file, if null will be determined from fileToUpload * @param mediaType unused; will be removed in the next major version
* @param pathArgs variable list of arguments used to build the URI * @param pathArgs variable list of arguments used to build the URI
* @return a ClientResponse instance with the data returned from the endpoint * @return a ClientResponse instance with the data returned from the endpoint
* @throws GitLabApiException if any exception occurs during execution * @throws GitLabApiException if any exception occurs during execution
...@@ -382,6 +383,14 @@ public abstract class AbstractApi implements Constants { ...@@ -382,6 +383,14 @@ public abstract class AbstractApi implements Constants {
} }
} }
protected Response upload(Response.Status expectedStatus, String name, InputStream inputStream, String filename, String mediaType, Object... pathArgs) throws GitLabApiException {
try {
return validate(getApiClient().upload(name, inputStream, filename, mediaType, pathArgs), expectedStatus);
} catch (Exception e) {
throw handle(e);
}
}
/** /**
* Perform a file upload with the specified File instance and path objects, returning * Perform a file upload with the specified File instance and path objects, returning
* a ClientResponse instance with the data returned from the endpoint. * a ClientResponse instance with the data returned from the endpoint.
...@@ -389,7 +398,7 @@ public abstract class AbstractApi implements Constants { ...@@ -389,7 +398,7 @@ public abstract class AbstractApi implements Constants {
* @param expectedStatus the HTTP status that should be returned from the server * @param expectedStatus the HTTP status that should be returned from the server
* @param name the name for the form field that contains the file name * @param name the name for the form field that contains the file name
* @param fileToUpload a File instance pointing to the file to upload * @param fileToUpload a File instance pointing to the file to upload
* @param mediaType the content-type of the uploaded file, if null will be determined from fileToUpload * @param mediaType unused; will be removed in the next major version
* @param url the fully formed path to the GitLab API endpoint * @param url the fully formed path to the GitLab API endpoint
* @return a ClientResponse instance with the data returned from the endpoint * @return a ClientResponse instance with the data returned from the endpoint
* @throws GitLabApiException if any exception occurs during execution * @throws GitLabApiException if any exception occurs during execution
...@@ -409,7 +418,7 @@ public abstract class AbstractApi implements Constants { ...@@ -409,7 +418,7 @@ public abstract class AbstractApi implements Constants {
* @param expectedStatus the HTTP status that should be returned from the server * @param expectedStatus the HTTP status that should be returned from the server
* @param name the name for the form field that contains the file name * @param name the name for the form field that contains the file name
* @param fileToUpload a File instance pointing to the file to upload * @param fileToUpload a File instance pointing to the file to upload
* @param mediaType the content-type of the uploaded file, if null will be determined from fileToUpload * @param mediaType unused; will be removed in the next major version
* @param formData the Form containing the name/value pairs * @param formData the Form containing the name/value pairs
* @param url the fully formed path to the GitLab API endpoint * @param url the fully formed path to the GitLab API endpoint
* @return a ClientResponse instance with the data returned from the endpoint * @return a ClientResponse instance with the data returned from the endpoint
......
...@@ -2,6 +2,7 @@ package org.gitlab4j.api; ...@@ -2,6 +2,7 @@ package org.gitlab4j.api;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.net.Socket; import java.net.Socket;
import java.net.URL; import java.net.URL;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
...@@ -13,7 +14,6 @@ import java.util.Map; ...@@ -13,7 +14,6 @@ import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngine;
...@@ -30,7 +30,6 @@ import javax.ws.rs.core.MediaType; ...@@ -30,7 +30,6 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput; import javax.ws.rs.core.StreamingOutput;
import org.gitlab4j.api.Constants.TokenType; import org.gitlab4j.api.Constants.TokenType;
import org.gitlab4j.api.GitLabApi.ApiVersion; import org.gitlab4j.api.GitLabApi.ApiVersion;
import org.gitlab4j.api.utils.JacksonJson; import org.gitlab4j.api.utils.JacksonJson;
...@@ -39,11 +38,13 @@ import org.glassfish.jersey.apache.connector.ApacheConnectorProvider; ...@@ -39,11 +38,13 @@ import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties; import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.JerseyClientBuilder; import org.glassfish.jersey.client.JerseyClientBuilder;
import org.glassfish.jersey.media.multipart.BodyPart;
import org.glassfish.jersey.media.multipart.Boundary; import org.glassfish.jersey.media.multipart.Boundary;
import org.glassfish.jersey.media.multipart.FormDataMultiPart; import org.glassfish.jersey.media.multipart.FormDataMultiPart;
import org.glassfish.jersey.media.multipart.MultiPart; import org.glassfish.jersey.media.multipart.MultiPart;
import org.glassfish.jersey.media.multipart.MultiPartFeature; import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.media.multipart.file.FileDataBodyPart; import org.glassfish.jersey.media.multipart.file.FileDataBodyPart;
import org.glassfish.jersey.media.multipart.file.StreamDataBodyPart;
/** /**
...@@ -561,14 +562,13 @@ public class GitLabApiClient implements AutoCloseable { ...@@ -561,14 +562,13 @@ public class GitLabApiClient implements AutoCloseable {
* *
* @param name the name for the form field that contains the file name * @param name the name for the form field that contains the file name
* @param fileToUpload a File instance pointing to the file to upload * @param fileToUpload a File instance pointing to the file to upload
* @param mediaTypeString the content-type of the uploaded file, if null will be determined from fileToUpload * @param mediaTypeString unused; will be removed in the next major version
* @param pathArgs variable list of arguments used to build the URI * @param pathArgs variable list of arguments used to build the URI
* @return a ClientResponse instance with the data returned from the endpoint * @return a ClientResponse instance with the data returned from the endpoint
* @throws IOException if an error occurs while constructing the URL * @throws IOException if an error occurs while constructing the URL
*/ */
protected Response upload(String name, File fileToUpload, String mediaTypeString, Object... pathArgs) throws IOException { protected Response upload(String name, File fileToUpload, String mediaTypeString, Object... pathArgs) throws IOException {
URL url = getApiUrl(pathArgs); return upload(name, fileToUpload, mediaTypeString, null, pathArgs);
return (upload(name, fileToUpload, mediaTypeString, null, url));
} }
/** /**
...@@ -577,7 +577,7 @@ public class GitLabApiClient implements AutoCloseable { ...@@ -577,7 +577,7 @@ public class GitLabApiClient implements AutoCloseable {
* *
* @param name the name for the form field that contains the file name * @param name the name for the form field that contains the file name
* @param fileToUpload a File instance pointing to the file to upload * @param fileToUpload a File instance pointing to the file to upload
* @param mediaTypeString the content-type of the uploaded file, if null will be determined from fileToUpload * @param mediaTypeString unused; will be removed in the next major version
* @param formData the Form containing the name/value pairs * @param formData the Form containing the name/value pairs
* @param pathArgs variable list of arguments used to build the URI * @param pathArgs variable list of arguments used to build the URI
* @return a ClientResponse instance with the data returned from the endpoint * @return a ClientResponse instance with the data returned from the endpoint
...@@ -594,30 +594,38 @@ public class GitLabApiClient implements AutoCloseable { ...@@ -594,30 +594,38 @@ public class GitLabApiClient implements AutoCloseable {
* *
* @param name the name for the form field that contains the file name * @param name the name for the form field that contains the file name
* @param fileToUpload a File instance pointing to the file to upload * @param fileToUpload a File instance pointing to the file to upload
* @param mediaTypeString the content-type of the uploaded file, if null will be determined from fileToUpload * @param mediaTypeString unused; will be removed in the next major version
* @param formData the Form containing the name/value pairs * @param formData the Form containing the name/value pairs
* @param url the fully formed path to the GitLab API endpoint * @param url the fully formed path to the GitLab API endpoint
* @return a ClientResponse instance with the data returned from the endpoint * @return a ClientResponse instance with the data returned from the endpoint
* @throws IOException if an error occurs while constructing the URL * @throws IOException if an error occurs while constructing the URL
*/ */
protected Response upload(String name, File fileToUpload, String mediaTypeString, Form formData, URL url) throws IOException { protected Response upload(String name, File fileToUpload, String mediaTypeString, Form formData, URL url) throws IOException {
FileDataBodyPart filePart = new FileDataBodyPart(name, fileToUpload);
return upload(filePart, formData, url);
}
MediaType mediaType = (mediaTypeString != null ? MediaType.valueOf(mediaTypeString) : null); protected Response upload(String name, InputStream inputStream, String filename, String mediaTypeString, Object... pathArgs) throws IOException {
try (FormDataMultiPart multiPart = new FormDataMultiPart()) { URL url = getApiUrl(pathArgs);
return (upload(name, inputStream, filename, mediaTypeString, null, url));
}
protected Response upload(String name, InputStream inputStream, String filename, String mediaTypeString, Form formData, URL url) throws IOException {
StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart(name, inputStream, filename);
return upload(streamDataBodyPart, formData, url);
}
protected Response upload(BodyPart bodyPart, Form formData, URL url) throws IOException {
try (FormDataMultiPart multiPart = new FormDataMultiPart()) {
if (formData != null) { if (formData != null) {
MultivaluedMap<String, String> formParams = formData.asMap(); formData.asMap().forEach((key, values) -> {
formParams.forEach((key, values) -> {
if (values != null) { if (values != null) {
values.forEach(value -> multiPart.field(key, value)); values.forEach(value -> multiPart.field(key, value));
} }
}); });
} }
FileDataBodyPart filePart = mediaType != null ? multiPart.bodyPart(bodyPart);
new FileDataBodyPart(name, fileToUpload, mediaType) :
new FileDataBodyPart(name, fileToUpload);
multiPart.bodyPart(filePart);
final Entity<?> entity = Entity.entity(multiPart, Boundary.addBoundary(multiPart.getMediaType())); final Entity<?> entity = Entity.entity(multiPart, Boundary.addBoundary(multiPart.getMediaType()));
return (invocation(url, null).post(entity)); return (invocation(url, null).post(entity));
} }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
package org.gitlab4j.api; package org.gitlab4j.api;
import java.io.File; import java.io.File;
import java.io.InputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.Date; import java.util.Date;
...@@ -32,12 +33,10 @@ import java.util.Map; ...@@ -32,12 +33,10 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.ws.rs.core.Form; import javax.ws.rs.core.Form;
import javax.ws.rs.core.GenericType; import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import org.gitlab4j.api.GitLabApi.ApiVersion; import org.gitlab4j.api.GitLabApi.ApiVersion;
import org.gitlab4j.api.models.AccessLevel; import org.gitlab4j.api.models.AccessLevel;
import org.gitlab4j.api.models.AccessRequest; import org.gitlab4j.api.models.AccessRequest;
...@@ -2565,7 +2564,7 @@ public class ProjectApi extends AbstractApi implements Constants { ...@@ -2565,7 +2564,7 @@ public class ProjectApi extends AbstractApi implements Constants {
* *
* @param projectIdOrPath the project in the form of an Integer(ID), String(path), or Project instance, required * @param projectIdOrPath the project in the form of an Integer(ID), String(path), or Project instance, required
* @param fileToUpload the File instance of the file to upload, required * @param fileToUpload the File instance of the file to upload, required
* @param mediaType the media type of the file to upload, optional * @param mediaType unused; will be removed in the next major version
* @return a FileUpload instance with information on the just uploaded file * @return a FileUpload instance with information on the just uploaded file
* @throws GitLabApiException if any exception occurs * @throws GitLabApiException if any exception occurs
*/ */
...@@ -2574,6 +2573,22 @@ public class ProjectApi extends AbstractApi implements Constants { ...@@ -2574,6 +2573,22 @@ public class ProjectApi extends AbstractApi implements Constants {
return (response.readEntity(FileUpload.class)); return (response.readEntity(FileUpload.class));
} }
/**
* Uploads some data in an {@link InputStream} to the specified project,
* to be used in an issue or merge request description, or a comment.
*
* <pre><code>GitLab Endpoint: POST /projects/:id/uploads</code></pre>
*
* @param projectIdOrPath the project in the form of an Integer(ID), String(path), or Project instance, required
* @param inputStream the data to upload, required
* @return a FileUpload instance with information on the just uploaded file
* @throws GitLabApiException if any exception occurs
*/
public FileUpload uploadFile(Object projectIdOrPath, InputStream inputStream, String filename, String mediaType) throws GitLabApiException {
Response response = upload(Response.Status.CREATED, "file", inputStream, filename, mediaType, "projects", getProjectIdOrPath(projectIdOrPath), "uploads");
return (response.readEntity(FileUpload.class));
}
/** /**
* Get the project's push rules. * Get the project's push rules.
* *
......
package org.gitlab4j.api; package org.gitlab4j.api;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assume.assumeNotNull; import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue; import static org.junit.Assume.assumeTrue;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Map; import java.util.Map;
import org.gitlab4j.api.models.FileUpload; import org.gitlab4j.api.models.FileUpload;
import org.gitlab4j.api.models.Project; import org.gitlab4j.api.models.Project;
import org.junit.Before; import org.junit.Before;
...@@ -18,17 +22,17 @@ import org.junit.runners.MethodSorters; ...@@ -18,17 +22,17 @@ import org.junit.runners.MethodSorters;
/** /**
* In order for these tests to run you must set the following properties in test-gitlab4j.properties * In order for these tests to run you must set the following properties in test-gitlab4j.properties
* *
* TEST_NAMESPACE * TEST_NAMESPACE
* TEST_PROJECT_NAME * TEST_PROJECT_NAME
* TEST_HOST_URL * TEST_HOST_URL
* TEST_PRIVATE_TOKEN * TEST_PRIVATE_TOKEN
* *
* If any of the above are NULL, all tests in this class will be skipped. * If any of the above are NULL, all tests in this class will be skipped.
*/ */
@Category(IntegrationTest.class) @Category(IntegrationTest.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING) @FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestFileUpload extends AbstractIntegrationTest { public class TestUpload extends AbstractIntegrationTest {
// The following needs to be set to your test repository // The following needs to be set to your test repository
private static final String TEST_PROXY_URI = HelperUtils.getProperty("TEST_PROXY_URI"); private static final String TEST_PROXY_URI = HelperUtils.getProperty("TEST_PROXY_URI");
...@@ -37,7 +41,7 @@ public class TestFileUpload extends AbstractIntegrationTest { ...@@ -37,7 +41,7 @@ public class TestFileUpload extends AbstractIntegrationTest {
private static GitLabApi gitLabApi; private static GitLabApi gitLabApi;
public TestFileUpload() { public TestUpload() {
super(); super();
} }
...@@ -93,4 +97,21 @@ public class TestFileUpload extends AbstractIntegrationTest { ...@@ -93,4 +97,21 @@ public class TestFileUpload extends AbstractIntegrationTest {
gitLabApi.close(); gitLabApi.close();
} }
@Test
public void testInputStreamUpload() throws GitLabApiException, FileNotFoundException {
Project project = gitLabApi.getProjectApi().getProject(TEST_NAMESPACE, TEST_PROJECT_NAME);
assertNotNull(project);
String filename = "README.md";
File fileToUpload = new File(filename);
FileUpload fileUpload = gitLabApi.getProjectApi().uploadFile(
project.getId(), new FileInputStream(fileToUpload), filename, null);
assertNotNull(fileUpload);
assertThat(fileUpload.getUrl(), endsWith(filename));
assertThat(fileUpload.getAlt(), equalTo(filename));
}
} }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment