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 f9704459..22d86bf8 100644 --- a/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java +++ b/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java @@ -27,6 +27,7 @@ import static com.spotify.github.v3.clients.GitHubClient.LIST_BRANCHES; import static com.spotify.github.v3.clients.GitHubClient.LIST_REPOSITORY; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import com.spotify.github.async.AsyncPage; import com.spotify.github.v3.comment.Comment; @@ -44,6 +45,7 @@ import com.spotify.github.v3.repos.Repository; import com.spotify.github.v3.repos.Status; import com.spotify.github.v3.repos.requests.RepositoryCreateStatus; +import com.spotify.github.v3.repos.requests.AuthenticatedUserRepositoriesFilter; import java.lang.invoke.MethodHandles; import java.util.Iterator; import java.util.List; @@ -78,6 +80,7 @@ public class RepositoryClient { private static final String MERGE_TEMPLATE = "/repos/%s/%s/merges"; private static final String FORK_TEMPLATE = "/repos/%s/%s/forks"; private static final String LIST_REPOSITORY_TEMPLATE = "/orgs/%s/repos"; + private static final String LIST_REPOSITORIES_FOR_AUTHENTICATED_USER = "/user/repos"; private final String owner; private final String repo; @@ -152,6 +155,18 @@ public CompletableFuture> listOrganizationRepositories() { return github.request(path, LIST_REPOSITORY); } + /** + * List repositories for the authenticated user. + * + * @param filter filter parameters + * @return list of repositories for the authenticated user + */ + public Iterator> listAuthenticatedUserRepositories(final AuthenticatedUserRepositoriesFilter filter) { + final String serial = filter.serialize(); + final String path = LIST_REPOSITORIES_FOR_AUTHENTICATED_USER + (Strings.isNullOrEmpty(serial) ? "" : "?" + serial); + return new GithubPageIterator<>(new GithubPage<>(github, path, LIST_REPOSITORY)); + } + /** * Create a webhook. * diff --git a/src/main/java/com/spotify/github/v3/repos/requests/AuthenticatedUserRepositoriesFilter.java b/src/main/java/com/spotify/github/v3/repos/requests/AuthenticatedUserRepositoriesFilter.java new file mode 100644 index 00000000..9aace7e6 --- /dev/null +++ b/src/main/java/com/spotify/github/v3/repos/requests/AuthenticatedUserRepositoriesFilter.java @@ -0,0 +1,75 @@ +/*- + * -\-\- + * 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 javax.annotation.Nullable; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.spotify.github.GithubStyle; +import com.spotify.github.Parameters; +import org.immutables.value.Value; + +/** + * Filter parameters for listing authenticated user's repositories. To be + * serialized as key=value. + */ +@Value.Immutable +@GithubStyle +@JsonSerialize(as = ImmutableAuthenticatedUserRepositoriesFilter.class) +@JsonDeserialize(as = ImmutableAuthenticatedUserRepositoriesFilter.class) +public interface AuthenticatedUserRepositoriesFilter extends Parameters { + + /** + * Can be one of all, public, or private. Default: all + */ + @Nullable String visibility(); + + /** + * Comma-separated list of values. Can include: + * * owner: Repositories that are owned by the authenticated user. + * * collaborator: Repositories that the user has been added to as a + * collaborator. + * * organization_member: Repositories that the user has access to through + * being a member of an organization. This includes every repository on + * every team that the user is on. + * + * Default: owner,collaborator,organization_member + */ + @Nullable String affiliation(); + + /** + * Can be one of all, owner, public, private, member. Default: all + * Will cause a 422 error if used in the same request as visibility or + * affiliation. + */ + @Nullable String type(); + + /** + * Can be one of created, updated, pushed, full_name. Default: full_name + */ + @Nullable String sort(); + + /** + * Can be one of asc or desc. Default: asc when using full_name, otherwise + * desc + * */ + @Nullable String direction(); +} 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 fa0c45ad..599abf52 100644 --- a/src/test/java/com/spotify/github/v3/clients/RepositoryClientTest.java +++ b/src/test/java/com/spotify/github/v3/clients/RepositoryClientTest.java @@ -37,10 +37,12 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static java.util.stream.StreamSupport.stream; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.io.Resources; +import com.spotify.github.async.AsyncPage; import com.spotify.github.jackson.Json; import com.spotify.github.v3.comment.Comment; import com.spotify.github.v3.repos.Branch; @@ -53,10 +55,12 @@ import com.spotify.github.v3.repos.Repository; import com.spotify.github.v3.repos.RepositoryTest; import com.spotify.github.v3.repos.Status; +import com.spotify.github.v3.repos.requests.ImmutableAuthenticatedUserRepositoriesFilter; import java.io.IOException; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import okhttp3.Headers; import okhttp3.MediaType; import okhttp3.Protocol; @@ -113,6 +117,24 @@ public void listOrganizationRepositories() throws Exception { assertThat(repositories.size(), is(1)); } + @Test + public void listAuthenticatedUserRepositories() throws Exception { + final String pageLink = "; rel=\"first\""; + final String pageBody = getFixture("list_of_repos_for_authenticated_user.json"); + final Response pageResponse = createMockResponse(pageLink, pageBody); + + when(github.request("/user/repos")).thenReturn(completedFuture(pageResponse)); + + final Iterable> pageIterator = () -> repoClient.listAuthenticatedUserRepositories(ImmutableAuthenticatedUserRepositoriesFilter.builder().build()); + final List repositories = + stream(pageIterator.spliterator(), false) + .flatMap(page -> stream(page.spliterator(), false)) + .collect(Collectors.toList()); + + assertThat(repositories.get(0).id(), is(1296269)); + assertThat(repositories.size(), is(1)); + } + @Test public void listCommits() throws Exception { final CompletableFuture> fixture = diff --git a/src/test/resources/com/spotify/github/v3/repos/list_of_repos_for_authenticated_user.json b/src/test/resources/com/spotify/github/v3/repos/list_of_repos_for_authenticated_user.json new file mode 100644 index 00000000..1fce8937 --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/repos/list_of_repos_for_authenticated_user.json @@ -0,0 +1,93 @@ +[ + { + "id": 1296269, + "owner": { + "login": "octocat", + "id": 1, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "description": "This your first repo!", + "private": false, + "fork": true, + "url": "https://api.github.com/repos/octocat/Hello-World", + "html_url": "https://github.com/octocat/Hello-World", + "archive_url": "http://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", + "assignees_url": "http://api.github.com/repos/octocat/Hello-World/assignees{/user}", + "blobs_url": "http://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", + "branches_url": "http://api.github.com/repos/octocat/Hello-World/branches{/branch}", + "clone_url": "https://github.com/octocat/Hello-World.git", + "collaborators_url": "http://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", + "comments_url": "http://api.github.com/repos/octocat/Hello-World/comments{/number}", + "commits_url": "http://api.github.com/repos/octocat/Hello-World/commits{/sha}", + "compare_url": "http://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", + "contents_url": "http://api.github.com/repos/octocat/Hello-World/contents/{+path}", + "contributors_url": "http://api.github.com/repos/octocat/Hello-World/contributors", + "deployments_url": "http://api.github.com/repos/octocat/Hello-World/deployments", + "downloads_url": "http://api.github.com/repos/octocat/Hello-World/downloads", + "events_url": "http://api.github.com/repos/octocat/Hello-World/events", + "forks_url": "http://api.github.com/repos/octocat/Hello-World/forks", + "git_commits_url": "http://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", + "git_refs_url": "http://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", + "git_tags_url": "http://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", + "git_url": "git:github.com/octocat/Hello-World.git", + "hooks_url": "http://api.github.com/repos/octocat/Hello-World/hooks", + "issue_comment_url": "http://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", + "issue_events_url": "http://api.github.com/repos/octocat/Hello-World/issues/events{/number}", + "issues_url": "http://api.github.com/repos/octocat/Hello-World/issues{/number}", + "keys_url": "http://api.github.com/repos/octocat/Hello-World/keys{/key_id}", + "labels_url": "http://api.github.com/repos/octocat/Hello-World/labels{/name}", + "languages_url": "http://api.github.com/repos/octocat/Hello-World/languages", + "merges_url": "http://api.github.com/repos/octocat/Hello-World/merges", + "milestones_url": "http://api.github.com/repos/octocat/Hello-World/milestones{/number}", + "mirror_url": "git:git.example.com/octocat/Hello-World", + "notifications_url": "http://api.github.com/repos/octocat/Hello-World/notifications{?since, all, participating}", + "pulls_url": "http://api.github.com/repos/octocat/Hello-World/pulls{/number}", + "releases_url": "http://api.github.com/repos/octocat/Hello-World/releases{/id}", + "ssh_url": "git@github.com:octocat/Hello-World.git", + "stargazers_url": "http://api.github.com/repos/octocat/Hello-World/stargazers", + "statuses_url": "http://api.github.com/repos/octocat/Hello-World/statuses/{sha}", + "subscribers_url": "http://api.github.com/repos/octocat/Hello-World/subscribers", + "subscription_url": "http://api.github.com/repos/octocat/Hello-World/subscription", + "svn_url": "https://svn.github.com/octocat/Hello-World", + "tags_url": "http://api.github.com/repos/octocat/Hello-World/tags", + "teams_url": "http://api.github.com/repos/octocat/Hello-World/teams", + "trees_url": "http://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", + "homepage": "https://github.com", + "language": null, + "forks_count": 9, + "stargazers_count": 80, + "watchers_count": 80, + "size": 108, + "default_branch": "master", + "open_issues_count": 0, + "has_issues": true, + "has_wiki": true, + "forks": 2, + "has_pages": false, + "has_downloads": true, + "pushed_at": "2011-01-26T19:06:43Z", + "created_at": "2011-01-26T19:01:12Z", + "updated_at": "2011-01-26T19:14:43Z", + "permissions": { + "admin": false, + "push": false, + "pull": true + } + } +] \ No newline at end of file