Skip to content

Commit

Permalink
feat: add support for creating and updating file contents
Browse files Browse the repository at this point in the history
  • Loading branch information
vootelerotov committed Sep 7, 2023
1 parent 1ffd719 commit 17cc521
Show file tree
Hide file tree
Showing 9 changed files with 351 additions and 0 deletions.
29 changes: 29 additions & 0 deletions src/main/java/com/spotify/github/v3/clients/RepositoryClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@
import com.spotify.github.v3.repos.CommitComparison;
import com.spotify.github.v3.repos.CommitItem;
import com.spotify.github.v3.repos.CommitStatus;
import com.spotify.github.v3.repos.CommitWithFolderContent;
import com.spotify.github.v3.repos.Content;
import com.spotify.github.v3.repos.requests.FileCreate;
import com.spotify.github.v3.repos.requests.FileUpdate;
import com.spotify.github.v3.repos.FolderContent;
import com.spotify.github.v3.repos.Languages;
import com.spotify.github.v3.repos.Repository;
Expand Down Expand Up @@ -394,6 +397,32 @@ public CompletableFuture<Content> getFileContent(final String path, final String
return github.request(getContentPath(path, "?ref=" + ref), Content.class);
}

/**
* Create a file
*
* @param path path to a file
* @param request file creation request
* @return commit with content
*/
public CompletableFuture<CommitWithFolderContent> createFileContent(final String path, final FileCreate request) {
final String contentPath = getContentPath(path, "");
final String requestBody = github.json().toJsonUnchecked(request);
return github.put(contentPath, requestBody, CommitWithFolderContent.class);
}

/**
* Update file contents
*
* @param path path to a file
* @param request file update request
* @return commit with content
*/
public CompletableFuture<CommitWithFolderContent> updateFileContent(final String path, final FileUpdate request) {
final String contentPath = getContentPath(path, "");
final String requestBody = github.json().toJsonUnchecked(request);
return github.put(contentPath, requestBody, CommitWithFolderContent.class);
}

/**
* Get repository contents of a folder.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*-
* -\-\-
* github-api
* --
* Copyright (C) 2016 - 2023 Spotify AB
* --
* 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.
* -/-/-
*/

package com.spotify.github.v3.repos;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.spotify.github.GithubStyle;
import com.spotify.github.v3.git.Commit;
import org.immutables.value.Value;

@Value.Immutable
@GithubStyle
@JsonSerialize(as = ImmutableCommitWithFolderContent.class)
@JsonDeserialize(as = ImmutableCommitWithFolderContent.class)
public interface CommitWithFolderContent {

/** Repository content resource */
FolderContent content();

/** Commit resource */
Commit commit();

}
49 changes: 49 additions & 0 deletions src/main/java/com/spotify/github/v3/repos/requests/FileCreate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*-
* -\-\-
* github-api
* --
* Copyright (C) 2016 - 2023 Spotify AB
* --
* 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.
* -/-/-
*/

package com.spotify.github.v3.repos.requests;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.spotify.github.GithubStyle;
import org.immutables.value.Value;

import javax.annotation.Nullable;

/**
* Request to create a file.
*/
@Value.Immutable
@GithubStyle
@JsonSerialize(as = ImmutableFileCreate.class)
@JsonDeserialize(as = ImmutableFileCreate.class)
public interface FileCreate {

/** The commit message */
String message();

/** The new file content, using Base64 encoding */
String content();

/** The branch name. Default: the repository’s default branch */
@Nullable
String branch();

}
52 changes: 52 additions & 0 deletions src/main/java/com/spotify/github/v3/repos/requests/FileUpdate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*-
* -\-\-
* github-api
* --
* Copyright (C) 2016 - 2023 Spotify AB
* --
* 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.
* -/-/-
*/

package com.spotify.github.v3.repos.requests;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.spotify.github.GithubStyle;
import org.immutables.value.Value;

import javax.annotation.Nullable;

/**
* Request to update file content.
*/
@Value.Immutable
@GithubStyle
@JsonSerialize(as = ImmutableFileUpdate.class)
@JsonDeserialize(as = ImmutableFileUpdate.class)
public interface FileUpdate {

/** The commit message */
String message();

/** The new file content, using Base64 encoding */
String content();

/** The SHA of the file being replaced. */
String sha();

/** The branch name. Default: the repository’s default branch */
@Nullable
String branch();

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.matches;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

Expand All @@ -56,19 +59,26 @@
import com.spotify.github.v3.repos.CommitComparison;
import com.spotify.github.v3.repos.CommitItem;
import com.spotify.github.v3.repos.CommitStatus;
import com.spotify.github.v3.repos.CommitWithFolderContent;
import com.spotify.github.v3.repos.Content;
import com.spotify.github.v3.repos.FolderContent;
import com.spotify.github.v3.repos.Repository;
import com.spotify.github.v3.repos.RepositoryInvitation;
import com.spotify.github.v3.repos.RepositoryPermission;
import com.spotify.github.v3.repos.RepositoryTest;
import com.spotify.github.v3.repos.Status;
import com.spotify.github.v3.repos.requests.FileCreate;
import com.spotify.github.v3.repos.requests.FileUpdate;
import com.spotify.github.v3.repos.requests.ImmutableAuthenticatedUserRepositoriesFilter;
import com.spotify.github.v3.repos.requests.ImmutableFileCreate;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import com.spotify.github.v3.repos.requests.ImmutableFileUpdate;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.Protocol;
Expand All @@ -79,8 +89,10 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import uk.co.datumedge.hamcrest.json.SameJSONAs;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ Headers.class, ResponseBody.class, Response.class})
Expand Down Expand Up @@ -298,6 +310,60 @@ public void getFileContent() throws Exception {
assertThat(fileContent.content(), is("encoded content ..."));
}

@Test
public void createFileContent() throws Exception {
String rawFileCreateRequest = getFixture("create-content-request.json");
final CompletableFuture<CommitWithFolderContent> fixture = completedFuture(
json.fromJson(getFixture("create-content-repsonse.json"), CommitWithFolderContent.class)
);
when(github.put(
eq("/repos/someowner/somerepo/contents/test/README.md"),
argThat(body -> SameJSONAs.sameJSONAs(rawFileCreateRequest).matches(body)),
eq(CommitWithFolderContent.class)
)).thenReturn(fixture);

FileCreate fileCreateRequest = ImmutableFileCreate.builder()
.message("my commit message")
.content("encoded content ...")
.build();

final CommitWithFolderContent commitWithFolderContent =
repoClient.createFileContent("test/README.md", fileCreateRequest).get();
assertThat(commitWithFolderContent.commit().message(), is("my commit message"));
assertThat(commitWithFolderContent.content().type(), is("file"));
assertThat(commitWithFolderContent.content().name(), is("README.md"));
assertThat(commitWithFolderContent.content().path(), is("test/README.md"));
}

@Test
public void updateFileContent() throws Exception {
String rawFileUpdateRequest = getFixture("update-content-request.json");
final CompletableFuture<CommitWithFolderContent> fixture = completedFuture(
json.fromJson(getFixture("create-content-repsonse.json"), CommitWithFolderContent.class)
);
when(github.put(
eq("/repos/someowner/somerepo/contents/test/README.md"),
argThat(body -> SameJSONAs.sameJSONAs(rawFileUpdateRequest).matches(body)),
eq(CommitWithFolderContent.class)
)).thenReturn(fixture);

FileUpdate fileUpdateRequest = ImmutableFileUpdate.builder()
.message("my commit message")
.content("encoded content ...")
.branch("test-branch")
.sha("12345")
.build();

final CommitWithFolderContent commitWithFolderContent =
repoClient.updateFileContent("test/README.md", fileUpdateRequest).get();
assertThat(commitWithFolderContent.commit().message(), is("my commit message"));
assertThat(commitWithFolderContent.content().type(), is("file"));
assertThat(commitWithFolderContent.content().name(), is("README.md"));
assertThat(commitWithFolderContent.content().path(), is("test/README.md"));
}



@Test
public void getFolderContent() throws Exception {
final CompletableFuture<List<FolderContent>> fixture =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"content": {
"name": "README.md",
"path": "test/README.md",
"sha": "95b966ae1c166bd92f8ae7d1c313e738c731dfc3",
"size": 9,
"url": "https://api.github.com/repos/someowner/somerepo/contents/test/README.md",
"html_url": "https://github.com/someowner/somerepo/blob/master/test/README.md",
"git_url": "https://api.github.com/repos/someowner/somerepo/git/blobs/95b966ae1c166bd92f8ae7d1c313e738c731dfc3",
"download_url": "https://raw.githubusercontent.com/someowner/HelloWorld/master/test/README.md",
"type": "file",
"_links": {
"self": "https://api.github.com/repos/someowner/somerepo/contents/test/README.md",
"git": "https://api.github.com/repos/someowner/somerepo/git/blobs/95b966ae1c166bd92f8ae7d1c313e738c731dfc3",
"html": "https://github.com/someowner/somerepo/blob/master/test/README.md"
}
},
"commit": {
"sha": "7638417db6d59f3c431d3e1f261cc637155684cd",
"node_id": "MDY6Q29tbWl0NzYzODQxN2RiNmQ1OWYzYzQzMWQzZTFmMjYxY2M2MzcxNTU2ODRjZA==",
"url": "https://api.github.com/repos/someowner/somerepo/git/commits/7638417db6d59f3c431d3e1f261cc637155684cd",
"html_url": "https://github.com/someowner/somerepo/git/commit/7638417db6d59f3c431d3e1f261cc637155684cd",
"author": {
"date": "2014-11-07T22:01:45Z",
"name": "Monalisa Octocat",
"email": "[email protected]"
},
"committer": {
"date": "2014-11-07T22:01:45Z",
"name": "Monalisa Octocat",
"email": "[email protected]"
},
"message": "my commit message",
"tree": {
"url": "https://api.github.com/repos/someowner/somerepo/git/trees/691272480426f78a0138979dd3ce63b77f706feb",
"sha": "691272480426f78a0138979dd3ce63b77f706feb"
},
"parents": [
{
"url": "https://api.github.com/repos/someowner/somerepo/git/commits/1acc419d4d6a9ce985db7be48c6349a0475975b5",
"html_url": "https://github.com/someowner/somerepo/git/commit/1acc419d4d6a9ce985db7be48c6349a0475975b5",
"sha": "1acc419d4d6a9ce985db7be48c6349a0475975b5"
}
],
"verification": {
"verified": false,
"reason": "unsigned",
"signature": null,
"payload": null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"message": "my commit message",
"content": "encoded content ..."
}
Loading

0 comments on commit 17cc521

Please sign in to comment.