diff --git a/pom.xml b/pom.xml index a3b27867e0..1e1161d95b 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ github-api - 1.52 + 1.53 GitHub API for Java http://github-api.kohsuke.org/ GitHub API for Java @@ -16,7 +16,7 @@ scm:git:git@github.com/kohsuke/${project.artifactId}.git scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git http://${project.artifactId}.kohsuke.org/ - HEAD + github-api-1.53 @@ -78,7 +78,6 @@ com.infradna.tool bridge-method-annotation 1.8 - true org.kohsuke.stapler @@ -98,6 +97,12 @@ 1.5.3 true + + org.kohsuke + wordnet-random-name + 1.2 + test + diff --git a/src/main/java/org/kohsuke/github/GHGist.java b/src/main/java/org/kohsuke/github/GHGist.java new file mode 100644 index 0000000000..9f757be73b --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHGist.java @@ -0,0 +1,200 @@ +package org.kohsuke.github; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.io.IOException; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +/** + * Gist + * + * @author Kohsuke Kawaguchi + * @see GHUser#listGists() + * @see GitHub#getGist(String) + * @see GitHub#createGist() + */ +public final class GHGist { + /*package almost final*/ GHUser owner; + /*package almost final*/ GitHub root; + + private String url, forks_url, commits_url, id, git_pull_url, git_push_url, html_url; + + @JsonProperty("public") + private boolean _public; + + private String created_at, updated_at, description; + + private int comments; + + private String comments_url; + + private Map files = new HashMap(); + + /** + * User that owns this Gist. + */ + public GHUser getOwner() { + return owner; + } + + /** + * API URL of this gist, such as 'https://api.github.com/gists/12345' + */ + public String getUrl() { + return url; + } + + public String getForksUrl() { + return forks_url; + } + + public String getCommitsUrl() { + return commits_url; + } + + /** + * ID of this gist, such as '12345' + */ + public String getId() { + return id; + } + + /** + * URL like https://gist.github.com/gists/12345.git + */ + public String getGitPullUrl() { + return git_pull_url; + } + + public String getGitPushUrl() { + return git_push_url; + } + + public String getHtmlUrl() { + return html_url; + } + + public boolean isPublic() { + return _public; + } + + public Date getCreatedAt() { + return GitHub.parseDate(created_at); + } + + public Date getUpdatedAt() { + return GitHub.parseDate(updated_at); + } + + public String getDescription() { + return description; + } + + public int getCommentCount() { + return comments; + } + + /** + * API URL of listing comments. + */ + public String getCommentsUrl() { + return comments_url; + } + + public GHGistFile getFile(String name) { + return files.get(name); + } + + public Map getFiles() { + return Collections.unmodifiableMap(files); + } + + /*package*/ GHGist wrapUp(GHUser owner) { + this.owner = owner; + this.root = owner.root; + wrapUp(); + return this; + } + + /** + * Used when caller obtains {@link GHGist} without knowing its owner. + * A partially constructed owner object is interned. + */ + /*package*/ GHGist wrapUp(GitHub root) throws IOException { + this.owner = root.getUser(owner); + this.root = root; + wrapUp(); + return this; + } + + private void wrapUp() { + for (Entry e : files.entrySet()) { + e.getValue().fileName = e.getKey(); + } + } + String getApiTailUrl(String tail) { + return "/gists/" + id + '/' + tail; + } + + public void star() throws IOException { + new Requester(root).method("PUT").to(getApiTailUrl("star")); + } + + public void unstar() throws IOException { + new Requester(root).method("DELETE").to(getApiTailUrl("star")); + } + + public boolean isStarred() throws IOException { + return root.retrieve().asHttpStatusCode(getApiTailUrl("star"))/100==2; + } + + /** + * Forks this gist into your own. + */ + public GHGist fork() throws IOException { + return new Requester(root).to(getApiTailUrl("forks"),GHGist.class).wrapUp(root); + } + + public PagedIterable listForks() { + return new PagedIterable() { + public PagedIterator iterator() { + return new PagedIterator(root.retrieve().asIterator(getApiTailUrl("forks"), GHGist[].class)) { + @Override + protected void wrapUp(GHGist[] page) { + try { + for (GHGist c : page) + c.wrapUp(root); + } catch (IOException e) { + throw new Error(e); + } + } + }; + } + }; + } + + /** + * Deletes this gist. + */ + public void delete() throws IOException { + new Requester(root).method("DELETE").to("/gists/" + id); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + GHGist ghGist = (GHGist) o; + return id.equals(ghGist.id); + + } + + @Override + public int hashCode() { + return id.hashCode(); + } +} diff --git a/src/main/java/org/kohsuke/github/GHGistBuilder.java b/src/main/java/org/kohsuke/github/GHGistBuilder.java new file mode 100644 index 0000000000..57fd255031 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHGistBuilder.java @@ -0,0 +1,48 @@ +package org.kohsuke.github; + +import java.io.IOException; +import java.util.Collections; +import java.util.LinkedHashMap; + +/** + * Builder pattern for creating a new Gist. + * + * @author Kohsuke Kawaguchi + * @see GitHub#createGist() + */ +public class GHGistBuilder { + private final GitHub root; + private final Requester req; + private final LinkedHashMap files = new LinkedHashMap(); + + public GHGistBuilder(GitHub root) { + this.root = root; + req = new Requester(root); + } + + public GHGistBuilder description(String desc) { + req.with("description",desc); + return this; + } + + public GHGistBuilder public_(boolean v) { + req.with("public",v); + return this; + } + + /** + * Adds a new file. + */ + public GHGistBuilder file(String fileName, String content) { + files.put(fileName, Collections.singletonMap("content", content)); + return this; + } + + /** + * Creates a Gist based on the parameters specified thus far. + */ + public GHGist create() throws IOException { + req._with("files",files); + return req.to("/gists",GHGist.class).wrapUp(root); + } +} diff --git a/src/main/java/org/kohsuke/github/GHGistFile.java b/src/main/java/org/kohsuke/github/GHGistFile.java new file mode 100644 index 0000000000..605afc993a --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHGistFile.java @@ -0,0 +1,60 @@ +package org.kohsuke.github; + +/** + * A file inside {@link GHGist} + * + * @author Kohsuke Kawaguchi + * @see GHGist#getFile(String) + * @see GHGist#getFiles() + */ +public class GHGistFile { + /*package almost final*/ String fileName; + + private int size; + private String raw_url, type, language, content; + private boolean truncated; + + + public String getFileName() { + return fileName; + } + + /** + * File size in bytes. + */ + public int getSize() { + return size; + } + + /** + * URL that serves this file as-is. + */ + public String getRawUrl() { + return raw_url; + } + + /** + * Content type of this Gist, such as "text/plain" + */ + public String getType() { + return type; + } + + public String getLanguage() { + return language; + } + + /** + * Content of this file. + */ + public String getContent() { + return content; + } + + /** + * (?) indicates if {@link #getContent()} contains a truncated content. + */ + public boolean isTruncated() { + return truncated; + } +} diff --git a/src/main/java/org/kohsuke/github/GHMyself.java b/src/main/java/org/kohsuke/github/GHMyself.java index 85c75c0971..06e61f83d3 100644 --- a/src/main/java/org/kohsuke/github/GHMyself.java +++ b/src/main/java/org/kohsuke/github/GHMyself.java @@ -102,7 +102,8 @@ public synchronized Map getAllRepositories() throws IOExcep * * Unlike {@link #getAllRepositories()}, this does not wait until all the repositories are returned. */ - public PagedIterable listAllRepositories() { + @Override + public PagedIterable listRepositories() { return new PagedIterable() { public PagedIterator iterator() { return new PagedIterator(root.retrieve().asIterator("/user/repos", GHRepository[].class)) { @@ -116,6 +117,14 @@ protected void wrapUp(GHRepository[] page) { }; } + /** + * @deprecated + * Use {@link #listRepositories()} + */ + public PagedIterable listAllRepositories() { + return listRepositories(); + } + // public void addEmails(Collection emails) throws IOException { //// new Requester(root,ApiVersion.V3).withCredential().to("/user/emails"); // root.retrieveWithAuth3() diff --git a/src/main/java/org/kohsuke/github/GHPerson.java b/src/main/java/org/kohsuke/github/GHPerson.java index fbabd1dcb6..7e17341517 100644 --- a/src/main/java/org/kohsuke/github/GHPerson.java +++ b/src/main/java/org/kohsuke/github/GHPerson.java @@ -43,13 +43,16 @@ protected void populate() throws IOException { } /** - * Gets the repositories this user owns. + * Gets the public repositories this user owns. + * + *

+ * To list your own repositories, including private repositories, + * use {@link GHMyself#listRepositories()} */ public synchronized Map getRepositories() throws IOException { Map repositories = new TreeMap(); - for (List batch : iterateRepositories(100)) { - for (GHRepository r : batch) - repositories.put(r.getName(),r); + for (GHRepository r : listRepositories()) { + repositories.put(r.getName(),r); } return Collections.unmodifiableMap(repositories); } @@ -206,6 +209,10 @@ public String getBlog() throws IOException { return blog; } + public String getHtmlUrl() { + return html_url; + } + /** * Gets the e-mail address of the user. */ diff --git a/src/main/java/org/kohsuke/github/GHRelease.java b/src/main/java/org/kohsuke/github/GHRelease.java index 0c405b33e2..1702ab7c93 100644 --- a/src/main/java/org/kohsuke/github/GHRelease.java +++ b/src/main/java/org/kohsuke/github/GHRelease.java @@ -207,7 +207,18 @@ public List getAssets() throws IOException { GHAsset[] assets = builder .method("GET") - .to(owner.getApiTailUrl(format("releases/%d/assets", id)), GHAsset[].class); + .to(getApiTailUrl("assets"), GHAsset[].class); return Arrays.asList(GHAsset.wrap(assets, this)); } + + /** + * Deletes this release. + */ + public void delete() throws IOException { + new Requester(root).method("DELETE").to(owner.getApiTailUrl("releases/"+id)); + } + + private String getApiTailUrl(String end) { + return owner.getApiTailUrl(format("releases/%s/%s",id,end)); + } } diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 7b12f08959..7a9fd28eb6 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -59,6 +59,7 @@ public class GHRepository { private String description, homepage, name; private String url; // this is the API url private String html_url; // this is the UI + private String git_url, ssh_url, clone_url, svn_url; private GHUser owner; // not fully populated. beware. private boolean has_issues, has_wiki, fork, has_downloads; @JsonProperty("private") @@ -97,7 +98,7 @@ public String getUrl() { * This URL is read-only. */ public String getGitTransportUrl() { - return "git://github.com/"+getOwnerName()+"/"+name+".git"; + return git_url; } /** @@ -105,7 +106,21 @@ public String getGitTransportUrl() { * This URL is read-only. */ public String gitHttpTransportUrl() { - return "https://github.com/"+getOwnerName()+"/"+name+".git"; + return clone_url; + } + + /** + * Gets the Subversion URL to access this repository: https://github.com/rails/rails + */ + public String getSvnUrl() { + return svn_url; + } + + /** + * Gets the SSH URL to access this repository, such as git@github.com:rails/rails.git + */ + public String getSshUrl() { + return ssh_url; } /** @@ -153,7 +168,7 @@ public List getIssues(GHIssueState state) throws IOException { public List getIssues(GHIssueState state, GHMilestone milestone) throws IOException { return Arrays.asList(GHIssue.wrap(root.retrieve() .to(String.format("/repos/%s/%s/issues?state=%s&milestone=%s", owner.login, name, - state.toString().toLowerCase(), milestone == null ? "none" : "" + milestone.getNumber()), + state.toString().toLowerCase(), milestone == null ? "none" : "" + milestone.getNumber()), GHIssue[].class ), this)); } @@ -179,9 +194,54 @@ public GHReleaseBuilder createRelease(String tag) { return new GHReleaseBuilder(this,tag); } + /** + * Creates a named ref, such as tag, branch, etc. + * + * @param name + * The name of the fully qualified reference (ie: refs/heads/master). + * If it doesn't start with 'refs' and have at least two slashes, it will be rejected. + * @param sha + * The SHA1 value to set this reference to + */ + public GHRef createRef(String name, String sha) throws IOException { + return new Requester(root) + .with("ref", name).with("sha", sha).method("POST").to(getApiTailUrl("git/refs"), GHRef.class); + } + + /** + * @deprecated + * use {@link #listReleases()} + */ public List getReleases() throws IOException { - return Arrays.asList(GHRelease.wrap(root.retrieve().to("/repos/" + owner.login + "/" + name + "/releases", - GHRelease[].class), this)); + return listReleases().asList(); + } + + public PagedIterable listReleases() throws IOException { + return new PagedIterable() { + public PagedIterator iterator() { + return new PagedIterator(root.retrieve().asIterator(getApiTailUrl("releases"), GHRelease[].class)) { + @Override + protected void wrapUp(GHRelease[] page) { + for (GHRelease c : page) + c.wrap(GHRepository.this); + } + }; + } + }; + } + + public PagedIterable listTags() throws IOException { + return new PagedIterable() { + public PagedIterator iterator() { + return new PagedIterator(root.retrieve().asIterator(getApiTailUrl("tags"), GHTag[].class)) { + @Override + protected void wrapUp(GHTag[] page) { + for (GHTag c : page) + c.wrap(GHRepository.this); + } + }; + } + }; } protected String getOwnerName() { @@ -424,6 +484,29 @@ protected void wrapUp(GHPullRequest[] page) { }; } + /** + * Creates a new pull request. + * + * @param title + * Required. The title of the pull request. + * @param head + * Required. The name of the branch where your changes are implemented. + * For cross-repository pull requests in the same network, + * namespace head with a user like this: username:branch. + * @param base + * Required. The name of the branch you want your changes pulled into. + * This should be an existing branch on the current repository. + * @param body + * The contents of the pull request. This is the markdown description + * of a pull request. + */ + public GHPullRequest createPullRequest(String title, String head, String base, String body) throws IOException { + return new Requester(root).with("title",title) + .with("head",head) + .with("base",base) + .with("body",body).to(getApiTailUrl("pulls"),GHPullRequest.class).wrapUp(this); + } + /** * Retrieves the currently configured hooks. */ @@ -453,7 +536,7 @@ public GHCompare getCompare(String id1, String id2) throws IOException { } public GHCompare getCompare(GHCommit id1, GHCommit id2) throws IOException { - return getCompare(id1.getSHA1(),id2.getSHA1()); + return getCompare(id1.getSHA1(), id2.getSHA1()); } public GHCompare getCompare(GHBranch id1, GHBranch id2) throws IOException { diff --git a/src/main/java/org/kohsuke/github/GHTag.java b/src/main/java/org/kohsuke/github/GHTag.java new file mode 100644 index 0000000000..60d4566cc8 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHTag.java @@ -0,0 +1,36 @@ +package org.kohsuke.github; + +/** + * Represents a tag in {@link GHRepository} + * + * @see GHRepository#listTags() + */ +public class GHTag { + private GHRepository owner; + private GitHub root; + + private String name; + private GHCommit commit; + + /*package*/ GHTag wrap(GHRepository owner) { + this.owner = owner; + this.root = owner.root; + return this; + } + + public GHRepository getOwner() { + return owner; + } + + public GitHub getRoot() { + return root; + } + + public String getName() { + return name; + } + + public GHCommit getCommit() { + return commit; + } +} diff --git a/src/main/java/org/kohsuke/github/GHUser.java b/src/main/java/org/kohsuke/github/GHUser.java index 55c528e3b1..7ebd356d9b 100644 --- a/src/main/java/org/kohsuke/github/GHUser.java +++ b/src/main/java/org/kohsuke/github/GHUser.java @@ -127,6 +127,23 @@ protected void wrapUp(GHEventInfo[] page) { }; } + /** + * Lists Gists created by this user. + */ + public PagedIterable listGists() throws IOException { + return new PagedIterable() { + public PagedIterator iterator() { + return new PagedIterator(root.retrieve().asIterator(String.format("/users/%s/gists", login), GHGist[].class)) { + @Override + protected void wrapUp(GHGist[] page) { + for (GHGist c : page) + c.wrapUp(GHUser.this); + } + }; + } + }; + } + @Override public String toString() { return "User:"+login; diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 00f94bd04b..2488c982a2 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -27,6 +27,7 @@ import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.Reader; import java.net.MalformedURLException; @@ -239,7 +240,16 @@ public void setConnector(HttpConnector connector) { * Gets the current rate limit. */ public GHRateLimit getRateLimit() throws IOException { - return retrieve().to("/rate_limit", JsonRateLimit.class).rate; + try { + return retrieve().to("/rate_limit", JsonRateLimit.class).rate; + } catch (FileNotFoundException e) { + // GitHub Enterprise doesn't have the rate limit, so in that case + // return some big number that's not too big. + // see issue #78 + GHRateLimit r = new GHRateLimit(); + r.limit = r.remaining = 1000000; + return r; + } } /** @@ -329,6 +339,17 @@ public List getEvents() throws IOException { return Arrays.asList(events); } + /** + * Gets a sigle gist by ID. + */ + public GHGist getGist(String id) throws IOException { + return retrieve().to("/gists/"+id,GHGist.class).wrapUp(this); + } + + public GHGistBuilder createGist() { + return new GHGistBuilder(this); + } + /** * Parses the GitHub event object. * @@ -345,6 +366,9 @@ public T parseEventPayload(Reader r, Class type) t /** * Creates a new repository. * + * To create a repository in an organization, see + * {@link GHOrganization#createRepository(String, String, String, GHTeam, boolean)} + * * @return * Newly created repository. */ diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index e7e3e4674a..10cb2bfb74 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -174,28 +174,7 @@ private T _to(String tailApiUrl, Class type, T instance) throws IOExcepti while (true) {// loop while API rate limit is hit HttpURLConnection uc = setupConnection(root.getApiURL(tailApiUrl)); - if (!method.equals("GET")) { - uc.setDoOutput(true); - uc.setRequestProperty("Content-type", contentType); - - if (body == null) { - Map json = new HashMap(); - for (Entry e : args) { - json.put(e.key, e.value); - } - MAPPER.writeValue(uc.getOutputStream(), json); - } else { - try { - byte[] bytes = new byte[32768]; - int read = 0; - while ((read = body.read(bytes)) != -1) { - uc.getOutputStream().write(bytes, 0, read); - } - } finally { - body.close(); - } - } - } + buildRequest(uc); try { return parse(uc,type,instance); @@ -205,6 +184,48 @@ private T _to(String tailApiUrl, Class type, T instance) throws IOExcepti } } + /** + * Makes a request and just obtains the HTTP status code. + */ + public int asHttpStatusCode(String tailApiUrl) throws IOException { + while (true) {// loop while API rate limit is hit + HttpURLConnection uc = setupConnection(root.getApiURL(tailApiUrl)); + + buildRequest(uc); + + try { + return uc.getResponseCode(); + } catch (IOException e) { + handleApiError(e,uc); + } + } + } + + private void buildRequest(HttpURLConnection uc) throws IOException { + if (!method.equals("GET")) { + uc.setDoOutput(true); + uc.setRequestProperty("Content-type", contentType); + + if (body == null) { + Map json = new HashMap(); + for (Entry e : args) { + json.put(e.key, e.value); + } + MAPPER.writeValue(uc.getOutputStream(), json); + } else { + try { + byte[] bytes = new byte[32768]; + int read = 0; + while ((read = body.read(bytes)) != -1) { + uc.getOutputStream().write(bytes, 0, read); + } + } finally { + body.close(); + } + } + } + } + /** * Loads pagenated resources. * diff --git a/src/test/java/org/kohsuke/github/AbstractGitHubApiTestBase.java b/src/test/java/org/kohsuke/github/AbstractGitHubApiTestBase.java new file mode 100644 index 0000000000..e45895d66e --- /dev/null +++ b/src/test/java/org/kohsuke/github/AbstractGitHubApiTestBase.java @@ -0,0 +1,36 @@ +package org.kohsuke.github; + +import org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.Before; +import org.kohsuke.randname.RandomNameGenerator; + +import java.io.FileInputStream; +import java.util.Properties; + +/** + * @author Kohsuke Kawaguchi + */ +public abstract class AbstractGitHubApiTestBase extends Assert { + + protected GitHub gitHub; + + @Before + public void setUp() throws Exception { + Properties props = new Properties(); + java.io.File f = new java.io.File(System.getProperty("user.home"), ".github.kohsuke2"); + if (f.exists()) { + FileInputStream in = new FileInputStream(f); + try { + props.load(in); + gitHub = GitHub.connect(props.getProperty("login"),props.getProperty("oauth")); + } finally { + IOUtils.closeQuietly(in); + } + } else { + gitHub = GitHub.connect(); + } + } + + protected static final RandomNameGenerator rnd = new RandomNameGenerator(); +} diff --git a/src/test/java/org/kohsuke/AppTest.java b/src/test/java/org/kohsuke/github/AppTest.java similarity index 89% rename from src/test/java/org/kohsuke/AppTest.java rename to src/test/java/org/kohsuke/github/AppTest.java index 09a6bdec70..d12b44683f 100644 --- a/src/test/java/org/kohsuke/AppTest.java +++ b/src/test/java/org/kohsuke/github/AppTest.java @@ -1,4 +1,4 @@ -package org.kohsuke; +package org.kohsuke.github; import java.io.IOException; import java.net.URL; @@ -6,60 +6,26 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import org.junit.Assume; -import org.junit.Before; import org.junit.Test; -import org.kohsuke.github.GHBranch; -import org.kohsuke.github.GHCommit; import org.kohsuke.github.GHCommit.File; -import org.kohsuke.github.GHCommitComment; -import org.kohsuke.github.GHCommitState; -import org.kohsuke.github.GHCommitStatus; -import org.kohsuke.github.GHEvent; -import org.kohsuke.github.GHEventInfo; -import org.kohsuke.github.GHEventPayload; -import org.kohsuke.github.GHHook; -import org.kohsuke.github.GHIssue; -import org.kohsuke.github.GHIssueComment; -import org.kohsuke.github.GHIssueState; -import org.kohsuke.github.GHKey; -import org.kohsuke.github.GHMilestone; -import org.kohsuke.github.GHMyself; -import org.kohsuke.github.GHOrganization; import org.kohsuke.github.GHOrganization.Permission; -import org.kohsuke.github.GHPullRequest; -import org.kohsuke.github.GHRepository; -import org.kohsuke.github.GHTeam; -import org.kohsuke.github.GHUser; -import org.kohsuke.github.GitHub; -import org.kohsuke.github.PagedIterable; -import java.io.IOException; -import java.net.URL; -import java.util.ArrayList; import java.util.Date; -import java.util.Map; -import java.util.Set; -import java.util.List; /** * Unit test for simple App. */ -public class AppTest { - - private GitHub gitHub; - - @Before - public void setUp() throws Exception { - gitHub = GitHub.connect(); - } - +public class AppTest extends AbstractGitHubApiTestBase { private String getTestRepositoryName() throws IOException { return getUser().getLogin() + "/github-api-test"; } @@ -246,13 +212,13 @@ public void testPublicKeys() throws Exception { @Test public void testOrgFork() throws Exception { kohsuke(); - getUser().getRepository("rubywm").forkTo(gitHub.getOrganization("jenkinsci")); + gitHub.getRepository("kohsuke/rubywm").forkTo(gitHub.getOrganization("github-api-test-org")); } @Test public void testGetTeamsForRepo() throws Exception { kohsuke(); - assertEquals(1,gitHub.getOrganization("stapler").getRepository("stapler").getTeams().size()); + assertEquals(1,gitHub.getOrganization("github-api-test-org").getRepository("testGetTeamsForRepo").getTeams().size()); } @Test @@ -271,16 +237,17 @@ public void testMemberOrgs() throws Exception { public void testOrgTeams() throws Exception { kohsuke(); int sz=0; - for (GHTeam t : gitHub.getOrganization("jenkinsci").listTeams()) { + for (GHTeam t : gitHub.getOrganization("github-api-test-org").listTeams()) { assertNotNull(t.getName()); sz++; } - assertTrue(sz>1000); + assertTrue(sz<100); } + @Test public void testOrgTeamByName() throws Exception { kohsuke(); - GHTeam e = gitHub.getOrganization("jenkinsci").getTeamByName("Everyone"); + GHTeam e = gitHub.getOrganization("github-api-test-org").getTeamByName("Core Developers"); assertNotNull(e); } @@ -472,7 +439,7 @@ public void testOrgRepositories() throws IOException { @Test public void testOrganization() throws IOException { kohsuke(); - GHOrganization j = gitHub.getOrganization("jenkinsci"); + GHOrganization j = gitHub.getOrganization("github-api-test-org"); GHTeam t = j.getTeams().get("Core Developers"); assertNotNull(j.getRepository("jenkins")); @@ -525,7 +492,45 @@ public void testCheckMembership() throws Exception { assertFalse(j.hasPublicMember(b)); } + @Test + public void testCreateRelease() throws Exception { + kohsuke(); + + GHRepository r = gitHub.getRepository("kohsuke2/testCreateRelease"); + + String tagName = UUID.randomUUID().toString(); + String releaseName = "release-" + tagName; + + GHRelease rel = r.createRelease(tagName) + .name(releaseName) + .prerelease(false) + .create(); + + try { + + for (GHTag tag : r.listTags()) { + if (tagName.equals(tag.getName())) { + String ash = tag.getCommit().getSHA1(); + GHRef ref = r.createRef("refs/heads/"+releaseName, ash); + assertEquals(ref.getRef(),"refs/heads/"+releaseName); + + for (Map.Entry entry : r.getBranches().entrySet()) { + System.out.println(entry.getKey() + "/" + entry.getValue()); + if (releaseName.equals(entry.getValue().getName())) { + return; + } + } + fail("branch not found"); + } + } + fail("release creation failed! tag not found"); + } finally { + rel.delete(); + } + } + private void kohsuke() { - Assume.assumeTrue(getUser().getLogin().equals("kohsuke")); + String login = getUser().getLogin(); + Assume.assumeTrue(login.equals("kohsuke") || login.equals("kohsuke2")); } } diff --git a/src/test/java/org/kohsuke/github/GHContentIntegrationTest.java b/src/test/java/org/kohsuke/github/GHContentIntegrationTest.java index d375f85403..39f8545aaa 100644 --- a/src/test/java/org/kohsuke/github/GHContentIntegrationTest.java +++ b/src/test/java/org/kohsuke/github/GHContentIntegrationTest.java @@ -1,28 +1,26 @@ package org.kohsuke.github; -import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Test; import java.util.List; -import java.util.UUID; /** * Integration test for {@link GHContent}. */ -public class GHContentIntegrationTest extends TestCase { +public class GHContentIntegrationTest extends AbstractGitHubApiTestBase { - private GitHub gitHub; private GHRepository repo; - private String createdFilename; + private String createdFilename = rnd.next(); + @Before @Override public void setUp() throws Exception { super.setUp(); - - gitHub = GitHub.connect(); - repo = gitHub.getRepository("acollign/github-api-test").fork(); - createdFilename = UUID.randomUUID().toString(); + repo = gitHub.getRepository("github-api-test-org/GHContentIntegrationTest").fork(); } + @Test public void testGetFileContent() throws Exception { GHContent content = repo.getFileContent("ghcontent-ro/a-file-with-content"); @@ -30,6 +28,7 @@ public void testGetFileContent() throws Exception { assertEquals("thanks for reading me\n", content.getContent()); } + @Test public void testGetEmptyFileContent() throws Exception { GHContent content = repo.getFileContent("ghcontent-ro/an-empty-file"); @@ -37,12 +36,14 @@ public void testGetEmptyFileContent() throws Exception { assertEquals("", content.getContent()); } + @Test public void testGetDirectoryContent() throws Exception { List entries = repo.getDirectoryContent("ghcontent-ro/a-dir-with-3-entries"); assertTrue(entries.size() == 3); } + @Test public void testCRUDContent() throws Exception { GHContentUpdateResponse created = repo.createContent("this is an awesome file I created\n", "Creating a file for integration tests.", createdFilename); GHContent createdContent = created.getContent(); diff --git a/src/test/java/org/kohsuke/github/GistTest.java b/src/test/java/org/kohsuke/github/GistTest.java new file mode 100644 index 0000000000..df3baf8eeb --- /dev/null +++ b/src/test/java/org/kohsuke/github/GistTest.java @@ -0,0 +1,73 @@ +package org.kohsuke.github; + +import org.junit.Test; + +/** + * @author Kohsuke Kawaguchi + */ +public class GistTest extends AbstractGitHubApiTestBase { + /** + * CRUD operation. + */ + @Test + public void lifecycleTest() throws Exception { + GHGist gist = gitHub.createGist() + .public_(false) + .description("Test Gist") + .file("abc.txt","abc") + .file("def.txt","def") + .create(); + + assertNotNull(gist.getCreatedAt()); + assertNotNull(gist.getUpdatedAt()); + + assertNotNull(gist.getCommentsUrl()); + assertNotNull(gist.getCommitsUrl()); + assertNotNull(gist.getGitPullUrl()); + assertNotNull(gist.getGitPushUrl()); + assertNotNull(gist.getHtmlUrl()); + + gist.delete(); + } + + @Test + public void starTest() throws Exception { + GHGist gist = gitHub.getGist("9903708"); + assertEquals("rtyler",gist.getOwner().getLogin()); + + gist.star(); + assertTrue(gist.isStarred()); + gist.unstar(); + assertFalse(gist.isStarred()); + + GHGist newGist = gist.fork(); + + try { + for (GHGist g : gist.listForks()) { + if (g.equals(newGist)) { + // expected to find it in the clone list + return; + } + } + + fail("Expected to find a newly cloned gist"); + } finally { + newGist.delete(); + } + } + + @Test + public void gistFile() throws Exception { + GHGist gist = gitHub.getGist("9903708"); + + assertTrue(gist.isPublic()); + + assertEquals(1,gist.getFiles().size()); + GHGistFile f = gist.getFile("keybase.md"); + + assertEquals("text/plain", f.getType()); + assertEquals("Markdown", f.getLanguage()); + assertTrue(f.getContent().contains("### Keybase proof")); + assertNotNull(f.getContent()); + } +} diff --git a/src/test/java/org/kohsuke/LifecycleTest.java b/src/test/java/org/kohsuke/github/LifecycleTest.java similarity index 86% rename from src/test/java/org/kohsuke/LifecycleTest.java rename to src/test/java/org/kohsuke/github/LifecycleTest.java index c248ec4db8..c4e1d1e0d9 100644 --- a/src/test/java/org/kohsuke/LifecycleTest.java +++ b/src/test/java/org/kohsuke/github/LifecycleTest.java @@ -1,18 +1,11 @@ -package org.kohsuke; +package org.kohsuke.github; -import junit.framework.TestCase; import org.apache.commons.io.IOUtils; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; -import org.kohsuke.github.GHAsset; -import org.kohsuke.github.GHIssue; -import org.kohsuke.github.GHMilestone; -import org.kohsuke.github.GHMyself; -import org.kohsuke.github.GHRelease; -import org.kohsuke.github.GHRepository; -import org.kohsuke.github.GitHub; +import org.junit.Test; import java.io.File; import java.io.FileInputStream; @@ -22,24 +15,19 @@ import java.util.List; import java.util.Properties; -public class LifecycleTest extends TestCase { - private GitHub gitHub; - - @Override - public void setUp() throws Exception { - super.setUp(); - gitHub = GitHub.connect(); - } - +public class LifecycleTest extends AbstractGitHubApiTestBase { + @Test public void testCreateRepository() throws IOException, GitAPIException, InterruptedException { GHMyself myself = gitHub.getMyself(); - GHRepository repository = myself.getRepository("github-api-test"); + GHOrganization org = gitHub.getOrganization("github-api-test-org"); + GHRepository repository = org.getRepository("github-api-test"); if (repository != null) { repository.delete(); Thread.sleep(1000); } - repository = gitHub.createRepository("github-api-test", - "a test repository used to test kohsuke's github-api", "http://github-api.kohsuke.org/", true); + repository = org.createRepository("github-api-test", + "a test repository used to test kohsuke's github-api", "http://github-api.kohsuke.org/", "Core Developers", true); + Thread.sleep(1000); // wait for the repository to become ready assertTrue(repository.getReleases().isEmpty()); try { @@ -54,7 +42,7 @@ public void testCreateRepository() throws IOException, GitAPIException, Interrup delete(repoDir); Git origin = Git.cloneRepository() .setBare(false) - .setURI(repository.gitHttpTransportUrl()) + .setURI(repository.getSshUrl()) .setDirectory(repoDir) .setCredentialsProvider(getCredentialsProvider(myself)) .call(); diff --git a/src/test/java/org/kohsuke/github/PullRequestTest.java b/src/test/java/org/kohsuke/github/PullRequestTest.java new file mode 100644 index 0000000000..18f4a160f7 --- /dev/null +++ b/src/test/java/org/kohsuke/github/PullRequestTest.java @@ -0,0 +1,18 @@ +package org.kohsuke.github; + +import org.junit.Test; + +/** + * @author Kohsuke Kawaguchi + */ +public class PullRequestTest extends AbstractGitHubApiTestBase { + @Test + public void createPullRequest() throws Exception { + GHRepository j = gitHub.getOrganization("github-api-test-org").getRepository("jenkins"); + String name = rnd.next(); + GHPullRequest p = j.createPullRequest(name, "stable", "master", "## test"); + System.out.println(p.getUrl()); + assertEquals(name, p.getTitle()); + p.close(); + } +}