Skip to content
This repository was archived by the owner on Apr 20, 2026. It is now read-only.
Closed
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
2 changes: 2 additions & 0 deletions src/main/java/com/spotify/github/jackson/GithubApiModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,7 @@ public class GithubApiModule extends SimpleModule {
public GithubApiModule() {
addSerializer(GitHubInstantJsonSerializer.INSTANCE);
addDeserializer(GitHubInstant.class, GitHubInstantJsonDeserializer.INSTANCE);
addSerializer(LabelSerializer.INSTANCE);
addSerializer(UserSerializer.INSTANCE);
}
}
48 changes: 48 additions & 0 deletions src/main/java/com/spotify/github/jackson/LabelSerializer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*-

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This serializer seems like it could be replaced by Jackson annotations too - thoughts?

* -\-\-
* 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.jackson;

import static java.util.Objects.isNull;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.spotify.github.v3.issues.Label;
import java.io.IOException;

class LabelSerializer extends StdSerializer<Label> {

static final LabelSerializer INSTANCE = new LabelSerializer();

private LabelSerializer() {
super(Label.class);
}

@Override
public void serialize(final Label value, final JsonGenerator gen, final SerializerProvider serializers)
throws IOException {
if (isNull(value)) {
gen.writeNull();
} else {
serializers.defaultSerializeValue(value.name(), gen);
}
}
}
48 changes: 48 additions & 0 deletions src/main/java/com/spotify/github/jackson/UserSerializer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*-

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This serializer seems like it could be replaced by Jackson annotations too - thoughts?

* -\-\-
* 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.jackson;

import static java.util.Objects.isNull;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.spotify.github.v3.User;
import java.io.IOException;

class UserSerializer extends StdSerializer<User> {

static final UserSerializer INSTANCE = new UserSerializer();

private UserSerializer() {
super(User.class);
}

@Override
public void serialize(final User value, final JsonGenerator gen, final SerializerProvider serializers)
throws IOException {
if (isNull(value)) {
gen.writeNull();
} else {
serializers.defaultSerializeValue(value.login(), gen);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import com.spotify.github.v3.exceptions.ReadOnlyRepositoryException;
import com.spotify.github.v3.exceptions.RequestNotOkException;
import com.spotify.github.v3.git.Reference;
import com.spotify.github.v3.issues.Issue;
import com.spotify.github.v3.issues.Label;
import com.spotify.github.v3.prs.PullRequestItem;
import com.spotify.github.v3.prs.Review;
import com.spotify.github.v3.prs.ReviewRequests;
Expand Down Expand Up @@ -70,8 +72,12 @@ public class GitHubClient {
response.body().close();
}
};
static final TypeReference<List<Comment>> LIST_COMMENT_TYPE_REFERENCE =
static final TypeReference<List<Issue>> LIST_ISSUE_TYPE_REFERENCE =
new TypeReference<>() {};
static final TypeReference<List<Comment>> LIST_COMMENT_TYPE_REFERENCE =
new TypeReference<>() {};
static final TypeReference<List<Label>> LIST_LABEL_TYPE_REFERENCE =
new TypeReference<>() {};
static final TypeReference<List<Repository>> LIST_REPOSITORY =
new TypeReference<>() {};
static final TypeReference<List<CommitItem>> LIST_COMMIT_TYPE_REFERENCE =
Expand Down
53 changes: 53 additions & 0 deletions src/main/java/com/spotify/github/v3/clients/IssueClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@

import static com.spotify.github.v3.clients.GitHubClient.IGNORE_RESPONSE_CONSUMER;
import static com.spotify.github.v3.clients.GitHubClient.LIST_COMMENT_TYPE_REFERENCE;
import static com.spotify.github.v3.clients.GitHubClient.LIST_ISSUE_TYPE_REFERENCE;

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;
Expand All @@ -35,6 +37,8 @@
/** Issue API client */
public class IssueClient {

static final String ISSUES_URI_TEMPLATE = "/repos/%s/%s/issues";
static final String ISSUES_URI_ID_TEMPLATE = "/repos/%s/%s/issues/%s";
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";
Expand All @@ -54,6 +58,51 @@ static IssueClient create(final GitHubClient github, final String owner, final S
return new IssueClient(github, owner, repo);
}

/**
* List repository issues.
*
* @return issues
*/
public Iterator<AsyncPage<Issue>> listIssues() {
return listIssues(String.format(ISSUES_URI_TEMPLATE, owner, repo));
}

/**
* Get a specific issue.
*
* @param number issue number
* @return an issue
*/
public CompletableFuture<Issue> getIssue(final int number) {
final String path = String.format(ISSUES_URI_ID_TEMPLATE, owner, repo, number);
log.info("Fetching issue from " + path);
return github.request(path, Issue.class);
}

/**
* Create an Issue
*
* @param issue an issue
* @return the Issue that was just created
*/
public CompletableFuture<Issue> createIssue(final Issue issue) {
final String path = String.format(ISSUES_URI_TEMPLATE, owner, repo);
final String requestBody = github.json().toJsonUnchecked(issue);
return github.post(path, requestBody, Issue.class);
}

/**
* Edit a specific issue.
*
* @param issue an issue
*/
public CompletableFuture<Void> editIssue(final Issue issue) {
final String path = String.format(ISSUES_URI_ID_TEMPLATE, owner, repo, issue.number());
return github
.patch(path, github.json().toJsonUnchecked(issue))
.thenAccept(IGNORE_RESPONSE_CONSUMER);
}

/**
* List repository comments.
*
Expand Down Expand Up @@ -122,6 +171,10 @@ public CompletableFuture<Void> deleteComment(final int id) {
.thenAccept(IGNORE_RESPONSE_CONSUMER);
}

private Iterator<AsyncPage<Issue>> listIssues(final String path) {
return new GithubPageIterator<>(new GithubPage<>(github, path, LIST_ISSUE_TYPE_REFERENCE));
}

private Iterator<AsyncPage<Comment>> listComments(final String path) {
return new GithubPageIterator<>(new GithubPage<>(github, path, LIST_COMMENT_TYPE_REFERENCE));
}
Expand Down
16 changes: 16 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 @@ -23,6 +23,7 @@
import static com.spotify.github.v3.clients.GitHubClient.IGNORE_RESPONSE_CONSUMER;
import static com.spotify.github.v3.clients.GitHubClient.LIST_COMMIT_TYPE_REFERENCE;
import static com.spotify.github.v3.clients.GitHubClient.LIST_FOLDERCONTENT_TYPE_REFERENCE;
import static com.spotify.github.v3.clients.GitHubClient.LIST_LABEL_TYPE_REFERENCE;
import static com.spotify.github.v3.clients.GitHubClient.LIST_STATUS_TYPE_REFERENCE;
import static com.spotify.github.v3.clients.GitHubClient.LIST_BRANCHES;
import static com.spotify.github.v3.clients.GitHubClient.LIST_REPOSITORY;
Expand All @@ -34,6 +35,7 @@
import com.spotify.github.v3.exceptions.RequestNotOkException;
import com.spotify.github.v3.git.Tree;
import com.spotify.github.v3.hooks.requests.WebhookCreate;
import com.spotify.github.v3.issues.Label;
import com.spotify.github.v3.repos.Branch;
import com.spotify.github.v3.repos.Commit;
import com.spotify.github.v3.repos.CommitComparison;
Expand Down Expand Up @@ -82,6 +84,7 @@ public class RepositoryClient {
private static final String LIST_REPOSITORY_TEMPLATE = "/orgs/%s/repos";
private static final String LIST_REPOSITORIES_FOR_AUTHENTICATED_USER = "/user/repos";
private static final String IS_USER_COLLABORATOR_OF_REPO = "/repos/%s/%s/collaborators/%s";
private static final String LABELS_URI_TEMPLATE = "/repos/%s/%s/labels";
private final String owner;
private final String repo;
private final GitHubClient github;
Expand Down Expand Up @@ -506,10 +509,23 @@ public CompletableFuture<Repository> createFork(final String organization) {
});
}

/**
* List repository labels.
*
* @return labels
*/
public Iterator<AsyncPage<Label>> listLabels() {
return listLabels(String.format(LABELS_URI_TEMPLATE, owner, repo));
}

private String getContentPath(final String path, final String query) {
if (path.startsWith("/") || path.endsWith("/")) {
throw new IllegalArgumentException(path + " starts or ends with '/'");
}
return String.format(CONTENTS_URI_TEMPLATE, owner, repo, path, query);
}

private Iterator<AsyncPage<Label>> listLabels(final String path) {
return new GithubPageIterator<>(new GithubPage<>(github, path, LIST_LABEL_TYPE_REFERENCE));
}
}
7 changes: 7 additions & 0 deletions src/main/java/com/spotify/github/v3/issues/Issue.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

package com.spotify.github.v3.issues;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.spotify.github.CloseTracking;
Expand Down Expand Up @@ -92,8 +93,14 @@ public interface Issue extends CloseTracking {
List<Label> labels();

/** Login for the user that this issue should be assigned to. */
@JsonInclude(JsonInclude.Include.NON_ABSENT)
Optional<User> assignee();
Comment thread
GriffinCodes marked this conversation as resolved.

/** Logins for the users that this issue should be assigned to. */
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@Nullable
List<User> assignees();

/** The milestone associated this issue with. */
Optional<Milestone> milestone();

Expand Down