diff --git a/pom.xml b/pom.xml index 42b509a4c6..b3cebb8139 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ github-api - 1.40 + 1.41 GitHub API for Java http://github-api.kohsuke.org/ GitHub API for Java diff --git a/src/main/java/org/kohsuke/github/GHIssue.java b/src/main/java/org/kohsuke/github/GHIssue.java index 74cb7fedd1..6cf376df19 100644 --- a/src/main/java/org/kohsuke/github/GHIssue.java +++ b/src/main/java/org/kohsuke/github/GHIssue.java @@ -200,7 +200,7 @@ protected void wrapUp(GHIssueComment[] page) { }; } - private String getApiRoute() { + protected String getApiRoute() { return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/issues/"+number; } diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java index 32523005e2..7adaa9342e 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequest.java +++ b/src/main/java/org/kohsuke/github/GHPullRequest.java @@ -63,7 +63,12 @@ GHPullRequest wrapUp(GitHub root) { 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 diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 6c7999492b..d71fce0b39 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -42,11 +42,9 @@ 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 @@ 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 users = new HashMap(); private final Map orgs = new HashMap(); - /*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. + * + *

+ * Several different combinations of the login/oauthAccessToken/password parameters are allowed + * to represent different ways of authentication. + * + *

+ *
Loging anonymously + *
Leave all three parameters null and you will be making HTTP requests without any authentication. + * + *
Log in with password + *
Specify the login and password, then leave oauthAccessToken null. + * This will use the HTTP BASIC auth with the GitHub API. + * + *
Log in with OAuth token + *
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. + *
* * @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 /api/v3 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; - } - 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(); + 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) + login = getMyself().getLogin(); + this.login = login; } - + /** * Obtains the credential from "~/.github" */ @@ -117,11 +140,7 @@ public static GitHub connect() throws IOException { } 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 static GitHub connect() throws IOException { * "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has /api/v3 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 connectToEnterprise(String apiUrl, String login, String password) throws IOException { + return new GitHub(apiUrl, login, null, password); } - public static GitHub connect(String login, String apiToken){ - return new GitHub(login,apiToken,null); + public static GitHub connect(String login, String oauthAccessToken) throws IOException { + return new GitHub(login,oauthAccessToken,null); } - public static GitHub connect(String login, String apiToken, String password){ - return new GitHub(login,apiToken,password); + /** + * @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 accessToken) throws IOException { - return connectUsingOAuth("github.com", accessToken); + public static GitHub connectUsingPassword(String login, String password) throws IOException { + return new GitHub(login,null,password); } - - public static GitHub connectUsingOAuth (String githubServer, String accessToken) throws IOException { - return new GitHub(githubServer, accessToken); + + 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 T parseEventPayload(Reader r, Class type) t t.wrapUp(this); return t; } - + /** * Creates a new repository. * @@ -311,7 +338,7 @@ public GHRepository createRepository(String name, String description, String hom * * 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 Documentation */ public GHAuthorization createToken(Collection scope, String note, String noteUrl) throws IOException{ Requester requester = new Requester(this) diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index feaa25e23a..795c2e2a1e 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -39,10 +39,12 @@ 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 @@ private HttpURLConnection setupConnection(URL url) throws IOException { // 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 @@ private InputStream wrapStream(HttpURLConnection uc, InputStream in) throws IOEx IOUtils.closeQuietly(es); } } + + private Set toSet(String s) { + Set r = new HashSet(); + for (String t : s.split(",")) + r.add(t.trim()); + return r; + } } diff --git a/src/test/java/Foo.java b/src/test/java/Foo.java new file mode 100644 index 0000000000..95e13f8182 --- /dev/null +++ b/src/test/java/Foo.java @@ -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()); + } +} diff --git a/src/test/java/org/kohsuke/github/GitHubTest.java b/src/test/java/org/kohsuke/github/GitHubTest.java index 8fbca796b3..6ff39feec9 100644 --- a/src/test/java/org/kohsuke/github/GitHubTest.java +++ b/src/test/java/org/kohsuke/github/GitHubTest.java @@ -8,17 +8,17 @@ 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()); } }