Compare commits

...

45 Commits

Author SHA1 Message Date
Kohsuke Kawaguchi
b24fcb18af [maven-release-plugin] prepare release github-api-1.71 2015-12-01 16:27:24 +01:00
Kohsuke Kawaguchi
c2f2d0f8af Making FindBugs happy 2015-12-01 16:23:51 +01:00
Kohsuke Kawaguchi
e33bdd7e62 Two teams now.
I assume this is because 'owner' is now a team.
2015-12-01 16:17:03 +01:00
Kohsuke Kawaguchi
402adc3559 Merge pull request #232 2015-12-01 16:05:25 +01:00
Kohsuke Kawaguchi
0f45d03c51 Reworked this change a bit.
- GHApiInfo need not be public because it's not publicly exposed.
- Throwing an exception is better IMO as it allows richer error message,
  including the differentiation between unreachable host name vs wrong
  URL, and reporting the API endpoint URL that was actually tried.
2015-12-01 16:01:01 +01:00
Kohsuke Kawaguchi
0397d7ab53 Fixing a test problem 2015-12-01 15:39:19 +01:00
Kohsuke Kawaguchi
79f86b82e4 Merge pull request #237 2015-12-01 15:18:15 +01:00
Kohsuke Kawaguchi
261a7a34e3 Consolidated timeout handling 2015-12-01 15:17:54 +01:00
Kohsuke Kawaguchi
723bb89e10 Merge pull request #219 from if6was9/cross-fork-compare
#218 enable cross fork compare
2015-12-01 15:04:50 +01:00
Oliver Gondža
832e4f3c37 Use default timeouts for URLConnections 2015-12-01 14:58:46 +01:00
Kohsuke Kawaguchi
75a4081549 Follow up to PR #216 2015-12-01 14:57:30 +01:00
Kohsuke Kawaguchi
f9291f9fd1 Merge pull request #216 from if6was9/issue-215-download-failure
#215 fix read() failure with private repos
2015-12-01 14:56:49 +01:00
Kohsuke Kawaguchi
c3b4ee9321 Merge pull request #226 from Shredder121/oauth-credentials
Check builder result to either be a token or a user
2015-12-01 14:54:35 +01:00
Kohsuke Kawaguchi
f86896943d Merge pull request #224 from Shredder121/directory-content-trailing-slash
Remove trailing slash when requesting directory content
2015-12-01 14:53:56 +01:00
Kohsuke Kawaguchi
c33f05e8ca Merge pull request #225 from Shredder121/findbugs-changes
Overzealous FindBugs changes.
2015-12-01 14:51:53 +01:00
Oleg Nenashev
52727ded03 Merge pull request #233 from vparfonov/master
Add information about mirror url if it exist.
2015-11-30 18:18:44 +03:00
Manuel Recena
f7d132758e Merge pull request #231 from recena/MergeCommitSha
Support for merge_commit_sha
2015-11-25 23:22:10 +01:00
Manuel Recena
bb17ca9a53 Merge pull request #236 from recena/findbugs
Findbugs plugin has been upgraded
2015-11-25 23:06:57 +01:00
Manuel Recena
aab21c5b17 findbugs plugin has been upgraded 2015-11-23 10:29:04 +01:00
Manuel Recena
acbafee02a Removed unrelated changes. @KostyaSha's suggestion 2015-11-23 10:25:41 +01:00
Manuel Recena
c6d2b1a222 @deprecated annotations were removed 2015-11-23 09:33:32 +01:00
Vitaly Parfonov
b037f75fb0 Add information about mirror url if it exist. Like https://github.com/apache/tomee 2015-11-19 12:09:34 +02:00
Ruben Dijkstra
a1e79d3050 Add unit test to cover the truncation of ?ref 2015-11-16 18:33:51 +01:00
Manuel Recena
354969d5fa Javadoc comment reviewed 2015-11-16 11:16:58 +01:00
Manuel Recena
a371892409 Added a new method to validate the GitHub API URL 2015-11-15 16:36:27 +01:00
Manuel Recena
b0789a7ce7 Set merge_commit_sha as deprecated 2015-11-15 11:50:13 +01:00
Manuel Recena
08be8eb4f8 Added a new test testMergeCommitSHA() 2015-11-15 11:46:18 +01:00
Manuel Recena
bafddf4baf Initial source code modifications 2015-11-14 12:11:24 +01:00
Ruben Dijkstra
75b9184a00 Check builder result to either be a token or a user
Currently, a `user` property is always required (it not having content is also fine).

This adds support for only having the `oauth` key in the property file/environment.
2015-10-09 17:20:11 +02:00
Ruben Dijkstra
5dc83cf2bf Overzealous FindBugs changes.
Charsets that are standard on the JRE are try-lookuped,
bridge methods were removed and a stream that would be closed later is closed explicitly
2015-10-08 19:31:55 +02:00
Ruben Dijkstra
092e9062c8 Remove trailing slash when requesting directory content 2015-10-06 18:23:51 +02:00
Rob Schoening
512c921a81 enable cross fork compare 2015-09-27 07:50:11 -07:00
Kohsuke Kawaguchi
defcd6fe26 Merge pull request #217 from dblevins/closed_at
Support Milestone closed_at date
2015-09-17 19:23:00 -07:00
dblevins
025b6cbfb7 Support Milestone closed_at date 2015-09-14 10:53:07 -07:00
Rob Schoening
b0687dbeb5 Fix compilation errror: The constructor ArrayList<GHHook>(List<capture#1-of ? extends GHHook[]>) is undefined 2015-09-06 08:45:42 -07:00
Rob Schoening
e0b109cba6 fix read() failure with private repos
reorder buildRequest()
2015-09-06 08:28:20 -07:00
Kohsuke Kawaguchi
adaa8ece89 [maven-release-plugin] prepare for next development iteration 2015-08-15 07:19:25 -07:00
Kohsuke Kawaguchi
6516b20e16 [maven-release-plugin] prepare release github-api-1.70 2015-08-15 07:19:22 -07:00
Kohsuke Kawaguchi
839cb03690 Overzealous FindBugs changes.
String given without the encoding mandated by a protocol/design/etc should be converted with the platform default encoding. After all it exists for a reason!
2015-08-15 07:17:15 -07:00
Kohsuke Kawaguchi
2bcd99b14f Overzealous findbugs fix.
This method should rely on platform specific encoding
2015-08-14 11:59:55 -07:00
Kohsuke Kawaguchi
e3ebf6e8a1 Merge pull request #212 from umajeric/master
Added option to edit GitHub release once it is created
2015-08-11 09:24:30 +02:00
Uros Majeric
76d28314b0 Added option to edit GitHub release once it is created 2015-08-06 15:40:26 +02:00
Oleg Nenashev
ec450b8fd8 Merge pull request #210 from oleg-nenashev/findbugs-cleanup
Cleanup issues discovered by FindBugs
2015-07-24 15:57:31 +03:00
Oleg Nenashev
79c5b2edd5 FindBugs: Fix over 100 issues and enforce FindBugs 2015-07-20 12:28:41 +03:00
Kohsuke Kawaguchi
2d45ac51ef [maven-release-plugin] prepare for next development iteration 2015-07-17 05:09:28 -07:00
43 changed files with 418 additions and 58 deletions

11
pom.xml
View File

@@ -7,7 +7,7 @@
</parent> </parent>
<artifactId>github-api</artifactId> <artifactId>github-api</artifactId>
<version>1.69</version> <version>1.71</version>
<name>GitHub API for Java</name> <name>GitHub API for Java</name>
<url>http://github-api.kohsuke.org/</url> <url>http://github-api.kohsuke.org/</url>
<description>GitHub API for Java</description> <description>GitHub API for Java</description>
@@ -16,7 +16,7 @@
<connection>scm:git:git@github.com/kohsuke/${project.artifactId}.git</connection> <connection>scm:git:git@github.com/kohsuke/${project.artifactId}.git</connection>
<developerConnection>scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git</developerConnection> <developerConnection>scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git</developerConnection>
<url>http://${project.artifactId}.kohsuke.org/</url> <url>http://${project.artifactId}.kohsuke.org/</url>
<tag>github-api-1.69</tag> <tag>github-api-1.71</tag>
</scm> </scm>
<distributionManagement> <distributionManagement>
@@ -28,6 +28,8 @@
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<findbugs-maven-plugin.version>3.0.2</findbugs-maven-plugin.version>
<findbugs-maven-plugin.failOnError>true</findbugs-maven-plugin.failOnError>
</properties> </properties>
<build> <build>
@@ -47,11 +49,10 @@
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId> <artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.1</version> <version>${findbugs-maven-plugin.version}</version>
<configuration> <configuration>
<xmlOutput>true</xmlOutput> <xmlOutput>true</xmlOutput>
<findbugsXmlWithMessages>true</findbugsXmlWithMessages> <failOnError>${findbugs-maven-plugin.failOnError}</failOnError>
<failOnError>false</failOnError>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>

View File

@@ -23,9 +23,13 @@
*/ */
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/** /**
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
@SuppressFBWarnings(value = "UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD",
justification = "Being constructed by JSON deserialization")
class DeleteToken { class DeleteToken {
public String delete_token; public String delete_token;
} }

View File

@@ -1,5 +1,6 @@
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.net.URL; import java.net.URL;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
@@ -59,6 +60,8 @@ public class GHAuthorization extends GHObject {
return app.name; return app.name;
} }
@SuppressFBWarnings(value = "NM_CONFUSING",
justification = "It's a part of the library API, cannot be changed")
public URL getApiURL() { public URL getApiURL() {
return GitHub.parseURL(url); return GitHub.parseURL(url);
} }
@@ -84,7 +87,8 @@ public class GHAuthorization extends GHObject {
return this; return this;
} }
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD"},
justification = "JSON API")
private static class App { private static class App {
private String url; private String url;
private String name; private String name;

View File

@@ -1,10 +1,14 @@
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/** /**
* A branch in a repository. * A branch in a repository.
* *
* @author Yusuke Kokubo * @author Yusuke Kokubo
*/ */
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public class GHBranch { public class GHBranch {
private GitHub root; private GitHub root;
private GHRepository owner; private GHRepository owner;
@@ -13,7 +17,10 @@ public class GHBranch {
private Commit commit; private Commit commit;
public static class 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() { public GitHub getRoot() {
@@ -37,7 +44,7 @@ public class GHBranch {
public String getSHA1() { public String getSHA1() {
return commit.sha; return commit.sha;
} }
@Override @Override
public String toString() { public String toString() {
final String url = owner != null ? owner.getUrl().toString() : "unknown"; final String url = owner != null ? owner.getUrl().toString() : "unknown";

View File

@@ -1,6 +1,7 @@
package org.kohsuke.github; package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
@@ -16,6 +17,8 @@ import java.util.List;
* @see GHRepository#getCommit(String) * @see GHRepository#getCommit(String)
* @see GHCommitComment#getCommit() * @see GHCommitComment#getCommit()
*/ */
@SuppressFBWarnings(value = {"NP_UNWRITTEN_FIELD", "UWF_UNWRITTEN_FIELD"},
justification = "JSON API")
public class GHCommit { public class GHCommit {
private GHRepository owner; private GHRepository owner;
@@ -24,6 +27,8 @@ public class GHCommit {
/** /**
* Short summary of this commit. * 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 { public static class ShortInfo {
private GHAuthor author; private GHAuthor author;
private GHAuthor committer; private GHAuthor committer;
@@ -67,6 +72,8 @@ public class GHCommit {
/** /**
* A file that was modified. * A file that was modified.
*/ */
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD",
justification = "It's being initilized by JSON deserialization")
public static class File { public static class File {
String status; String status;
int changes,additions,deletions; int changes,additions,deletions;
@@ -104,6 +111,8 @@ public class GHCommit {
/** /**
* Full path in the repository. * 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() { public String getFileName() {
return filename; return filename;
} }
@@ -147,13 +156,19 @@ public class GHCommit {
} }
public static class Parent { 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 { static class User {
// TODO: what if someone who doesn't have an account on GitHub makes a commit? // 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; int id;
String login;
} }
String url,sha; String url,sha;

View File

@@ -1,5 +1,6 @@
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.Date; import java.util.Date;
@@ -12,6 +13,8 @@ import java.util.Date;
* @see GHCommit#listComments() * @see GHCommit#listComments()
* @see GHCommit#createComment(String, String, Integer, Integer) * @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 { public class GHCommitComment extends GHObject {
private GHRepository owner; private GHRepository owner;
@@ -22,8 +25,12 @@ public class GHCommitComment extends GHObject {
static class User { static class User {
// TODO: what if someone who doesn't have an account on GitHub makes a commit? // 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; int id;
String login;
} }
public GHRepository getOwner() { public GHRepository getOwner() {
@@ -83,7 +90,7 @@ public class GHCommitComment extends GHObject {
* Updates the body of the commit message. * Updates the body of the commit message.
*/ */
public void update(String body) throws IOException { public void update(String body) throws IOException {
GHCommitComment r = new Requester(owner.root) new Requester(owner.root)
.with("body", body) .with("body", body)
.method("PATCH").to(getApiTail(), GHCommitComment.class); .method("PATCH").to(getApiTail(), GHCommitComment.class);
this.body = body; this.body = body;

View File

@@ -1,8 +1,10 @@
package org.kohsuke.github; package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.net.URL; import java.net.URL;
import java.util.Arrays;
import java.util.Date; import java.util.Date;
/** /**
@@ -65,12 +67,20 @@ public class GHCompare {
return merge_base_commit; return merge_base_commit;
} }
/**
* Gets an array of commits.
* @return A copy of the array being stored in the class.
*/
public Commit[] getCommits() { 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() { public GHCommit.File[] getFiles() {
return files; return Arrays.copyOf(files, files.length);
} }
public GHCompare wrap(GHRepository owner) { public GHCompare wrap(GHRepository owner) {
@@ -87,6 +97,8 @@ public class GHCompare {
* Compare commits had a child commit element with additional details we want to capture. * Compare commits had a child commit element with additional details we want to capture.
* This extenstion of GHCommit provides that. * 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 { public static class Commit extends GHCommit {
private InnerCommit commit; private InnerCommit commit;

View File

@@ -1,5 +1,6 @@
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
@@ -75,6 +76,7 @@ public class GHContent {
* @deprecated * @deprecated
* Use {@link #read()} * Use {@link #read()}
*/ */
@SuppressFBWarnings("DM_DEFAULT_ENCODING")
public String getContent() throws IOException { public String getContent() throws IOException {
return new String(DatatypeConverter.parseBase64Binary(getEncodedContent())); return new String(DatatypeConverter.parseBase64Binary(getEncodedContent()));
} }
@@ -161,10 +163,12 @@ public class GHContent {
}; };
} }
@SuppressFBWarnings("DM_DEFAULT_ENCODING")
public GHContentUpdateResponse update(String newContent, String commitMessage) throws IOException { public GHContentUpdateResponse update(String newContent, String commitMessage) throws IOException {
return update(newContent.getBytes(), commitMessage, null); return update(newContent.getBytes(), commitMessage, null);
} }
@SuppressFBWarnings("DM_DEFAULT_ENCODING")
public GHContentUpdateResponse update(String newContent, String commitMessage, String branch) throws IOException { public GHContentUpdateResponse update(String newContent, String commitMessage, String branch) throws IOException {
return update(newContent.getBytes(), commitMessage, branch); return update(newContent.getBytes(), commitMessage, branch);
} }

View File

@@ -1,6 +1,7 @@
package org.kohsuke.github; package org.kohsuke.github;
import java.net.URL; import java.net.URL;
import java.util.Locale;
public class GHDeploymentStatus extends GHObject { public class GHDeploymentStatus extends GHObject {
private GHRepository owner; private GHRepository owner;
@@ -28,8 +29,9 @@ public class GHDeploymentStatus extends GHObject {
public URL getRepositoryUrl() { public URL getRepositoryUrl() {
return GitHub.parseURL(repository_url); return GitHub.parseURL(repository_url);
} }
public GHDeploymentState getState() { public GHDeploymentState getState() {
return GHDeploymentState.valueOf(state.toUpperCase()); return GHDeploymentState.valueOf(state.toUpperCase(Locale.ENGLISH));
} }
/** /**

View File

@@ -1,6 +1,7 @@
package org.kohsuke.github; package org.kohsuke.github;
import java.io.IOException; import java.io.IOException;
import java.util.Locale;
public class GHDeploymentStatusBuilder { public class GHDeploymentStatusBuilder {
private final Requester builder; private final Requester builder;
@@ -11,7 +12,7 @@ public class GHDeploymentStatusBuilder {
this.repo = repo; this.repo = repo;
this.deploymentId = deploymentId; this.deploymentId = deploymentId;
this.builder = new Requester(repo.root); 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) { public GHDeploymentStatusBuilder description(String description) {

View File

@@ -23,12 +23,16 @@
*/ */
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/** /**
* Represents an email of GitHub. * Represents an email of GitHub.
* *
* @author Kelly Campbell * @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 { public class GHEmail {
protected String email; protected String email;

View File

@@ -4,12 +4,14 @@ import java.io.IOException;
import java.util.Date; import java.util.Date;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/** /**
* Represents an event. * Represents an event.
* *
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
@SuppressFBWarnings(value = "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", justification = "JSON API")
public class GHEventInfo { public class GHEventInfo {
private GitHub root; private GitHub root;
@@ -27,8 +29,12 @@ public class GHEventInfo {
/** /**
* Inside the event JSON model, GitHub uses a slightly different format. * 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 { public static class GHEventRepository {
@SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now")
private int id; 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 url; // repository API URL
private String name; // owner/repo private String name; // owner/repo
} }
@@ -55,10 +61,14 @@ public class GHEventInfo {
/** /**
* Repository where the change was made. * 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 { public GHRepository getRepository() throws IOException {
return root.getRepository(repo.name); 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 { public GHUser getActor() throws IOException {
return root.getUser(actor.getLogin()); return root.getUser(actor.getLogin());
} }
@@ -70,6 +80,8 @@ public class GHEventInfo {
return actor.getLogin(); return actor.getLogin();
} }
@SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" },
justification = "The field comes from JSON deserialization")
public GHOrganization getOrganization() throws IOException { public GHOrganization getOrganization() throws IOException {
return (org==null || org.getLogin()==null) ? null : root.getOrganization(org.getLogin()); return (org==null || org.getLogin()==null) ? null : root.getOrganization(org.getLogin());
} }

View File

@@ -1,5 +1,6 @@
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.Reader; import java.io.Reader;
import java.util.List; import java.util.List;
@@ -25,6 +26,8 @@ public abstract class GHEventPayload {
* *
* @see <a href="http://developer.github.com/v3/activity/events/types/#pullrequestevent">authoritative source</a> * @see <a href="http://developer.github.com/v3/activity/events/types/#pullrequestevent">authoritative source</a>
*/ */
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public static class PullRequest extends GHEventPayload { public static class PullRequest extends GHEventPayload {
private String action; private String action;
private int number; private int number;
@@ -67,12 +70,15 @@ public abstract class GHEventPayload {
* *
* @see <a href="http://developer.github.com/v3/activity/events/types/#issuecommentevent">authoritative source</a> * @see <a href="http://developer.github.com/v3/activity/events/types/#issuecommentevent">authoritative source</a>
*/ */
@SuppressFBWarnings(value = {"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", "NP_UNWRITTEN_FIELD" },
justification = "Constructed by JSON deserialization")
public static class IssueComment extends GHEventPayload { public static class IssueComment extends GHEventPayload {
private String action; private String action;
private GHIssueComment comment; private GHIssueComment comment;
private GHIssue issue; private GHIssue issue;
private GHRepository repository; private GHRepository repository;
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Comes from JSON deserialization")
public String getAction() { public String getAction() {
return action; return action;
} }

View File

@@ -1,5 +1,6 @@
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.Collections; import java.util.Collections;
@@ -11,6 +12,8 @@ import java.util.Map;
/** /**
* @author Kohsuke Kawaguchi * @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 { public abstract class GHHook extends GHObject {
String name; String name;
List<String> events; List<String> events;

View File

@@ -21,8 +21,9 @@ class GHHooks {
} }
public List<GHHook> getHooks() throws IOException { public List<GHHook> getHooks() throws IOException {
List<GHHook> list = new ArrayList<GHHook>(Arrays.asList(
root.retrieve().to(collection(), collectionClass()))); GHHook [] hookArray = root.retrieve().to(collection(),collectionClass()); // jdk/eclipse bug requires this to be on separate line
List<GHHook> list = new ArrayList<GHHook>(Arrays.asList(hookArray));
for (GHHook h : list) for (GHHook h : list)
wrap(h); wrap(h);
return list; return list;

View File

@@ -25,6 +25,7 @@
package org.kohsuke.github; package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
@@ -269,6 +270,8 @@ public class GHIssue extends GHObject {
return milestone; return milestone;
} }
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD"},
justification = "JSON API")
public static class PullRequest{ public static class PullRequest{
private String diff_url, patch_url, html_url; private String diff_url, patch_url, html_url;

View File

@@ -1,5 +1,6 @@
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringBuilder;
/** /**
@@ -7,6 +8,7 @@ import org.apache.commons.lang.builder.ToStringBuilder;
* *
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
@SuppressFBWarnings(value = "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", justification = "JSON API")
public class GHKey { public class GHKey {
/*package almost final*/ GitHub root; /*package almost final*/ GitHub root;
@@ -33,6 +35,10 @@ public class GHKey {
return url; return url;
} }
public GitHub getRoot() {
return root;
}
public boolean isVerified() { public boolean isVerified() {
return verified; return verified;
} }

View File

@@ -17,6 +17,7 @@ public class GHMilestone extends GHObject {
GHUser creator; GHUser creator;
private String state, due_on, title, description, html_url; private String state, due_on, title, description, html_url;
private int closed_issues, open_issues, number; private int closed_issues, open_issues, number;
protected String closed_at;
public GitHub getRoot() { public GitHub getRoot() {
return root; return root;
@@ -34,7 +35,14 @@ public class GHMilestone extends GHObject {
if (due_on == null) return null; if (due_on == null) return null;
return GitHub.parseDate(due_on); return GitHub.parseDate(due_on);
} }
/**
* When was this milestone closed?
*/
public Date getClosedAt() throws IOException {
return GitHub.parseDate(closed_at);
}
public String getTitle() { public String getTitle() {
return title; return title;
} }

View File

@@ -6,6 +6,7 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
@@ -159,7 +160,7 @@ public class GHMyself extends GHUser {
return new PagedIterable<GHRepository>() { return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> iterator() { public PagedIterator<GHRepository> iterator() {
return new PagedIterator<GHRepository>(root.retrieve().asIterator("/user/repos?per_page=" + pageSize + return new PagedIterator<GHRepository>(root.retrieve().asIterator("/user/repos?per_page=" + pageSize +
"&type=" + repoType.name().toLowerCase(), GHRepository[].class)) { "&type=" + repoType.name().toLowerCase(Locale.ENGLISH), GHRepository[].class)) {
@Override @Override
protected void wrapUp(GHRepository[] page) { protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page) for (GHRepository c : page)

View File

@@ -152,7 +152,7 @@ public class GHNotificationStream implements Iterable<GHThread> {
while (true) { while (true) {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (nextCheckTime < now) break; 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); Thread.sleep(waitTime);
} }
@@ -180,7 +180,8 @@ public class GHNotificationStream implements Iterable<GHThread> {
private long calcNextCheckTime() { private long calcNextCheckTime() {
String v = req.getResponseHeader("X-Poll-Interval"); String v = req.getResponseHeader("X-Poll-Interval");
if (v==null) v="60"; 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() { public void remove() {

View File

@@ -1,6 +1,7 @@
package org.kohsuke.github; package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
@@ -9,6 +10,8 @@ import java.util.Date;
/** /**
* Most (all?) domain objects in GitHub seems to have these 4 properties. * 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 { public abstract class GHObject {
protected String url; protected String url;
protected int id; protected int id;
@@ -26,6 +29,7 @@ public abstract class GHObject {
return GitHub.parseDate(created_at); return GitHub.parseDate(created_at);
} }
@SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD", justification = "Bridge method of getCreatedAt")
private Object createdAtStr(Date id, Class type) { private Object createdAtStr(Date id, Class type) {
return created_at; return created_at;
} }
@@ -59,10 +63,12 @@ public abstract class GHObject {
return id; return id;
} }
@SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD", justification = "Bridge method of getId")
private Object intToString(int id, Class type) { private Object intToString(int id, Class type) {
return String.valueOf(id); return String.valueOf(id);
} }
@SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD", justification = "Bridge method of getHtmlUrl")
private Object urlToString(URL url, Class type) { private Object urlToString(URL url, Class type) {
return url==null ? null : url.toString(); return url==null ? null : url.toString();
} }

View File

@@ -175,7 +175,7 @@ public class GHOrganization extends GHPerson {
* Creates a new team and assigns the repositories. * Creates a new team and assigns the repositories.
*/ */
public GHTeam createTeam(String name, Permission p, Collection<GHRepository> repositories) throws IOException { public GHTeam createTeam(String name, Permission p, Collection<GHRepository> 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<String> repo_names = new ArrayList<String>(); List<String> repo_names = new ArrayList<String>();
for (GHRepository r : repositories) { for (GHRepository r : repositories) {
repo_names.add(r.getName()); repo_names.add(r.getName());

View File

@@ -10,6 +10,8 @@ import java.util.HashSet;
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
public class GHPersonSet<T extends GHPerson> extends HashSet<T> { public class GHPersonSet<T extends GHPerson> extends HashSet<T> {
private static final long serialVersionUID = 1L;
public GHPersonSet() { public GHPersonSet() {
} }

View File

@@ -50,6 +50,7 @@ public class GHPullRequest extends GHIssue {
private int deletions; private int deletions;
private String mergeable_state; private String mergeable_state;
private int changed_files; private int changed_files;
private String merge_commit_sha;
/** /**
* GitHub doesn't return some properties of {@link GHIssue} when requesting the GET on the 'pulls' API * GitHub doesn't return some properties of {@link GHIssue} when requesting the GET on the 'pulls' API
@@ -142,9 +143,9 @@ public class GHPullRequest extends GHIssue {
} }
// //
// details that are only available via get with ID // details that are only available via get with ID
// //
//
public GHUser getMergedBy() throws IOException { public GHUser getMergedBy() throws IOException {
populate(); populate();
return merged_by; return merged_by;
@@ -185,6 +186,14 @@ public class GHPullRequest extends GHIssue {
return changed_files; return changed_files;
} }
/**
* See <a href="https://developer.github.com/changes/2013-04-25-deprecating-merge-commit-sha">GitHub blog post</a>
*/
public String getMergeCommitSha() throws IOException {
populate();
return merge_commit_sha;
}
/** /**
* Fully populate the data by retrieving missing data. * Fully populate the data by retrieving missing data.
* *

View File

@@ -24,8 +24,10 @@
package org.kohsuke.github; package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.net.URL; import java.net.URL;
import java.util.Arrays;
/** /**
* Commit detail inside a {@link GHPullRequest}. * Commit detail inside a {@link GHPullRequest}.
@@ -33,6 +35,8 @@ import java.net.URL;
* @author Luca Milanesio * @author Luca Milanesio
* @see GHPullRequest#listCommits() * @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 { public class GHPullRequestCommitDetail {
private GHPullRequest owner; private GHPullRequest owner;
@@ -88,6 +92,10 @@ public class GHPullRequestCommitDetail {
public int getComment_count() { public int getComment_count() {
return comment_count; return comment_count;
} }
public Tree getTree() {
return tree;
}
} }
public static class CommitPointer { public static class CommitPointer {
@@ -136,6 +144,6 @@ public class GHPullRequestCommitDetail {
} }
public CommitPointer[] getParents() { public CommitPointer[] getParents() {
return parents; return Arrays.copyOf(parents, parents.length);
} }
} }

View File

@@ -1,5 +1,6 @@
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Date; import java.util.Date;
/** /**
@@ -24,6 +25,8 @@ public class GHRateLimit {
/** /**
* Non-epoch date * Non-epoch date
*/ */
@SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR",
justification = "The value comes from JSON deserialization")
public Date getResetDate() { public Date getResetDate() {
return new Date(reset.getTime() * 1000); return new Date(reset.getTime() * 1000);
} }

View File

@@ -1,5 +1,6 @@
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
@@ -77,7 +78,8 @@ public class GHRef {
return in; return in;
} }
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public static class GHObject { public static class GHObject {
private String type, sha, url; private String type, sha, url;

View File

@@ -45,6 +45,12 @@ public class GHRelease extends GHObject {
return draft; return draft;
} }
public GHRelease setDraft(boolean draft) throws IOException {
edit("draft", draft);
this.draft = draft;
return this;
}
public URL getHtmlUrl() { public URL getHtmlUrl() {
return GitHub.parseURL(html_url); return GitHub.parseURL(html_url);
} }
@@ -70,7 +76,7 @@ public class GHRelease extends GHObject {
} }
public Date getPublished_at() { public Date getPublished_at() {
return published_at; return new Date(published_at.getTime());
} }
public GitHub getRoot() { public GitHub getRoot() {
@@ -144,6 +150,13 @@ public class GHRelease extends GHObject {
new Requester(root).method("DELETE").to(owner.getApiTailUrl("releases/"+id)); new Requester(root).method("DELETE").to(owner.getApiTailUrl("releases/"+id));
} }
/**
* Edit this release.
*/
private void edit(String key, Object value) throws IOException {
new Requester(root)._with(key, value).method("PATCH").to(owner.getApiTailUrl("releases/"+id));
}
private String getApiTailUrl(String end) { private String getApiTailUrl(String end) {
return owner.getApiTailUrl(format("releases/%s/%s",id,end)); return owner.getApiTailUrl(format("releases/%s/%s",id,end));
} }

View File

@@ -25,6 +25,7 @@ package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import javax.xml.bind.DatatypeConverter; import javax.xml.bind.DatatypeConverter;
@@ -33,7 +34,9 @@ import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.InterruptedIOException; import java.io.InterruptedIOException;
import java.io.Reader; import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.URL; import java.net.URL;
import java.nio.charset.Charset;
import java.util.*; import java.util.*;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
@@ -44,12 +47,14 @@ import static java.util.Arrays.asList;
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
@SuppressWarnings({"UnusedDeclaration"}) @SuppressWarnings({"UnusedDeclaration"})
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public class GHRepository extends GHObject { public class GHRepository extends GHObject {
/*package almost final*/ GitHub root; /*package almost final*/ GitHub root;
private String description, homepage, name, full_name; private String description, homepage, name, full_name;
private String html_url; // this is the UI private String html_url; // this is the UI
private String git_url, ssh_url, clone_url, svn_url; private String git_url, ssh_url, clone_url, svn_url, mirror_url;
private GHUser owner; // not fully populated. beware. private GHUser owner; // not fully populated. beware.
private boolean has_issues, has_wiki, fork, has_downloads; private boolean has_issues, has_wiki, fork, has_downloads;
@JsonProperty("private") @JsonProperty("private")
@@ -154,6 +159,14 @@ public class GHRepository extends GHObject {
return svn_url; return svn_url;
} }
/**
* Gets the Mirror URL to access this repository: https://github.com/apache/tomee
* mirrored from git://git.apache.org/tomee.git
*/
public String getMirrorUrl() {
return mirror_url;
}
/** /**
* Gets the SSH URL to access this repository, such as git@github.com:rails/rails.git * Gets the SSH URL to access this repository, such as git@github.com:rails/rails.git
*/ */
@@ -217,7 +230,8 @@ public class GHRepository extends GHObject {
public List<GHIssue> getIssues(GHIssueState state, GHMilestone milestone) throws IOException { public List<GHIssue> getIssues(GHIssueState state, GHMilestone milestone) throws IOException {
return Arrays.asList(GHIssue.wrap(root.retrieve() return Arrays.asList(GHIssue.wrap(root.retrieve()
.to(getApiTailUrl(String.format("issues?state=%s&milestone=%s", .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 GHIssue[].class
), this)); ), this));
} }
@@ -383,7 +397,8 @@ public class GHRepository extends GHObject {
public int getSize() { public int getSize() {
return size; return size;
} }
/** /**
* Gets the collaborators on this repository. * Gets the collaborators on this repository.
* This set always appear to include the owner. * This set always appear to include the owner.
@@ -675,7 +690,23 @@ public class GHRepository extends GHObject {
} }
public GHCompare getCompare(GHBranch id1, GHBranch id2) throws IOException { public GHCompare getCompare(GHBranch id1, GHBranch id2) throws IOException {
return getCompare(id1.getName(),id2.getName());
GHRepository owner1 = id1.getOwner();
GHRepository owner2 = id2.getOwner();
// If the owner of the branches is different, we have a cross-fork compare.
if (owner1!=null && owner2!=null) {
String ownerName1 = owner1.getOwnerName();
String ownerName2 = owner2.getOwnerName();
if (!StringUtils.equals(ownerName1, ownerName2)) {
String qualifiedName1 = String.format("%s:%s", ownerName1, id1.getName());
String qualifiedName2 = String.format("%s:%s", ownerName2, id2.getName());
return getCompare(qualifiedName1, qualifiedName2);
}
}
return getCompare(id1.getName(), id2.getName());
} }
/** /**
@@ -950,6 +981,8 @@ public class GHRepository extends GHObject {
* @deprecated * @deprecated
* Use {@link #getHooks()} and {@link #createHook(String, Map, Collection, boolean)} * 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<URL> getPostCommitHooks() { public Set<URL> getPostCommitHooks() {
return postCommitHooks; return postCommitHooks;
} }
@@ -957,6 +990,8 @@ public class GHRepository extends GHObject {
/** /**
* Live set view of the post-commit hook. * 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<URL> postCommitHooks = new AbstractSet<URL>() { private final Set<URL> postCommitHooks = new AbstractSet<URL>() {
private List<URL> getPostCommitHooks() { private List<URL> getPostCommitHooks() {
try { try {
@@ -1083,6 +1118,9 @@ public class GHRepository extends GHObject {
public List<GHContent> getDirectoryContent(String path, String ref) throws IOException { public List<GHContent> getDirectoryContent(String path, String ref) throws IOException {
Requester requester = root.retrieve(); Requester requester = root.retrieve();
while (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
String target = getApiTailUrl("contents/" + path); String target = getApiTailUrl("contents/" + path);
GHContent[] files = requester.with("ref",ref).to(target, GHContent[].class); GHContent[] files = requester.with("ref",ref).to(target, GHContent[].class);
@@ -1101,11 +1139,17 @@ public class GHRepository extends GHObject {
} }
public GHContentUpdateResponse createContent(String content, String commitMessage, String path) 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 { 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 { public GHContentUpdateResponse createContent(byte[] contentBytes, String commitMessage, String path) throws IOException {
@@ -1225,6 +1269,18 @@ public class GHRepository extends GHObject {
public int getContributions() { public int getContributions() {
return contributions; 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);
}
} }
/** /**

View File

@@ -1,10 +1,14 @@
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/** /**
* Represents a tag in {@link GHRepository} * Represents a tag in {@link GHRepository}
* *
* @see GHRepository#listTags() * @see GHRepository#listTags()
*/ */
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public class GHTag { public class GHTag {
private GHRepository owner; private GHRepository owner;
private GitHub root; private GitHub root;

View File

@@ -1,5 +1,6 @@
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
@@ -12,6 +13,8 @@ import java.util.Date;
* @see GHNotificationStream * @see GHNotificationStream
* @author Kohsuke Kawaguchi * @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 { public class GHThread extends GHObject {
private GitHub root; private GitHub root;
private GHRepository repository; private GHRepository repository;
@@ -67,6 +70,10 @@ public class GHThread extends GHObject {
public String getType() { public String getType() {
return subject.type; return subject.type;
} }
public String getLastCommentUrl() {
return subject.latest_comment_url;
}
/** /**
* If this thread is about an issue, return that issue. * If this thread is about an issue, return that issue.

View File

@@ -47,12 +47,14 @@ import java.util.Set;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std; import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import java.nio.charset.Charset;
/** /**
* Root of the GitHub API. * Root of the GitHub API.
@@ -128,7 +130,8 @@ public class GitHub {
} else { } else {
if (password!=null) { if (password!=null) {
String authorization = (login + ':' + password); String authorization = (login + ':' + password);
encodedAuthorization = "Basic "+new String(Base64.encodeBase64(authorization.getBytes())); Charset charset = Charsets.UTF_8;
encodedAuthorization = "Basic "+new String(Base64.encodeBase64(authorization.getBytes(charset)), charset);
} else {// anonymous access } else {// anonymous access
encodedAuthorization = null; encodedAuthorization = null;
} }
@@ -197,6 +200,15 @@ public class GitHub {
return new GitHubBuilder().build(); return new GitHubBuilder().build();
} }
/**
* Connects to GitHub Enterprise anonymously.
*
* All operations that requires authentication will fail.
*/
public static GitHub connectToEnterpriseAnonymously(String apiUrl) throws IOException {
return new GitHubBuilder().withEndpoint(apiUrl).build();
}
/** /**
* Is this an anonymous connection * Is this an anonymous connection
* @return {@code true} if operations that require authentication will fail. * @return {@code true} if operations that require authentication will fail.
@@ -439,6 +451,29 @@ public class GitHub {
} }
} }
private static class GHApiInfo {
private String rate_limit_url;
void check(String apiUrl) throws IOException {
if (rate_limit_url==null)
throw new IOException(apiUrl+" doesn't look like GitHub API URL");
// make sure that the URL is legitimate
new URL(rate_limit_url);
}
}
/**
* Ensures that the API URL is valid.
*
* <p>
* This method returns normally if the endpoint is reachable and verified to be GitHub API URL.
* Otherwise this method throws {@link IOException} to indicate the problem.
*/
public void checkApiUrlValidity() throws IOException {
retrieve().to("/", GHApiInfo.class).check(apiUrl);
}
/** /**
* Search issues. * Search issues.
*/ */

View File

@@ -1,6 +1,7 @@
package org.kohsuke.github; package org.kohsuke.github;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.kohsuke.github.extras.ImpatientHttpConnector;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@@ -51,7 +52,7 @@ public class GitHubBuilder {
try { try {
builder = fromPropertyFile(); builder = fromPropertyFile();
if (builder.user != null) if (builder.oauthToken != null || builder.user != null)
return builder; return builder;
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
// fall through // fall through
@@ -60,7 +61,7 @@ public class GitHubBuilder {
builder = fromEnvironment(); builder = fromEnvironment();
if (builder.user != null) if (builder.oauthToken != null || builder.user != null)
return builder; return builder;
else else
throw (IOException)new IOException("Failed to resolve credentials from ~/.github or the environment.").initCause(cause); throw (IOException)new IOException("Failed to resolve credentials from ~/.github or the environment.").initCause(cause);
@@ -184,11 +185,11 @@ public class GitHubBuilder {
* the system default one. * the system default one.
*/ */
public GitHubBuilder withProxy(final Proxy p) { public GitHubBuilder withProxy(final Proxy p) {
return withConnector(new HttpConnector() { return withConnector(new ImpatientHttpConnector(new HttpConnector() {
public HttpURLConnection connect(URL url) throws IOException { public HttpURLConnection connect(URL url) throws IOException {
return (HttpURLConnection) url.openConnection(p); return (HttpURLConnection) url.openConnection(p);
} }
}); }));
} }
public GitHub build() throws IOException { public GitHub build() throws IOException {

View File

@@ -1,5 +1,6 @@
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Date; import java.util.Date;
/** /**
@@ -11,6 +12,8 @@ import java.util.Date;
* *
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public class GitUser { public class GitUser {
private String name, email, date; private String name, email, date;

View File

@@ -1,8 +1,11 @@
package org.kohsuke.github; package org.kohsuke.github;
import org.kohsuke.github.extras.ImpatientHttpConnector;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.util.concurrent.TimeUnit;
/** /**
* Pluggability for customizing HTTP request behaviors or using altogether different library. * Pluggability for customizing HTTP request behaviors or using altogether different library.
@@ -21,9 +24,9 @@ public interface HttpConnector {
/** /**
* Default implementation that uses {@link URL#openConnection()}. * Default implementation that uses {@link URL#openConnection()}.
*/ */
HttpConnector DEFAULT = new HttpConnector() { HttpConnector DEFAULT = new ImpatientHttpConnector(new HttpConnector() {
public HttpURLConnection connect(URL url) throws IOException { public HttpURLConnection connect(URL url) throws IOException {
return (HttpURLConnection) url.openConnection(); return (HttpURLConnection) url.openConnection();
} }
}; });
} }

View File

@@ -1,5 +1,6 @@
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Iterator; import java.util.Iterator;
/** /**
@@ -7,6 +8,8 @@ import java.util.Iterator;
* *
* @author Kohsuke Kawaguchi * @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<T> extends PagedIterable<T> { public abstract class PagedSearchIterable<T> extends PagedIterable<T> {
private final GitHub root; private final GitHub root;

View File

@@ -53,6 +53,8 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import javax.annotation.WillClose;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static org.kohsuke.github.GitHub.*; import static org.kohsuke.github.GitHub.*;
@@ -119,7 +121,7 @@ class Requester {
public Requester with(String key, Integer value) { public Requester with(String key, Integer value) {
if (value!=null) if (value!=null)
_with(key, value.intValue()); _with(key, value);
return this; return this;
} }
@@ -143,7 +145,7 @@ class Requester {
return _with(key, value); return _with(key, value);
} }
public Requester with(InputStream body) { public Requester with(@WillClose/*later*/ InputStream body) {
this.body = body; this.body = body;
return this; return this;
} }
@@ -257,6 +259,8 @@ class Requester {
while (true) {// loop while API rate limit is hit while (true) {// loop while API rate limit is hit
setupConnection(root.getApiURL(tailApiUrl)); setupConnection(root.getApiURL(tailApiUrl));
uc.setRequestMethod("GET");
buildRequest(); buildRequest();
try { try {
@@ -271,8 +275,11 @@ class Requester {
while (true) {// loop while API rate limit is hit while (true) {// loop while API rate limit is hit
setupConnection(root.getApiURL(tailApiUrl)); setupConnection(root.getApiURL(tailApiUrl));
buildRequest(); // if the download link is encoded with a token on the query string, the default behavior of POST will fail
uc.setRequestMethod("GET");
buildRequest();
try { try {
return wrapStream(uc.getInputStream()); return wrapStream(uc.getInputStream());
} catch (IOException e) { } catch (IOException e) {
@@ -323,23 +330,26 @@ class Requester {
* *
* Every iterator call reports a new batch. * Every iterator call reports a new batch.
*/ */
/*package*/ <T> Iterator<T> asIterator(String _tailApiUrl, final Class<T> type) { /*package*/ <T> Iterator<T> asIterator(final String _tailApiUrl, final Class<T> type) {
method("GET"); method("GET");
final StringBuilder strBuilder = new StringBuilder(_tailApiUrl);
if (!args.isEmpty()) { if (!args.isEmpty()) {
boolean first=true; boolean first=true;
try { try {
for (Entry a : args) { for (Entry a : args) {
_tailApiUrl += first ? '?' : '&'; strBuilder.append(first ? '?' : '&');
first = false; 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) { } catch (UnsupportedEncodingException e) {
throw new AssertionError(e); // UTF-8 is mandatory throw new AssertionError(e); // UTF-8 is mandatory
} }
} }
final String tailApiUrl = _tailApiUrl; final String tailApiUrl = strBuilder.toString();
return new Iterator<T>() { return new Iterator<T>() {
/** /**
@@ -507,11 +517,4 @@ class Requester {
IOUtils.closeQuietly(es); IOUtils.closeQuietly(es);
} }
} }
private Set<String> toSet(String s) {
Set<String> r = new HashSet<String>();
for (String t : s.split(","))
r.add(t.trim());
return r;
}
} }

View File

@@ -1,12 +1,18 @@
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/** /**
* Represents the result of a search * Represents the result of a search
* *
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
abstract class SearchResult<T> { abstract class SearchResult<T> {
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Field comes from JSON deserialization")
int total_count; int total_count;
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Field comes from JSON deserialization")
boolean incomplete_results; boolean incomplete_results;
/** /**

View File

@@ -0,0 +1,58 @@
package org.kohsuke.github.extras;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.kohsuke.github.HttpConnector;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.TimeUnit;
/**
* {@link HttpConnector} wrapper that sets timeout
*
* @author Kohsuke Kawaguchi
*/
public class ImpatientHttpConnector implements HttpConnector {
private final HttpConnector base;
private final int readTimeout, connectTimeout;
/**
* @param connectTimeout
* HTTP connection timeout in milliseconds
* @param readTimeout
* HTTP read timeout in milliseconds
*/
public ImpatientHttpConnector(HttpConnector base, int connectTimeout, int readTimeout) {
this.base = base;
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
}
public ImpatientHttpConnector(HttpConnector base, int timeout) {
this(base,timeout,timeout);
}
public ImpatientHttpConnector(HttpConnector base) {
this(base,CONNECT_TIMEOUT,READ_TIMEOUT);
}
public HttpURLConnection connect(URL url) throws IOException {
HttpURLConnection con = base.connect(url);
con.setConnectTimeout(connectTimeout);
con.setReadTimeout(readTimeout);
return con;
}
/**
* Default connection timeout in milliseconds
*/
@SuppressFBWarnings("MS_SHOULD_BE_FINAL")
public static int CONNECT_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(10);
/**
* Default read timeout in milliseconds
*/
@SuppressFBWarnings("MS_SHOULD_BE_FINAL")
public static int READ_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(10);
}

View File

@@ -286,7 +286,8 @@ public class AppTest extends AbstractGitHubApiTestBase {
@Test @Test
public void testGetTeamsForRepo() throws Exception { public void testGetTeamsForRepo() throws Exception {
kohsuke(); kohsuke();
assertEquals(1, gitHub.getOrganization("github-api-test-org").getRepository("testGetTeamsForRepo").getTeams().size()); // 'Core Developers' and 'Owners'
assertEquals(2, gitHub.getOrganization("github-api-test-org").getRepository("testGetTeamsForRepo").getTeams().size());
} }
@Test @Test

View File

@@ -43,6 +43,14 @@ public class GHContentIntegrationTest extends AbstractGitHubApiTestBase {
assertTrue(entries.size() == 3); assertTrue(entries.size() == 3);
} }
@Test
public void testGetDirectoryContentTrailingSlash() throws Exception {
//Used to truncate the ?ref=master, see gh-224 https://github.com/kohsuke/github-api/pull/224
List<GHContent> entries = repo.getDirectoryContent("ghcontent-ro/a-dir-with-3-entries/", "master");
assertTrue(entries.get(0).getUrl().endsWith("?ref=master"));
}
@Test @Test
public void testCRUDContent() throws Exception { public void testCRUDContent() throws Exception {
GHContentUpdateResponse created = repo.createContent("this is an awesome file I created\n", "Creating a file for integration tests.", createdFilename); GHContentUpdateResponse created = repo.createContent("this is an awesome file I created\n", "Creating a file for integration tests.", createdFilename);

View File

@@ -12,6 +12,7 @@ import org.junit.Test;
import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -119,4 +120,10 @@ public class GitHubTest {
GHRateLimit rateLimit = github.getRateLimit(); GHRateLimit rateLimit = github.getRateLimit();
assertThat(rateLimit.getResetDate(), notNullValue()); assertThat(rateLimit.getResetDate(), notNullValue());
} }
@Test
public void testGitHubIsApiUrlValid() throws IOException {
GitHub github = GitHub.connectAnonymously();
github.checkApiUrlValidity();
}
} }

View File

@@ -49,6 +49,26 @@ public class PullRequestTest extends AbstractGitHubApiTestBase {
assertTrue(comments.isEmpty()); assertTrue(comments.isEmpty());
} }
@Test
public void testMergeCommitSHA() throws Exception {
String name = rnd.next();
GHPullRequest p = getRepository().createPullRequest(name, "mergeable-branch", "master", "## test");
for (int i=0; i<100; i++) {
GHPullRequest updated = getRepository().getPullRequest(p.getNumber());
if (updated.getMergeCommitSha()!=null) {
// make sure commit exists
GHCommit commit = getRepository().getCommit(updated.getMergeCommitSha());
assertNotNull(commit);
return;
}
// mergeability computation takes time. give it more chance
Thread.sleep(100);
}
// hmm?
fail();
}
@Test @Test
// Requires push access to the test repo to pass // Requires push access to the test repo to pass
public void setLabels() throws Exception { public void setLabels() throws Exception {