mirror of
https://github.com/jlengrand/github-api.git
synced 2026-03-11 08:21:23 +00:00
Compare commits
63 Commits
github-api
...
github-api
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d5c6cf71c | ||
|
|
89aac45f41 | ||
|
|
4965fd5f4c | ||
|
|
87fbb8ec98 | ||
|
|
0d92d4ba61 | ||
|
|
b0df93bbcb | ||
|
|
290d0b226a | ||
|
|
8b3469610c | ||
|
|
50b47fb73b | ||
|
|
5334cb8688 | ||
|
|
38983df42d | ||
|
|
df963cb71c | ||
|
|
e9368fb04e | ||
|
|
e2a1630cf4 | ||
|
|
4f15b7c9fa | ||
|
|
63f500ad7f | ||
|
|
a9fb4546e1 | ||
|
|
cabbbf7f02 | ||
|
|
59324b0082 | ||
|
|
6a356c82a5 | ||
|
|
70f0f5714a | ||
|
|
07b527a0f2 | ||
|
|
80aa75aab1 | ||
|
|
0cf4211aa5 | ||
|
|
1de02a5099 | ||
|
|
bb1cecb95b | ||
|
|
d82397a173 | ||
|
|
856cf5e568 | ||
|
|
9f5a6ee549 | ||
|
|
a2f0837d14 | ||
|
|
c7f6889534 | ||
|
|
0415326d09 | ||
|
|
16a0f8ece0 | ||
|
|
5d1ef296b3 | ||
|
|
16dbcde90b | ||
|
|
50cbf25c72 | ||
|
|
7b87de2b4c | ||
|
|
1ce54a7925 | ||
|
|
1bfe7dd99b | ||
|
|
27e855ddbd | ||
|
|
3d1bed0f8f | ||
|
|
5c9ea9b63a | ||
|
|
7c034f5670 | ||
|
|
3b9f5a417a | ||
|
|
cde501af8d | ||
|
|
3c5592c1c8 | ||
|
|
2508e022bb | ||
|
|
01fcbc24e8 | ||
|
|
204e639679 | ||
|
|
3d301ec730 | ||
|
|
9ab6d57019 | ||
|
|
37c473130f | ||
|
|
5f95987a48 | ||
|
|
d530b34073 | ||
|
|
35dec7a5ec | ||
|
|
baedad8124 | ||
|
|
007378c3a6 | ||
|
|
beae9fd6ec | ||
|
|
b7507076c6 | ||
|
|
6b5ade3ca0 | ||
|
|
715192d26c | ||
|
|
ce140460af | ||
|
|
d30b0403ce |
6
pom.xml
6
pom.xml
@@ -7,7 +7,7 @@
|
||||
</parent>
|
||||
|
||||
<artifactId>github-api</artifactId>
|
||||
<version>1.74</version>
|
||||
<version>1.79</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.74</tag>
|
||||
<tag>github-api-1.79</tag>
|
||||
</scm>
|
||||
|
||||
<distributionManagement>
|
||||
@@ -135,7 +135,7 @@
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp</groupId>
|
||||
<artifactId>okhttp-urlconnection</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<version>2.7.5</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
63
src/main/java/org/kohsuke/github/AbuseLimitHandler.java
Normal file
63
src/main/java/org/kohsuke/github/AbuseLimitHandler.java
Normal file
@@ -0,0 +1,63 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
/**
|
||||
* Pluggable strategy to determine what to do when the API abuse limit is hit.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GitHubBuilder#withAbuseLimitHandler(AbuseLimitHandler)
|
||||
* @see <a href="https://developer.github.com/v3/#abuse-rate-limits">documentation</a>
|
||||
* @see RateLimitHandler
|
||||
*/
|
||||
public abstract class AbuseLimitHandler {
|
||||
/**
|
||||
* Called when the library encounters HTTP error indicating that the API abuse limit is reached.
|
||||
*
|
||||
* <p>
|
||||
* Any exception thrown from this method will cause the request to fail, and the caller of github-api
|
||||
* will receive an exception. If this method returns normally, another request will be attempted.
|
||||
* For that to make sense, the implementation needs to wait for some time.
|
||||
*
|
||||
* @see <a href="https://developer.github.com/v3/#abuse-rate-limits">API documentation from GitHub</a>
|
||||
* @param e
|
||||
* Exception from Java I/O layer. If you decide to fail the processing, you can throw
|
||||
* this exception (or wrap this exception into another exception and throw it.)
|
||||
* @param uc
|
||||
* Connection that resulted in an error. Useful for accessing other response headers.
|
||||
*/
|
||||
public abstract void onError(IOException e, HttpURLConnection uc) throws IOException;
|
||||
|
||||
/**
|
||||
* Wait until the API abuse "wait time" is passed.
|
||||
*/
|
||||
public static final AbuseLimitHandler WAIT = new AbuseLimitHandler() {
|
||||
@Override
|
||||
public void onError(IOException e, HttpURLConnection uc) throws IOException {
|
||||
try {
|
||||
Thread.sleep(parseWaitTime(uc));
|
||||
} catch (InterruptedException _) {
|
||||
throw (InterruptedIOException)new InterruptedIOException().initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
private long parseWaitTime(HttpURLConnection uc) {
|
||||
String v = uc.getHeaderField("Retry-After");
|
||||
if (v==null) return 60 * 1000; // can't tell, return 1 min
|
||||
|
||||
return Math.max(1000, Long.parseLong(v)*1000);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Fail immediately.
|
||||
*/
|
||||
public static final AbuseLimitHandler FAIL = new AbuseLimitHandler() {
|
||||
@Override
|
||||
public void onError(IOException e, HttpURLConnection uc) throws IOException {
|
||||
throw (IOException)new IOException("Abust limit reached").initCause(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
21
src/main/java/org/kohsuke/github/BranchProtection.java
Normal file
21
src/main/java/org/kohsuke/github/BranchProtection.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GHBranch#disableProtection()
|
||||
*/
|
||||
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD", "URF_UNREAD_FIELD"}, justification = "JSON API")
|
||||
class BranchProtection {
|
||||
boolean enabled;
|
||||
RequiredStatusChecks requiredStatusChecks;
|
||||
|
||||
static class RequiredStatusChecks {
|
||||
EnforcementLevel enforcement_level;
|
||||
List<String> contexts = new ArrayList<String>();
|
||||
}
|
||||
}
|
||||
14
src/main/java/org/kohsuke/github/EnforcementLevel.java
Normal file
14
src/main/java/org/kohsuke/github/EnforcementLevel.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public enum EnforcementLevel {
|
||||
OFF, NON_ADMINS, EVERYONE;
|
||||
|
||||
public String toString() {
|
||||
return name().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,13 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import org.kohsuke.github.BranchProtection.RequiredStatusChecks;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.kohsuke.github.Previews.LOKI;
|
||||
|
||||
/**
|
||||
* A branch in a repository.
|
||||
@@ -8,7 +15,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
* @author Yusuke Kokubo
|
||||
*/
|
||||
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
|
||||
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
|
||||
"NP_UNWRITTEN_FIELD", "URF_UNREAD_FIELD"}, justification = "JSON API")
|
||||
public class GHBranch {
|
||||
private GitHub root;
|
||||
private GHRepository owner;
|
||||
@@ -44,6 +51,44 @@ public class GHBranch {
|
||||
public String getSHA1() {
|
||||
return commit.sha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables branch protection and allows anyone with push access to push changes.
|
||||
*/
|
||||
@Preview @Deprecated
|
||||
public void disableProtection() throws IOException {
|
||||
BranchProtection bp = new BranchProtection();
|
||||
bp.enabled = false;
|
||||
setProtection(bp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables branch protection to control what commit statuses are required to push.
|
||||
*
|
||||
* @see GHCommitStatus#getContext()
|
||||
*/
|
||||
@Preview @Deprecated
|
||||
public void enableProtection(EnforcementLevel level, Collection<String> contexts) throws IOException {
|
||||
BranchProtection bp = new BranchProtection();
|
||||
bp.enabled = true;
|
||||
bp.requiredStatusChecks = new RequiredStatusChecks();
|
||||
bp.requiredStatusChecks.enforcement_level = level;
|
||||
bp.requiredStatusChecks.contexts.addAll(contexts);
|
||||
setProtection(bp);
|
||||
}
|
||||
|
||||
@Preview @Deprecated
|
||||
public void enableProtection(EnforcementLevel level, String... contexts) throws IOException {
|
||||
enableProtection(level, Arrays.asList(contexts));
|
||||
}
|
||||
|
||||
private void setProtection(BranchProtection bp) throws IOException {
|
||||
new Requester(root).method("PATCH").withPreview(LOKI)._with("protection",bp).to(getApiRoute());
|
||||
}
|
||||
|
||||
String getApiRoute() {
|
||||
return owner.getApiTailUrl("/branches/"+name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
@@ -2,12 +2,12 @@ package org.kohsuke.github;
|
||||
|
||||
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -42,11 +42,19 @@ public class GHCommit {
|
||||
return author;
|
||||
}
|
||||
|
||||
public Date getAuthoredDate() {
|
||||
return GitHub.parseDate(author.date);
|
||||
}
|
||||
|
||||
@WithBridgeMethods(value = GHAuthor.class, castRequired = true)
|
||||
public GitUser getCommitter() {
|
||||
return committer;
|
||||
}
|
||||
|
||||
public Date getCommitDate() {
|
||||
return GitHub.parseDate(committer.date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit message.
|
||||
*/
|
||||
@@ -63,6 +71,7 @@ public class GHCommit {
|
||||
* @deprecated Use {@link GitUser} instead.
|
||||
*/
|
||||
public static class GHAuthor extends GitUser {
|
||||
private String date;
|
||||
}
|
||||
|
||||
public static class Stats {
|
||||
@@ -179,7 +188,8 @@ public class GHCommit {
|
||||
|
||||
|
||||
public ShortInfo getCommitShortInfo() throws IOException {
|
||||
populate();
|
||||
if (commit==null)
|
||||
populate();
|
||||
return commit;
|
||||
}
|
||||
|
||||
@@ -271,10 +281,29 @@ public class GHCommit {
|
||||
return resolveUser(author);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the date the change was authored on.
|
||||
* @return the date the change was authored on.
|
||||
* @throws IOException if the information was not already fetched and an attempt at fetching the information failed.
|
||||
*/
|
||||
public Date getAuthoredDate() throws IOException {
|
||||
return getCommitShortInfo().getAuthoredDate();
|
||||
}
|
||||
|
||||
public GHUser getCommitter() throws IOException {
|
||||
return resolveUser(committer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the date the change was committed on.
|
||||
*
|
||||
* @return the date the change was committed on.
|
||||
* @throws IOException if the information was not already fetched and an attempt at fetching the information failed.
|
||||
*/
|
||||
public Date getCommitDate() throws IOException {
|
||||
return getCommitShortInfo().getCommitDate();
|
||||
}
|
||||
|
||||
private GHUser resolveUser(User author) throws IOException {
|
||||
if (author==null || author.login==null) return null;
|
||||
return owner.root.getUser(author.login);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Represents a status of a commit.
|
||||
@@ -10,6 +8,7 @@ import java.util.Date;
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GHRepository#getLastCommitStatus(String)
|
||||
* @see GHCommit#getLastStatus()
|
||||
* @see GHRepository#createCommitStatus(String, GHCommitState, String, String)
|
||||
*/
|
||||
public class GHCommitStatus extends GHObject {
|
||||
String state;
|
||||
|
||||
21
src/main/java/org/kohsuke/github/GHContentWithLicense.java
Normal file
21
src/main/java/org/kohsuke/github/GHContentWithLicense.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
/**
|
||||
* {@link GHContent} with license information.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see <a href="https://developer.github.com/v3/licenses/#get-a-repositorys-license">documentation</a>
|
||||
* @see GHRepository#getLicense()
|
||||
*/
|
||||
@Preview @Deprecated
|
||||
class GHContentWithLicense extends GHContent {
|
||||
GHLicense license;
|
||||
|
||||
@Override
|
||||
GHContentWithLicense wrap(GHRepository owner) {
|
||||
super.wrap(owner);
|
||||
if (license!=null)
|
||||
license.wrap(owner.root);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,9 @@ import java.util.Locale;
|
||||
/**
|
||||
* Hook event type.
|
||||
*
|
||||
* See http://developer.github.com/v3/events/types/
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GHEventInfo
|
||||
* @see <a href="https://developer.github.com/v3/activity/events/types/">Event type reference</a>
|
||||
*/
|
||||
public enum GHEvent {
|
||||
COMMIT_COMMENT,
|
||||
|
||||
@@ -54,6 +54,7 @@ public class GHIssue extends GHObject {
|
||||
protected int number;
|
||||
protected String closed_at;
|
||||
protected int comments;
|
||||
@SkipFromToString
|
||||
protected String body;
|
||||
// for backward compatibility with < 1.63, this collection needs to hold instances of Label, not GHLabel
|
||||
protected List<Label> labels;
|
||||
|
||||
168
src/main/java/org/kohsuke/github/GHLicense.java
Normal file
168
src/main/java/org/kohsuke/github/GHLicense.java
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2016, Duncan Dickinson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.kohsuke.github;
|
||||
|
||||
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.kohsuke.github.Previews.DRAX;
|
||||
|
||||
/**
|
||||
* The GitHub Preview API's license information
|
||||
* <p>
|
||||
* WARNING: This uses a PREVIEW API - subject to change.
|
||||
*
|
||||
* @author Duncan Dickinson
|
||||
* @see GitHub#getLicense(String)
|
||||
* @see GHRepository#getLicense()
|
||||
* @see <a href="https://developer.github.com/v3/licenses/">https://developer.github.com/v3/licenses/</a>
|
||||
*/
|
||||
@Preview @Deprecated
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
|
||||
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
|
||||
public class GHLicense extends GHObject {
|
||||
@SuppressFBWarnings("IS2_INCONSISTENT_SYNC") // root is set before the object is returned to the app
|
||||
/*package almost final*/ GitHub root;
|
||||
|
||||
// these fields are always present, even in the short form
|
||||
protected String key, name;
|
||||
|
||||
// the rest is only after populated
|
||||
protected Boolean featured;
|
||||
|
||||
protected String html_url, description, category, implementation, body;
|
||||
|
||||
protected List<String> required = new ArrayList<String>();
|
||||
protected List<String> permitted = new ArrayList<String>();
|
||||
protected List<String> forbidden = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* @return a mnemonic for the license
|
||||
*/
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the license name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return API URL of this object.
|
||||
*/
|
||||
@WithBridgeMethods(value = String.class, adapterMethod = "urlToString")
|
||||
public URL getUrl() {
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Featured licenses are bold in the new repository drop-down
|
||||
*
|
||||
* @return True if the license is featured, false otherwise
|
||||
*/
|
||||
public Boolean isFeatured() throws IOException {
|
||||
populate();
|
||||
return featured;
|
||||
}
|
||||
|
||||
public URL getHtmlUrl() throws IOException {
|
||||
populate();
|
||||
return GitHub.parseURL(html_url);
|
||||
}
|
||||
|
||||
public String getDescription() throws IOException {
|
||||
populate();
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getCategory() throws IOException {
|
||||
populate();
|
||||
return category;
|
||||
}
|
||||
|
||||
public String getImplementation() throws IOException {
|
||||
populate();
|
||||
return implementation;
|
||||
}
|
||||
|
||||
public List<String> getRequired() throws IOException {
|
||||
populate();
|
||||
return required;
|
||||
}
|
||||
|
||||
public List<String> getPermitted() throws IOException {
|
||||
populate();
|
||||
return permitted;
|
||||
}
|
||||
|
||||
public List<String> getForbidden() throws IOException {
|
||||
populate();
|
||||
return forbidden;
|
||||
}
|
||||
|
||||
public String getBody() throws IOException {
|
||||
populate();
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fully populate the data by retrieving missing data.
|
||||
*
|
||||
* Depending on the original API call where this object is created, it may not contain everything.
|
||||
*/
|
||||
protected synchronized void populate() throws IOException {
|
||||
if (description!=null) return; // already populated
|
||||
|
||||
root.retrieve().withPreview(DRAX).to(url, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof GHLicense)) return false;
|
||||
|
||||
GHLicense that = (GHLicense) o;
|
||||
return this.url.equals(that.url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return url.hashCode();
|
||||
}
|
||||
|
||||
/*package*/ GHLicense wrap(GitHub root) {
|
||||
this.root = root;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -72,12 +72,19 @@ public class GHMilestone extends GHObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this issue.
|
||||
* Closes this milestone.
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
edit("state", "closed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reopens this milestone.
|
||||
*/
|
||||
public void reopen() throws IOException {
|
||||
edit("state", "open");
|
||||
}
|
||||
|
||||
private void edit(String key, Object value) throws IOException {
|
||||
new Requester(root)._with(key, value).method("PATCH").to(getApiRoute());
|
||||
}
|
||||
|
||||
@@ -2,8 +2,13 @@ package org.kohsuke.github;
|
||||
|
||||
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
|
||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang.builder.ToStringStyle;
|
||||
import org.apache.commons.lang.reflect.FieldUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
|
||||
@@ -46,7 +51,7 @@ public abstract class GHObject {
|
||||
* URL of this object for humans, which renders some HTML.
|
||||
*/
|
||||
@WithBridgeMethods(value=String.class, adapterMethod="urlToString")
|
||||
public abstract URL getHtmlUrl();
|
||||
public abstract URL getHtmlUrl() throws IOException;
|
||||
|
||||
/**
|
||||
* When was this resource last updated?
|
||||
@@ -72,4 +77,39 @@ public abstract class GHObject {
|
||||
private Object urlToString(URL url, Class type) {
|
||||
return url==null ? null : url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* String representation to assist debugging and inspection. The output format of this string
|
||||
* is not a committed part of the API and is subject to change.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ReflectionToStringBuilder(this, TOSTRING_STYLE, null, null, false, false) {
|
||||
@Override
|
||||
protected boolean accept(Field field) {
|
||||
return super.accept(field) && !field.isAnnotationPresent(SkipFromToString.class);
|
||||
}
|
||||
}.toString();
|
||||
}
|
||||
|
||||
private static final ToStringStyle TOSTRING_STYLE = new ToStringStyle() {
|
||||
{
|
||||
this.setUseShortClassName(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void append(StringBuffer buffer, String fieldName, Object value, Boolean fullDetail) {
|
||||
// skip unimportant properties. '_' is a heuristics as important properties tend to have short names
|
||||
if (fieldName.contains("_"))
|
||||
return;
|
||||
// avoid recursing other GHObject
|
||||
if (value instanceof GHObject)
|
||||
return;
|
||||
// likewise no point in showing root
|
||||
if (value instanceof GitHub)
|
||||
return;
|
||||
|
||||
super.append(buffer,fieldName,value,fullDetail);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -93,6 +93,17 @@ public class GHOrganization extends GHPerson {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a team that has the given slug in its {@link GHTeam#getSlug()}
|
||||
*/
|
||||
public GHTeam getTeamBySlug(String slug) throws IOException {
|
||||
for (GHTeam t : listTeams()) {
|
||||
if(t.getSlug().equals(slug))
|
||||
return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this organization has the specified user as a member.
|
||||
*/
|
||||
@@ -209,7 +220,7 @@ public class GHOrganization extends GHPerson {
|
||||
*/
|
||||
public List<GHRepository> getRepositoriesWithOpenPullRequests() throws IOException {
|
||||
List<GHRepository> r = new ArrayList<GHRepository>();
|
||||
for (GHRepository repository : listRepositories()) {
|
||||
for (GHRepository repository : listRepositories(100)) {
|
||||
repository.wrap(root);
|
||||
List<GHPullRequest> pullRequests = repository.getPullRequests(GHIssueState.OPEN);
|
||||
if (pullRequests.size() > 0) {
|
||||
|
||||
@@ -52,7 +52,7 @@ public abstract class GHPerson extends GHObject {
|
||||
*/
|
||||
public synchronized Map<String,GHRepository> getRepositories() throws IOException {
|
||||
Map<String,GHRepository> repositories = new TreeMap<String, GHRepository>();
|
||||
for (GHRepository r : listRepositories()) {
|
||||
for (GHRepository r : listRepositories(100)) {
|
||||
repositories.put(r.getName(),r);
|
||||
}
|
||||
return Collections.unmodifiableMap(repositories);
|
||||
@@ -204,7 +204,7 @@ public abstract class GHPerson extends GHObject {
|
||||
|
||||
public Date getUpdatedAt() throws IOException {
|
||||
populate();
|
||||
return super.getCreatedAt();
|
||||
return super.getUpdatedAt();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,6 +51,7 @@ import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.kohsuke.github.Previews.DRAX;
|
||||
|
||||
/**
|
||||
* A repository on GitHub.
|
||||
@@ -65,6 +66,13 @@ public class GHRepository extends GHObject {
|
||||
|
||||
private String description, homepage, name, full_name;
|
||||
private String html_url; // this is the UI
|
||||
/*
|
||||
* The license information makes use of the preview API.
|
||||
*
|
||||
* See: https://developer.github.com/v3/licenses/
|
||||
*/
|
||||
private GHLicense license;
|
||||
|
||||
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;
|
||||
@@ -77,6 +85,7 @@ public class GHRepository extends GHObject {
|
||||
private String default_branch,language;
|
||||
private Map<String,GHCommit> commits = new HashMap<String, GHCommit>();
|
||||
|
||||
@SkipFromToString
|
||||
private GHRepoPermission permissions;
|
||||
|
||||
private GHRepository source, parent;
|
||||
@@ -586,7 +595,19 @@ public class GHRepository extends GHObject {
|
||||
* Newly forked repository that belong to you.
|
||||
*/
|
||||
public GHRepository fork() throws IOException {
|
||||
return new Requester(root).method("POST").to(getApiTailUrl("forks"), GHRepository.class).wrap(root);
|
||||
new Requester(root).method("POST").to(getApiTailUrl("forks"), null);
|
||||
|
||||
// this API is asynchronous. we need to wait for a bit
|
||||
for (int i=0; i<10; i++) {
|
||||
GHRepository r = root.getMyself().getRepository(name);
|
||||
if (r!=null) return r;
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
} catch (InterruptedException e) {
|
||||
throw (IOException)new InterruptedIOException().initCause(e);
|
||||
}
|
||||
}
|
||||
throw new IOException(this+" was forked but can't find the new repository");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -744,6 +765,10 @@ public class GHRepository extends GHObject {
|
||||
* invalid ref type being requested
|
||||
*/
|
||||
public GHRef getRef(String refName) throws IOException {
|
||||
// hashes in branch names must be replaced with the url encoded equivalent or this call will fail
|
||||
// FIXME: how about other URL unsafe characters, like space, @, : etc? do we need to be using URLEncoder.encode()?
|
||||
// OTOH, '/' need no escaping
|
||||
refName = refName.replaceAll("#", "%23");
|
||||
return root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", owner.login, name, refName), GHRef.class).wrap(root);
|
||||
}
|
||||
/**
|
||||
@@ -827,6 +852,46 @@ public class GHRepository extends GHObject {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the basic license details for the repository.
|
||||
* <p>
|
||||
* This is a preview item and subject to change.
|
||||
*
|
||||
* @throws IOException as usual but also if you don't use the preview connector
|
||||
* @return null if there's no license.
|
||||
*/
|
||||
@Preview @Deprecated
|
||||
public GHLicense getLicense() throws IOException{
|
||||
GHContentWithLicense lic = getLicenseContent_();
|
||||
return lic!=null ? lic.license : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the contents of the repository's license file - makes an additional API call
|
||||
* <p>
|
||||
* This is a preview item and subject to change.
|
||||
*
|
||||
* @return details regarding the license contents, or null if there's no license.
|
||||
* @throws IOException as usual but also if you don't use the preview connector
|
||||
*/
|
||||
@Preview @Deprecated
|
||||
public GHContent getLicenseContent() throws IOException {
|
||||
return getLicenseContent_();
|
||||
}
|
||||
|
||||
@Preview @Deprecated
|
||||
private GHContentWithLicense getLicenseContent_() throws IOException {
|
||||
try {
|
||||
return root.retrieve()
|
||||
.withPreview(DRAX)
|
||||
.to(getApiTailUrl("license"), GHContentWithLicense.class).wrap(this);
|
||||
} catch (FileNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Lists all the commit statues attached to the given commit, newer ones first.
|
||||
*/
|
||||
@@ -935,12 +1000,36 @@ public class GHRepository extends GHObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all the users who have starred this repo.
|
||||
* Lists all the users who have starred this repo based on the old version of the API. For
|
||||
* additional information, like date when the repository was starred, see {@link #listStargazers2()}
|
||||
*/
|
||||
public PagedIterable<GHUser> listStargazers() {
|
||||
return listUsers("stargazers");
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all the users who have starred this repo based on new version of the API, having extended
|
||||
* information like the time when the repository was starred. For compatibility with the old API
|
||||
* see {@link #listStargazers()}
|
||||
*/
|
||||
public PagedIterable<GHStargazer> listStargazers2() {
|
||||
return new PagedIterable<GHStargazer>() {
|
||||
@Override
|
||||
public PagedIterator<GHStargazer> _iterator(int pageSize) {
|
||||
Requester requester = root.retrieve();
|
||||
requester.setHeader("Accept", "application/vnd.github.v3.star+json");
|
||||
return new PagedIterator<GHStargazer>(requester.asIterator(getApiTailUrl("stargazers"), GHStargazer[].class, pageSize)) {
|
||||
@Override
|
||||
protected void wrapUp(GHStargazer[] page) {
|
||||
for (GHStargazer c : page) {
|
||||
c.wrapUp(GHRepository.this);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private PagedIterable<GHUser> listUsers(final String suffix) {
|
||||
return new PagedIterable<GHUser>() {
|
||||
public PagedIterator<GHUser> _iterator(int pageSize) {
|
||||
@@ -1009,6 +1098,7 @@ public class GHRepository extends GHObject {
|
||||
*/
|
||||
@SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS",
|
||||
justification = "It causes a performance degradation, but we have already exposed it to the API")
|
||||
@SkipFromToString
|
||||
private final Set<URL> postCommitHooks = new AbstractSet<URL>() {
|
||||
private List<URL> getPostCommitHooks() {
|
||||
try {
|
||||
@@ -1078,6 +1168,10 @@ public class GHRepository extends GHObject {
|
||||
return r;
|
||||
}
|
||||
|
||||
public GHBranch getBranch(String name) throws IOException {
|
||||
return root.retrieve().to(getApiTailUrl("branches/"+name),GHBranch.class).wrap(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Use {@link #listMilestones(GHIssueState)}
|
||||
@@ -1326,14 +1420,9 @@ public class GHRepository extends GHObject {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Repository:"+owner.login+":"+name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
return ("Repository:"+owner.login+":"+name).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
51
src/main/java/org/kohsuke/github/GHStargazer.java
Normal file
51
src/main/java/org/kohsuke/github/GHStargazer.java
Normal file
@@ -0,0 +1,51 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* A stargazer at a repository on GitHub.
|
||||
*
|
||||
* @author noctarius
|
||||
*/
|
||||
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD"}, justification = "JSON API")
|
||||
public class GHStargazer {
|
||||
|
||||
private GHRepository repository;
|
||||
private String starred_at;
|
||||
private GHUser user;
|
||||
|
||||
/**
|
||||
* Gets the repository that is stargazed
|
||||
*
|
||||
* @return the starred repository
|
||||
*/
|
||||
public GHRepository getRepository() {
|
||||
return repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the date when the repository was starred, however old stars before
|
||||
* August 2012, will all show the date the API was changed to support starred_at.
|
||||
*
|
||||
* @return the date the stargazer was added
|
||||
*/
|
||||
public Date getStarredAt() {
|
||||
return GitHub.parseDate(starred_at);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user that starred the repository
|
||||
*
|
||||
* @return the stargazer user
|
||||
*/
|
||||
public GHUser getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
void wrapUp(GHRepository repository) {
|
||||
this.repository = repository;
|
||||
user.wrapUp(repository.root);
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import java.util.TreeMap;
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public class GHTeam {
|
||||
private String name,permission;
|
||||
private String name,permission,slug;
|
||||
private int id;
|
||||
private GHOrganization organization; // populated by GET /user/teams where Teams+Orgs are returned together
|
||||
|
||||
@@ -43,6 +43,10 @@ public class GHTeam {
|
||||
return permission;
|
||||
}
|
||||
|
||||
public String getSlug() {
|
||||
return slug;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
@@ -120,12 +124,25 @@ public class GHTeam {
|
||||
}
|
||||
|
||||
public void add(GHRepository r) throws IOException {
|
||||
org.root.retrieve().method("PUT").to(api("/repos/" + r.getOwnerName() + '/' + r.getName()), null);
|
||||
add(r,null);
|
||||
}
|
||||
|
||||
public void add(GHRepository r, GHOrganization.Permission permission) throws IOException {
|
||||
org.root.retrieve().method("PUT")
|
||||
.with("permission",permission)
|
||||
.to(api("/repos/" + r.getOwnerName() + '/' + r.getName()), null);
|
||||
}
|
||||
|
||||
public void remove(GHRepository r) throws IOException {
|
||||
org.root.retrieve().method("DELETE").to(api("/repos/" + r.getOwnerName() + '/' + r.getName()), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes this team.
|
||||
*/
|
||||
public void delete() throws IOException {
|
||||
org.root.retrieve().method("DELETE").to(api(""));
|
||||
}
|
||||
|
||||
private String api(String tail) {
|
||||
return "/teams/"+id+tail;
|
||||
|
||||
@@ -196,11 +196,6 @@ public class GHUser extends GHPerson {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User:"+login;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return login.hashCode();
|
||||
|
||||
@@ -27,6 +27,7 @@ import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
|
||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
|
||||
import static java.util.logging.Level.FINE;
|
||||
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
|
||||
import static org.kohsuke.github.Previews.DRAX;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
@@ -56,6 +57,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std;
|
||||
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
@@ -83,6 +85,7 @@ public class GitHub {
|
||||
private final String apiUrl;
|
||||
|
||||
/*package*/ final RateLimitHandler rateLimitHandler;
|
||||
/*package*/ final AbuseLimitHandler abuseLimitHandler;
|
||||
|
||||
private HttpConnector connector = HttpConnector.DEFAULT;
|
||||
|
||||
@@ -122,7 +125,7 @@ public class GitHub {
|
||||
* @param connector
|
||||
* HttpConnector to use. Pass null to use default connector.
|
||||
*/
|
||||
/* package */ GitHub(String apiUrl, String login, String oauthAccessToken, String password, HttpConnector connector, RateLimitHandler rateLimitHandler) throws IOException {
|
||||
/* package */ GitHub(String apiUrl, String login, String oauthAccessToken, String password, HttpConnector connector, RateLimitHandler rateLimitHandler, AbuseLimitHandler abuseLimitHandler) throws IOException {
|
||||
if (apiUrl.endsWith("/")) apiUrl = apiUrl.substring(0, apiUrl.length()-1); // normalize
|
||||
this.apiUrl = apiUrl;
|
||||
if (null != connector) this.connector = connector;
|
||||
@@ -140,6 +143,7 @@ public class GitHub {
|
||||
}
|
||||
|
||||
this.rateLimitHandler = rateLimitHandler;
|
||||
this.abuseLimitHandler = abuseLimitHandler;
|
||||
|
||||
if (login==null && encodedAuthorization!=null)
|
||||
login = getMyself().getLogin();
|
||||
@@ -337,6 +341,46 @@ public class GitHub {
|
||||
String[] tokens = name.split("/");
|
||||
return retrieve().to("/repos/" + tokens[0] + '/' + tokens[1], GHRepository.class).wrap(this);
|
||||
}
|
||||
/**
|
||||
* Returns a list of popular open source licenses
|
||||
*
|
||||
* WARNING: This uses a PREVIEW API.
|
||||
*
|
||||
* @see <a href="https://developer.github.com/v3/licenses/">GitHub API - Licenses</a>
|
||||
*
|
||||
* @return a list of popular open source licenses
|
||||
*/
|
||||
@Preview @Deprecated
|
||||
public PagedIterable<GHLicense> listLicenses() throws IOException {
|
||||
return new PagedIterable<GHLicense>() {
|
||||
public PagedIterator<GHLicense> _iterator(int pageSize) {
|
||||
return new PagedIterator<GHLicense>(retrieve().withPreview(DRAX).asIterator("/licenses", GHLicense[].class, pageSize)) {
|
||||
@Override
|
||||
protected void wrapUp(GHLicense[] page) {
|
||||
for (GHLicense c : page)
|
||||
c.wrap(GitHub.this);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full details for a license
|
||||
*
|
||||
* WARNING: This uses a PREVIEW API.
|
||||
*
|
||||
* @param key The license key provided from the API
|
||||
* @return The license details
|
||||
* @throws IOException
|
||||
* @see GHLicense#getKey()
|
||||
*/
|
||||
@Preview @Deprecated
|
||||
public GHLicense getLicense(String key) throws IOException {
|
||||
return retrieve().withPreview(DRAX).to("/licenses/" + key, GHLicense.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* This method returns a shallowly populated organizations.
|
||||
|
||||
@@ -30,6 +30,7 @@ public class GitHubBuilder {
|
||||
private HttpConnector connector;
|
||||
|
||||
private RateLimitHandler rateLimitHandler = RateLimitHandler.WAIT;
|
||||
private AbuseLimitHandler abuseLimitHandler = AbuseLimitHandler.WAIT;
|
||||
|
||||
public GitHubBuilder() {
|
||||
}
|
||||
@@ -178,6 +179,10 @@ public class GitHubBuilder {
|
||||
this.rateLimitHandler = handler;
|
||||
return this;
|
||||
}
|
||||
public GitHubBuilder withAbuseLimitHandler(AbuseLimitHandler handler) {
|
||||
this.abuseLimitHandler = handler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures {@linkplain #withConnector(HttpConnector) connector}
|
||||
@@ -193,6 +198,6 @@ public class GitHubBuilder {
|
||||
}
|
||||
|
||||
public GitHub build() throws IOException {
|
||||
return new GitHub(endpoint, user, oauthToken, password, connector, rateLimitHandler);
|
||||
return new GitHub(endpoint, user, oauthToken, password, connector, rateLimitHandler, abuseLimitHandler);
|
||||
}
|
||||
}
|
||||
|
||||
18
src/main/java/org/kohsuke/github/Preview.java
Normal file
18
src/main/java/org/kohsuke/github/Preview.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Indicates that the method/class/etc marked maps to GitHub API in the preview period.
|
||||
*
|
||||
* These APIs are subject to change and not a part of the backward compatibility commitment.
|
||||
* Always used in conjunction with 'deprecated' to raise awareness to clients.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Preview {
|
||||
}
|
||||
9
src/main/java/org/kohsuke/github/Previews.java
Normal file
9
src/main/java/org/kohsuke/github/Previews.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
/**
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
/*package*/ class Previews {
|
||||
static final String LOKI = "application/vnd.github.loki-preview+json";
|
||||
static final String DRAX = "application/vnd.github.drax-preview+json";
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import java.net.HttpURLConnection;
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GitHubBuilder#withRateLimitHandler(RateLimitHandler)
|
||||
* @see AbuseLimitHandler
|
||||
*/
|
||||
public abstract class RateLimitHandler {
|
||||
/**
|
||||
|
||||
@@ -46,7 +46,6 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
@@ -106,6 +105,15 @@ class Requester {
|
||||
headers.put(name,value);
|
||||
}
|
||||
|
||||
public Requester withHeader(String name, String value) {
|
||||
setHeader(name,value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/*package*/ Requester withPreview(String name) {
|
||||
return withHeader("Accept",name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request with authentication credential.
|
||||
*/
|
||||
@@ -463,6 +471,11 @@ class Requester {
|
||||
uc.setRequestProperty(e.getKey(), v);
|
||||
}
|
||||
|
||||
setRequestMethod(uc);
|
||||
uc.setRequestProperty("Accept-Encoding", "gzip");
|
||||
}
|
||||
|
||||
private void setRequestMethod(HttpURLConnection uc) throws IOException {
|
||||
try {
|
||||
uc.setRequestMethod(method);
|
||||
} catch (ProtocolException e) {
|
||||
@@ -474,8 +487,23 @@ class Requester {
|
||||
} catch (Exception x) {
|
||||
throw (IOException)new IOException("Failed to set the custom verb").initCause(x);
|
||||
}
|
||||
// sun.net.www.protocol.https.DelegatingHttpsURLConnection delegates to another HttpURLConnection
|
||||
try {
|
||||
Field $delegate = uc.getClass().getDeclaredField("delegate");
|
||||
$delegate.setAccessible(true);
|
||||
Object delegate = $delegate.get(uc);
|
||||
if (delegate instanceof HttpURLConnection) {
|
||||
HttpURLConnection nested = (HttpURLConnection) delegate;
|
||||
setRequestMethod(nested);
|
||||
}
|
||||
} catch (NoSuchFieldException x) {
|
||||
// no problem
|
||||
} catch (IllegalAccessException x) {
|
||||
throw (IOException)new IOException("Failed to set the custom verb").initCause(x);
|
||||
}
|
||||
}
|
||||
uc.setRequestProperty("Accept-Encoding", "gzip");
|
||||
if (!uc.getRequestMethod().equals(method))
|
||||
throw new IllegalStateException("Failed to set the request method to "+method);
|
||||
}
|
||||
|
||||
private <T> T parse(Class<T> type, T instance) throws IOException {
|
||||
@@ -488,6 +516,10 @@ class Requester {
|
||||
if (responseCode == 304) {
|
||||
return null; // special case handling for 304 unmodified, as the content will be ""
|
||||
}
|
||||
if (responseCode == 204 && type!=null && type.isArray()) {
|
||||
// no content
|
||||
return type.cast(Array.newInstance(type.getComponentType(),0));
|
||||
}
|
||||
|
||||
r = new InputStreamReader(wrapStream(uc.getInputStream()), "UTF-8");
|
||||
String data = IOUtils.toString(r);
|
||||
@@ -545,6 +577,13 @@ class Requester {
|
||||
return;
|
||||
}
|
||||
|
||||
// Retry-After is not documented but apparently that field exists
|
||||
if (responseCode == HttpURLConnection.HTTP_FORBIDDEN &&
|
||||
uc.getHeaderField("Retry-After") != null) {
|
||||
this.root.abuseLimitHandler.onError(e,uc);
|
||||
return;
|
||||
}
|
||||
|
||||
InputStream es = wrapStream(uc.getErrorStream());
|
||||
try {
|
||||
if (es!=null) {
|
||||
|
||||
16
src/main/java/org/kohsuke/github/SkipFromToString.java
Normal file
16
src/main/java/org/kohsuke/github/SkipFromToString.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Ignores this field for {@link GHObject#toString()}
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface SkipFromToString {
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import org.kohsuke.github.GHRepository;
|
||||
import org.kohsuke.github.GHRepository.Contributor;
|
||||
import org.kohsuke.github.GHUser;
|
||||
import org.kohsuke.github.GitHub;
|
||||
|
||||
@@ -9,11 +10,10 @@ import java.util.Collection;
|
||||
*/
|
||||
public class Foo {
|
||||
public static void main(String[] args) throws Exception {
|
||||
Collection<GHRepository> lst = GitHub.connect().getUser("kohsuke").getRepositories().values();
|
||||
for (GHRepository r : lst) {
|
||||
System.out.println(r.getName());
|
||||
GitHub gh = GitHub.connect();
|
||||
for (Contributor c : gh.getRepository("kohsuke/yo").listContributors()) {
|
||||
System.out.println(c);
|
||||
}
|
||||
System.out.println(lst.size());
|
||||
}
|
||||
|
||||
private static void testRateLimit() throws Exception {
|
||||
|
||||
@@ -14,6 +14,7 @@ import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@@ -39,7 +40,7 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRepositoryWithAutoInitializationCRUD() throws IOException {
|
||||
public void testRepositoryWithAutoInitializationCRUD() throws Exception {
|
||||
String name = "github-api-test-autoinit";
|
||||
deleteRepository(name);
|
||||
GHRepository r = gitHub.createRepository(name)
|
||||
@@ -49,6 +50,7 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
r.enableIssueTracker(false);
|
||||
r.enableDownloads(false);
|
||||
r.enableWiki(false);
|
||||
Thread.sleep(3000);
|
||||
assertNotNull(r.getReadme());
|
||||
getUser().getRepository(name).delete();
|
||||
}
|
||||
@@ -221,10 +223,12 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMyTeamsContainsAllMyOrganizations() throws IOException {
|
||||
public void testMyOrganizationsContainMyTeams() throws IOException {
|
||||
Map<String, Set<GHTeam>> teams = gitHub.getMyTeams();
|
||||
Map<String, GHOrganization> myOrganizations = gitHub.getMyOrganizations();
|
||||
assertEquals(teams.keySet(), myOrganizations.keySet());
|
||||
//GitHub no longer has default 'owners' team, so there may be organization memberships without a team
|
||||
//https://help.github.com/articles/about-improved-organization-permissions/
|
||||
assertTrue(myOrganizations.keySet().containsAll(teams.keySet()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -335,6 +339,13 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
assertNotNull(e);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrgTeamBySlug() throws Exception {
|
||||
kohsuke();
|
||||
GHTeam e = gitHub.getOrganization("github-api-test-org").getTeamBySlug("core-developers");
|
||||
assertNotNull(e);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommit() throws Exception {
|
||||
GHCommit commit = gitHub.getUser("jenkinsci").getRepository("jenkins").getCommit("08c1c9970af4d609ae754fbe803e06186e3206f7");
|
||||
@@ -592,6 +603,8 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
.prerelease(false)
|
||||
.create();
|
||||
|
||||
Thread.sleep(3000);
|
||||
|
||||
try {
|
||||
|
||||
for (GHTag tag : r.listTags()) {
|
||||
@@ -845,6 +858,18 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
gitHub.listNotifications().markAsRead();
|
||||
}
|
||||
|
||||
/**
|
||||
* Just basic code coverage to make sure toString() doesn't blow up
|
||||
*/
|
||||
@Test
|
||||
public void checkToString() throws Exception {
|
||||
GHUser u = gitHub.getUser("rails");
|
||||
System.out.println(u);
|
||||
GHRepository r = u.getRepository("rails");
|
||||
System.out.println(r);
|
||||
System.out.println(r.getIssue(1));
|
||||
}
|
||||
|
||||
private void kohsuke() {
|
||||
String login = getUser().getLogin();
|
||||
Assume.assumeTrue(login.equals("kohsuke") || login.equals("kohsuke2"));
|
||||
|
||||
@@ -20,6 +20,13 @@ public class GHContentIntegrationTest extends AbstractGitHubApiTestBase {
|
||||
repo = gitHub.getRepository("github-api-test-org/GHContentIntegrationTest").fork();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBranchProtection() throws Exception {
|
||||
GHBranch b = repo.getBranch("master");
|
||||
b.enableProtection(EnforcementLevel.NON_ADMINS, "foo/bar");
|
||||
b.disableProtection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFileContent() throws Exception {
|
||||
GHContent content = repo.getFileContent("ghcontent-ro/a-file-with-content");
|
||||
|
||||
193
src/test/java/org/kohsuke/github/GHLicenseTest.java
Normal file
193
src/test/java/org/kohsuke/github/GHLicenseTest.java
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2016, Duncan Dickinson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.kohsuke.github;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* @author Duncan Dickinson
|
||||
*/
|
||||
public class GHLicenseTest extends Assert {
|
||||
private GitHub gitHub;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
gitHub = new GitHubBuilder()
|
||||
.fromCredentials()
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic test to ensure that the list of licenses from {@link GitHub#listLicenses()} is returned
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void listLicenses() throws IOException {
|
||||
Iterable<GHLicense> licenses = gitHub.listLicenses();
|
||||
assertTrue(licenses.iterator().hasNext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that {@link GitHub#listLicenses()} returns the MIT license
|
||||
* in the expected manner.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void listLicensesCheckIndividualLicense() throws IOException {
|
||||
PagedIterable<GHLicense> licenses = gitHub.listLicenses();
|
||||
for (GHLicense lic : licenses) {
|
||||
if (lic.getKey().equals("mit")) {
|
||||
assertTrue(lic.getUrl().equals(new URL("https://api.github.com/licenses/mit")));
|
||||
return;
|
||||
}
|
||||
}
|
||||
fail("The MIT license was not found");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the request for an individual license using {@link GitHub#getLicense(String)}
|
||||
* returns expected values (not all properties are checked)
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void getLicense() throws IOException {
|
||||
String key = "mit";
|
||||
GHLicense license = gitHub.getLicense(key);
|
||||
assertNotNull(license);
|
||||
assertTrue("The name is correct", license.getName().equals("MIT License"));
|
||||
assertTrue("The HTML URL is correct", license.getHtmlUrl().equals(new URL("http://choosealicense.com/licenses/mit/")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Accesses the 'kohsuke/github-api' repo using {@link GitHub#getRepository(String)}
|
||||
* and checks that the license is correct
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void checkRepositoryLicense() throws IOException {
|
||||
GHRepository repo = gitHub.getRepository("kohsuke/github-api");
|
||||
GHLicense license = repo.getLicense();
|
||||
assertNotNull("The license is populated", license);
|
||||
assertTrue("The key is correct", license.getKey().equals("mit"));
|
||||
assertTrue("The name is correct", license.getName().equals("MIT License"));
|
||||
assertTrue("The URL is correct", license.getUrl().equals(new URL("https://api.github.com/licenses/mit")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Accesses the 'atom/atom' repo using {@link GitHub#getRepository(String)}
|
||||
* and checks that the license is correct
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void checkRepositoryLicenseAtom() throws IOException {
|
||||
GHRepository repo = gitHub.getRepository("atom/atom");
|
||||
GHLicense license = repo.getLicense();
|
||||
assertNotNull("The license is populated", license);
|
||||
assertTrue("The key is correct", license.getKey().equals("mit"));
|
||||
assertTrue("The name is correct", license.getName().equals("MIT License"));
|
||||
assertTrue("The URL is correct", license.getUrl().equals(new URL("https://api.github.com/licenses/mit")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Accesses the 'pomes/pomes' repo using {@link GitHub#getRepository(String)}
|
||||
* and checks that the license is correct
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void checkRepositoryLicensePomes() throws IOException {
|
||||
GHRepository repo = gitHub.getRepository("pomes/pomes");
|
||||
GHLicense license = repo.getLicense();
|
||||
assertNotNull("The license is populated", license);
|
||||
assertTrue("The key is correct", license.getKey().equals("apache-2.0"));
|
||||
assertTrue("The name is correct", license.getName().equals("Apache License 2.0"));
|
||||
assertTrue("The URL is correct", license.getUrl().equals(new URL("https://api.github.com/licenses/apache-2.0")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Accesses the 'dedickinson/test-repo' repo using {@link GitHub#getRepository(String)}
|
||||
* and checks that *no* license is returned as the repo doesn't have one
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void checkRepositoryWithoutLicense() throws IOException {
|
||||
GHRepository repo = gitHub.getRepository("dedickinson/test-repo");
|
||||
GHLicense license = repo.getLicense();
|
||||
assertNull("There is no license", license);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accesses the 'kohsuke/github-api' repo using {@link GitHub#getRepository(String)}
|
||||
* and then calls {@link GHRepository#getLicense()} and checks that certain
|
||||
* properties are correct
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void checkRepositoryFullLicense() throws IOException {
|
||||
GHRepository repo = gitHub.getRepository("kohsuke/github-api");
|
||||
GHLicense license = repo.getLicense();
|
||||
assertNotNull("The license is populated", license);
|
||||
assertTrue("The key is correct", license.getKey().equals("mit"));
|
||||
assertTrue("The name is correct", license.getName().equals("MIT License"));
|
||||
assertTrue("The URL is correct", license.getUrl().equals(new URL("https://api.github.com/licenses/mit")));
|
||||
assertTrue("The HTML URL is correct", license.getHtmlUrl().equals(new URL("http://choosealicense.com/licenses/mit/")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Accesses the 'pomes/pomes' repo using {@link GitHub#getRepository(String)}
|
||||
* and then calls {@link GHRepository#getLicenseContent()} and checks that certain
|
||||
* properties are correct
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void checkRepositoryLicenseContent() throws IOException {
|
||||
GHRepository repo = gitHub.getRepository("pomes/pomes");
|
||||
GHContent content = repo.getLicenseContent();
|
||||
assertNotNull("The license content is populated", content);
|
||||
assertTrue("The type is 'file'", content.getType().equals("file"));
|
||||
assertTrue("The license file is 'LICENSE'", content.getName().equals("LICENSE"));
|
||||
|
||||
if (content.getEncoding().equals("base64")) {
|
||||
String licenseText = new String(IOUtils.toByteArray(content.read()));
|
||||
assertTrue("The license appears to be an Apache License", licenseText.contains("Apache License"));
|
||||
} else {
|
||||
fail("Expected the license to be Base64 encoded but instead it was " + content.getEncoding());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,4 +50,12 @@ public class RepositoryTest extends AbstractGitHubApiTestBase {
|
||||
String mainLanguage = r.getLanguage();
|
||||
assertTrue(r.listLanguages().containsKey(mainLanguage));
|
||||
}
|
||||
|
||||
@Test // Issue #261
|
||||
public void listEmptyContributors() throws IOException {
|
||||
GitHub gh = GitHub.connect();
|
||||
for (Contributor c : gh.getRepository("github-api-test-org/empty").listContributors()) {
|
||||
System.out.println(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user