Compare commits

..

25 Commits

Author SHA1 Message Date
Kohsuke Kawaguchi
7b4d3a869b [maven-release-plugin] prepare release github-api-1.68 2015-04-19 17:40:35 -07:00
Kohsuke Kawaguchi
eeebb1b59f Added the 'sha' parameter.
Fixes issue #176
2015-04-19 17:25:13 -07:00
Julien HENRY
63136f64b7 Merge pull request #174
The merge was done manually because the original commit contains lots of
whitespace only changes.
2015-04-19 17:22:04 -07:00
Kohsuke Kawaguchi
1d2fbf2d92 Merge pull request #179 from lskillen/master
Fix NullPointerException on RateLimitHandler when handling API errors.
2015-04-19 17:03:50 -07:00
Kohsuke Kawaguchi
1e52dded14 Added a helper method 2015-04-15 08:33:18 -07:00
Lee Skillen
cfc7005275 Fix NullPointerException on RateLimiter when handling API errors. 2015-04-14 14:45:47 +01:00
Kohsuke Kawaguchi
f23afcd5aa [maven-release-plugin] prepare for next development iteration 2015-04-13 18:30:43 -07:00
Kohsuke Kawaguchi
4e88a0c91b [maven-release-plugin] prepare release github-api-1.67 2015-04-13 18:30:40 -07:00
Kohsuke Kawaguchi
d070f9deb0 TAB -> WS 2015-04-13 18:25:44 -07:00
Kohsuke Kawaguchi
b736e20a74 Added more getHtmlUrl() methods 2015-04-13 18:17:37 -07:00
Kohsuke Kawaguchi
aad20d0a03 Merge pull request #169 from KostyaSha/fixAuthLoop
Throw error for bad creds
2015-04-13 16:55:58 -07:00
Kohsuke Kawaguchi
7ff97348d9 Merge pull request #170 from KostyaSha/coverity
Improvements
2015-04-13 16:55:24 -07:00
Kohsuke Kawaguchi
68dda3a46d Merge pull request #175 2015-04-13 16:47:32 -07:00
Kohsuke Kawaguchi
2cd44f8c33 Added the pair method 2015-04-13 16:47:25 -07:00
Kohsuke Kawaguchi
9775954aff Massaging the PR.
- need to retrieve the object in full to have all the fields properly populated
- documentation fix, as this method points to the root of the forking chain, not just an upstream.
2015-04-13 16:45:38 -07:00
Kohsuke Kawaguchi
1a071b0b54 Returning null instead of throwing an exception (as a matter of taste) 2015-04-13 16:39:20 -07:00
Kohsuke Kawaguchi
8dcea59c74 Fixed javadoc errors 2015-04-13 16:36:14 -07:00
Kohsuke Kawaguchi
f482f77871 Merge pull request #177 from infm/feat/notif
Added getters for the objects notifications refer to
2015-04-13 16:38:22 -07:00
infm
b058c39ee1 Added getters for the objects notifications refer to 2015-04-09 01:21:38 +03:00
Jason Nichols
b926b6c67f Added the source attribute to GHRepository 2015-04-02 14:54:13 -04:00
Kohsuke Kawaguchi
3fb8e5f799 [maven-release-plugin] prepare for next development iteration 2015-03-24 10:26:48 -07:00
Kanstantsin Shautsou
9ebc9c0867 Use FAIL rate-limit handler for tests
Should avoid possible Thread.sleep() for tests execution.
2015-03-23 21:14:42 +03:00
Kanstantsin Shautsou
f1f96713a4 [CID-107552] Unintended regular expression
regex_expected: The . character(s) in the pattern ".md" can match any character, because calls to replaceAll treat the pattern as a regular expression, which might be unexpected.
2015-03-23 02:35:55 +03:00
Kanstantsin Shautsou
fc3b6d2c2e [CID-107535] Missing call to superclass
Similar to other events
2015-03-23 02:23:44 +03:00
Kanstantsin Shautsou
d0d0716b3b Throw error for bad creds 2015-03-23 02:09:23 +03:00
33 changed files with 1004 additions and 585 deletions

View File

@@ -7,7 +7,7 @@
</parent> </parent>
<artifactId>github-api</artifactId> <artifactId>github-api</artifactId>
<version>1.66</version> <version>1.68</version>
<name>GitHub API for Java</name> <name>GitHub API for Java</name>
<url>http://github-api.kohsuke.org/</url> <url>http://github-api.kohsuke.org/</url>
<description>GitHub API for Java</description> <description>GitHub API for Java</description>
@@ -16,7 +16,7 @@
<connection>scm:git:git@github.com/kohsuke/${project.artifactId}.git</connection> <connection>scm:git:git@github.com/kohsuke/${project.artifactId}.git</connection>
<developerConnection>scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git</developerConnection> <developerConnection>scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git</developerConnection>
<url>http://${project.artifactId}.kohsuke.org/</url> <url>http://${project.artifactId}.kohsuke.org/</url>
<tag>github-api-1.66</tag> <tag>github-api-1.68</tag>
</scm> </scm>
<distributionManagement> <distributionManagement>

View File

@@ -1,6 +1,7 @@
package org.kohsuke.github; package org.kohsuke.github;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
/** /**
* Asset in a release. * Asset in a release.
@@ -60,6 +61,14 @@ public class GHAsset extends GHObject {
return state; return state;
} }
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
public String getBrowserDownloadUrl() { public String getBrowserDownloadUrl() {
return browser_download_url; return browser_download_url;
} }

View File

@@ -10,78 +10,83 @@ import java.util.List;
* *
* @author janinko * @author janinko
* @see GitHub#createToken(Collection, String, String) * @see GitHub#createToken(Collection, String, String)
* @see http://developer.github.com/v3/oauth/#create-a-new-authorization * @see <a href="http://developer.github.com/v3/oauth/#create-a-new-authorization">API documentation</a>
*/ */
public class GHAuthorization extends GHObject { public class GHAuthorization extends GHObject {
public static final String USER = "user"; public static final String USER = "user";
public static final String USER_EMAIL = "user:email"; public static final String USER_EMAIL = "user:email";
public static final String USER_FOLLOW = "user:follow"; public static final String USER_FOLLOW = "user:follow";
public static final String PUBLIC_REPO = "public_repo"; public static final String PUBLIC_REPO = "public_repo";
public static final String REPO = "repo"; public static final String REPO = "repo";
public static final String REPO_STATUS = "repo:status"; public static final String REPO_STATUS = "repo:status";
public static final String DELETE_REPO = "delete_repo"; public static final String DELETE_REPO = "delete_repo";
public static final String NOTIFICATIONS = "notifications"; public static final String NOTIFICATIONS = "notifications";
public static final String GIST = "gist"; public static final String GIST = "gist";
public static final String READ_HOOK = "read:repo_hook"; public static final String READ_HOOK = "read:repo_hook";
public static final String WRITE_HOOK = "write:repo_hook"; public static final String WRITE_HOOK = "write:repo_hook";
public static final String AMIN_HOOK = "admin:repo_hook"; public static final String AMIN_HOOK = "admin:repo_hook";
public static final String READ_ORG = "read:org"; public static final String READ_ORG = "read:org";
public static final String WRITE_ORG = "write:org"; public static final String WRITE_ORG = "write:org";
public static final String ADMIN_ORG = "admin:org"; public static final String ADMIN_ORG = "admin:org";
public static final String READ_KEY = "read:public_key"; public static final String READ_KEY = "read:public_key";
public static final String WRITE_KEY = "write:public_key"; public static final String WRITE_KEY = "write:public_key";
public static final String ADMIN_KEY = "admin:public_key"; public static final String ADMIN_KEY = "admin:public_key";
private GitHub root; private GitHub root;
private List<String> scopes; private List<String> scopes;
private String token; private String token;
private App app; private App app;
private String note; private String note;
private String note_url; private String note_url;
public GitHub getRoot() { public GitHub getRoot() {
return root; return root;
} }
public List<String> getScopes() { public List<String> getScopes() {
return scopes; return scopes;
} }
public String getToken(){ public String getToken() {
return token; return token;
} }
public URL getAppUrl(){ public URL getAppUrl() {
return GitHub.parseURL(app.url); return GitHub.parseURL(app.url);
} }
public String getAppName() { public String getAppName() {
return app.name; return app.name;
} }
public URL getApiURL(){ public URL getApiURL() {
return GitHub.parseURL(url); return GitHub.parseURL(url);
} }
public String getNote() { /**
return note; * @deprecated This object has no HTML URL.
} */
@Override
public URL getHtmlUrl() {
return null;
}
public URL getNoteUrl(){ public String getNote() {
return note;
}
public URL getNoteUrl() {
return GitHub.parseURL(note_url); return GitHub.parseURL(note_url);
} }
/*package*/ GHAuthorization wrap(GitHub root) { /*package*/ GHAuthorization wrap(GitHub root) {
this.root = root; this.root = root;
return this; return this;
} }
private static class App {
private String url;
private String name;
private static class App{ }
private String url;
private String name;
}
} }

View File

@@ -32,26 +32,26 @@ public class GHCommit {
private int comment_count; private int comment_count;
@WithBridgeMethods(value=GHAuthor.class,castRequired=true) @WithBridgeMethods(value = GHAuthor.class, castRequired = true)
public GitUser getAuthor() { public GitUser getAuthor() {
return author; return author;
} }
@WithBridgeMethods(value=GHAuthor.class,castRequired=true) @WithBridgeMethods(value = GHAuthor.class, castRequired = true)
public GitUser getCommitter() { public GitUser getCommitter() {
return committer; return committer;
} }
/** /**
* Commit message. * Commit message.
*/ */
public String getMessage() { public String getMessage() {
return message; return message;
} }
public int getCommentCount() { public int getCommentCount() {
return comment_count; return comment_count;
} }
} }
/** /**
@@ -153,14 +153,13 @@ public class GHCommit {
Stats stats; Stats stats;
List<Parent> parents; List<Parent> parents;
User author,committer; User author,committer;
public ShortInfo getCommitShortInfo() { public ShortInfo getCommitShortInfo() {
return commit; return commit;
} }
/** /**
* The repository that contains the commit. * The repository that contains the commit.
*/ */
public GHRepository getOwner() { public GHRepository getOwner() {

View File

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

View File

@@ -1,14 +1,15 @@
package org.kohsuke.github; package org.kohsuke.github;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.util.Date; import java.util.Date;
/** /**
* Represents a status of a commit. * Represents a status of a commit.
* *
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
* @see GHRepository#getCommitStatus(String) * @see GHRepository#getLastCommitStatus(String)
* @see GHCommit#getStatus() * @see GHCommit#getLastStatus()
*/ */
public class GHCommitStatus extends GHObject { public class GHCommitStatus extends GHObject {
String state; String state;
@@ -49,7 +50,15 @@ public class GHCommitStatus extends GHObject {
return creator; return creator;
} }
public String getContext() { public String getContext() {
return context; return context;
} }
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
} }

View File

@@ -70,10 +70,10 @@ public class GHCompare {
} }
public GHCommit.File[] getFiles() { public GHCommit.File[] getFiles() {
return files; return files;
} }
public GHCompare wrap(GHRepository owner) { public GHCompare wrap(GHRepository owner) {
this.owner = owner; this.owner = owner;
for (Commit commit : commits) { for (Commit commit : commits) {
commit.wrapUp(owner); commit.wrapUp(owner);

View File

@@ -9,7 +9,7 @@ public class GHDeployKey {
protected String url, key, title; protected String url, key, title;
protected boolean verified; protected boolean verified;
protected int id; protected int id;
private GHRepository owner; private GHRepository owner;
public int getId() { public int getId() {
return id; return id;
@@ -31,10 +31,10 @@ public class GHDeployKey {
return verified; return verified;
} }
public GHDeployKey wrap(GHRepository repo) { public GHDeployKey wrap(GHRepository repo) {
this.owner = repo; this.owner = repo;
return this; return this;
} }
public String toString() { public String toString() {
return new ToStringBuilder(this).append("title",title).append("id",id).append("key",key).toString(); return new ToStringBuilder(this).append("title",title).append("id",id).append("key",key).toString();

View File

@@ -50,4 +50,12 @@ public class GHDeployment extends GHObject {
public String getSha(){ public String getSha(){
return sha; return sha;
} }
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
} }

View File

@@ -32,5 +32,11 @@ public class GHDeploymentStatus extends GHObject {
return GHDeploymentState.valueOf(state.toUpperCase()); return GHDeploymentState.valueOf(state.toUpperCase());
} }
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
} }

View File

@@ -165,6 +165,7 @@ public abstract class GHEventPayload {
@Override @Override
void wrapUp(GitHub root) { void wrapUp(GitHub root) {
super.wrapUp(root);
if (repository!=null) if (repository!=null)
repository.wrap(root); repository.wrap(root);
} }

View File

@@ -3,6 +3,7 @@ package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -60,8 +61,8 @@ public class GHGist extends GHObject {
return git_push_url; return git_push_url;
} }
public String getHtmlUrl() { public URL getHtmlUrl() {
return html_url; return GitHub.parseURL(html_url);
} }
public boolean isPublic() { public boolean isPublic() {

View File

@@ -1,6 +1,7 @@
package org.kohsuke.github; package org.kohsuke.github;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
@@ -51,4 +52,12 @@ public class GHHook extends GHObject {
public void delete() throws IOException { public void delete() throws IOException {
new Requester(repository.root).method("DELETE").to(String.format("/repos/%s/%s/hooks/%d", repository.getOwnerName(), repository.getName(), id)); new Requester(repository.root).method("DELETE").to(String.format("/repos/%s/%s/hooks/%d", repository.getOwnerName(), repository.getName(), id));
} }
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
} }

View File

@@ -44,8 +44,8 @@ import java.util.Locale;
public class GHIssue extends GHObject { public class GHIssue extends GHObject {
GitHub root; GitHub root;
GHRepository owner; GHRepository owner;
// API v3 // API v3
protected GHUser assignee; protected GHUser assignee;
protected String state; protected String state;
protected int number; protected int number;
@@ -74,9 +74,9 @@ public class GHIssue extends GHObject {
/*package*/ GHIssue wrap(GitHub root) { /*package*/ GHIssue wrap(GitHub root) {
this.root = root; this.root = root;
if(assignee != null) assignee.wrapUp(root); if(assignee != null) assignee.wrapUp(root);
if(user != null) user.wrapUp(root); if(user != null) user.wrapUp(root);
if(closed_by != null) closed_by.wrapUp(root); if(closed_by != null) closed_by.wrapUp(root);
return this; return this;
} }
@@ -134,9 +134,9 @@ public class GHIssue extends GHObject {
return GitHub.parseDate(closed_at); return GitHub.parseDate(closed_at);
} }
public URL getApiURL(){ public URL getApiURL(){
return GitHub.parseURL(url); return GitHub.parseURL(url);
} }
/** /**
* Updates the issue by adding a comment. * Updates the issue by adding a comment.
@@ -185,16 +185,16 @@ public class GHIssue extends GHObject {
/** /**
* Obtains all the comments associated with this issue. * Obtains all the comments associated with this issue.
* *
* @see #listComments() * @see #listComments()
*/
public List<GHIssueComment> getComments() throws IOException {
return listComments().asList();
}
/**
* Obtains all the comments associated with this issue.
*/ */
public List<GHIssueComment> getComments() throws IOException {
return listComments().asList();
}
/**
* Obtains all the comments associated with this issue.
*/
public PagedIterable<GHIssueComment> listComments() throws IOException { public PagedIterable<GHIssueComment> listComments() throws IOException {
return new PagedIterable<GHIssueComment>() { return new PagedIterable<GHIssueComment>() {
public PagedIterator<GHIssueComment> iterator() { public PagedIterator<GHIssueComment> iterator() {
@@ -216,16 +216,16 @@ public class GHIssue extends GHObject {
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/issues/"+number; return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/issues/"+number;
} }
public GHUser getAssignee() { public GHUser getAssignee() {
return assignee; return assignee;
} }
/** /**
* User who submitted the issue. * User who submitted the issue.
*/ */
public GHUser getUser() { public GHUser getUser() {
return user; return user;
} }
/** /**
* Reports who has closed the issue. * Reports who has closed the issue.
@@ -235,46 +235,46 @@ public class GHIssue extends GHObject {
* even for an issue that's already closed. See * even for an issue that's already closed. See
* https://github.com/kohsuke/github-api/issues/60. * https://github.com/kohsuke/github-api/issues/60.
*/ */
public GHUser getClosedBy() { public GHUser getClosedBy() {
if(!"closed".equals(state)) return null; if(!"closed".equals(state)) return null;
if(closed_by != null) return closed_by; if(closed_by != null) return closed_by;
//TODO closed_by = owner.getIssue(number).getClosed_by(); //TODO closed_by = owner.getIssue(number).getClosed_by();
return closed_by; return closed_by;
} }
public int getCommentsCount(){ public int getCommentsCount(){
return comments; return comments;
} }
/** /**
* Returns non-null if this issue is a shadow of a pull request. * Returns non-null if this issue is a shadow of a pull request.
*/ */
public PullRequest getPullRequest() { public PullRequest getPullRequest() {
return pull_request; return pull_request;
} }
public boolean isPullRequest() { public boolean isPullRequest() {
return pull_request!=null; return pull_request!=null;
} }
public GHMilestone getMilestone() { public GHMilestone getMilestone() {
return milestone; return milestone;
} }
public static class PullRequest{ public static class PullRequest{
private String diff_url, patch_url, html_url; private String diff_url, patch_url, html_url;
public URL getDiffUrl() { public URL getDiffUrl() {
return GitHub.parseURL(diff_url); return GitHub.parseURL(diff_url);
} }
public URL getPatchUrl() { public URL getPatchUrl() {
return GitHub.parseURL(patch_url); return GitHub.parseURL(patch_url);
} }
public URL getUrl() { public URL getUrl() {
return GitHub.parseURL(html_url); return GitHub.parseURL(html_url);
} }
} }
} }

View File

@@ -71,4 +71,12 @@ public class GHIssueComment extends GHObject {
public GHUser getUser() throws IOException { public GHUser getUser() throws IOException {
return owner.root.getUser(user.getLogin()); return owner.root.getUser(user.getLogin());
} }
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
} }

View File

@@ -1,6 +1,7 @@
package org.kohsuke.github; package org.kohsuke.github;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.util.Date; import java.util.Date;
import java.util.Locale; import java.util.Locale;
@@ -11,52 +12,56 @@ import java.util.Locale;
*/ */
public class GHMilestone extends GHObject { public class GHMilestone extends GHObject {
GitHub root; GitHub root;
GHRepository owner; GHRepository owner;
GHUser creator; GHUser creator;
private String state, due_on, title, description; private String state, due_on, title, description, html_url;
private int closed_issues, open_issues, number; private int closed_issues, open_issues, number;
public GitHub getRoot() { public GitHub getRoot() {
return root; return root;
} }
public GHRepository getOwner() { public GHRepository getOwner() {
return owner; return owner;
} }
public GHUser getCreator() { public GHUser getCreator() {
return creator; return creator;
} }
public Date getDueOn() { public Date getDueOn() {
if (due_on == null) return null; if (due_on == null) return null;
return GitHub.parseDate(due_on); return GitHub.parseDate(due_on);
} }
public String getTitle() { public String getTitle() {
return title; return title;
} }
public String getDescription() { public String getDescription() {
return description; return description;
} }
public int getClosedIssues() { public int getClosedIssues() {
return closed_issues; return closed_issues;
} }
public int getOpenIssues() { public int getOpenIssues() {
return open_issues; return open_issues;
} }
public int getNumber() { public int getNumber() {
return number; return number;
} }
public GHMilestoneState getState() { public URL getHtmlUrl() {
return Enum.valueOf(GHMilestoneState.class, state.toUpperCase(Locale.ENGLISH)); return GitHub.parseURL(html_url);
} }
public GHMilestoneState getState() {
return Enum.valueOf(GHMilestoneState.class, state.toUpperCase(Locale.ENGLISH));
}
/** /**
* Closes this issue. * Closes this issue.
@@ -73,9 +78,9 @@ public class GHMilestone extends GHObject {
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/milestones/"+number; return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/milestones/"+number;
} }
public GHMilestone wrap(GHRepository repo) { public GHMilestone wrap(GHRepository repo) {
this.owner = repo; this.owner = repo;
this.root = repo.root; this.root = repo.root;
return this; return this;
} }
} }

View File

@@ -38,6 +38,12 @@ public abstract class GHObject {
return GitHub.parseURL(url); return GitHub.parseURL(url);
} }
/**
* URL of this object for humans, which renders some HTML.
*/
@WithBridgeMethods(value=String.class, adapterMethod="urlToString")
public abstract URL getHtmlUrl();
/** /**
* When was this resource last updated? * When was this resource last updated?
*/ */

View File

@@ -2,6 +2,7 @@ package org.kohsuke.github;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
@@ -214,8 +215,9 @@ public abstract class GHPerson extends GHObject {
return blog; return blog;
} }
public String getHtmlUrl() { @Override
return html_url; public URL getHtmlUrl() {
return GitHub.parseURL(html_url);
} }
/** /**

View File

@@ -27,7 +27,6 @@ import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.Locale;
/** /**
* A pull request. * A pull request.
@@ -37,20 +36,20 @@ import java.util.Locale;
*/ */
@SuppressWarnings({"UnusedDeclaration"}) @SuppressWarnings({"UnusedDeclaration"})
public class GHPullRequest extends GHIssue { public class GHPullRequest extends GHIssue {
private String patch_url, diff_url, issue_url; private String patch_url, diff_url, issue_url;
private GHCommitPointer base; private GHCommitPointer base;
private String merged_at; private String merged_at;
private GHCommitPointer head; private GHCommitPointer head;
// details that are only available when obtained from ID // details that are only available when obtained from ID
private GHUser merged_by; private GHUser merged_by;
private int review_comments, additions; private int review_comments, additions;
private boolean merged; private boolean merged;
private Boolean mergeable; private Boolean mergeable;
private int deletions; private int deletions;
private String mergeable_state; private String mergeable_state;
private int changed_files; private int changed_files;
/** /**
* GitHub doesn't return some properties of {@link GHIssue} when requesting the GET on the 'pulls' API * GitHub doesn't return some properties of {@link GHIssue} when requesting the GET on the 'pulls' API
@@ -60,15 +59,15 @@ public class GHPullRequest extends GHIssue {
private transient boolean fetchedIssueDetails; private transient boolean fetchedIssueDetails;
GHPullRequest wrapUp(GHRepository owner) { GHPullRequest wrapUp(GHRepository owner) {
this.wrap(owner); this.wrap(owner);
return wrapUp(owner.root); return wrapUp(owner.root);
} }
GHPullRequest wrapUp(GitHub root) { GHPullRequest wrapUp(GitHub root) {
if (owner!=null) owner.wrap(root); if (owner != null) owner.wrap(root);
if (base!=null) base.wrapUp(root); if (base != null) base.wrapUp(root);
if (head!=null) head.wrapUp(root); if (head != null) head.wrapUp(root);
if (merged_by != null) merged_by.wrapUp(root); if (merged_by != null) merged_by.wrapUp(root);
return this; return this;
} }
@@ -85,8 +84,8 @@ public class GHPullRequest extends GHIssue {
public URL getPatchUrl() { public URL getPatchUrl() {
return GitHub.parseURL(patch_url); return GitHub.parseURL(patch_url);
} }
/** /**
* The URL of the patch file. * The URL of the patch file.
* like https://github.com/jenkinsci/jenkins/pull/100.patch * like https://github.com/jenkinsci/jenkins/pull/100.patch
*/ */
@@ -108,8 +107,8 @@ public class GHPullRequest extends GHIssue {
public GHCommitPointer getHead() { public GHCommitPointer getHead() {
return head; return head;
} }
@Deprecated @Deprecated
public Date getIssueUpdatedAt() throws IOException { public Date getIssueUpdatedAt() throws IOException {
return super.getUpdatedAt(); return super.getUpdatedAt();
} }
@@ -126,65 +125,65 @@ public class GHPullRequest extends GHIssue {
return GitHub.parseDate(merged_at); return GitHub.parseDate(merged_at);
} }
@Override @Override
public Collection<GHLabel> getLabels() throws IOException { public Collection<GHLabel> getLabels() throws IOException {
fetchIssue(); fetchIssue();
return super.getLabels(); return super.getLabels();
} }
@Override @Override
public GHUser getClosedBy() { public GHUser getClosedBy() {
return null; return null;
} }
@Override @Override
public PullRequest getPullRequest() { public PullRequest getPullRequest() {
return null; return null;
} }
// //
// details that are only available via get with ID // details that are only available via get with ID
// //
// //
public GHUser getMergedBy() throws IOException { public GHUser getMergedBy() throws IOException {
populate(); populate();
return merged_by; return merged_by;
} }
public int getReviewComments() throws IOException { public int getReviewComments() throws IOException {
populate(); populate();
return review_comments; return review_comments;
} }
public int getAdditions() throws IOException { public int getAdditions() throws IOException {
populate(); populate();
return additions; return additions;
} }
public boolean isMerged() throws IOException { public boolean isMerged() throws IOException {
populate(); populate();
return merged; return merged;
} }
public Boolean getMergeable() throws IOException { public Boolean getMergeable() throws IOException {
populate(); populate();
return mergeable; return mergeable;
} }
public int getDeletions() throws IOException { public int getDeletions() throws IOException {
populate(); populate();
return deletions; return deletions;
} }
public String getMergeableState() throws IOException { public String getMergeableState() throws IOException {
populate(); populate();
return mergeable_state; return mergeable_state;
} }
public int getChangedFiles() throws IOException { public int getChangedFiles() throws IOException {
populate(); populate();
return changed_files; return changed_files;
} }
/** /**
* Fully populate the data by retrieving missing data. * Fully populate the data by retrieving missing data.
@@ -197,6 +196,39 @@ public class GHPullRequest extends GHIssue {
root.retrieve().to(url, this).wrapUp(owner); root.retrieve().to(url, this).wrapUp(owner);
} }
/**
* Retrieves all the commits associated to this pull request.
*/
public PagedIterable<GHPullRequestFileDetail> listFiles() {
return new PagedIterable<GHPullRequestFileDetail>() {
public PagedIterator<GHPullRequestFileDetail> iterator() {
return new PagedIterator<GHPullRequestFileDetail>(root.retrieve().asIterator(String.format("%s/files", getApiURL()),
GHPullRequestFileDetail[].class)) {
@Override
protected void wrapUp(GHPullRequestFileDetail[] page) {
}
};
}
};
}
/**
* Obtains all the review comments associated with this pull request.
*/
public PagedIterable<GHPullRequestReviewComment> listReviewComments() throws IOException {
return new PagedIterable<GHPullRequestReviewComment>() {
public PagedIterator<GHPullRequestReviewComment> iterator() {
return new PagedIterator<GHPullRequestReviewComment>(root.retrieve().asIterator(getApiRoute() + "/comments",
GHPullRequestReviewComment[].class)) {
protected void wrapUp(GHPullRequestReviewComment[] page) {
for (GHPullRequestReviewComment c : page)
c.wrapUp(GHPullRequest.this);
}
};
}
};
}
/** /**
* Retrieves all the commits associated to this pull request. * Retrieves all the commits associated to this pull request.
*/ */
@@ -208,12 +240,23 @@ public class GHPullRequest extends GHIssue {
GHPullRequestCommitDetail[].class)) { GHPullRequestCommitDetail[].class)) {
@Override @Override
protected void wrapUp(GHPullRequestCommitDetail[] page) { protected void wrapUp(GHPullRequestCommitDetail[] page) {
for (GHPullRequestCommitDetail c : page)
c.wrapUp(GHPullRequest.this);
} }
}; };
} }
}; };
} }
public GHPullRequestReviewComment createReviewComment(String body, String sha, String path, int position) throws IOException {
return new Requester(root).method("POST")
.with("body", body)
.with("commit_id", sha)
.with("path", path)
.with("position", position)
.to(getApiRoute() + "/comments", GHPullRequestReviewComment.class).wrapUp(this);
}
/** /**
* Merge this pull request. * Merge this pull request.
* *
@@ -223,7 +266,21 @@ public class GHPullRequest extends GHIssue {
* Commit message. If null, the default one will be used. * Commit message. If null, the default one will be used.
*/ */
public void merge(String msg) throws IOException { public void merge(String msg) throws IOException {
new Requester(root).method("PUT").with("commit_message",msg).to(getApiRoute()+"/merge"); merge(msg,null);
}
/**
* Merge this pull request.
*
* The equivalent of the big green "Merge pull request" button.
*
* @param msg
* Commit message. If null, the default one will be used.
* @param sha
* SHA that pull request head must match to allow merge.
*/
public void merge(String msg, String sha) throws IOException {
new Requester(root).method("PUT").with("commit_message",msg).with("sha",sha).to(getApiRoute()+"/merge");
} }
private void fetchIssue() throws IOException { private void fetchIssue() throws IOException {

View File

@@ -31,99 +31,111 @@ import java.net.URL;
* Commit detail inside a {@link GHPullRequest}. * Commit detail inside a {@link GHPullRequest}.
* *
* @author Luca Milanesio * @author Luca Milanesio
* @see GHPullRequest#listCommits()
*/ */
public class GHPullRequestCommitDetail { public class GHPullRequestCommitDetail {
private GHPullRequest owner;
/*package*/ void wrapUp(GHPullRequest owner) {
this.owner = owner;
}
/** /**
* @deprecated Use {@link GitUser} * @deprecated Use {@link GitUser}
*/ */
public static class Authorship extends GitUser {} public static class Authorship extends GitUser {
}
public static class Tree { public static class Tree {
String sha;
String url;
public String getSha() {
return sha;
}
public URL getUrl() {
return GitHub.parseURL(url);
}
}
public static class Commit {
Authorship author;
Authorship committer;
String message;
Tree tree;
String url;
int comment_count;
@WithBridgeMethods(value = Authorship.class, castRequired = true)
public GitUser getAuthor() {
return author;
}
@WithBridgeMethods(value = Authorship.class, castRequired = true)
public GitUser getCommitter() {
return committer;
}
public String getMessage() {
return message;
}
public URL getUrl() {
return GitHub.parseURL(url);
}
public int getComment_count() {
return comment_count;
}
}
public static class CommitPointer {
String sha;
String url;
String html_url;
public URL getUrl() {
return GitHub.parseURL(url);
}
public URL getHtml_url() {
return GitHub.parseURL(html_url);
}
public String getSha() {
return sha;
}
}
String sha; String sha;
String url; Commit commit;
public String getSha() {
return sha;
}
public URL getUrl() {
return GitHub.parseURL(url);
}
}
public static class Commit {
Authorship author;
Authorship committer;
String message;
Tree tree;
String url;
int comment_count;
@WithBridgeMethods(value=Authorship.class,castRequired=true)
public GitUser getAuthor() {
return author;
}
@WithBridgeMethods(value=Authorship.class,castRequired=true)
public GitUser getCommitter() {
return committer;
}
public String getMessage() {
return message;
}
public URL getUrl() {
return GitHub.parseURL(url);
}
public int getComment_count() {
return comment_count;
}
}
public static class CommitPointer {
String sha;
String url; String url;
String html_url; String html_url;
String comments_url;
public URL getUrl() { CommitPointer[] parents;
return GitHub.parseURL(url);
}
public URL getHtml_url() {
return GitHub.parseURL(html_url);
}
public String getSha() { public String getSha() {
return sha; return sha;
} }
}
String sha; public Commit getCommit() {
Commit commit; return commit;
String url; }
String html_url;
String comments_url; public URL getApiUrl() {
CommitPointer[] parents; return GitHub.parseURL(url);
}
public String getSha() {
return sha; public URL getUrl() {
} return GitHub.parseURL(html_url);
public Commit getCommit() { }
return commit;
} public URL getCommentsUrl() {
public URL getApiUrl() { return GitHub.parseURL(comments_url);
return GitHub.parseURL(url); }
}
public URL getUrl() { public CommitPointer[] getParents() {
return GitHub.parseURL(html_url); return parents;
} }
public URL getCommentsUrl() {
return GitHub.parseURL(comments_url);
}
public CommitPointer[] getParents() {
return parents;
}
} }

View File

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

View File

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

View File

@@ -3,6 +3,7 @@ package org.kohsuke.github;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@@ -44,8 +45,8 @@ public class GHRelease extends GHObject {
return draft; return draft;
} }
public String getHtmlUrl() { public URL getHtmlUrl() {
return html_url; return GitHub.parseURL(html_url);
} }
public String getName() { public String getName() {

View File

@@ -63,6 +63,8 @@ public class GHRepository extends GHObject {
private GHRepoPermission permissions; private GHRepoPermission permissions;
private GHRepository source, parent;
public GHDeploymentBuilder createDeployment(String ref) { public GHDeploymentBuilder createDeployment(String ref) {
return new GHDeploymentBuilder(this,ref); return new GHDeploymentBuilder(this,ref);
} }
@@ -159,6 +161,10 @@ public class GHRepository extends GHObject {
return ssh_url; return ssh_url;
} }
public URL getHtmlUrl() {
return GitHub.parseURL(html_url);
}
/** /**
* Short repository name without the owner. For example 'jenkins' in case of http://github.com/jenkinsci/jenkins * Short repository name without the owner. For example 'jenkins' in case of http://github.com/jenkinsci/jenkins
*/ */
@@ -353,7 +359,7 @@ public class GHRepository extends GHObject {
} }
/** /**
* Returns the primary branch you'll configure in the "Admin > Options" config page. * Returns the primary branch you'll configure in the "Admin &gt; Options" config page.
* *
* @return * @return
* This field is null until the user explicitly configures the master branch. * This field is null until the user explicitly configures the master branch.
@@ -642,48 +648,48 @@ public class GHRepository extends GHObject {
return GHRef.wrap(root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", owner.login, name, refType), GHRef[].class),root); return GHRef.wrap(root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", owner.login, name, refType), GHRef[].class),root);
} }
/** /**
* Retrive a ref of the given type for the current GitHub repository. * Retrive a ref of the given type for the current GitHub repository.
* *
* @param refName * @param refName
* eg: heads/branch * eg: heads/branch
* @return refs matching the request type * @return refs matching the request type
* @throws IOException * @throws IOException
* on failure communicating with GitHub, potentially due to an * on failure communicating with GitHub, potentially due to an
* invalid ref type being requested * invalid ref type being requested
*/ */
public GHRef getRef(String refName) throws IOException { public GHRef getRef(String refName) throws IOException {
return root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", owner.login, name, refName), GHRef.class).wrap(root); return root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", owner.login, name, refName), GHRef.class).wrap(root);
} }
/** /**
* Retrive a tree of the given type for the current GitHub repository. * Retrive a tree of the given type for the current GitHub repository.
* *
* @param sha - sha number or branch name ex: "master" * @param sha - sha number or branch name ex: "master"
* @return refs matching the request type * @return refs matching the request type
* @throws IOException * @throws IOException
* on failure communicating with GitHub, potentially due to an * on failure communicating with GitHub, potentially due to an
* invalid tree type being requested * invalid tree type being requested
*/ */
public GHTree getTree(String sha) throws IOException { public GHTree getTree(String sha) throws IOException {
String url = String.format("/repos/%s/%s/git/trees/%s", owner.login, name, sha); String url = String.format("/repos/%s/%s/git/trees/%s", owner.login, name, sha);
return root.retrieve().to(url, GHTree.class).wrap(root); return root.retrieve().to(url, GHTree.class).wrap(root);
} }
/** /**
* Retrieves the tree for the current GitHub repository, recursively as described in here: * Retrieves the tree for the current GitHub repository, recursively as described in here:
* https://developer.github.com/v3/git/trees/#get-a-tree-recursively * https://developer.github.com/v3/git/trees/#get-a-tree-recursively
* *
* @param sha - sha number or branch name ex: "master" * @param sha - sha number or branch name ex: "master"
* @param recursive use 1 * @param recursive use 1
* @throws IOException * @throws IOException
* on failure communicating with GitHub, potentially due to an * on failure communicating with GitHub, potentially due to an
* invalid tree type being requested * invalid tree type being requested
*/ */
public GHTree getTreeRecursive(String sha, int recursive) throws IOException { public GHTree getTreeRecursive(String sha, int recursive) throws IOException {
String url = String.format("/repos/%s/%s/git/trees/%s?recursive=%d", owner.login, name, sha, recursive); String url = String.format("/repos/%s/%s/git/trees/%s?recursive=%d", owner.login, name, sha, recursive);
return root.retrieve().to(url, GHTree.class).wrap(root); return root.retrieve().to(url, GHTree.class).wrap(root);
} }
/** /**
* Gets a commit object in this repository. * Gets a commit object in this repository.
*/ */
public GHCommit getCommit(String sha1) throws IOException { public GHCommit getCommit(String sha1) throws IOException {
@@ -780,10 +786,10 @@ public class GHRepository extends GHObject {
} }
/** /**
* @see {@link #createCommitStatus(String, GHCommitState,String,String,String) createCommitStatus} * @see #createCommitStatus(String, GHCommitState,String,String,String)
*/ */
public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description) throws IOException { public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description) throws IOException {
return createCommitStatus(sha1, state, targetUrl, description,null); return createCommitStatus(sha1, state, targetUrl, description,null);
} }
/** /**
@@ -989,10 +995,10 @@ public class GHRepository extends GHObject {
*/ */
public Map<Integer, GHMilestone> getMilestones() throws IOException { public Map<Integer, GHMilestone> getMilestones() throws IOException {
Map<Integer,GHMilestone> milestones = new TreeMap<Integer, GHMilestone>(); Map<Integer,GHMilestone> milestones = new TreeMap<Integer, GHMilestone>();
for (GHMilestone m : listMilestones(GHIssueState.OPEN)) { for (GHMilestone m : listMilestones(GHIssueState.OPEN)) {
milestones.put(m.getNumber(), m); milestones.put(m.getNumber(), m);
} }
return milestones; return milestones;
} }
/** /**
@@ -1012,16 +1018,16 @@ public class GHRepository extends GHObject {
}; };
} }
public GHMilestone getMilestone(int number) throws IOException { public GHMilestone getMilestone(int number) throws IOException {
GHMilestone m = milestones.get(number); GHMilestone m = milestones.get(number);
if (m == null) { if (m == null) {
m = root.retrieve().to(getApiTailUrl("milestones/" + number), GHMilestone.class); m = root.retrieve().to(getApiTailUrl("milestones/" + number), GHMilestone.class);
m.owner = this; m.owner = this;
m.root = root; m.root = root;
milestones.put(m.getNumber(), m); milestones.put(m.getNumber(), m);
} }
return m; return m;
} }
public GHContent getFileContent(String path) throws IOException { public GHContent getFileContent(String path) throws IOException {
return getFileContent(path, null); return getFileContent(path, null);
@@ -1088,25 +1094,57 @@ public class GHRepository extends GHObject {
return response; return response;
} }
public GHMilestone createMilestone(String title, String description) throws IOException { public GHMilestone createMilestone(String title, String description) throws IOException {
return new Requester(root) return new Requester(root)
.with("title", title).with("description", description).method("POST").to(getApiTailUrl("milestones"), GHMilestone.class).wrap(this); .with("title", title).with("description", description).method("POST").to(getApiTailUrl("milestones"), GHMilestone.class).wrap(this);
} }
public GHDeployKey addDeployKey(String title,String key) throws IOException { public GHDeployKey addDeployKey(String title,String key) throws IOException {
return new Requester(root) return new Requester(root)
.with("title", title).with("key", key).method("POST").to(getApiTailUrl("keys"), GHDeployKey.class).wrap(this); .with("title", title).with("key", key).method("POST").to(getApiTailUrl("keys"), GHDeployKey.class).wrap(this);
} }
public List<GHDeployKey> getDeployKeys() throws IOException{ public List<GHDeployKey> getDeployKeys() throws IOException{
List<GHDeployKey> list = new ArrayList<GHDeployKey>(Arrays.asList( List<GHDeployKey> list = new ArrayList<GHDeployKey>(Arrays.asList(
root.retrieve().to(getApiTailUrl("keys"), GHDeployKey[].class))); root.retrieve().to(getApiTailUrl("keys"), GHDeployKey[].class)));
for (GHDeployKey h : list) for (GHDeployKey h : list)
h.wrap(this); h.wrap(this);
return list; return list;
} }
/**
* Forked repositories have a 'source' attribute that specifies the ultimate source of the forking chain.
*
* @return
* {@link GHRepository} that points to the root repository where this repository is forked
* (indirectly or directly) from. Otherwise null.
* @see #getParent()
*/
public GHRepository getSource() throws IOException {
if (source == null) return null;
if (source.root == null)
source = root.getRepository(source.getFullName());
return source;
}
/**
* Forked repositories have a 'parent' attribute that specifies the repository this repository
* is directly forked from. If we keep traversing {@link #getParent()} until it returns null, that
* is {@link #getSource()}.
*
* @return
* {@link GHRepository} that points to the repository where this repository is forked
* directly from. Otherwise null.
* @see #getSource()
*/
public GHRepository getParent() throws IOException {
if (parent == null) return null;
if (parent.root == null)
parent = root.getRepository(parent.getFullName());
return parent;
}
/** /**
* Subscribes to this repository to get notifications. * Subscribes to this repository to get notifications.
*/ */

View File

@@ -47,10 +47,10 @@ public class GHTeam {
return id; return id;
} }
/** /**
* Retrieves the current members. * Retrieves the current members.
*/ */
public PagedIterable<GHUser> listMembers() throws IOException { public PagedIterable<GHUser> listMembers() throws IOException {
return new PagedIterable<GHUser>() { return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> iterator() { public PagedIterator<GHUser> iterator() {
return new PagedIterator<GHUser>(org.root.retrieve().asIterator(api("/members"), GHUser[].class)) { return new PagedIterator<GHUser>(org.root.retrieve().asIterator(api("/members"), GHUser[].class)) {
@@ -64,8 +64,8 @@ public class GHTeam {
} }
public Set<GHUser> getMembers() throws IOException { public Set<GHUser> getMembers() throws IOException {
return Collections.unmodifiableSet(listMembers().asSet()); return Collections.unmodifiableSet(listMembers().asSet());
} }
/** /**
* Checks if this team has the specified user as a member. * Checks if this team has the specified user as a member.

View File

@@ -2,6 +2,7 @@ package org.kohsuke.github;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.util.Date; import java.util.Date;
/** /**
@@ -37,6 +38,14 @@ public class GHThread extends GHObject {
return GitHub.parseDate(last_read_at); return GitHub.parseDate(last_read_at);
} }
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
public String getReason() { public String getReason() {
return reason; return reason;
} }
@@ -59,6 +68,41 @@ public class GHThread extends GHObject {
return subject.type; return subject.type;
} }
/**
* If this thread is about an issue, return that issue.
*
* @return null if this thread is not about an issue.
*/
public GHIssue getBoundIssue() throws IOException {
if (!"Issue".equals(subject.type) && "PullRequest".equals(subject.type))
return null;
return repository.getIssue(
Integer.parseInt(subject.url.substring(subject.url.lastIndexOf('/') + 1)));
}
/**
* If this thread is about a pull request, return that pull request.
*
* @return null if this thread is not about a pull request.
*/
public GHPullRequest getBoundPullRequest() throws IOException {
if (!"PullRequest".equals(subject.type))
return null;
return repository.getPullRequest(
Integer.parseInt(subject.url.substring(subject.url.lastIndexOf('/') + 1)));
}
/**
* If this thread is about a commit, return that commit.
*
* @return null if this thread is not about a commit.
*/
public GHCommit getBoundCommit() throws IOException {
if (!"Commit".equals(subject.type))
return null;
return repository.getCommit(subject.url.substring(subject.url.lastIndexOf('/') + 1));
}
/*package*/ GHThread wrap(GitHub root) { /*package*/ GHThread wrap(GitHub root) {
this.root = root; this.root = root;
if (this.repository!=null) if (this.repository!=null)

View File

@@ -13,46 +13,46 @@ import java.util.List;
* @see GHRepository#getTree(String) * @see GHRepository#getTree(String)
*/ */
public class GHTree { public class GHTree {
/* package almost final */GitHub root; /* package almost final */GitHub root;
private boolean truncated; private boolean truncated;
private String sha, url; private String sha, url;
private GHTreeEntry[] tree; private GHTreeEntry[] tree;
/** /**
* The SHA for this trees * The SHA for this trees
*/ */
public String getSha() { public String getSha() {
return sha; return sha;
} }
/** /**
* Return an array of entries of the trees * Return an array of entries of the trees
* @return * @return
*/ */
public List<GHTreeEntry> getTree() { public List<GHTreeEntry> getTree() {
return Collections.unmodifiableList(Arrays.asList(tree)); return Collections.unmodifiableList(Arrays.asList(tree));
} }
/** /**
* Returns true if the number of items in the tree array exceeded the GitHub maximum limit. * Returns true if the number of items in the tree array exceeded the GitHub maximum limit.
* @return true true if the number of items in the tree array exceeded the GitHub maximum limit otherwise false. * @return true true if the number of items in the tree array exceeded the GitHub maximum limit otherwise false.
*/ */
public boolean isTruncated() { public boolean isTruncated() {
return truncated; return truncated;
} }
/** /**
* The API URL of this tag, such as * The API URL of this tag, such as
* "url": "https://api.github.com/repos/octocat/Hello-World/trees/fc6274d15fa3ae2ab983129fb037999f264ba9a7", * "url": "https://api.github.com/repos/octocat/Hello-World/trees/fc6274d15fa3ae2ab983129fb037999f264ba9a7",
*/ */
public URL getUrl() { public URL getUrl() {
return GitHub.parseURL(url); return GitHub.parseURL(url);
} }
/* package */GHTree wrap(GitHub root) { /* package */GHTree wrap(GitHub root) {
this.root = root; this.root = root;
return this; return this;
} }
} }

View File

@@ -60,7 +60,7 @@ import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
* <p> * <p>
* This library aims to be safe for use by multiple threads concurrently, although * This library aims to be safe for use by multiple threads concurrently, although
* the library itself makes no attempt to control/serialize potentially conflicting * the library itself makes no attempt to control/serialize potentially conflicting
* operations to GitHub, such as updating & deleting a repository at the same time. * operations to GitHub, such as updating &amp; deleting a repository at the same time.
* *
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
@@ -133,10 +133,11 @@ public class GitHub {
} }
} }
this.rateLimitHandler = rateLimitHandler;
if (login==null && encodedAuthorization!=null) if (login==null && encodedAuthorization!=null)
login = getMyself().getLogin(); login = getMyself().getLogin();
this.login = login; this.login = login;
this.rateLimitHandler = rateLimitHandler;
} }
/** /**
@@ -252,11 +253,11 @@ public class GitHub {
} }
/** /**
* Gets the {@link GHUser} that represents yourself. * Gets the {@link GHUser} that represents yourself.
*/ */
@WithBridgeMethods(GHUser.class) @WithBridgeMethods(GHUser.class)
public GHMyself getMyself() throws IOException { public GHMyself getMyself() throws IOException {
requireCredential(); requireCredential();
GHMyself u = retrieve().to("/user", GHMyself.class); GHMyself u = retrieve().to("/user", GHMyself.class);
@@ -264,20 +265,20 @@ public class GitHub {
users.put(u.getLogin(), u); users.put(u.getLogin(), u);
return u; return u;
} }
/** /**
* Obtains the object that represents the named user. * Obtains the object that represents the named user.
*/ */
public GHUser getUser(String login) throws IOException { public GHUser getUser(String login) throws IOException {
GHUser u = users.get(login); GHUser u = users.get(login);
if (u == null) { if (u == null) {
u = retrieve().to("/users/" + login, GHUser.class); u = retrieve().to("/users/" + login, GHUser.class);
u.root = this; u.root = this;
users.put(u.getLogin(), u); users.put(u.getLogin(), u);
} }
return u; return u;
} }
/** /**
@@ -415,14 +416,14 @@ public class GitHub {
* *
* @see <a href="http://developer.github.com/v3/oauth/#create-a-new-authorization">Documentation</a> * @see <a href="http://developer.github.com/v3/oauth/#create-a-new-authorization">Documentation</a>
*/ */
public GHAuthorization createToken(Collection<String> scope, String note, String noteUrl) throws IOException{ public GHAuthorization createToken(Collection<String> scope, String note, String noteUrl) throws IOException{
Requester requester = new Requester(this) Requester requester = new Requester(this)
.with("scopes", scope) .with("scopes", scope)
.with("note", note) .with("note", note)
.with("note_url", noteUrl); .with("note_url", noteUrl);
return requester.method("POST").to("/authorizations", GHAuthorization.class).wrap(this); return requester.method("POST").to("/authorizations", GHAuthorization.class).wrap(this);
} }
/** /**
* Ensures that the credential is valid. * Ensures that the credential is valid.

View File

@@ -45,18 +45,18 @@ public class GitHubBuilder {
* @throws IOException If there are no credentials defined in the ~/.github properties file or the process environment. * @throws IOException If there are no credentials defined in the ~/.github properties file or the process environment.
*/ */
public static GitHubBuilder fromCredentials() throws IOException { public static GitHubBuilder fromCredentials() throws IOException {
Exception cause = null; Exception cause = null;
GitHubBuilder builder; GitHubBuilder builder;
try { try {
builder = fromPropertyFile(); builder = fromPropertyFile();
if (builder.user != null) if (builder.user != null)
return builder; return builder;
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
// fall through // fall through
cause = e; cause = e;
} }
builder = fromEnvironment(); builder = fromEnvironment();
@@ -77,8 +77,8 @@ public class GitHubBuilder {
private static void loadIfSet(String envName, Properties p, String propName) { private static void loadIfSet(String envName, Properties p, String propName) {
String v = System.getenv(envName); String v = System.getenv(envName);
if (v != null) if (v != null)
p.put(propName, v); p.put(propName, v);
} }
/** /**
@@ -87,12 +87,12 @@ public class GitHubBuilder {
* different clients of this library will all recognize one consistent set of coordinates. * different clients of this library will all recognize one consistent set of coordinates.
*/ */
public static GitHubBuilder fromEnvironment(String loginVariableName, String passwordVariableName, String oauthVariableName, String endpointVariableName) throws IOException { public static GitHubBuilder fromEnvironment(String loginVariableName, String passwordVariableName, String oauthVariableName, String endpointVariableName) throws IOException {
Properties env = new Properties(); Properties env = new Properties();
loadIfSet(loginVariableName,env,"login"); loadIfSet(loginVariableName,env,"login");
loadIfSet(passwordVariableName,env,"password"); loadIfSet(passwordVariableName,env,"password");
loadIfSet(oauthVariableName,env,"oauth"); loadIfSet(oauthVariableName,env,"oauth");
loadIfSet(endpointVariableName,env,"endpoint"); loadIfSet(endpointVariableName,env,"endpoint");
return fromProperties(env); return fromProperties(env);
} }
/** /**
@@ -116,7 +116,7 @@ public class GitHubBuilder {
* login, password, oauth * login, password, oauth
*/ */
public static GitHubBuilder fromEnvironment() throws IOException { public static GitHubBuilder fromEnvironment() throws IOException {
Properties props = new Properties(); Properties props = new Properties();
for (Entry<String, String> e : System.getenv().entrySet()) { for (Entry<String, String> e : System.getenv().entrySet()) {
String name = e.getKey().toLowerCase(Locale.ENGLISH); String name = e.getKey().toLowerCase(Locale.ENGLISH);
if (name.startsWith("github_")) name=name.substring(7); if (name.startsWith("github_")) name=name.substring(7);

View File

@@ -479,6 +479,9 @@ class Requester {
* Handle API error by either throwing it or by returning normally to retry. * Handle API error by either throwing it or by returning normally to retry.
*/ */
/*package*/ void handleApiError(IOException e) throws IOException { /*package*/ void handleApiError(IOException e) throws IOException {
if (uc.getResponseCode() == 401) // Unauthorized == bad creds
throw e;
if ("0".equals(uc.getHeaderField("X-RateLimit-Remaining"))) { if ("0".equals(uc.getHeaderField("X-RateLimit-Remaining"))) {
root.rateLimitHandler.onError(e,uc); root.rateLimitHandler.onError(e,uc);
} }

View File

@@ -19,9 +19,9 @@ public abstract class AbstractGitHubApiTestBase extends Assert {
if (f.exists()) { if (f.exists()) {
// use the non-standard credential preferentially, so that developers of this library do not have // use the non-standard credential preferentially, so that developers of this library do not have
// to clutter their event stream. // to clutter their event stream.
gitHub = GitHubBuilder.fromPropertyFile(f.getPath()).build(); gitHub = GitHubBuilder.fromPropertyFile(f.getPath()).withRateLimitHandler(RateLimitHandler.FAIL).build();
} else { } else {
gitHub = GitHub.connect(); gitHub = GitHubBuilder.fromCredentials().withRateLimitHandler(RateLimitHandler.FAIL).build();
} }
} }

View File

@@ -598,10 +598,10 @@ public class AppTest extends AbstractGitHubApiTestBase {
} }
@Test @Test
public void testRef() throws IOException { public void testRef() throws IOException {
GHRef masterRef = gitHub.getRepository("jenkinsci/jenkins").getRef("heads/master"); GHRef masterRef = gitHub.getRepository("jenkinsci/jenkins").getRef("heads/master");
assertEquals("https://api.github.com/repos/jenkinsci/jenkins/git/refs/heads/master", masterRef.getUrl().toString()); assertEquals("https://api.github.com/repos/jenkinsci/jenkins/git/refs/heads/master", masterRef.getUrl().toString());
} }
@Test @Test
public void directoryListing() throws IOException { public void directoryListing() throws IOException {
@@ -618,8 +618,8 @@ public class AppTest extends AbstractGitHubApiTestBase {
@Test @Test
public void testAddDeployKey() throws IOException { public void testAddDeployKey() throws IOException {
GHRepository myRepository = Iterables.get(gitHub.getMyself().getRepositories().values(),0); GHRepository myRepository = Iterables.get(gitHub.getMyself().getRepositories().values(),0);
final GHDeployKey newDeployKey = myRepository.addDeployKey("test", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUt0RAycC5cS42JKh6SecfFZBR1RrF+2hYMctz4mk74/arBE+wFb7fnSHGzdGKX2h5CFOWODifRCJVhB7hlVxodxe+QkQQYAEL/x1WVCJnGgTGQGOrhOMj95V3UE5pQKhsKD608C+u5tSofcWXLToP1/wZ7U4/AHjqYi08OLsWToHCax55TZkvdt2jo0hbIoYU+XI9Q8Uv4ONDN1oabiOdgeKi8+crvHAuvNleiBhWVBzFh8KdfzaH5uNdw7ihhFjEd1vzqACsjCINCjdMfzl6jD9ExuWuE92nZJnucls2cEoNC6k2aPmrZDg9hA32FXVpyseY+bDUWFU6LO2LG6PB kohsuke@atlas"); final GHDeployKey newDeployKey = myRepository.addDeployKey("test", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUt0RAycC5cS42JKh6SecfFZBR1RrF+2hYMctz4mk74/arBE+wFb7fnSHGzdGKX2h5CFOWODifRCJVhB7hlVxodxe+QkQQYAEL/x1WVCJnGgTGQGOrhOMj95V3UE5pQKhsKD608C+u5tSofcWXLToP1/wZ7U4/AHjqYi08OLsWToHCax55TZkvdt2jo0hbIoYU+XI9Q8Uv4ONDN1oabiOdgeKi8+crvHAuvNleiBhWVBzFh8KdfzaH5uNdw7ihhFjEd1vzqACsjCINCjdMfzl6jD9ExuWuE92nZJnucls2cEoNC6k2aPmrZDg9hA32FXVpyseY+bDUWFU6LO2LG6PB kohsuke@atlas");
try { try {
assertNotNull(newDeployKey.getId()); assertNotNull(newDeployKey.getId());
@@ -636,11 +636,11 @@ public class AppTest extends AbstractGitHubApiTestBase {
@Test @Test
public void testCommitStatusContext() throws IOException { public void testCommitStatusContext() throws IOException {
GHRepository myRepository = Iterables.get(gitHub.getMyself().getRepositories().values(), 0); GHRepository myRepository = Iterables.get(gitHub.getMyself().getRepositories().values(), 0);
GHRef masterRef = myRepository.getRef("heads/master"); GHRef masterRef = myRepository.getRef("heads/master");
GHCommitStatus commitStatus = myRepository.createCommitStatus(masterRef.getObject().getSha(), GHCommitState.SUCCESS, "http://www.example.com", "test", "test/context"); GHCommitStatus commitStatus = myRepository.createCommitStatus(masterRef.getObject().getSha(), GHCommitState.SUCCESS, "http://www.example.com", "test", "test/context");
assertEquals("test/context", commitStatus.getContext()); assertEquals("test/context", commitStatus.getContext());
} }
@Test @Test
@@ -671,28 +671,28 @@ public class AppTest extends AbstractGitHubApiTestBase {
@Test @Test
public void testTrees() throws IOException { public void testTrees() throws IOException {
GHTree masterTree = gitHub.getRepository("kohsuke/github-api").getTree("master"); GHTree masterTree = gitHub.getRepository("kohsuke/github-api").getTree("master");
boolean foundReadme = false; boolean foundReadme = false;
for(GHTreeEntry e : masterTree.getTree()){ for(GHTreeEntry e : masterTree.getTree()){
if("readme".equalsIgnoreCase(e.getPath().replaceAll(".md", ""))){ if("readme".equalsIgnoreCase(e.getPath().replaceAll("\\.md", ""))){
foundReadme = true; foundReadme = true;
break; break;
} }
} }
assertTrue(foundReadme); assertTrue(foundReadme);
} }
@Test @Test
public void testTreesRecursive() throws IOException { public void testTreesRecursive() throws IOException {
GHTree masterTree = gitHub.getRepository("kohsuke/github-api").getTreeRecursive("master", 1); GHTree masterTree = gitHub.getRepository("kohsuke/github-api").getTreeRecursive("master", 1);
boolean foundThisFile = false; boolean foundThisFile = false;
for(GHTreeEntry e : masterTree.getTree()){ for(GHTreeEntry e : masterTree.getTree()){
if(e.getPath().endsWith(AppTest.class.getSimpleName() + ".java")){ if(e.getPath().endsWith(AppTest.class.getSimpleName() + ".java")){
foundThisFile = true; foundThisFile = true;
break; break;
} }
} }
assertTrue(foundThisFile); assertTrue(foundThisFile);
} }
@Test @Test

View File

@@ -30,21 +30,21 @@ public class GitHubTest extends TestCase {
} }
public void testGitHubBuilderFromEnvironment() throws IOException { public void testGitHubBuilderFromEnvironment() throws IOException {
Map<String, String>props = new HashMap<String, String>(); Map<String, String>props = new HashMap<String, String>();
props.put("login", "bogus"); props.put("login", "bogus");
props.put("oauth", "bogus"); props.put("oauth", "bogus");
props.put("password", "bogus"); props.put("password", "bogus");
setupEnvironment(props); setupEnvironment(props);
GitHubBuilder builder = GitHubBuilder.fromEnvironment(); GitHubBuilder builder = GitHubBuilder.fromEnvironment();
assertEquals("bogus", builder.user); assertEquals("bogus", builder.user);
assertEquals("bogus", builder.oauthToken); assertEquals("bogus", builder.oauthToken);
assertEquals("bogus", builder.password); assertEquals("bogus", builder.password);
} }
/* /*
@@ -55,59 +55,54 @@ public class GitHubTest extends TestCase {
* Its used to wire in values for the github credentials to test that the GitHubBuilder works properly to resolve them. * 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) { private void setupEnvironment(Map<String, String> newenv) {
try try {
{ Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment"); Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment"); theEnvironmentField.setAccessible(true);
theEnvironmentField.setAccessible(true); Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null); env.putAll(newenv);
env.putAll(newenv); Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment"); theCaseInsensitiveEnvironmentField.setAccessible(true);
theCaseInsensitiveEnvironmentField.setAccessible(true); Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null); cienv.putAll(newenv);
cienv.putAll(newenv); } catch (NoSuchFieldException e) {
} try {
catch (NoSuchFieldException e) Class[] classes = Collections.class.getDeclaredClasses();
{ Map<String, String> env = System.getenv();
try { for (Class cl : classes) {
Class[] classes = Collections.class.getDeclaredClasses(); if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
Map<String, String> env = System.getenv(); Field field = cl.getDeclaredField("m");
for(Class cl : classes) { field.setAccessible(true);
if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) { Object obj = field.get(env);
Field field = cl.getDeclaredField("m"); Map<String, String> map = (Map<String, String>) obj;
field.setAccessible(true); map.clear();
Object obj = field.get(env); map.putAll(newenv);
Map<String, String> map = (Map<String, String>) obj; }
map.clear(); }
map.putAll(newenv); } catch (Exception e2) {
} e2.printStackTrace();
} }
} catch (Exception e2) { } catch (Exception e1) {
e2.printStackTrace(); e1.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");
props.put("customEndpoint", "bogusEndpoint");
setupEnvironment(props);
GitHubBuilder builder = GitHubBuilder.fromEnvironment("customLogin", "customPassword", "customOauth", "customEndpoint");
assertEquals("bogusLogin", builder.user);
assertEquals("bogusOauth", builder.oauthToken);
assertEquals("bogusPassword", builder.password);
assertEquals("bogusEndpoint", builder.endpoint);
} }
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");
props.put("customEndpoint", "bogusEndpoint");
setupEnvironment(props);
GitHubBuilder builder = GitHubBuilder.fromEnvironment("customLogin", "customPassword", "customOauth", "customEndpoint");
assertEquals("bogusLogin", builder.user);
assertEquals("bogusOauth", builder.oauthToken);
assertEquals("bogusPassword", builder.password);
assertEquals("bogusEndpoint", builder.endpoint);
}
} }