Compare commits

...

100 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
Kohsuke Kawaguchi
505bb8f06d [maven-release-plugin] prepare release github-api-1.69 2015-07-17 05:09:25 -07:00
Kohsuke Kawaguchi
f8408bd29f This method can return null.
I think what's going on is that GitHub takes some non-zero amount of time to compute this value, and our test runs too fast sometimes and try to fetch a PR before its mergeability is computed
2015-07-17 15:06:39 +03:00
Kohsuke Kawaguchi
5f2c84a913 Tests should use test repositories for mutating tests.
Picking up the first random repository you are an owner of and making a change to it is too dangerous.
2015-07-17 14:33:18 +03:00
Kohsuke Kawaguchi
3011c99e3f Merge pull request #208 from oleg-nenashev/master
Fix potential NPE in the code
2015-07-17 14:24:14 +03:00
Oleg Nenashev
ebc97f42ad Fix potential NPE in the code 2015-07-17 14:21:46 +03:00
Kohsuke Kawaguchi
4660c6d363 Merge pull request #192
Changing GHHook to abstract is a binary incompatible change in theory,
but given the way this class is designed it is difficult to imagine
any client code instantiating this class.

So I think it is OK.
2015-07-17 14:06:47 +03:00
Kohsuke Kawaguchi
e239ef50ba Consistent name with other classes 2015-07-17 14:06:35 +03:00
Kohsuke Kawaguchi
8b4312a880 Merge pull request #203 2015-07-17 13:52:35 +03:00
Kohsuke Kawaguchi
90daf8087e Turning this into javadoc so that users can see them in IDE. 2015-07-17 13:52:16 +03:00
Kohsuke Kawaguchi
dd21bcb34c I think this is a better name 2015-07-17 13:51:31 +03:00
Kohsuke Kawaguchi
c4113f1ac7 Merge pull request #182 from henryju/master
Fix invalid URL for pull request comments update/delete
2015-07-17 13:47:43 +03:00
Kohsuke Kawaguchi
efa48acd1d Merge pull request #185 from marc-guenther/master
Fixes #183: added a method listForks() to GHRepository
2015-07-17 13:47:17 +03:00
Kohsuke Kawaguchi
15e4d07a6d Merge pull request #187 from yegorius/master
Recognize previous_file field in GHCommit.File
2015-07-17 13:46:21 +03:00
Kohsuke Kawaguchi
cb2248809c Merge pull request #190 2015-07-17 13:43:01 +03:00
Kohsuke Kawaguchi
eb9551d81b Renamed getMasterBranch to getDefaultBranch
The new set method can be simply renamed without the backward
compatibility version since it's new
2015-07-17 13:42:20 +03:00
Kohsuke Kawaguchi
87d1256a1b Merge pull request #189 from if6was9/fix-post-body-regression
fixed regression that caused POST operations to be sent as GET
2015-07-17 13:39:52 +03:00
Kohsuke Kawaguchi
dd6179cf25 Merge pull request #197 from treeduck/patch-1
added Page Build
2015-07-17 13:35:20 +03:00
Marc Guenther
23c56ff887 remove unused import 2015-07-17 12:30:49 +02:00
Kohsuke Kawaguchi
c4eefa6917 Merge branch 'master' of github.com:kohsuke/github-api 2015-07-17 13:29:40 +03:00
Kohsuke Kawaguchi
202cff58f2 Merge pull request #201 2015-07-17 13:29:22 +03:00
Kohsuke Kawaguchi
025806f0fd Consistent name with other classes 2015-07-17 13:29:07 +03:00
Kohsuke Kawaguchi
b0c54ef0f1 Restored backward compatibility with the former signature 2015-07-17 13:27:20 +03:00
Kohsuke Kawaguchi
4d7681b1a4 Merge pull request #206 from torodev/master
Specified the GET
2015-07-17 13:24:48 +03:00
Kohsuke Kawaguchi
340fb3f624 Merge pull request #207 from oleg-nenashev/findbugs-enable
Enable FindBugs in the repo
2015-07-17 13:13:23 +03:00
Marc Guenther
a83aad22ca renamed Sort enum, some cleanup, better javadoc 2015-07-17 09:33:48 +02:00
Oleg Nenashev
5a418dcce6 Enable FindBugs 2015-07-16 16:56:09 +03:00
torodev
ec5392708f Specified the GET
Previously doesn't specify the HTTP method to perform
2015-07-14 09:47:04 +08:00
Oleg Nenashev
901db92b11 Merge pull request #205 from stephenc/fix-npe
Fix NPE found when resolving issues from search api
2015-07-07 00:22:46 +03:00
Stephen Connolly
01b8b10344 Fix NPE found when resolving issues from search api 2015-07-06 11:07:05 +01:00
Oleg Nenashev
698d642ec8 Merge pull request #204 from lanwen/ping_event
add ping event to GH events enum
2015-07-05 19:57:20 +03:00
MerkushevKirill
90d1047fb2 add ping event to GH events enum 2015-07-05 19:37:56 +03:00
Luca Milanesio
b0d1eac477 GitHub API have changed the semantics of /user/repos API
It seems that since a couple of days (or weeks?) the /user/repos is returning
ALL the repositories that the user has access or collaborates to whilst previously
were only the ones that belong to him.

JavaDoc updated in order to avoid getting unwanted results and introduced as well
the possibility to filter a specific type of repository to be returned:
- All (the GitHub's default)
- Owner (the user's repos)
- Public / Private (public or private repos)
- Member (the user collaborates to)
2015-06-26 13:42:43 +01:00
Julien HENRY
cce02aec3d Add delete and update for GHIssueComment 2015-06-16 09:27:55 +02:00
Julien HENRY
492ff58aa8 Fix invalid URL for pull request comments update/delete 2015-06-16 09:16:49 +02:00
Kohsuke Kawaguchi
dd3e73996b Merge pull request #200 from lanwen/lost_body_write
fix for unused json map when method with body, but body is null
2015-06-15 10:38:14 -07:00
MerkushevKirill
931ed7adac don't ignore args when method without body
in case of GET or DELETE request
2015-06-15 18:14:58 +03:00
MerkushevKirill
861fd55d06 fix for unused json map when method with body, but body is null
fixes regression from b976e0ef4e
2015-06-15 17:57:16 +03:00
Kohsuke Kawaguchi
9a4eee4e7d Merge pull request #198 from lanwen/rate-reset
fix for GH Enterprise which does not have rate limit reset field
2015-06-11 10:53:11 -07:00
MerkushevKirill
ed76cdbddf fix for GH Enterprise which does not have rate limit reset field
Fixes regression from a4c1c8de24
2015-06-11 14:52:50 +03:00
Koji Habu
9d91549803 added Page Build 2015-06-10 15:43:57 -07:00
Marc Guenther
a5425a3c71 improved javadoc for listForks() 2015-05-28 22:18:02 +02:00
Chris Hut
f4b105b10f Enable creation and retrieval of org webhooks
made GHHook abstract and created two concrete subclasses for org
and repo hooks. Created utility class GHHooks to manage creation
and retrieval of org/repo hooks with minimal code duplication. These
are invoked by GHOrganization and GHRepository respectively.
2015-05-15 13:29:18 -07:00
Rob Schoening
e4de09c55b allow default branch to be set 2015-05-09 01:05:04 -07:00
Rob Schoening
d77be9d382 fixed regression that caused POST operations to be sent as GET 2015-05-09 01:01:04 -07:00
yegorius
626909addb recognize previous_file field in GHCommit.File 2015-05-01 17:59:01 +03:00
Marc Guenther
9b750bedef Fixes #183: added a method listForks() to GHRepository
listForks() will list all forks of a repository.
An optional sort argument is also supported.
2015-05-01 14:06:20 +02:00
Kohsuke Kawaguchi
b976e0ef4e Issue #180: don't write body if HTTP method is DELETE. 2015-04-26 10:52:43 -07:00
Kohsuke Kawaguchi
fd434292ad [maven-release-plugin] prepare for next development iteration 2015-04-19 17:40:39 -07:00
Kohsuke Kawaguchi
7b4d3a869b [maven-release-plugin] prepare release github-api-1.68 2015-04-19 17:40:35 -07:00
Kohsuke Kawaguchi
eeebb1b59f Added the 'sha' parameter.
Fixes issue #176
2015-04-19 17:25:13 -07:00
Julien HENRY
63136f64b7 Merge pull request #174
The merge was done manually because the original commit contains lots of
whitespace only changes.
2015-04-19 17:22:04 -07:00
Kohsuke Kawaguchi
1d2fbf2d92 Merge pull request #179 from lskillen/master
Fix NullPointerException on RateLimitHandler when handling API errors.
2015-04-19 17:03:50 -07:00
Kohsuke Kawaguchi
1e52dded14 Added a helper method 2015-04-15 08:33:18 -07:00
Lee Skillen
cfc7005275 Fix NullPointerException on RateLimiter when handling API errors. 2015-04-14 14:45:47 +01:00
Kohsuke Kawaguchi
f23afcd5aa [maven-release-plugin] prepare for next development iteration 2015-04-13 18:30:43 -07:00
50 changed files with 1261 additions and 218 deletions

30
pom.xml
View File

@@ -7,7 +7,7 @@
</parent> </parent>
<artifactId>github-api</artifactId> <artifactId>github-api</artifactId>
<version>1.67</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.67</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>
@@ -44,6 +46,24 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>${findbugs-maven-plugin.version}</version>
<configuration>
<xmlOutput>true</xmlOutput>
<failOnError>${findbugs-maven-plugin.failOnError}</failOnError>
</configuration>
<executions>
<execution>
<id>run-findbugs</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>
@@ -109,6 +129,12 @@
<version>1.9.5</version> <version>1.9.5</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>annotations</artifactId>
<version>3.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>
<repositories> <repositories>
<repository> <repository>

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,10 +44,11 @@ public class GHBranch {
public String getSHA1() { public String getSHA1() {
return commit.sha; return commit.sha;
} }
@Override @Override
public String toString() { public String toString() {
return "Branch:" + name + " in " + owner.getUrl(); final String url = owner != null ? owner.getUrl().toString() : "unknown";
return "Branch:" + name + " in " + url;
} }
/*package*/ GHBranch wrap(GHRepository repo) { /*package*/ GHBranch wrap(GHRepository repo) {

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,10 +72,13 @@ 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;
String raw_url, blob_url, filename, sha, patch; String raw_url, blob_url, sha, patch;
String filename, previous_filename;
/** /**
* Number of lines added + removed. * Number of lines added + removed.
@@ -101,12 +109,21 @@ public class GHCommit {
} }
/** /**
* Just the base name and the extension without any directory name. * 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;
} }
/**
* Previous path, in case file has moved.
*/
public String getPreviousFilename() {
return previous_filename;
}
/** /**
* The actual change. * The actual change.
*/ */
@@ -139,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

@@ -23,6 +23,8 @@
*/ */
package org.kohsuke.github; package org.kohsuke.github;
import java.io.IOException;
/** /**
* Identifies a commit in {@link GHPullRequest}. * Identifies a commit in {@link GHPullRequest}.
* *
@@ -69,6 +71,13 @@ public class GHCommitPointer {
return label; return label;
} }
/**
* Obtains the commit that this pointer is referring to.
*/
public GHCommit getCommit() throws IOException {
return getRepository().getCommit(getSha());
}
void wrapUp(GitHub root) { void wrapUp(GitHub root) {
if (user!=null) user.root = root; if (user!=null) user.root = root;
if (repo!=null) repo.wrap(root); if (repo!=null) repo.wrap(root);

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

@@ -23,12 +23,15 @@ public enum GHEvent {
ISSUE_COMMENT, ISSUE_COMMENT,
ISSUES, ISSUES,
MEMBER, MEMBER,
PAGE_BUILD,
PUBLIC, PUBLIC,
PULL_REQUEST, PULL_REQUEST,
PULL_REQUEST_REVIEW_COMMENT, PULL_REQUEST_REVIEW_COMMENT,
PUSH, PUSH,
RELEASE, RELEASE,
REPOSITORY, // only valid for org hooks
STATUS, STATUS,
TEAM_ADD, TEAM_ADD,
WATCH WATCH,
PING
} }

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;
} }
@@ -104,8 +110,12 @@ public abstract class GHEventPayload {
@Override @Override
void wrapUp(GitHub root) { void wrapUp(GitHub root) {
super.wrapUp(root); super.wrapUp(root);
repository.wrap(root); if (repository != null) {
issue.wrap(repository); repository.wrap(root);
issue.wrap(repository);
} else {
issue.wrap(root);
}
comment.wrapUp(issue); comment.wrapUp(issue);
} }
} }

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,22 +12,14 @@ import java.util.Map;
/** /**
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
public class GHHook extends GHObject { @SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
/** "NP_UNWRITTEN_FIELD"}, justification = "JSON API")
* Repository that the hook belongs to. public abstract class GHHook extends GHObject {
*/
/*package*/ transient GHRepository repository;
String name; String name;
List<String> events; List<String> events;
boolean active; boolean active;
Map<String,String> config; Map<String,String> config;
/*package*/ GHHook wrap(GHRepository owner) {
this.repository = owner;
return this;
}
public String getName() { public String getName() {
return name; return name;
} }
@@ -50,7 +43,7 @@ public class GHHook extends GHObject {
* Deletes this hook. * Deletes this hook.
*/ */
public void delete() throws IOException { public void delete() throws IOException {
new Requester(repository.root).method("DELETE").to(String.format("/repos/%s/%s/hooks/%d", repository.getOwnerName(), repository.getName(), id)); new Requester(getRoot()).method("DELETE").to(getApiRoute());
} }
/** /**
@@ -60,4 +53,8 @@ public class GHHook extends GHObject {
public URL getHtmlUrl() { public URL getHtmlUrl() {
return null; return null;
} }
abstract GitHub getRoot();
abstract String getApiRoute();
} }

View File

@@ -0,0 +1,131 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* Utility class for creating and retrieving webhooks; removes duplication between GHOrganization and GHRepository
* functionality
*/
class GHHooks {
static abstract class Context {
private final GitHub root;
private Context(GitHub root) {
this.root = root;
}
public List<GHHook> getHooks() throws IOException {
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)
wrap(h);
return list;
}
public GHHook getHook(int id) throws IOException {
GHHook hook = root.retrieve().to(collection() + "/" + id, clazz());
return wrap(hook);
}
public GHHook createHook(String name, Map<String, String> config, Collection<GHEvent> events, boolean active) throws IOException {
List<String> ea = null;
if (events!=null) {
ea = new ArrayList<String>();
for (GHEvent e : events)
ea.add(e.name().toLowerCase(Locale.ENGLISH));
}
GHHook hook = new Requester(root)
.with("name", name)
.with("active", active)
._with("config", config)
._with("events", ea)
.to(collection(), clazz());
return wrap(hook);
}
abstract String collection();
abstract Class<? extends GHHook[]> collectionClass();
abstract Class<? extends GHHook> clazz();
abstract GHHook wrap(GHHook hook);
}
private static class RepoContext extends Context {
private final GHRepository repository;
private final GHUser owner;
private RepoContext(GHRepository repository, GHUser owner) {
super(repository.root);
this.repository = repository;
this.owner = owner;
}
@Override
String collection() {
return String.format("/repos/%s/%s/hooks", owner.getLogin(), repository.getName());
}
@Override
Class<? extends GHHook[]> collectionClass() {
return GHRepoHook[].class;
}
@Override
Class<? extends GHHook> clazz() {
return GHRepoHook.class;
}
@Override
GHHook wrap(GHHook hook) {
return ((GHRepoHook)hook).wrap(repository);
}
}
private static class OrgContext extends Context {
private final GHOrganization organization;
private OrgContext(GHOrganization organization) {
super(organization.root);
this.organization = organization;
}
@Override
String collection() {
return String.format("/orgs/%s/hooks", organization.getLogin());
}
@Override
Class<? extends GHHook[]> collectionClass() {
return GHOrgHook[].class;
}
@Override
Class<? extends GHHook> clazz() {
return GHOrgHook.class;
}
@Override
GHHook wrap(GHHook hook) {
return ((GHOrgHook)hook).wrap(organization);
}
}
static Context repoContext(GHRepository repository, GHUser owner) {
return new RepoContext(repository, owner);
}
static Context orgContext(GHOrganization organization) {
return new OrgContext(organization);
}
}

View File

@@ -24,6 +24,9 @@
package org.kohsuke.github; 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.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.Collection; import java.util.Collection;
@@ -140,9 +143,14 @@ public class GHIssue extends GHObject {
/** /**
* Updates the issue by adding a comment. * Updates the issue by adding a comment.
*
* @return
* Newly posted comment.
*/ */
public void comment(String message) throws IOException { @WithBridgeMethods(void.class)
new Requester(root).with("body",message).to(getIssuesApiRoute() + "/comments"); public GHIssueComment comment(String message) throws IOException {
GHIssueComment r = new Requester(root).with("body",message).to(getIssuesApiRoute() + "/comments", GHIssueComment.class);
return r.wrapUp(this);
} }
private void edit(String key, Object value) throws IOException { private void edit(String key, Object value) throws IOException {
@@ -176,7 +184,7 @@ public class GHIssue extends GHObject {
} }
public void assignTo(GHUser user) throws IOException { public void assignTo(GHUser user) throws IOException {
editIssue("assignee",user.getLogin()); editIssue("assignee", user.getLogin());
} }
public void setLabels(String... labels) throws IOException { public void setLabels(String... labels) throws IOException {
@@ -262,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

@@ -25,7 +25,6 @@ package org.kohsuke.github;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.Date;
/** /**
* Comment to the issue * Comment to the issue
@@ -79,4 +78,23 @@ public class GHIssueComment extends GHObject {
public URL getHtmlUrl() { public URL getHtmlUrl() {
return null; return null;
} }
/**
* Updates the body of the issue comment.
*/
public void update(String body) throws IOException {
new Requester(owner.root).with("body", body).method("PATCH").to(getApiRoute(), GHIssueComment.class);
this.body = body;
}
/**
* Deletes this issue comment.
*/
public void delete() throws IOException {
new Requester(owner.root).method("DELETE").to(getApiRoute());
}
private String getApiRoute() {
return "/repos/"+owner.getRepository().getOwnerName()+"/"+owner.getRepository().getName()+"/issues/comments/" + id;
}
} }

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

@@ -5,8 +5,8 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
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;
@@ -17,6 +17,33 @@ import java.util.TreeMap;
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
public class GHMyself extends GHUser { public class GHMyself extends GHUser {
/**
* Type of repositories returned during listing.
*/
public enum RepositoryListFilter {
/**
* All public and private repositories that current user has access or collaborates to
*/
ALL,
/**
* Public and private repositories owned by current user
*/
OWNER,
/**
* Public repositories that current user has access or collaborates to
*/
PUBLIC,
/**
* Private repositories that current user has access or collaborates to
*/
PRIVATE,
/**
* Public and private repositories that current user is a member
*/
MEMBER;
}
/** /**
* @deprecated * @deprecated
* Use {@link #getEmails2()} * Use {@link #getEmails2()}
@@ -109,16 +136,31 @@ public class GHMyself extends GHUser {
} }
/** /**
* Lists up all the repositories this user owns (public and private) using the specified page size. * List repositories that are accessible to the authenticated user (public and private) using the specified page size.
*
* This includes repositories owned by the authenticated user, repositories that belong to other users
* where the authenticated user is a collaborator, and other organizations' repositories that the authenticated
* user has access to through an organization membership.
* *
* @param pageSize size for each page of items returned by GitHub. Maximum page size is 100. * @param pageSize size for each page of items returned by GitHub. Maximum page size is 100.
* *
* Unlike {@link #getRepositories()}, this does not wait until all the repositories are returned. * Unlike {@link #getRepositories()}, this does not wait until all the repositories are returned.
*/ */
public PagedIterable<GHRepository> listRepositories(final int pageSize) { public PagedIterable<GHRepository> listRepositories(final int pageSize) {
return listRepositories(pageSize, RepositoryListFilter.ALL);
}
/**
* List repositories of a certain type that are accessible by current authenticated user using the specified page size.
*
* @param pageSize size for each page of items returned by GitHub. Maximum page size is 100.
* @param repoType type of repository returned in the listing
*/
public PagedIterable<GHRepository> listRepositories(final int pageSize, final RepositoryListFilter repoType) {
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, GHRepository[].class)) { return new PagedIterator<GHRepository>(root.retrieve().asIterator("/user/repos?per_page=" + pageSize +
"&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

@@ -0,0 +1,27 @@
/*
* © Copyright 2015 - SourceClear Inc
*/
package org.kohsuke.github;
class GHOrgHook extends GHHook {
/**
* Organization that the hook belongs to.
*/
/*package*/ transient GHOrganization organization;
/*package*/ GHOrgHook wrap(GHOrganization owner) {
this.organization = owner;
return this;
}
@Override
GitHub getRoot() {
return organization.root;
}
@Override
String getApiRoute() {
return String.format("/orgs/%s/hooks/%d", organization.getLogin(), id);
}
}

View File

@@ -1,10 +1,13 @@
package org.kohsuke.github; package org.kohsuke.github;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
@@ -26,7 +29,7 @@ public class GHOrganization extends GHPerson {
GHTeam t = getTeams().get(team); GHTeam t = getTeams().get(team);
if (t==null) if (t==null)
throw new IllegalArgumentException("No such team: "+team); throw new IllegalArgumentException("No such team: "+team);
return createRepository(name,description,homepage,t,isPublic); return createRepository(name, description, homepage, t, isPublic);
} }
public GHRepository createRepository(String name, String description, String homepage, GHTeam team, boolean isPublic) throws IOException { public GHRepository createRepository(String name, String description, String homepage, GHTeam team, boolean isPublic) throws IOException {
@@ -172,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());
@@ -252,4 +255,39 @@ public class GHOrganization extends GHPerson {
} }
}; };
} }
/**
* Retrieves the currently configured hooks.
*/
public List<GHHook> getHooks() throws IOException {
return GHHooks.orgContext(this).getHooks();
}
public GHHook getHook(int id) throws IOException {
return GHHooks.orgContext(this).getHook(id);
}
/**
*
* See https://api.github.com/hooks for possible names and their configuration scheme.
* TODO: produce type-safe binding
*
* @param name
* Type of the hook to be created. See https://api.github.com/hooks for possible names.
* @param config
* The configuration hash.
* @param events
* Can be null. Types of events to hook into.
*/
public GHHook createHook(String name, Map<String,String> config, Collection<GHEvent> events, boolean active) throws IOException {
return GHHooks.orgContext(this).createHook(name, config, events, active);
}
public GHHook createWebHook(URL url, Collection<GHEvent> events) throws IOException {
return createHook("web", Collections.singletonMap("url", url.toExternalForm()),events,true);
}
public GHHook createWebHook(URL url) throws IOException {
return createWebHook(url, null);
}
} }

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

@@ -27,7 +27,6 @@ import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.Locale;
/** /**
* A pull request. * A pull request.
@@ -51,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
@@ -143,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;
@@ -186,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.
* *
@@ -197,6 +205,39 @@ public class GHPullRequest extends GHIssue {
root.retrieve().to(url, this).wrapUp(owner); root.retrieve().to(url, this).wrapUp(owner);
} }
/**
* Retrieves all the commits associated to this pull request.
*/
public PagedIterable<GHPullRequestFileDetail> listFiles() {
return new PagedIterable<GHPullRequestFileDetail>() {
public PagedIterator<GHPullRequestFileDetail> iterator() {
return new PagedIterator<GHPullRequestFileDetail>(root.retrieve().asIterator(String.format("%s/files", getApiURL()),
GHPullRequestFileDetail[].class)) {
@Override
protected void wrapUp(GHPullRequestFileDetail[] page) {
}
};
}
};
}
/**
* Obtains all the review comments associated with this pull request.
*/
public PagedIterable<GHPullRequestReviewComment> listReviewComments() throws IOException {
return new PagedIterable<GHPullRequestReviewComment>() {
public PagedIterator<GHPullRequestReviewComment> iterator() {
return new PagedIterator<GHPullRequestReviewComment>(root.retrieve().asIterator(getApiRoute() + "/comments",
GHPullRequestReviewComment[].class)) {
protected void wrapUp(GHPullRequestReviewComment[] page) {
for (GHPullRequestReviewComment c : page)
c.wrapUp(GHPullRequest.this);
}
};
}
};
}
/** /**
* Retrieves all the commits associated to this pull request. * Retrieves all the commits associated to this pull request.
*/ */
@@ -208,12 +249,23 @@ public class GHPullRequest extends GHIssue {
GHPullRequestCommitDetail[].class)) { GHPullRequestCommitDetail[].class)) {
@Override @Override
protected void wrapUp(GHPullRequestCommitDetail[] page) { protected void wrapUp(GHPullRequestCommitDetail[] page) {
for (GHPullRequestCommitDetail c : page)
c.wrapUp(GHPullRequest.this);
} }
}; };
} }
}; };
} }
public GHPullRequestReviewComment createReviewComment(String body, String sha, String path, int position) throws IOException {
return new Requester(root).method("POST")
.with("body", body)
.with("commit_id", sha)
.with("path", path)
.with("position", position)
.to(getApiRoute() + "/comments", GHPullRequestReviewComment.class).wrapUp(this);
}
/** /**
* Merge this pull request. * Merge this pull request.
* *
@@ -223,7 +275,21 @@ public class GHPullRequest extends GHIssue {
* Commit message. If null, the default one will be used. * Commit message. If null, the default one will be used.
*/ */
public void merge(String msg) throws IOException { public void merge(String msg) throws IOException {
new Requester(root).method("PUT").with("commit_message",msg).to(getApiRoute()+"/merge"); merge(msg,null);
}
/**
* Merge this pull request.
*
* The equivalent of the big green "Merge pull request" button.
*
* @param msg
* Commit message. If null, the default one will be used.
* @param sha
* SHA that pull request head must match to allow merge.
*/
public void merge(String msg, String sha) throws IOException {
new Requester(root).method("PUT").with("commit_message",msg).with("sha",sha).to(getApiRoute()+"/merge");
} }
private void fetchIssue() throws IOException { private void fetchIssue() throws IOException {

View File

@@ -24,106 +24,126 @@
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}.
* *
* @author Luca Milanesio * @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 { public class GHPullRequestCommitDetail {
private GHPullRequest owner;
/*package*/ void wrapUp(GHPullRequest owner) {
this.owner = owner;
}
/** /**
* @deprecated Use {@link GitUser} * @deprecated Use {@link GitUser}
*/ */
public static class Authorship extends GitUser {} public static class Authorship extends GitUser {
}
public static class Tree { public static class Tree {
String sha;
String url;
public String getSha() {
return sha;
}
public URL getUrl() {
return GitHub.parseURL(url);
}
}
public static class Commit {
Authorship author;
Authorship committer;
String message;
Tree tree;
String url;
int comment_count;
@WithBridgeMethods(value = Authorship.class, castRequired = true)
public GitUser getAuthor() {
return author;
}
@WithBridgeMethods(value = Authorship.class, castRequired = true)
public GitUser getCommitter() {
return committer;
}
public String getMessage() {
return message;
}
public URL getUrl() {
return GitHub.parseURL(url);
}
public int getComment_count() {
return comment_count;
}
public Tree getTree() {
return tree;
}
}
public static class CommitPointer {
String sha;
String url;
String html_url;
public URL getUrl() {
return GitHub.parseURL(url);
}
public URL getHtml_url() {
return GitHub.parseURL(html_url);
}
public String getSha() {
return sha;
}
}
String sha; String sha;
String url; Commit commit;
public String getSha() {
return sha;
}
public URL getUrl() {
return GitHub.parseURL(url);
}
}
public static class Commit {
Authorship author;
Authorship committer;
String message;
Tree tree;
String url;
int comment_count;
@WithBridgeMethods(value=Authorship.class,castRequired=true)
public GitUser getAuthor() {
return author;
}
@WithBridgeMethods(value=Authorship.class,castRequired=true)
public GitUser getCommitter() {
return committer;
}
public String getMessage() {
return message;
}
public URL getUrl() {
return GitHub.parseURL(url);
}
public int getComment_count() {
return comment_count;
}
}
public static class CommitPointer {
String sha;
String url; String url;
String html_url; String html_url;
String comments_url;
public URL getUrl() { CommitPointer[] parents;
return GitHub.parseURL(url);
}
public URL getHtml_url() {
return GitHub.parseURL(html_url);
}
public String getSha() { public String getSha() {
return sha; return sha;
} }
}
String sha; public Commit getCommit() {
Commit commit; return commit;
String url; }
String html_url;
String comments_url; public URL getApiUrl() {
CommitPointer[] parents; return GitHub.parseURL(url);
}
public String getSha() {
return sha; public URL getUrl() {
} return GitHub.parseURL(html_url);
public Commit getCommit() { }
return commit;
} public URL getCommentsUrl() {
public URL getApiUrl() { return GitHub.parseURL(comments_url);
return GitHub.parseURL(url); }
}
public URL getUrl() { public CommitPointer[] getParents() {
return GitHub.parseURL(html_url); return Arrays.copyOf(parents, parents.length);
} }
public URL getCommentsUrl() {
return GitHub.parseURL(comments_url);
}
public CommitPointer[] getParents() {
return parents;
}
} }

View File

@@ -0,0 +1,86 @@
/*
* The MIT License
*
* Copyright (c) 2015, Julien Henry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.kohsuke.github;
import java.net.URL;
/**
* File detail inside a {@link GHPullRequest}.
*
* @author Julien Henry
* @see GHPullRequest#listFiles()
*/
public class GHPullRequestFileDetail {
String sha;
String filename;
String status;
int additions;
int deletions;
int changes;
String blob_url;
String raw_url;
String contents_url;
String patch;
public String getSha() {
return sha;
}
public String getFilename() {
return filename;
}
public String getStatus() {
return status;
}
public int getAdditions() {
return additions;
}
public int getDeletions() {
return deletions;
}
public int getChanges() {
return changes;
}
public URL getBlobUrl() {
return GitHub.parseURL(blob_url);
}
public URL getRawUrl() {
return GitHub.parseURL(raw_url);
}
public URL getContentsUrl() {
return GitHub.parseURL(contents_url);
}
public String getPatch() {
return patch;
}
}

View File

@@ -0,0 +1,106 @@
/*
* The MIT License
*
* Copyright (c) 2010, Kohsuke Kawaguchi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
/**
* Review comment to the pull request
*
* @author Julien Henry
* @see GHPullRequest#listReviewComments()
* @see GHPullRequest#createReviewComment(String, String, String, int)
*/
public class GHPullRequestReviewComment extends GHObject {
GHPullRequest owner;
private String body;
private GHUser user;
private String path;
private int position;
private int originalPosition;
/*package*/ GHPullRequestReviewComment wrapUp(GHPullRequest owner) {
this.owner = owner;
return this;
}
/**
* Gets the pull request to which this review comment is associated.
*/
public GHPullRequest getParent() {
return owner;
}
/**
* The comment itself.
*/
public String getBody() {
return body;
}
/**
* Gets the user who posted this comment.
*/
public GHUser getUser() throws IOException {
return owner.root.getUser(user.getLogin());
}
public String getPath() {
return path;
}
public int getPosition() {
return position;
}
public int getOriginalPosition() {
return originalPosition;
}
@Override
public URL getHtmlUrl() {
return null;
}
protected String getApiRoute() {
return "/repos/"+owner.getRepository().getFullName()+"/pulls/comments/"+id;
}
/**
* Updates the comment.
*/
public void update(String body) throws IOException {
new Requester(owner.root).method("PATCH").with("body", body).to(getApiRoute(),this);
this.body = body;
}
/**
* Deletes this review comment.
*/
public void delete() throws IOException {
new Requester(owner.root).method("DELETE").to(getApiRoute());
}
}

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

@@ -0,0 +1,23 @@
package org.kohsuke.github;
class GHRepoHook extends GHHook {
/**
* Repository that the hook belongs to.
*/
/*package*/ transient GHRepository repository;
/*package*/ GHRepoHook wrap(GHRepository owner) {
this.repository = owner;
return this;
}
@Override
GitHub getRoot() {
return repository.root;
}
@Override
String getApiRoute() {
return String.format("/repos/%s/%s/hooks/%d", repository.getOwnerName(), repository.getName(), id);
}
}

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,23 +34,27 @@ 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;
/** /**
* A repository on GitHub. * A repository on GitHub.
* *
* @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")
@@ -57,14 +62,14 @@ public class GHRepository extends GHObject {
private int watchers,forks,open_issues,size,network_count,subscribers_count; private int watchers,forks,open_issues,size,network_count,subscribers_count;
private String pushed_at; private String pushed_at;
private Map<Integer,GHMilestone> milestones = new HashMap<Integer, GHMilestone>(); private Map<Integer,GHMilestone> milestones = new HashMap<Integer, GHMilestone>();
private String default_branch,language; private String default_branch,language;
private Map<String,GHCommit> commits = new HashMap<String, GHCommit>(); private Map<String,GHCommit> commits = new HashMap<String, GHCommit>();
private GHRepoPermission permissions; private GHRepoPermission permissions;
private GHRepository source, parent; private GHRepository source, parent;
public GHDeploymentBuilder createDeployment(String ref) { public GHDeploymentBuilder createDeployment(String ref) {
return new GHDeploymentBuilder(this,ref); return new GHDeploymentBuilder(this,ref);
} }
@@ -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
*/ */
@@ -164,7 +177,7 @@ public class GHRepository extends GHObject {
public URL getHtmlUrl() { public URL getHtmlUrl() {
return GitHub.parseURL(html_url); return GitHub.parseURL(html_url);
} }
/** /**
* Short repository name without the owner. For example 'jenkins' in case of http://github.com/jenkinsci/jenkins * Short repository name without the owner. For example 'jenkins' in case of http://github.com/jenkinsci/jenkins
*/ */
@@ -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));
} }
@@ -321,6 +335,10 @@ public class GHRepository extends GHObject {
return fork; return fork;
} }
/**
* Returns the number of all forks of this repository.
* This not only counts direct forks, but also forks of forks, and so on.
*/
public int getForks() { public int getForks() {
return forks; return forks;
} }
@@ -364,6 +382,14 @@ public class GHRepository extends GHObject {
* @return * @return
* This field is null until the user explicitly configures the master branch. * This field is null until the user explicitly configures the master branch.
*/ */
public String getDefaultBranch() {
return default_branch;
}
/**
* @deprecated
* Renamed to {@link #getDefaultBranch()}
*/
public String getMasterBranch() { public String getMasterBranch() {
return default_branch; return default_branch;
} }
@@ -371,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.
@@ -494,6 +521,10 @@ public class GHRepository extends GHObject {
edit("homepage",value); edit("homepage",value);
} }
public void setDefaultBranch(String value) throws IOException {
edit("default_branch", value);
}
/** /**
* Deletes this repository. * Deletes this repository.
*/ */
@@ -505,6 +536,43 @@ public class GHRepository extends GHObject {
} }
} }
/**
* Sort orders for listing forks
*/
public static enum ForkSort { NEWEST, OLDEST, STARGAZERS }
/**
* Lists all the direct forks of this repository, sorted by
* github api default, currently {@link ForkSort#NEWEST ForkSort.NEWEST}.
*/
public PagedIterable<GHRepository> listForks() {
return listForks(null);
}
/**
* Lists all the direct forks of this repository, sorted by the given sort order.
* @param sort the sort order. If null, defaults to github api default,
* currently {@link ForkSort#NEWEST ForkSort.NEWEST}.
*/
public PagedIterable<GHRepository> listForks(final ForkSort sort) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> iterator() {
String sortParam = "";
if (sort != null) {
sortParam = "?sort=" + sort.toString().toLowerCase(Locale.ENGLISH);
}
return new PagedIterator<GHRepository>(root.retrieve().asIterator(getApiTailUrl("forks" + sortParam), GHRepository[].class)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page) {
c.wrap(root);
}
}
};
}
};
}
/** /**
* Forks this repository as your repository. * Forks this repository as your repository.
* *
@@ -597,15 +665,11 @@ public class GHRepository extends GHObject {
* Retrieves the currently configured hooks. * Retrieves the currently configured hooks.
*/ */
public List<GHHook> getHooks() throws IOException { public List<GHHook> getHooks() throws IOException {
List<GHHook> list = new ArrayList<GHHook>(Arrays.asList( return GHHooks.repoContext(this, owner).getHooks();
root.retrieve().to(getApiTailUrl("hooks"), GHHook[].class)));
for (GHHook h : list)
h.wrap(this);
return list;
} }
public GHHook getHook(int id) throws IOException { public GHHook getHook(int id) throws IOException {
return root.retrieve().to(getApiTailUrl("hooks/" + id), GHHook.class).wrap(this); return GHHooks.repoContext(this, owner).getHook(id);
} }
/** /**
@@ -626,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());
} }
/** /**
@@ -649,7 +729,7 @@ public class GHRepository extends GHObject {
} }
/** /**
* Retrive a ref of the given type for the current GitHub repository. * Retrive a ref of the given type for the current GitHub repository.
* *
* @param refName * @param refName
* eg: heads/branch * eg: heads/branch
* @return refs matching the request type * @return refs matching the request type
@@ -662,7 +742,7 @@ public class GHRepository extends GHObject {
} }
/** /**
* Retrive a tree of the given type for the current GitHub repository. * Retrive a tree of the given type for the current GitHub repository.
* *
* @param sha - sha number or branch name ex: "master" * @param sha - sha number or branch name ex: "master"
* @return refs matching the request type * @return refs matching the request type
* @throws IOException * @throws IOException
@@ -673,11 +753,11 @@ public class GHRepository extends GHObject {
String url = String.format("/repos/%s/%s/git/trees/%s", owner.login, name, sha); String url = String.format("/repos/%s/%s/git/trees/%s", owner.login, name, sha);
return root.retrieve().to(url, GHTree.class).wrap(root); return root.retrieve().to(url, GHTree.class).wrap(root);
} }
/** /**
* Retrieves the tree for the current GitHub repository, recursively as described in here: * Retrieves the tree for the current GitHub repository, recursively as described in here:
* https://developer.github.com/v3/git/trees/#get-a-tree-recursively * https://developer.github.com/v3/git/trees/#get-a-tree-recursively
* *
* @param sha - sha number or branch name ex: "master" * @param sha - sha number or branch name ex: "master"
* @param recursive use 1 * @param recursive use 1
* @throws IOException * @throws IOException
@@ -774,7 +854,7 @@ public class GHRepository extends GHObject {
* @param description * @param description
* Optional short description. * Optional short description.
* @param context * @param context
* Optinal commit status context. * Optinal commit status context.
*/ */
public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description, String context) throws IOException { public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description, String context) throws IOException {
return new Requester(root) return new Requester(root)
@@ -784,7 +864,7 @@ public class GHRepository extends GHObject {
.with("context", context) .with("context", context)
.to(String.format("/repos/%s/%s/statuses/%s",owner.login,this.name,sha1),GHCommitStatus.class).wrapUp(root); .to(String.format("/repos/%s/%s/statuses/%s",owner.login,this.name,sha1),GHCommitStatus.class).wrapUp(root);
} }
/** /**
* @see #createCommitStatus(String, GHCommitState,String,String,String) * @see #createCommitStatus(String, GHCommitState,String,String,String)
*/ */
@@ -858,10 +938,10 @@ public class GHRepository extends GHObject {
} }
/** /**
* *
* See https://api.github.com/hooks for possible names and their configuration scheme. * See https://api.github.com/hooks for possible names and their configuration scheme.
* TODO: produce type-safe binding * TODO: produce type-safe binding
* *
* @param name * @param name
* Type of the hook to be created. See https://api.github.com/hooks for possible names. * Type of the hook to be created. See https://api.github.com/hooks for possible names.
* @param config * @param config
@@ -870,21 +950,9 @@ public class GHRepository extends GHObject {
* Can be null. Types of events to hook into. * Can be null. Types of events to hook into.
*/ */
public GHHook createHook(String name, Map<String,String> config, Collection<GHEvent> events, boolean active) throws IOException { public GHHook createHook(String name, Map<String,String> config, Collection<GHEvent> events, boolean active) throws IOException {
List<String> ea = null; return GHHooks.repoContext(this, owner).createHook(name, config, events, active);
if (events!=null) {
ea = new ArrayList<String>();
for (GHEvent e : events)
ea.add(e.name().toLowerCase(Locale.ENGLISH));
}
return new Requester(root)
.with("name", name)
.with("active", active)
._with("config", config)
._with("events",ea)
.to(String.format("/repos/%s/%s/hooks",owner.login,this.name),GHHook.class).wrap(this);
} }
public GHHook createWebHook(URL url, Collection<GHEvent> events) throws IOException { public GHHook createWebHook(URL url, Collection<GHEvent> events) throws IOException {
return createHook("web",Collections.singletonMap("url",url.toExternalForm()),events,true); return createHook("web",Collections.singletonMap("url",url.toExternalForm()),events,true);
} }
@@ -909,10 +977,12 @@ public class GHRepository extends GHObject {
/** /**
* Returns a set that represents the post-commit hook URLs. * Returns a set that represents the post-commit hook URLs.
* The returned set is live, and changes made to them are reflected to GitHub. * The returned set is live, and changes made to them are reflected to GitHub.
* *
* @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;
} }
@@ -920,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 {
@@ -1046,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);
@@ -1064,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 {
@@ -1098,19 +1179,19 @@ public class GHRepository extends GHObject {
return new Requester(root) return new Requester(root)
.with("title", title).with("description", description).method("POST").to(getApiTailUrl("milestones"), GHMilestone.class).wrap(this); .with("title", title).with("description", description).method("POST").to(getApiTailUrl("milestones"), GHMilestone.class).wrap(this);
} }
public GHDeployKey addDeployKey(String title,String key) throws IOException { public GHDeployKey addDeployKey(String title,String key) throws IOException {
return new Requester(root) return new Requester(root)
.with("title", title).with("key", key).method("POST").to(getApiTailUrl("keys"), GHDeployKey.class).wrap(this); .with("title", title).with("key", key).method("POST").to(getApiTailUrl("keys"), GHDeployKey.class).wrap(this);
} }
public List<GHDeployKey> getDeployKeys() throws IOException{ public List<GHDeployKey> getDeployKeys() throws IOException{
List<GHDeployKey> list = new ArrayList<GHDeployKey>(Arrays.asList( List<GHDeployKey> list = new ArrayList<GHDeployKey>(Arrays.asList(
root.retrieve().to(getApiTailUrl("keys"), GHDeployKey[].class))); root.retrieve().to(getApiTailUrl("keys"), GHDeployKey[].class)));
for (GHDeployKey h : list) for (GHDeployKey h : list)
h.wrap(this); h.wrap(this);
return list; return list;
} }
/** /**
@@ -1119,7 +1200,7 @@ public class GHRepository extends GHObject {
* @return * @return
* {@link GHRepository} that points to the root repository where this repository is forked * {@link GHRepository} that points to the root repository where this repository is forked
* (indirectly or directly) from. Otherwise null. * (indirectly or directly) from. Otherwise null.
* @see #getParent() * @see #getParent()
*/ */
public GHRepository getSource() throws IOException { public GHRepository getSource() throws IOException {
if (source == null) return null; if (source == null) return null;
@@ -1136,7 +1217,7 @@ public class GHRepository extends GHObject {
* @return * @return
* {@link GHRepository} that points to the repository where this repository is forked * {@link GHRepository} that points to the repository where this repository is forked
* directly from. Otherwise null. * directly from. Otherwise null.
* @see #getSource() * @see #getSource()
*/ */
public GHRepository getParent() throws IOException { public GHRepository getParent() throws IOException {
if (parent == null) return null; if (parent == null) return null;
@@ -1144,7 +1225,7 @@ public class GHRepository extends GHObject {
parent = root.getRepository(parent.getFullName()); parent = root.getRepository(parent.getFullName());
return parent; return parent;
} }
/** /**
* Subscribes to this repository to get notifications. * Subscribes to this repository to get notifications.
*/ */
@@ -1162,7 +1243,7 @@ public class GHRepository extends GHObject {
*/ */
public GHSubscription getSubscription() throws IOException { public GHSubscription getSubscription() throws IOException {
try { try {
return new Requester(root).to(getApiTailUrl("subscription"), GHSubscription.class).wrapUp(this); return root.retrieve().to(getApiTailUrl("subscription"), GHSubscription.class).wrapUp(this);
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
return null; return null;
} }
@@ -1188,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

@@ -45,13 +45,16 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TimeZone; import java.util.TimeZone;
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.
@@ -127,16 +130,18 @@ 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;
} }
} }
this.rateLimitHandler = rateLimitHandler;
if (login==null && encodedAuthorization!=null) if (login==null && encodedAuthorization!=null)
login = getMyself().getLogin(); login = getMyself().getLogin();
this.login = login; this.login = login;
this.rateLimitHandler = rateLimitHandler;
} }
/** /**
@@ -195,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.
@@ -247,6 +261,7 @@ public class GitHub {
// see issue #78 // see issue #78
GHRateLimit r = new GHRateLimit(); GHRateLimit r = new GHRateLimit();
r.limit = r.remaining = 1000000; r.limit = r.remaining = 1000000;
r.reset = new Date(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(1));
return r; return r;
} }
} }
@@ -436,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,9 @@ 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 org.kohsuke.github.GitHub.*; import static org.kohsuke.github.GitHub.*;
/** /**
@@ -61,6 +64,8 @@ import static org.kohsuke.github.GitHub.*;
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
class Requester { class Requester {
private static final List<String> METHODS_WITHOUT_BODY = asList("GET", "DELETE");
private final GitHub root; private final GitHub root;
private final List<Entry> args = new ArrayList<Entry>(); private final List<Entry> args = new ArrayList<Entry>();
private final Map<String,String> headers = new LinkedHashMap<String, String>(); private final Map<String,String> headers = new LinkedHashMap<String, String>();
@@ -116,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;
} }
@@ -140,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;
} }
@@ -208,7 +213,7 @@ class Requester {
private <T> T _to(String tailApiUrl, Class<T> type, T instance) throws IOException { private <T> T _to(String tailApiUrl, Class<T> type, T instance) throws IOException {
while (true) {// loop while API rate limit is hit while (true) {// loop while API rate limit is hit
if (method.equals("GET") && !args.isEmpty()) { if (METHODS_WITHOUT_BODY.contains(method) && !args.isEmpty()) {
StringBuilder qs=new StringBuilder(); StringBuilder qs=new StringBuilder();
for (Entry arg : args) { for (Entry arg : args) {
qs.append(qs.length()==0 ? '?' : '&'); qs.append(qs.length()==0 ? '?' : '&');
@@ -254,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 {
@@ -268,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) {
@@ -287,7 +297,7 @@ class Requester {
* Set up the request parameters or POST payload. * Set up the request parameters or POST payload.
*/ */
private void buildRequest() throws IOException { private void buildRequest() throws IOException {
if (!method.equals("GET")) { if (isMethodWithBody()) {
uc.setDoOutput(true); uc.setDoOutput(true);
uc.setRequestProperty("Content-type", contentType); uc.setRequestProperty("Content-type", contentType);
@@ -311,28 +321,35 @@ class Requester {
} }
} }
private boolean isMethodWithBody() {
return !METHODS_WITHOUT_BODY.contains(method);
}
/** /**
* Loads pagenated resources. * Loads pagenated resources.
* *
* 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>() {
/** /**
@@ -500,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
@@ -351,7 +352,7 @@ public class AppTest extends AbstractGitHubApiTestBase {
sha1.add(c.getSHA1()); sha1.add(c.getSHA1());
} }
assertEquals("1cccddb22e305397151b2b7b87b4b47d74ca337b",sha1.get(0)); assertEquals("1cccddb22e305397151b2b7b87b4b47d74ca337b",sha1.get(0));
assertEquals(29,sha1.size()); assertEquals(29, sha1.size());
} }
@Test @Test
@@ -618,7 +619,7 @@ public class AppTest extends AbstractGitHubApiTestBase {
@Test @Test
public void testAddDeployKey() throws IOException { public void testAddDeployKey() throws IOException {
GHRepository myRepository = Iterables.get(gitHub.getMyself().getRepositories().values(),0); GHRepository myRepository = getTestRepository();
final GHDeployKey newDeployKey = myRepository.addDeployKey("test", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUt0RAycC5cS42JKh6SecfFZBR1RrF+2hYMctz4mk74/arBE+wFb7fnSHGzdGKX2h5CFOWODifRCJVhB7hlVxodxe+QkQQYAEL/x1WVCJnGgTGQGOrhOMj95V3UE5pQKhsKD608C+u5tSofcWXLToP1/wZ7U4/AHjqYi08OLsWToHCax55TZkvdt2jo0hbIoYU+XI9Q8Uv4ONDN1oabiOdgeKi8+crvHAuvNleiBhWVBzFh8KdfzaH5uNdw7ihhFjEd1vzqACsjCINCjdMfzl6jD9ExuWuE92nZJnucls2cEoNC6k2aPmrZDg9hA32FXVpyseY+bDUWFU6LO2LG6PB kohsuke@atlas"); final GHDeployKey newDeployKey = myRepository.addDeployKey("test", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUt0RAycC5cS42JKh6SecfFZBR1RrF+2hYMctz4mk74/arBE+wFb7fnSHGzdGKX2h5CFOWODifRCJVhB7hlVxodxe+QkQQYAEL/x1WVCJnGgTGQGOrhOMj95V3UE5pQKhsKD608C+u5tSofcWXLToP1/wZ7U4/AHjqYi08OLsWToHCax55TZkvdt2jo0hbIoYU+XI9Q8Uv4ONDN1oabiOdgeKi8+crvHAuvNleiBhWVBzFh8KdfzaH5uNdw7ihhFjEd1vzqACsjCINCjdMfzl6jD9ExuWuE92nZJnucls2cEoNC6k2aPmrZDg9hA32FXVpyseY+bDUWFU6LO2LG6PB kohsuke@atlas");
try { try {
assertNotNull(newDeployKey.getId()); assertNotNull(newDeployKey.getId());
@@ -636,7 +637,7 @@ public class AppTest extends AbstractGitHubApiTestBase {
@Test @Test
public void testCommitStatusContext() throws IOException { public void testCommitStatusContext() throws IOException {
GHRepository myRepository = Iterables.get(gitHub.getMyself().getRepositories().values(), 0); GHRepository myRepository = getTestRepository();
GHRef masterRef = myRepository.getRef("heads/master"); GHRef masterRef = myRepository.getRef("heads/master");
GHCommitStatus commitStatus = myRepository.createCommitStatus(masterRef.getObject().getSha(), GHCommitState.SUCCESS, "http://www.example.com", "test", "test/context"); GHCommitStatus commitStatus = myRepository.createCommitStatus(masterRef.getObject().getSha(), GHCommitState.SUCCESS, "http://www.example.com", "test", "test/context");
assertEquals("test/context", commitStatus.getContext()); assertEquals("test/context", commitStatus.getContext());

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

@@ -1,34 +1,41 @@
package org.kohsuke.github; package org.kohsuke.github;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import junit.framework.TestCase; import org.junit.Test;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
/** /**
* Unit test for {@link GitHub}. * Unit test for {@link GitHub}.
*/ */
public class GitHubTest extends TestCase { public class GitHubTest {
@Test
public void testGitHubServerWithHttp() throws Exception { public void testGitHubServerWithHttp() throws Exception {
GitHub hub = GitHub.connectToEnterprise("http://enterprise.kohsuke.org/api/v3", "bogus","bogus"); GitHub hub = GitHub.connectToEnterprise("http://enterprise.kohsuke.org/api/v3", "bogus","bogus");
assertEquals("http://enterprise.kohsuke.org/api/v3/test", hub.getApiURL("/test").toString()); assertEquals("http://enterprise.kohsuke.org/api/v3/test", hub.getApiURL("/test").toString());
} }
@Test
public void testGitHubServerWithHttps() throws Exception { public void testGitHubServerWithHttps() throws Exception {
GitHub hub = GitHub.connectToEnterprise("https://enterprise.kohsuke.org/api/v3", "bogus","bogus"); GitHub hub = GitHub.connectToEnterprise("https://enterprise.kohsuke.org/api/v3", "bogus","bogus");
assertEquals("https://enterprise.kohsuke.org/api/v3/test", hub.getApiURL("/test").toString()); assertEquals("https://enterprise.kohsuke.org/api/v3/test", hub.getApiURL("/test").toString());
} }
@Test
public void testGitHubServerWithoutServer() throws Exception { public void testGitHubServerWithoutServer() throws Exception {
GitHub hub = GitHub.connectUsingPassword("kohsuke", "bogus"); GitHub hub = GitHub.connectUsingPassword("kohsuke", "bogus");
assertEquals("https://api.github.com/test", hub.getApiURL("/test").toString()); assertEquals("https://api.github.com/test", hub.getApiURL("/test").toString());
} }
@Test
public void testGitHubBuilderFromEnvironment() throws IOException { public void testGitHubBuilderFromEnvironment() throws IOException {
Map<String, String>props = new HashMap<String, String>(); Map<String, String>props = new HashMap<String, String>();
@@ -86,7 +93,7 @@ public class GitHubTest extends TestCase {
e1.printStackTrace(); e1.printStackTrace();
} }
} }
@Test
public void testGitHubBuilderFromCustomEnvironment() throws IOException { public void testGitHubBuilderFromCustomEnvironment() throws IOException {
Map<String, String> props = new HashMap<String, String>(); Map<String, String> props = new HashMap<String, String>();
@@ -105,4 +112,18 @@ public class GitHubTest extends TestCase {
assertEquals("bogusEndpoint", builder.endpoint); assertEquals("bogusEndpoint", builder.endpoint);
} }
@Test
public void testGitHubEnterpriseDoesNotHaveRateLimit() throws IOException {
GitHub github = spy(new GitHubBuilder().build());
when(github.retrieve()).thenThrow(FileNotFoundException.class);
GHRateLimit rateLimit = github.getRateLimit();
assertThat(rateLimit.getResetDate(), notNullValue());
}
@Test
public void testGitHubIsApiUrlValid() throws IOException {
GitHub github = GitHub.connectAnonymously();
github.checkApiUrlValidity();
}
} }

View File

@@ -5,6 +5,7 @@ import org.junit.Test;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.List;
/** /**
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
@@ -18,7 +19,58 @@ public class PullRequestTest extends AbstractGitHubApiTestBase {
assertEquals(name, p.getTitle()); assertEquals(name, p.getTitle());
} }
@Test // Requires push access to the test repo to pass @Test
public void createPullRequestComment() throws Exception {
String name = rnd.next();
GHPullRequest p = getRepository().createPullRequest(name, "stable", "master", "## test");
p.comment("Some comment");
}
@Test
public void testPullRequestReviewComments() throws Exception {
String name = rnd.next();
GHPullRequest p = getRepository().createPullRequest(name, "stable", "master", "## test");
System.out.println(p.getUrl());
assertTrue(p.listReviewComments().asList().isEmpty());
p.createReviewComment("Sample review comment", p.getHead().getSha(), "cli/pom.xml", 5);
List<GHPullRequestReviewComment> comments = p.listReviewComments().asList();
assertEquals(1, comments.size());
GHPullRequestReviewComment comment = comments.get(0);
assertEquals("Sample review comment", comment.getBody());
comment.update("Updated review comment");
comments = p.listReviewComments().asList();
assertEquals(1, comments.size());
comment = comments.get(0);
assertEquals("Updated review comment", comment.getBody());
comment.delete();
comments = p.listReviewComments().asList();
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
// Requires push access to the test repo to pass
public void setLabels() throws Exception { public void setLabels() throws Exception {
GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test"); GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test");
String label = rnd.next(); String label = rnd.next();
@@ -29,7 +81,8 @@ public class PullRequestTest extends AbstractGitHubApiTestBase {
assertEquals(label, labels.iterator().next().getName()); assertEquals(label, labels.iterator().next().getName());
} }
@Test // Requires push access to the test repo to pass @Test
// Requires push access to the test repo to pass
public void setAssignee() throws Exception { public void setAssignee() throws Exception {
GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test"); GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test");
GHMyself user = gitHub.getMyself(); GHMyself user = gitHub.getMyself();
@@ -49,7 +102,7 @@ public class PullRequestTest extends AbstractGitHubApiTestBase {
PagedIterable<GHPullRequest> ghPullRequests = getRepository().listPullRequests(GHIssueState.OPEN); PagedIterable<GHPullRequest> ghPullRequests = getRepository().listPullRequests(GHIssueState.OPEN);
for (GHPullRequest pr : ghPullRequests) { for (GHPullRequest pr : ghPullRequests) {
assertNotNull(pr.getUser().root); assertNotNull(pr.getUser().root);
assertFalse(pr.getMergeable()); pr.getMergeable();
assertNotNull(pr.getUser().root); assertNotNull(pr.getUser().root);
} }
} }