From 0649896af6bd219c47a87ea44b2e14b2666864b4 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Mon, 18 Mar 2024 14:50:05 +0100 Subject: [PATCH] feat: Add RepoUpdate endpoint --- .../github/v3/clients/RepositoryClient.java | 75 ++-- .../github/v3/repos/RepositoryBase.java | 4 + .../v3/repos/requests/RepositoryUpdate.java | 166 +++++++++ .../v3/clients/RepositoryClientTest.java | 335 ++++++++++-------- 4 files changed, 407 insertions(+), 173 deletions(-) create mode 100644 src/main/java/com/spotify/github/v3/repos/requests/RepositoryUpdate.java diff --git a/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java b/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java index f48f0687..97fd5bc1 100644 --- a/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java +++ b/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java @@ -44,15 +44,13 @@ 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.requests.*; import com.spotify.github.v3.repos.FolderContent; import com.spotify.github.v3.repos.Languages; import com.spotify.github.v3.repos.Repository; import com.spotify.github.v3.repos.RepositoryInvitation; import com.spotify.github.v3.repos.Status; -import com.spotify.github.v3.repos.requests.AuthenticatedUserRepositoriesFilter; -import com.spotify.github.v3.repos.requests.RepositoryCreateStatus; + import java.io.InputStream; import java.lang.invoke.MethodHandles; import java.util.Iterator; @@ -79,7 +77,8 @@ public class RepositoryClient { public static final String STATUS_URI_TEMPLATE = "/repos/%s/%s/statuses/%s"; private static final String COMMITS_URI_TEMPLATE = "/repos/%s/%s/commits"; private static final String COMMIT_SHA_URI_TEMPLATE = "/repos/%s/%s/commits/%s"; - private static final String COMMIT_PULL_REQUESTS_SHA_URI_TEMPLATE = "/repos/%s/%s/commits/%s/pulls"; + private static final String COMMIT_PULL_REQUESTS_SHA_URI_TEMPLATE = + "/repos/%s/%s/commits/%s/pulls"; private static final String COMMIT_STATUS_URI_TEMPLATE = "/repos/%s/%s/commits/%s/status"; private static final String TREE_SHA_URI_TEMPLATE = "/repos/%s/%s/git/trees/%s"; private static final String COMPARE_COMMIT_TEMPLATE = "/repos/%s/%s/compare/%s...%s"; @@ -160,6 +159,18 @@ public CompletableFuture getRepository() { return github.request(path, Repository.class); } + /** + * Update Repository properties + * https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#update-a-repository + * + * @return repository information + */ + public CompletableFuture updateRepository(final RepositoryUpdate repoUpdate) { + final String path = String.format(REPOSITORY_URI_TEMPLATE, owner, repo); + final String data = github.json().toJsonUnchecked(repoUpdate); + return github.patch(path, data, Repository.class); + } + /** * List all repositories in this organization. * @@ -199,13 +210,13 @@ public CompletableFuture isCollaborator(final String user) { /** * Add a collaborator to the repo. * - * @param user the GitHub username to add + * @param user the GitHub username to add * @param permission the permission level for the user; one of RepositoryPermission, or a custom - * role + * role * @return */ - public CompletableFuture> addCollaborator(final String user, - final String permission) { + public CompletableFuture> addCollaborator( + final String user, final String permission) { final String path = String.format(REPOSITORY_COLLABORATOR, owner, repo, user); final String data = github.json().toJsonUnchecked(Map.of("permission", permission)); return github @@ -216,12 +227,12 @@ public CompletableFuture> addCollaborator(final S // not called. if (response.code() == NO_CONTENT) { /* - GitHub returns a 204 when: - - an existing collaborator is added as a collaborator - - an organization member is added as an individual collaborator - - an existing team member (whose team is also a repository collaborator) is - added as a collaborator - */ + GitHub returns a 204 when: + - an existing collaborator is added as a collaborator + - an organization member is added as an individual collaborator + - an existing team member (whose team is also a repository collaborator) is + added as a collaborator + */ return Optional.empty(); } final RepositoryInvitation invitation = @@ -284,18 +295,22 @@ public CompletableFuture> downloadZipball(final String ref return downloadRepository(REPOSITORY_DOWNLOAD_ZIPBALL, Optional.of(ref)); } - private CompletableFuture> downloadRepository(final String path, final Optional maybeRef) { + private CompletableFuture> downloadRepository( + final String path, final Optional maybeRef) { final var repoRef = maybeRef.orElse(""); final var repoPath = String.format(path, owner, repo, repoRef); - return github.request(repoPath).thenApply(response -> { - var body = response.body(); + return github + .request(repoPath) + .thenApply( + response -> { + var body = response.body(); - if (body == null) { - return Optional.empty(); - } + if (body == null) { + return Optional.empty(); + } - return Optional.of(body.byteStream()); - }); + return Optional.of(body.byteStream()); + }); } /** @@ -457,7 +472,8 @@ public CompletableFuture getFileContent(final String path, final String * @param request file creation request * @return commit with content */ - public CompletableFuture createFileContent(final String path, final FileCreate request) { + public CompletableFuture 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); @@ -470,7 +486,8 @@ public CompletableFuture createFileContent(final String * @param request file update request * @return commit with content */ - public CompletableFuture updateFileContent(final String path, final FileUpdate request) { + public CompletableFuture 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); @@ -546,9 +563,8 @@ public CompletableFuture getBranch(final String branch) { } /** - * List some branches in repository. - * Doesn't return more than 30 branches. - * Use {@link RepositoryClient#listAllBranches} instead to get all branches. + * List some branches in repository. Doesn't return more than 30 branches. Use {@link + * RepositoryClient#listAllBranches} instead to get all branches. * * @return list of 30 branches in repository */ @@ -557,7 +573,7 @@ public CompletableFuture> listBranches() { return github.request(path, LIST_BRANCHES); } - /** + /** * List all branches in repository * * @return list of all branches in repository @@ -567,7 +583,6 @@ public Iterator> listAllBranches() { return new GithubPageIterator<>(new GithubPage<>(github, path, LIST_BRANCHES)); } - /** * Delete a comment for a given id. * diff --git a/src/main/java/com/spotify/github/v3/repos/RepositoryBase.java b/src/main/java/com/spotify/github/v3/repos/RepositoryBase.java index f8431f75..5e91f696 100644 --- a/src/main/java/com/spotify/github/v3/repos/RepositoryBase.java +++ b/src/main/java/com/spotify/github/v3/repos/RepositoryBase.java @@ -79,6 +79,10 @@ public interface RepositoryBase extends UpdateTracking { @Nullable URI htmlUrl(); + /** Allow auto merges */ + @Nullable + Boolean allowAutoMerge(); + /** Allow squash merges */ @Nullable Boolean allowSquashMerge(); diff --git a/src/main/java/com/spotify/github/v3/repos/requests/RepositoryUpdate.java b/src/main/java/com/spotify/github/v3/repos/requests/RepositoryUpdate.java new file mode 100644 index 00000000..edd61422 --- /dev/null +++ b/src/main/java/com/spotify/github/v3/repos/requests/RepositoryUpdate.java @@ -0,0 +1,166 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 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.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.spotify.github.GithubStyle; +import java.util.Optional; +import org.immutables.value.Value; + +@Value.Immutable +@GithubStyle +@JsonSerialize(as = ImmutableRepositoryUpdate.class) +@JsonDeserialize(as = ImmutableRepositoryUpdate.class) +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public interface RepositoryUpdate { + + /** Description */ + Optional description(); + + /** Allow auto merges */ + Optional allowAutoMerge(); + + /** + * Either true to allow private forks, or false to prevent private forks. + * + *

Default: false + */ + Optional allowForking(); + + /** Allow squash merges */ + Optional allowSquashMerge(); + + /** Allow merge commits */ + Optional allowMergeCommit(); + + /** Allow rebase merges */ + Optional allowRebaseMerge(); + + /** + * Either true to always allow a pull request head branch that is behind its base branch to be + * updated even if it is not required to be up to date before merging, or false otherwise. + * + *

Default: false + */ + Optional allowUpdateBranch(); + + /** Updates the default branch for this repository. */ + Optional defaultBranch(); + + /** + * Either true to allow automatically deleting head branches when pull requests are merged, or + * false to prevent automatic deletion. + * + *

Default: false + */ + Optional deleteBranchOnMerge(); + + /** Homepage URL */ + Optional homepage(); + + /** Does it have downloads */ + Optional hasDownloads(); + + /** Does it have issues */ + Optional hasIssues(); + + /** Does it have wiki */ + Optional hasWiki(); + + /** Does it have pages */ + Optional hasPages(); + + /** Does it have projects */ + Optional hasProjects(); + + /** + * Whether to archive this repository. false will unarchive a previously archived repository. + * + *

Default: false + */ + @JsonProperty("archived") + Optional isArchived(); + + /** Is it private */ + @JsonProperty("private") + Optional isPrivate(); + + /** + * Either true to make this repo available as a template repository or false to prevent it. + * Default: false + */ + Optional isTemplate(); + + /** + * The default value for a squash merge commit message: + * + *

PR_BODY - default to the pull request's body. COMMIT_MESSAGES - default to the branch's + * commit messages. BLANK - default to a blank commit message. Can be one of: PR_BODY, + * COMMIT_MESSAGES, BLANK + */ + Optional squashMergeCommitMessage(); + + /** + * squash_merge_commit_title string The default value for a squash merge commit title: + * + *

PR_TITLE - default to the pull request's title. COMMIT_OR_PR_TITLE - default to the commit's + * title (if only one commit) or the pull request's title (when more than one commit). Can be one + * of: PR_TITLE, COMMIT_OR_PR_TITLE + */ + Optional squashMergeCommitTitle(); + + /** + * The default value for a merge commit message. + * + *

PR_TITLE - default to the pull request's title. PR_BODY - default to the pull request's + * body. BLANK - default to a blank commit message. + */ + Optional mergeCommitMessage(); + + /** + * The default value for a merge commit title. + * + *

PR_TITLE - default to the pull request's title. MERGE_MESSAGE - default to the classic title + * for a merge message (e.g., Merge pull request #123 from branch-name). Can be one of: PR_TITLE, + * MERGE_MESSAGE + */ + Optional mergeCommitTitle(); + + /** + * The id of the team that will be granted access to this repository. This is only valid when + * creating a repository in an organization. Default: false + */ + Optional teamId(); + + /** The visibility of the repo. Can be one of `public`, `private`, `internal` */ + Optional visibility(); + + /** + * Either true to require contributors to sign off on web-based commits, or false to not require + * contributors to sign off on web-based commits. + * + *

Default: false + */ + Optional webCommitSignoffRequired(); +} diff --git a/src/test/java/com/spotify/github/v3/clients/RepositoryClientTest.java b/src/test/java/com/spotify/github/v3/clients/RepositoryClientTest.java index ab286d07..3f1e8e56 100644 --- a/src/test/java/com/spotify/github/v3/clients/RepositoryClientTest.java +++ b/src/test/java/com/spotify/github/v3/clients/RepositoryClientTest.java @@ -38,9 +38,7 @@ import static org.hamcrest.core.Is.is; 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.ArgumentMatchers.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -65,11 +63,8 @@ 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 com.spotify.github.v3.repos.requests.*; + import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; @@ -120,6 +115,24 @@ public void getRepository() throws Exception { assertThat(repository.fork(), is(false)); } + @Test + public void updateRepository() throws Exception { + final CompletableFuture fixture = + completedFuture(json.fromJson(getFixture("repository_get.json"), Repository.class)); + when(github.patch(eq("/repos/someowner/somerepo"), eq("{\"allow_auto_merge\":true}"), eq(Repository.class))) + .thenReturn(fixture); + RepositoryUpdate request = + ImmutableRepositoryUpdate.builder().allowAutoMerge(Optional.of(true)).build(); + final Repository repository = repoClient.updateRepository(request).get(); + assertThat(repository.id(), is(1296269)); + assertUser(repository.owner()); + assertThat(repository.name(), is("Hello-World")); + assertThat(repository.fullName(), is(repository.owner().login() + "/Hello-World")); + assertThat(repository.isPrivate(), is(false)); + assertThat(repository.isArchived(), is(false)); + assertThat(repository.fork(), is(false)); + } + @Test public void listOrganizationRepositories() throws Exception { final CompletableFuture> fixture = @@ -138,8 +151,12 @@ public void listAuthenticatedUserRepositories() throws Exception { when(github.request("/user/repos")).thenReturn(completedFuture(pageResponse)); - final Iterable> pageIterator = () -> repoClient.listAuthenticatedUserRepositories(ImmutableAuthenticatedUserRepositoriesFilter.builder().build()); - final List repositories = Async.streamFromPaginatingIterable(pageIterator).collect(Collectors.toList()); + final Iterable> pageIterator = + () -> + repoClient.listAuthenticatedUserRepositories( + ImmutableAuthenticatedUserRepositoriesFilter.builder().build()); + final List repositories = + Async.streamFromPaginatingIterable(pageIterator).collect(Collectors.toList()); assertThat(repositories.get(0).id(), is(1296269)); assertThat(repositories.size(), is(1)); @@ -149,7 +166,8 @@ public void listAuthenticatedUserRepositories() throws Exception { public void isCollaborator() throws Exception { final Response response = mock(Response.class); when(response.code()).thenReturn(204); - when(github.request("/repos/someowner/somerepo/collaborators/user")).thenReturn(completedFuture(response)); + when(github.request("/repos/someowner/somerepo/collaborators/user")) + .thenReturn(completedFuture(response)); boolean isCollaborator = repoClient.isCollaborator("user").get(); assertTrue(isCollaborator); } @@ -158,7 +176,8 @@ public void isCollaborator() throws Exception { public void isNotCollaborator() throws Exception { final Response response = mock(Response.class); when(response.code()).thenReturn(404); - when(github.request("/repos/someowner/somerepo/collaborators/user")).thenReturn(completedFuture(response)); + when(github.request("/repos/someowner/somerepo/collaborators/user")) + .thenReturn(completedFuture(response)); boolean isCollaborator = repoClient.isCollaborator("user").get(); assertFalse(isCollaborator); } @@ -166,11 +185,11 @@ public void isNotCollaborator() throws Exception { @Test public void addCollaborator() throws Exception { final Response response = createMockResponse("", getFixture("repository_invitation.json")); - when(github.put("/repos/someowner/somerepo/collaborators/user", "{\"permission\":\"pull\"}")).thenReturn( - completedFuture(response)); + when(github.put("/repos/someowner/somerepo/collaborators/user", "{\"permission\":\"pull\"}")) + .thenReturn(completedFuture(response)); - final Optional maybeInvite = repoClient.addCollaborator("user", - RepositoryPermission.PULL).get(); + final Optional maybeInvite = + repoClient.addCollaborator("user", RepositoryPermission.PULL).get(); assertTrue(maybeInvite.isPresent()); final RepositoryInvitation repoInvite = maybeInvite.get(); @@ -187,11 +206,11 @@ public void addCollaborator() throws Exception { public void addCollaboratorUserExists() throws Exception { final Response response = mock(Response.class); when(response.code()).thenReturn(204); - when(github.put("/repos/someowner/somerepo/collaborators/user", "{\"permission\":\"pull\"}")).thenReturn( - completedFuture(response)); + when(github.put("/repos/someowner/somerepo/collaborators/user", "{\"permission\":\"pull\"}")) + .thenReturn(completedFuture(response)); - final Optional maybeInvite = repoClient.addCollaborator("user", - RepositoryPermission.PULL).get(); + final Optional maybeInvite = + repoClient.addCollaborator("user", RepositoryPermission.PULL).get(); assertTrue(maybeInvite.isEmpty()); } @@ -223,16 +242,16 @@ public void removeInvite() throws Exception { @Test public void listInvites() throws Exception { final CompletableFuture> fixture = - completedFuture( - json.fromJson("[" + getFixture("repository_invitation.json") + "]", LIST_REPOSITORY_INVITATION)); + completedFuture( + json.fromJson( + "[" + getFixture("repository_invitation.json") + "]", LIST_REPOSITORY_INVITATION)); when(github.request("/repos/someowner/somerepo/invitations", LIST_REPOSITORY_INVITATION)) - .thenReturn(fixture); + .thenReturn(fixture); final List invitations = repoClient.listInvitations().get(); assertThat(invitations.size(), is(1)); assertThat(invitations.get(0).repository().name(), is("Hello-World")); - assertThat( - invitations.get(0).inviter().login(), is("octocat")); + assertThat(invitations.get(0).inviter().login(), is("octocat")); } @Test @@ -254,8 +273,12 @@ public void listCommits() throws Exception { public void listPullRequestsForCommit() throws Exception { final CompletableFuture> fixture = completedFuture( - json.fromJson("[" + getFixture("../prs/pull_request_item.json") + "]", LIST_PR_TYPE_REFERENCE)); - when(github.request(eq("/repos/someowner/somerepo/commits/thesha/pulls"), eq(LIST_PR_TYPE_REFERENCE), any())) + json.fromJson( + "[" + getFixture("../prs/pull_request_item.json") + "]", LIST_PR_TYPE_REFERENCE)); + when(github.request( + eq("/repos/someowner/somerepo/commits/thesha/pulls"), + eq(LIST_PR_TYPE_REFERENCE), + any())) .thenReturn(fixture); final List prs = repoClient.listPullRequestsForCommit("thesha").get(); assertThat(prs.size(), is(1)); @@ -301,19 +324,21 @@ public void getFileContent() throws Exception { @Test public void createFileContent() throws Exception { String rawFileCreateRequest = getFixture("create-content-request.json"); - final CompletableFuture fixture = completedFuture( - json.fromJson(getFixture("create-content-repsonse.json"), CommitWithFolderContent.class) - ); + final CompletableFuture 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); + 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(); + FileCreate fileCreateRequest = + ImmutableFileCreate.builder() + .message("my commit message") + .content("encoded content ...") + .build(); final CommitWithFolderContent commitWithFolderContent = repoClient.createFileContent("test/README.md", fileCreateRequest).get(); @@ -326,21 +351,23 @@ public void createFileContent() throws Exception { @Test public void updateFileContent() throws Exception { String rawFileUpdateRequest = getFixture("update-content-request.json"); - final CompletableFuture fixture = completedFuture( - json.fromJson(getFixture("create-content-repsonse.json"), CommitWithFolderContent.class) - ); + final CompletableFuture 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(); + 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(); @@ -394,14 +421,18 @@ public void getBranch() throws Exception { .thenReturn(fixture); final Branch branch = repoClient.getBranch("somebranch").get(); assertThat(branch.isProtected().orElse(false), is(true)); - assertThat(branch.protectionUrl().get().toString(), is("https://api.github.com/repos/octocat/Hello-World/branches/master/protection")); + assertThat( + branch.protectionUrl().get().toString(), + is("https://api.github.com/repos/octocat/Hello-World/branches/master/protection")); assertThat(branch.commit().sha(), is("6dcb09b5b57875f334f61aebed695e2e4193db5e")); assertThat( branch.commit().url().toString(), - is("https://api.github.com/repos/octocat/Hello-World/commits/c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc")); + is( + "https://api.github.com/repos/octocat/Hello-World/commits/c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc")); assertTrue(branch.protection().isPresent()); assertTrue(branch.protection().get().enabled()); - assertThat(branch.protection().get().requiredStatusChecks().enforcementLevel(), is("non_admins")); + assertThat( + branch.protection().get().requiredStatusChecks().enforcementLevel(), is("non_admins")); assertTrue(branch.protection().get().requiredStatusChecks().contexts().contains("Context 1")); assertTrue(branch.protection().get().requiredStatusChecks().contexts().contains("Context 2")); } @@ -421,7 +452,8 @@ public void getBranchWithNoProtection() throws Exception { @Test public void getBranchWithoutProtectionFields() throws Exception { final CompletableFuture fixture = - completedFuture(json.fromJson(getFixture("branch-no-protection-fields.json"), Branch.class)); + completedFuture( + json.fromJson(getFixture("branch-no-protection-fields.json"), Branch.class)); when(github.request("/repos/someowner/somerepo/branches/somebranch", Branch.class)) .thenReturn(fixture); final Branch branch = repoClient.getBranch("somebranch").get(); @@ -430,41 +462,47 @@ public void getBranchWithoutProtectionFields() throws Exception { assertThat(branch.commit().sha(), is("6dcb09b5b57875f334f61aebed695e2e4193db5e")); assertThat( branch.commit().url().toString(), - is("https://api.github.com/repos/octocat/Hello-World/commits/c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc")); + is( + "https://api.github.com/repos/octocat/Hello-World/commits/c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc")); } @Test public void getBranchWithCharactersIncorrectlyUnescapedByTheGithubApi() throws Exception { final CompletableFuture fixture = completedFuture(json.fromJson(getFixture("branch-escape-chars.json"), Branch.class)); - when(github.request("/repos/someowner/somerepo/branches/unescaped-percent-sign-%", Branch.class)) + when(github.request( + "/repos/someowner/somerepo/branches/unescaped-percent-sign-%", Branch.class)) .thenReturn(fixture); final Branch branch = repoClient.getBranch("unescaped-percent-sign-%").get(); assertThat(branch.commit().sha(), is("6dcb09b5b57875f334f61aebed695e2e4193db5e")); assertThat( branch.protectionUrl().get().toString(), - is("https://api.github.com/repos/octocat/Hello-World/branches/unescaped-percent-sign-%25/protection")); + is( + "https://api.github.com/repos/octocat/Hello-World/branches/unescaped-percent-sign-%25/protection")); } @Test - public void getBranchWithCharactersIncorrectlyUnescapedByTheGithubApi_uriVariationTwo() throws Exception { + public void getBranchWithCharactersIncorrectlyUnescapedByTheGithubApi_uriVariationTwo() + throws Exception { final CompletableFuture fixture = - completedFuture(json.fromJson(getFixture("branch-escape-chars-url-variation-two.json"), Branch.class)); - when(github.request("/repos/someowner/somerepo/branches/unescaped-percent-sign-%", Branch.class)) + completedFuture( + json.fromJson(getFixture("branch-escape-chars-url-variation-two.json"), Branch.class)); + when(github.request( + "/repos/someowner/somerepo/branches/unescaped-percent-sign-%", Branch.class)) .thenReturn(fixture); final Branch branch = repoClient.getBranch("unescaped-percent-sign-%").get(); assertThat(branch.commit().sha(), is("6dcb09b5b57875f334f61aebed695e2e4193db5e")); assertThat( branch.protectionUrl().get().toString(), - is("https://api.github.com/api/v3/repos/octocat/Hello-World/branches/branch-name-with-slashes/unescaped-percent-sign-%25/protection")); + is( + "https://api.github.com/api/v3/repos/octocat/Hello-World/branches/branch-name-with-slashes/unescaped-percent-sign-%25/protection")); } @Test public void listBranches() throws Exception { final CompletableFuture> fixture = completedFuture(json.fromJson(getFixture("list_branches.json"), LIST_BRANCHES)); - when(github.request("/repos/someowner/somerepo/branches", LIST_BRANCHES)) - .thenReturn(fixture); + when(github.request("/repos/someowner/somerepo/branches", LIST_BRANCHES)).thenReturn(fixture); final List branches = repoClient.listBranches().get(); assertThat(branches.get(0).commit().sha(), is("c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc")); assertThat(branches.size(), is(1)); @@ -472,12 +510,15 @@ public void listBranches() throws Exception { @Test void listAllBranches() throws Exception { - final String link = "; rel=\"last\""; - final Response response = createMockResponse(link, getFixture( "list_branches.json")); + final String link = + "; rel=\"last\""; + final Response response = createMockResponse(link, getFixture("list_branches.json")); when(github.request("/repos/someowner/somerepo/branches")) .thenReturn(completedFuture(response)); - final List branches = Async.streamFromPaginatingIterable(repoClient::listAllBranches).collect(Collectors.toList()); + final List branches = + Async.streamFromPaginatingIterable(repoClient::listAllBranches) + .collect(Collectors.toList()); assertThat(branches.get(0).commit().sha(), is("c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc")); assertThat(branches.size(), is(1)); } @@ -527,16 +568,24 @@ public void testStatusesPaginationForeach() throws Exception { when(github.urlFor("")).thenReturn("https://github.com/api/v3"); when(github.request( - format(STATUS_URI_TEMPLATE, "someowner", "somerepo", "553c2077f0edc3d5dc5d17262f6aa498e69d6f8e"))) + format( + STATUS_URI_TEMPLATE, + "someowner", + "somerepo", + "553c2077f0edc3d5dc5d17262f6aa498e69d6f8e"))) .thenReturn(completedFuture(firstPageResponse)); when(github.request( - format(STATUS_URI_TEMPLATE + "?page=2", "someowner", "somerepo", "553c2077f0edc3d5dc5d17262f6aa498e69d6f8e"))) + format( + STATUS_URI_TEMPLATE + "?page=2", + "someowner", + "somerepo", + "553c2077f0edc3d5dc5d17262f6aa498e69d6f8e"))) .thenReturn(completedFuture(lastPageResponse)); final List listStatuses = Lists.newArrayList(); - repoClient.listCommitStatuses("553c2077f0edc3d5dc5d17262f6aa498e69d6f8e", 10) - .forEachRemaining(page -> page.iterator() - .forEachRemaining(listStatuses::add)); + repoClient + .listCommitStatuses("553c2077f0edc3d5dc5d17262f6aa498e69d6f8e", 10) + .forEachRemaining(page -> page.iterator().forEachRemaining(listStatuses::add)); assertThat(listStatuses.size(), is(12)); assertThat(listStatuses.get(0).id(), is(61764535L)); @@ -545,23 +594,23 @@ public void testStatusesPaginationForeach() throws Exception { @Test public void merge() throws IOException { - CompletableFuture okResponse = completedFuture( - new Response.Builder() - .request(new Request.Builder().url("http://example.com/whatever").build()) - .protocol(Protocol.HTTP_1_1) - .message("") - .code(201) - .body( - ResponseBody.create( - MediaType.get("application/json"), - getFixture("merge_commit_item.json") - )) - .build()); - final String expectedRequestBody = json.toJsonUnchecked(ImmutableMap.of( - "base", "basebranch", - "head", "headbranch")); - when(github - .post("/repos/someowner/somerepo/merges", expectedRequestBody)) + CompletableFuture okResponse = + completedFuture( + new Response.Builder() + .request(new Request.Builder().url("http://example.com/whatever").build()) + .protocol(Protocol.HTTP_1_1) + .message("") + .code(201) + .body( + ResponseBody.create( + MediaType.get("application/json"), getFixture("merge_commit_item.json"))) + .build()); + final String expectedRequestBody = + json.toJsonUnchecked( + ImmutableMap.of( + "base", "basebranch", + "head", "headbranch")); + when(github.post("/repos/someowner/somerepo/merges", expectedRequestBody)) .thenReturn(okResponse); final CommitItem commit = repoClient.merge("basebranch", "headbranch").join().get(); @@ -572,21 +621,19 @@ public void merge() throws IOException { @Test public void createFork() throws IOException { - CompletableFuture okResponse = completedFuture( - new Response.Builder() - .request(new Request.Builder().url("http://example.com/whatever").build()) - .protocol(Protocol.HTTP_1_1) - .message("") - .code(202) - .body( - ResponseBody.create( - MediaType.get("application/json"), - getFixture("fork_create_item.json") - )) - .build()); + CompletableFuture okResponse = + completedFuture( + new Response.Builder() + .request(new Request.Builder().url("http://example.com/whatever").build()) + .protocol(Protocol.HTTP_1_1) + .message("") + .code(202) + .body( + ResponseBody.create( + MediaType.get("application/json"), getFixture("fork_create_item.json"))) + .build()); final String expectedRequestBody = json.toJsonUnchecked(ImmutableMap.of()); - when(github - .post("/repos/someowner/somerepo/forks", expectedRequestBody)) + when(github.post("/repos/someowner/somerepo/forks", expectedRequestBody)) .thenReturn(okResponse); final Repository repo = repoClient.createFork(null).join(); @@ -595,13 +642,14 @@ public void createFork() throws IOException { @Test public void mergeNoop() { - CompletableFuture okResponse = completedFuture( - new Response.Builder() - .request(new Request.Builder().url("http://example.com/whatever").build()) - .protocol(Protocol.HTTP_1_1) - .message("") - .code(204) // No Content - .build()); + CompletableFuture okResponse = + completedFuture( + new Response.Builder() + .request(new Request.Builder().url("http://example.com/whatever").build()) + .protocol(Protocol.HTTP_1_1) + .message("") + .code(204) // No Content + .build()); when(github.post(any(), any())).thenReturn(okResponse); final Optional maybeCommit = repoClient.merge("basebranch", "headbranch").join(); assertThat(maybeCommit, is(Optional.empty())); @@ -609,21 +657,21 @@ public void mergeNoop() { @Test public void shouldDownloadTarball() throws Exception { - CompletableFuture fixture = completedFuture( - new Response.Builder() - .request(new Request.Builder().url("https://example.com/whatever").build()) - .protocol(Protocol.HTTP_1_1) - .message("") - .code(200) - .body( - ResponseBody.create( - "some bytes".getBytes(StandardCharsets.UTF_8), - MediaType.get("application/gzip") - )) - .build()); + CompletableFuture fixture = + completedFuture( + new Response.Builder() + .request(new Request.Builder().url("https://example.com/whatever").build()) + .protocol(Protocol.HTTP_1_1) + .message("") + .code(200) + .body( + ResponseBody.create( + "some bytes".getBytes(StandardCharsets.UTF_8), + MediaType.get("application/gzip"))) + .build()); when(github.request("/repos/someowner/somerepo/tarball/")).thenReturn(fixture); - try(InputStream response = repoClient.downloadTarball().get().orElseThrow()) { + try (InputStream response = repoClient.downloadTarball().get().orElseThrow()) { String result = new String(response.readAllBytes(), StandardCharsets.UTF_8); assertThat(result, is("some bytes")); } @@ -631,18 +679,18 @@ public void shouldDownloadTarball() throws Exception { @Test public void shouldDownloadZipball() throws Exception { - CompletableFuture fixture = completedFuture( - new Response.Builder() - .request(new Request.Builder().url("https://example.com/whatever").build()) - .protocol(Protocol.HTTP_1_1) - .message("") - .code(200) - .body( - ResponseBody.create( - "some bytes".getBytes(StandardCharsets.UTF_8), - MediaType.get("application/gzip") - )) - .build()); + CompletableFuture fixture = + completedFuture( + new Response.Builder() + .request(new Request.Builder().url("https://example.com/whatever").build()) + .protocol(Protocol.HTTP_1_1) + .message("") + .code(200) + .body( + ResponseBody.create( + "some bytes".getBytes(StandardCharsets.UTF_8), + MediaType.get("application/gzip"))) + .build()); when(github.request("/repos/someowner/somerepo/zipball/")).thenReturn(fixture); try (InputStream response = repoClient.downloadZipball().get().orElseThrow()) { @@ -653,13 +701,14 @@ public void shouldDownloadZipball() throws Exception { @Test public void shouldReturnEmptyOptionalWhenResponseBodyNotPresent() throws Exception { - CompletableFuture fixture = completedFuture( - new Response.Builder() - .request(new Request.Builder().url("https://example.com/whatever").build()) - .protocol(Protocol.HTTP_1_1) - .message("") - .code(204) // No Content - .build()); + CompletableFuture fixture = + completedFuture( + new Response.Builder() + .request(new Request.Builder().url("https://example.com/whatever").build()) + .protocol(Protocol.HTTP_1_1) + .message("") + .code(204) // No Content + .build()); when(github.request("/repos/someowner/somerepo/zipball/master")).thenReturn(fixture); Optional response = repoClient.downloadZipball("master").get();