Unverified Commit be337ebb authored by Greg Messner's avatar Greg Messner Committed by GitHub
Browse files

Add functionality to CommitAction to support fetching content from file. (#344)

* Added Encoding constant (#342).
* Mods to use Encoding enum constant (#342).
* Mods to support reading content from files when using CommitsApi.createCommit() (#342).
parent ebb10cb3
...@@ -13,6 +13,7 @@ import javax.ws.rs.core.Response; ...@@ -13,6 +13,7 @@ import javax.ws.rs.core.Response;
import org.gitlab4j.api.models.Comment; import org.gitlab4j.api.models.Comment;
import org.gitlab4j.api.models.Commit; import org.gitlab4j.api.models.Commit;
import org.gitlab4j.api.models.CommitAction; import org.gitlab4j.api.models.CommitAction;
import org.gitlab4j.api.models.CommitAction.Action;
import org.gitlab4j.api.models.CommitPayload; import org.gitlab4j.api.models.CommitPayload;
import org.gitlab4j.api.models.CommitRef; import org.gitlab4j.api.models.CommitRef;
import org.gitlab4j.api.models.CommitRef.RefType; import org.gitlab4j.api.models.CommitRef.RefType;
...@@ -23,6 +24,7 @@ import org.gitlab4j.api.utils.ISO8601; ...@@ -23,6 +24,7 @@ import org.gitlab4j.api.utils.ISO8601;
/** /**
* This class implements the client side API for the GitLab commits calls. * This class implements the client side API for the GitLab commits calls.
* See <a href="https://docs.gitlab.com/ce/api/commits.html">Commits API at GitLab</a> for more information.
*/ */
public class CommitsApi extends AbstractApi { public class CommitsApi extends AbstractApi {
...@@ -566,6 +568,23 @@ public class CommitsApi extends AbstractApi { ...@@ -566,6 +568,23 @@ public class CommitsApi extends AbstractApi {
public Commit createCommit(Object projectIdOrPath, String branch, String commitMessage, String startBranch, public Commit createCommit(Object projectIdOrPath, String branch, String commitMessage, String startBranch,
String authorEmail, String authorName, List<CommitAction> actions) throws GitLabApiException { String authorEmail, String authorName, List<CommitAction> actions) throws GitLabApiException {
// Validate the actions
if (actions == null || actions.isEmpty()) {
throw new GitLabApiException("actions cannot be null or empty.");
}
for (CommitAction action : actions) {
// File content is required for create and update
Action actionType = action.getAction();
if (actionType == Action.CREATE || actionType == Action.UPDATE) {
String content = action.getContent();
if (content == null) {
throw new GitLabApiException("Content cannot be null for create or update actions.");
}
}
}
CommitPayload payload = new CommitPayload(); CommitPayload payload = new CommitPayload();
payload.setBranch(branch); payload.setBranch(branch);
payload.setCommitMessage(commitMessage); payload.setCommitMessage(commitMessage);
...@@ -574,7 +593,8 @@ public class CommitsApi extends AbstractApi { ...@@ -574,7 +593,8 @@ public class CommitsApi extends AbstractApi {
payload.setAuthorName(authorName); payload.setAuthorName(authorName);
payload.setActions(actions); payload.setActions(actions);
Response response = post(Response.Status.CREATED, payload, "projects", getProjectIdOrPath(projectIdOrPath), "repository", "commits"); Response response = post(Response.Status.CREATED, payload,
"projects", getProjectIdOrPath(projectIdOrPath), "repository", "commits");
return (response.readEntity(Commit.class)); return (response.readEntity(Commit.class));
} }
} }
...@@ -39,6 +39,28 @@ public interface Constants { ...@@ -39,6 +39,28 @@ public interface Constants {
ACCESS, OAUTH2_ACCESS, PRIVATE; ACCESS, OAUTH2_ACCESS, PRIVATE;
} }
/** Enum to specify encoding of file contents. */
public enum Encoding {
TEXT, BASE64;
private static JacksonJsonEnumHelper<Encoding> enumHelper = new JacksonJsonEnumHelper<>(Encoding.class);
@JsonCreator
public static Encoding forValue(String value) {
return enumHelper.forValue((value != null ? value.toLowerCase() : value));
}
@JsonValue
public String toValue() {
return (enumHelper.toString(this));
}
@Override
public String toString() {
return (enumHelper.toString(this));
}
}
/** Enum to use for ordering the results of various API calls. */ /** Enum to use for ordering the results of various API calls. */
public enum SortOrder { public enum SortOrder {
......
...@@ -16,6 +16,7 @@ import org.gitlab4j.api.models.RepositoryFile; ...@@ -16,6 +16,7 @@ import org.gitlab4j.api.models.RepositoryFile;
/** /**
* This class provides an entry point to all the GitLab API repository files calls. * This class provides an entry point to all the GitLab API repository files calls.
* See <a href="https://docs.gitlab.com/ce/api/repository_files.html">Repository Files API at GitLab</a> for more information.
*/ */
public class RepositoryFileApi extends AbstractApi { public class RepositoryFileApi extends AbstractApi {
...@@ -67,7 +68,10 @@ public class RepositoryFileApi extends AbstractApi { ...@@ -67,7 +68,10 @@ public class RepositoryFileApi extends AbstractApi {
RepositoryFile file = new RepositoryFile(); RepositoryFile file = new RepositoryFile();
file.setBlobId(response.getHeaderString("X-Gitlab-Blob-Id")); file.setBlobId(response.getHeaderString("X-Gitlab-Blob-Id"));
file.setCommitId(response.getHeaderString("X-Gitlab-Commit-Id")); file.setCommitId(response.getHeaderString("X-Gitlab-Commit-Id"));
file.setEncoding(response.getHeaderString("X-Gitlab-Encoding"));
String encoding = response.getHeaderString("X-Gitlab-Encoding");
file.setEncoding(Constants.Encoding.forValue(encoding));
file.setFileName(response.getHeaderString("X-Gitlab-File-Name")); file.setFileName(response.getHeaderString("X-Gitlab-File-Name"));
file.setFilePath(response.getHeaderString("X-Gitlab-File-Path")); file.setFilePath(response.getHeaderString("X-Gitlab-File-Path"));
file.setLastCommitId(response.getHeaderString("X-Gitlab-Last-Commit-Id")); file.setLastCommitId(response.getHeaderString("X-Gitlab-Last-Commit-Id"));
......
package org.gitlab4j.api.models; package org.gitlab4j.api.models;
import java.io.File;
import java.io.IOException;
import org.gitlab4j.api.Constants.Encoding;
import org.gitlab4j.api.GitLabApiException;
import org.gitlab4j.api.utils.FileUtils;
import org.gitlab4j.api.utils.JacksonJson; import org.gitlab4j.api.utils.JacksonJson;
import org.gitlab4j.api.utils.JacksonJsonEnumHelper; import org.gitlab4j.api.utils.JacksonJsonEnumHelper;
...@@ -30,28 +36,6 @@ public class CommitAction { ...@@ -30,28 +36,6 @@ public class CommitAction {
} }
} }
public enum Encoding {
BASE64, TEXT;
private static JacksonJsonEnumHelper<Encoding> enumHelper = new JacksonJsonEnumHelper<>(Encoding.class);
@JsonCreator
public static Encoding forValue(String value) {
return enumHelper.forValue(value);
}
@JsonValue
public String toValue() {
return (enumHelper.toString(this));
}
@Override
public String toString() {
return (enumHelper.toString(this));
}
}
private Action action; private Action action;
private String filePath; private String filePath;
private String previousPath; private String previousPath;
...@@ -151,6 +135,25 @@ public class CommitAction { ...@@ -151,6 +135,25 @@ public class CommitAction {
return this; return this;
} }
public CommitAction withFileContent(String filePath, Encoding encoding) throws GitLabApiException {
File file = new File(filePath);
return (withFileContent(file, filePath, encoding));
}
public CommitAction withFileContent(File file, String filePath, Encoding encoding) throws GitLabApiException {
this.encoding = (encoding != null ? encoding : Encoding.TEXT);
this.filePath = filePath;
try {
content = FileUtils.getFileContentAsString(file, this.encoding);
} catch (IOException e) {
throw new GitLabApiException(e);
}
return (this);
}
@Override @Override
public String toString() { public String toString() {
return (JacksonJson.toJsonString(this)); return (JacksonJson.toJsonString(this));
......
...@@ -3,6 +3,7 @@ package org.gitlab4j.api.models; ...@@ -3,6 +3,7 @@ package org.gitlab4j.api.models;
import java.util.Base64; import java.util.Base64;
import org.gitlab4j.api.Constants.Encoding;
import org.gitlab4j.api.utils.JacksonJson; import org.gitlab4j.api.utils.JacksonJson;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
...@@ -12,7 +13,7 @@ public class RepositoryFile { ...@@ -12,7 +13,7 @@ public class RepositoryFile {
private String fileName; // file name only, Ex. class.rb private String fileName; // file name only, Ex. class.rb
private String filePath; // full path to file. Ex. lib/class.rb private String filePath; // full path to file. Ex. lib/class.rb
private Integer size; private Integer size;
private String encoding; private Encoding encoding;
private String content; private String content;
private String ref; private String ref;
private String blobId; private String blobId;
...@@ -43,11 +44,11 @@ public class RepositoryFile { ...@@ -43,11 +44,11 @@ public class RepositoryFile {
this.size = size; this.size = size;
} }
public String getEncoding() { public Encoding getEncoding() {
return encoding; return encoding;
} }
public void setEncoding(String encoding) { public void setEncoding(Encoding encoding) {
this.encoding = encoding; this.encoding = encoding;
} }
...@@ -104,7 +105,7 @@ public class RepositoryFile { ...@@ -104,7 +105,7 @@ public class RepositoryFile {
return (null); return (null);
} }
if ("base64".equalsIgnoreCase(encoding)) { if (Encoding.BASE64.equals(encoding)) {
return (new String(Base64.getDecoder().decode(content))); return (new String(Base64.getDecoder().decode(content)));
} }
...@@ -124,7 +125,7 @@ public class RepositoryFile { ...@@ -124,7 +125,7 @@ public class RepositoryFile {
return (null); return (null);
} }
if ("base64".equalsIgnoreCase(encoding)) { if (encoding == Encoding.BASE64) {
return (Base64.getDecoder().decode(content)); return (Base64.getDecoder().decode(content));
} }
...@@ -157,7 +158,7 @@ public class RepositoryFile { ...@@ -157,7 +158,7 @@ public class RepositoryFile {
} }
this.content = Base64.getEncoder().encodeToString(byteContent); this.content = Base64.getEncoder().encodeToString(byteContent);
encoding = "base64"; encoding = Encoding.BASE64;
} }
@Override @Override
......
package org.gitlab4j.api.utils; package org.gitlab4j.api.utils;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.nio.file.Files;
import java.util.Base64;
import java.util.Scanner; import java.util.Scanner;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import org.gitlab4j.api.Constants.Encoding;
/** /**
* This class provides static utility methods used throughout GitLab4J. * This class provides static utility methods used throughout GitLab4J.
*/ */
...@@ -79,7 +84,7 @@ public class FileUtils { ...@@ -79,7 +84,7 @@ public class FileUtils {
/** /**
* Reads the content of a Reader instance and returns it as a String. * Reads the content of a Reader instance and returns it as a String.
* *
* @param reader the Reader instance to read the content from * @param reader the Reader instance to read the content from
* @return the content of a Reader instance as a String * @return the content of a Reader instance as a String
* @throws IOException if any error occurs * @throws IOException if any error occurs
...@@ -95,4 +100,27 @@ public class FileUtils { ...@@ -95,4 +100,27 @@ public class FileUtils {
return (out.toString()); return (out.toString());
} }
/**
* Reads the content of a File instance and returns it as a String of either text or base64 encoded text.
*
* @param file the File instance to read from
* @param encoding whether to encode as Base64 or as Text, defaults to Text if null
* @return the content of the File as a String
* @throws IOException if any error occurs
*/
public static String getFileContentAsString(File file, Encoding encoding) throws IOException {
if (encoding == Encoding.BASE64) {
try (FileInputStream stream = new FileInputStream(file)) {
byte data[] = new byte[(int) file.length()];
stream.read(data);
return (Base64.getEncoder().encodeToString(data));
}
} else {
return(new String (Files.readAllBytes(file.toPath())));
}
}
} }
package org.gitlab4j.api; package org.gitlab4j.api;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue; import static org.junit.Assume.assumeTrue;
import java.text.ParseException; import java.text.ParseException;
import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Optional;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import org.gitlab4j.api.models.Comment; import org.gitlab4j.api.models.Comment;
import org.gitlab4j.api.models.Commit; import org.gitlab4j.api.models.Commit;
import org.gitlab4j.api.models.CommitAction;
import org.gitlab4j.api.models.CommitAction.Action;
import org.gitlab4j.api.models.CommitRef; import org.gitlab4j.api.models.CommitRef;
import org.gitlab4j.api.models.Diff; import org.gitlab4j.api.models.Diff;
import org.gitlab4j.api.models.Project; import org.gitlab4j.api.models.Project;
import org.gitlab4j.api.models.RepositoryFile; import org.gitlab4j.api.models.RepositoryFile;
import org.gitlab4j.api.utils.ISO8601; import org.gitlab4j.api.utils.ISO8601;
import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.FixMethodOrder; import org.junit.FixMethodOrder;
...@@ -40,9 +45,9 @@ import org.junit.runners.MethodSorters; ...@@ -40,9 +45,9 @@ import org.junit.runners.MethodSorters;
@FixMethodOrder(MethodSorters.NAME_ASCENDING) @FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestCommitsApi extends AbstractIntegrationTest { public class TestCommitsApi extends AbstractIntegrationTest {
private static final String TEST_CREATE_COMMIT_FILEPATH = "gitlab4j-create-commit-test-file.txt";
private static GitLabApi gitLabApi; private static GitLabApi gitLabApi;
private static Project testProject; private static Project testProject;
private static boolean createdSubDirectoryPathFile = false;
public TestCommitsApi() { public TestCommitsApi() {
super(); super();
...@@ -60,20 +65,10 @@ public class TestCommitsApi extends AbstractIntegrationTest { ...@@ -60,20 +65,10 @@ public class TestCommitsApi extends AbstractIntegrationTest {
repoFile.setFilePath(TEST_PROJECT_SUBDIRECTORY_PATH); repoFile.setFilePath(TEST_PROJECT_SUBDIRECTORY_PATH);
repoFile.setContent("This is a test project used to test GitLab4J-API."); repoFile.setContent("This is a test project used to test GitLab4J-API.");
gitLabApi.getRepositoryFileApi().createFile(testProject, repoFile, "master", "Initial commit."); gitLabApi.getRepositoryFileApi().createFile(testProject, repoFile, "master", "Initial commit.");
createdSubDirectoryPathFile = true;
} catch (GitLabApiException ignore) {} } catch (GitLabApiException ignore) {}
} }
} }
@AfterClass
public static void teardown() {
if (createdSubDirectoryPathFile) {
try {
gitLabApi.getRepositoryFileApi().deleteFile(testProject, TEST_PROJECT_SUBDIRECTORY_PATH, "master", "No longer needed.");
} catch (Exception ignore) {}
}
}
@Before @Before
public void beforeMethod() { public void beforeMethod() {
assumeTrue(gitLabApi != null); assumeTrue(gitLabApi != null);
...@@ -198,4 +193,98 @@ public class TestCommitsApi extends AbstractIntegrationTest { ...@@ -198,4 +193,98 @@ public class TestCommitsApi extends AbstractIntegrationTest {
assertEquals(Response.Status.NOT_FOUND, gle.getHttpStatus()); assertEquals(Response.Status.NOT_FOUND, gle.getHttpStatus());
} }
} }
@Test
public void testCreateCommit() throws GitLabApiException {
// Make sure the file to create does not exist.
if (gitLabApi.getRepositoryFileApi().getOptionalFile(testProject, TEST_CREATE_COMMIT_FILEPATH, "master").isPresent()) {
gitLabApi.getRepositoryFileApi().deleteFile(testProject, TEST_CREATE_COMMIT_FILEPATH, "master", "Deleted test file");
}
// Arrange
CommitAction commitAction = new CommitAction()
.withAction(Action.CREATE)
.withContent("This is the original data in the file")
.withFilePath(TEST_CREATE_COMMIT_FILEPATH);
// Act
Commit commit = gitLabApi.getCommitsApi().createCommit(
testProject, "master", "Testing createCommit() create action", null, null, null, Arrays.asList(commitAction));
// Assert
assertNotNull(commit);
// Arrange
commitAction = new CommitAction()
.withAction(Action.DELETE)
.withFilePath(TEST_CREATE_COMMIT_FILEPATH);
// Act
commit = gitLabApi.getCommitsApi().createCommit(
testProject, "master", "Testing createCommit() delete action", null, null, null, Arrays.asList(commitAction));
// Assert
assertNotNull(commit);
Optional<RepositoryFile> repoFile = gitLabApi.getRepositoryFileApi().getOptionalFile(testProject, TEST_CREATE_COMMIT_FILEPATH, "master");
assertFalse(repoFile.isPresent());
}
@Test
public void testCreateCommitFromFile() throws GitLabApiException {
// Make sure the file to create does not exist.
if (gitLabApi.getRepositoryFileApi().getOptionalFile(testProject, TEST_CREATE_COMMIT_FILEPATH, "master").isPresent()) {
try {
gitLabApi.getRepositoryFileApi().deleteFile(testProject, TEST_CREATE_COMMIT_FILEPATH, "master", "Deleted test file");
} catch (GitLabApiException ignore) {}
}
// Arrange
CommitAction commitAction = new CommitAction()
.withAction(Action.CREATE)
.withContent("This is the original data in the file")
.withFilePath(TEST_CREATE_COMMIT_FILEPATH);
// Act
Commit commit = gitLabApi.getCommitsApi().createCommit(
testProject, "master", "Testing createCommit() create action", null, null, null, Arrays.asList(commitAction));
// Assert
assertNotNull(commit);
// Arrange
commitAction = new CommitAction()
.withAction(Action.DELETE)
.withFilePath(TEST_CREATE_COMMIT_FILEPATH);
// Act
commit = gitLabApi.getCommitsApi().createCommit(
testProject, "master", "Testing createCommit() delete action", null, null, null, Arrays.asList(commitAction));
// Assert
assertNotNull(commit);
Optional<RepositoryFile> repoFile = gitLabApi.getRepositoryFileApi().getOptionalFile(testProject, TEST_CREATE_COMMIT_FILEPATH, "master");
assertFalse(repoFile.isPresent());
}
@Test
public void testCreateCommitCreateWithNoContent() throws GitLabApiException {
// Arrange
CommitAction commitAction = new CommitAction()
.withAction(Action.CREATE)
.withContent(null)
.withFilePath(TEST_CREATE_COMMIT_FILEPATH + ".bk");
// Act - expecting exception
try {
gitLabApi.getCommitsApi().createCommit(testProject, "master", "Testing createCommit() create action",
null, null, null, Arrays.asList(commitAction));
fail("Commit should have been rejected due to no content.");
} catch (GitLabApiException ignore) {
}
}
} }
\ No newline at end of file
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