Compare commits

...

29 Commits

Author SHA1 Message Date
Kohsuke Kawaguchi
4956278f17 [maven-release-plugin] prepare release github-api-1.43 2013-07-06 22:26:39 -07:00
Kohsuke Kawaguchi
5858a86624 using the latest 2013-07-06 22:24:21 -07:00
Kohsuke Kawaguchi
c87d178a6a added a method that matches the convention elsewhere. 2013-07-06 17:49:56 -07:00
Kohsuke Kawaguchi
6fc872b1fd this is no longer efficient 2013-07-06 17:49:46 -07:00
Kohsuke Kawaguchi
589c5783a0 "myself" only makes sense when there's a credential 2013-05-24 12:01:56 -07:00
Kohsuke Kawaguchi
40165628d6 [maven-release-plugin] prepare for next development iteration 2013-05-07 11:09:20 -07:00
Kohsuke Kawaguchi
435be77249 [maven-release-plugin] prepare release github-api-1.42 2013-05-07 11:09:13 -07:00
Kohsuke Kawaguchi
b932ba856d fixed NPE 2013-05-07 11:07:12 -07:00
Kohsuke Kawaguchi
094514f617 Merge pull request #36 from spiffxp/require-credentials-fix
Allow oauthToken to be used without login
2013-05-06 14:34:06 -07:00
Kohsuke Kawaguchi
fab96879d0 Merge pull request #37 from spiffxp/pr-comments-fix
Force issues-based API route for PR comments
2013-05-06 14:33:29 -07:00
Kohsuke Kawaguchi
367a5f0c57 Merge pull request #38 from janinko/fixPullRequestPayload
add repository to Pull Request payload and wrap the PR with the repository
2013-05-06 14:32:11 -07:00
Honza Brázdil
0d2ecfbc67 add repository to Pull Request payload and wrap the PR with the repository 2013-05-02 18:11:40 +02:00
Aaron Crickenberger
5410ba3b1d Force issues-based API route for PR comments
pulls/:number/comments is used for review_comments
2013-05-01 13:59:45 -07:00
Aaron Crickenberger
716bfd4611 requireCredential should allow for oauthToken with no login 2013-04-30 15:41:08 -07:00
Kohsuke Kawaguchi
3830a58493 [maven-release-plugin] prepare for next development iteration 2013-04-23 10:30:54 -07:00
Kohsuke Kawaguchi
31d5cf6129 [maven-release-plugin] prepare release github-api-1.41 2013-04-23 10:30:48 -07:00
Kohsuke Kawaguchi
8c78d20e6e doc improvement 2013-04-23 10:25:57 -07:00
Kohsuke Kawaguchi
abe78cf0bb Formatting only changes 2013-04-23 10:20:07 -07:00
Kohsuke Kawaguchi
eeebfd5f04 added a little helper code that generates an OAuth token for ~/.github 2013-04-23 10:19:50 -07:00
Kohsuke Kawaguchi
5e3d3dd023 In fact there's no point in looking up the 'token' property since API token is no longer supported by GitHub 2013-04-23 10:05:45 -07:00
Kohsuke Kawaguchi
60175ebfad if the user name is available, pass that in and save a lookup 2013-04-23 10:05:06 -07:00
Kohsuke Kawaguchi
c6fafe453f Cleaned up the authentication part of the code 2013-04-23 10:04:20 -07:00
Kohsuke Kawaguchi
838ecd0dd8 Merge branch 'pull-33' 2013-04-23 09:40:37 -07:00
Kohsuke Kawaguchi
beec605e2c [FIXED issue #34] API route for pull requests uses 'pulls' 2013-04-23 09:28:00 -07:00
watsonian
da1405a060 Remove apiToken completely. 2013-04-20 11:58:52 -07:00
watsonian
e38eeae533 Update constructor to use OAuth tokens rather than API tokens. 2013-04-20 11:43:54 -07:00
watsonian
8442e7e326 Declare the exception type. 2013-04-19 17:10:29 -07:00
watsonian
e6c82e2003 Stop using deprecated API tokens for Enterprise.
Authentication by API token is deprecated and doesn't work anymore.
Instead, authentication should be done via OAuth token now.
2013-04-19 16:27:09 -07:00
Kohsuke Kawaguchi
c4de972c53 [maven-release-plugin] prepare for next development iteration 2013-04-16 12:30:34 -07:00
10 changed files with 161 additions and 69 deletions

View File

@@ -3,11 +3,11 @@
<parent>
<groupId>org.kohsuke</groupId>
<artifactId>pom</artifactId>
<version>4</version>
<version>6</version>
</parent>
<artifactId>github-api</artifactId>
<version>1.40</version>
<version>1.43</version>
<name>GitHub API for Java</name>
<url>http://github-api.kohsuke.org/</url>
<description>GitHub API for Java</description>

View File

@@ -27,6 +27,7 @@ public abstract class GHEventPayload {
private String action;
private int number;
private GHPullRequest pull_request;
private GHRepository repository;
public String getAction() {
return action;
@@ -41,10 +42,19 @@ public abstract class GHEventPayload {
return pull_request;
}
public GHRepository getRepository() {
return repository;
}
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
pull_request.wrapUp(root);
if (repository!=null) {
repository.wrap(root);
pull_request.wrap(repository);
} else {
pull_request.wrapUp(root);
}
}
}

View File

@@ -138,7 +138,7 @@ public class GHIssue {
* Updates the issue by adding a comment.
*/
public void comment(String message) throws IOException {
new Requester(root).with("body",message).to(getApiRoute() + "/comments");
new Requester(root).with("body",message).to(getIssuesApiRoute() + "/comments");
}
private void edit(String key, Object value) throws IOException {
@@ -190,7 +190,7 @@ public class GHIssue {
public PagedIterable<GHIssueComment> listComments() throws IOException {
return new PagedIterable<GHIssueComment>() {
public PagedIterator<GHIssueComment> iterator() {
return new PagedIterator<GHIssueComment>(root.retrieve().asIterator(getApiRoute() + "/comments", GHIssueComment[].class)) {
return new PagedIterator<GHIssueComment>(root.retrieve().asIterator(getIssuesApiRoute() + "/comments", GHIssueComment[].class)) {
protected void wrapUp(GHIssueComment[] page) {
for (GHIssueComment c : page)
c.wrapUp(GHIssue.this);
@@ -200,7 +200,11 @@ public class GHIssue {
};
}
private String getApiRoute() {
protected String getApiRoute() {
return getIssuesApiRoute();
}
private String getIssuesApiRoute() {
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/issues/"+number;
}
@@ -250,4 +254,4 @@ public class GHIssue {
return GitHub.parseURL(html_url);
}
}
}
}

View File

@@ -130,10 +130,13 @@ public class GHOrganization extends GHPerson {
/**
* List up repositories that has some open pull requests.
*
* This used to be an efficient method that didn't involve traversing every repository, but now
* it doesn't do any optimization.
*/
public List<GHRepository> getRepositoriesWithOpenPullRequests() throws IOException {
List<GHRepository> r = new ArrayList<GHRepository>();
for (GHRepository repository : root.retrieve().to("/orgs/" + login + "/repos", GHRepository[].class)) {
for (GHRepository repository : listRepositories()) {
repository.wrap(root);
List<GHPullRequest> pullRequests = repository.getPullRequests(GHIssueState.OPEN);
if (pullRequests.size() > 0) {

View File

@@ -54,6 +54,25 @@ public abstract class GHPerson {
return Collections.unmodifiableMap(repositories);
}
/**
* Lists up all the repositories.
*
* Unlike {@link #getRepositories()}, this does not wait until all the repositories are returned.
*/
public PagedIterable<GHRepository> listRepositories() {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> iterator() {
return new PagedIterator<GHRepository>(root.retrieve().asIterator("/users/" + login + "/repos", GHRepository[].class)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
c.wrap(root);
}
};
}
};
}
/**
* Loads repository list in a pagenated fashion.
*
@@ -63,6 +82,9 @@ public abstract class GHPerson {
*
* Every {@link Iterator#next()} call results in I/O. Exceptions that occur during the processing is wrapped
* into {@link Error}.
*
* @deprecated
* Use {@link #listRepositories()}
*/
public synchronized Iterable<List<GHRepository>> iterateRepositories(final int pageSize) {
return new Iterable<List<GHRepository>>() {

View File

@@ -63,7 +63,12 @@ public class GHPullRequest extends GHIssue {
if (merged_by != null) merged_by.wrapUp(root);
return this;
}
@Override
protected String getApiRoute() {
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/pulls/"+number;
}
/**
* The URL of the patch file.
* like https://github.com/jenkinsci/jenkins/pull/100.patch

View File

@@ -42,11 +42,9 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TimeZone;
import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.*;
@@ -59,52 +57,77 @@ import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.*;
public class GitHub {
/*package*/ final String login;
/**
* Value of the authorization header to be sent with the request.
*/
/*package*/ final String encodedAuthorization;
/*package*/ final String apiToken;
private final Map<String,GHUser> users = new HashMap<String, GHUser>();
private final Map<String,GHOrganization> orgs = new HashMap<String, GHOrganization>();
/*package*/ String oauthAccessToken;
private final String apiUrl;
private GitHub(String login, String apiToken, String password) {
this (GITHUB_URL, login, apiToken, password);
}
private final String apiUrl;
/**
* 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.
*
* <p>
* Several different combinations of the login/oauthAccessToken/password parameters are allowed
* to represent different ways of authentication.
*
* <dl>
* <dt>Loging anonymously
* <dd>Leave all three parameters null and you will be making HTTP requests without any authentication.
*
* <dt>Log in with password
* <dd>Specify the login and password, then leave oauthAccessToken null.
* This will use the HTTP BASIC auth with the GitHub API.
*
* <dt>Log in with OAuth token
* <dd>Specify oauthAccessToken, and optionally specify the login. Leave password null.
* This will send OAuth token to the GitHub API. If the login parameter is null,
* The constructor makes an API call to figure out the user name that owns the token.
* </dl>
*
* @param apiUrl
* The URL of GitHub (or GitHub enterprise) API endpoint, such as "https://api.github.com" or
* "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has <tt>/api/v3</tt> in the URL.
* For historical reasons, this parameter still accepts the bare domain name, but that's considered deprecated.
* Password is also considered deprecated as it is no longer required for api usage.
* @param login
* The use ID on GitHub that you are logging in as. Can be omitted if the OAuth token is
* provided or if logging in anonymously. Specifying this would save one API call.
* @param oauthAccessToken
* Secret OAuth token.
* @param password
* User's password. Always used in conjunction with the {@code login} parameter
*/
private GitHub(String apiUrl, String login, String apiToken, String password) {
private GitHub(String apiUrl, String login, String oauthAccessToken, String password) throws IOException {
if (apiUrl.endsWith("/")) apiUrl = apiUrl.substring(0, apiUrl.length()-1); // normalize
this.apiUrl = apiUrl;
this.login = login;
this.apiToken = apiToken;
if (apiToken!=null || password!=null) {
String authorization = password==null ? (login + "/token" + ":" + apiToken) : (login + ':'+password);
encodedAuthorization = new String(Base64.encodeBase64(authorization.getBytes()));
} else
encodedAuthorization = null;
if (oauthAccessToken!=null) {
encodedAuthorization = "token "+oauthAccessToken;
} else {
if (password!=null) {
String authorization = (login + ':' + password);
encodedAuthorization = "Basic "+new String(Base64.encodeBase64(authorization.getBytes()));
} else {// anonymous access
encodedAuthorization = null;
}
}
if (login==null && encodedAuthorization!=null)
login = getMyself().getLogin();
this.login = login;
}
private GitHub (String apiUrl, String oauthAccessToken) throws IOException {
if (apiUrl.endsWith("/")) apiUrl = apiUrl.substring(0, apiUrl.length()-1); // normalize
this.apiUrl = apiUrl;
this.encodedAuthorization = null;
this.oauthAccessToken = oauthAccessToken;
this.apiToken = oauthAccessToken;
this.login = getMyself().getLogin();
}
/**
* Obtains the credential from "~/.github"
*/
@@ -117,11 +140,7 @@ public class GitHub {
} finally {
IOUtils.closeQuietly(in);
}
String oauth = props.getProperty("oauth");
if (oauth!=null)
return new GitHub(GITHUB_URL,oauth);
else
return new GitHub(props.getProperty("login"),props.getProperty("token"),props.getProperty("password"));
return new GitHub(GITHUB_URL,props.getProperty("login"), props.getProperty("oauth"),props.getProperty("password"));
}
/**
@@ -132,45 +151,53 @@ public class GitHub {
* "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has <tt>/api/v3</tt> in the URL.
* For historical reasons, this parameter still accepts the bare domain name, but that's considered deprecated.
*/
public static GitHub connectToEnterprise(String apiUrl, String login, String apiToken) {
return new GitHub(apiUrl,login,apiToken,null);
public static GitHub connectToEnterprise(String apiUrl, String oauthAccessToken) throws IOException {
return connectUsingOAuth(apiUrl, oauthAccessToken);
}
public static GitHub connect(String login, String apiToken){
return new GitHub(login,apiToken,null);
public static GitHub connectToEnterprise(String apiUrl, String login, String password) throws IOException {
return new GitHub(apiUrl, login, null, password);
}
public static GitHub connect(String login, String apiToken, String password){
return new GitHub(login,apiToken,password);
public static GitHub connect(String login, String oauthAccessToken) throws IOException {
return new GitHub(login,oauthAccessToken,null);
}
public static GitHub connectUsingOAuth (String accessToken) throws IOException {
return connectUsingOAuth("github.com", accessToken);
/**
* @deprecated
* Either OAuth token or password is sufficient, so there's no point in passing both.
* 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);
}
public static GitHub connectUsingOAuth (String githubServer, String accessToken) throws IOException {
return new GitHub(githubServer, accessToken);
public static GitHub connectUsingPassword(String login, String password) throws IOException {
return new GitHub(login,null,password);
}
public static GitHub connectUsingOAuth(String oauthAccessToken) throws IOException {
return new GitHub(null, oauthAccessToken, null);
}
public static GitHub connectUsingOAuth(String githubServer, String oauthAccessToken) throws IOException {
return new GitHub(githubServer,null, oauthAccessToken,null);
}
/**
* Connects to GitHub anonymously.
*
* All operations that requires authentication will fail.
*/
public static GitHub connectAnonymously() {
public static GitHub connectAnonymously() throws IOException {
return new GitHub(null,null,null);
}
/*package*/ void requireCredential() {
if ((login==null || encodedAuthorization==null) && oauthAccessToken == null)
if (login==null && encodedAuthorization==null)
throw new IllegalStateException("This operation requires a credential but none is given to the GitHub constructor");
}
/*package*/ URL getApiURL(String tailApiUrl) throws IOException {
if (oauthAccessToken != null) {
// append the access token
tailApiUrl = tailApiUrl + (tailApiUrl.indexOf('?')>=0 ?'&':'?') + "access_token=" + oauthAccessToken;
}
if (tailApiUrl.startsWith("/")) {
if ("github.com".equals(apiUrl)) {// backward compatibility
return new URL(GITHUB_URL + tailApiUrl);
@@ -292,7 +319,7 @@ public class GitHub {
t.wrapUp(this);
return t;
}
/**
* Creates a new repository.
*
@@ -311,7 +338,7 @@ public class GitHub {
*
* The token created can be then used for {@link GitHub#connectUsingOAuth(String)} in the future.
*
* @see http://developer.github.com/v3/oauth/#create-a-new-authorization
* @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{
Requester requester = new Requester(this)

View File

@@ -39,10 +39,12 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.zip.GZIPInputStream;
import static org.kohsuke.github.GitHub.*;
@@ -271,9 +273,8 @@ class Requester {
// if the authentication is needed but no credential is given, try it anyway (so that some calls
// that do work with anonymous access in the reduced form should still work.)
// if OAuth token is present, it'll be set in the URL, so need to set the Authorization header
if (root.encodedAuthorization!=null && root.oauthAccessToken == null)
uc.setRequestProperty("Authorization", "Basic " + root.encodedAuthorization);
if (root.encodedAuthorization!=null)
uc.setRequestProperty("Authorization", root.encodedAuthorization);
try {
uc.setRequestMethod(method);
@@ -345,4 +346,11 @@ class Requester {
IOUtils.closeQuietly(es);
}
}
private Set<String> toSet(String s) {
Set<String> r = new HashSet<String>();
for (String t : s.split(","))
r.add(t.trim());
return r;
}
}

13
src/test/java/Foo.java Normal file
View File

@@ -0,0 +1,13 @@
import org.kohsuke.github.GitHub;
import java.util.Arrays;
/**
* @author Kohsuke Kawaguchi
*/
public class Foo {
public static void main(String[] args) throws Exception {
System.out.println(GitHub.connect().createToken(
Arrays.asList("user", "repo", "delete_repo", "notifications", "gist"), "GitHub API", null).getToken());
}
}

View File

@@ -8,17 +8,17 @@ import junit.framework.TestCase;
public class GitHubTest extends TestCase {
public void testGitHubServerWithHttp() throws Exception {
GitHub hub = GitHub.connectToEnterprise("http://enterprise.kohsuke.org/api/v3", "kohsuke", "token");
GitHub hub = GitHub.connectToEnterprise("http://enterprise.kohsuke.org/api/v3", "bogus","bogus");
assertEquals("http://enterprise.kohsuke.org/api/v3/test", hub.getApiURL("/test").toString());
}
public void testGitHubServerWithHttps() throws Exception {
GitHub hub = GitHub.connectToEnterprise("https://enterprise.kohsuke.org/api/v3", "kohsuke", "token");
GitHub hub = GitHub.connectToEnterprise("https://enterprise.kohsuke.org/api/v3", "bogus","bogus");
assertEquals("https://enterprise.kohsuke.org/api/v3/test", hub.getApiURL("/test").toString());
}
public void testGitHubServerWithoutServer() throws Exception {
GitHub hub = GitHub.connect("kohsuke", "token", "password");
GitHub hub = GitHub.connectUsingPassword("kohsuke", "bogus");
assertEquals("https://api.github.com/test", hub.getApiURL("/test").toString());
}
}