From dbd2968b51dad795894aa75181569196782183fc Mon Sep 17 00:00:00 2001 From: Greg Messner Date: Thu, 9 May 2019 09:05:09 -0700 Subject: [PATCH 1/3] Added Encoding constant (#342). --- src/main/java/org/gitlab4j/api/Constants.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main/java/org/gitlab4j/api/Constants.java b/src/main/java/org/gitlab4j/api/Constants.java index c8bbfa9c6..47f04797e 100644 --- a/src/main/java/org/gitlab4j/api/Constants.java +++ b/src/main/java/org/gitlab4j/api/Constants.java @@ -39,6 +39,28 @@ public enum TokenType { ACCESS, OAUTH2_ACCESS, PRIVATE; } + /** Enum to specify encoding of file contents. */ + public enum Encoding { + TEXT, BASE64; + + private static JacksonJsonEnumHelper 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. */ public enum SortOrder { From d87000281ab4bea69002ee5e201c077a144177cb Mon Sep 17 00:00:00 2001 From: Greg Messner Date: Thu, 9 May 2019 09:06:29 -0700 Subject: [PATCH 2/3] Mods to use Encoding enum constant (#342). --- .../java/org/gitlab4j/api/RepositoryFileApi.java | 6 +++++- .../org/gitlab4j/api/models/RepositoryFile.java | 13 +++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/gitlab4j/api/RepositoryFileApi.java b/src/main/java/org/gitlab4j/api/RepositoryFileApi.java index c64ed5325..32013e32c 100644 --- a/src/main/java/org/gitlab4j/api/RepositoryFileApi.java +++ b/src/main/java/org/gitlab4j/api/RepositoryFileApi.java @@ -16,6 +16,7 @@ /** * This class provides an entry point to all the GitLab API repository files calls. + * See Repository Files API at GitLab for more information. */ public class RepositoryFileApi extends AbstractApi { @@ -67,7 +68,10 @@ public RepositoryFile getFileInfo(Object projectIdOrPath, String filePath, Strin RepositoryFile file = new RepositoryFile(); file.setBlobId(response.getHeaderString("X-Gitlab-Blob-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.setFilePath(response.getHeaderString("X-Gitlab-File-Path")); file.setLastCommitId(response.getHeaderString("X-Gitlab-Last-Commit-Id")); diff --git a/src/main/java/org/gitlab4j/api/models/RepositoryFile.java b/src/main/java/org/gitlab4j/api/models/RepositoryFile.java index daafdbaa2..6496269a9 100644 --- a/src/main/java/org/gitlab4j/api/models/RepositoryFile.java +++ b/src/main/java/org/gitlab4j/api/models/RepositoryFile.java @@ -3,6 +3,7 @@ import java.util.Base64; +import org.gitlab4j.api.Constants.Encoding; import org.gitlab4j.api.utils.JacksonJson; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -12,7 +13,7 @@ public class RepositoryFile { private String fileName; // file name only, Ex. class.rb private String filePath; // full path to file. Ex. lib/class.rb private Integer size; - private String encoding; + private Encoding encoding; private String content; private String ref; private String blobId; @@ -43,11 +44,11 @@ public void setSize(Integer size) { this.size = size; } - public String getEncoding() { + public Encoding getEncoding() { return encoding; } - public void setEncoding(String encoding) { + public void setEncoding(Encoding encoding) { this.encoding = encoding; } @@ -104,7 +105,7 @@ public String getDecodedContentAsString() { return (null); } - if ("base64".equalsIgnoreCase(encoding)) { + if (Encoding.BASE64.equals(encoding)) { return (new String(Base64.getDecoder().decode(content))); } @@ -124,7 +125,7 @@ public byte[] getDecodedContentAsBytes() { return (null); } - if ("base64".equalsIgnoreCase(encoding)) { + if (encoding == Encoding.BASE64) { return (Base64.getDecoder().decode(content)); } @@ -157,7 +158,7 @@ public void encodeAndSetContent(byte[] byteContent) { } this.content = Base64.getEncoder().encodeToString(byteContent); - encoding = "base64"; + encoding = Encoding.BASE64; } @Override From ba4e8ee06c38345fa57e82cd6fc90b8ebf66d9c9 Mon Sep 17 00:00:00 2001 From: Greg Messner Date: Thu, 9 May 2019 09:09:09 -0700 Subject: [PATCH 3/3] Mods to support reading content from files when using CommitsApi.createCommit() (#342). --- .../java/org/gitlab4j/api/CommitsApi.java | 22 +++- .../org/gitlab4j/api/models/CommitAction.java | 47 ++++---- .../org/gitlab4j/api/utils/FileUtils.java | 30 ++++- .../java/org/gitlab4j/api/TestCommitsApi.java | 113 ++++++++++++++++-- 4 files changed, 176 insertions(+), 36 deletions(-) diff --git a/src/main/java/org/gitlab4j/api/CommitsApi.java b/src/main/java/org/gitlab4j/api/CommitsApi.java index 5c0381190..7b1425483 100644 --- a/src/main/java/org/gitlab4j/api/CommitsApi.java +++ b/src/main/java/org/gitlab4j/api/CommitsApi.java @@ -13,6 +13,7 @@ import org.gitlab4j.api.models.Comment; import org.gitlab4j.api.models.Commit; import org.gitlab4j.api.models.CommitAction; +import org.gitlab4j.api.models.CommitAction.Action; import org.gitlab4j.api.models.CommitPayload; import org.gitlab4j.api.models.CommitRef; import org.gitlab4j.api.models.CommitRef.RefType; @@ -23,6 +24,7 @@ /** * This class implements the client side API for the GitLab commits calls. + * See Commits API at GitLab for more information. */ public class CommitsApi extends AbstractApi { @@ -566,6 +568,23 @@ public Comment addComment(Object projectIdOrPath, String sha, String note) throw public Commit createCommit(Object projectIdOrPath, String branch, String commitMessage, String startBranch, String authorEmail, String authorName, List 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(); payload.setBranch(branch); payload.setCommitMessage(commitMessage); @@ -574,7 +593,8 @@ public Commit createCommit(Object projectIdOrPath, String branch, String commitM payload.setAuthorName(authorName); 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)); } } diff --git a/src/main/java/org/gitlab4j/api/models/CommitAction.java b/src/main/java/org/gitlab4j/api/models/CommitAction.java index 02036231c..0b1335023 100644 --- a/src/main/java/org/gitlab4j/api/models/CommitAction.java +++ b/src/main/java/org/gitlab4j/api/models/CommitAction.java @@ -1,5 +1,11 @@ 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.JacksonJsonEnumHelper; @@ -30,28 +36,6 @@ public String toString() { } } - public enum Encoding { - - BASE64, TEXT; - - private static JacksonJsonEnumHelper 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 String filePath; private String previousPath; @@ -151,6 +135,25 @@ public CommitAction withExecuteFilemode(Boolean executeFilemode) { 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 public String toString() { return (JacksonJson.toJsonString(this)); diff --git a/src/main/java/org/gitlab4j/api/utils/FileUtils.java b/src/main/java/org/gitlab4j/api/utils/FileUtils.java index f3f7aad18..1316f72c4 100644 --- a/src/main/java/org/gitlab4j/api/utils/FileUtils.java +++ b/src/main/java/org/gitlab4j/api/utils/FileUtils.java @@ -1,12 +1,17 @@ package org.gitlab4j.api.utils; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.Reader; +import java.nio.file.Files; +import java.util.Base64; import java.util.Scanner; import javax.ws.rs.core.Response; +import org.gitlab4j.api.Constants.Encoding; + /** * This class provides static utility methods used throughout GitLab4J. */ @@ -79,7 +84,7 @@ public static String readFileContents(File file) throws IOException { /** * Reads the content of a Reader instance and returns it as a String. - * + * * @param reader the Reader instance to read the content from * @return the content of a Reader instance as a String * @throws IOException if any error occurs @@ -95,4 +100,27 @@ public static String getReaderContentAsString(Reader reader) throws IOException 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()))); + } + } } diff --git a/src/test/java/org/gitlab4j/api/TestCommitsApi.java b/src/test/java/org/gitlab4j/api/TestCommitsApi.java index b6f9ef14d..b7c5fee31 100644 --- a/src/test/java/org/gitlab4j/api/TestCommitsApi.java +++ b/src/test/java/org/gitlab4j/api/TestCommitsApi.java @@ -1,24 +1,29 @@ package org.gitlab4j.api; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import java.text.ParseException; +import java.util.Arrays; import java.util.Date; import java.util.List; +import java.util.Optional; import javax.ws.rs.core.Response; import org.gitlab4j.api.models.Comment; 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.Diff; import org.gitlab4j.api.models.Project; import org.gitlab4j.api.models.RepositoryFile; import org.gitlab4j.api.utils.ISO8601; -import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.FixMethodOrder; @@ -40,9 +45,9 @@ @FixMethodOrder(MethodSorters.NAME_ASCENDING) 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 Project testProject; - private static boolean createdSubDirectoryPathFile = false; public TestCommitsApi() { super(); @@ -60,20 +65,10 @@ public static void setup() { repoFile.setFilePath(TEST_PROJECT_SUBDIRECTORY_PATH); repoFile.setContent("This is a test project used to test GitLab4J-API."); gitLabApi.getRepositoryFileApi().createFile(testProject, repoFile, "master", "Initial commit."); - createdSubDirectoryPathFile = true; } 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 public void beforeMethod() { assumeTrue(gitLabApi != null); @@ -198,4 +193,98 @@ public void testCommitsByPathNotFound() throws GitLabApiException { 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 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 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