Skip to content
This repository was archived by the owner on Apr 20, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -447,6 +450,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 {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went with request object, not sure where do you draw the line for sensible amount of parameters. Was on the fence with 3 here, with 4 for FileUpdate it seemed more clear cut.


/** 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,6 +40,7 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
Expand All @@ -56,14 +57,19 @@
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 com.spotify.github.v3.repos.requests.ImmutableFileUpdate;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
Expand All @@ -79,6 +85,7 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import uk.co.datumedge.hamcrest.json.SameJSONAs;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Saw it on classpath, okay to use? Do not want to worry about difference in whitespace/order in mock and real-deal.


public class RepositoryClientTest {

Expand Down Expand Up @@ -294,6 +301,58 @@ 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": "octocat@github.com"
},
"committer": {
"date": "2014-11-07T22:01:45Z",
"name": "Monalisa Octocat",
"email": "octocat@github.com"
},
"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 ..."
}
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": "octocat@github.com"
},
"committer": {
"date": "2014-11-07T22:01:45Z",
"name": "Monalisa Octocat",
"email": "octocat@github.com"
},
"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
}
}
}
Loading