Compare commits

...

66 Commits

Author SHA1 Message Date
Kohsuke Kawaguchi
013eaa30b6 [maven-release-plugin] prepare release github-api-1.73 2016-02-29 21:03:31 -08:00
Kohsuke Kawaguchi
751043bf81 change in the markup generated 2016-02-29 21:01:18 -08:00
Kohsuke Kawaguchi
14f7198a07 Handle "all" webhook correctly
This fixes #250
2016-02-29 20:56:47 -08:00
Kohsuke Kawaguchi
94af819ae5 Merge pull request #249 from zapelin/master
Added getHtmlUrl() to GHCommit
2016-02-29 20:48:19 -08:00
Kohsuke Kawaguchi
dbcc9afbc7 Merge pull request #248 from daniel-beck/populate-commit
Populate commit with data for getCommitShortInfo
2016-02-29 20:47:52 -08:00
Kohsuke Kawaguchi
8556033ae6 Merge pull request #245 from daniel-beck/email-hook-error
Fix error when creating email service hook
2016-02-29 20:45:40 -08:00
Kohsuke Kawaguchi
650493f863 Merge pull request #244 from benbek/patch-1
Minor amendment to the documentation
2016-02-29 19:57:47 -08:00
Kohsuke Kawaguchi
d80ad77871 Use builder pattern to support all the other options 2016-02-29 19:57:16 -08:00
Artem Gubanov
f4b129b9f1 Added getHtmlUrl() to GHCommit 2016-02-25 10:46:17 +02:00
Daniel Beck
c0a05e0650 Populate commit with data for getCommitShortInfo 2016-02-21 01:26:43 +01:00
Daniel Beck
33d95d3e3a Fix error when creating email service hook 2016-01-20 23:30:10 +01:00
benbek
f573f83fb9 Amendment to the documentation
The status reported by GitHub for deleting a file is actually "removed", not "deleted".
2016-01-19 00:05:01 +02:00
Daniel Lovera
e94c36b7e6 clean: remove unused import 2015-12-13 21:05:36 +01:00
Daniel Lovera
c879e9e34d Support for auto_init parameter in organization
The GitHub api auto_init parameter allows to initialize created repository with a readme file.
Add createRepository methods in GHOrganization using auto_init parameter. Already existing createRepository methods use auto_init parameter as false for retro-compatibility.
2015-12-13 21:00:40 +01:00
Daniel Lovera
ac39b564a8 Support for auto_init parameter
The GitHub api auto_init parameter allows to initialize created repository with a readme file.
Add a createRepository method using auto_init parameter. Already existing createRepository method uses auto_init parameter as false for retro-compatibility.
2015-12-13 20:59:49 +01:00
Kohsuke Kawaguchi
d91388aba4 [maven-release-plugin] prepare for next development iteration 2015-12-10 07:00:06 -08:00
Kohsuke Kawaguchi
733d78abdd [maven-release-plugin] prepare release github-api-1.72 2015-12-10 06:59:37 -08:00
Kohsuke Kawaguchi
d5809e375c Simplification via enum handling in 'req.with' 2015-12-10 06:33:49 -08:00
Kohsuke Kawaguchi
2440a676bd Added more comprehensive API to list pull requests
This fixes issue #234
2015-12-10 06:26:04 -08:00
Kohsuke Kawaguchi
03ac6c72e7 Formatting change 2015-12-10 06:01:34 -08:00
Kohsuke Kawaguchi
1bbbcabae0 Making API flow better 2015-12-10 05:56:08 -08:00
Kohsuke Kawaguchi
9149b6b998 GHCommit might be only partially populated.
This fixes issue #230
2015-12-10 05:53:55 -08:00
Kohsuke Kawaguchi
2603b5a402 Added stargazers and stars 2015-12-03 17:55:06 +01:00
Kohsuke Kawaguchi
dbddf5b9eb Implemented pagenation size support. 2015-12-03 17:41:43 +01:00
Kohsuke Kawaguchi
841f77bac2 Naming anonymous iterator.
... in anticipation of the page size support.
2015-12-03 16:33:39 +01:00
Kohsuke Kawaguchi
83ffe75baa Fixed rate handling limit handling
Issue #220. If RateLimitHandler returns normally, it should retry.
2015-12-02 12:03:39 +01:00
Kohsuke Kawaguchi
8cb7094803 Added pagination for following & follower 2015-12-02 08:35:56 +01:00
Kohsuke Kawaguchi
ed8cd0ad19 Added getter for ID
And the actual value has already gone past 'int'

This fixes issue #199
2015-12-01 17:02:53 +01:00
Kohsuke Kawaguchi
90d8e65a3b [maven-release-plugin] prepare for next development iteration 2015-12-01 16:27:29 +01:00
Kohsuke Kawaguchi
b24fcb18af [maven-release-plugin] prepare release github-api-1.71 2015-12-01 16:27:24 +01:00
Kohsuke Kawaguchi
c2f2d0f8af Making FindBugs happy 2015-12-01 16:23:51 +01:00
Kohsuke Kawaguchi
e33bdd7e62 Two teams now.
I assume this is because 'owner' is now a team.
2015-12-01 16:17:03 +01:00
Kohsuke Kawaguchi
402adc3559 Merge pull request #232 2015-12-01 16:05:25 +01:00
Kohsuke Kawaguchi
0f45d03c51 Reworked this change a bit.
- GHApiInfo need not be public because it's not publicly exposed.
- Throwing an exception is better IMO as it allows richer error message,
  including the differentiation between unreachable host name vs wrong
  URL, and reporting the API endpoint URL that was actually tried.
2015-12-01 16:01:01 +01:00
Kohsuke Kawaguchi
0397d7ab53 Fixing a test problem 2015-12-01 15:39:19 +01:00
Kohsuke Kawaguchi
79f86b82e4 Merge pull request #237 2015-12-01 15:18:15 +01:00
Kohsuke Kawaguchi
261a7a34e3 Consolidated timeout handling 2015-12-01 15:17:54 +01:00
Kohsuke Kawaguchi
723bb89e10 Merge pull request #219 from if6was9/cross-fork-compare
#218 enable cross fork compare
2015-12-01 15:04:50 +01:00
Oliver Gondža
832e4f3c37 Use default timeouts for URLConnections 2015-12-01 14:58:46 +01:00
Kohsuke Kawaguchi
75a4081549 Follow up to PR #216 2015-12-01 14:57:30 +01:00
Kohsuke Kawaguchi
f9291f9fd1 Merge pull request #216 from if6was9/issue-215-download-failure
#215 fix read() failure with private repos
2015-12-01 14:56:49 +01:00
Kohsuke Kawaguchi
c3b4ee9321 Merge pull request #226 from Shredder121/oauth-credentials
Check builder result to either be a token or a user
2015-12-01 14:54:35 +01:00
Kohsuke Kawaguchi
f86896943d Merge pull request #224 from Shredder121/directory-content-trailing-slash
Remove trailing slash when requesting directory content
2015-12-01 14:53:56 +01:00
Kohsuke Kawaguchi
c33f05e8ca Merge pull request #225 from Shredder121/findbugs-changes
Overzealous FindBugs changes.
2015-12-01 14:51:53 +01:00
Oleg Nenashev
52727ded03 Merge pull request #233 from vparfonov/master
Add information about mirror url if it exist.
2015-11-30 18:18:44 +03:00
Manuel Recena
f7d132758e Merge pull request #231 from recena/MergeCommitSha
Support for merge_commit_sha
2015-11-25 23:22:10 +01:00
Manuel Recena
bb17ca9a53 Merge pull request #236 from recena/findbugs
Findbugs plugin has been upgraded
2015-11-25 23:06:57 +01:00
Manuel Recena
aab21c5b17 findbugs plugin has been upgraded 2015-11-23 10:29:04 +01:00
Manuel Recena
acbafee02a Removed unrelated changes. @KostyaSha's suggestion 2015-11-23 10:25:41 +01:00
Manuel Recena
c6d2b1a222 @deprecated annotations were removed 2015-11-23 09:33:32 +01:00
Vitaly Parfonov
b037f75fb0 Add information about mirror url if it exist. Like https://github.com/apache/tomee 2015-11-19 12:09:34 +02:00
Ruben Dijkstra
a1e79d3050 Add unit test to cover the truncation of ?ref 2015-11-16 18:33:51 +01:00
Manuel Recena
354969d5fa Javadoc comment reviewed 2015-11-16 11:16:58 +01:00
Manuel Recena
a371892409 Added a new method to validate the GitHub API URL 2015-11-15 16:36:27 +01:00
Manuel Recena
b0789a7ce7 Set merge_commit_sha as deprecated 2015-11-15 11:50:13 +01:00
Manuel Recena
08be8eb4f8 Added a new test testMergeCommitSHA() 2015-11-15 11:46:18 +01:00
Manuel Recena
bafddf4baf Initial source code modifications 2015-11-14 12:11:24 +01:00
Ruben Dijkstra
75b9184a00 Check builder result to either be a token or a user
Currently, a `user` property is always required (it not having content is also fine).

This adds support for only having the `oauth` key in the property file/environment.
2015-10-09 17:20:11 +02:00
Ruben Dijkstra
5dc83cf2bf Overzealous FindBugs changes.
Charsets that are standard on the JRE are try-lookuped,
bridge methods were removed and a stream that would be closed later is closed explicitly
2015-10-08 19:31:55 +02:00
Ruben Dijkstra
092e9062c8 Remove trailing slash when requesting directory content 2015-10-06 18:23:51 +02:00
Rob Schoening
512c921a81 enable cross fork compare 2015-09-27 07:50:11 -07:00
Kohsuke Kawaguchi
defcd6fe26 Merge pull request #217 from dblevins/closed_at
Support Milestone closed_at date
2015-09-17 19:23:00 -07:00
dblevins
025b6cbfb7 Support Milestone closed_at date 2015-09-14 10:53:07 -07:00
Rob Schoening
b0687dbeb5 Fix compilation errror: The constructor ArrayList<GHHook>(List<capture#1-of ? extends GHHook[]>) is undefined 2015-09-06 08:45:42 -07:00
Rob Schoening
e0b109cba6 fix read() failure with private repos
reorder buildRequest()
2015-09-06 08:28:20 -07:00
Kohsuke Kawaguchi
adaa8ece89 [maven-release-plugin] prepare for next development iteration 2015-08-15 07:19:25 -07:00
47 changed files with 909 additions and 260 deletions

View File

@@ -7,7 +7,7 @@
</parent>
<artifactId>github-api</artifactId>
<version>1.70</version>
<version>1.73</version>
<name>GitHub API for Java</name>
<url>http://github-api.kohsuke.org/</url>
<description>GitHub API for Java</description>
@@ -16,7 +16,7 @@
<connection>scm:git:git@github.com/kohsuke/${project.artifactId}.git</connection>
<developerConnection>scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git</developerConnection>
<url>http://${project.artifactId}.kohsuke.org/</url>
<tag>github-api-1.70</tag>
<tag>github-api-1.73</tag>
</scm>
<distributionManagement>
@@ -28,7 +28,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<findbugs-maven-plugin.version>3.0.1</findbugs-maven-plugin.version>
<findbugs-maven-plugin.version>3.0.2</findbugs-maven-plugin.version>
<findbugs-maven-plugin.failOnError>true</findbugs-maven-plugin.failOnError>
</properties>
@@ -52,7 +52,6 @@
<version>${findbugs-maven-plugin.version}</version>
<configuration>
<xmlOutput>true</xmlOutput>
<findbugsXmlWithMessages>true</findbugsXmlWithMessages>
<failOnError>${findbugs-maven-plugin.failOnError}</failOnError>
</configuration>
<executions>

View File

@@ -102,7 +102,7 @@ public class GHCommit {
}
/**
* "modified", "added", or "deleted"
* "modified", "added", or "removed"
*/
public String getStatus() {
return status;
@@ -171,14 +171,15 @@ public class GHCommit {
String login;
}
String url,sha;
String url,html_url,sha;
List<File> files;
Stats stats;
List<Parent> parents;
User author,committer;
public ShortInfo getCommitShortInfo() {
public ShortInfo getCommitShortInfo() throws IOException {
populate();
return commit;
}
@@ -192,24 +193,34 @@ public class GHCommit {
/**
* Number of lines added + removed.
*/
public int getLinesChanged() {
public int getLinesChanged() throws IOException {
populate();
return stats.total;
}
/**
* Number of lines added.
*/
public int getLinesAdded() {
public int getLinesAdded() throws IOException {
populate();
return stats.additions;
}
/**
* Number of lines removed.
*/
public int getLinesDeleted() {
public int getLinesDeleted() throws IOException {
populate();
return stats.deletions;
}
/**
* URL of this commit like "https://github.com/kohsuke/sandbox-ant/commit/8ae38db0ea5837313ab5f39d43a6f73de3bd9000"
*/
public URL getHtmlUrl() {
return GitHub.parseURL(html_url);
}
/**
* [0-9a-f]{40} SHA1 checksum.
*/
@@ -223,7 +234,8 @@ public class GHCommit {
* @return
* Can be empty but never null.
*/
public List<File> getFiles() {
public List<File> getFiles() throws IOException {
populate();
return files!=null ? Collections.unmodifiableList(files) : Collections.<File>emptyList();
}
@@ -273,8 +285,8 @@ public class GHCommit {
*/
public PagedIterable<GHCommitComment> listComments() {
return new PagedIterable<GHCommitComment>() {
public PagedIterator<GHCommitComment> iterator() {
return new PagedIterator<GHCommitComment>(owner.root.retrieve().asIterator(String.format("/repos/%s/%s/commits/%s/comments", owner.getOwnerName(), owner.getName(), sha), GHCommitComment[].class)) {
public PagedIterator<GHCommitComment> _iterator(int pageSize) {
return new PagedIterator<GHCommitComment>(owner.root.retrieve().asIterator(String.format("/repos/%s/%s/commits/%s/comments", owner.getOwnerName(), owner.getName(), sha), GHCommitComment[].class, pageSize)) {
@Override
protected void wrapUp(GHCommitComment[] page) {
for (GHCommitComment c : page)
@@ -301,7 +313,7 @@ public class GHCommit {
}
public GHCommitComment createComment(String body) throws IOException {
return createComment(body,null,null,null);
return createComment(body, null, null, null);
}
/**
@@ -318,6 +330,14 @@ public class GHCommit {
return owner.getLastCommitStatus(sha);
}
/**
* Some of the fields are not always filled in when this object is retrieved as a part of another API call.
*/
void populate() throws IOException {
if (files==null && stats==null)
owner.root.retrieve().to(owner.getApiTailUrl("commits/" + sha), this);
}
GHCommit wrapUp(GHRepository owner) {
this.owner = owner;
return this;

View File

@@ -92,8 +92,8 @@ public class GHCommitQueryBuilder {
*/
public PagedIterable<GHCommit> list() {
return new PagedIterable<GHCommit>() {
public PagedIterator<GHCommit> iterator() {
return new PagedIterator<GHCommit>(req.asIterator(repo.getApiTailUrl("commits"), GHCommit[].class)) {
public PagedIterator<GHCommit> _iterator(int pageSize) {
return new PagedIterator<GHCommit>(req.asIterator(repo.getApiTailUrl("commits"), GHCommit[].class, pageSize)) {
protected void wrapUp(GHCommit[] page) {
for (GHCommit c : page)
c.wrapUp(repo);

View File

@@ -152,8 +152,8 @@ public class GHContent {
throw new IllegalStateException(path+" is not a directory");
return new PagedIterable<GHContent>() {
public PagedIterator<GHContent> iterator() {
return new PagedIterator<GHContent>(root.retrieve().asIterator(url, GHContent[].class)) {
public PagedIterator<GHContent> _iterator(int pageSize) {
return new PagedIterator<GHContent>(root.retrieve().asIterator(url, GHContent[].class, pageSize)) {
@Override
protected void wrapUp(GHContent[] page) {
GHContent.wrap(page, repository);

View File

@@ -0,0 +1,114 @@
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
/**
* Creates a repository
*
* @author Kohsuke Kawaguchi
*/
public class GHCreateRepositoryBuilder {
private final GitHub root;
protected final Requester builder;
private final String apiUrlTail;
/*package*/ GHCreateRepositoryBuilder(GitHub root, String apiUrlTail, String name) {
this.root = root;
this.apiUrlTail = apiUrlTail;
this.builder = new Requester(root);
this.builder.with("name",name);
}
public GHCreateRepositoryBuilder description(String description) {
this.builder.with("description",description);
return this;
}
public GHCreateRepositoryBuilder homepage(URL homepage) {
return homepage(homepage.toExternalForm());
}
public GHCreateRepositoryBuilder homepage(String homepage) {
this.builder.with("homepage",homepage);
return this;
}
/**
* Creates a private repository
*/
public GHCreateRepositoryBuilder private_(boolean b) {
this.builder.with("private",b);
return this;
}
/**
* Enables issue tracker
*/
public GHCreateRepositoryBuilder issues(boolean b) {
this.builder.with("has_issues",b);
return this;
}
/**
* Enables wiki
*/
public GHCreateRepositoryBuilder wiki(boolean b) {
this.builder.with("has_wiki",b);
return this;
}
/**
* Enables downloads
*/
public GHCreateRepositoryBuilder downloads(boolean b) {
this.builder.with("has_downloads",b);
return this;
}
/**
* If true, create an initial commit with empty README.
*/
public GHCreateRepositoryBuilder autoInit(boolean b) {
this.builder.with("auto_init",b);
return this;
}
/**
* Creates a default .gitignore
*
* See https://developer.github.com/v3/repos/#create
*/
public GHCreateRepositoryBuilder gitignoreTemplate(String language) {
this.builder.with("gitignore_template",language);
return this;
}
/**
* Desired license template to apply
*
* See https://developer.github.com/v3/repos/#create
*/
public GHCreateRepositoryBuilder licenseTemplate(String license) {
this.builder.with("license_template",license);
return this;
}
/**
* The team that gets granted access to this repository. Only valid for creating a repository in
* an organization.
*/
public GHCreateRepositoryBuilder team(GHTeam team) {
if (team!=null)
this.builder.with("team_id",team.getId());
return this;
}
/**
* Creates a repository with all the parameters.
*/
public GHRepository create() throws IOException {
return builder.method("POST").to(apiUrlTail, GHRepository.class).wrap(root);
}
}

View File

@@ -12,7 +12,7 @@ public class GHDeploymentStatusBuilder {
this.repo = repo;
this.deploymentId = deploymentId;
this.builder = new Requester(repo.root);
this.builder.with("state",state.toString().toLowerCase(Locale.ENGLISH));
this.builder.with("state",state);
}
public GHDeploymentStatusBuilder description(String description) {

View File

@@ -0,0 +1,10 @@
package org.kohsuke.github;
/**
* Sort direction
*
* @author Kohsuke Kawaguchi
*/
public enum GHDirection {
ASC, DESC
}

View File

@@ -1,5 +1,7 @@
package org.kohsuke.github;
import java.util.Locale;
/**
* Hook event type.
*
@@ -33,5 +35,18 @@ public enum GHEvent {
STATUS,
TEAM_ADD,
WATCH,
PING
PING,
/**
* Special event type that means "every possible event"
*/
ALL;
/**
* Returns GitHub's internal representation of this event.
*/
String symbol() {
if (this==ALL) return "*";
return name().toLowerCase(Locale.ENGLISH);
}
}

View File

@@ -18,6 +18,7 @@ public class GHEventInfo {
// we don't want to expose Jackson dependency to the user. This needs databinding
private ObjectNode payload;
private long id;
private String created_at;
private String type;
@@ -54,6 +55,10 @@ public class GHEventInfo {
return this;
}
public long getId() {
return id;
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}

View File

@@ -140,8 +140,8 @@ public class GHGist extends GHObject {
public PagedIterable<GHGist> listForks() {
return new PagedIterable<GHGist>() {
public PagedIterator<GHGist> iterator() {
return new PagedIterator<GHGist>(root.retrieve().asIterator(getApiTailUrl("forks"), GHGist[].class)) {
public PagedIterator<GHGist> _iterator(int pageSize) {
return new PagedIterator<GHGist>(root.retrieve().asIterator(getApiTailUrl("forks"), GHGist[].class, pageSize)) {
@Override
protected void wrapUp(GHGist[] page) {
try {

View File

@@ -26,8 +26,10 @@ public abstract class GHHook extends GHObject {
public EnumSet<GHEvent> getEvents() {
EnumSet<GHEvent> s = EnumSet.noneOf(GHEvent.class);
for (String e : events)
s.add(Enum.valueOf(GHEvent.class,e.toUpperCase(Locale.ENGLISH)));
for (String e : events) {
if (e.equals("*")) s.add(GHEvent.ALL);
else s.add(Enum.valueOf(GHEvent.class, e.toUpperCase(Locale.ENGLISH)));
}
return s;
}

View File

@@ -21,8 +21,9 @@ class GHHooks {
}
public List<GHHook> getHooks() throws IOException {
List<GHHook> list = new ArrayList<GHHook>(Arrays.asList(
root.retrieve().to(collection(), collectionClass())));
GHHook [] hookArray = root.retrieve().to(collection(),collectionClass()); // jdk/eclipse bug requires this to be on separate line
List<GHHook> list = new ArrayList<GHHook>(Arrays.asList(hookArray));
for (GHHook h : list)
wrap(h);
return list;
@@ -38,7 +39,7 @@ class GHHooks {
if (events!=null) {
ea = new ArrayList<String>();
for (GHEvent e : events)
ea.add(e.name().toLowerCase(Locale.ENGLISH));
ea.add(e.symbol());
}
GHHook hook = new Requester(root)

View File

@@ -205,8 +205,8 @@ public class GHIssue extends GHObject {
*/
public PagedIterable<GHIssueComment> listComments() throws IOException {
return new PagedIterable<GHIssueComment>() {
public PagedIterator<GHIssueComment> iterator() {
return new PagedIterator<GHIssueComment>(root.retrieve().asIterator(getIssuesApiRoute() + "/comments", GHIssueComment[].class)) {
public PagedIterator<GHIssueComment> _iterator(int pageSize) {
return new PagedIterator<GHIssueComment>(root.retrieve().asIterator(getIssuesApiRoute() + "/comments", GHIssueComment[].class, pageSize)) {
protected void wrapUp(GHIssueComment[] page) {
for (GHIssueComment c : page)
c.wrapUp(GHIssue.this);

View File

@@ -42,7 +42,7 @@ public class GHIssueSearchBuilder extends GHSearchBuilder<GHIssue> {
}
public GHIssueSearchBuilder sort(Sort sort) {
req.with("sort",sort.toString().toLowerCase(Locale.ENGLISH));
req.with("sort",sort);
return this;
}

View File

@@ -24,7 +24,11 @@
package org.kohsuke.github;
/**
* @see GHPullRequestQueryBuilder#state(GHIssueState)
*/
public enum GHIssueState {
OPEN,
CLOSED
CLOSED,
ALL
}

View File

@@ -17,6 +17,7 @@ public class GHMilestone extends GHObject {
GHUser creator;
private String state, due_on, title, description, html_url;
private int closed_issues, open_issues, number;
protected String closed_at;
public GitHub getRoot() {
return root;
@@ -34,7 +35,14 @@ public class GHMilestone extends GHObject {
if (due_on == null) return null;
return GitHub.parseDate(due_on);
}
/**
* When was this milestone closed?
*/
public Date getClosedAt() throws IOException {
return GitHub.parseDate(closed_at);
}
public String getTitle() {
return title;
}

View File

@@ -158,9 +158,8 @@ public class GHMyself extends GHUser {
*/
public PagedIterable<GHRepository> listRepositories(final int pageSize, final RepositoryListFilter repoType) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> iterator() {
return new PagedIterator<GHRepository>(root.retrieve().asIterator("/user/repos?per_page=" + pageSize +
"&type=" + repoType.name().toLowerCase(Locale.ENGLISH), GHRepository[].class)) {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(root.retrieve().with("type",repoType).asIterator("/user/repos", GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
@@ -168,7 +167,7 @@ public class GHMyself extends GHUser {
}
};
}
};
}.withPageSize(pageSize);
}
/**

View File

@@ -29,6 +29,11 @@ public abstract class GHObject {
return GitHub.parseDate(created_at);
}
@SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD", justification = "Bridge method of getCreatedAt")
private Object createdAtStr(Date id, Class type) {
return created_at;
}
/**
* API URL of this object.
*/
@@ -57,4 +62,14 @@ public abstract class GHObject {
public int getId() {
return id;
}
@SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD", justification = "Bridge method of getId")
private Object intToString(int id, Class type) {
return String.valueOf(id);
}
@SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD", justification = "Bridge method of getHtmlUrl")
private Object urlToString(URL url, Class type) {
return url==null ? null : url.toString();
}
}

View File

@@ -7,7 +7,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
@@ -24,6 +23,8 @@ public class GHOrganization extends GHPerson {
*
* @return
* Newly created repository.
* @deprecated
* Use {@link #createRepository(String)} that uses a builder pattern to let you control every aspect.
*/
public GHRepository createRepository(String name, String description, String homepage, String team, boolean isPublic) throws IOException {
GHTeam t = getTeams().get(team);
@@ -32,13 +33,25 @@ public class GHOrganization extends GHPerson {
return createRepository(name, description, homepage, t, isPublic);
}
/**
* @deprecated
* Use {@link #createRepository(String)} that uses a builder pattern to let you control every aspect.
*/
public GHRepository createRepository(String name, String description, String homepage, GHTeam team, boolean isPublic) throws IOException {
if (team==null)
throw new IllegalArgumentException("Invalid team");
// such API doesn't exist, so fall back to HTML scraping
return new Requester(root)
.with("name", name).with("description", description).with("homepage", homepage)
.with("public", isPublic).with("team_id",team.getId()).to("/orgs/"+login+"/repos", GHRepository.class).wrap(root);
return createRepository(name).description(description).homepage(homepage).private_(!isPublic).team(team).create();
}
/**
* Starts a builder that creates a new repository.
*
* <p>
* You use the returned builder to set various properties, then call {@link GHCreateRepositoryBuilder#create()}
* to finally createa repository.
*/
public GHCreateRepositoryBuilder createRepository(String name) throws IOException {
return new GHCreateRepositoryBuilder(root,"/orgs/"+login+"/repos",name);
}
/**
@@ -57,8 +70,8 @@ public class GHOrganization extends GHPerson {
*/
public PagedIterable<GHTeam> listTeams() throws IOException {
return new PagedIterable<GHTeam>() {
public PagedIterator<GHTeam> iterator() {
return new PagedIterator<GHTeam>(root.retrieve().asIterator(String.format("/orgs/%s/teams", login), GHTeam[].class)) {
public PagedIterator<GHTeam> _iterator(int pageSize) {
return new PagedIterator<GHTeam>(root.retrieve().asIterator(String.format("/orgs/%s/teams", login), GHTeam[].class, pageSize)) {
@Override
protected void wrapUp(GHTeam[] page) {
for (GHTeam c : page)
@@ -150,9 +163,9 @@ public class GHOrganization extends GHPerson {
private PagedIterable<GHUser> listMembers(final String suffix, final String filter) throws IOException {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> iterator() {
public PagedIterator<GHUser> _iterator(int pageSize) {
String filterParams = (filter == null) ? "" : ("?filter=" + filter);
return new PagedIterator<GHUser>(root.retrieve().asIterator(String.format("/orgs/%s/%s%s", login, suffix, filterParams), GHUser[].class)) {
return new PagedIterator<GHUser>(root.retrieve().asIterator(String.format("/orgs/%s/%s%s", login, suffix, filterParams), GHUser[].class, pageSize)) {
@Override
protected void wrapUp(GHUser[] users) {
GHUser.wrap(users, root);
@@ -175,7 +188,7 @@ public class GHOrganization extends GHPerson {
* Creates a new team and assigns the repositories.
*/
public GHTeam createTeam(String name, Permission p, Collection<GHRepository> repositories) throws IOException {
Requester post = new Requester(root).with("name", name).with("permission", p.name().toLowerCase(Locale.ENGLISH));
Requester post = new Requester(root).with("name", name).with("permission", p);
List<String> repo_names = new ArrayList<String>();
for (GHRepository r : repositories) {
repo_names.add(r.getName());
@@ -185,7 +198,7 @@ public class GHOrganization extends GHPerson {
}
public GHTeam createTeam(String name, Permission p, GHRepository... repositories) throws IOException {
return createTeam(name,p, Arrays.asList(repositories));
return createTeam(name, p, Arrays.asList(repositories));
}
/**
@@ -222,8 +235,8 @@ public class GHOrganization extends GHPerson {
*/
public PagedIterable<GHEventInfo> listEvents() throws IOException {
return new PagedIterable<GHEventInfo>() {
public PagedIterator<GHEventInfo> iterator() {
return new PagedIterator<GHEventInfo>(root.retrieve().asIterator(String.format("/orgs/%s/events", login), GHEventInfo[].class)) {
public PagedIterator<GHEventInfo> _iterator(int pageSize) {
return new PagedIterator<GHEventInfo>(root.retrieve().asIterator(String.format("/orgs/%s/events", login), GHEventInfo[].class, pageSize)) {
@Override
protected void wrapUp(GHEventInfo[] page) {
for (GHEventInfo c : page)
@@ -244,8 +257,8 @@ public class GHOrganization extends GHPerson {
@Override
public PagedIterable<GHRepository> listRepositories(final int pageSize) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> iterator() {
return new PagedIterator<GHRepository>(root.retrieve().asIterator("/orgs/" + login + "/repos?per_page=" + pageSize, GHRepository[].class)) {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(root.retrieve().asIterator("/orgs/" + login + "/repos?per_page=" + pageSize, GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)

View File

@@ -76,8 +76,8 @@ public abstract class GHPerson extends GHObject {
*/
public PagedIterable<GHRepository> listRepositories(final int pageSize) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> iterator() {
return new PagedIterator<GHRepository>(root.retrieve().asIterator("/users/" + login + "/repos?per_page=" + pageSize, GHRepository[].class)) {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(root.retrieve().asIterator("/users/" + login + "/repos?per_page=" + pageSize, GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
@@ -104,7 +104,7 @@ public abstract class GHPerson extends GHObject {
public synchronized Iterable<List<GHRepository>> iterateRepositories(final int pageSize) {
return new Iterable<List<GHRepository>>() {
public Iterator<List<GHRepository>> iterator() {
final Iterator<GHRepository[]> pager = root.retrieve().asIterator("/users/" + login + "/repos?per_page="+pageSize,GHRepository[].class);
final Iterator<GHRepository[]> pager = root.retrieve().asIterator("/users/" + login + "/repos?per_page="+pageSize,GHRepository[].class, pageSize);
return new Iterator<List<GHRepository>>() {
public boolean hasNext() {

View File

@@ -50,6 +50,7 @@ public class GHPullRequest extends GHIssue {
private int deletions;
private String mergeable_state;
private int changed_files;
private String merge_commit_sha;
/**
* GitHub doesn't return some properties of {@link GHIssue} when requesting the GET on the 'pulls' API
@@ -142,9 +143,9 @@ public class GHPullRequest extends GHIssue {
}
//
// details that are only available via get with ID
//
//
// details that are only available via get with ID
//
public GHUser getMergedBy() throws IOException {
populate();
return merged_by;
@@ -185,6 +186,14 @@ public class GHPullRequest extends GHIssue {
return changed_files;
}
/**
* See <a href="https://developer.github.com/changes/2013-04-25-deprecating-merge-commit-sha">GitHub blog post</a>
*/
public String getMergeCommitSha() throws IOException {
populate();
return merge_commit_sha;
}
/**
* Fully populate the data by retrieving missing data.
*
@@ -201,9 +210,9 @@ public class GHPullRequest extends GHIssue {
*/
public PagedIterable<GHPullRequestFileDetail> listFiles() {
return new PagedIterable<GHPullRequestFileDetail>() {
public PagedIterator<GHPullRequestFileDetail> iterator() {
public PagedIterator<GHPullRequestFileDetail> _iterator(int pageSize) {
return new PagedIterator<GHPullRequestFileDetail>(root.retrieve().asIterator(String.format("%s/files", getApiURL()),
GHPullRequestFileDetail[].class)) {
GHPullRequestFileDetail[].class, pageSize)) {
@Override
protected void wrapUp(GHPullRequestFileDetail[] page) {
}
@@ -217,9 +226,9 @@ public class GHPullRequest extends GHIssue {
*/
public PagedIterable<GHPullRequestReviewComment> listReviewComments() throws IOException {
return new PagedIterable<GHPullRequestReviewComment>() {
public PagedIterator<GHPullRequestReviewComment> iterator() {
public PagedIterator<GHPullRequestReviewComment> _iterator(int pageSize) {
return new PagedIterator<GHPullRequestReviewComment>(root.retrieve().asIterator(getApiRoute() + "/comments",
GHPullRequestReviewComment[].class)) {
GHPullRequestReviewComment[].class, pageSize)) {
protected void wrapUp(GHPullRequestReviewComment[] page) {
for (GHPullRequestReviewComment c : page)
c.wrapUp(GHPullRequest.this);
@@ -234,10 +243,10 @@ public class GHPullRequest extends GHIssue {
*/
public PagedIterable<GHPullRequestCommitDetail> listCommits() {
return new PagedIterable<GHPullRequestCommitDetail>() {
public PagedIterator<GHPullRequestCommitDetail> iterator() {
public PagedIterator<GHPullRequestCommitDetail> _iterator(int pageSize) {
return new PagedIterator<GHPullRequestCommitDetail>(root.retrieve().asIterator(
String.format("%s/commits", getApiURL()),
GHPullRequestCommitDetail[].class)) {
GHPullRequestCommitDetail[].class, pageSize)) {
@Override
protected void wrapUp(GHPullRequestCommitDetail[] page) {
for (GHPullRequestCommitDetail c : page)

View File

@@ -0,0 +1,58 @@
package org.kohsuke.github;
/**
* Lists up pull requests with some filtering and sorting.
*
* @author Kohsuke Kawaguchi
* @see GHRepository#queryPullRequests()
*/
public class GHPullRequestQueryBuilder extends GHQueryBuilder<GHPullRequest> {
private final GHRepository repo;
/*package*/ GHPullRequestQueryBuilder(GHRepository repo) {
super(repo.root);
this.repo = repo;
}
public GHPullRequestQueryBuilder state(GHIssueState state) {
req.with("state",state);
return this;
}
public GHPullRequestQueryBuilder head(String head) {
req.with("head",head);
return this;
}
public GHPullRequestQueryBuilder base(String base) {
req.with("base",base);
return this;
}
public GHPullRequestQueryBuilder sort(Sort sort) {
req.with("sort",sort);
return this;
}
public enum Sort { CREATED, UPDATED, POPULARITY, LONG_RUNNING }
public GHPullRequestQueryBuilder direction(GHDirection d) {
req.with("direction",d);
return this;
}
@Override
public PagedIterable<GHPullRequest> list() {
return new PagedIterable<GHPullRequest>() {
public PagedIterator<GHPullRequest> _iterator(int pageSize) {
return new PagedIterator<GHPullRequest>(req.asIterator(repo.getApiTailUrl("pulls"), GHPullRequest[].class, pageSize)) {
@Override
protected void wrapUp(GHPullRequest[] page) {
for (GHPullRequest pr : page)
pr.wrapUp(repo);
}
};
}
};
}
}

View File

@@ -0,0 +1,21 @@
package org.kohsuke.github;
/**
* Used to specify filters, sort order, etc for listing items in a collection.
*
* @author Kohsuke Kawaguchi
*/
public abstract class GHQueryBuilder<T> {
protected final GitHub root;
protected final Requester req;
/*package*/ GHQueryBuilder(GitHub root) {
this.root = root;
this.req = root.retrieve();
}
/**
* Start listing items by using the settings built up on this object.
*/
public abstract PagedIterable<T> list();
}

View File

@@ -129,14 +129,9 @@ public class GHRelease extends GHObject {
String url = format("https://uploads.github.com%s/releases/%d/assets?name=%s",
owner.getApiTailUrl(""), getId(), file.getName());
FileInputStream istream = new FileInputStream(file);
try {
return builder.contentType(contentType)
.with(istream)
return builder.contentType(contentType)
.with(new FileInputStream(file))
.to(url, GHAsset.class).wrap(this);
} finally {
istream.close();
}
}
public List<GHAsset> getAssets() throws IOException {

View File

@@ -36,7 +36,6 @@ import java.io.InterruptedIOException;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.*;
import static java.util.Arrays.asList;
@@ -54,7 +53,7 @@ public class GHRepository extends GHObject {
private String description, homepage, name, full_name;
private String html_url; // this is the UI
private String git_url, ssh_url, clone_url, svn_url;
private String git_url, ssh_url, clone_url, svn_url, mirror_url;
private GHUser owner; // not fully populated. beware.
private boolean has_issues, has_wiki, fork, has_downloads;
@JsonProperty("private")
@@ -76,8 +75,8 @@ public class GHRepository extends GHObject {
public PagedIterable<GHDeploymentStatus> getDeploymentStatuses(final int id) {
return new PagedIterable<GHDeploymentStatus>() {
public PagedIterator<GHDeploymentStatus> iterator() {
return new PagedIterator<GHDeploymentStatus>(root.retrieve().asIterator(getApiTailUrl("deployments")+"/"+id+"/statuses", GHDeploymentStatus[].class)) {
public PagedIterator<GHDeploymentStatus> _iterator(int pageSize) {
return new PagedIterator<GHDeploymentStatus>(root.retrieve().asIterator(getApiTailUrl("deployments")+"/"+id+"/statuses", GHDeploymentStatus[].class, pageSize)) {
@Override
protected void wrapUp(GHDeploymentStatus[] page) {
for (GHDeploymentStatus c : page)
@@ -92,8 +91,8 @@ public class GHRepository extends GHObject {
List<String> params = Arrays.asList(getParam("sha", sha), getParam("ref", ref), getParam("task", task), getParam("environment", environment));
final String deploymentsUrl = getApiTailUrl("deployments") + "?"+ join(params,"&");
return new PagedIterable<GHDeployment>() {
public PagedIterator<GHDeployment> iterator() {
return new PagedIterator<GHDeployment>(root.retrieve().asIterator(deploymentsUrl, GHDeployment[].class)) {
public PagedIterator<GHDeployment> _iterator(int pageSize) {
return new PagedIterator<GHDeployment>(root.retrieve().asIterator(deploymentsUrl, GHDeployment[].class, pageSize)) {
@Override
protected void wrapUp(GHDeployment[] page) {
for (GHDeployment c : page)
@@ -159,6 +158,14 @@ public class GHRepository extends GHObject {
return svn_url;
}
/**
* Gets the Mirror URL to access this repository: https://github.com/apache/tomee
* mirrored from git://git.apache.org/tomee.git
*/
public String getMirrorUrl() {
return mirror_url;
}
/**
* Gets the SSH URL to access this repository, such as git@github.com:rails/rails.git
*/
@@ -221,11 +228,10 @@ public class GHRepository extends GHObject {
public List<GHIssue> getIssues(GHIssueState state, GHMilestone milestone) throws IOException {
return Arrays.asList(GHIssue.wrap(root.retrieve()
.to(getApiTailUrl(String.format("issues?state=%s&milestone=%s",
state.toString().toLowerCase(Locale.ENGLISH),
milestone == null ? "none" : "" + milestone.getNumber())),
GHIssue[].class
), this));
.with("state", state)
.with("milestone", milestone == null ? "none" : "" + milestone.getNumber())
.to(getApiTailUrl("issues"),
GHIssue[].class), this));
}
/**
@@ -233,8 +239,8 @@ public class GHRepository extends GHObject {
*/
public PagedIterable<GHIssue> listIssues(final GHIssueState state) {
return new PagedIterable<GHIssue>() {
public PagedIterator<GHIssue> iterator() {
return new PagedIterator<GHIssue>(root.retrieve().asIterator(getApiTailUrl("issues?state="+state.toString().toLowerCase(Locale.ENGLISH)), GHIssue[].class)) {
public PagedIterator<GHIssue> _iterator(int pageSize) {
return new PagedIterator<GHIssue>(root.retrieve().with("state",state).asIterator(getApiTailUrl("issues"), GHIssue[].class, pageSize)) {
@Override
protected void wrapUp(GHIssue[] page) {
for (GHIssue c : page)
@@ -273,8 +279,8 @@ public class GHRepository extends GHObject {
public PagedIterable<GHRelease> listReleases() throws IOException {
return new PagedIterable<GHRelease>() {
public PagedIterator<GHRelease> iterator() {
return new PagedIterator<GHRelease>(root.retrieve().asIterator(getApiTailUrl("releases"), GHRelease[].class)) {
public PagedIterator<GHRelease> _iterator(int pageSize) {
return new PagedIterator<GHRelease>(root.retrieve().asIterator(getApiTailUrl("releases"), GHRelease[].class, pageSize)) {
@Override
protected void wrapUp(GHRelease[] page) {
for (GHRelease c : page)
@@ -287,8 +293,8 @@ public class GHRepository extends GHObject {
public PagedIterable<GHTag> listTags() throws IOException {
return new PagedIterable<GHTag>() {
public PagedIterator<GHTag> iterator() {
return new PagedIterator<GHTag>(root.retrieve().asIterator(getApiTailUrl("tags"), GHTag[].class)) {
public PagedIterator<GHTag> _iterator(int pageSize) {
return new PagedIterator<GHTag>(root.retrieve().asIterator(getApiTailUrl("tags"), GHTag[].class, pageSize)) {
@Override
protected void wrapUp(GHTag[] page) {
for (GHTag c : page)
@@ -408,9 +414,9 @@ public class GHRepository extends GHObject {
*/
public PagedIterable<GHUser> listCollaborators() throws IOException {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> iterator() {
public PagedIterator<GHUser> _iterator(int pageSize) {
return new PagedIterator<GHUser>(root.retrieve().asIterator(getApiTailUrl("collaborators"), GHUser[].class)) {
return new PagedIterator<GHUser>(root.retrieve().asIterator(getApiTailUrl("collaborators"), GHUser[].class, pageSize)) {
@Override
protected void wrapUp(GHUser[] users) {
@@ -469,7 +475,7 @@ public class GHRepository extends GHObject {
public void setEmailServiceHook(String address) throws IOException {
Map<String, String> config = new HashMap<String, String>();
config.put("address", address);
new Requester(root).method("POST").with("name", "email").with("config", config).with("active", "true")
new Requester(root).method("POST").with("name", "email").with("config", config).with("active", true)
.to(getApiTailUrl("hooks"));
}
@@ -531,7 +537,7 @@ public class GHRepository extends GHObject {
/**
* Sort orders for listing forks
*/
public static enum ForkSort { NEWEST, OLDEST, STARGAZERS }
public enum ForkSort { NEWEST, OLDEST, STARGAZERS }
/**
* Lists all the direct forks of this repository, sorted by
@@ -548,12 +554,8 @@ public class GHRepository extends GHObject {
*/
public PagedIterable<GHRepository> listForks(final ForkSort sort) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> iterator() {
String sortParam = "";
if (sort != null) {
sortParam = "?sort=" + sort.toString().toLowerCase(Locale.ENGLISH);
}
return new PagedIterator<GHRepository>(root.retrieve().asIterator(getApiTailUrl("forks" + sortParam), GHRepository[].class)) {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(root.retrieve().with("sort",sort).asIterator(getApiTailUrl("forks"), GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page) {
@@ -610,24 +612,24 @@ public class GHRepository extends GHObject {
* @see #listPullRequests(GHIssueState)
*/
public List<GHPullRequest> getPullRequests(GHIssueState state) throws IOException {
return listPullRequests(state).asList();
return queryPullRequests().state(state).list().asList();
}
/**
* Retrieves all the pull requests of a particular state.
*
* @deprecated
* Use {@link #queryPullRequests()}
*/
public PagedIterable<GHPullRequest> listPullRequests(final GHIssueState state) {
return new PagedIterable<GHPullRequest>() {
public PagedIterator<GHPullRequest> iterator() {
return new PagedIterator<GHPullRequest>(root.retrieve().asIterator(getApiTailUrl("pulls?state="+state.name().toLowerCase(Locale.ENGLISH)), GHPullRequest[].class)) {
@Override
protected void wrapUp(GHPullRequest[] page) {
for (GHPullRequest pr : page)
pr.wrapUp(GHRepository.this);
}
};
}
};
public PagedIterable<GHPullRequest> listPullRequests(GHIssueState state) {
return queryPullRequests().state(state).list();
}
/**
* Retrieves pull requests.
*/
public GHPullRequestQueryBuilder queryPullRequests() {
return new GHPullRequestQueryBuilder(this);
}
/**
@@ -682,7 +684,23 @@ public class GHRepository extends GHObject {
}
public GHCompare getCompare(GHBranch id1, GHBranch id2) throws IOException {
return getCompare(id1.getName(),id2.getName());
GHRepository owner1 = id1.getOwner();
GHRepository owner2 = id2.getOwner();
// If the owner of the branches is different, we have a cross-fork compare.
if (owner1!=null && owner2!=null) {
String ownerName1 = owner1.getOwnerName();
String ownerName2 = owner2.getOwnerName();
if (!StringUtils.equals(ownerName1, ownerName2)) {
String qualifiedName1 = String.format("%s:%s", ownerName1, id1.getName());
String qualifiedName2 = String.format("%s:%s", ownerName2, id2.getName());
return getCompare(qualifiedName1, qualifiedName2);
}
}
return getCompare(id1.getName(), id2.getName());
}
/**
@@ -691,7 +709,7 @@ public class GHRepository extends GHObject {
* @throws IOException on failure communicating with GitHub
*/
public GHRef[] getRefs() throws IOException {
return GHRef.wrap(root.retrieve().to(String.format("/repos/%s/%s/git/refs", owner.login, name), GHRef[].class),root);
return GHRef.wrap(root.retrieve().to(String.format("/repos/%s/%s/git/refs", owner.login, name), GHRef[].class), root);
}
/**
@@ -762,8 +780,8 @@ public class GHRepository extends GHObject {
*/
public PagedIterable<GHCommit> listCommits() {
return new PagedIterable<GHCommit>() {
public PagedIterator<GHCommit> iterator() {
return new PagedIterator<GHCommit>(root.retrieve().asIterator(String.format("/repos/%s/%s/commits", owner.login, name), GHCommit[].class)) {
public PagedIterator<GHCommit> _iterator(int pageSize) {
return new PagedIterator<GHCommit>(root.retrieve().asIterator(String.format("/repos/%s/%s/commits", owner.login, name), GHCommit[].class, pageSize)) {
protected void wrapUp(GHCommit[] page) {
for (GHCommit c : page)
c.wrapUp(GHRepository.this);
@@ -785,8 +803,8 @@ public class GHRepository extends GHObject {
*/
public PagedIterable<GHCommitComment> listCommitComments() {
return new PagedIterable<GHCommitComment>() {
public PagedIterator<GHCommitComment> iterator() {
return new PagedIterator<GHCommitComment>(root.retrieve().asIterator(String.format("/repos/%s/%s/comments", owner.login, name), GHCommitComment[].class)) {
public PagedIterator<GHCommitComment> _iterator(int pageSize) {
return new PagedIterator<GHCommitComment>(root.retrieve().asIterator(String.format("/repos/%s/%s/comments", owner.login, name), GHCommitComment[].class, pageSize)) {
@Override
protected void wrapUp(GHCommitComment[] page) {
for (GHCommitComment c : page)
@@ -802,8 +820,8 @@ public class GHRepository extends GHObject {
*/
public PagedIterable<GHCommitStatus> listCommitStatuses(final String sha1) throws IOException {
return new PagedIterable<GHCommitStatus>() {
public PagedIterator<GHCommitStatus> iterator() {
return new PagedIterator<GHCommitStatus>(root.retrieve().asIterator(String.format("/repos/%s/%s/statuses/%s", owner.login, name, sha1), GHCommitStatus[].class)) {
public PagedIterator<GHCommitStatus> _iterator(int pageSize) {
return new PagedIterator<GHCommitStatus>(root.retrieve().asIterator(String.format("/repos/%s/%s/statuses/%s", owner.login, name, sha1), GHCommitStatus[].class, pageSize)) {
@Override
protected void wrapUp(GHCommitStatus[] page) {
for (GHCommitStatus c : page)
@@ -834,7 +852,7 @@ public class GHRepository extends GHObject {
*/
public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description, String context) throws IOException {
return new Requester(root)
.with("state", state.name().toLowerCase(Locale.ENGLISH))
.with("state", state)
.with("target_url", targetUrl)
.with("description", description)
.with("context", context)
@@ -845,7 +863,7 @@ public class GHRepository extends GHObject {
* @see #createCommitStatus(String, GHCommitState,String,String,String)
*/
public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description) throws IOException {
return createCommitStatus(sha1, state, targetUrl, description,null);
return createCommitStatus(sha1, state, targetUrl, description, null);
}
/**
@@ -853,8 +871,8 @@ public class GHRepository extends GHObject {
*/
public PagedIterable<GHEventInfo> listEvents() throws IOException {
return new PagedIterable<GHEventInfo>() {
public PagedIterator<GHEventInfo> iterator() {
return new PagedIterator<GHEventInfo>(root.retrieve().asIterator(String.format("/repos/%s/%s/events", owner.login, name), GHEventInfo[].class)) {
public PagedIterator<GHEventInfo> _iterator(int pageSize) {
return new PagedIterator<GHEventInfo>(root.retrieve().asIterator(String.format("/repos/%s/%s/events", owner.login, name), GHEventInfo[].class, pageSize)) {
@Override
protected void wrapUp(GHEventInfo[] page) {
for (GHEventInfo c : page)
@@ -872,8 +890,8 @@ public class GHRepository extends GHObject {
*/
public PagedIterable<GHLabel> listLabels() throws IOException {
return new PagedIterable<GHLabel>() {
public PagedIterator<GHLabel> iterator() {
return new PagedIterator<GHLabel>(root.retrieve().asIterator(getApiTailUrl("labels"), GHLabel[].class)) {
public PagedIterator<GHLabel> _iterator(int pageSize) {
return new PagedIterator<GHLabel>(root.retrieve().asIterator(getApiTailUrl("labels"), GHLabel[].class, pageSize)) {
@Override
protected void wrapUp(GHLabel[] page) {
for (GHLabel c : page)
@@ -891,7 +909,7 @@ public class GHRepository extends GHObject {
public GHLabel createLabel(String name, String color) throws IOException {
return root.retrieve().method("POST")
.with("name",name)
.with("color",color)
.with("color", color)
.to(getApiTailUrl("labels"), GHLabel.class).wrapUp(this);
}
@@ -901,9 +919,20 @@ public class GHRepository extends GHObject {
* https://developer.github.com/v3/activity/watching/
*/
public PagedIterable<GHUser> listSubscribers() {
return listUsers("subscribers");
}
/**
* Lists all the users who have starred this repo.
*/
public PagedIterable<GHUser> listStargazers() {
return listUsers("stargazers");
}
private PagedIterable<GHUser> listUsers(final String suffix) {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> iterator() {
return new PagedIterator<GHUser>(root.retrieve().asIterator(getApiTailUrl("subscribers"), GHUser[].class)) {
public PagedIterator<GHUser> _iterator(int pageSize) {
return new PagedIterator<GHUser>(root.retrieve().asIterator(getApiTailUrl(suffix), GHUser[].class, pageSize)) {
protected void wrapUp(GHUser[] page) {
for (GHUser c : page)
c.wrapUp(root);
@@ -1054,8 +1083,8 @@ public class GHRepository extends GHObject {
*/
public PagedIterable<GHMilestone> listMilestones(final GHIssueState state) {
return new PagedIterable<GHMilestone>() {
public PagedIterator<GHMilestone> iterator() {
return new PagedIterator<GHMilestone>(root.retrieve().asIterator(getApiTailUrl("milestones?state="+state.toString().toLowerCase(Locale.ENGLISH)), GHMilestone[].class)) {
public PagedIterator<GHMilestone> _iterator(int pageSize) {
return new PagedIterator<GHMilestone>(root.retrieve().with("state",state).asIterator(getApiTailUrl("milestones"), GHMilestone[].class, pageSize)) {
@Override
protected void wrapUp(GHMilestone[] page) {
for (GHMilestone c : page)
@@ -1094,6 +1123,9 @@ public class GHRepository extends GHObject {
public List<GHContent> getDirectoryContent(String path, String ref) throws IOException {
Requester requester = root.retrieve();
while (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
String target = getApiTailUrl("contents/" + path);
GHContent[] files = requester.with("ref",ref).to(target, GHContent[].class);
@@ -1224,8 +1256,8 @@ public class GHRepository extends GHObject {
public PagedIterable<Contributor> listContributors() throws IOException {
return new PagedIterable<Contributor>() {
public PagedIterator<Contributor> iterator() {
return new PagedIterator<Contributor>(root.retrieve().asIterator(getApiTailUrl("contributors"), Contributor[].class)) {
public PagedIterator<Contributor> _iterator(int pageSize) {
return new PagedIterator<Contributor>(root.retrieve().asIterator(getApiTailUrl("contributors"), Contributor[].class, pageSize)) {
@Override
protected void wrapUp(Contributor[] page) {
for (Contributor c : page)

View File

@@ -58,7 +58,7 @@ public class GHRepositorySearchBuilder extends GHSearchBuilder<GHRepository> {
}
public GHRepositorySearchBuilder sort(Sort sort) {
req.with("sort",sort.toString().toLowerCase(Locale.ENGLISH));
req.with("sort",sort);
return this;
}

View File

@@ -10,9 +10,7 @@ import java.util.List;
*
* @author Kohsuke Kawaguchi
*/
public abstract class GHSearchBuilder<T> {
protected final GitHub root;
protected final Requester req;
public abstract class GHSearchBuilder<T> extends GHQueryBuilder<T> {
protected final List<String> terms = new ArrayList<String>();
/**
@@ -21,15 +19,14 @@ public abstract class GHSearchBuilder<T> {
private final Class<? extends SearchResult<T>> receiverType;
/*package*/ GHSearchBuilder(GitHub root, Class<? extends SearchResult<T>> receiverType) {
this.root = root;
this.req = root.retrieve();
super(root);
this.receiverType = receiverType;
}
/**
* Search terms.
*/
public GHSearchBuilder q(String term) {
public GHQueryBuilder<T> q(String term) {
terms.add(term);
return this;
}
@@ -37,11 +34,12 @@ public abstract class GHSearchBuilder<T> {
/**
* Performs the search.
*/
@Override
public PagedSearchIterable<T> list() {
return new PagedSearchIterable<T>(root) {
public PagedIterator<T> iterator() {
public PagedIterator<T> _iterator(int pageSize) {
req.set("q", StringUtils.join(terms, " "));
return new PagedIterator<T>(adapt(req.asIterator(getApiUrl(), receiverType))) {
return new PagedIterator<T>(adapt(req.asIterator(getApiUrl(), receiverType, pageSize))) {
protected void wrapUp(T[] page) {
// SearchResult.getItems() should do it
}

View File

@@ -52,8 +52,8 @@ public class GHTeam {
*/
public PagedIterable<GHUser> listMembers() throws IOException {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> iterator() {
return new PagedIterator<GHUser>(org.root.retrieve().asIterator(api("/members"), GHUser[].class)) {
public PagedIterator<GHUser> _iterator(int pageSize) {
return new PagedIterator<GHUser>(org.root.retrieve().asIterator(api("/members"), GHUser[].class, pageSize)) {
@Override
protected void wrapUp(GHUser[] page) {
GHUser.wrap(page, org.root);
@@ -89,8 +89,8 @@ public class GHTeam {
public PagedIterable<GHRepository> listRepositories() {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> iterator() {
return new PagedIterator<GHRepository>(org.root.retrieve().asIterator(api("/repos"), GHRepository[].class)) {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(org.root.retrieve().asIterator(api("/repos"), GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository r : page)

View File

@@ -26,7 +26,6 @@ package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@@ -56,8 +55,14 @@ public class GHUser extends GHPerson {
*/
@WithBridgeMethods(Set.class)
public GHPersonSet<GHUser> getFollows() throws IOException {
GHUser[] followers = root.retrieve().to("/users/" + login + "/following", GHUser[].class);
return new GHPersonSet<GHUser>(Arrays.asList(wrap(followers,root)));
return new GHPersonSet<GHUser>(listFollows().asList());
}
/**
* Lists the users that this user is following
*/
public PagedIterable<GHUser> listFollows() {
return listUser("following");
}
/**
@@ -65,8 +70,26 @@ public class GHUser extends GHPerson {
*/
@WithBridgeMethods(Set.class)
public GHPersonSet<GHUser> getFollowers() throws IOException {
GHUser[] followers = root.retrieve().to("/users/" + login + "/followers", GHUser[].class);
return new GHPersonSet<GHUser>(Arrays.asList(wrap(followers,root)));
return new GHPersonSet<GHUser>(listFollowers().asList());
}
/**
* Lists the users who are following this user.
*/
public PagedIterable<GHUser> listFollowers() {
return listUser("followers");
}
private PagedIterable<GHUser> listUser(final String suffix) {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> _iterator(int pageSize) {
return new PagedIterator<GHUser>(root.retrieve().asIterator(getApiTailUrl(suffix), GHUser[].class, pageSize)) {
protected void wrapUp(GHUser[] page) {
GHUser.wrap(page,root);
}
};
}
};
}
/**
@@ -75,9 +98,20 @@ public class GHUser extends GHPerson {
* https://developer.github.com/v3/activity/watching/
*/
public PagedIterable<GHRepository> listSubscriptions() {
return listRepositories("subscriptions");
}
/**
* Lists all the repositories that this user has starred.
*/
public PagedIterable<GHRepository> listStarredRepositories() {
return listRepositories("starred");
}
private PagedIterable<GHRepository> listRepositories(final String suffix) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> iterator() {
return new PagedIterator<GHRepository>(root.retrieve().asIterator(getApiTailUrl("subscriptions"), GHRepository[].class)) {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(root.retrieve().asIterator(getApiTailUrl(suffix), GHRepository[].class, pageSize)) {
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
c.wrap(root);
@@ -133,8 +167,8 @@ public class GHUser extends GHPerson {
*/
public PagedIterable<GHEventInfo> listEvents() throws IOException {
return new PagedIterable<GHEventInfo>() {
public PagedIterator<GHEventInfo> iterator() {
return new PagedIterator<GHEventInfo>(root.retrieve().asIterator(String.format("/users/%s/events", login), GHEventInfo[].class)) {
public PagedIterator<GHEventInfo> _iterator(int pageSize) {
return new PagedIterator<GHEventInfo>(root.retrieve().asIterator(String.format("/users/%s/events", login), GHEventInfo[].class, pageSize)) {
@Override
protected void wrapUp(GHEventInfo[] page) {
for (GHEventInfo c : page)
@@ -150,8 +184,8 @@ public class GHUser extends GHPerson {
*/
public PagedIterable<GHGist> listGists() throws IOException {
return new PagedIterable<GHGist>() {
public PagedIterator<GHGist> iterator() {
return new PagedIterator<GHGist>(root.retrieve().asIterator(String.format("/users/%s/gists", login), GHGist[].class)) {
public PagedIterator<GHGist> _iterator(int pageSize) {
return new PagedIterator<GHGist>(root.retrieve().asIterator(String.format("/users/%s/gists", login), GHGist[].class, pageSize)) {
@Override
protected void wrapUp(GHGist[] page) {
for (GHGist c : page)

View File

@@ -50,7 +50,7 @@ public class GHUserSearchBuilder extends GHSearchBuilder<GHUser> {
}
public GHUserSearchBuilder sort(Sort sort) {
req.with("sort",sort.toString().toLowerCase(Locale.ENGLISH));
req.with("sort",sort);
return this;
}

View File

@@ -47,6 +47,7 @@ import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.binary.Base64;
import com.fasterxml.jackson.databind.DeserializationFeature;
@@ -129,12 +130,7 @@ public class GitHub {
} else {
if (password!=null) {
String authorization = (login + ':' + password);
final Charset charset;
try {
charset = Charset.forName("UTF-8");
} catch (Exception ex) {
throw new IOException("UTF-8 encoding is not supported", ex);
}
Charset charset = Charsets.UTF_8;
encodedAuthorization = "Basic "+new String(Base64.encodeBase64(authorization.getBytes(charset)), charset);
} else {// anonymous access
encodedAuthorization = null;
@@ -204,6 +200,15 @@ public class GitHub {
return new GitHubBuilder().build();
}
/**
* Connects to GitHub Enterprise anonymously.
*
* All operations that requires authentication will fail.
*/
public static GitHub connectToEnterpriseAnonymously(String apiUrl) throws IOException {
return new GitHubBuilder().withEndpoint(apiUrl).build();
}
/**
* Is this an anonymous connection
* @return {@code true} if operations that require authentication will fail.
@@ -405,17 +410,28 @@ public class GitHub {
/**
* Creates a new repository.
*
* To create a repository in an organization, see
* {@link GHOrganization#createRepository(String, String, String, GHTeam, boolean)}
*
* @return
* Newly created repository.
* @deprecated
* Use {@link #createRepository(String)} that uses a builder pattern to let you control every aspect.
*/
public GHRepository createRepository(String name, String description, String homepage, boolean isPublic) throws IOException {
Requester requester = new Requester(this)
.with("name", name).with("description", description).with("homepage", homepage)
.with("public", isPublic ? 1 : 0);
return requester.method("POST").to("/user/repos", GHRepository.class).wrap(this);
return createRepository(name).description(description).homepage(homepage).private_(!isPublic).create();
}
/**
* Starts a builder that creates a new repository.
*
* <p>
* You use the returned builder to set various properties, then call {@link GHCreateRepositoryBuilder#create()}
* to finally createa repository.
*
* <p>
* To create a repository in an organization, see
* {@link GHOrganization#createRepository(String, String, String, GHTeam, boolean)}
*/
public GHCreateRepositoryBuilder createRepository(String name) {
return new GHCreateRepositoryBuilder(this,"/user/repos",name);
}
/**
@@ -446,6 +462,29 @@ public class GitHub {
}
}
private static class GHApiInfo {
private String rate_limit_url;
void check(String apiUrl) throws IOException {
if (rate_limit_url==null)
throw new IOException(apiUrl+" doesn't look like GitHub API URL");
// make sure that the URL is legitimate
new URL(rate_limit_url);
}
}
/**
* Ensures that the API URL is valid.
*
* <p>
* This method returns normally if the endpoint is reachable and verified to be GitHub API URL.
* Otherwise this method throws {@link IOException} to indicate the problem.
*/
public void checkApiUrlValidity() throws IOException {
retrieve().to("/", GHApiInfo.class).check(apiUrl);
}
/**
* Search issues.
*/
@@ -498,8 +537,8 @@ public class GitHub {
*/
public PagedIterable<GHRepository> listAllPublicRepositories(final String since) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> iterator() {
return new PagedIterator<GHRepository>(retrieve().with("since",since).asIterator("/repositories", GHRepository[].class)) {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(retrieve().with("since",since).asIterator("/repositories", GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)

View File

@@ -1,6 +1,7 @@
package org.kohsuke.github;
import org.apache.commons.io.IOUtils;
import org.kohsuke.github.extras.ImpatientHttpConnector;
import java.io.File;
import java.io.FileInputStream;
@@ -51,7 +52,7 @@ public class GitHubBuilder {
try {
builder = fromPropertyFile();
if (builder.user != null)
if (builder.oauthToken != null || builder.user != null)
return builder;
} catch (FileNotFoundException e) {
// fall through
@@ -60,7 +61,7 @@ public class GitHubBuilder {
builder = fromEnvironment();
if (builder.user != null)
if (builder.oauthToken != null || builder.user != null)
return builder;
else
throw (IOException)new IOException("Failed to resolve credentials from ~/.github or the environment.").initCause(cause);
@@ -184,11 +185,11 @@ public class GitHubBuilder {
* the system default one.
*/
public GitHubBuilder withProxy(final Proxy p) {
return withConnector(new HttpConnector() {
return withConnector(new ImpatientHttpConnector(new HttpConnector() {
public HttpURLConnection connect(URL url) throws IOException {
return (HttpURLConnection) url.openConnection(p);
}
});
}));
}
public GitHub build() throws IOException {

View File

@@ -1,8 +1,11 @@
package org.kohsuke.github;
import org.kohsuke.github.extras.ImpatientHttpConnector;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.TimeUnit;
/**
* Pluggability for customizing HTTP request behaviors or using altogether different library.
@@ -21,9 +24,9 @@ public interface HttpConnector {
/**
* Default implementation that uses {@link URL#openConnection()}.
*/
HttpConnector DEFAULT = new HttpConnector() {
HttpConnector DEFAULT = new ImpatientHttpConnector(new HttpConnector() {
public HttpURLConnection connect(URL url) throws IOException {
return (HttpURLConnection) url.openConnection();
}
};
});
}

View File

@@ -1,5 +1,6 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
@@ -11,7 +12,27 @@ import java.util.Set;
* @author Kohsuke Kawaguchi
*/
public abstract class PagedIterable<T> implements Iterable<T> {
public abstract PagedIterator<T> iterator();
/**
* Page size. 0 is default.
*/
private int size = 0;
/**
* Sets the pagination size.
*
* <p>
* When set to non-zero, each API call will retrieve this many entries.
*/
public PagedIterable<T> withPageSize(int size) {
this.size = size;
return this;
}
public final PagedIterator<T> iterator() {
return _iterator(size);
}
public abstract PagedIterator<T> _iterator(int pageSize);
/**
* Eagerly walk {@link Iterable} and return the result in a list.

View File

@@ -1,6 +1,8 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.util.Iterator;
/**
@@ -22,6 +24,11 @@ public abstract class PagedSearchIterable<T> extends PagedIterable<T> {
this.root = root;
}
@Override
public PagedSearchIterable<T> withPageSize(int size) {
return (PagedSearchIterable<T>)super.withPageSize(size);
}
/**
* Returns the total number of hit, including the results that's not yet fetched.
*/

View File

@@ -42,17 +42,18 @@ import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import javax.annotation.WillClose;
import static java.util.Arrays.asList;
import static org.kohsuke.github.GitHub.*;
@@ -130,6 +131,14 @@ class Requester {
return _with(key, value);
}
public Requester with(String key, Enum e) {
if (e==null) return _with(key, null);
// by convention Java constant names are upper cases, but github uses
// lower-case constants. GitHub also uses '-', which in Java we always
// replace by '_'
return with(key, e.toString().toLowerCase(Locale.ENGLISH).replace('_','-'));
}
public Requester with(String key, String value) {
return _with(key, value);
@@ -143,7 +152,7 @@ class Requester {
return _with(key, value);
}
public Requester with(InputStream body) {
public Requester with(@WillClose/*later*/ InputStream body) {
this.body = body;
return this;
}
@@ -257,6 +266,8 @@ class Requester {
while (true) {// loop while API rate limit is hit
setupConnection(root.getApiURL(tailApiUrl));
uc.setRequestMethod("GET");
buildRequest();
try {
@@ -271,8 +282,11 @@ class Requester {
while (true) {// loop while API rate limit is hit
setupConnection(root.getApiURL(tailApiUrl));
buildRequest();
// if the download link is encoded with a token on the query string, the default behavior of POST will fail
uc.setRequestMethod("GET");
buildRequest();
try {
return wrapStream(uc.getInputStream());
} catch (IOException e) {
@@ -323,104 +337,112 @@ class Requester {
*
* Every iterator call reports a new batch.
*/
/*package*/ <T> Iterator<T> asIterator(final String _tailApiUrl, final Class<T> type) {
/*package*/ <T> Iterator<T> asIterator(String tailApiUrl, Class<T> type, int pageSize) {
method("GET");
final StringBuilder strBuilder = new StringBuilder(_tailApiUrl);
if (pageSize!=0)
args.add(new Entry("per_page",pageSize));
StringBuilder s = new StringBuilder(tailApiUrl);
if (!args.isEmpty()) {
boolean first=true;
boolean first = true;
try {
for (Entry a : args) {
strBuilder.append(first ? '?' : '&');
s.append(first ? '?' : '&');
first = false;
strBuilder.append(URLEncoder.encode(a.key, "UTF-8"));
strBuilder.append('=');
strBuilder.append(URLEncoder.encode(a.value.toString(), "UTF-8"));
s.append(URLEncoder.encode(a.key, "UTF-8"));
s.append('=');
s.append(URLEncoder.encode(a.value.toString(), "UTF-8"));
}
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e); // UTF-8 is mandatory
}
}
final String tailApiUrl = strBuilder.toString();
try {
return new PagingIterator<T>(type, root.getApiURL(s.toString()));
} catch (IOException e) {
throw new Error(e);
}
}
return new Iterator<T>() {
/**
* The next batch to be returned from {@link #next()}.
*/
T next;
/**
* URL of the next resource to be retrieved, or null if no more data is available.
*/
URL url;
class PagingIterator<T> implements Iterator<T> {
{
try {
url = root.getApiURL(tailApiUrl);
} catch (IOException e) {
throw new Error(e);
}
}
private final Class<T> type;
public boolean hasNext() {
fetch();
return next!=null;
}
/**
* The next batch to be returned from {@link #next()}.
*/
private T next;
public T next() {
fetch();
T r = next;
if (r==null) throw new NoSuchElementException();
next = null;
return r;
}
/**
* URL of the next resource to be retrieved, or null if no more data is available.
*/
private URL url;
public void remove() {
throw new UnsupportedOperationException();
}
PagingIterator(Class<T> type, URL url) {
this.url = url;
this.type = type;
}
private void fetch() {
if (next!=null) return; // already fetched
if (url==null) return; // no more data to fetch
public boolean hasNext() {
fetch();
return next!=null;
}
try {
while (true) {// loop while API rate limit is hit
setupConnection(url);
try {
next = parse(type,null);
assert next!=null;
findNextURL();
return;
} catch (IOException e) {
handleApiError(e);
}
}
} catch (IOException e) {
throw new Error(e);
}
}
public T next() {
fetch();
T r = next;
if (r==null) throw new NoSuchElementException();
next = null;
return r;
}
/**
* Locate the next page from the pagination "Link" tag.
*/
private void findNextURL() throws MalformedURLException {
url = null; // start defensively
String link = uc.getHeaderField("Link");
if (link==null) return;
public void remove() {
throw new UnsupportedOperationException();
}
for (String token : link.split(", ")) {
if (token.endsWith("rel=\"next\"")) {
// found the next page. This should look something like
// <https://api.github.com/repos?page=3&per_page=100>; rel="next"
int idx = token.indexOf('>');
url = new URL(token.substring(1,idx));
private void fetch() {
if (next!=null) return; // already fetched
if (url==null) return; // no more data to fetch
try {
while (true) {// loop while API rate limit is hit
setupConnection(url);
try {
next = parse(type,null);
assert next!=null;
findNextURL();
return;
} catch (IOException e) {
handleApiError(e);
}
}
// no more "next" link. we are done.
} catch (IOException e) {
throw new Error(e);
}
};
}
/**
* Locate the next page from the pagination "Link" tag.
*/
private void findNextURL() throws MalformedURLException {
url = null; // start defensively
String link = uc.getHeaderField("Link");
if (link==null) return;
for (String token : link.split(", ")) {
if (token.endsWith("rel=\"next\"")) {
// found the next page. This should look something like
// <https://api.github.com/repos?page=3&per_page=100>; rel="next"
int idx = token.indexOf('>');
url = new URL(token.substring(1,idx));
return;
}
}
// no more "next" link. we are done.
}
}
@@ -494,6 +516,7 @@ class Requester {
if ("0".equals(uc.getHeaderField("X-RateLimit-Remaining"))) {
root.rateLimitHandler.onError(e,uc);
return;
}
InputStream es = wrapStream(uc.getErrorStream());

View File

@@ -7,7 +7,6 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
*
* @author Kohsuke Kawaguchi
*/
abstract class SearchResult<T> {
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Field comes from JSON deserialization")
int total_count;

View File

@@ -0,0 +1,58 @@
package org.kohsuke.github.extras;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.kohsuke.github.HttpConnector;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.TimeUnit;
/**
* {@link HttpConnector} wrapper that sets timeout
*
* @author Kohsuke Kawaguchi
*/
public class ImpatientHttpConnector implements HttpConnector {
private final HttpConnector base;
private final int readTimeout, connectTimeout;
/**
* @param connectTimeout
* HTTP connection timeout in milliseconds
* @param readTimeout
* HTTP read timeout in milliseconds
*/
public ImpatientHttpConnector(HttpConnector base, int connectTimeout, int readTimeout) {
this.base = base;
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
}
public ImpatientHttpConnector(HttpConnector base, int timeout) {
this(base,timeout,timeout);
}
public ImpatientHttpConnector(HttpConnector base) {
this(base,CONNECT_TIMEOUT,READ_TIMEOUT);
}
public HttpURLConnection connect(URL url) throws IOException {
HttpURLConnection con = base.connect(url);
con.setConnectTimeout(connectTimeout);
con.setReadTimeout(readTimeout);
return con;
}
/**
* Default connection timeout in milliseconds
*/
@SuppressFBWarnings("MS_SHOULD_BE_FINAL")
public static int CONNECT_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(10);
/**
* Default read timeout in milliseconds
*/
@SuppressFBWarnings("MS_SHOULD_BE_FINAL")
public static int READ_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(10);
}

View File

@@ -1,4 +1,5 @@
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GHUser;
import org.kohsuke.github.GitHub;
import java.util.Collection;
@@ -14,4 +15,11 @@ public class Foo {
}
System.out.println(lst.size());
}
private static void testRateLimit() throws Exception {
GitHub g = GitHub.connectAnonymously();
for (GHUser u : g.getOrganization("jenkinsci").listMembers()) {
u.getFollowersCount();
}
}
}

View File

@@ -38,6 +38,21 @@ public class AppTest extends AbstractGitHubApiTestBase {
getUser().getRepository(targetName).delete();
}
@Test
public void testRepositoryWithAutoInitializationCRUD() throws IOException {
String name = "github-api-test-autoinit";
deleteRepository(name);
GHRepository r = gitHub.createRepository(name)
.description("a test repository for auto init")
.homepage("http://github-api.kohsuke.org/")
.autoInit(true).create();
r.enableIssueTracker(false);
r.enableDownloads(false);
r.enableWiki(false);
assertNotNull(r.getReadme());
getUser().getRepository(name).delete();
}
private void deleteRepository(final String name) throws IOException {
GHRepository repository = getUser().getRepository(name);
if(repository != null) {
@@ -286,7 +301,8 @@ public class AppTest extends AbstractGitHubApiTestBase {
@Test
public void testGetTeamsForRepo() throws Exception {
kohsuke();
assertEquals(1, gitHub.getOrganization("github-api-test-org").getRepository("testGetTeamsForRepo").getTeams().size());
// 'Core Developers' and 'Owners'
assertEquals(2, gitHub.getOrganization("github-api-test-org").getRepository("testGetTeamsForRepo").getTeams().size());
}
@Test
@@ -325,6 +341,8 @@ public class AppTest extends AbstractGitHubApiTestBase {
System.out.println(commit);
assertEquals(1, commit.getParents().size());
assertEquals(1,commit.getFiles().size());
assertEquals("https://github.com/jenkinsci/jenkins/commit/08c1c9970af4d609ae754fbe803e06186e3206f7",
commit.getHtmlUrl().toString());
File f = commit.getFiles().get(0);
assertEquals(48,f.getLinesChanged());
@@ -773,7 +791,7 @@ public class AppTest extends AbstractGitHubApiTestBase {
assertTrue(actual.contains("href=\"https://github.com/kohsuke\""));
assertTrue(actual.contains("href=\"https://github.com/kohsuke/github-api/pull/1\""));
assertTrue(actual.contains("class=\"user-mention\""));
assertTrue(actual.contains("class=\"issue-link\""));
assertTrue(actual.contains("class=\"issue-link "));
assertTrue(actual.contains("to fix issue"));
}

View File

@@ -1,5 +1,7 @@
package org.kohsuke.github;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import org.junit.Test;
import java.io.IOException;
@@ -13,4 +15,14 @@ public class CommitTest extends AbstractGitHubApiTestBase {
GHTag t = gitHub.getRepository("stapler/stapler").listTags().iterator().next();
t.getCommit().getLastStatus();
}
@Test // issue 230
public void listFiles() throws Exception {
GHRepository repo = gitHub.getRepository("stapler/stapler");
PagedIterable<GHCommit> commits = repo.queryCommits().path("pom.xml").list();
for (GHCommit commit : Iterables.limit(commits, 10)) {
GHCommit expected = repo.getCommit( commit.getSHA1() );
assertEquals(expected.getFiles().size(), commit.getFiles().size());
}
}
}

View File

@@ -43,6 +43,14 @@ public class GHContentIntegrationTest extends AbstractGitHubApiTestBase {
assertTrue(entries.size() == 3);
}
@Test
public void testGetDirectoryContentTrailingSlash() throws Exception {
//Used to truncate the ?ref=master, see gh-224 https://github.com/kohsuke/github-api/pull/224
List<GHContent> entries = repo.getDirectoryContent("ghcontent-ro/a-dir-with-3-entries/", "master");
assertTrue(entries.get(0).getUrl().endsWith("?ref=master"));
}
@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);

View File

@@ -0,0 +1,43 @@
package org.kohsuke.github;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException;
public class GHOrganizationTest extends AbstractGitHubApiTestBase {
public static final String GITHUB_API_TEST = "github-api-test";
private GHOrganization org;
@Override
public void setUp() throws Exception {
super.setUp();
org = gitHub.getOrganization("github-api-test-org");
}
@Test
public void testCreateRepository() throws IOException {
GHRepository repository = org.createRepository(GITHUB_API_TEST,
"a test repository used to test kohsuke's github-api", "http://github-api.kohsuke.org/", "Core Developers", true);
Assert.assertNotNull(repository);
}
@Test
public void testCreateRepositoryWithAutoInitialization() throws IOException {
GHRepository repository = org.createRepository(GITHUB_API_TEST)
.description("a test repository used to test kohsuke's github-api")
.homepage("http://github-api.kohsuke.org/")
.team(org.getTeamByName("Core Developers"))
.autoInit(true).create();
Assert.assertNotNull(repository);
Assert.assertNotNull(repository.getReadme());
}
@After
public void cleanUp() throws Exception {
GHRepository repository = org.getRepository(GITHUB_API_TEST);
repository.delete();
}
}

View File

@@ -12,6 +12,7 @@ import org.junit.Test;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -119,4 +120,10 @@ public class GitHubTest {
GHRateLimit rateLimit = github.getRateLimit();
assertThat(rateLimit.getResetDate(), notNullValue());
}
@Test
public void testGitHubIsApiUrlValid() throws IOException {
GitHub github = GitHub.connectAnonymously();
github.checkApiUrlValidity();
}
}

View File

@@ -49,6 +49,26 @@ public class PullRequestTest extends AbstractGitHubApiTestBase {
assertTrue(comments.isEmpty());
}
@Test
public void testMergeCommitSHA() throws Exception {
String name = rnd.next();
GHPullRequest p = getRepository().createPullRequest(name, "mergeable-branch", "master", "## test");
for (int i=0; i<100; i++) {
GHPullRequest updated = getRepository().getPullRequest(p.getNumber());
if (updated.getMergeCommitSha()!=null) {
// make sure commit exists
GHCommit commit = getRepository().getCommit(updated.getMergeCommitSha());
assertNotNull(commit);
return;
}
// mergeability computation takes time. give it more chance
Thread.sleep(100);
}
// hmm?
fail();
}
@Test
// Requires push access to the test repo to pass
public void setLabels() throws Exception {

View File

@@ -48,7 +48,7 @@ public class RepositoryMockTest {
when(requester.asIterator("/repos/*/*/collaborators",
GHUser[].class)).thenReturn(iterator, iterator);
GHUser[].class, 0)).thenReturn(iterator, iterator);
PagedIterable<GHUser> pagedIterable = Mockito.mock(PagedIterable.class);

View File

@@ -0,0 +1,30 @@
package org.kohsuke.github;
import org.junit.Test;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
/**
* @author Kohsuke Kawaguchi
*/
public class UserTest extends AbstractGitHubApiTestBase {
@Test
public void listFollowsAndFollowers() throws IOException {
GHUser u = gitHub.getUser("rtyler");
assertNotEquals(
count50(u.listFollowers()),
count50(u.listFollows()));
}
private Set<GHUser> count50(PagedIterable<GHUser> l) {
Set<GHUser> users = new HashSet<GHUser>();
PagedIterator<GHUser> itr = l.iterator();
for (int i=0; i<50 && itr.hasNext(); i++) {
users.add(itr.next());
}
assertEquals(50, users.size());
return users;
}
}