diff --git a/pom.xml b/pom.xml index 21fb790eb6..9d55c08537 100644 --- a/pom.xml +++ b/pom.xml @@ -28,6 +28,8 @@ UTF-8 + 3.0.1 + true @@ -47,11 +49,11 @@ org.codehaus.mojo findbugs-maven-plugin - 3.0.1 + ${findbugs-maven-plugin.version} true true - false + ${findbugs-maven-plugin.failOnError} diff --git a/src/main/java/org/kohsuke/github/DeleteToken.java b/src/main/java/org/kohsuke/github/DeleteToken.java index eb61011920..d9d4724eb9 100644 --- a/src/main/java/org/kohsuke/github/DeleteToken.java +++ b/src/main/java/org/kohsuke/github/DeleteToken.java @@ -23,9 +23,13 @@ */ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + /** * @author Kohsuke Kawaguchi */ +@SuppressFBWarnings(value = "UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD", + justification = "Being constructed by JSON deserialization") class DeleteToken { public String delete_token; } diff --git a/src/main/java/org/kohsuke/github/GHAuthorization.java b/src/main/java/org/kohsuke/github/GHAuthorization.java index f990cbefb3..b8b7aff19a 100644 --- a/src/main/java/org/kohsuke/github/GHAuthorization.java +++ b/src/main/java/org/kohsuke/github/GHAuthorization.java @@ -1,5 +1,6 @@ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.net.URL; import java.util.Collection; import java.util.Date; @@ -59,6 +60,8 @@ public String getAppName() { return app.name; } + @SuppressFBWarnings(value = "NM_CONFUSING", + justification = "It's a part of the library API, cannot be changed") public URL getApiURL() { return GitHub.parseURL(url); } @@ -84,7 +87,8 @@ public URL getNoteUrl() { return this; } - + @SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD"}, + justification = "JSON API") private static class App { private String url; private String name; diff --git a/src/main/java/org/kohsuke/github/GHBranch.java b/src/main/java/org/kohsuke/github/GHBranch.java index 9c3d331adc..272c643f47 100644 --- a/src/main/java/org/kohsuke/github/GHBranch.java +++ b/src/main/java/org/kohsuke/github/GHBranch.java @@ -1,10 +1,14 @@ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + /** * A branch in a repository. * * @author Yusuke Kokubo */ +@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", + "NP_UNWRITTEN_FIELD"}, justification = "JSON API") public class GHBranch { private GitHub root; private GHRepository owner; @@ -13,7 +17,10 @@ public class GHBranch { private Commit commit; public static class Commit { - String sha,url; + String sha; + + @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now") + String url; } public GitHub getRoot() { @@ -37,7 +44,7 @@ public String getName() { public String getSHA1() { return commit.sha; } - + @Override public String toString() { final String url = owner != null ? owner.getUrl().toString() : "unknown"; diff --git a/src/main/java/org/kohsuke/github/GHCommit.java b/src/main/java/org/kohsuke/github/GHCommit.java index ce56cddd6b..b45683f2d2 100644 --- a/src/main/java/org/kohsuke/github/GHCommit.java +++ b/src/main/java/org/kohsuke/github/GHCommit.java @@ -1,6 +1,7 @@ package org.kohsuke.github; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; import java.net.URL; @@ -16,6 +17,8 @@ * @see GHRepository#getCommit(String) * @see GHCommitComment#getCommit() */ +@SuppressFBWarnings(value = {"NP_UNWRITTEN_FIELD", "UWF_UNWRITTEN_FIELD"}, + justification = "JSON API") public class GHCommit { private GHRepository owner; @@ -24,6 +27,8 @@ public class GHCommit { /** * Short summary of this commit. */ + @SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", + "NP_UNWRITTEN_FIELD", "UWF_UNWRITTEN_FIELD"}, justification = "JSON API") public static class ShortInfo { private GHAuthor author; private GHAuthor committer; @@ -67,6 +72,8 @@ public static class Stats { /** * A file that was modified. */ + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", + justification = "It's being initilized by JSON deserialization") public static class File { String status; int changes,additions,deletions; @@ -104,6 +111,8 @@ public String getStatus() { /** * Full path in the repository. */ + @SuppressFBWarnings(value = "NM_CONFUSING", + justification = "It's a part of the library's API and cannot be renamed") public String getFileName() { return filename; } @@ -147,13 +156,19 @@ public String getSha() { } public static class Parent { - String url,sha; + @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now") + String url; + String sha; } static class User { // TODO: what if someone who doesn't have an account on GitHub makes a commit? - String url,avatar_url,login,gravatar_id; + @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now") + String url,avatar_url,gravatar_id; + @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now") int id; + + String login; } String url,sha; diff --git a/src/main/java/org/kohsuke/github/GHCommitComment.java b/src/main/java/org/kohsuke/github/GHCommitComment.java index 7deebbc6ad..7020f9b98f 100644 --- a/src/main/java/org/kohsuke/github/GHCommitComment.java +++ b/src/main/java/org/kohsuke/github/GHCommitComment.java @@ -1,5 +1,6 @@ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; import java.net.URL; import java.util.Date; @@ -12,6 +13,8 @@ * @see GHCommit#listComments() * @see GHCommit#createComment(String, String, Integer, Integer) */ +@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", + "NP_UNWRITTEN_FIELD"}, justification = "JSON API") public class GHCommitComment extends GHObject { private GHRepository owner; @@ -22,8 +25,12 @@ public class GHCommitComment extends GHObject { static class User { // TODO: what if someone who doesn't have an account on GitHub makes a commit? - String url,avatar_url,login,gravatar_id; + @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now") + String url,avatar_url,gravatar_id; + @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now") int id; + + String login; } public GHRepository getOwner() { @@ -83,7 +90,7 @@ public GHCommit getCommit() throws IOException { * Updates the body of the commit message. */ public void update(String body) throws IOException { - GHCommitComment r = new Requester(owner.root) + new Requester(owner.root) .with("body", body) .method("PATCH").to(getApiTail(), GHCommitComment.class); this.body = body; diff --git a/src/main/java/org/kohsuke/github/GHCompare.java b/src/main/java/org/kohsuke/github/GHCompare.java index 2c2bc5ba72..c9c882ba4e 100644 --- a/src/main/java/org/kohsuke/github/GHCompare.java +++ b/src/main/java/org/kohsuke/github/GHCompare.java @@ -1,8 +1,10 @@ package org.kohsuke.github; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.net.URL; +import java.util.Arrays; import java.util.Date; /** @@ -65,12 +67,20 @@ public Commit getMergeBaseCommit() { return merge_base_commit; } + /** + * Gets an array of commits. + * @return A copy of the array being stored in the class. + */ public Commit[] getCommits() { - return commits; + return Arrays.copyOf(commits, commits.length); } + /** + * Gets an array of commits. + * @return A copy of the array being stored in the class. + */ public GHCommit.File[] getFiles() { - return files; + return Arrays.copyOf(files, files.length); } public GHCompare wrap(GHRepository owner) { @@ -87,6 +97,8 @@ public GHCompare wrap(GHRepository owner) { * Compare commits had a child commit element with additional details we want to capture. * This extenstion of GHCommit provides that. */ + @SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD"}, + justification = "JSON API") public static class Commit extends GHCommit { private InnerCommit commit; diff --git a/src/main/java/org/kohsuke/github/GHContent.java b/src/main/java/org/kohsuke/github/GHContent.java index 8ab48d2fdd..bc96af5ddc 100644 --- a/src/main/java/org/kohsuke/github/GHContent.java +++ b/src/main/java/org/kohsuke/github/GHContent.java @@ -76,7 +76,7 @@ public String getPath() { * Use {@link #read()} */ public String getContent() throws IOException { - return new String(DatatypeConverter.parseBase64Binary(getEncodedContent())); + return new String(DatatypeConverter.parseBase64Binary(getEncodedContent()), getEncoding()); } /** @@ -162,11 +162,11 @@ protected void wrapUp(GHContent[] page) { } public GHContentUpdateResponse update(String newContent, String commitMessage) throws IOException { - return update(newContent.getBytes(), commitMessage, null); + return update(newContent.getBytes(getEncoding()), commitMessage, null); } public GHContentUpdateResponse update(String newContent, String commitMessage, String branch) throws IOException { - return update(newContent.getBytes(), commitMessage, branch); + return update(newContent.getBytes(getEncoding()), commitMessage, branch); } public GHContentUpdateResponse update(byte[] newContentBytes, String commitMessage) throws IOException { diff --git a/src/main/java/org/kohsuke/github/GHDeploymentStatus.java b/src/main/java/org/kohsuke/github/GHDeploymentStatus.java index c8679c1343..a058b8a447 100644 --- a/src/main/java/org/kohsuke/github/GHDeploymentStatus.java +++ b/src/main/java/org/kohsuke/github/GHDeploymentStatus.java @@ -1,6 +1,7 @@ package org.kohsuke.github; import java.net.URL; +import java.util.Locale; public class GHDeploymentStatus extends GHObject { private GHRepository owner; @@ -28,8 +29,9 @@ public URL getDeploymentUrl() { public URL getRepositoryUrl() { return GitHub.parseURL(repository_url); } + public GHDeploymentState getState() { - return GHDeploymentState.valueOf(state.toUpperCase()); + return GHDeploymentState.valueOf(state.toUpperCase(Locale.ENGLISH)); } /** diff --git a/src/main/java/org/kohsuke/github/GHDeploymentStatusBuilder.java b/src/main/java/org/kohsuke/github/GHDeploymentStatusBuilder.java index 4310153800..b1ecf8918c 100644 --- a/src/main/java/org/kohsuke/github/GHDeploymentStatusBuilder.java +++ b/src/main/java/org/kohsuke/github/GHDeploymentStatusBuilder.java @@ -1,6 +1,7 @@ package org.kohsuke.github; import java.io.IOException; +import java.util.Locale; public class GHDeploymentStatusBuilder { private final Requester builder; @@ -11,7 +12,7 @@ public GHDeploymentStatusBuilder(GHRepository repo, int deploymentId, GHDeployme this.repo = repo; this.deploymentId = deploymentId; this.builder = new Requester(repo.root); - this.builder.with("state",state.toString().toLowerCase()); + this.builder.with("state",state.toString().toLowerCase(Locale.ENGLISH)); } public GHDeploymentStatusBuilder description(String description) { diff --git a/src/main/java/org/kohsuke/github/GHEmail.java b/src/main/java/org/kohsuke/github/GHEmail.java index 5f230c5945..9eeac04336 100644 --- a/src/main/java/org/kohsuke/github/GHEmail.java +++ b/src/main/java/org/kohsuke/github/GHEmail.java @@ -23,12 +23,16 @@ */ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + /** * Represents an email of GitHub. * * @author Kelly Campbell */ +@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", + "NP_UNWRITTEN_FIELD", "NP_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD"}, justification = "JSON API") public class GHEmail { protected String email; diff --git a/src/main/java/org/kohsuke/github/GHEventInfo.java b/src/main/java/org/kohsuke/github/GHEventInfo.java index 09db42aa0f..9772cba16e 100644 --- a/src/main/java/org/kohsuke/github/GHEventInfo.java +++ b/src/main/java/org/kohsuke/github/GHEventInfo.java @@ -4,12 +4,14 @@ import java.util.Date; import com.fasterxml.jackson.databind.node.ObjectNode; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; /** * Represents an event. * * @author Kohsuke Kawaguchi */ +@SuppressFBWarnings(value = "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", justification = "JSON API") public class GHEventInfo { private GitHub root; @@ -27,8 +29,12 @@ public class GHEventInfo { /** * Inside the event JSON model, GitHub uses a slightly different format. */ + @SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", + "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" }, justification = "JSON API") public static class GHEventRepository { + @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now") private int id; + @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now") private String url; // repository API URL private String name; // owner/repo } @@ -55,10 +61,14 @@ public Date getCreatedAt() { /** * Repository where the change was made. */ + @SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" }, + justification = "The field comes from JSON deserialization") public GHRepository getRepository() throws IOException { return root.getRepository(repo.name); } + @SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" }, + justification = "The field comes from JSON deserialization") public GHUser getActor() throws IOException { return root.getUser(actor.getLogin()); } @@ -70,6 +80,8 @@ public String getActorLogin() throws IOException { return actor.getLogin(); } + @SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" }, + justification = "The field comes from JSON deserialization") public GHOrganization getOrganization() throws IOException { return (org==null || org.getLogin()==null) ? null : root.getOrganization(org.getLogin()); } diff --git a/src/main/java/org/kohsuke/github/GHEventPayload.java b/src/main/java/org/kohsuke/github/GHEventPayload.java index e60fa40193..08b112880d 100644 --- a/src/main/java/org/kohsuke/github/GHEventPayload.java +++ b/src/main/java/org/kohsuke/github/GHEventPayload.java @@ -1,5 +1,6 @@ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.Reader; import java.util.List; @@ -25,6 +26,8 @@ public abstract class GHEventPayload { * * @see authoritative source */ + @SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", + "NP_UNWRITTEN_FIELD"}, justification = "JSON API") public static class PullRequest extends GHEventPayload { private String action; private int number; @@ -67,12 +70,15 @@ void wrapUp(GitHub root) { * * @see authoritative source */ + @SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", "NP_UNWRITTEN_FIELD" }, + justification = "Constructed by JSON deserialization") public static class IssueComment extends GHEventPayload { private String action; private GHIssueComment comment; private GHIssue issue; private GHRepository repository; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Comes from JSON deserialization") public String getAction() { return action; } diff --git a/src/main/java/org/kohsuke/github/GHHook.java b/src/main/java/org/kohsuke/github/GHHook.java index ce8c8a4dfd..7d63f9d950 100644 --- a/src/main/java/org/kohsuke/github/GHHook.java +++ b/src/main/java/org/kohsuke/github/GHHook.java @@ -1,5 +1,6 @@ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; import java.net.URL; import java.util.Collections; @@ -11,6 +12,8 @@ /** * @author Kohsuke Kawaguchi */ +@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", + "NP_UNWRITTEN_FIELD"}, justification = "JSON API") public abstract class GHHook extends GHObject { String name; List events; diff --git a/src/main/java/org/kohsuke/github/GHIssue.java b/src/main/java/org/kohsuke/github/GHIssue.java index e7864087dd..d45e49b935 100644 --- a/src/main/java/org/kohsuke/github/GHIssue.java +++ b/src/main/java/org/kohsuke/github/GHIssue.java @@ -25,6 +25,7 @@ package org.kohsuke.github; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; import java.net.URL; @@ -269,6 +270,8 @@ public GHMilestone getMilestone() { return milestone; } + @SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD"}, + justification = "JSON API") public static class PullRequest{ private String diff_url, patch_url, html_url; diff --git a/src/main/java/org/kohsuke/github/GHKey.java b/src/main/java/org/kohsuke/github/GHKey.java index 91632cf175..63ab7b3ff9 100644 --- a/src/main/java/org/kohsuke/github/GHKey.java +++ b/src/main/java/org/kohsuke/github/GHKey.java @@ -1,5 +1,6 @@ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.apache.commons.lang.builder.ToStringBuilder; /** @@ -7,6 +8,7 @@ * * @author Kohsuke Kawaguchi */ +@SuppressFBWarnings(value = "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", justification = "JSON API") public class GHKey { /*package almost final*/ GitHub root; @@ -33,6 +35,10 @@ public String getUrl() { return url; } + public GitHub getRoot() { + return root; + } + public boolean isVerified() { return verified; } diff --git a/src/main/java/org/kohsuke/github/GHMyself.java b/src/main/java/org/kohsuke/github/GHMyself.java index 2041336367..74ba96189d 100644 --- a/src/main/java/org/kohsuke/github/GHMyself.java +++ b/src/main/java/org/kohsuke/github/GHMyself.java @@ -6,6 +6,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TreeMap; @@ -159,7 +160,7 @@ public PagedIterable listRepositories(final int pageSize, final Re return new PagedIterable() { public PagedIterator iterator() { return new PagedIterator(root.retrieve().asIterator("/user/repos?per_page=" + pageSize + - "&type=" + repoType.name().toLowerCase(), GHRepository[].class)) { + "&type=" + repoType.name().toLowerCase(Locale.ENGLISH), GHRepository[].class)) { @Override protected void wrapUp(GHRepository[] page) { for (GHRepository c : page) diff --git a/src/main/java/org/kohsuke/github/GHNotificationStream.java b/src/main/java/org/kohsuke/github/GHNotificationStream.java index 5ea6fb69cb..b8f8d7c296 100644 --- a/src/main/java/org/kohsuke/github/GHNotificationStream.java +++ b/src/main/java/org/kohsuke/github/GHNotificationStream.java @@ -152,7 +152,7 @@ GHThread fetch() { while (true) { long now = System.currentTimeMillis(); if (nextCheckTime < now) break; - long waitTime = Math.max(Math.min(nextCheckTime - now, 1000), 60 * 1000); + long waitTime = Math.min(Math.max(nextCheckTime - now, 1000), 60 * 1000); Thread.sleep(waitTime); } @@ -180,7 +180,8 @@ GHThread fetch() { private long calcNextCheckTime() { String v = req.getResponseHeader("X-Poll-Interval"); if (v==null) v="60"; - return System.currentTimeMillis()+Integer.parseInt(v)*1000; + long seconds = Integer.parseInt(v); + return System.currentTimeMillis() + seconds*1000; } public void remove() { diff --git a/src/main/java/org/kohsuke/github/GHObject.java b/src/main/java/org/kohsuke/github/GHObject.java index 914f1280d3..50aa0a6a86 100644 --- a/src/main/java/org/kohsuke/github/GHObject.java +++ b/src/main/java/org/kohsuke/github/GHObject.java @@ -1,6 +1,7 @@ package org.kohsuke.github; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; import java.net.URL; @@ -9,6 +10,8 @@ /** * Most (all?) domain objects in GitHub seems to have these 4 properties. */ +@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", + "NP_UNWRITTEN_FIELD"}, justification = "JSON API") public abstract class GHObject { protected String url; protected int id; @@ -26,10 +29,6 @@ public Date getCreatedAt() throws IOException { return GitHub.parseDate(created_at); } - private Object createdAtStr(Date id, Class type) { - return created_at; - } - /** * API URL of this object. */ @@ -58,12 +57,4 @@ public Date getUpdatedAt() throws IOException { public int getId() { return id; } - - private Object intToString(int id, Class type) { - return String.valueOf(id); - } - - private Object urlToString(URL url, Class type) { - return url==null ? null : url.toString(); - } } diff --git a/src/main/java/org/kohsuke/github/GHOrganization.java b/src/main/java/org/kohsuke/github/GHOrganization.java index 4409dafaaa..b39cc6b98b 100644 --- a/src/main/java/org/kohsuke/github/GHOrganization.java +++ b/src/main/java/org/kohsuke/github/GHOrganization.java @@ -175,7 +175,7 @@ public enum Permission { ADMIN, PUSH, PULL } * Creates a new team and assigns the repositories. */ public GHTeam createTeam(String name, Permission p, Collection repositories) throws IOException { - Requester post = new Requester(root).with("name", name).with("permission", p.name().toLowerCase()); + Requester post = new Requester(root).with("name", name).with("permission", p.name().toLowerCase(Locale.ENGLISH)); List repo_names = new ArrayList(); for (GHRepository r : repositories) { repo_names.add(r.getName()); diff --git a/src/main/java/org/kohsuke/github/GHPersonSet.java b/src/main/java/org/kohsuke/github/GHPersonSet.java index 1c1d43dccb..eb35b1bf7a 100644 --- a/src/main/java/org/kohsuke/github/GHPersonSet.java +++ b/src/main/java/org/kohsuke/github/GHPersonSet.java @@ -10,6 +10,8 @@ * @author Kohsuke Kawaguchi */ public class GHPersonSet extends HashSet { + private static final long serialVersionUID = 1L; + public GHPersonSet() { } diff --git a/src/main/java/org/kohsuke/github/GHPullRequestCommitDetail.java b/src/main/java/org/kohsuke/github/GHPullRequestCommitDetail.java index 3568550904..d4b48da538 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequestCommitDetail.java +++ b/src/main/java/org/kohsuke/github/GHPullRequestCommitDetail.java @@ -24,8 +24,10 @@ package org.kohsuke.github; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.net.URL; +import java.util.Arrays; /** * Commit detail inside a {@link GHPullRequest}. @@ -33,6 +35,8 @@ * @author Luca Milanesio * @see GHPullRequest#listCommits() */ +@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", + "NP_UNWRITTEN_FIELD", "URF_UNREAD_FIELD"}, justification = "JSON API") public class GHPullRequestCommitDetail { private GHPullRequest owner; @@ -88,6 +92,10 @@ public URL getUrl() { public int getComment_count() { return comment_count; } + + public Tree getTree() { + return tree; + } } public static class CommitPointer { @@ -136,6 +144,6 @@ public URL getCommentsUrl() { } public CommitPointer[] getParents() { - return parents; + return Arrays.copyOf(parents, parents.length); } } diff --git a/src/main/java/org/kohsuke/github/GHRateLimit.java b/src/main/java/org/kohsuke/github/GHRateLimit.java index 301bd7993d..b9b900d785 100644 --- a/src/main/java/org/kohsuke/github/GHRateLimit.java +++ b/src/main/java/org/kohsuke/github/GHRateLimit.java @@ -1,5 +1,6 @@ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.Date; /** @@ -24,6 +25,8 @@ public class GHRateLimit { /** * Non-epoch date */ + @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", + justification = "The value comes from JSON deserialization") public Date getResetDate() { return new Date(reset.getTime() * 1000); } diff --git a/src/main/java/org/kohsuke/github/GHRef.java b/src/main/java/org/kohsuke/github/GHRef.java index f052cdf903..8212dc2c3b 100644 --- a/src/main/java/org/kohsuke/github/GHRef.java +++ b/src/main/java/org/kohsuke/github/GHRef.java @@ -1,5 +1,6 @@ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; import java.net.URL; @@ -77,7 +78,8 @@ public void delete() throws IOException { return in; } - + @SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", + "NP_UNWRITTEN_FIELD"}, justification = "JSON API") public static class GHObject { private String type, sha, url; diff --git a/src/main/java/org/kohsuke/github/GHRelease.java b/src/main/java/org/kohsuke/github/GHRelease.java index 86736e909d..6b30a062de 100644 --- a/src/main/java/org/kohsuke/github/GHRelease.java +++ b/src/main/java/org/kohsuke/github/GHRelease.java @@ -70,7 +70,7 @@ public boolean isPrerelease() { } public Date getPublished_at() { - return published_at; + return new Date(published_at.getTime()); } public GitHub getRoot() { @@ -123,9 +123,14 @@ public GHAsset uploadAsset(File file, String contentType) throws IOException { String url = format("https://uploads.github.com%s/releases/%d/assets?name=%s", owner.getApiTailUrl(""), getId(), file.getName()); - return builder.contentType(contentType) - .with(new FileInputStream(file)) + FileInputStream istream = new FileInputStream(file); + try { + return builder.contentType(contentType) + .with(istream) .to(url, GHAsset.class).wrap(this); + } finally { + istream.close(); + } } public List getAssets() throws IOException { diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 5acf0a648b..54acc2c8c3 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -25,6 +25,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.apache.commons.lang.StringUtils; import javax.xml.bind.DatatypeConverter; @@ -33,7 +34,9 @@ import java.io.InputStreamReader; import java.io.InterruptedIOException; import java.io.Reader; +import java.io.UnsupportedEncodingException; import java.net.URL; +import java.nio.charset.Charset; import java.util.*; import static java.util.Arrays.asList; @@ -44,6 +47,8 @@ * @author Kohsuke Kawaguchi */ @SuppressWarnings({"UnusedDeclaration"}) +@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", + "NP_UNWRITTEN_FIELD"}, justification = "JSON API") public class GHRepository extends GHObject { /*package almost final*/ GitHub root; @@ -217,7 +222,8 @@ public List getIssues(GHIssueState state) throws IOException { public List getIssues(GHIssueState state, GHMilestone milestone) throws IOException { return Arrays.asList(GHIssue.wrap(root.retrieve() .to(getApiTailUrl(String.format("issues?state=%s&milestone=%s", - state.toString().toLowerCase(), milestone == null ? "none" : "" + milestone.getNumber())), + state.toString().toLowerCase(Locale.ENGLISH), + milestone == null ? "none" : "" + milestone.getNumber())), GHIssue[].class ), this)); } @@ -383,7 +389,8 @@ public String getMasterBranch() { public int getSize() { return size; } - + + /** * Gets the collaborators on this repository. * This set always appear to include the owner. @@ -950,6 +957,8 @@ private void verifyMine() throws IOException { * @deprecated * Use {@link #getHooks()} and {@link #createHook(String, Map, Collection, boolean)} */ + @SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS", + justification = "It causes a performance degradation, but we have already exposed it to the API") public Set getPostCommitHooks() { return postCommitHooks; } @@ -957,6 +966,8 @@ public Set getPostCommitHooks() { /** * Live set view of the post-commit hook. */ + @SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS", + justification = "It causes a performance degradation, but we have already exposed it to the API") private final Set postCommitHooks = new AbstractSet() { private List getPostCommitHooks() { try { @@ -1101,11 +1112,17 @@ public GHContent getReadme() throws IOException { } public GHContentUpdateResponse createContent(String content, String commitMessage, String path) throws IOException { - return createContent(content.getBytes(), commitMessage, path, null); + return createContent(content, commitMessage, path, null); } public GHContentUpdateResponse createContent(String content, String commitMessage, String path, String branch) throws IOException { - return createContent(content.getBytes(), commitMessage, path, branch); + final byte[] payload; + try { + payload = content.getBytes("UTF-8"); + } catch (UnsupportedEncodingException ex) { + throw new IOException("UTF-8 encoding is not supported", ex); + } + return createContent(payload, commitMessage, path, branch); } public GHContentUpdateResponse createContent(byte[] contentBytes, String commitMessage, String path) throws IOException { @@ -1225,6 +1242,18 @@ public static class Contributor extends GHUser { public int getContributions() { return contributions; } + + @Override + public int hashCode() { + // We ignore contributions in the calculation + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + // We ignore contributions in the calculation + return super.equals(obj); + } } /** diff --git a/src/main/java/org/kohsuke/github/GHTag.java b/src/main/java/org/kohsuke/github/GHTag.java index 3a72407754..802f51f8f3 100644 --- a/src/main/java/org/kohsuke/github/GHTag.java +++ b/src/main/java/org/kohsuke/github/GHTag.java @@ -1,10 +1,14 @@ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + /** * Represents a tag in {@link GHRepository} * * @see GHRepository#listTags() */ +@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", + "NP_UNWRITTEN_FIELD"}, justification = "JSON API") public class GHTag { private GHRepository owner; private GitHub root; diff --git a/src/main/java/org/kohsuke/github/GHThread.java b/src/main/java/org/kohsuke/github/GHThread.java index 6a2608f253..a1964b10de 100644 --- a/src/main/java/org/kohsuke/github/GHThread.java +++ b/src/main/java/org/kohsuke/github/GHThread.java @@ -1,5 +1,6 @@ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; @@ -12,6 +13,8 @@ * @see GHNotificationStream * @author Kohsuke Kawaguchi */ +@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", + "NP_UNWRITTEN_FIELD"}, justification = "JSON API") public class GHThread extends GHObject { private GitHub root; private GHRepository repository; @@ -67,6 +70,10 @@ public String getTitle() { public String getType() { return subject.type; } + + public String getLastCommentUrl() { + return subject.latest_comment_url; + } /** * If this thread is about an issue, return that issue. diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index d3853380e8..9e638bb4aa 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -53,6 +53,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; +import java.nio.charset.Charset; /** * Root of the GitHub API. @@ -128,7 +129,13 @@ public class GitHub { } else { if (password!=null) { String authorization = (login + ':' + password); - encodedAuthorization = "Basic "+new String(Base64.encodeBase64(authorization.getBytes())); + final Charset charset; + try { + charset = Charset.forName("UTF-8"); + } catch (Exception ex) { + throw new IOException("UTF-8 encoding is not supported", ex); + } + encodedAuthorization = "Basic "+new String(Base64.encodeBase64(authorization.getBytes(charset)), charset); } else {// anonymous access encodedAuthorization = null; } diff --git a/src/main/java/org/kohsuke/github/GitUser.java b/src/main/java/org/kohsuke/github/GitUser.java index fc97ef8882..751aabd378 100644 --- a/src/main/java/org/kohsuke/github/GitUser.java +++ b/src/main/java/org/kohsuke/github/GitUser.java @@ -1,5 +1,6 @@ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.Date; /** @@ -11,6 +12,8 @@ * * @author Kohsuke Kawaguchi */ +@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", + "NP_UNWRITTEN_FIELD"}, justification = "JSON API") public class GitUser { private String name, email, date; diff --git a/src/main/java/org/kohsuke/github/PagedSearchIterable.java b/src/main/java/org/kohsuke/github/PagedSearchIterable.java index 65b6c7490d..222cedcd00 100644 --- a/src/main/java/org/kohsuke/github/PagedSearchIterable.java +++ b/src/main/java/org/kohsuke/github/PagedSearchIterable.java @@ -1,5 +1,6 @@ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.Iterator; /** @@ -7,6 +8,8 @@ * * @author Kohsuke Kawaguchi */ +@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", + "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR"}, justification = "Constructed by JSON API") public abstract class PagedSearchIterable extends PagedIterable { private final GitHub root; diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index 281426dd3e..78ead072d9 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -119,7 +119,7 @@ public Requester with(String key, int value) { public Requester with(String key, Integer value) { if (value!=null) - _with(key, value.intValue()); + _with(key, value); return this; } @@ -323,23 +323,26 @@ private boolean isMethodWithBody() { * * Every iterator call reports a new batch. */ - /*package*/ Iterator asIterator(String _tailApiUrl, final Class type) { + /*package*/ Iterator asIterator(final String _tailApiUrl, final Class type) { method("GET"); + final StringBuilder strBuilder = new StringBuilder(_tailApiUrl); if (!args.isEmpty()) { boolean first=true; try { for (Entry a : args) { - _tailApiUrl += first ? '?' : '&'; + strBuilder.append(first ? '?' : '&'); first = false; - _tailApiUrl += URLEncoder.encode(a.key,"UTF-8")+'='+URLEncoder.encode(a.value.toString(),"UTF-8"); + strBuilder.append(URLEncoder.encode(a.key, "UTF-8")); + strBuilder.append('='); + strBuilder.append(URLEncoder.encode(a.value.toString(), "UTF-8")); } } catch (UnsupportedEncodingException e) { throw new AssertionError(e); // UTF-8 is mandatory } } - final String tailApiUrl = _tailApiUrl; + final String tailApiUrl = strBuilder.toString(); return new Iterator() { /** @@ -507,11 +510,4 @@ private InputStream wrapStream(InputStream in) throws IOException { IOUtils.closeQuietly(es); } } - - private Set toSet(String s) { - Set r = new HashSet(); - for (String t : s.split(",")) - r.add(t.trim()); - return r; - } } diff --git a/src/main/java/org/kohsuke/github/SearchResult.java b/src/main/java/org/kohsuke/github/SearchResult.java index a8a7583a4c..7b9f9a0c59 100644 --- a/src/main/java/org/kohsuke/github/SearchResult.java +++ b/src/main/java/org/kohsuke/github/SearchResult.java @@ -1,12 +1,18 @@ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + /** * Represents the result of a search * * @author Kohsuke Kawaguchi */ + abstract class SearchResult { + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Field comes from JSON deserialization") int total_count; + + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Field comes from JSON deserialization") boolean incomplete_results; /**