diff --git a/pom.xml b/pom.xml
index 7f3bb58efa..2dfa10b3b6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
org.kohsuke
github-api
jar
- 1.7
+ 1.8
GitHub API for Java
http://kohsuke.org/github-api/
GitHub API for Java
diff --git a/src/main/java/org/kohsuke/github/GHCommitPointer.java b/src/main/java/org/kohsuke/github/GHCommitPointer.java
new file mode 100644
index 0000000000..3e0a5d4ad0
--- /dev/null
+++ b/src/main/java/org/kohsuke/github/GHCommitPointer.java
@@ -0,0 +1,71 @@
+/*
+ * 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;
+
+/**
+ * Identifies a commit in {@link GHPullRequest}.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class GHCommitPointer {
+ private String ref, sha, label;
+ private GHUser user;
+ private GHRepository repository;
+
+ /**
+ * This points to the user who owns
+ * the {@link #repository}.
+ */
+ public GHUser getUser() {
+ return user;
+ }
+
+ /**
+ * The repository that contains the commit.
+ */
+ public GHRepository getRepository() {
+ return repository;
+ }
+
+ /**
+ * Named ref to the commit.
+ */
+ public String getRef() {
+ return ref;
+ }
+
+ /**
+ * SHA1 of the commit.
+ */
+ public String getSha() {
+ return sha;
+ }
+
+ /**
+ * String that looks like "USERNAME:REF".
+ */
+ public String getLabel() {
+ return label;
+ }
+}
diff --git a/src/main/java/org/kohsuke/github/GHOrganization.java b/src/main/java/org/kohsuke/github/GHOrganization.java
index 8f08877862..a8bfb7f1e9 100644
--- a/src/main/java/org/kohsuke/github/GHOrganization.java
+++ b/src/main/java/org/kohsuke/github/GHOrganization.java
@@ -1,12 +1,16 @@
package org.kohsuke.github;
import com.gargoylesoftware.htmlunit.WebClient;
+import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
+import org.kohsuke.github.GHPullRequest.State;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
/**
@@ -63,4 +67,29 @@ public GHTeam createTeam(String name, Permission p, GHRepository... repositories
return createTeam(name,p, Arrays.asList(repositories));
}
+ /**
+ * List up repositories that has some open pull requests.
+ */
+ public List getRepositoriesWithOpenPullRequests() throws IOException {
+ WebClient wc = root.createWebClient();
+ HtmlPage pg = (HtmlPage)wc.getPage("https://github.com/organizations/"+login+"/dashboard/pulls");
+ List r = new ArrayList();
+ for (HtmlAnchor e : pg.getElementById("js-issue-list").selectNodes(".//UL[@class='smallnav']/LI[not(@class='zeroed')]/A")) {
+ String a = e.getHrefAttribute();
+ String name = a.substring(a.lastIndexOf('/')+1);
+ r.add(getRepository(name));
+ }
+ return r;
+ }
+
+ /**
+ * Gets all the open pull requests in this organizataion.
+ */
+ public List getPullRequests() throws IOException {
+ List all = new ArrayList();
+ for (GHRepository r : getRepositoriesWithOpenPullRequests()) {
+ all.addAll(r.getPullRequests(State.OPEN));
+ }
+ return all;
+ }
}
diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java
new file mode 100644
index 0000000000..995c4b8aa3
--- /dev/null
+++ b/src/main/java/org/kohsuke/github/GHPullRequest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.net.URL;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * A pull request.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+@SuppressWarnings({"UnusedDeclaration"})
+public class GHPullRequest {
+ /*package almost final*/ GitHub root;
+
+ private String gravatar_id, closed_at, state, body, created_at, patch_url, issue_updated_at;
+ private int number, position, comments, votes;
+ private GHUser issue_user, user;
+ // labels??
+ private GHCommitPointer base, head;
+ private String mergeable, updated_at, html_url, title, diff_url;
+
+ public enum State {
+ OPEN, CLOSED
+ }
+
+ /**
+ * The description of this pull request.
+ */
+ public String getBody() {
+ return body;
+ }
+
+ /**
+ * The URL of the patch file.
+ * like https://github.com/jenkinsci/jenkins/pull/100.patch
+ */
+ public URL getPatchUrl() {
+ return GitHub.parseURL(patch_url);
+ }
+
+ /**
+ * ID.
+ */
+ public int getNumber() {
+ return number;
+ }
+
+ /**
+ * User who submitted a pull request.
+ */
+ public GHUser getUser() {
+ return user;
+ }
+
+ /**
+ * Repository to which the pull request was sent.
+ */
+ public GHRepository getRepository() {
+ return getBase().getRepository();
+ }
+
+ /**
+ * This points to where the change should be pulled into,
+ * but I'm not really sure what exactly it means.
+ */
+ public GHCommitPointer getBase() {
+ return base;
+ }
+
+ /**
+ * The change that should be pulled.
+ */
+ public GHCommitPointer getHead() {
+ return head;
+ }
+
+ /**
+ * The HTML page of this pull request,
+ * like https://github.com/jenkinsci/jenkins/pull/100
+ */
+ public URL getUrl() {
+ return GitHub.parseURL(html_url);
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ * The diff file,
+ * like https://github.com/jenkinsci/jenkins/pull/100.diff
+ */
+ public URL getDiffUrl() {
+ return GitHub.parseURL(diff_url);
+ }
+
+ public Date getClosedAt() {
+ return GitHub.parseDate(closed_at);
+ }
+
+ public Date getCreatedAt() {
+ return GitHub.parseDate(created_at);
+ }
+
+ public Date getUpdatedAt() {
+ return GitHub.parseDate(updated_at);
+ }
+
+ public State getState() {
+ return State.valueOf(state.toUpperCase(Locale.ENGLISH));
+ }
+}
diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java
index be17ed46dd..1c49524f92 100644
--- a/src/main/java/org/kohsuke/github/GHRepository.java
+++ b/src/main/java/org/kohsuke/github/GHRepository.java
@@ -27,7 +27,6 @@
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlButton;
import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
-import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlInput;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
@@ -36,8 +35,6 @@
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URL;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
@@ -46,6 +43,7 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Locale;
import java.util.Set;
import static java.util.Arrays.*;
@@ -55,6 +53,7 @@
*
* @author Kohsuke Kawaguchi
*/
+@SuppressWarnings({"UnusedDeclaration"})
public class GHRepository {
/*package almost final*/ GitHub root;
@@ -119,19 +118,11 @@ public int getWatchers() {
}
public Date getPushedAt() {
- return parseDate(pushed_at);
+ return GitHub.parseDate(pushed_at);
}
public Date getCreatedAt() {
- return parseDate(created_at);
- }
-
- private Date parseDate(String timestamp) {
- try {
- return new SimpleDateFormat(TIME_FORMAT).parse(timestamp);
- } catch (ParseException e) {
- throw new IllegalStateException("Unable to parse the timestamp: "+pushed_at);
- }
+ return GitHub.parseDate(created_at);
}
@@ -178,7 +169,7 @@ public void setEmailServiceHook(String address) throws IOException {
active.setChecked(true);
final HtmlForm f = email.getEnclosingFormOrDie();
- f.submit((HtmlButton)f.getElementsByTagName("button").get(0));
+ f.submit((HtmlButton) f.getElementsByTagName("button").get(0));
}
/**
@@ -260,6 +251,27 @@ public void renameTo(String newName) throws IOException {
throw new IllegalArgumentException("Either you don't have the privilege to rename "+owner+'/'+name+" or there's a bug in HTML scraping");
}
+ /**
+ * Retrieves a specified pull request.
+ */
+ public GHPullRequest getPullRequest(int i) throws IOException {
+ return root.retrieveWithAuth("/pulls/" + owner + '/' + name + "/" + i, JsonPullRequest.class).wrap(root);
+ }
+
+ /**
+ * Retrieves all the pull requests of a particular state.
+ */
+ public List getPullRequests(GHPullRequest.State state) throws IOException {
+ return root.retrieveWithAuth("/pulls/"+owner+'/'+name+"/"+state.name().toLowerCase(Locale.ENGLISH),JsonPullRequests.class).wrap(root);
+ }
+
+// this is no different from getPullRequests(OPEN)
+// /**
+// * Retrieves all the pull requests.
+// */
+// public List getPullRequests() throws IOException {
+// return root.retrieveWithAuth("/pulls/"+owner+'/'+name,JsonPullRequests.class).wrap(root);
+// }
private void verifyMine() throws IOException {
if (!root.login.equals(owner))
@@ -371,5 +383,18 @@ public String toString() {
return "Repository:"+owner+":"+name;
}
- private static final String TIME_FORMAT = "yyyy/MM/dd HH:mm:ss ZZZZ";
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof GHRepository) {
+ GHRepository that = (GHRepository) obj;
+ return this.owner.equals(that.owner)
+ && this.name.equals(that.name);
+ }
+ return false;
+ }
}
diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java
index db791305a1..c5dae6ec0c 100644
--- a/src/main/java/org/kohsuke/github/GitHub.java
+++ b/src/main/java/org/kohsuke/github/GitHub.java
@@ -38,7 +38,11 @@
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
import java.net.URL;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
@@ -242,9 +246,29 @@ WebClient createWebClient() throws IOException {
return wc;
}
+ /*package*/ static URL parseURL(String s) {
+ try {
+ return s==null ? null : new URL(s);
+ } catch (MalformedURLException e) {
+ throw new IllegalStateException("Invalid URL: "+s);
+ }
+ }
+
+ /*package*/ static Date parseDate(String timestamp) {
+ for (String f : TIME_FORMATS) {
+ try {
+ return new SimpleDateFormat(f).parse(timestamp);
+ } catch (ParseException e) {
+ // try next
+ }
+ }
+ throw new IllegalStateException("Unable to parse the timestamp: "+timestamp);
+ }
/*package*/ static final ObjectMapper MAPPER = new ObjectMapper();
+ private static final String[] TIME_FORMATS = {"yyyy/MM/dd HH:mm:ss ZZZZ","yyyy-MM-dd'T'HH:mm:ss'Z'"};
+
static {
MAPPER.setVisibilityChecker(new Std(NONE, NONE, NONE, NONE, ANY));
MAPPER.getDeserializationConfig().set(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
diff --git a/src/main/java/org/kohsuke/github/JsonPullRequest.java b/src/main/java/org/kohsuke/github/JsonPullRequest.java
new file mode 100644
index 0000000000..7e70c48aca
--- /dev/null
+++ b/src/main/java/org/kohsuke/github/JsonPullRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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(GitHub root) {
+ pull.root = root;
+ return pull;
+ }
+}
diff --git a/src/main/java/org/kohsuke/github/JsonPullRequests.java b/src/main/java/org/kohsuke/github/JsonPullRequests.java
new file mode 100644
index 0000000000..24cc048690
--- /dev/null
+++ b/src/main/java/org/kohsuke/github/JsonPullRequests.java
@@ -0,0 +1,39 @@
+/*
+ * 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(GitHub root) {
+ for (GHPullRequest pull : pulls)
+ pull.root = root;
+ return pulls;
+ }
+}
diff --git a/src/test/java/org/kohsuke/AppTest.java b/src/test/java/org/kohsuke/AppTest.java
index bb0749e826..5852dab638 100644
--- a/src/test/java/org/kohsuke/AppTest.java
+++ b/src/test/java/org/kohsuke/AppTest.java
@@ -3,13 +3,20 @@
import junit.framework.TestCase;
import org.kohsuke.github.GHOrganization;
import org.kohsuke.github.GHOrganization.Permission;
+import org.kohsuke.github.GHPullRequest;
+import org.kohsuke.github.GHPullRequest.State;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GHTeam;
import org.kohsuke.github.GitHub;
import java.io.IOException;
import java.net.URL;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
/**
* Unit test for simple App.