mirror of
https://github.com/jlengrand/github-api.git
synced 2026-03-20 15:50:29 +00:00
Compare commits
47 Commits
github-api
...
github-api
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
715192d26c | ||
|
|
d30b0403ce | ||
|
|
255c993548 | ||
|
|
557ae4165c | ||
|
|
a31395ed80 | ||
|
|
397886d289 | ||
|
|
7307bec2ae | ||
|
|
0cd5147e1a | ||
|
|
36d5b092d7 | ||
|
|
f9014dbab3 | ||
|
|
755d5f77ea | ||
|
|
906d9af7b7 | ||
|
|
14dcb37ee1 | ||
|
|
c1c2a27358 | ||
|
|
5ab9657f9c | ||
|
|
7a78f9f5aa | ||
|
|
ac8c65f062 | ||
|
|
1954a9f3f8 | ||
|
|
3b764f9c90 | ||
|
|
10f55cc549 | ||
|
|
cd8d955646 | ||
|
|
bba07c9080 | ||
|
|
dba84a33b9 | ||
|
|
ae49166aa2 | ||
|
|
e09185fd0e | ||
|
|
56379bb3b9 | ||
|
|
027e4b4f25 | ||
|
|
ba951cb6e3 | ||
|
|
ae85cf4b6c | ||
|
|
dbc79f8c42 | ||
|
|
54c3070607 | ||
|
|
013eaa30b6 | ||
|
|
751043bf81 | ||
|
|
14f7198a07 | ||
|
|
94af819ae5 | ||
|
|
dbcc9afbc7 | ||
|
|
8556033ae6 | ||
|
|
650493f863 | ||
|
|
d80ad77871 | ||
|
|
f4b129b9f1 | ||
|
|
c0a05e0650 | ||
|
|
33d95d3e3a | ||
|
|
f573f83fb9 | ||
|
|
e94c36b7e6 | ||
|
|
c879e9e34d | ||
|
|
ac39b564a8 | ||
|
|
d91388aba4 |
25
pom.xml
25
pom.xml
@@ -7,7 +7,7 @@
|
|||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>github-api</artifactId>
|
<artifactId>github-api</artifactId>
|
||||||
<version>1.72</version>
|
<version>1.75</version>
|
||||||
<name>GitHub API for Java</name>
|
<name>GitHub API for Java</name>
|
||||||
<url>http://github-api.kohsuke.org/</url>
|
<url>http://github-api.kohsuke.org/</url>
|
||||||
<description>GitHub API for Java</description>
|
<description>GitHub API for Java</description>
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
<connection>scm:git:git@github.com/kohsuke/${project.artifactId}.git</connection>
|
<connection>scm:git:git@github.com/kohsuke/${project.artifactId}.git</connection>
|
||||||
<developerConnection>scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git</developerConnection>
|
<developerConnection>scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git</developerConnection>
|
||||||
<url>http://${project.artifactId}.kohsuke.org/</url>
|
<url>http://${project.artifactId}.kohsuke.org/</url>
|
||||||
<tag>github-api-1.72</tag>
|
<tag>github-api-1.75</tag>
|
||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
<distributionManagement>
|
<distributionManagement>
|
||||||
@@ -34,6 +34,27 @@
|
|||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>animal-sniffer-maven-plugin</artifactId>
|
||||||
|
<version>1.15</version>
|
||||||
|
<configuration>
|
||||||
|
<signature>
|
||||||
|
<groupId>org.codehaus.mojo.signature</groupId>
|
||||||
|
<artifactId>java15</artifactId>
|
||||||
|
<version>1.0</version>
|
||||||
|
</signature>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>ensure-java-1.5-class-library</id>
|
||||||
|
<phase>test</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>check</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>com.infradna.tool</groupId>
|
<groupId>com.infradna.tool</groupId>
|
||||||
<artifactId>bridge-method-injector</artifactId>
|
<artifactId>bridge-method-injector</artifactId>
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ public class GHCommit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "modified", "added", or "deleted"
|
* "modified", "added", or "removed"
|
||||||
*/
|
*/
|
||||||
public String getStatus() {
|
public String getStatus() {
|
||||||
return status;
|
return status;
|
||||||
@@ -171,14 +171,15 @@ public class GHCommit {
|
|||||||
String login;
|
String login;
|
||||||
}
|
}
|
||||||
|
|
||||||
String url,sha;
|
String url,html_url,sha;
|
||||||
List<File> files;
|
List<File> files;
|
||||||
Stats stats;
|
Stats stats;
|
||||||
List<Parent> parents;
|
List<Parent> parents;
|
||||||
User author,committer;
|
User author,committer;
|
||||||
|
|
||||||
|
|
||||||
public ShortInfo getCommitShortInfo() {
|
public ShortInfo getCommitShortInfo() throws IOException {
|
||||||
|
populate();
|
||||||
return commit;
|
return commit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,6 +214,13 @@ public class GHCommit {
|
|||||||
return stats.deletions;
|
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.
|
* [0-9a-f]{40} SHA1 checksum.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
|||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The model user for comparing 2 commits in the GitHub API.
|
* The model user for comparing 2 commits in the GitHub API.
|
||||||
@@ -72,7 +70,9 @@ public class GHCompare {
|
|||||||
* @return A copy of the array being stored in the class.
|
* @return A copy of the array being stored in the class.
|
||||||
*/
|
*/
|
||||||
public Commit[] getCommits() {
|
public Commit[] getCommits() {
|
||||||
return Arrays.copyOf(commits, commits.length);
|
Commit[] newValue = new Commit[commits.length];
|
||||||
|
System.arraycopy(commits, 0, newValue, 0, commits.length);
|
||||||
|
return newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,7 +80,9 @@ public class GHCompare {
|
|||||||
* @return A copy of the array being stored in the class.
|
* @return A copy of the array being stored in the class.
|
||||||
*/
|
*/
|
||||||
public GHCommit.File[] getFiles() {
|
public GHCommit.File[] getFiles() {
|
||||||
return Arrays.copyOf(files, files.length);
|
GHCommit.File[] newValue = new GHCommit.File[files.length];
|
||||||
|
System.arraycopy(files, 0, newValue, 0, files.length);
|
||||||
|
return newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GHCompare wrap(GHRepository owner) {
|
public GHCompare wrap(GHRepository owner) {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ public class GHContent {
|
|||||||
*/
|
*/
|
||||||
@SuppressFBWarnings("DM_DEFAULT_ENCODING")
|
@SuppressFBWarnings("DM_DEFAULT_ENCODING")
|
||||||
public String getContent() throws IOException {
|
public String getContent() throws IOException {
|
||||||
return new String(DatatypeConverter.parseBase64Binary(getEncodedContent()));
|
return new String(Base64.decodeBase64(getEncodedContent()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,7 +115,8 @@ public class GHContent {
|
|||||||
* Retrieves the actual content stored here.
|
* Retrieves the actual content stored here.
|
||||||
*/
|
*/
|
||||||
public InputStream read() throws IOException {
|
public InputStream read() throws IOException {
|
||||||
return new Requester(root).asStream(getDownloadUrl());
|
// if the download link is encoded with a token on the query string, the default behavior of POST will fail
|
||||||
|
return new Requester(root).method("GET").asStream(getDownloadUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -178,7 +179,7 @@ public class GHContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public GHContentUpdateResponse update(byte[] newContentBytes, String commitMessage, String branch) throws IOException {
|
public GHContentUpdateResponse update(byte[] newContentBytes, String commitMessage, String branch) throws IOException {
|
||||||
String encodedContent = DatatypeConverter.printBase64Binary(newContentBytes);
|
String encodedContent = Base64.encodeBase64String(newContentBytes);
|
||||||
|
|
||||||
Requester requester = new Requester(root)
|
Requester requester = new Requester(root)
|
||||||
.with("path", path)
|
.with("path", path)
|
||||||
|
|||||||
114
src/main/java/org/kohsuke/github/GHCreateRepositoryBuilder.java
Normal file
114
src/main/java/org/kohsuke/github/GHCreateRepositoryBuilder.java
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook event type.
|
* Hook event type.
|
||||||
*
|
*
|
||||||
@@ -33,5 +35,18 @@ public enum GHEvent {
|
|||||||
STATUS,
|
STATUS,
|
||||||
TEAM_ADD,
|
TEAM_ADD,
|
||||||
WATCH,
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,8 +26,10 @@ public abstract class GHHook extends GHObject {
|
|||||||
|
|
||||||
public EnumSet<GHEvent> getEvents() {
|
public EnumSet<GHEvent> getEvents() {
|
||||||
EnumSet<GHEvent> s = EnumSet.noneOf(GHEvent.class);
|
EnumSet<GHEvent> s = EnumSet.noneOf(GHEvent.class);
|
||||||
for (String e : events)
|
for (String e : events) {
|
||||||
s.add(Enum.valueOf(GHEvent.class,e.toUpperCase(Locale.ENGLISH)));
|
if (e.equals("*")) s.add(GHEvent.ALL);
|
||||||
|
else s.add(Enum.valueOf(GHEvent.class, e.toUpperCase(Locale.ENGLISH)));
|
||||||
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class GHHooks {
|
|||||||
if (events!=null) {
|
if (events!=null) {
|
||||||
ea = new ArrayList<String>();
|
ea = new ArrayList<String>();
|
||||||
for (GHEvent e : events)
|
for (GHEvent e : events)
|
||||||
ea.add(e.name().toLowerCase(Locale.ENGLISH));
|
ea.add(e.symbol());
|
||||||
}
|
}
|
||||||
|
|
||||||
GHHook hook = new Requester(root)
|
GHHook hook = new Requester(root)
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import java.util.Arrays;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
@@ -24,6 +23,8 @@ public class GHOrganization extends GHPerson {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* Newly created repository.
|
* 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 {
|
public GHRepository createRepository(String name, String description, String homepage, String team, boolean isPublic) throws IOException {
|
||||||
GHTeam t = getTeams().get(team);
|
GHTeam t = getTeams().get(team);
|
||||||
@@ -32,13 +33,25 @@ public class GHOrganization extends GHPerson {
|
|||||||
return createRepository(name, description, homepage, t, isPublic);
|
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 {
|
public GHRepository createRepository(String name, String description, String homepage, GHTeam team, boolean isPublic) throws IOException {
|
||||||
if (team==null)
|
if (team==null)
|
||||||
throw new IllegalArgumentException("Invalid team");
|
throw new IllegalArgumentException("Invalid team");
|
||||||
// such API doesn't exist, so fall back to HTML scraping
|
return createRepository(name).description(description).homepage(homepage).private_(!isPublic).team(team).create();
|
||||||
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);
|
/**
|
||||||
|
* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -185,7 +198,7 @@ public class GHOrganization extends GHPerson {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public GHTeam createTeam(String name, Permission p, GHRepository... repositories) throws IOException {
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
|||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commit detail inside a {@link GHPullRequest}.
|
* Commit detail inside a {@link GHPullRequest}.
|
||||||
@@ -144,6 +143,8 @@ public class GHPullRequestCommitDetail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public CommitPointer[] getParents() {
|
public CommitPointer[] getParents() {
|
||||||
return Arrays.copyOf(parents, parents.length);
|
CommitPointer[] newValue = new CommitPointer[parents.length];
|
||||||
|
System.arraycopy(parents, 0, newValue, 0, parents.length);
|
||||||
|
return newValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ package org.kohsuke.github;
|
|||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
|
||||||
import javax.xml.bind.DatatypeConverter;
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
@@ -36,7 +36,19 @@ import java.io.InterruptedIOException;
|
|||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.*;
|
import java.util.AbstractSet;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
|
|
||||||
@@ -475,7 +487,7 @@ public class GHRepository extends GHObject {
|
|||||||
public void setEmailServiceHook(String address) throws IOException {
|
public void setEmailServiceHook(String address) throws IOException {
|
||||||
Map<String, String> config = new HashMap<String, String>();
|
Map<String, String> config = new HashMap<String, String>();
|
||||||
config.put("address", address);
|
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"));
|
.to(getApiTailUrl("hooks"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1152,7 +1164,7 @@ public class GHRepository extends GHObject {
|
|||||||
try {
|
try {
|
||||||
payload = content.getBytes("UTF-8");
|
payload = content.getBytes("UTF-8");
|
||||||
} catch (UnsupportedEncodingException ex) {
|
} catch (UnsupportedEncodingException ex) {
|
||||||
throw new IOException("UTF-8 encoding is not supported", ex);
|
throw (IOException) new IOException("UTF-8 encoding is not supported").initCause(ex);
|
||||||
}
|
}
|
||||||
return createContent(payload, commitMessage, path, branch);
|
return createContent(payload, commitMessage, path, branch);
|
||||||
}
|
}
|
||||||
@@ -1165,7 +1177,7 @@ public class GHRepository extends GHObject {
|
|||||||
Requester requester = new Requester(root)
|
Requester requester = new Requester(root)
|
||||||
.with("path", path)
|
.with("path", path)
|
||||||
.with("message", commitMessage)
|
.with("message", commitMessage)
|
||||||
.with("content", DatatypeConverter.printBase64Binary(contentBytes))
|
.with("content", Base64.encodeBase64String(contentBytes))
|
||||||
.method("PUT");
|
.method("PUT");
|
||||||
|
|
||||||
if (branch != null) {
|
if (branch != null) {
|
||||||
|
|||||||
@@ -25,12 +25,15 @@ package org.kohsuke.github;
|
|||||||
|
|
||||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
|
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
|
||||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
|
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
|
||||||
|
import static java.util.logging.Level.FINE;
|
||||||
|
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
@@ -45,7 +48,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import org.apache.commons.codec.Charsets;
|
import org.apache.commons.codec.Charsets;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
@@ -54,7 +56,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std;
|
import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std;
|
||||||
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||||
import java.nio.charset.Charset;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Root of the GitHub API.
|
* Root of the GitHub API.
|
||||||
@@ -130,8 +132,8 @@ public class GitHub {
|
|||||||
} else {
|
} else {
|
||||||
if (password!=null) {
|
if (password!=null) {
|
||||||
String authorization = (login + ':' + password);
|
String authorization = (login + ':' + password);
|
||||||
Charset charset = Charsets.UTF_8;
|
String charsetName = Charsets.UTF_8.name();
|
||||||
encodedAuthorization = "Basic "+new String(Base64.encodeBase64(authorization.getBytes(charset)), charset);
|
encodedAuthorization = "Basic "+new String(Base64.encodeBase64(authorization.getBytes(charsetName)), charsetName);
|
||||||
} else {// anonymous access
|
} else {// anonymous access
|
||||||
encodedAuthorization = null;
|
encodedAuthorization = null;
|
||||||
}
|
}
|
||||||
@@ -261,7 +263,8 @@ public class GitHub {
|
|||||||
// see issue #78
|
// see issue #78
|
||||||
GHRateLimit r = new GHRateLimit();
|
GHRateLimit r = new GHRateLimit();
|
||||||
r.limit = r.remaining = 1000000;
|
r.limit = r.remaining = 1000000;
|
||||||
r.reset = new Date(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(1));
|
long hours = 1000L * 60 * 60;
|
||||||
|
r.reset = new Date(System.currentTimeMillis() + 1 * hours );
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -410,17 +413,28 @@ public class GitHub {
|
|||||||
/**
|
/**
|
||||||
* Creates a new repository.
|
* Creates a new repository.
|
||||||
*
|
*
|
||||||
* To create a repository in an organization, see
|
|
||||||
* {@link GHOrganization#createRepository(String, String, String, GHTeam, boolean)}
|
|
||||||
*
|
|
||||||
* @return
|
* @return
|
||||||
* Newly created repository.
|
* 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 {
|
public GHRepository createRepository(String name, String description, String homepage, boolean isPublic) throws IOException {
|
||||||
Requester requester = new Requester(this)
|
return createRepository(name).description(description).homepage(homepage).private_(!isPublic).create();
|
||||||
.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);
|
/**
|
||||||
|
* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -447,6 +461,8 @@ public class GitHub {
|
|||||||
retrieve().to("/user", GHUser.class);
|
retrieve().to("/user", GHUser.class);
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
if (LOGGER.isLoggable(FINE))
|
||||||
|
LOGGER.log(FINE, "Exception validating credentials on " + this.apiUrl + " with login '" + this.login + "' " + e, e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -464,14 +480,59 @@ public class GitHub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that the API URL is valid.
|
* Tests the connection.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Verify that the API URL and credentials are valid to access this GitHub.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* This method returns normally if the endpoint is reachable and verified to be GitHub API URL.
|
* 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.
|
* Otherwise this method throws {@link IOException} to indicate the problem.
|
||||||
*/
|
*/
|
||||||
public void checkApiUrlValidity() throws IOException {
|
public void checkApiUrlValidity() throws IOException {
|
||||||
|
try {
|
||||||
retrieve().to("/", GHApiInfo.class).check(apiUrl);
|
retrieve().to("/", GHApiInfo.class).check(apiUrl);
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (isPrivateModeEnabled()) {
|
||||||
|
throw (IOException)new IOException("GitHub Enterprise server (" + apiUrl + ") with private mode enabled").initCause(e);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures if a GitHub Enterprise server is configured in private mode.
|
||||||
|
*
|
||||||
|
* @return {@code true} if private mode is enabled. If it tries to use this method with GitHub, returns {@code
|
||||||
|
* false}.
|
||||||
|
*/
|
||||||
|
private boolean isPrivateModeEnabled() {
|
||||||
|
try {
|
||||||
|
HttpURLConnection uc = getConnector().connect(getApiURL("/"));
|
||||||
|
/*
|
||||||
|
$ curl -i https://github.mycompany.com/api/v3/
|
||||||
|
HTTP/1.1 401 Unauthorized
|
||||||
|
Server: GitHub.com
|
||||||
|
Date: Sat, 05 Mar 2016 19:45:01 GMT
|
||||||
|
Content-Type: application/json; charset=utf-8
|
||||||
|
Content-Length: 130
|
||||||
|
Status: 401 Unauthorized
|
||||||
|
X-GitHub-Media-Type: github.v3
|
||||||
|
X-XSS-Protection: 1; mode=block
|
||||||
|
X-Frame-Options: deny
|
||||||
|
Content-Security-Policy: default-src 'none'
|
||||||
|
Access-Control-Allow-Credentials: true
|
||||||
|
Access-Control-Expose-Headers: ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval
|
||||||
|
Access-Control-Allow-Origin: *
|
||||||
|
X-GitHub-Request-Id: dbc70361-b11d-4131-9a7f-674b8edd0411
|
||||||
|
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
|
||||||
|
X-Content-Type-Options: nosniff
|
||||||
|
*/
|
||||||
|
return uc.getResponseCode() == HTTP_UNAUTHORIZED
|
||||||
|
&& uc.getHeaderField("X-GitHub-Media-Type") != null;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -593,4 +654,6 @@ public class GitHub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* package */ static final String GITHUB_URL = "https://api.github.com";
|
/* package */ static final String GITHUB_URL = "https://api.github.com";
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(GitHub.class.getName());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import java.util.Map.Entry;
|
|||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Configures connection details and produces {@link GitHub}.
|
||||||
*
|
*
|
||||||
* @since 1.59
|
* @since 1.59
|
||||||
*/
|
*/
|
||||||
|
|||||||
118
src/main/java/org/kohsuke/github/HttpException.java
Normal file
118
src/main/java/org/kohsuke/github/HttpException.java
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import javax.annotation.CheckForNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link IOException} for http exceptions because {@link HttpURLConnection} throws un-discerned
|
||||||
|
* {@link IOException} and it can help to know the http response code to decide how to handle an
|
||||||
|
* http exceptions.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:cleclerc@cloudbees.com">Cyrille Le Clerc</a>
|
||||||
|
*/
|
||||||
|
public class HttpException extends IOException {
|
||||||
|
static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final int responseCode;
|
||||||
|
private final String responseMessage;
|
||||||
|
private final String url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param message The detail message (which is saved for later retrieval
|
||||||
|
* by the {@link #getMessage()} method)
|
||||||
|
* @param responseCode Http response code. {@code -1} if no code can be discerned.
|
||||||
|
* @param responseMessage Http response message
|
||||||
|
* @param url The url that was invoked
|
||||||
|
* @see HttpURLConnection#getResponseCode()
|
||||||
|
* @see HttpURLConnection#getResponseMessage()
|
||||||
|
*/
|
||||||
|
public HttpException(String message, int responseCode, String responseMessage, String url) {
|
||||||
|
super(message);
|
||||||
|
this.responseCode = responseCode;
|
||||||
|
this.responseMessage = responseMessage;
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param message The detail message (which is saved for later retrieval
|
||||||
|
* by the {@link #getMessage()} method)
|
||||||
|
* @param responseCode Http response code. {@code -1} if no code can be discerned.
|
||||||
|
* @param responseMessage Http response message
|
||||||
|
* @param url The url that was invoked
|
||||||
|
* @param cause The cause (which is saved for later retrieval by the
|
||||||
|
* {@link #getCause()} method). (A null value is permitted,
|
||||||
|
* and indicates that the cause is nonexistent or unknown.)
|
||||||
|
* @see HttpURLConnection#getResponseCode()
|
||||||
|
* @see HttpURLConnection#getResponseMessage()
|
||||||
|
*/
|
||||||
|
public HttpException(String message, int responseCode, String responseMessage, String url, Throwable cause) {
|
||||||
|
super(message);
|
||||||
|
initCause(cause);
|
||||||
|
this.responseCode = responseCode;
|
||||||
|
this.responseMessage = responseMessage;
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param responseCode Http response code. {@code -1} if no code can be discerned.
|
||||||
|
* @param responseMessage Http response message
|
||||||
|
* @param url The url that was invoked
|
||||||
|
* @param cause The cause (which is saved for later retrieval by the
|
||||||
|
* {@link #getCause()} method). (A null value is permitted,
|
||||||
|
* and indicates that the cause is nonexistent or unknown.)
|
||||||
|
* @see HttpURLConnection#getResponseCode()
|
||||||
|
* @see HttpURLConnection#getResponseMessage()
|
||||||
|
*/
|
||||||
|
public HttpException(int responseCode, String responseMessage, String url, Throwable cause) {
|
||||||
|
super("Server returned HTTP response code: " + responseCode + ", message: '" + responseMessage + "'" +
|
||||||
|
" for URL: " + url);
|
||||||
|
initCause(cause);
|
||||||
|
this.responseCode = responseCode;
|
||||||
|
this.responseMessage = responseMessage;
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param responseCode Http response code. {@code -1} if no code can be discerned.
|
||||||
|
* @param responseMessage Http response message
|
||||||
|
* @param url The url that was invoked
|
||||||
|
* @param cause The cause (which is saved for later retrieval by the
|
||||||
|
* {@link #getCause()} method). (A null value is permitted,
|
||||||
|
* and indicates that the cause is nonexistent or unknown.)
|
||||||
|
* @see HttpURLConnection#getResponseCode()
|
||||||
|
* @see HttpURLConnection#getResponseMessage()
|
||||||
|
*/
|
||||||
|
public HttpException(int responseCode, String responseMessage, @CheckForNull URL url, Throwable cause) {
|
||||||
|
this(responseCode, responseMessage, url == null ? null : url.toString(), cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Http response code of the request that cause the exception
|
||||||
|
*
|
||||||
|
* @return {@code -1} if no code can be discerned.
|
||||||
|
*/
|
||||||
|
public int getResponseCode() {
|
||||||
|
return responseCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Http response message of the request that cause the exception
|
||||||
|
*
|
||||||
|
* @return {@code null} if no response message can be discerned.
|
||||||
|
*/
|
||||||
|
public String getResponseMessage() {
|
||||||
|
return responseMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The http URL that caused the exception
|
||||||
|
*
|
||||||
|
* @return url
|
||||||
|
*/
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||||
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
@@ -45,9 +46,11 @@ import java.util.HashMap;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.ListIterator;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.logging.Logger;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
@@ -55,6 +58,7 @@ import java.util.zip.GZIPInputStream;
|
|||||||
import javax.annotation.WillClose;
|
import javax.annotation.WillClose;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.logging.Level.FINE;
|
||||||
import static org.kohsuke.github.GitHub.*;
|
import static org.kohsuke.github.GitHub.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,8 +67,6 @@ import static org.kohsuke.github.GitHub.*;
|
|||||||
* @author Kohsuke Kawaguchi
|
* @author Kohsuke Kawaguchi
|
||||||
*/
|
*/
|
||||||
class Requester {
|
class Requester {
|
||||||
private static final List<String> METHODS_WITHOUT_BODY = asList("GET", "DELETE");
|
|
||||||
|
|
||||||
private final GitHub root;
|
private final GitHub root;
|
||||||
private final List<Entry> args = new ArrayList<Entry>();
|
private final List<Entry> args = new ArrayList<Entry>();
|
||||||
private final Map<String,String> headers = new LinkedHashMap<String, String>();
|
private final Map<String,String> headers = new LinkedHashMap<String, String>();
|
||||||
@@ -137,7 +139,7 @@ class Requester {
|
|||||||
// by convention Java constant names are upper cases, but github uses
|
// by convention Java constant names are upper cases, but github uses
|
||||||
// lower-case constants. GitHub also uses '-', which in Java we always
|
// lower-case constants. GitHub also uses '-', which in Java we always
|
||||||
// replace by '_'
|
// replace by '_'
|
||||||
return with(key, e.toString().toLowerCase(Locale.ENGLISH).replace('_','-'));
|
return with(key, e.toString().toLowerCase(Locale.ENGLISH).replace('_', '-'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Requester with(String key, String value) {
|
public Requester with(String key, String value) {
|
||||||
@@ -215,19 +217,24 @@ class Requester {
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public <T> T to(String tailApiUrl, Class<T> type, String method) throws IOException {
|
public <T> T to(String tailApiUrl, Class<T> type, String method) throws IOException {
|
||||||
return method(method).to(tailApiUrl,type);
|
return method(method).to(tailApiUrl, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressFBWarnings("SBSC_USE_STRINGBUFFER_CONCATENATION")
|
||||||
private <T> T _to(String tailApiUrl, Class<T> type, T instance) throws IOException {
|
private <T> T _to(String tailApiUrl, Class<T> type, T instance) throws IOException {
|
||||||
while (true) {// loop while API rate limit is hit
|
|
||||||
if (METHODS_WITHOUT_BODY.contains(method) && !args.isEmpty()) {
|
if (METHODS_WITHOUT_BODY.contains(method) && !args.isEmpty()) {
|
||||||
StringBuilder qs=new StringBuilder();
|
boolean questionMarkFound = tailApiUrl.indexOf('?') != -1;
|
||||||
for (Entry arg : args) {
|
tailApiUrl += questionMarkFound ? '&' : '?';
|
||||||
qs.append(qs.length()==0 ? '?' : '&');
|
for (Iterator<Entry> it = args.listIterator(); it.hasNext();) {
|
||||||
qs.append(arg.key).append('=').append(URLEncoder.encode(arg.value.toString(),"UTF-8"));
|
Entry arg = it.next();
|
||||||
|
tailApiUrl += arg.key + '=' + URLEncoder.encode(arg.value.toString(),"UTF-8");
|
||||||
|
if (it.hasNext()) {
|
||||||
|
tailApiUrl += '&';
|
||||||
}
|
}
|
||||||
tailApiUrl += qs.toString();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {// loop while API rate limit is hit
|
||||||
setupConnection(root.getApiURL(tailApiUrl));
|
setupConnection(root.getApiURL(tailApiUrl));
|
||||||
|
|
||||||
buildRequest();
|
buildRequest();
|
||||||
@@ -264,10 +271,9 @@ class Requester {
|
|||||||
*/
|
*/
|
||||||
public int asHttpStatusCode(String tailApiUrl) throws IOException {
|
public int asHttpStatusCode(String tailApiUrl) throws IOException {
|
||||||
while (true) {// loop while API rate limit is hit
|
while (true) {// loop while API rate limit is hit
|
||||||
|
method("GET");
|
||||||
setupConnection(root.getApiURL(tailApiUrl));
|
setupConnection(root.getApiURL(tailApiUrl));
|
||||||
|
|
||||||
uc.setRequestMethod("GET");
|
|
||||||
|
|
||||||
buildRequest();
|
buildRequest();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -282,9 +288,6 @@ class Requester {
|
|||||||
while (true) {// loop while API rate limit is hit
|
while (true) {// loop while API rate limit is hit
|
||||||
setupConnection(root.getApiURL(tailApiUrl));
|
setupConnection(root.getApiURL(tailApiUrl));
|
||||||
|
|
||||||
// if the download link is encoded with a token on the query string, the default behavior of POST will fail
|
|
||||||
uc.setRequestMethod("GET");
|
|
||||||
|
|
||||||
buildRequest();
|
buildRequest();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -476,21 +479,33 @@ class Requester {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private <T> T parse(Class<T> type, T instance) throws IOException {
|
private <T> T parse(Class<T> type, T instance) throws IOException {
|
||||||
if (uc.getResponseCode()==304)
|
|
||||||
return null; // special case handling for 304 unmodified, as the content will be ""
|
|
||||||
InputStreamReader r = null;
|
InputStreamReader r = null;
|
||||||
|
int responseCode = -1;
|
||||||
|
String responseMessage = null;
|
||||||
try {
|
try {
|
||||||
|
responseCode = uc.getResponseCode();
|
||||||
|
responseMessage = uc.getResponseMessage();
|
||||||
|
if (responseCode == 304) {
|
||||||
|
return null; // special case handling for 304 unmodified, as the content will be ""
|
||||||
|
}
|
||||||
|
|
||||||
r = new InputStreamReader(wrapStream(uc.getInputStream()), "UTF-8");
|
r = new InputStreamReader(wrapStream(uc.getInputStream()), "UTF-8");
|
||||||
String data = IOUtils.toString(r);
|
String data = IOUtils.toString(r);
|
||||||
if (type!=null)
|
if (type!=null)
|
||||||
try {
|
try {
|
||||||
return MAPPER.readValue(data,type);
|
return MAPPER.readValue(data,type);
|
||||||
} catch (JsonMappingException e) {
|
} catch (JsonMappingException e) {
|
||||||
throw (IOException)new IOException("Failed to deserialize "+data).initCause(e);
|
throw (IOException)new IOException("Failed to deserialize " +data).initCause(e);
|
||||||
}
|
}
|
||||||
if (instance!=null)
|
if (instance!=null)
|
||||||
return MAPPER.readerForUpdating(instance).<T>readValue(data);
|
return MAPPER.readerForUpdating(instance).<T>readValue(data);
|
||||||
return null;
|
return null;
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
// java.net.URLConnection handles 404 exception has FileNotFoundException, don't wrap exception in HttpException
|
||||||
|
// to preserve backward compatibility
|
||||||
|
throw e;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new HttpException(responseCode, responseMessage, uc.getURL(), e);
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(r);
|
IOUtils.closeQuietly(r);
|
||||||
}
|
}
|
||||||
@@ -511,7 +526,18 @@ class Requester {
|
|||||||
* Handle API error by either throwing it or by returning normally to retry.
|
* Handle API error by either throwing it or by returning normally to retry.
|
||||||
*/
|
*/
|
||||||
/*package*/ void handleApiError(IOException e) throws IOException {
|
/*package*/ void handleApiError(IOException e) throws IOException {
|
||||||
if (uc.getResponseCode() == 401) // Unauthorized == bad creds
|
int responseCode;
|
||||||
|
try {
|
||||||
|
responseCode = uc.getResponseCode();
|
||||||
|
} catch (IOException e2) {
|
||||||
|
// likely to be a network exception (e.g. SSLHandshakeException),
|
||||||
|
// uc.getResponseCode() and any other getter on the response will cause an exception
|
||||||
|
if (LOGGER.isLoggable(FINE))
|
||||||
|
LOGGER.log(FINE, "Silently ignore exception retrieving response code for '" + uc.getURL() + "'" +
|
||||||
|
" handling exception " + e, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) // 401 / Unauthorized == bad creds
|
||||||
throw e;
|
throw e;
|
||||||
|
|
||||||
if ("0".equals(uc.getHeaderField("X-RateLimit-Remaining"))) {
|
if ("0".equals(uc.getHeaderField("X-RateLimit-Remaining"))) {
|
||||||
@@ -533,4 +559,7 @@ class Requester {
|
|||||||
IOUtils.closeQuietly(es);
|
IOUtils.closeQuietly(es);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final List<String> METHODS_WITHOUT_BODY = asList("GET", "DELETE");
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(Requester.class.getName());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,21 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
|||||||
getUser().getRepository(targetName).delete();
|
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 {
|
private void deleteRepository(final String name) throws IOException {
|
||||||
GHRepository repository = getUser().getRepository(name);
|
GHRepository repository = getUser().getRepository(name);
|
||||||
if(repository != null) {
|
if(repository != null) {
|
||||||
@@ -326,6 +341,8 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
|||||||
System.out.println(commit);
|
System.out.println(commit);
|
||||||
assertEquals(1, commit.getParents().size());
|
assertEquals(1, commit.getParents().size());
|
||||||
assertEquals(1,commit.getFiles().size());
|
assertEquals(1,commit.getFiles().size());
|
||||||
|
assertEquals("https://github.com/jenkinsci/jenkins/commit/08c1c9970af4d609ae754fbe803e06186e3206f7",
|
||||||
|
commit.getHtmlUrl().toString());
|
||||||
|
|
||||||
File f = commit.getFiles().get(0);
|
File f = commit.getFiles().get(0);
|
||||||
assertEquals(48,f.getLinesChanged());
|
assertEquals(48,f.getLinesChanged());
|
||||||
@@ -774,7 +791,7 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
|||||||
assertTrue(actual.contains("href=\"https://github.com/kohsuke\""));
|
assertTrue(actual.contains("href=\"https://github.com/kohsuke\""));
|
||||||
assertTrue(actual.contains("href=\"https://github.com/kohsuke/github-api/pull/1\""));
|
assertTrue(actual.contains("href=\"https://github.com/kohsuke/github-api/pull/1\""));
|
||||||
assertTrue(actual.contains("class=\"user-mention\""));
|
assertTrue(actual.contains("class=\"user-mention\""));
|
||||||
assertTrue(actual.contains("class=\"issue-link\""));
|
assertTrue(actual.contains("class=\"issue-link "));
|
||||||
assertTrue(actual.contains("to fix issue"));
|
assertTrue(actual.contains("to fix issue"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ public class GHContentIntegrationTest extends AbstractGitHubApiTestBase {
|
|||||||
|
|
||||||
assertNotNull(updatedContentResponse.getCommit());
|
assertNotNull(updatedContentResponse.getCommit());
|
||||||
assertNotNull(updatedContentResponse.getContent());
|
assertNotNull(updatedContentResponse.getContent());
|
||||||
assertEquals("this is some new content\n", updatedContent.getContent());
|
// due to what appears to be a cache propagation delay, this test is too flaky
|
||||||
|
// assertEquals("this is some new content\n", updatedContent.getContent());
|
||||||
|
|
||||||
GHContentUpdateResponse deleteResponse = updatedContent.delete("Enough of this foolishness!");
|
GHContentUpdateResponse deleteResponse = updatedContent.delete("Enough of this foolishness!");
|
||||||
|
|
||||||
|
|||||||
43
src/test/java/org/kohsuke/github/GHOrganizationTest.java
Normal file
43
src/test/java/org/kohsuke/github/GHOrganizationTest.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -124,6 +124,11 @@ public class GitHubTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testGitHubIsApiUrlValid() throws IOException {
|
public void testGitHubIsApiUrlValid() throws IOException {
|
||||||
GitHub github = GitHub.connectAnonymously();
|
GitHub github = GitHub.connectAnonymously();
|
||||||
|
//GitHub github = GitHub.connectToEnterpriseAnonymously("https://github.mycompany.com/api/v3/");
|
||||||
|
try {
|
||||||
github.checkApiUrlValidity();
|
github.checkApiUrlValidity();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
assertTrue(ioe.getMessage().contains("private mode enabled"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user