From 44f1038516a23109d232a3425c1867521395b62d Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Tue, 3 Jan 2012 11:16:15 -0800 Subject: [PATCH 01/16] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 29645e620b..7869e99efa 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ github-api - 1.16 + 1.17-SNAPSHOT GitHub API for Java http://github-api.kohsuke.org/ GitHub API for Java From ac1dd9a0ee40f4521e3f15f8cf5546c8c4267c03 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 8 Jan 2012 16:37:07 -0800 Subject: [PATCH 02/16] 'Z' isn't parsed but it means GMT --- src/main/java/org/kohsuke/github/GitHub.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 2cc3624f28..ccc53816df 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -48,6 +48,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Properties; +import java.util.TimeZone; import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.*; import static org.kohsuke.github.ApiVersion.*; @@ -331,7 +332,9 @@ WebClient createWebClient() throws IOException { /*package*/ static Date parseDate(String timestamp) { for (String f : TIME_FORMATS) { try { - return new SimpleDateFormat(f).parse(timestamp); + SimpleDateFormat df = new SimpleDateFormat(f); + df.setTimeZone(TimeZone.getTimeZone("GMT")); + return df.parse(timestamp); } catch (ParseException e) { // try next } From 4a507a5625a523f97e838ef170cbcd5ff99f4a56 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 8 Jan 2012 16:53:20 -0800 Subject: [PATCH 03/16] adding event support --- .../java/org/kohsuke/github/GHEventInfo.java | 57 +++++++++++++++++++ .../java/org/kohsuke/github/GHRepository.java | 3 + src/main/java/org/kohsuke/github/GitHub.java | 24 +++++++- src/test/java/org/kohsuke/AppTest.java | 5 ++ 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/kohsuke/github/GHEventInfo.java diff --git a/src/main/java/org/kohsuke/github/GHEventInfo.java b/src/main/java/org/kohsuke/github/GHEventInfo.java new file mode 100644 index 0000000000..3a2abe04ba --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHEventInfo.java @@ -0,0 +1,57 @@ +package org.kohsuke.github; + +import org.codehaus.jackson.node.ObjectNode; + +import java.io.IOException; +import java.util.Date; + +/** + * Represents an event. + * + * @author Kohsuke Kawaguchi + */ +public class GHEventInfo { + private GitHub root; + + private ObjectNode payload; + + private String created_at; + private String type; + + // these are all shallow objects + private GHRepository repo; + private GHUser actor; + private GHOrganization org; + + public GHEvent getType() { + for (GHEvent e : GHEvent.values()) { + if (e.name().replace("_","").equalsIgnoreCase(type)) + return e; + } + return null; // unknown event type + } + + /*package*/ GHEventInfo wrapUp(GitHub root) { + this.root = root; + return this; + } + + public Date getCreatedAt() { + return GitHub.parseDate(created_at); + } + + /** + * Repository where the change was made. + */ + public GHRepository getRepository() throws IOException { + return root.getRepository(repo.getName()); + } + + public GHUser getActor() throws IOException { + return root.getUser(actor.getLogin()); + } + + public GHOrganization getOrganization() throws IOException { + return (org==null || org.getLogin()==null) ? null : root.getOrganization(org.getLogin()); + } +} diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 81b584b4ef..d5a9eb830a 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -84,6 +84,9 @@ public String getUrl() { return html_url; } + /** + * String of the form "owner/reponame" + */ public String getName() { return name; } diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index ccc53816df..3e0fa44bc1 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -44,8 +44,10 @@ import java.net.URL; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Arrays; import java.util.Date; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Properties; import java.util.TimeZone; @@ -280,9 +282,29 @@ public GHOrganization getOrganization(String name) throws IOException { return o; } + /** + * Gets the repository object from 'user/reponame' string that GitHub calls as "repository name" + * + * @see GHRepository#getName() + */ + public GHRepository getRepository(String name) throws IOException { + String[] tokens = name.split("/"); + return getUser(tokens[0]).getRepository(tokens[1]); + } + public Map getMyOrganizations() throws IOException { return retrieveWithAuth("/organizations",JsonOrganizations.class).wrap(this); - + } + + /** + * Public events visible to you. Equivalent of what's displayed on https://github.com/ + */ + public List getEvents() throws IOException { + // TODO: pagenation + GHEventInfo[] events = retrieve3("/events", GHEventInfo[].class); + for (GHEventInfo e : events) + e.wrapUp(this); + return Arrays.asList(events); } /** diff --git a/src/test/java/org/kohsuke/AppTest.java b/src/test/java/org/kohsuke/AppTest.java index 7d8a1f8581..e36d3141b5 100644 --- a/src/test/java/org/kohsuke/AppTest.java +++ b/src/test/java/org/kohsuke/AppTest.java @@ -1,6 +1,8 @@ package org.kohsuke; import junit.framework.TestCase; +import org.kohsuke.github.GHEvent; +import org.kohsuke.github.GHEventInfo; import org.kohsuke.github.GHHook; import org.kohsuke.github.GHOrganization; import org.kohsuke.github.GHOrganization.Permission; @@ -56,6 +58,9 @@ public void tryHook() throws Exception { public void testApp() throws IOException { GitHub gitHub = GitHub.connect(); + for (GHEventInfo ev : gitHub.getEvents()) { + System.out.println(ev); + } // GHRepository r = gitHub.connect().getOrganization("jenkinsci").createRepository("kktest4", "Kohsuke's test", "http://kohsuke.org/", "Everyone", true); // r.fork(); From 696daf73875f29f87c693fe73c4e2d77ca614c82 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 8 Jan 2012 17:23:28 -0800 Subject: [PATCH 04/16] adding the payload handling --- .../java/org/kohsuke/github/GHEventInfo.java | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/GHEventInfo.java b/src/main/java/org/kohsuke/github/GHEventInfo.java index 3a2abe04ba..2d0ce14d14 100644 --- a/src/main/java/org/kohsuke/github/GHEventInfo.java +++ b/src/main/java/org/kohsuke/github/GHEventInfo.java @@ -1,9 +1,16 @@ package org.kohsuke.github; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.map.type.TypeFactory; import org.codehaus.jackson.node.ObjectNode; import java.io.IOException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.util.Date; +import java.util.Iterator; +import java.util.Map.Entry; /** * Represents an event. @@ -13,6 +20,7 @@ public class GHEventInfo { private GitHub root; + // we don't want to expose Jackson dependency to the user. This needs databinding private ObjectNode payload; private String created_at; @@ -24,8 +32,10 @@ public class GHEventInfo { private GHOrganization org; public GHEvent getType() { + String t = type; + if (t.endsWith("Event")) t=t.substring(0,t.length()-5); for (GHEvent e : GHEvent.values()) { - if (e.name().replace("_","").equalsIgnoreCase(type)) + if (e.name().replace("_","").equalsIgnoreCase(t)) return e; } return null; // unknown event type @@ -54,4 +64,49 @@ public GHUser getActor() throws IOException { public GHOrganization getOrganization() throws IOException { return (org==null || org.getLogin()==null) ? null : root.getOrganization(org.getLogin()); } + + /** + * Retrieves the payload. + * + * @param type + * Specify one of the {@link Payload} subtype that defines a type-safe access to the payload. + * This must match the {@linkplain #getType() event type}. + */ + public T getPayload(Class type) { + return type.cast(Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{type}, new InvocationHandler() { + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (method.getDeclaringClass() == Object.class) + return method.invoke(this, method, args); // hashCode, equals + + String name = method.getName(); + if (name.startsWith("get")) name = name.substring(3); + + Iterator> itr = payload.getFields(); + while (itr.hasNext()) { + Entry e = itr.next(); + if (e.getKey().replace("_","").equalsIgnoreCase(name)) { + return GitHub.MAPPER.readValue(e.getValue().traverse(), + TypeFactory.type(method.getGenericReturnType())); + } + } + + return null; + } + })); + } + + /** + * Marker interface for types used for databinding of the event payload. + */ + public interface Payload {} + + public interface CommitComment extends Payload { + // GHComment getComment(); + } + + public interface PullRequest extends Payload { + String getAction(); + int getNumber(); + GHPullRequest getPullRequest(); + } } From a4026d46ce0b7a14dbb6fe6a5e068a349c03078c Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 8 Jan 2012 18:14:57 -0800 Subject: [PATCH 05/16] after an experiment, revisiting the design --- pom.xml | 6 +++ .../java/org/kohsuke/github/GHEventInfo.java | 49 ++----------------- .../org/kohsuke/github/GHEventPayload.java | 40 +++++++++++++++ .../java/org/kohsuke/github/GHRepository.java | 2 +- src/main/java/org/kohsuke/github/GitHub.java | 14 ++++++ src/test/java/org/kohsuke/AppTest.java | 6 +++ src/test/java/org/kohsuke/HookApp.java | 29 +++++++++++ 7 files changed, 101 insertions(+), 45 deletions(-) create mode 100644 src/main/java/org/kohsuke/github/GHEventPayload.java create mode 100644 src/test/java/org/kohsuke/HookApp.java diff --git a/pom.xml b/pom.xml index 7869e99efa..621ba6f01f 100644 --- a/pom.xml +++ b/pom.xml @@ -77,6 +77,12 @@ 1.4 true + + org.kohsuke.stapler + stapler-jetty + 1.1 + test + diff --git a/src/main/java/org/kohsuke/github/GHEventInfo.java b/src/main/java/org/kohsuke/github/GHEventInfo.java index 2d0ce14d14..77ff2f6704 100644 --- a/src/main/java/org/kohsuke/github/GHEventInfo.java +++ b/src/main/java/org/kohsuke/github/GHEventInfo.java @@ -1,16 +1,9 @@ package org.kohsuke.github; -import org.codehaus.jackson.JsonNode; -import org.codehaus.jackson.map.type.TypeFactory; import org.codehaus.jackson.node.ObjectNode; import java.io.IOException; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; import java.util.Date; -import java.util.Iterator; -import java.util.Map.Entry; /** * Represents an event. @@ -69,44 +62,12 @@ public GHOrganization getOrganization() throws IOException { * Retrieves the payload. * * @param type - * Specify one of the {@link Payload} subtype that defines a type-safe access to the payload. + * Specify one of the {@link GHEventPayload} subtype that defines a type-safe access to the payload. * This must match the {@linkplain #getType() event type}. */ - public T getPayload(Class type) { - return type.cast(Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{type}, new InvocationHandler() { - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if (method.getDeclaringClass() == Object.class) - return method.invoke(this, method, args); // hashCode, equals - - String name = method.getName(); - if (name.startsWith("get")) name = name.substring(3); - - Iterator> itr = payload.getFields(); - while (itr.hasNext()) { - Entry e = itr.next(); - if (e.getKey().replace("_","").equalsIgnoreCase(name)) { - return GitHub.MAPPER.readValue(e.getValue().traverse(), - TypeFactory.type(method.getGenericReturnType())); - } - } - - return null; - } - })); - } - - /** - * Marker interface for types used for databinding of the event payload. - */ - public interface Payload {} - - public interface CommitComment extends Payload { - // GHComment getComment(); - } - - public interface PullRequest extends Payload { - String getAction(); - int getNumber(); - GHPullRequest getPullRequest(); + public T getPayload(Class type) throws IOException { + T v = GitHub.MAPPER.readValue(payload.traverse(), type); + v.wrapUp(root); + return v; } } diff --git a/src/main/java/org/kohsuke/github/GHEventPayload.java b/src/main/java/org/kohsuke/github/GHEventPayload.java new file mode 100644 index 0000000000..fefafd1477 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHEventPayload.java @@ -0,0 +1,40 @@ +package org.kohsuke.github; + +import java.io.Reader; + +/** + * Base type for types used in databinding of the event payload. + * + * @see GitHub#parseEventPayload(Reader, Class) + * @see GHEventInfo#getPayload(Class) + */ +public abstract class GHEventPayload { + protected GitHub root; + + /*package*/ GHEventPayload() { + } + + /*package*/ void wrapUp(GitHub root) { + this.root = root; + } + + public static class PullRequest extends GHEventPayload { + private String action; + private int number; + GHPullRequest pull_request; + + public String getAction() { + return action; + } + + public int getNumber() { + return number; + } + + public GHPullRequest getPullRequest() { + pull_request.root = root; + return pull_request; + } + } + +} diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index d5a9eb830a..594a86416d 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -324,7 +324,7 @@ public GHHook getHook(int id) throws IOException { * TODO: produce type-safe binding * * @param name - * Type of the hook to be created. + * Type of the hook to be created. See https://api.github.com/hooks for possible names. * @param config * The configuration hash. * @param events diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 3e0fa44bc1..5f6308b2b4 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -39,6 +39,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.InterruptedIOException; +import java.io.Reader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; @@ -306,6 +307,19 @@ public List getEvents() throws IOException { e.wrapUp(this); return Arrays.asList(events); } + + /** + * Parses the GitHub event object. + * + * This is primarily intended for receiving a POST HTTP call from a hook. + * Unfortunately, hook script payloads aren't self-descriptive, so you need + * to know the type of the payload you are expecting. + */ + public T parseEventPayload(Reader r, Class type) throws IOException { + T t = MAPPER.readValue(r, type); + t.wrapUp(this); + return t; + } /** * Creates a new repository. diff --git a/src/test/java/org/kohsuke/AppTest.java b/src/test/java/org/kohsuke/AppTest.java index e36d3141b5..c7a4532dc6 100644 --- a/src/test/java/org/kohsuke/AppTest.java +++ b/src/test/java/org/kohsuke/AppTest.java @@ -3,6 +3,7 @@ import junit.framework.TestCase; import org.kohsuke.github.GHEvent; import org.kohsuke.github.GHEventInfo; +import org.kohsuke.github.GHEventPayload; import org.kohsuke.github.GHHook; import org.kohsuke.github.GHOrganization; import org.kohsuke.github.GHOrganization.Permission; @@ -60,6 +61,11 @@ public void testApp() throws IOException { GitHub gitHub = GitHub.connect(); for (GHEventInfo ev : gitHub.getEvents()) { System.out.println(ev); + if (ev.getType()==GHEvent.PULL_REQUEST) { + GHEventPayload.PullRequest pr = ev.getPayload(GHEventPayload.PullRequest.class); + System.out.println(pr.getNumber()); + System.out.println(pr.getPullRequest()); + } } // GHRepository r = gitHub.connect().getOrganization("jenkinsci").createRepository("kktest4", "Kohsuke's test", "http://kohsuke.org/", "Everyone", true); diff --git a/src/test/java/org/kohsuke/HookApp.java b/src/test/java/org/kohsuke/HookApp.java new file mode 100644 index 0000000000..6eab20b6c4 --- /dev/null +++ b/src/test/java/org/kohsuke/HookApp.java @@ -0,0 +1,29 @@ +package org.kohsuke; + +import org.kohsuke.github.GHEventPayload; +import org.kohsuke.github.GitHub; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.jetty.JettyRunner; + +import java.io.IOException; +import java.io.StringReader; + +/** + * @author Kohsuke Kawaguchi + */ +public class HookApp { + public static void main(String[] args) throws Exception { +// GitHub.connect().getMyself().getRepository("sandbox").createWebHook( +// new URL("http://173.203.118.45:18080/"), EnumSet.of(GHEvent.PULL_REQUEST)); + JettyRunner jr = new JettyRunner(new HookApp()); + jr.addHttpListener(8080); + jr.start(); + } + + public void doIndex(StaplerRequest req) throws IOException { + String str = req.getParameter("payload"); + System.out.println(str); + GHEventPayload.PullRequest o = GitHub.connect().parseEventPayload(new StringReader(str),GHEventPayload.PullRequest.class); + System.out.println(o); + } +} From 57b26b6a211b9edafd66c58008f0bea1171ac95f Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 8 Jan 2012 18:19:38 -0800 Subject: [PATCH 06/16] doc improvement --- src/main/java/org/kohsuke/github/GHPullRequest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java index 323b5874a7..8a7c20f042 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequest.java +++ b/src/main/java/org/kohsuke/github/GHPullRequest.java @@ -25,7 +25,6 @@ import java.net.URL; import java.util.Date; -import java.util.Locale; /** * A pull request. @@ -64,7 +63,7 @@ public GHCommitPointer getBase() { } /** - * The change that should be pulled. + * The change that should be pulled. The tip of the commits to merge. */ public GHCommitPointer getHead() { return head; From 748cbdd03b6ac82a55807a910e6b004b8f3b0a88 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 8 Jan 2012 18:19:43 -0800 Subject: [PATCH 07/16] doc improvement --- src/test/java/org/kohsuke/HookApp.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/org/kohsuke/HookApp.java b/src/test/java/org/kohsuke/HookApp.java index 6eab20b6c4..aac24ddf84 100644 --- a/src/test/java/org/kohsuke/HookApp.java +++ b/src/test/java/org/kohsuke/HookApp.java @@ -9,6 +9,9 @@ import java.io.StringReader; /** + * App to test the hook script. You need some internet-facing server that can forward the request to you + * (typically via SSH reverse port forwarding.) + * * @author Kohsuke Kawaguchi */ public class HookApp { From 222277ae0a86ce44d749f9886301624cd563b53d Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 14 Jan 2012 11:42:09 -0800 Subject: [PATCH 08/16] doc improvement --- src/main/java/org/kohsuke/github/GHCommitPointer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/GHCommitPointer.java b/src/main/java/org/kohsuke/github/GHCommitPointer.java index 3e0a5d4ad0..4b95be45f7 100644 --- a/src/main/java/org/kohsuke/github/GHCommitPointer.java +++ b/src/main/java/org/kohsuke/github/GHCommitPointer.java @@ -49,7 +49,7 @@ public GHRepository getRepository() { } /** - * Named ref to the commit. + * Named ref to the commit. This appears to be a "short ref" that doesn't include "refs/heads/" portion. */ public String getRef() { return ref; From b950be9626a16a5d8aec94e7cfd42138d38a981c Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 14 Jan 2012 11:53:53 -0800 Subject: [PATCH 09/16] bug fix in the event API. Turns out GHRepository isn't usable for this, because the name field is different. /repos/:user/:repo returns just ":repo" portion in the name field, whereas in the event it has both ":user/:repo" --- src/main/java/org/kohsuke/github/GHEventInfo.java | 15 ++++++++++++--- .../java/org/kohsuke/github/GHRepository.java | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHEventInfo.java b/src/main/java/org/kohsuke/github/GHEventInfo.java index 77ff2f6704..fe9aada27f 100644 --- a/src/main/java/org/kohsuke/github/GHEventInfo.java +++ b/src/main/java/org/kohsuke/github/GHEventInfo.java @@ -20,10 +20,19 @@ public class GHEventInfo { private String type; // these are all shallow objects - private GHRepository repo; + private GHEventRepository repo; private GHUser actor; private GHOrganization org; - + + /** + * Inside the event JSON model, GitHub uses a slightly different format. + */ + public static class GHEventRepository { + private int id; + private String url; // repository API URL + private String name; // owner/repo + } + public GHEvent getType() { String t = type; if (t.endsWith("Event")) t=t.substring(0,t.length()-5); @@ -47,7 +56,7 @@ public Date getCreatedAt() { * Repository where the change was made. */ public GHRepository getRepository() throws IOException { - return root.getRepository(repo.getName()); + return root.getRepository(repo.name); } public GHUser getActor() throws IOException { diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 594a86416d..806e1f3b4c 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -85,7 +85,7 @@ public String getUrl() { } /** - * String of the form "owner/reponame" + * Short repository name without the owner. For example 'jenkins' in case of http://github.com/jenkinsci/jenkins */ public String getName() { return name; From 58af8d0e906413e344bc999b44991b3bebab8843 Mon Sep 17 00:00:00 2001 From: Michael O'Cleirigh Date: Tue, 31 Jan 2012 21:50:39 -0500 Subject: [PATCH 10/16] Add support for github enterprise different base url This changes how the ApiVersion enumeration works so that each of the V2 and V3 Url schemes is actually a template. Then the serverName/hostname to use is passed in and used to generate the full url. This will allow the github-api project to be used against users running the enterprise version of github. This is needed to support github enterprise based authentication with the github-oauth-plugin. --- .../java/org/kohsuke/github/ApiVersion.java | 17 +++++++++++----- src/main/java/org/kohsuke/github/GitHub.java | 20 +++++++++++++------ 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/kohsuke/github/ApiVersion.java b/src/main/java/org/kohsuke/github/ApiVersion.java index 52ecedb14e..922dbe7aa1 100644 --- a/src/main/java/org/kohsuke/github/ApiVersion.java +++ b/src/main/java/org/kohsuke/github/ApiVersion.java @@ -6,12 +6,19 @@ * @author Kohsuke Kawaguchi */ enum ApiVersion { - V2("https://github.com/api/v2/json"), - V3("https://api.github.com"); + + V2("https://?/api/v2/json"), + V3("https://api.?"); - final String url; + final String templateUrl; - ApiVersion(String url) { - this.url = url; + ApiVersion(String templateUrl) { + this.templateUrl = templateUrl; + } + + public String getApiVersionBaseUrl(String githubServer) { + + return templateUrl.replaceFirst("\\?", githubServer); + } } diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 5f6308b2b4..4669ae1e3e 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -70,9 +70,16 @@ public class GitHub { private final Map users = new HashMap(); private final Map orgs = new HashMap(); /*package*/ String oauthAccessToken; + + private final String githubServer; - private GitHub(String login, String apiToken, String password) { - this.login = login; + private GitHub(String login, String apiToken, String password) { + this ("github.com", login, apiToken, password); + } + + private GitHub(String githubServer, String login, String apiToken, String password) { + this.githubServer = githubServer; + this.login = login; this.apiToken = apiToken; this.password = password; @@ -84,8 +91,9 @@ private GitHub(String login, String apiToken, String password) { encodedAuthorization = null; } - private GitHub (String oauthAccessToken) throws IOException { + private GitHub (String githubServer, String oauthAccessToken) throws IOException { + this.githubServer = githubServer; this.password = null; this.encodedAuthorization = null; @@ -118,8 +126,8 @@ public static GitHub connect(String login, String apiToken, String password) thr return new GitHub(login,apiToken,password); } - public static GitHub connectUsingOAuth (String accessToken) throws IOException { - return new GitHub(accessToken); + public static GitHub connectUsingOAuth (String githubServer, String accessToken) throws IOException { + return new GitHub(githubServer, accessToken); } /** * Connects to GitHub anonymously. @@ -141,7 +149,7 @@ public static GitHub connectAnonymously() { tailApiUrl = tailApiUrl + (tailApiUrl.indexOf('?')>=0 ?'&':'?') + "access_token=" + oauthAccessToken; } - return new URL(v.url+tailApiUrl); + return new URL(v.getApiVersionBaseUrl(githubServer)+tailApiUrl); } /*package*/ T retrieve(String tailApiUrl, Class type) throws IOException { From 202a5d435c47aa84130873a5d0e2a45438244ac8 Mon Sep 17 00:00:00 2001 From: Michael O'Cleirigh Date: Wed, 1 Feb 2012 21:24:19 -0500 Subject: [PATCH 11/16] Add original GitHub.connectUsingOAuth(token) back This adds the original API back which defaults to the 'github.com' server. --- src/main/java/org/kohsuke/github/GitHub.java | 28 +++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 4669ae1e3e..8f3c472c58 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -23,14 +23,10 @@ */ package org.kohsuke.github; -import com.gargoylesoftware.htmlunit.WebClient; -import com.gargoylesoftware.htmlunit.html.HtmlForm; -import com.gargoylesoftware.htmlunit.html.HtmlPage; -import org.apache.commons.io.IOUtils; -import org.codehaus.jackson.map.DeserializationConfig.Feature; -import org.codehaus.jackson.map.ObjectMapper; -import org.codehaus.jackson.map.introspect.VisibilityChecker.Std; -import sun.misc.BASE64Encoder; +import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.ANY; +import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.NONE; +import static org.kohsuke.github.ApiVersion.V2; +import static org.kohsuke.github.ApiVersion.V3; import java.io.File; import java.io.FileInputStream; @@ -53,8 +49,16 @@ import java.util.Properties; import java.util.TimeZone; -import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.*; -import static org.kohsuke.github.ApiVersion.*; +import org.apache.commons.io.IOUtils; +import org.codehaus.jackson.map.DeserializationConfig.Feature; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.introspect.VisibilityChecker.Std; + +import sun.misc.BASE64Encoder; + +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlPage; /** * Root of the GitHub API. @@ -126,6 +130,10 @@ public static GitHub connect(String login, String apiToken, String password) thr return new GitHub(login,apiToken,password); } + public static GitHub connectUsingOAuth (String accessToken) throws IOException { + return connectUsingOAuth("github.com", accessToken); + } + public static GitHub connectUsingOAuth (String githubServer, String accessToken) throws IOException { return new GitHub(githubServer, accessToken); } From 2718cf5ccba722a2d31e05a00a20a61ab5cada43 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 12 Feb 2012 07:27:39 -0800 Subject: [PATCH 12/16] support both v2 and v3 --- src/main/java/org/kohsuke/github/GHCommitPointer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHCommitPointer.java b/src/main/java/org/kohsuke/github/GHCommitPointer.java index 4b95be45f7..184ccc4d69 100644 --- a/src/main/java/org/kohsuke/github/GHCommitPointer.java +++ b/src/main/java/org/kohsuke/github/GHCommitPointer.java @@ -31,7 +31,7 @@ public class GHCommitPointer { private String ref, sha, label; private GHUser user; - private GHRepository repository; + private GHRepository repository/*V2*/,repo/*V3*/; /** * This points to the user who owns @@ -45,7 +45,7 @@ public GHUser getUser() { * The repository that contains the commit. */ public GHRepository getRepository() { - return repository; + return repo!=null ? repo : repository; } /** From dac2a566715f31265488f34e5004109ba5f89ec8 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 12 Feb 2012 07:43:06 -0800 Subject: [PATCH 13/16] fully populate the root field upon deserialization --- src/main/java/org/kohsuke/github/GHCommitPointer.java | 6 ++++++ src/main/java/org/kohsuke/github/GHEventPayload.java | 6 ++++++ src/main/java/org/kohsuke/github/GHPullRequest.java | 9 +++++++++ 3 files changed, 21 insertions(+) diff --git a/src/main/java/org/kohsuke/github/GHCommitPointer.java b/src/main/java/org/kohsuke/github/GHCommitPointer.java index 184ccc4d69..c4d67f6410 100644 --- a/src/main/java/org/kohsuke/github/GHCommitPointer.java +++ b/src/main/java/org/kohsuke/github/GHCommitPointer.java @@ -68,4 +68,10 @@ public String getSha() { public String getLabel() { return label; } + + void wrapUp(GitHub root) { + if (user!=null) user.root = root; + if (repo!=null) repo.wrap(root); + if (repository!=null) repository.wrap(root); + } } diff --git a/src/main/java/org/kohsuke/github/GHEventPayload.java b/src/main/java/org/kohsuke/github/GHEventPayload.java index fefafd1477..efb3d0d3fe 100644 --- a/src/main/java/org/kohsuke/github/GHEventPayload.java +++ b/src/main/java/org/kohsuke/github/GHEventPayload.java @@ -35,6 +35,12 @@ public GHPullRequest getPullRequest() { pull_request.root = root; return pull_request; } + + @Override + void wrapUp(GitHub root) { + super.wrapUp(root); + pull_request.wrapUp(root); + } } } diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java index 8a7c20f042..4ad028f0e5 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequest.java +++ b/src/main/java/org/kohsuke/github/GHPullRequest.java @@ -92,4 +92,13 @@ public URL getDiffUrl() { public Date getClosedAt() { return GitHub.parseDate(closed_at); } + + void wrapUp(GitHub root) { + this.root = root; + if (owner!=null) owner.wrap(root); + if (issue_user!=null) issue_user.root=root; + if (user!=null) user.root=root; + if (base!=null) base.wrapUp(root); + if (head!=null) head.wrapUp(root); + } } From e8ff7a4ae8fede7ac8d5235be28dfacd814c6be8 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 12 Feb 2012 08:11:15 -0800 Subject: [PATCH 14/16] updated to use V3 API --- .../org/kohsuke/github/GHPullRequest.java | 8 +++- .../java/org/kohsuke/github/GHRepository.java | 7 +++- .../org/kohsuke/github/JsonPullRequest.java | 37 ----------------- .../org/kohsuke/github/JsonPullRequests.java | 41 ------------------- src/test/java/org/kohsuke/AppTest.java | 8 ++++ 5 files changed, 20 insertions(+), 81 deletions(-) delete mode 100644 src/main/java/org/kohsuke/github/JsonPullRequest.java delete mode 100644 src/main/java/org/kohsuke/github/JsonPullRequests.java diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java index 4ad028f0e5..1f86981e0f 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequest.java +++ b/src/main/java/org/kohsuke/github/GHPullRequest.java @@ -93,12 +93,18 @@ public Date getClosedAt() { return GitHub.parseDate(closed_at); } - void wrapUp(GitHub root) { + GHPullRequest wrapUp(GHRepository owner) { + this.owner = owner; + return wrapUp(owner.root); + } + + GHPullRequest wrapUp(GitHub root) { this.root = root; if (owner!=null) owner.wrap(root); if (issue_user!=null) issue_user.root=root; if (user!=null) user.root=root; if (base!=null) base.wrapUp(root); if (head!=null) head.wrapUp(root); + return this; } } diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 806e1f3b4c..342923e05a 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -293,14 +293,17 @@ public void renameTo(String newName) throws IOException { * Retrieves a specified pull request. */ public GHPullRequest getPullRequest(int i) throws IOException { - return root.retrieveWithAuth("/pulls/" + owner.login + '/' + name + "/" + i, JsonPullRequest.class).wrap(this); + return root.retrieveWithAuth3("/repos/" + owner.login + '/' + name + "/pulls/" + i, GHPullRequest.class).wrapUp(this); } /** * Retrieves all the pull requests of a particular state. */ public List getPullRequests(GHIssueState state) throws IOException { - return root.retrieveWithAuth("/pulls/"+owner.login+'/'+name+"/"+state.name().toLowerCase(Locale.ENGLISH),JsonPullRequests.class).wrap(this); + GHPullRequest[] r = root.retrieveWithAuth3("/repos/" + owner.login + '/' + name + "/pulls?state=" + state.name().toLowerCase(Locale.ENGLISH), GHPullRequest[].class); + for (GHPullRequest p : r) + p.wrapUp(this); + return new ArrayList(Arrays.asList(r)); } /** diff --git a/src/main/java/org/kohsuke/github/JsonPullRequest.java b/src/main/java/org/kohsuke/github/JsonPullRequest.java deleted file mode 100644 index 80cc367b2a..0000000000 --- a/src/main/java/org/kohsuke/github/JsonPullRequest.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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; - -/** - * @author Kohsuke Kawaguchi - */ -class JsonPullRequest { - public GHPullRequest pull; - - public GHPullRequest wrap(GHRepository owner) { - pull.owner = owner; - pull.root = owner.root; - return pull; - } -} diff --git a/src/main/java/org/kohsuke/github/JsonPullRequests.java b/src/main/java/org/kohsuke/github/JsonPullRequests.java deleted file mode 100644 index fd5e47eb58..0000000000 --- a/src/main/java/org/kohsuke/github/JsonPullRequests.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.util.List; - -/** - * @author Kohsuke Kawaguchi - */ -class JsonPullRequests { - public List pulls; - - public List wrap(GHRepository owner) { - for (GHPullRequest pull : pulls) { - pull.owner = owner; - pull.root = owner.root; - } - return pulls; - } -} diff --git a/src/test/java/org/kohsuke/AppTest.java b/src/test/java/org/kohsuke/AppTest.java index c7a4532dc6..8e49623f93 100644 --- a/src/test/java/org/kohsuke/AppTest.java +++ b/src/test/java/org/kohsuke/AppTest.java @@ -5,6 +5,7 @@ import org.kohsuke.github.GHEventInfo; import org.kohsuke.github.GHEventPayload; import org.kohsuke.github.GHHook; +import org.kohsuke.github.GHIssueState; import org.kohsuke.github.GHOrganization; import org.kohsuke.github.GHOrganization.Permission; import org.kohsuke.github.GHRepository; @@ -24,6 +25,13 @@ public void testCredentialValid() throws IOException { assertFalse(GitHub.connect("totally","bogus").isCredentialValid()); } + public void testFetchPullRequest() throws Exception { + GitHub gh = GitHub.connect(); + GHRepository r = gh.getOrganization("jenkinsci").getRepository("jenkins"); + r.getPullRequest(1); + r.getPullRequests(GHIssueState.OPEN); + } + public void tryOrgFork() throws Exception { GitHub gh = GitHub.connect(); gh.getUser("kohsuke").getRepository("rubywm").forkTo(gh.getOrganization("jenkinsci")); From 830fb7192d039cac86ce249f5320e148bb555551 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 12 Feb 2012 08:20:10 -0800 Subject: [PATCH 15/16] added additional convenience method --- .../java/org/kohsuke/github/GHRepository.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 342923e05a..20392d1192 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -78,12 +78,28 @@ public String getHomepage() { } /** - * URL of this repository, like 'http://github.com/kohsuke/hudson' + * URL of this repository, like 'http://github.com/kohsuke/jenkins' */ public String getUrl() { return html_url; } + /** + * Gets the git:// URL to this repository, such as "git://github.com/kohsuke/jenkins.git" + * This URL is read-only. + */ + public String getGitTransportUrl() { + return "git://github.com/"+getOwnerName()+"/"+name+".git"; + } + + /** + * Gets the HTTPS URL to this repository, such as "https://github.com/kohsuke/jenkins.git" + * This URL is read-only. + */ + public String gitHttpTransportUrl() { + return "https://github.com/"+getOwnerName()+"/"+name+".git"; + } + /** * Short repository name without the owner. For example 'jenkins' in case of http://github.com/jenkinsci/jenkins */ From a9b6f7bc9c4dd3eb268e1af7d89a2a2a5fe8ccc7 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 12 Feb 2012 09:30:06 -0800 Subject: [PATCH 16/16] [maven-release-plugin] prepare release github-api-1.17 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 621ba6f01f..b8aadaafff 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ github-api - 1.17-SNAPSHOT + 1.17 GitHub API for Java http://github-api.kohsuke.org/ GitHub API for Java