Compare commits

..

11 Commits

Author SHA1 Message Date
Kohsuke Kawaguchi
fa761bf280 [maven-release-plugin] prepare release github-api-1.8 2011-06-16 23:50:53 -07:00
Kohsuke Kawaguchi
3cba773184 removed a local test 2011-06-16 23:50:36 -07:00
Kohsuke Kawaguchi
073b0e6d7f added more convenience methods 2011-06-16 22:39:47 -07:00
Kohsuke Kawaguchi
dc150b7680 GitHub uses different formats in different places 2011-06-16 22:20:45 -07:00
Kohsuke Kawaguchi
6c7b891397 added a page-scraping based method of listing up all the pull requests 2011-06-16 22:03:47 -07:00
Kohsuke Kawaguchi
795c642f49 this doesn't work as intended. 2011-06-16 21:36:55 -07:00
Kohsuke Kawaguchi
559cc37055 added pull request support 2011-06-16 21:32:28 -07:00
Kohsuke Kawaguchi
4b5816242a moved the convenience method here so that I can use it from elsewhere 2011-06-16 21:18:40 -07:00
Kohsuke Kawaguchi
2864d650cc added a convenience method 2011-06-16 21:14:58 -07:00
Kohsuke Kawaguchi
bc2da22671 added value equality 2011-06-16 21:04:40 -07:00
Kohsuke Kawaguchi
2df450c199 [maven-release-plugin] prepare for next development iteration 2011-05-28 15:25:48 +02:00
9 changed files with 383 additions and 16 deletions

View File

@@ -3,7 +3,7 @@
<groupId>org.kohsuke</groupId> <groupId>org.kohsuke</groupId>
<artifactId>github-api</artifactId> <artifactId>github-api</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<version>1.7</version> <version>1.8</version>
<name>GitHub API for Java</name> <name>GitHub API for Java</name>
<url>http://kohsuke.org/github-api/</url> <url>http://kohsuke.org/github-api/</url>
<description>GitHub API for Java</description> <description>GitHub API for Java</description>

View File

@@ -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;
}
}

View File

@@ -1,12 +1,16 @@
package org.kohsuke.github; package org.kohsuke.github;
import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.html.HtmlPage;
import org.kohsuke.github.GHPullRequest.State;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@@ -63,4 +67,29 @@ public class GHOrganization extends GHPerson {
return createTeam(name,p, Arrays.asList(repositories)); return createTeam(name,p, Arrays.asList(repositories));
} }
/**
* List up repositories that has some open pull requests.
*/
public List<GHRepository> getRepositoriesWithOpenPullRequests() throws IOException {
WebClient wc = root.createWebClient();
HtmlPage pg = (HtmlPage)wc.getPage("https://github.com/organizations/"+login+"/dashboard/pulls");
List<GHRepository> r = new ArrayList<GHRepository>();
for (HtmlAnchor e : pg.getElementById("js-issue-list").<HtmlAnchor>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<GHPullRequest> getPullRequests() throws IOException {
List<GHPullRequest> all = new ArrayList<GHPullRequest>();
for (GHRepository r : getRepositoriesWithOpenPullRequests()) {
all.addAll(r.getPullRequests(State.OPEN));
}
return all;
}
} }

View File

@@ -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));
}
}

View File

@@ -27,7 +27,6 @@ import com.gargoylesoftware.htmlunit.ElementNotFoundException;
import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlButton; import com.gargoylesoftware.htmlunit.html.HtmlButton;
import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput; import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlInput; import com.gargoylesoftware.htmlunit.html.HtmlInput;
import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.html.HtmlPage;
@@ -36,8 +35,6 @@ import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.net.URL; import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.AbstractSet; import java.util.AbstractSet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@@ -46,6 +43,7 @@ import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Set; import java.util.Set;
import static java.util.Arrays.*; import static java.util.Arrays.*;
@@ -55,6 +53,7 @@ import static java.util.Arrays.*;
* *
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
@SuppressWarnings({"UnusedDeclaration"})
public class GHRepository { public class GHRepository {
/*package almost final*/ GitHub root; /*package almost final*/ GitHub root;
@@ -119,19 +118,11 @@ public class GHRepository {
} }
public Date getPushedAt() { public Date getPushedAt() {
return parseDate(pushed_at); return GitHub.parseDate(pushed_at);
} }
public Date getCreatedAt() { public Date getCreatedAt() {
return parseDate(created_at); return GitHub.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);
}
} }
@@ -178,7 +169,7 @@ public class GHRepository {
active.setChecked(true); active.setChecked(true);
final HtmlForm f = email.getEnclosingFormOrDie(); 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 class GHRepository {
throw new IllegalArgumentException("Either you don't have the privilege to rename "+owner+'/'+name+" or there's a bug in HTML scraping"); 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<GHPullRequest> 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<GHPullRequest> getPullRequests() throws IOException {
// return root.retrieveWithAuth("/pulls/"+owner+'/'+name,JsonPullRequests.class).wrap(root);
// }
private void verifyMine() throws IOException { private void verifyMine() throws IOException {
if (!root.login.equals(owner)) if (!root.login.equals(owner))
@@ -371,5 +383,18 @@ public class GHRepository {
return "Repository:"+owner+":"+name; 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;
}
} }

View File

@@ -38,7 +38,11 @@ import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.InterruptedIOException; import java.io.InterruptedIOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
@@ -242,9 +246,29 @@ public class GitHub {
return wc; 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(); /*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 { static {
MAPPER.setVisibilityChecker(new Std(NONE, NONE, NONE, NONE, ANY)); MAPPER.setVisibilityChecker(new Std(NONE, NONE, NONE, NONE, ANY));
MAPPER.getDeserializationConfig().set(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); MAPPER.getDeserializationConfig().set(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

View File

@@ -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;
}
}

View File

@@ -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<GHPullRequest> pulls;
public List<GHPullRequest> wrap(GitHub root) {
for (GHPullRequest pull : pulls)
pull.root = root;
return pulls;
}
}

View File

@@ -3,13 +3,20 @@ package org.kohsuke;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.kohsuke.github.GHOrganization; import org.kohsuke.github.GHOrganization;
import org.kohsuke.github.GHOrganization.Permission; 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.GHRepository;
import org.kohsuke.github.GHTeam; import org.kohsuke.github.GHTeam;
import org.kohsuke.github.GitHub; import org.kohsuke.github.GitHub;
import java.io.IOException; import java.io.IOException;
import java.net.URL; 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.Set;
import java.util.concurrent.TimeUnit;
/** /**
* Unit test for simple App. * Unit test for simple App.