Compare commits

...

81 Commits

Author SHA1 Message Date
Kohsuke Kawaguchi
d6722266f5 [maven-release-plugin] prepare release github-api-1.63 2015-03-02 09:10:49 -08:00
Kohsuke Kawaguchi
11566891dc Restored backward compatibility
The signature of the method can change for the future, but it still has
to return Label instances for older binaries
2015-03-02 08:33:00 -08:00
Kohsuke Kawaguchi
9aaf69cc9a Added maling list 2015-03-02 08:14:15 -08:00
Kohsuke Kawaguchi
aa43e265b7 [maven-release-plugin] prepare for next development iteration 2015-02-15 09:12:26 -08:00
Kohsuke Kawaguchi
67280951ff [maven-release-plugin] prepare release github-api-1.62 2015-02-15 09:12:23 -08:00
Kohsuke Kawaguchi
c3a9f6f9f5 Fixed NPE.
issue #152
2015-02-15 09:06:04 -08:00
Kohsuke Kawaguchi
e631e46dd1 Exposed this method.
I'm generally against having these inter-object short cut methods
(in this case it's getOwner().getName() but oh well.)

Fixes issue #149
2015-02-15 08:57:36 -08:00
Kohsuke Kawaguchi
15163ffde0 Avoid multiple concurrent population 2015-02-15 08:56:57 -08:00
Kohsuke Kawaguchi
b898284821 Mentions thread-safety and state the goal.
Most of the objects are effectively immutable, so this should be an easy goal

Fixes issue #148.
2015-02-15 08:56:29 -08:00
Kohsuke Kawaguchi
3bb7eb2e03 Added API to list contributors 2015-02-15 08:50:55 -08:00
Kohsuke Kawaguchi
11fcb9d456 Report the repository the push happened to
Fixes issue #144.
2015-02-15 08:42:32 -08:00
Kohsuke Kawaguchi
29f826448a Added a convenience method.
See: issue #134
2015-02-15 08:35:31 -08:00
Kohsuke Kawaguchi
a8cf4a7120 Added watch API support.
Fixes issue #130
2015-02-15 08:31:57 -08:00
Kohsuke Kawaguchi
60dce94a47 renamed to created RepositoryTest 2015-02-15 08:25:49 -08:00
Kohsuke Kawaguchi
c965b9cc24 follow up fix to the GHRepository.getApiTailUrl() change 2015-02-15 08:20:28 -08:00
Kohsuke Kawaguchi
762a32eb6d Added repository watch listing 2015-02-15 07:45:11 -08:00
Kohsuke Kawaguchi
541dac1aee Use getApiTailUrl for consistency 2015-02-15 07:35:02 -08:00
Kohsuke Kawaguchi
e2e2329301 Noting issue #60 that this method can return null 2015-02-15 07:16:18 -08:00
Kohsuke Kawaguchi
9afad71b0f Newly created user object resets root to null.
Fixes issue #111.
Test case from KostyaSha
2015-02-15 07:13:33 -08:00
Kohsuke Kawaguchi
7bbe0f7e8a Allow the client to explicitly control proxy
Fixes issue #109.
2015-02-15 07:02:50 -08:00
Kohsuke Kawaguchi
d90adfa98e Implemented label CRUD operations on GHRepository
Fixes issue #105
2015-02-15 06:55:35 -08:00
Kohsuke Kawaguchi
1dbcc4b776 Fixed the getReadme() method.
It was calling the wrong endpoint.
Fixed issue #99.
2015-02-15 06:31:22 -08:00
Kohsuke Kawaguchi
18696fca2d [maven-release-plugin] prepare for next development iteration 2015-02-14 10:28:55 -08:00
Kohsuke Kawaguchi
c40100b6da [maven-release-plugin] prepare release github-api-1.61 2015-02-14 10:28:51 -08:00
Kohsuke Kawaguchi
6396818740 MRELEASE-812 botched 1.60 2015-02-14 10:27:13 -08:00
Kohsuke Kawaguchi
6df5a0d47b Added a test 2015-02-14 10:13:25 -08:00
Kohsuke Kawaguchi
15c18c5547 Improved the search API 2015-02-14 10:08:46 -08:00
Kohsuke Kawaguchi
4b6981c2e7 Added issue-search capability 2015-02-14 09:53:29 -08:00
Kohsuke Kawaguchi
1b4025300c Merge remote-tracking branch 'origin/master' 2015-02-14 09:32:53 -08:00
Kohsuke Kawaguchi
983c871bff More compilation error fix 2015-02-14 09:30:50 -08:00
Kohsuke Kawaguchi
609f532f8c Merge pull request #143 2015-02-14 08:29:09 -08:00
Kohsuke Kawaguchi
c6fc03c73a In this library domain objects should be immutable. 2015-02-14 08:28:55 -08:00
Kohsuke Kawaguchi
b6e48cc4f9 Use GHObject as much as we can 2015-02-14 08:27:20 -08:00
Kohsuke Kawaguchi
50f43cc178 Inserted backward compatibility methods 2015-02-14 08:26:49 -08:00
Kohsuke Kawaguchi
f421067a0d Looks like Windows line ends have crept in. 2015-02-14 07:01:32 -08:00
Kohsuke Kawaguchi
edd9a2d5b6 Using newly added GHObject in more places. 2015-02-14 06:59:46 -08:00
Kohsuke Kawaguchi
41e0329f55 doc improvement 2015-02-14 06:52:48 -08:00
Kohsuke Kawaguchi
21ea916e0d Pull request #143 introduced wrong file permissions 2015-02-14 06:48:56 -08:00
Kohsuke Kawaguchi
3b6ca3020e Pull request #143 introduced wrong file permissions 2015-02-14 06:47:52 -08:00
Kohsuke Kawaguchi
3737845b78 Merge pull request #143 2015-02-14 06:47:26 -08:00
Kohsuke Kawaguchi
a30c78cd12 restored backward compatibility in the public API 2015-02-14 06:46:27 -08:00
Kohsuke Kawaguchi
f8fba41a30 Merge pull request #141 from alvaro1728/master
Trivial change to enable creating/updating binary content (files).
2015-02-14 09:42:55 -05:00
Kohsuke Kawaguchi
052902fb49 Merge pull request #146 2015-02-14 06:41:06 -08:00
Surya Gaddipati
58143c26bc Use GHCommitState for deployment status state 2015-01-12 10:04:01 -06:00
Surya Gaddipati
5d83894056 Add method for listing deployments 2015-01-02 16:46:56 -06:00
Rob Schoening
e35667525f fix #145 GHTeam.getMembers() does not page properly 2014-12-28 15:47:57 -08:00
Surya Gaddipati
2f318152d8 Complete api implementation for setting/retriving deployment status on a deployment 2014-12-20 17:09:59 -06:00
Surya Gaddipati
bc518a9ae8 Complete implementation of create deployment api 2014-12-20 11:52:49 -06:00
Kohsuke Kawaguchi
425ae2d536 Merge pull request #142 from suryagaddipati/master
Add code for creating deployments for a repo
2014-12-19 11:45:15 -08:00
Kohsuke Kawaguchi
a6cacd4aba Merge pull request #137 from simonecarriero/master
added 'diverged' constant to GHCompare.Status enum
2014-12-19 11:44:10 -08:00
Kohsuke Kawaguchi
5a7083537c Merge pull request #136 from rtyley/page-team-repositories
Add paging support for Team's Repositories
2014-12-19 11:43:56 -08:00
Surya Gaddipati
e15f7a59fd Merge pull request #139 from farmdawgnation/mocking-scope
Put mockito in the test scope.
2014-12-19 12:53:15 -06:00
Surya Gaddipati
a2fa526aa0 Add code for creating deployments for a repo 2014-12-19 12:47:00 -06:00
mendeza
7e959d6a87 Added binary content support - without tabs. 2014-12-18 21:15:29 -08:00
mendeza
5121fe1cbf Added binary content support. 2014-12-18 21:03:28 -08:00
Matt Farmer
3c3d4fc151 Put mockito in the test scope. 2014-11-16 15:31:04 -05:00
Simone Carriero
a7f75c9a6c added 'diverged' constant to GHCompare.Status enum 2014-11-06 12:18:16 +01:00
Roberto Tyley
e7262b8fbe Add paging support for Team's Repositories
The team repositories endpoint does do paging, so gotta support that.
2014-11-06 09:40:37 +00:00
Kohsuke Kawaguchi
af3099c526 [maven-release-plugin] prepare for next development iteration 2014-10-08 12:17:53 -07:00
Kohsuke Kawaguchi
2b9d47cea8 [maven-release-plugin] prepare release github-api-1.59 2014-10-08 12:17:49 -07:00
Kohsuke Kawaguchi
5db90d3fc4 This test is invalid if ~/.github file exists, which is quite common 2014-10-08 12:15:32 -07:00
Kohsuke Kawaguchi
372d5ff758 Fixed a test regression
Presumably due to the behaviour change on GitHub API?
2014-10-08 12:07:09 -07:00
Kohsuke Kawaguchi
ebf39eaea1 [INFRA-142]
Reworked version of https://github.com/kohsuke/github-api/pull/133/files
2014-10-08 11:29:17 -07:00
Michael O'Cleirigh
556786f2e1 Merge pull request #131 from mocleiri/resolve-credentials-from-environment
Modify GitHubBuilder to resolve user credentials from the system environ...
2014-09-30 14:07:35 -04:00
Michael O'Cleirigh
0f64994537 Make Github.connect() fail if no credentials are setup
With the previous change if no credentials were defined Github.connect() would
fall back on an anonymous connection.

This commit changes the behaviour back to what it was before so that if there
are no credentials defined in the ~/.github file and no credentials defined
in the environment an IOException is thrown to alert the method caller.

The caller can call Github.connectAnonymously() if that scenario is allowed.

This should handle most cases unless callers are depending on the
FileNotFoundException being specifically thrown instead of an IOException.
2014-09-30 13:58:06 -04:00
Michael O'Cleirigh
ac64c2022b Merge pull request #132 from mocleiri/add-getFiles-method-to-GHCompare
Add GHCompare.getFiles() method to be able to see the precise files chan...
2014-09-30 12:03:54 -04:00
Michael O'Cleirigh
9802132b6f Add GHCompare.getFiles() method to be able to see the precise files changed.
There is a file field inside of GHCompare but no getter to extract the values
for analysis.

There are contents in that field so I've added a new get method so that they
can be extracted.
2014-09-30 11:51:57 -04:00
Michael O'Cleirigh
4d6c5c14f1 Modify GitHubBuilder to resolve user credentials from the system environment
Using the Jenkins EnvInject or Credentials Binding Plugins its possible to
pass credentials as Environment Variables.

Its useful for Github.connect() to be able to directly read the values of the
'login', 'password' and 'oauth' properties directly from the environment.

This commit modifies the base Github.connect() method to resolve credentials
in two steps:

1. ~/.github credentials file if it exists.
2. login, password or oauth variables from the environment

A further fromEnvironment() method is provided to support
loading from non-standard variable names.

The old Github.connect() method would throw an IOException if the ~/.github file
did not exist.  Now it will fail silently instead dropping back to the anonymous
users access level.

Added new unit tests into GitHubTest.
2014-09-29 13:42:28 -04:00
Kohsuke Kawaguchi
d228a5fb93 Merge pull request #128 from ndeloof/patch-1
Update github scopes according to https://developer.github.com/v3/oauth/#scopes
2014-09-26 18:10:15 -07:00
Michael O'Cleirigh
7b46ef10c8 Merge pull request #129 from mocleiri/fix-pull-request-remote-repo-get-commit
Allow pullRequest.getHead().getRepository().getCommit(headSha1) to work
2014-09-26 15:14:25 -04:00
Michael O'Cleirigh
8eb9fba051 Allow pullRequest.getHead().getRepository().getCommit(headSha1) to work
The wrong .wrap method was used for pull requests initialized by state
(GHRepository.getPullReqests).

The wrong wrap call was introduced in 9fd34aec7f

This commit sets it back to the .wrapUp method which makes sure the pull request
substructure has the repo object set properly.

Without this change a NullPointerException is thrown on the last line of this
code because the repo object inside of the remoteRepository object is null:

GHRepository repo = github.getRepository(targetRepository);

List<GHPullRequest> openPullRequests = repo.getPullRequests(GHIssueState.OPEN);

for (GHPullRequest pullRequest : openPullRequests) {

    GHCommitPointer head = pullRequest.getHead();

	GHRepository remoteRepository = head.getRepository();

	String commitId = head.getSha();

	GHCommit headCommit = remoteRepository.getCommit(commitId);
2014-09-22 10:53:13 -04:00
Nicolas De loof
7b58182683 Update github scopes according to https://developer.github.com/v3/oauth/#scopes 2014-09-12 23:16:43 +02:00
Kohsuke Kawaguchi
95fbf9274b Merge pull request #124 from ohtake/connector
Allow to use custom HttpConnector when only OAuth token is given
2014-09-04 10:32:11 -07:00
Kohsuke Kawaguchi
09557dfa0f Merge pull request #123 from rtyley/use-issues-endpoints-for-pull-requests
Use issues endpoints for pull requests
2014-09-04 10:31:25 -07:00
Kohsuke Kawaguchi
4029fcc1ca Merge pull request #122 from tbruyelle/browserDownloadUrl
Add missing field browser_download_url in GHAsset
2014-09-04 10:29:23 -07:00
OHTAKE Tomohiro
d6627b1e34 Use custom HttpConnector when only OAuth token is given 2014-09-04 13:18:35 +09:00
OHTAKE Tomohiro
86d75fd767 Introduce GitHubBuilder for flexible GitHub instance creation 2014-09-04 13:17:43 +09:00
Roberto Tyley
e2220bb3b3 Fix setting labels and assignee on PullRequests
Setting labels and assignee on Pull requests failed silently, because
the API endpoint being hit contained '/pulls/' rather than '/issues/'.

"Every pull request is an issue, but not every issue is a pull request.
For this reason, “shared” actions for both features, like manipulating
assignees, labels and milestones, are provided within the Issues API."

https://developer.github.com/v3/pulls/#labels-assignees-and-milestones
2014-09-03 23:34:58 +01:00
Roberto Tyley
1a9b8bd1da Separate out clean-up of Pull requests created during test
If the test assertion fails, we want the pull-request to be closed anyway.
You can't have more than one pull-request merging a given branch into
another, so leaving the PR hanging will cause subsequent test runs to fail
in setup.
2014-09-03 23:18:22 +01:00
Thomas Bruyelle
9eda2d3f77 Add missing field browser_download_url in GHAsset 2014-09-03 22:01:43 +02:00
Kohsuke Kawaguchi
e6d59df705 [maven-release-plugin] prepare for next development iteration 2014-08-30 14:15:29 -07:00
43 changed files with 1535 additions and 488 deletions

19
pom.xml
View File

@@ -3,11 +3,11 @@
<parent>
<groupId>org.kohsuke</groupId>
<artifactId>pom</artifactId>
<version>10</version>
<version>12</version>
</parent>
<artifactId>github-api</artifactId>
<version>1.58</version>
<version>1.63</version>
<name>GitHub API for Java</name>
<url>http://github-api.kohsuke.org/</url>
<description>GitHub API for Java</description>
@@ -16,7 +16,7 @@
<connection>scm:git:git@github.com/kohsuke/${project.artifactId}.git</connection>
<developerConnection>scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git</developerConnection>
<url>http://${project.artifactId}.kohsuke.org/</url>
<tag>github-api-1.58</tag>
<tag>github-api-1.63</tag>
</scm>
<distributionManagement>
@@ -35,7 +35,7 @@
<plugin>
<groupId>com.infradna.tool</groupId>
<artifactId>bridge-method-injector</artifactId>
<version>1.12</version>
<version>1.14</version>
<executions>
<execution>
<goals>
@@ -77,7 +77,7 @@
<dependency>
<groupId>com.infradna.tool</groupId>
<artifactId>bridge-method-annotation</artifactId>
<version>1.12</version>
<version>1.14</version>
</dependency>
<dependency>
<groupId>org.kohsuke.stapler</groupId>
@@ -107,6 +107,7 @@
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
@@ -138,4 +139,12 @@
<distribution>repo</distribution>
</license>
</licenses>
<mailingLists>
<mailingList>
<name>User List</name>
<post>github-api@googlegroups.com</post>
<archive>https://groups.google.com/forum/#!forum/github-api</archive>
</mailingList>
</mailingLists>
</project>

View File

@@ -1,26 +1,22 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Date;
/**
* Asset in a release.
*
* @see GHRelease#getAssets()
*/
public class GHAsset {
public class GHAsset extends GHObject {
GitHub root;
GHRepository owner;
private String url;
private String id;
private String name;
private String label;
private String state;
private String content_type;
private long size;
private long download_count;
private Date created_at;
private Date updated_at;
private String browser_download_url;
public String getContentType() {
return content_type;
@@ -31,18 +27,10 @@ public class GHAsset {
this.content_type = contentType;
}
public Date getCreatedAt() {
return created_at;
}
public long getDownloadCount() {
return download_count;
}
public String getId() {
return id;
}
public String getLabel() {
return label;
}
@@ -72,12 +60,8 @@ public class GHAsset {
return state;
}
public Date getUpdatedAt() {
return updated_at;
}
public String getUrl() {
return url;
public String getBrowserDownloadUrl() {
return browser_download_url;
}
private void edit(String key, Object value) throws IOException {

View File

@@ -12,7 +12,7 @@ import java.util.List;
* @see GitHub#createToken(Collection, String, String)
* @see http://developer.github.com/v3/oauth/#create-a-new-authorization
*/
public class GHAuthorization {
public class GHAuthorization extends GHObject {
public static final String USER = "user";
public static final String USER_EMAIL = "user:email";
public static final String USER_FOLLOW = "user:follow";
@@ -22,26 +22,27 @@ public class GHAuthorization {
public static final String DELETE_REPO = "delete_repo";
public static final String NOTIFICATIONS = "notifications";
public static final String GIST = "gist";
public static final String READ_HOOK = "read:repo_hook";
public static final String WRITE_HOOK = "write:repo_hook";
public static final String AMIN_HOOK = "admin:repo_hook";
public static final String READ_ORG = "read:org";
public static final String WRITE_ORG = "write:org";
public static final String ADMIN_ORG = "admin:org";
public static final String READ_KEY = "read:public_key";
public static final String WRITE_KEY = "write:public_key";
public static final String ADMIN_KEY = "admin:public_key";
private GitHub root;
private int id;
private String url;
private List<String> scopes;
private String token;
private App app;
private String note;
private String note_url;
private String updated_at;
private String created_at;
public GitHub getRoot() {
return root;
}
public int getId() {
return id;
}
public List<String> getScopes() {
return scopes;
}
@@ -69,14 +70,6 @@ public class GHAuthorization {
public URL getNoteUrl(){
return GitHub.parseURL(note_url);
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public Date getUpdatedAt() {
return GitHub.parseDate(updated_at);
}
/*package*/ GHAuthorization wrap(GitHub root) {
this.root = root;

View File

@@ -12,13 +12,11 @@ import java.util.Date;
* @see GHCommit#listComments()
* @see GHCommit#createComment(String, String, Integer, Integer)
*/
public class GHCommitComment {
public class GHCommitComment extends GHObject {
private GHRepository owner;
String updated_at, created_at;
String body, url, html_url, commit_id;
String body, html_url, commit_id;
Integer line;
int id;
String path;
User user;
@@ -32,14 +30,6 @@ public class GHCommitComment {
return owner;
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public Date getUpdatedAt() {
return GitHub.parseDate(updated_at);
}
/**
* URL like 'https://github.com/kohsuke/sandbox-ant/commit/8ae38db0ea5837313ab5f39d43a6f73de3bd9000#commitcomment-1252827' to
* show this commit comment in a browser.
@@ -75,10 +65,6 @@ public class GHCommitComment {
return line!=null ? line : -1;
}
public int getId() {
return id;
}
/**
* Gets the user who put this comment.
*/

View File

@@ -10,12 +10,9 @@ import java.util.Date;
* @see GHRepository#getCommitStatus(String)
* @see GHCommit#getStatus()
*/
public class GHCommitStatus {
String created_at, updated_at;
public class GHCommitStatus extends GHObject {
String state;
String target_url,description;
int id;
String url;
String context;
GHUser creator;
@@ -27,14 +24,6 @@ public class GHCommitStatus {
return this;
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public Date getUpdatedAt() {
return GitHub.parseDate(updated_at);
}
public GHCommitState getState() {
for (GHCommitState s : GHCommitState.values()) {
if (s.name().equalsIgnoreCase(state))
@@ -56,17 +45,6 @@ public class GHCommitStatus {
return description;
}
public int getId() {
return id;
}
/**
* API URL of this commit status.
*/
public String getUrl() {
return url;
}
public GHUser getCreator() {
return creator;
}

View File

@@ -68,9 +68,12 @@ public class GHCompare {
public Commit[] getCommits() {
return commits;
}
public GHCommit.File[] getFiles() {
return files;
}
public GHCompare wrap(GHRepository owner) {
public GHCompare wrap(GHRepository owner) {
this.owner = owner;
for (Commit commit : commits) {
commit.wrapUp(owner);
@@ -145,6 +148,6 @@ public class GHCompare {
}
public static enum Status {
behind, ahead, identical
behind, ahead, identical, diverged
}
}

View File

@@ -129,11 +129,19 @@ public class GHContent {
}
public GHContentUpdateResponse update(String newContent, String commitMessage) throws IOException {
return update(newContent, commitMessage, null);
return update(newContent.getBytes(), commitMessage, null);
}
public GHContentUpdateResponse update(String newContent, String commitMessage, String branch) throws IOException {
String encodedContent = DatatypeConverter.printBase64Binary(newContent.getBytes());
return update(newContent.getBytes(), commitMessage, branch);
}
public GHContentUpdateResponse update(byte[] newContentBytes, String commitMessage) throws IOException {
return update(newContentBytes, commitMessage, null);
}
public GHContentUpdateResponse update(byte[] newContentBytes, String commitMessage, String branch) throws IOException {
String encodedContent = DatatypeConverter.printBase64Binary(newContentBytes);
Requester requester = new Requester(owner.root)
.with("path", path)

View File

@@ -0,0 +1,53 @@
package org.kohsuke.github;
import java.net.URL;
public class GHDeployment extends GHObject {
private GHRepository owner;
private GitHub root;
protected String sha;
protected String ref;
protected String task;
protected Object payload;
protected String environment;
protected String description;
protected String statuses_url;
protected String repository_url;
protected GHUser creator;
GHDeployment wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
if(creator != null) creator.wrapUp(root);
return this;
}
public URL getStatusesUrl() {
return GitHub.parseURL(statuses_url);
}
public URL getRepositoryUrl() {
return GitHub.parseURL(repository_url);
}
public String getTask() {
return task;
}
public String getPayload() {
return (String) payload;
}
public String getEnvironment() {
return environment;
}
public GHUser getCreator() {
return creator;
}
public String getRef() {
return ref;
}
public String getSha(){
return sha;
}
}

View File

@@ -0,0 +1,55 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.List;
//Based on https://developer.github.com/v3/repos/deployments/#create-a-deployment
public class GHDeploymentBuilder {
private final GHRepository repo;
private final Requester builder;
public GHDeploymentBuilder(GHRepository repo) {
this.repo = repo;
this.builder = new Requester(repo.root);
}
public GHDeploymentBuilder(GHRepository repo, String ref) {
this(repo);
ref(ref);
}
public GHDeploymentBuilder ref(String branch) {
builder.with("ref",branch);
return this;
}
public GHDeploymentBuilder task(String task) {
builder.with("task",task);
return this;
}
public GHDeploymentBuilder autoMerge(boolean autoMerge) {
builder.with("auto_merge",autoMerge);
return this;
}
public GHDeploymentBuilder requiredContexts(List<String> requiredContexts) {
builder.with("required_contexts",requiredContexts);
return this;
}
public GHDeploymentBuilder payload(String payload) {
builder.with("payload",payload);
return this;
}
public GHDeploymentBuilder environment(String environment) {
builder.with("environment",environment);
return this;
}
public GHDeploymentBuilder description(String description) {
builder.with("description",description);
return this;
}
public GHDeployment create() throws IOException {
return builder.to(repo.getApiTailUrl("deployments"),GHDeployment.class).wrap(repo);
}
}

View File

@@ -0,0 +1,8 @@
package org.kohsuke.github;
/**
* Represents the state of deployment
*/
public enum GHDeploymentState {
PENDING, SUCCESS, ERROR, FAILURE
}

View File

@@ -0,0 +1,36 @@
package org.kohsuke.github;
import java.net.URL;
public class GHDeploymentStatus extends GHObject {
private GHRepository owner;
private GitHub root;
protected GHUser creator;
protected String state;
protected String description;
protected String target_url;
protected String deployment_url;
protected String repository_url;
public GHDeploymentStatus wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
if(creator != null) creator.wrapUp(root);
return this;
}
public URL getTargetUrl() {
return GitHub.parseURL(target_url);
}
public URL getDeploymentUrl() {
return GitHub.parseURL(deployment_url);
}
public URL getRepositoryUrl() {
return GitHub.parseURL(repository_url);
}
public GHDeploymentState getState() {
return GHDeploymentState.valueOf(state.toUpperCase());
}
}

View File

@@ -0,0 +1,30 @@
package org.kohsuke.github;
import java.io.IOException;
public class GHDeploymentStatusBuilder {
private final Requester builder;
private GHRepository repo;
private int deploymentId;
public GHDeploymentStatusBuilder(GHRepository repo, int deploymentId, GHDeploymentState state) {
this.repo = repo;
this.deploymentId = deploymentId;
this.builder = new Requester(repo.root);
this.builder.with("state",state.toString().toLowerCase());
}
public GHDeploymentStatusBuilder description(String description) {
this.builder.with("description",description);
return this;
}
public GHDeploymentStatusBuilder targetUrl(String targetUrl) {
this.builder.with("target_url",targetUrl);
return this;
}
public GHDeploymentStatus create() throws IOException {
return builder.to(repo.getApiTailUrl("deployments")+"/"+deploymentId+"/statuses",GHDeploymentStatus.class).wrap(repo);
}
}

View File

@@ -120,6 +120,7 @@ public abstract class GHEventPayload {
private String ref;
private int size;
private List<PushCommit> commits;
private GHRepository repository;
/**
* The SHA of the HEAD commit on the repository
@@ -158,6 +159,16 @@ public abstract class GHEventPayload {
return commits;
}
public GHRepository getRepository() {
return repository;
}
@Override
void wrapUp(GitHub root) {
if (repository!=null)
repository.wrap(root);
}
/**
* Commit in a push
*/

View File

@@ -4,7 +4,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.IOException;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
@@ -16,17 +15,18 @@ import java.util.Map.Entry;
* @see GHUser#listGists()
* @see GitHub#getGist(String)
* @see GitHub#createGist()
* @see <a href="https://developer.github.com/v3/gists/">documentation</a>
*/
public class GHGist {
public class GHGist extends GHObject {
/*package almost final*/ GHUser owner;
/*package almost final*/ GitHub root;
private String url, forks_url, commits_url, id, git_pull_url, git_push_url, html_url;
private String forks_url, commits_url, id, git_pull_url, git_push_url, html_url;
@JsonProperty("public")
private boolean _public;
private String created_at, updated_at, description;
private String description;
private int comments;
@@ -41,13 +41,6 @@ public class GHGist {
return owner;
}
/**
* API URL of this gist, such as 'https://api.github.com/gists/12345'
*/
public String getUrl() {
return url;
}
public String getForksUrl() {
return forks_url;
}
@@ -56,13 +49,6 @@ public class GHGist {
return commits_url;
}
/**
* ID of this gist, such as '12345'
*/
public String getId() {
return id;
}
/**
* URL like https://gist.github.com/gists/12345.git
*/
@@ -82,14 +68,6 @@ public class GHGist {
return _public;
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public Date getUpdatedAt() {
return GitHub.parseDate(updated_at);
}
public String getDescription() {
return description;
}

View File

@@ -10,18 +10,17 @@ import java.util.Map;
/**
* @author Kohsuke Kawaguchi
*/
public class GHHook {
public class GHHook extends GHObject {
/**
* Repository that the hook belongs to.
*/
/*package*/ transient GHRepository repository;
String created_at, updated_at, name;
String name;
List<String> events;
boolean active;
Map<String,String> config;
int id;
/*package*/ GHHook wrap(GHRepository owner) {
this.repository = owner;
return this;
@@ -46,10 +45,6 @@ public class GHHook {
return Collections.unmodifiableMap(config);
}
public int getId() {
return id;
}
/**
* Deletes this hook.
*/

View File

@@ -37,8 +37,11 @@ import java.util.Locale;
*
* @author Eric Maupin
* @author Kohsuke Kawaguchi
* @see GHRepository#getIssue(int)
* @see GitHub#searchIssues()
* @see GHIssueSearchBuilder
*/
public class GHIssue {
public class GHIssue extends GHObject {
GitHub root;
GHRepository owner;
@@ -49,37 +52,28 @@ public class GHIssue {
protected String closed_at;
protected int comments;
protected String body;
// for backward compatibility with < 1.63, this collection needs to hold instances of Label, not GHLabel
protected List<Label> labels;
protected GHUser user;
protected String title, created_at, html_url;
protected String title, html_url;
protected GHIssue.PullRequest pull_request;
protected GHMilestone milestone;
protected String url, updated_at;
protected int id;
protected GHUser closed_by;
public static class Label {
private String url;
private String name;
private String color;
public String getUrl() {
return url;
}
public String getName() {
return name;
}
public String getColor() {
return color;
}
/**
* @deprecated use {@link GHLabel}
*/
public static class Label extends GHLabel {
}
/*package*/ GHIssue wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
if(milestone != null) milestone.wrap(owner);
if(milestone != null) milestone.wrap(owner);
return wrap(owner.root);
}
/*package*/ GHIssue wrap(GitHub root) {
this.root = root;
if(assignee != null) assignee.wrapUp(root);
if(user != null) user.wrapUp(root);
if(closed_by != null) closed_by.wrapUp(root);
@@ -117,7 +111,7 @@ public class GHIssue {
* The HTML page of this issue,
* like https://github.com/jenkinsci/jenkins/issues/100
*/
public URL getUrl() {
public URL getHtmlUrl() {
return GitHub.parseURL(html_url);
}
@@ -129,19 +123,11 @@ public class GHIssue {
return Enum.valueOf(GHIssueState.class, state.toUpperCase(Locale.ENGLISH));
}
public Collection<Label> getLabels() {
public Collection<GHLabel> getLabels() throws IOException {
if(labels == null){
return Collections.EMPTY_LIST;
return Collections.emptyList();
}
return Collections.unmodifiableList(labels);
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public Date getUpdatedAt() {
return GitHub.parseDate(updated_at);
return Collections.<GHLabel>unmodifiableList(labels);
}
public Date getClosedAt() {
@@ -163,6 +149,10 @@ public class GHIssue {
new Requester(root)._with(key, value).method("PATCH").to(getApiRoute());
}
private void editIssue(String key, Object value) throws IOException {
new Requester(root)._with(key, value).method("PATCH").to(getIssuesApiRoute());
}
/**
* Closes this issue.
*/
@@ -186,11 +176,11 @@ public class GHIssue {
}
public void assignTo(GHUser user) throws IOException {
edit("assignee",user.getLogin());
editIssue("assignee",user.getLogin());
}
public void setLabels(String... labels) throws IOException {
edit("labels",labels);
editIssue("labels",labels);
}
/**
@@ -222,7 +212,7 @@ public class GHIssue {
return getIssuesApiRoute();
}
private String getIssuesApiRoute() {
protected String getIssuesApiRoute() {
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/issues/"+number;
}
@@ -236,7 +226,15 @@ public class GHIssue {
public GHUser getUser() {
return user;
}
/**
* Reports who has closed the issue.
*
* <p>
* Note that GitHub doesn't always seem to report this information
* even for an issue that's already closed. See
* https://github.com/kohsuke/github-api/issues/60.
*/
public GHUser getClosedBy() {
if(!"closed".equals(state)) return null;
if(closed_by != null) return closed_by;
@@ -249,10 +247,17 @@ public class GHIssue {
return comments;
}
/**
* Returns non-null if this issue is a shadow of a pull request.
*/
public PullRequest getPullRequest() {
return pull_request;
}
public boolean isPullRequest() {
return pull_request!=null;
}
public GHMilestone getMilestone() {
return milestone;
}

View File

@@ -32,12 +32,10 @@ import java.util.Date;
*
* @author Kohsuke Kawaguchi
*/
public class GHIssueComment {
public class GHIssueComment extends GHObject {
GHIssue owner;
private String body, gravatar_id, created_at, updated_at;
private URL url;
private int id;
private String body, gravatar_id;
private GHUser user;
/*package*/ GHIssueComment wrapUp(GHIssue owner) {
@@ -59,22 +57,6 @@ public class GHIssueComment {
return body;
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public Date getUpdatedAt() {
return GitHub.parseDate(updated_at);
}
public int getId() {
return id;
}
public URL getUrl() {
return url;
}
/**
* Gets the ID of the user who posted this comment.
*/

View File

@@ -0,0 +1,85 @@
package org.kohsuke.github;
import org.apache.commons.lang.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
* Search issues.
*
* @author Kohsuke Kawaguchi
* @see GitHub#searchIssues()
*/
public class GHIssueSearchBuilder {
private final GitHub root;
private final Requester req;
private final List<String> terms = new ArrayList<String>();
/*package*/ GHIssueSearchBuilder(GitHub root) {
this.root = root;
req = root.retrieve();
}
/**
* Search terms.
*/
public GHIssueSearchBuilder q(String term) {
terms.add(term);
return this;
}
public GHIssueSearchBuilder mentions(GHUser u) {
return mentions(u.getLogin());
}
public GHIssueSearchBuilder mentions(String login) {
return q("mentions:"+login);
}
public GHIssueSearchBuilder isOpen() {
return q("is:open");
}
public GHIssueSearchBuilder isClosed() {
return q("is:closed");
}
public GHIssueSearchBuilder isMerged() {
return q("is:merged");
}
public GHIssueSearchBuilder sort(Sort sort) {
req.with("sort",sort.toString().toLowerCase(Locale.ENGLISH));
return this;
}
public enum Sort { COMMENTS, CREATED, UPDATED }
private static class IssueSearchResult extends SearchResult<GHIssue> {
private GHIssue[] items;
@Override
public GHIssue[] getItems() {
return items;
}
}
/**
* Lists up the issues with the criteria built so far.
*/
public PagedSearchIterable<GHIssue> list() {
return new PagedSearchIterable<GHIssue>() {
public PagedIterator<GHIssue> iterator() {
req.set("q", StringUtils.join(terms," "));
return new PagedIterator<GHIssue>(adapt(req.asIterator("/search/issues", IssueSearchResult.class))) {
protected void wrapUp(GHIssue[] page) {
for (GHIssue c : page)
c.wrap(root);
}
};
}
};
}
}

View File

@@ -0,0 +1,37 @@
package org.kohsuke.github;
import java.io.IOException;
/**
* @author Kohsuke Kawaguchi
* @see GHIssue#getLabels()
* @see GHRepository#listLabels()
*/
public class GHLabel {
private String url, name, color;
private GHRepository repo;
public String getUrl() {
return url;
}
public String getName() {
return name;
}
/**
* Color code without leading '#', such as 'f29513'
*/
public String getColor() {
return color;
}
/*package*/ GHLabel wrapUp(GHRepository repo) {
this.repo = repo;
return this;
}
public void delete() throws IOException {
repo.root.retrieve().method("DELETE").to(url);
}
}

View File

@@ -9,12 +9,12 @@ import java.util.Locale;
* @author Yusuke Kokubo
*
*/
public class GHMilestone {
public class GHMilestone extends GHObject {
GitHub root;
GHRepository owner;
GHUser creator;
private String state, due_on, title, url, created_at, description;
private String state, due_on, title, description;
private int closed_issues, open_issues, number;
public GitHub getRoot() {
@@ -38,14 +38,6 @@ public class GHMilestone {
return title;
}
public String getUrl() {
return url;
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public String getDescription() {
return description;
}

View File

@@ -0,0 +1,63 @@
package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import java.io.IOException;
import java.net.URL;
import java.util.Date;
/**
* Most (all?) domain objects in GitHub seems to have these 4 properties.
*/
public abstract class GHObject {
protected String url;
protected int id;
protected String created_at;
protected String updated_at;
/*package*/ GHObject() {
}
/**
* When was this resource created?
*/
@WithBridgeMethods(value=String.class, adapterMethod="createdAtStr")
public Date getCreatedAt() throws IOException {
return GitHub.parseDate(created_at);
}
private Object createdAtStr(Date id, Class type) {
return created_at;
}
/**
* API URL of this object.
*/
@WithBridgeMethods(value=String.class, adapterMethod="urlToString")
public URL getUrl() {
return GitHub.parseURL(url);
}
/**
* When was this resource last updated?
*/
public Date getUpdatedAt() throws IOException {
return GitHub.parseDate(updated_at);
}
/**
* Unique ID number of this resource.
*/
@WithBridgeMethods(value=String.class, adapterMethod="intToString")
public int getId() {
return id;
}
private Object intToString(int id, Class type) {
return String.valueOf(id);
}
private Object urlToString(URL url, Class type) {
return url==null ? null : url.toString();
}
}

View File

@@ -4,6 +4,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -14,15 +15,14 @@ import java.util.TreeMap;
*
* @author Kohsuke Kawaguchi
*/
public abstract class GHPerson {
public abstract class GHPerson extends GHObject {
/*package almost final*/ GitHub root;
// core data fields that exist even for "small" user data (such as the user info in pull request)
protected String login, avatar_url, url, gravatar_id;
protected int id;
protected String login, avatar_url, gravatar_id;
// other fields (that only show up in full data)
protected String location,blog,email,name,created_at,company;
protected String location,blog,email,name,company;
protected String html_url;
protected int followers,following,public_repos,public_gists;
@@ -36,7 +36,7 @@ public abstract class GHPerson {
*
* Depending on the original API call where this object is created, it may not contain everything.
*/
protected void populate() throws IOException {
protected synchronized void populate() throws IOException {
if (created_at!=null) return; // already populated
root.retrieve().to(url, this);
@@ -196,9 +196,14 @@ public abstract class GHPerson {
return location;
}
public String getCreatedAt() throws IOException {
public Date getCreatedAt() throws IOException {
populate();
return created_at;
return super.getCreatedAt();
}
public Date getUpdatedAt() throws IOException {
populate();
return super.getCreatedAt();
}
/**
@@ -236,13 +241,6 @@ public abstract class GHPerson {
return following;
}
/**
* What appears to be a GitHub internal unique number that identifies this user.
*/
public int getId() {
return id;
}
public int getFollowersCount() throws IOException {
populate();
return followers;

View File

@@ -52,6 +52,13 @@ public class GHPullRequest extends GHIssue {
private String mergeable_state;
private int changed_files;
/**
* GitHub doesn't return some properties of {@link GHIssue} when requesting the GET on the 'pulls' API
* route as opposed to 'issues' API route. This flag remembers whether we made the GET call on the 'issues' route
* on this object to fill in those missing details
*/
private transient boolean fetchedIssueDetails;
GHPullRequest wrapUp(GHRepository owner) {
this.wrap(owner);
@@ -103,7 +110,7 @@ public class GHPullRequest extends GHIssue {
}
@Deprecated
public Date getIssueUpdatedAt() {
public Date getIssueUpdatedAt() throws IOException {
return super.getUpdatedAt();
}
@@ -120,11 +127,12 @@ public class GHPullRequest extends GHIssue {
}
@Override
public Collection<Label> getLabels() {
public Collection<GHLabel> getLabels() throws IOException {
fetchIssue();
return super.getLabels();
}
@Override
@Override
public GHUser getClosedBy() {
return null;
}
@@ -186,7 +194,7 @@ public class GHPullRequest extends GHIssue {
private void populate() throws IOException {
if (merged_by!=null) return; // already populated
root.retrieve().to(url, this);
root.retrieve().to(url, this).wrapUp(owner);
}
/**
@@ -218,4 +226,10 @@ public class GHPullRequest extends GHIssue {
new Requester(root).method("PUT").with("commit_message",msg).to(getApiRoute()+"/merge");
}
private void fetchIssue() throws IOException {
if (!fetchedIssueDetails) {
new Requester(root).to(getIssuesApiRoute(), this);
fetchedIssueDetails = true;
}
}
}

View File

@@ -15,22 +15,19 @@ import static java.lang.String.format;
* @see GHRepository#getReleases()
* @see GHRepository#createRelease(String)
*/
public class GHRelease {
public class GHRelease extends GHObject {
GitHub root;
GHRepository owner;
private String url;
private String html_url;
private String assets_url;
private String upload_url;
private long id;
private String tag_name;
private String target_commitish;
private String name;
private String body;
private boolean draft;
private boolean prerelease;
private Date created_at;
private Date published_at;
private String tarball_url;
private String zipball_url;
@@ -39,50 +36,18 @@ public class GHRelease {
return assets_url;
}
public void setAssetsUrl(String assets_url) {
this.assets_url = assets_url;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public Date getCreatedAt() {
return created_at;
}
public void setCreatedAt(Date created_at) {
this.created_at = created_at;
}
public boolean isDraft() {
return draft;
}
public void setDraft(boolean draft) {
this.draft = draft;
}
public String getHtmlUrl() {
return html_url;
}
public void setHtmlUrl(String html_url) {
this.html_url = html_url;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
@@ -103,74 +68,34 @@ public class GHRelease {
return prerelease;
}
public void setPrerelease(boolean prerelease) {
this.prerelease = prerelease;
}
public Date getPublished_at() {
return published_at;
}
public void setPublished_at(Date published_at) {
this.published_at = published_at;
}
public GitHub getRoot() {
return root;
}
public void setRoot(GitHub root) {
this.root = root;
}
public String getTagName() {
return tag_name;
}
public void setTagName(String tag_name) {
this.tag_name = tag_name;
}
public String getTargetCommitish() {
return target_commitish;
}
public void setTargetCommitish(String target_commitish) {
this.target_commitish = target_commitish;
}
public String getUploadUrl() {
return upload_url;
}
public void setUploadUrl(String upload_url) {
this.upload_url = upload_url;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getZipballUrl() {
return zipball_url;
}
public void setZipballUrl(String zipballUrl) {
this.zipball_url = zipballUrl;
}
public String getTarballUrl() {
return tarball_url;
}
public void setTarballUrl(String tarballUrl) {
this.tarball_url = tarballUrl;
}
GHRelease wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
@@ -195,7 +120,7 @@ public class GHRelease {
public GHAsset uploadAsset(File file, String contentType) throws IOException {
Requester builder = new Requester(owner.root);
String url = format("https://uploads.github.com%sreleases/%d/assets?name=%s",
String url = format("https://uploads.github.com%s/releases/%d/assets?name=%s",
owner.getApiTailUrl(""), getId(), file.getName());
return builder.contentType(contentType)
.with(new FileInputStream(file))

View File

@@ -25,28 +25,16 @@ package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import java.io.FileNotFoundException;
import org.apache.commons.lang.StringUtils;
import javax.xml.bind.DatatypeConverter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.URL;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.*;
import static java.util.Arrays.*;
import static java.util.Arrays.asList;
/**
* A repository on GitHub.
@@ -54,11 +42,10 @@ import static java.util.Arrays.*;
* @author Kohsuke Kawaguchi
*/
@SuppressWarnings({"UnusedDeclaration"})
public class GHRepository {
public class GHRepository extends GHObject {
/*package almost final*/ GitHub root;
private String description, homepage, name, full_name;
private String url; // this is the API url
private String html_url; // this is the UI
private String git_url, ssh_url, clone_url, svn_url;
private GHUser owner; // not fully populated. beware.
@@ -66,7 +53,7 @@ public class GHRepository {
@JsonProperty("private")
private boolean _private;
private int watchers,forks,open_issues,size,network_count,subscribers_count;
private String created_at, pushed_at;
private String pushed_at;
private Map<Integer,GHMilestone> milestones = new HashMap<Integer, GHMilestone>();
private String default_branch,language;
@@ -74,6 +61,59 @@ public class GHRepository {
private GHRepoPermission permissions;
public GHDeploymentBuilder createDeployment(String ref) {
return new GHDeploymentBuilder(this,ref);
}
public PagedIterable<GHDeploymentStatus> getDeploymentStatuses(final int id) {
return new PagedIterable<GHDeploymentStatus>() {
public PagedIterator<GHDeploymentStatus> iterator() {
return new PagedIterator<GHDeploymentStatus>(root.retrieve().asIterator(getApiTailUrl("deployments")+"/"+id+"/statuses", GHDeploymentStatus[].class)) {
@Override
protected void wrapUp(GHDeploymentStatus[] page) {
for (GHDeploymentStatus c : page)
c.wrap(GHRepository.this);
}
};
}
};
}
public PagedIterable<GHDeployment> listDeployments(String sha,String ref,String task,String environment){
List<String> params = Arrays.asList(getParam("sha", sha), getParam("ref", ref), getParam("task", task), getParam("environment", environment));
final String deploymentsUrl = getApiTailUrl("deployments") + "?"+ join(params,"&");
return new PagedIterable<GHDeployment>() {
public PagedIterator<GHDeployment> iterator() {
return new PagedIterator<GHDeployment>(root.retrieve().asIterator(deploymentsUrl, GHDeployment[].class)) {
@Override
protected void wrapUp(GHDeployment[] page) {
for (GHDeployment c : page)
c.wrap(GHRepository.this);
}
};
}
};
}
private String join(List<String> params, String joinStr) {
StringBuilder output = new StringBuilder();
for(String param: params){
if(param != null){
output.append(param+joinStr);
}
}
return output.toString();
}
private String getParam(String name, String value) {
return StringUtils.trimToNull(value)== null? null: name+"="+value;
}
public GHDeploymentStatusBuilder createDeployStatus(int deploymentId, GHDeploymentState ghDeploymentState) {
return new GHDeploymentStatusBuilder(this,deploymentId,ghDeploymentState);
}
private static class GHRepoPermission {
boolean pull,push,admin;
}
@@ -87,13 +127,6 @@ public class GHRepository {
return homepage;
}
/**
* URL of this repository, like 'http://github.com/kohsuke/jenkins'
*/
public String getUrl() {
return html_url;
}
/**
* Gets the git:// URL to this repository, such as "git://github.com/kohsuke/jenkins.git"
* This URL is read-only.
@@ -162,7 +195,7 @@ public class GHRepository {
}
public GHIssue getIssue(int id) throws IOException {
return root.retrieve().to("/repos/" + owner.login + "/" + name + "/issues/" + id, GHIssue.class).wrap(this);
return root.retrieve().to(getApiTailUrl("issues/" + id), GHIssue.class).wrap(this);
}
public GHIssueBuilder createIssue(String title) {
@@ -175,8 +208,8 @@ public class GHRepository {
public List<GHIssue> getIssues(GHIssueState state, GHMilestone milestone) throws IOException {
return Arrays.asList(GHIssue.wrap(root.retrieve()
.to(String.format("/repos/%s/%s/issues?state=%s&milestone=%s", owner.login, name,
state.toString().toLowerCase(), milestone == null ? "none" : "" + milestone.getNumber()),
.to(getApiTailUrl(String.format("issues?state=%s&milestone=%s",
state.toString().toLowerCase(), milestone == null ? "none" : "" + milestone.getNumber())),
GHIssue[].class
), this));
}
@@ -252,7 +285,7 @@ public class GHRepository {
};
}
protected String getOwnerName() {
public String getOwnerName() {
return owner.login;
}
@@ -305,10 +338,6 @@ public class GHRepository {
return GitHub.parseDate(pushed_at);
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
/**
* Returns the primary branch you'll configure in the "Admin > Options" config page.
*
@@ -342,7 +371,7 @@ public class GHRepository {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> iterator() {
return new PagedIterator<GHUser>(root.retrieve().asIterator("/repos/" + owner.login + "/" + name + "/collaborators", GHUser[].class)) {
return new PagedIterator<GHUser>(root.retrieve().asIterator(getApiTailUrl("collaborators"), GHUser[].class)) {
@Override
protected void wrapUp(GHUser[] users) {
@@ -363,7 +392,7 @@ public class GHRepository {
*/
public Set<String> getCollaboratorNames() throws IOException {
Set<String> r = new HashSet<String>();
for (GHUser u : GHUser.wrap(root.retrieve().to("/repos/" + owner.login + "/" + name + "/collaborators", GHUser[].class),root))
for (GHUser u : GHUser.wrap(root.retrieve().to(getApiTailUrl("collaborators"), GHUser[].class),root))
r.add(u.login);
return r;
}
@@ -372,7 +401,7 @@ public class GHRepository {
* If this repository belongs to an organization, return a set of teams.
*/
public Set<GHTeam> getTeams() throws IOException {
return Collections.unmodifiableSet(new HashSet<GHTeam>(Arrays.asList(GHTeam.wrapUp(root.retrieve().to("/repos/" + owner.login + "/" + name + "/teams", GHTeam[].class), root.getOrganization(owner.login)))));
return Collections.unmodifiableSet(new HashSet<GHTeam>(Arrays.asList(GHTeam.wrapUp(root.retrieve().to(getApiTailUrl("teams"), GHTeam[].class), root.getOrganization(owner.login)))));
}
public void addCollaborators(GHUser... users) throws IOException {
@@ -394,7 +423,7 @@ public class GHRepository {
private void modifyCollaborators(Collection<GHUser> users, String method) throws IOException {
verifyMine();
for (GHUser user : users) {
new Requester(root).method(method).to("/repos/" + owner.login + "/" + name + "/collaborators/" + user.getLogin());
new Requester(root).method(method).to(getApiTailUrl("collaborators/" + user.getLogin()));
}
}
@@ -402,14 +431,14 @@ public class GHRepository {
Map<String, String> config = new HashMap<String, String>();
config.put("address", address);
new Requester(root).method("POST").with("name", "email").with("config", config).with("active", "true")
.to(String.format("/repos/%s/%s/hooks", owner.login, name));
.to(getApiTailUrl("hooks"));
}
private void edit(String key, String value) throws IOException {
Requester requester = new Requester(root);
if (!key.equals("name"))
requester.with("name", name); // even when we don't change the name, we need to send it in
requester.with(key, value).method("PATCH").to("/repos/" + owner.login + "/" + name);
requester.with(key, value).method("PATCH").to(getApiTailUrl(""));
}
/**
@@ -450,7 +479,7 @@ public class GHRepository {
*/
public void delete() throws IOException {
try {
new Requester(root).method("DELETE").to("/repos/" + owner.login + "/" + name);
new Requester(root).method("DELETE").to(getApiTailUrl(""));
} catch (FileNotFoundException x) {
throw (FileNotFoundException) new FileNotFoundException("Failed to delete " + owner.login + "/" + name + "; might not exist, or you might need the delete_repo scope in your token: http://stackoverflow.com/a/19327004/12916").initCause(x);
}
@@ -463,7 +492,7 @@ public class GHRepository {
* Newly forked repository that belong to you.
*/
public GHRepository fork() throws IOException {
return new Requester(root).method("POST").to("/repos/" + owner.login + "/" + name + "/forks", GHRepository.class).wrap(root);
return new Requester(root).method("POST").to(getApiTailUrl("forks"), GHRepository.class).wrap(root);
}
/**
@@ -473,7 +502,7 @@ public class GHRepository {
* Newly forked repository that belong to you.
*/
public GHRepository forkTo(GHOrganization org) throws IOException {
new Requester(root).to(String.format("/repos/%s/%s/forks?org=%s", owner.login, name, org.getLogin()));
new Requester(root).to(getApiTailUrl("forks?org="+org.getLogin()));
// this API is asynchronous. we need to wait for a bit
for (int i=0; i<10; i++) {
@@ -492,7 +521,7 @@ public class GHRepository {
* Retrieves a specified pull request.
*/
public GHPullRequest getPullRequest(int i) throws IOException {
return root.retrieve().to("/repos/" + owner.login + '/' + name + "/pulls/" + i, GHPullRequest.class).wrapUp(this);
return root.retrieve().to(getApiTailUrl("pulls/" + i), GHPullRequest.class).wrapUp(this);
}
/**
@@ -510,11 +539,11 @@ public class GHRepository {
public PagedIterable<GHPullRequest> listPullRequests(final GHIssueState state) {
return new PagedIterable<GHPullRequest>() {
public PagedIterator<GHPullRequest> iterator() {
return new PagedIterator<GHPullRequest>(root.retrieve().asIterator(String.format("/repos/%s/%s/pulls?state=%s", owner.login, name, state.name().toLowerCase(Locale.ENGLISH)), GHPullRequest[].class)) {
return new PagedIterator<GHPullRequest>(root.retrieve().asIterator(getApiTailUrl("pulls?state="+state.name().toLowerCase(Locale.ENGLISH)), GHPullRequest[].class)) {
@Override
protected void wrapUp(GHPullRequest[] page) {
for (GHPullRequest pr : page)
pr.wrap(GHRepository.this);
pr.wrapUp(GHRepository.this);
}
};
}
@@ -549,14 +578,14 @@ public class GHRepository {
*/
public List<GHHook> getHooks() throws IOException {
List<GHHook> list = new ArrayList<GHHook>(Arrays.asList(
root.retrieve().to(String.format("/repos/%s/%s/hooks", owner.login, name), GHHook[].class)));
root.retrieve().to(getApiTailUrl("hooks"), GHHook[].class)));
for (GHHook h : list)
h.wrap(this);
return list;
}
public GHHook getHook(int id) throws IOException {
return root.retrieve().to(String.format("/repos/%s/%s/hooks/%d", owner.login, name, id), GHHook.class).wrap(this);
return root.retrieve().to(getApiTailUrl("hooks/" + id), GHHook.class).wrap(this);
}
/**
@@ -568,7 +597,7 @@ public class GHRepository {
* @throws IOException on failure communicating with GitHub
*/
public GHCompare getCompare(String id1, String id2) throws IOException {
GHCompare compare = root.retrieve().to(String.format("/repos/%s/%s/compare/%s...%s", owner.login, name, id1, id2), GHCompare.class);
GHCompare compare = root.retrieve().to(getApiTailUrl(String.format("compare/%s...%s", id1, id2)), GHCompare.class);
return compare.wrap(this);
}
@@ -731,6 +760,54 @@ public class GHRepository {
};
}
/**
* Lists labels in this repository.
*
* https://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository
*/
public PagedIterable<GHLabel> listLabels() throws IOException {
return new PagedIterable<GHLabel>() {
public PagedIterator<GHLabel> iterator() {
return new PagedIterator<GHLabel>(root.retrieve().asIterator(getApiTailUrl("labels"), GHLabel[].class)) {
@Override
protected void wrapUp(GHLabel[] page) {
for (GHLabel c : page)
c.wrapUp(GHRepository.this);
}
};
}
};
}
public GHLabel getLabel(String name) throws IOException {
return root.retrieve().to(getApiTailUrl("labels/"+name), GHLabel.class).wrapUp(this);
}
public GHLabel createLabel(String name, String color) throws IOException {
return root.retrieve().method("POST")
.with("name",name)
.with("color",color)
.to(getApiTailUrl("labels"), GHLabel.class).wrapUp(this);
}
/**
* Lists all the subscribers (aka watchers.)
*
* https://developer.github.com/v3/activity/watching/
*/
public PagedIterable<GHUser> listSubscribers() {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> iterator() {
return new PagedIterator<GHUser>(root.retrieve().asIterator(getApiTailUrl("subscribers"), GHUser[].class)) {
protected void wrapUp(GHUser[] page) {
for (GHUser c : page)
c.wrapUp(root);
}
};
}
};
}
/**
*
* See https://api.github.com/hooks for possible names and their configuration scheme.
@@ -909,7 +986,7 @@ public class GHRepository {
public GHContent getFileContent(String path, String ref) throws IOException {
Requester requester = root.retrieve();
String target = String.format("/repos/%s/%s/contents/%s", owner.login, name, path);
String target = getApiTailUrl("contents/" + path);
if (ref != null)
target = target + "?ref=" + ref;
@@ -923,7 +1000,7 @@ public class GHRepository {
public List<GHContent> getDirectoryContent(String path, String ref) throws IOException {
Requester requester = root.retrieve();
String target = String.format("/repos/%s/%s/contents/%s", owner.login, name, path);
String target = getApiTailUrl("contents/" + path);
if (ref != null)
target = target + "?ref=" + ref;
@@ -935,19 +1012,31 @@ public class GHRepository {
return Arrays.asList(files);
}
public GHContent getReadme() throws Exception {
return getFileContent("readme");
/**
* https://developer.github.com/v3/repos/contents/#get-the-readme
*/
public GHContent getReadme() throws IOException {
Requester requester = root.retrieve();
return requester.to(getApiTailUrl("readme"), GHContent.class).wrap(this);
}
public GHContentUpdateResponse createContent(String content, String commitMessage, String path) throws IOException {
return createContent(content, commitMessage, path, null);
return createContent(content.getBytes(), commitMessage, path, null);
}
public GHContentUpdateResponse createContent(String content, String commitMessage, String path, String branch) throws IOException {
return createContent(content.getBytes(), commitMessage, path, branch);
}
public GHContentUpdateResponse createContent(byte[] contentBytes, String commitMessage, String path) throws IOException {
return createContent(contentBytes, commitMessage, path, null);
}
public GHContentUpdateResponse createContent(byte[] contentBytes, String commitMessage, String path, String branch) throws IOException {
Requester requester = new Requester(root)
.with("path", path)
.with("message", commitMessage)
.with("content", DatatypeConverter.printBase64Binary(content.getBytes()))
.with("content", DatatypeConverter.printBase64Binary(contentBytes))
.method("PUT");
if (branch != null) {
@@ -975,11 +1064,56 @@ public class GHRepository {
public List<GHDeployKey> getDeployKeys() throws IOException{
List<GHDeployKey> list = new ArrayList<GHDeployKey>(Arrays.asList(
root.retrieve().to(String.format("/repos/%s/%s/keys", owner.login, name), GHDeployKey[].class)));
root.retrieve().to(getApiTailUrl("keys"), GHDeployKey[].class)));
for (GHDeployKey h : list)
h.wrap(this);
return list;
}
/**
* Subscribes to this repository to get notifications.
*/
public GHSubscription subscribe(boolean subscribed, boolean ignored) throws IOException {
return new Requester(root)
.with("subscribed", subscribed)
.with("ignored", ignored)
.method("PUT").to(getApiTailUrl("subscription"), GHSubscription.class).wrapUp(this);
}
/**
* Returns the current subscription.
*
* @return null if no subscription exists.
*/
public GHSubscription getSubscription() throws IOException {
try {
return new Requester(root).to(getApiTailUrl("subscription"), GHSubscription.class).wrapUp(this);
} catch (FileNotFoundException e) {
return null;
}
}
public PagedIterable<Contributor> listContributors() throws IOException {
return new PagedIterable<Contributor>() {
public PagedIterator<Contributor> iterator() {
return new PagedIterator<Contributor>(root.retrieve().asIterator(getApiTailUrl("contributors"), Contributor[].class)) {
@Override
protected void wrapUp(Contributor[] page) {
for (Contributor c : page)
c.wrapUp(root);
}
};
}
};
}
public static class Contributor extends GHUser {
private int contributions;
public int getContributions() {
return contributions;
}
}
@@ -1004,6 +1138,7 @@ public class GHRepository {
}
String getApiTailUrl(String tail) {
return "/repos/" + owner.login + "/" + name +'/'+tail;
if (tail.length()>0 && !tail.startsWith("/")) tail='/'+tail;
return "/repos/" + owner.login + "/" + name +tail;
}
}

View File

@@ -0,0 +1,62 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Date;
/**
* Represents your subscribing to a repository.
*
* @author Kohsuke Kawaguchi
*/
public class GHSubscription {
private String created_at, url, repository_url, reason;
private boolean subscribed, ignored;
private GitHub root;
private GHRepository repo;
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public String getUrl() {
return url;
}
public String getRepositoryUrl() {
return repository_url;
}
public String getReason() {
return reason;
}
public boolean isSubscribed() {
return subscribed;
}
public boolean isIgnored() {
return ignored;
}
public GHRepository getRepository() {
return repo;
}
/**
* Removes this subscription.
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").to(url);
}
GHSubscription wrapUp(GHRepository repo) {
this.repo = repo;
return wrapUp(repo.root);
}
GHSubscription wrapUp(GitHub root) {
this.root = root;
return this;
}
}

View File

@@ -15,6 +15,8 @@ public class GHTag {
/*package*/ GHTag wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
if (commit!=null)
commit.wrapUp(owner);
return this;
}

View File

@@ -1,8 +1,7 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
@@ -48,13 +47,26 @@ public class GHTeam {
return id;
}
/**
* Retrieves the current members.
*/
public Set<GHUser> getMembers() throws IOException {
return new HashSet<GHUser>(Arrays.asList(GHUser.wrap(org.root.retrieve().to(api("/members"), GHUser[].class), org.root)));
/**
* Retrieves the current members.
*/
public PagedIterable<GHUser> listMembers() throws IOException {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> iterator() {
return new PagedIterator<GHUser>(org.root.retrieve().asIterator(api("/members"), GHUser[].class)) {
@Override
protected void wrapUp(GHUser[] page) {
GHUser.wrap(page, org.root);
}
};
}
};
}
public Set<GHUser> getMembers() throws IOException {
return Collections.unmodifiableSet(listMembers().asSet());
}
/**
* Checks if this team has the specified user as a member.
*/
@@ -68,19 +80,36 @@ public class GHTeam {
}
public Map<String,GHRepository> getRepositories() throws IOException {
GHRepository[] repos = org.root.retrieve().to(api("/repos"), GHRepository[].class);
Map<String,GHRepository> m = new TreeMap<String, GHRepository>();
for (GHRepository r : repos) {
m.put(r.getName(),r.wrap(org.root));
for (GHRepository r : listRepositories()) {
m.put(r.getName(), r);
}
return m;
}
public PagedIterable<GHRepository> listRepositories() {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> iterator() {
return new PagedIterator<GHRepository>(org.root.retrieve().asIterator(api("/repos"), GHRepository[].class)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository r : page)
r.wrap(org.root);
}
};
}
};
}
/**
* Adds a member to the team.
*
* The user will be invited to the organization if required.
*
* @since 1.59
*/
public void add(GHUser u) throws IOException {
org.root.retrieve().method("PUT").to(api("/members/" + u.getLogin()), null);
org.root.retrieve().method("PUT").to(api("/memberships/" + u.getLogin()), null);
}
/**

View File

@@ -69,6 +69,24 @@ public class GHUser extends GHPerson {
return new GHPersonSet<GHUser>(Arrays.asList(wrap(followers,root)));
}
/**
* Lists all the subscribed (aka watched) repositories.
*
* https://developer.github.com/v3/activity/watching/
*/
public PagedIterable<GHRepository> listSubscriptions() {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> iterator() {
return new PagedIterator<GHRepository>(root.retrieve().asIterator(getApiTailUrl("subscriptions"), GHRepository[].class)) {
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
c.wrap(root);
}
};
}
};
}
/**
* Returns true if this user belongs to the specified organization.
*/
@@ -162,4 +180,9 @@ public class GHUser extends GHPerson {
}
return false;
}
String getApiTailUrl(String tail) {
if (tail.length()>0 && !tail.startsWith("/")) tail='/'+tail;
return "/users/" + login + tail;
}
}

View File

@@ -26,8 +26,6 @@ package org.kohsuke.github;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Reader;
@@ -40,14 +38,13 @@ import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TimeZone;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -57,6 +54,12 @@ import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
/**
* Root of the GitHub API.
*
* <h2>Thread safety</h2>
* <p>
* This library aims to be safe for use by multiple threads concurrently, although
* the library itself makes no attempt to control/serialize potentially conflicting
* operations to GitHub, such as updating & deleting a repository at the same time.
*
* @author Kohsuke Kawaguchi
*/
public class GitHub {
@@ -67,20 +70,13 @@ public class GitHub {
*/
/*package*/ final String encodedAuthorization;
private final Map<String,GHUser> users = new HashMap<String, GHUser>();
private final Map<String,GHOrganization> orgs = new HashMap<String, GHOrganization>();
private final Map<String,GHUser> users = new Hashtable<String, GHUser>();
private final Map<String,GHOrganization> orgs = new Hashtable<String, GHOrganization>();
private final String apiUrl;
private HttpConnector connector = HttpConnector.DEFAULT;
/**
* Connects to GitHub.com
*/
private GitHub(String login, String oauthAccessToken, String password) throws IOException {
this (GITHUB_URL, login, oauthAccessToken, password);
}
/**
* Creates a client API root object.
*
@@ -114,10 +110,13 @@ public class GitHub {
* Secret OAuth token.
* @param password
* User's password. Always used in conjunction with the {@code login} parameter
* @param connector
* HttpConnector to use. Pass null to use default connector.
*/
private GitHub(String apiUrl, String login, String oauthAccessToken, String password) throws IOException {
/* package */ GitHub(String apiUrl, String login, String oauthAccessToken, String password, HttpConnector connector) throws IOException {
if (apiUrl.endsWith("/")) apiUrl = apiUrl.substring(0, apiUrl.length()-1); // normalize
this.apiUrl = apiUrl;
if (null != connector) this.connector = connector;
if (oauthAccessToken!=null) {
encodedAuthorization = "token "+oauthAccessToken;
@@ -136,18 +135,10 @@ public class GitHub {
}
/**
* Obtains the credential from "~/.github"
* Obtains the credential from "~/.github" or from the System Environment Properties.
*/
public static GitHub connect() throws IOException {
Properties props = new Properties();
File homeDir = new File(System.getProperty("user.home"));
FileInputStream in = new FileInputStream(new File(homeDir, ".github"));
try {
props.load(in);
} finally {
IOUtils.closeQuietly(in);
}
return new GitHub(GITHUB_URL,props.getProperty("login"), props.getProperty("oauth"),props.getProperty("password"));
return GitHubBuilder.fromCredentials().build();
}
/**
@@ -159,15 +150,15 @@ public class GitHub {
* For historical reasons, this parameter still accepts the bare domain name, but that's considered deprecated.
*/
public static GitHub connectToEnterprise(String apiUrl, String oauthAccessToken) throws IOException {
return connectUsingOAuth(apiUrl, oauthAccessToken);
return new GitHubBuilder().withEndpoint(apiUrl).withOAuthToken(oauthAccessToken).build();
}
public static GitHub connectToEnterprise(String apiUrl, String login, String password) throws IOException {
return new GitHub(apiUrl, login, null, password);
return new GitHubBuilder().withEndpoint(apiUrl).withPassword(login, password).build();
}
public static GitHub connect(String login, String oauthAccessToken) throws IOException {
return new GitHub(login,oauthAccessToken,null);
return new GitHubBuilder().withOAuthToken(oauthAccessToken, login).build();
}
/**
@@ -176,19 +167,19 @@ public class GitHub {
* Use {@link #connectUsingPassword(String, String)} or {@link #connectUsingOAuth(String)}.
*/
public static GitHub connect(String login, String oauthAccessToken, String password) throws IOException {
return new GitHub(login,oauthAccessToken,password);
return new GitHubBuilder().withOAuthToken(oauthAccessToken, login).withPassword(login, password).build();
}
public static GitHub connectUsingPassword(String login, String password) throws IOException {
return new GitHub(login,null,password);
return new GitHubBuilder().withPassword(login, password).build();
}
public static GitHub connectUsingOAuth(String oauthAccessToken) throws IOException {
return new GitHub(null, oauthAccessToken, null);
return new GitHubBuilder().withOAuthToken(oauthAccessToken).build();
}
public static GitHub connectUsingOAuth(String githubServer, String oauthAccessToken) throws IOException {
return new GitHub(githubServer,null, oauthAccessToken,null);
return new GitHubBuilder().withEndpoint(githubServer).withOAuthToken(oauthAccessToken).build();
}
/**
* Connects to GitHub anonymously.
@@ -196,7 +187,7 @@ public class GitHub {
* All operations that requires authentication will fail.
*/
public static GitHub connectAnonymously() throws IOException {
return new GitHub(null,null,null);
return new GitHubBuilder().build();
}
/**
@@ -440,6 +431,14 @@ public class GitHub {
}
}
/**
* Search issues.
*/
public GHIssueSearchBuilder searchIssues() {
return new GHIssueSearchBuilder(this);
}
/*package*/ static URL parseURL(String s) {
try {
return s==null ? null : new URL(s);
@@ -475,5 +474,5 @@ public class GitHub {
MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
private static final String GITHUB_URL = "https://api.github.com";
/* package */ static final String GITHUB_URL = "https://api.github.com";
}

View File

@@ -0,0 +1,175 @@
package org.kohsuke.github;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.util.Map;
import java.util.Properties;
/**
* @since 1.59
*/
public class GitHubBuilder {
private String endpoint = GitHub.GITHUB_URL;
// default scoped so unit tests can read them.
/* private */ String user;
/* private */ String password;
/* private */ String oauthToken;
private HttpConnector connector;
public GitHubBuilder() {
}
/**
* First check if the credentials are configured using the ~/.github properties file.
*
* If no user is specified it means there is no configuration present so check the environment instead.
*
* If there is still no user it means there are no credentials defined and throw an IOException.
*
* @return the configured Builder from credentials defined on the system or in the environment.
*
* @throws IOException If there are no credentials defined in the ~/.github properties file or the process environment.
*/
public static GitHubBuilder fromCredentials() throws IOException {
GitHubBuilder builder;
try {
builder = fromPropertyFile();
if (builder.user != null)
return builder;
else {
// this is the case where the ~/.github file exists but has no content.
builder = fromEnvironment();
if (builder.user != null)
return builder;
else
throw new IOException("Failed to resolve credentials from ~/.github or the environment.");
}
} catch (FileNotFoundException e) {
builder = fromEnvironment();
if (builder.user != null)
return builder;
else
throw new IOException("Failed to resolve credentials from ~/.github or the environment.", e);
}
}
public static GitHubBuilder fromEnvironment(String loginVariableName, String passwordVariableName, String oauthVariableName) throws IOException {
Properties env = new Properties();
Object loginValue = System.getenv(loginVariableName);
if (loginValue != null)
env.put("login", loginValue);
Object passwordValue = System.getenv(passwordVariableName);
if (passwordValue != null)
env.put("password", passwordValue);
Object oauthValue = System.getenv(oauthVariableName);
if (oauthValue != null)
env.put("oauth", oauthValue);
return fromProperties(env);
}
public static GitHubBuilder fromEnvironment() throws IOException {
Properties props = new Properties();
Map<String, String> env = System.getenv();
for (Map.Entry<String, String> element : env.entrySet()) {
props.put(element.getKey(), element.getValue());
}
return fromProperties(props);
}
public static GitHubBuilder fromPropertyFile() throws IOException {
File homeDir = new File(System.getProperty("user.home"));
File propertyFile = new File(homeDir, ".github");
return fromPropertyFile(propertyFile.getPath());
}
public static GitHubBuilder fromPropertyFile(String propertyFileName) throws IOException {
Properties props = new Properties();
FileInputStream in = null;
try {
in = new FileInputStream(propertyFileName);
props.load(in);
} finally {
IOUtils.closeQuietly(in);
}
return fromProperties(props);
}
public static GitHubBuilder fromProperties(Properties props) {
GitHubBuilder self = new GitHubBuilder();
self.withOAuthToken(props.getProperty("oauth"), props.getProperty("login"));
self.withPassword(props.getProperty("login"), props.getProperty("password"));
return self;
}
public GitHubBuilder withEndpoint(String endpoint) {
this.endpoint = endpoint;
return this;
}
public GitHubBuilder withPassword(String user, String password) {
this.user = user;
this.password = password;
return this;
}
public GitHubBuilder withOAuthToken(String oauthToken) {
return withOAuthToken(oauthToken, null);
}
public GitHubBuilder withOAuthToken(String oauthToken, String user) {
this.oauthToken = oauthToken;
this.user = user;
return this;
}
public GitHubBuilder withConnector(HttpConnector connector) {
this.connector = connector;
return this;
}
/**
* Configures {@linkplain #withConnector(HttpConnector) connector}
* that uses HTTP library in JRE but use a specific proxy, instead of
* the system default one.
*/
public GitHubBuilder withProxy(final Proxy p) {
return withConnector(new HttpConnector() {
public HttpURLConnection connect(URL url) throws IOException {
return (HttpURLConnection) url.openConnection(p);
}
});
}
public GitHub build() throws IOException {
return new GitHub(endpoint, user, oauthToken, password, connector);
}
}

View File

@@ -1,7 +1,9 @@
package org.kohsuke.github;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
/**
* {@link Iterable} that returns {@link PagedIterator}
@@ -21,4 +23,15 @@ public abstract class PagedIterable<T> implements Iterable<T> {
}
return r;
}
/**
* Eagerly walk {@link Iterable} and return the result in a set.
*/
public Set<T> asSet() {
LinkedHashSet<T> r = new LinkedHashSet<T>();
for(PagedIterator<T> i = iterator(); i.hasNext();) {
r.addAll(i.nextPage());
}
return r;
}
}

View File

@@ -0,0 +1,54 @@
package org.kohsuke.github;
import java.util.Iterator;
/**
* {@link PagedIterable} enhanced to report search result specific information.
*
* @author Kohsuke Kawaguchi
*/
public abstract class PagedSearchIterable<T> extends PagedIterable<T> {
/**
* As soon as we have any result fetched, it's set here so that we can report the total count.
*/
private SearchResult<T> result;
/**
* Returns the total number of hit, including the results that's not yet fetched.
*/
public int getTotalCount() {
populate();
return result.total_count;
}
public boolean isIncomplete() {
populate();
return result.incomplete_results;
}
private void populate() {
if (result==null)
iterator().hasNext();
}
/**
* Adapts {@link Iterator}.
*/
protected Iterator<T[]> adapt(final Iterator<? extends SearchResult<T>> base) {
return new Iterator<T[]>() {
public boolean hasNext() {
return base.hasNext();
}
public T[] next() {
SearchResult<T> v = base.next();
if (result==null) result = v;
return v.getItems();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}

View File

@@ -134,6 +134,19 @@ class Requester {
return this;
}
/**
* Unlike {@link #with(String, String)}, overrides the existing value
*/
public Requester set(String key, Object value) {
for (Entry e : args) {
if (e.key.equals(key)) {
e.value = value;
return this;
}
}
return _with(key,value);
}
public Requester method(String method) {
this.method = method;
return this;

View File

@@ -0,0 +1,13 @@
package org.kohsuke.github;
/**
* Represents the result of a search
*
* @author Kohsuke Kawaguchi
*/
abstract class SearchResult<T> {
int total_count;
boolean incomplete_results;
public abstract T[] getItems();
}

View File

@@ -15,6 +15,7 @@
<item name="Introduction" href="/index.html"/>
<item name="Download" href="http://mvnrepository.com/artifact/${project.groupId}/${project.artifactId}"/>
<item name="Source code" href="https://github.com/kohsuke/${project.artifactId}"/>
<item name="Mailing List" href="https://groups.google.com/forum/#!forum/github-api"/>
</menu>
<menu name="References">

View File

@@ -1,23 +1,17 @@
import org.kohsuke.github.GHOrganization;
import org.kohsuke.github.GHTeam;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GitHub;
import java.util.Arrays;
import java.util.Map;
import java.util.Collection;
/**
* @author Kohsuke Kawaguchi
*/
public class Foo {
public static void main(String[] args) throws Exception {
GHOrganization org = GitHub.connect().getOrganization("jenkinsci");
Map<String, GHTeam> teams = org.getTeams();
System.out.println(teams.size());
int sz = 0;
for (GHTeam t : org.listTeams()) {
sz++;
Collection<GHRepository> lst = GitHub.connect().getUser("kohsuke").getRepositories().values();
for (GHRepository r : lst) {
System.out.println(r.getName());
}
System.out.println(sz);
System.out.println(lst.size());
}
}

141
src/test/java/org/kohsuke/github/AppTest.java Normal file → Executable file
View File

@@ -1,22 +1,18 @@
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.junit.Assume;
import org.junit.Test;
import org.kohsuke.github.GHCommit.File;
import org.kohsuke.github.GHOrganization.Permission;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Pattern;
/**
* Unit test for simple App.
@@ -82,6 +78,51 @@ public class AppTest extends AbstractGitHubApiTestBase {
o.close();
}
@Test
public void testCreateDeployment() throws IOException {
GHRepository repository = getTestRepository();
GHDeployment deployment = repository.createDeployment("master")
.payload("{\"user\":\"atmos\",\"room_id\":123456}")
.description("question")
.create();
assertNotNull(deployment.getCreator());
assertNotNull(deployment.getId());
}
@Test
public void testListDeployments() throws IOException {
GHRepository repository = getTestRepository();
GHDeployment deployment = repository.createDeployment("master")
.payload("{\"user\":\"atmos\",\"room_id\":123456}")
.description("question")
.environment("unittest")
.create();
assertNotNull(deployment.getCreator());
assertNotNull(deployment.getId());
ArrayList<GHDeployment> deployments = Lists.newArrayList(repository.listDeployments(null, "master", null, "unittest"));
assertNotNull(deployments);
assertFalse(Iterables.isEmpty(deployments));
GHDeployment unitTestDeployment = deployments.get(0);
assertEquals("unittest",unitTestDeployment.getEnvironment());
assertEquals("master", unitTestDeployment.getRef());
}
@Test
public void testGetDeploymentStatuses() throws IOException {
GHRepository repository = getTestRepository();
GHDeployment deployment = repository.createDeployment("master")
.description("question")
.payload("{\"user\":\"atmos\",\"room_id\":123456}")
.create();
GHDeploymentStatus ghDeploymentStatus = repository.createDeployStatus(deployment.getId(), GHDeploymentState.SUCCESS)
.description("success")
.targetUrl("http://www.github.com").create();
Iterable<GHDeploymentStatus> deploymentStatuses = repository.getDeploymentStatuses(deployment.getId());
assertNotNull(deploymentStatuses);
assertEquals(1,Iterables.size(deploymentStatuses));
assertEquals(ghDeploymentStatus.getId(), Iterables.get(deploymentStatuses, 0).getId());
}
@Test
public void testGetIssues() throws Exception {
List<GHIssue> closedIssues = gitHub.getUser("kohsuke").getRepository("github-api").getIssues(GHIssueState.CLOSED);
@@ -243,7 +284,7 @@ public class AppTest extends AbstractGitHubApiTestBase {
@Test
public void testGetTeamsForRepo() throws Exception {
kohsuke();
assertEquals(1,gitHub.getOrganization("github-api-test-org").getRepository("testGetTeamsForRepo").getTeams().size());
assertEquals(1, gitHub.getOrganization("github-api-test-org").getRepository("testGetTeamsForRepo").getTeams().size());
}
@Test
@@ -266,7 +307,7 @@ public class AppTest extends AbstractGitHubApiTestBase {
assertNotNull(t.getName());
sz++;
}
assertTrue(sz<100);
assertTrue(sz < 100);
}
@Test
@@ -458,7 +499,7 @@ public class AppTest extends AbstractGitHubApiTestBase {
long start = System.currentTimeMillis();
Map<String, GHRepository> repos = j.getRepositories();
long end = System.currentTimeMillis();
System.out.printf("%d repositories in %dms\n",repos.size(),end-start);
System.out.printf("%d repositories in %dms\n", repos.size(), end - start);
}
@Test
@@ -484,7 +525,7 @@ public class AppTest extends AbstractGitHubApiTestBase {
state = lst.get(0);
System.out.println(state);
assertEquals("testing!",state.getDescription());
assertEquals("http://kohsuke.org/",state.getTargetUrl());
assertEquals("http://kohsuke.org/", state.getTargetUrl());
}
@Test
@@ -600,6 +641,74 @@ public class AppTest extends AbstractGitHubApiTestBase {
}
@Test
public void testMemberPagenation() throws IOException {
Set<GHUser> all = new HashSet<GHUser>();
for (GHUser u : gitHub.getOrganization("github-api-test-org").getTeamByName("Core Developers").listMembers()) {
System.out.println(u.getLogin());
all.add(u);
}
assertFalse(all.isEmpty());
}
@Test
public void testIssueSearch() throws IOException {
PagedSearchIterable<GHIssue> r = gitHub.searchIssues().mentions("kohsuke").isOpen().list();
for (GHIssue i : r) {
System.out.println(i.getTitle());
}
}
@Test // issue #99
public void testReadme() throws IOException {
GHContent readme = gitHub.getRepository("github-api-test-org/test-readme").getReadme();
assertEquals(readme.getName(),"README.md");
assertEquals(readme.getContent(),"This is a markdown readme.\n");
}
@Test
public void testRepoLabel() throws IOException {
GHRepository r = gitHub.getRepository("github-api-test-org/test-labels");
List<GHLabel> lst = r.listLabels().asList();
for (GHLabel l : lst) {
System.out.println(l.getName());
}
assertTrue(lst.size() > 5);
GHLabel e = r.getLabel("enhancement");
assertEquals("enhancement",e.getName());
assertNotNull(e.getUrl());
assertTrue(Pattern.matches("[0-9a-fA-F]{6}",e.getColor()));
{// CRUD
GHLabel t = r.createLabel("test", "123456");
GHLabel t2 = r.getLabel("test");
assertEquals(t.getName(), t2.getName());
assertEquals(t.getColor(), "123456");
assertEquals(t.getColor(), t2.getColor());
assertEquals(t.getUrl(), t2.getUrl());
t.delete();
}
}
@Test
public void testSubscribers() throws IOException {
boolean kohsuke = false;
GHRepository mr = gitHub.getRepository("kohsuke/github-api");
for (GHUser u : mr.listSubscribers()) {
System.out.println(u.getLogin());
kohsuke |= u.getLogin().equals("kohsuke");
}
assertTrue(kohsuke);
System.out.println("---");
boolean githubApi = false;
for (GHRepository r : gitHub.getUser("kohsuke").listRepositories()) {
System.out.println(r.getName());
githubApi |= r.equals(mr);
}
assertTrue(githubApi);
}
private void kohsuke() {
String login = getUser().getLogin();
Assume.assumeTrue(login.equals("kohsuke") || login.equals("kohsuke2"));

View File

@@ -0,0 +1,16 @@
package org.kohsuke.github;
import org.junit.Test;
import java.io.IOException;
/**
* @author Kohsuke Kawaguchi
*/
public class CommitTest extends AbstractGitHubApiTestBase {
@Test // issue 152
public void lastStatus() throws IOException {
GHTag t = gitHub.getRepository("stapler/stapler").listTags().iterator().next();
t.getCommit().getLastStatus();
}
}

View File

@@ -1,5 +1,12 @@
package org.kohsuke.github;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import junit.framework.TestCase;
/**
@@ -21,4 +28,85 @@ public class GitHubTest extends TestCase {
GitHub hub = GitHub.connectUsingPassword("kohsuke", "bogus");
assertEquals("https://api.github.com/test", hub.getApiURL("/test").toString());
}
public void testGitHubBuilderFromEnvironment() throws IOException {
Map<String, String>props = new HashMap<String, String>();
props.put("login", "bogus");
props.put("oauth", "bogus");
props.put("password", "bogus");
setupEnvironment(props);
GitHubBuilder builder = GitHubBuilder.fromEnvironment();
assertEquals("bogus", builder.user);
assertEquals("bogus", builder.oauthToken);
assertEquals("bogus", builder.password);
}
/*
* Copied from StackOverflow: http://stackoverflow.com/a/7201825/2336755
*
* This allows changing the in memory process environment.
*
* Its used to wire in values for the github credentials to test that the GitHubBuilder works properly to resolve them.
*/
private void setupEnvironment(Map<String, String> newenv) {
try
{
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
theEnvironmentField.setAccessible(true);
Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
env.putAll(newenv);
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
theCaseInsensitiveEnvironmentField.setAccessible(true);
Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
cienv.putAll(newenv);
}
catch (NoSuchFieldException e)
{
try {
Class[] classes = Collections.class.getDeclaredClasses();
Map<String, String> env = System.getenv();
for(Class cl : classes) {
if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Object obj = field.get(env);
Map<String, String> map = (Map<String, String>) obj;
map.clear();
map.putAll(newenv);
}
}
} catch (Exception e2) {
e2.printStackTrace();
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
public void testGitHubBuilderFromCustomEnvironment() throws IOException {
Map<String, String>props = new HashMap<String, String>();
props.put("customLogin", "bogusLogin");
props.put("customOauth", "bogusOauth");
props.put("customPassword", "bogusPassword");
setupEnvironment(props);
GitHubBuilder builder = GitHubBuilder.fromEnvironment("customLogin", "customPassword", "customOauth");
assertEquals("bogusLogin", builder.user);
assertEquals("bogusOauth", builder.oauthToken);
assertEquals("bogusPassword", builder.password);
}
}

View File

@@ -1,18 +1,67 @@
package org.kohsuke.github;
import org.junit.After;
import org.junit.Test;
import java.io.IOException;
import java.util.Collection;
/**
* @author Kohsuke Kawaguchi
*/
public class PullRequestTest extends AbstractGitHubApiTestBase {
@Test
public void createPullRequest() throws Exception {
GHRepository j = gitHub.getOrganization("github-api-test-org").getRepository("jenkins");
String name = rnd.next();
GHPullRequest p = j.createPullRequest(name, "stable", "master", "## test");
GHPullRequest p = getRepository().createPullRequest(name, "stable", "master", "## test");
System.out.println(p.getUrl());
assertEquals(name, p.getTitle());
p.close();
}
@Test // Requires push access to the test repo to pass
public void setLabels() throws Exception {
GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test");
String label = rnd.next();
p.setLabels(label);
Collection<GHLabel> labels = getRepository().getPullRequest(p.getNumber()).getLabels();
assertEquals(1, labels.size());
assertEquals(label, labels.iterator().next().getName());
}
@Test // Requires push access to the test repo to pass
public void setAssignee() throws Exception {
GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test");
GHMyself user = gitHub.getMyself();
p.assignTo(user);
assertEquals(user, getRepository().getPullRequest(p.getNumber()).getAssignee());
}
@Test
public void testGetUser() throws IOException {
GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test");
GHPullRequest prSingle = getRepository().getPullRequest(p.getNumber());
assertNotNull(prSingle.getUser().root);
prSingle.getMergeable();
assertNotNull(prSingle.getUser().root);
PagedIterable<GHPullRequest> ghPullRequests = getRepository().listPullRequests(GHIssueState.OPEN);
for (GHPullRequest pr : ghPullRequests) {
assertNotNull(pr.getUser().root);
assertFalse(pr.getMergeable());
assertNotNull(pr.getUser().root);
}
}
@After
public void cleanUp() throws Exception {
for (GHPullRequest pr : getRepository().getPullRequests(GHIssueState.OPEN)) {
pr.close();
}
}
private GHRepository getRepository() throws IOException {
return gitHub.getOrganization("github-api-test-org").getRepository("jenkins");
}
}

View File

@@ -0,0 +1,89 @@
package org.kohsuke.github;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.Iterator;
import static org.mockito.Mockito.when;
/**
* @author Luciano P. Sabenca (luciano.sabenca [at] movile [com] | lucianosabenca [at] gmail [dot] com
*/
public class RepositoryMockTest {
@Mock
GitHub mockGitHub;
@Mock
Iterator<GHUser[]> iterator;
@Mock
GHRepository mockRepository;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void listCollaborators() throws Exception {
GHUser user1 = new GHUser();
user1.login = "login1";
GHUser user2 = new GHUser();
user2.login = "login2";
when(iterator.hasNext()).thenReturn(true, false, true);
when(iterator.next()).thenReturn(new GHUser[]{user1}, new GHUser[]{user2});
Requester requester = Mockito.mock(Requester.class);
when(mockGitHub.retrieve()).thenReturn(requester);
when(requester.asIterator("/repos/*/*/collaborators",
GHUser[].class)).thenReturn(iterator, iterator);
PagedIterable<GHUser> pagedIterable = Mockito.mock(PagedIterable.class);
when(mockRepository.listCollaborators()).thenReturn(pagedIterable);
PagedIterator<GHUser> userPagedIterator = new PagedIterator<GHUser>(iterator) {
@Override
protected void wrapUp(GHUser[] page) {
}
};
PagedIterator<GHUser> userPagedIterator2 = new PagedIterator<GHUser>(iterator) {
@Override
protected void wrapUp(GHUser[] page) {
}
};
when(pagedIterable.iterator()).thenReturn(userPagedIterator, userPagedIterator2);
Iterator<GHUser> returnIterator1 = mockRepository.listCollaborators().iterator();
Assert.assertTrue(returnIterator1.hasNext());
GHUser user = returnIterator1.next();
Assert.assertEquals(user, user1);
Assert.assertFalse(returnIterator1.hasNext());
Iterator returnIterator2 = mockRepository.listCollaborators().iterator();
Assert.assertTrue(returnIterator2.hasNext());
user = returnIterator1.next();
Assert.assertEquals(user, user2);
}
}

View File

@@ -1,91 +1,46 @@
package org.kohsuke.github;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.kohsuke.github.GHRepository.Contributor;
import java.util.Iterator;
import static org.mockito.Mockito.when;
import java.io.IOException;
/**
* @author Luciano P. Sabenca (luciano.sabenca [at] movile [com] | lucianosabenca [at] gmail [dot] com
* @author Kohsuke Kawaguchi
*/
public class RepositoryTest {
public class RepositoryTest extends AbstractGitHubApiTestBase {
@Test
public void subscription() throws Exception {
GHRepository r = getRepository();
assertNull(r.getSubscription());
@Mock
GitHub mockGitHub;
GHSubscription s = r.subscribe(true, false);
assertEquals(s.getRepository(), r);
@Mock
Iterator<GHUser[]> iterator;
s.delete();
@Mock
GHRepository mockRepository;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
assertNull(r.getSubscription());
}
@Test
public void listCollaborators() throws Exception {
GHUser user1 = new GHUser();
user1.login = "login1";
public void listContributors() throws IOException {
GHRepository r = gitHub.getOrganization("stapler").getRepository("stapler");
int i=0;
boolean kohsuke = false;
GHUser user2 = new GHUser();
user2.login = "login2";
when(iterator.hasNext()).thenReturn(true, false, true);
when(iterator.next()).thenReturn(new GHUser[]{user1}, new GHUser[]{user2});
Requester requester = Mockito.mock(Requester.class);
when(mockGitHub.retrieve()).thenReturn(requester);
when(requester.asIterator("/repos/*/*/collaborators",
GHUser[].class)).thenReturn(iterator, iterator);
PagedIterable<GHUser> pagedIterable = Mockito.mock(PagedIterable.class);
when(mockRepository.listCollaborators()).thenReturn(pagedIterable);
PagedIterator<GHUser> userPagedIterator = new PagedIterator<GHUser>(iterator) {
@Override
protected void wrapUp(GHUser[] page) {
}
};
PagedIterator<GHUser> userPagedIterator2 = new PagedIterator<GHUser>(iterator) {
@Override
protected void wrapUp(GHUser[] page) {
}
};
when(pagedIterable.iterator()).thenReturn(userPagedIterator, userPagedIterator2);
Iterator<GHUser> returnIterator1 = mockRepository.listCollaborators().iterator();
Assert.assertTrue(returnIterator1.hasNext());
GHUser user = returnIterator1.next();
Assert.assertEquals(user, user1);
Assert.assertFalse(returnIterator1.hasNext());
Iterator returnIterator2 = mockRepository.listCollaborators().iterator();
Assert.assertTrue(returnIterator2.hasNext());
user = returnIterator1.next();
Assert.assertEquals(user, user2);
for (Contributor c : r.listContributors()) {
System.out.println(c.getName());
assertTrue(c.getContributions()>0);
if (c.getLogin().equals("kohsuke"))
kohsuke = true;
if (i++ > 5)
break;
}
assertTrue(kohsuke);
}
private GHRepository getRepository() throws IOException {
return gitHub.getOrganization("github-api-test-org").getRepository("jenkins");
}
}