diff --git a/src/main/java/com/spotify/github/v3/clients/IssueClient.java b/src/main/java/com/spotify/github/v3/clients/IssueClient.java index 1d965d27..2ba32318 100644 --- a/src/main/java/com/spotify/github/v3/clients/IssueClient.java +++ b/src/main/java/com/spotify/github/v3/clients/IssueClient.java @@ -26,6 +26,7 @@ import com.google.common.collect.ImmutableMap; import com.spotify.github.async.AsyncPage; import com.spotify.github.v3.comment.Comment; +import com.spotify.github.v3.issues.Issue; import java.lang.invoke.MethodHandles; import java.util.Iterator; import java.util.concurrent.CompletableFuture; @@ -38,6 +39,7 @@ public class IssueClient { static final String COMMENTS_URI_NUMBER_TEMPLATE = "/repos/%s/%s/issues/%s/comments"; static final String COMMENTS_URI_TEMPLATE = "/repos/%s/%s/issues/comments"; static final String COMMENTS_URI_ID_TEMPLATE = "/repos/%s/%s/issues/comments/%s"; + static final String ISSUES_URI_ID_TEMPLATE = "/repos/%s/%s/issues/%s"; private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private final GitHubClient github; @@ -125,4 +127,14 @@ public CompletableFuture deleteComment(final int id) { private Iterator> listComments(final String path) { return new GithubPageIterator<>(new GithubPage<>(github, path, LIST_COMMENT_TYPE_REFERENCE)); } + + /*** + * Get issue by id + * + * @param id + * @return the Issue for the given id if exists. + */ + public CompletableFuture getIssue(final int id) { + return github.request(String.format(ISSUES_URI_ID_TEMPLATE, owner, repo, id), Issue.class); + } } diff --git a/src/test/java/com/spotify/github/v3/clients/IssueClientTest.java b/src/test/java/com/spotify/github/v3/clients/IssueClientTest.java index dc7d1939..473fe26f 100644 --- a/src/test/java/com/spotify/github/v3/clients/IssueClientTest.java +++ b/src/test/java/com/spotify/github/v3/clients/IssueClientTest.java @@ -23,13 +23,18 @@ import static com.google.common.io.Resources.getResource; import static com.spotify.github.FixtureHelper.loadFixture; import static com.spotify.github.v3.clients.IssueClient.COMMENTS_URI_NUMBER_TEMPLATE; +import static com.spotify.github.v3.clients.IssueClient.ISSUES_URI_ID_TEMPLATE; import static com.spotify.github.v3.clients.MockHelper.createMockResponse; import static java.lang.String.format; import static java.nio.charset.Charset.defaultCharset; import static java.util.concurrent.CompletableFuture.completedFuture; +import static java.util.concurrent.CompletableFuture.failedFuture; import static java.util.stream.Collectors.toList; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -41,8 +46,13 @@ import com.spotify.github.async.AsyncPage; import com.spotify.github.jackson.Json; import com.spotify.github.v3.comment.Comment; +import com.spotify.github.v3.exceptions.RequestNotOkException; +import com.spotify.github.v3.issues.Issue; import java.io.IOException; +import java.util.HashMap; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import okhttp3.Response; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -51,11 +61,14 @@ public class IssueClientTest { private GitHubClient github; private IssueClient issueClient; + private Json json; + @BeforeEach public void setUp() { + json = Json.create(); github = mock(GitHubClient.class); - when(github.json()).thenReturn(Json.create()); + when(github.json()).thenReturn(json); when(github.urlFor("")).thenReturn("https://github.com/api/v3"); issueClient = new IssueClient(github, "someowner", "somerepo"); } @@ -132,4 +145,27 @@ public void testCommentCreated() throws IOException { assertThat(comment.id(), is(114)); } + + @Test + public void testGetIssue() throws IOException { + final String fixture = loadFixture("issues/issue.json"); + final CompletableFuture response = completedFuture(json.fromJson(fixture, Issue.class)); + final String path = format(ISSUES_URI_ID_TEMPLATE, "someowner", "somerepo", 2); + when(github.request(eq(path), eq(Issue.class))).thenReturn(response); + + final var issue = issueClient.getIssue(2).join(); + + assertThat(issue.id(), is(2)); + assertNotNull(issue.labels()); + assertFalse(issue.labels().isEmpty()); + assertThat(issue.labels().get(0).name(), is("bug")); + } + + @Test + public void testGetIssueNoIssue() { + final String path = format(ISSUES_URI_ID_TEMPLATE, "someowner", "somerepo", 2); + when(github.request(eq(path), eq(Issue.class))).thenReturn(failedFuture(new RequestNotOkException("", "", 404, "", new HashMap<>()))); + + assertThrows(CompletionException.class, () -> issueClient.getIssue(2).join()); + } } diff --git a/src/test/resources/com/spotify/github/v3/issues/issue.json b/src/test/resources/com/spotify/github/v3/issues/issue.json index 00e88af9..768fcdbf 100644 --- a/src/test/resources/com/spotify/github/v3/issues/issue.json +++ b/src/test/resources/com/spotify/github/v3/issues/issue.json @@ -1,5 +1,6 @@ { - "id": 1, + "id": 2, + "node_id": "MDU6SXNzdWUx", "url": "https://api.github.com/repos/octocat/Hello-World/issues/1347", "repository_url": "https://api.github.com/repos/octocat/Hello-World", "labels_url": "https://api.github.com/repos/octocat/Hello-World/issues/1347/labels{/name}", @@ -13,6 +14,7 @@ "user": { "login": "octocat", "id": 1, + "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", @@ -31,14 +33,19 @@ }, "labels": [ { + "id": 208045946, + "node_id": "MDU6TGFiZWwyMDgwNDU5NDY=", "url": "https://api.github.com/repos/octocat/Hello-World/labels/bug", "name": "bug", - "color": "f29513" + "description": "Something isn't working", + "color": "f29513", + "default": true } ], "assignee": { "login": "octocat", "id": 1, + "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", @@ -55,11 +62,34 @@ "type": "User", "site_admin": false }, + "assignees": [ + { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "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 + } + ], "milestone": { "url": "https://api.github.com/repos/octocat/Hello-World/milestones/1", "html_url": "https://github.com/octocat/Hello-World/milestones/v1.0", "labels_url": "https://api.github.com/repos/octocat/Hello-World/milestones/1/labels", "id": 1002604, + "node_id": "MDk6TWlsZXN0b25lMTAwMjYwNA==", "number": 1, "state": "open", "title": "v1.0", @@ -67,6 +97,7 @@ "creator": { "login": "octocat", "id": 1, + "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", @@ -90,7 +121,8 @@ "closed_at": "2013-02-12T13:22:01Z", "due_on": "2012-10-09T23:39:01Z" }, - "locked": false, + "locked": true, + "active_lock_reason": "too heated", "comments": 0, "pull_request": { "url": "https://api.github.com/repos/octocat/Hello-World/pulls/1347", @@ -100,5 +132,27 @@ }, "closed_at": null, "created_at": "2011-04-22T13:33:48Z", - "updated_at": "2011-04-22T13:33:48Z" + "updated_at": "2011-04-22T13:33:48Z", + "closed_by": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "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 + }, + "author_association": "COLLABORATOR", + "state_reason": "completed" } \ No newline at end of file