mirror of
https://github.com/jlengrand/github-api.git
synced 2026-03-11 08:21:23 +00:00
Compare commits
126 Commits
github-api
...
github-api
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47409a9a99 | ||
|
|
60bfea2d3b | ||
|
|
d3ed8eaed5 | ||
|
|
692dccf110 | ||
|
|
92caf98683 | ||
|
|
6178d38895 | ||
|
|
40fb38a9ba | ||
|
|
20e68d53fd | ||
|
|
2d3557e049 | ||
|
|
d8f4bc7395 | ||
|
|
353f9bb809 | ||
|
|
ccfe3ad4f7 | ||
|
|
9012820c03 | ||
|
|
fe2af19e42 | ||
|
|
f721e053f1 | ||
|
|
e6ad9feb84 | ||
|
|
635350c40e | ||
|
|
17edd33703 | ||
|
|
b0f2a871c6 | ||
|
|
8928a8a1dc | ||
|
|
2b6f37a6cc | ||
|
|
f3a3b87861 | ||
|
|
9cf6ee78d4 | ||
|
|
bbc2f3962f | ||
|
|
be49eb22d2 | ||
|
|
fb47067215 | ||
|
|
2c80ef178d | ||
|
|
9af8112148 | ||
|
|
57c36f437a | ||
|
|
5ed8a34566 | ||
|
|
ea8df9bd61 | ||
|
|
b0c51e03b7 | ||
|
|
336924ef23 | ||
|
|
ad28ca4a90 | ||
|
|
aebbe86cfc | ||
|
|
df9faf4943 | ||
|
|
3e295b6be4 | ||
|
|
8dd6dbf995 | ||
|
|
612139f2ff | ||
|
|
240bcabb76 | ||
|
|
cda27d5963 | ||
|
|
2f8c3997f7 | ||
|
|
46b89a48db | ||
|
|
5c9cbee2f9 | ||
|
|
ee8973c239 | ||
|
|
2e2813f363 | ||
|
|
7ceca0769f | ||
|
|
4d277cc61f | ||
|
|
e67fbb4621 | ||
|
|
29b5357ceb | ||
|
|
9dabec107b | ||
|
|
f2a2ad90b7 | ||
|
|
cfe4c0c510 | ||
|
|
23cd51a6da | ||
|
|
7396395f90 | ||
|
|
a1819bf232 | ||
|
|
8accf07d46 | ||
|
|
6dcbace572 | ||
|
|
e90c86ec2f | ||
|
|
971ae1fa4d | ||
|
|
4abe87036c | ||
|
|
8d1b44db97 | ||
|
|
b537f9925b | ||
|
|
f2fe8eaf86 | ||
|
|
46715cac08 | ||
|
|
0f21eba57f | ||
|
|
cb7620395a | ||
|
|
3a40af8871 | ||
|
|
c9b5074bc4 | ||
|
|
44d4d0d767 | ||
|
|
64af13f40d | ||
|
|
e9b59c6bef | ||
|
|
3d03659508 | ||
|
|
0374d2de48 | ||
|
|
2627dc5ee4 | ||
|
|
5554332b5b | ||
|
|
1cffea892b | ||
|
|
fd859815b0 | ||
|
|
166e26d101 | ||
|
|
be081eec3f | ||
|
|
55b00a87f6 | ||
|
|
429b26cee8 | ||
|
|
fafe6b0ff7 | ||
|
|
5b156006fb | ||
|
|
75f0c08ca4 | ||
|
|
1f4325e7db | ||
|
|
f2e7b40425 | ||
|
|
4ee3086b6d | ||
|
|
a3a715c3ba | ||
|
|
6cad4a3c33 | ||
|
|
b9b6f4fd44 | ||
|
|
17d1994a53 | ||
|
|
13184e72e1 | ||
|
|
911e8d21a7 | ||
|
|
5b69a2925f | ||
|
|
d1c900a620 | ||
|
|
6bfeb54f3c | ||
|
|
198fede915 | ||
|
|
1212ae3eb3 | ||
|
|
1266dcc0c7 | ||
|
|
6fcddf4a47 | ||
|
|
dfea424b94 | ||
|
|
9d03435aa1 | ||
|
|
26c20a7a22 | ||
|
|
470da06ecf | ||
|
|
a746a310bc | ||
|
|
3dbb516084 | ||
|
|
32177283b3 | ||
|
|
3a66e90b7a | ||
|
|
a454fb10ec | ||
|
|
b5386a35ee | ||
|
|
11651da411 | ||
|
|
88d52c44ad | ||
|
|
2d7d4bbd4e | ||
|
|
e6ee278fde | ||
|
|
6380cf9ed0 | ||
|
|
2e78dc52c7 | ||
|
|
ccb42d3249 | ||
|
|
c5009ab44b | ||
|
|
9d15cd43a3 | ||
|
|
0780e10fa2 | ||
|
|
0731f63237 | ||
|
|
a29896042b | ||
|
|
68ebc08c9d | ||
|
|
a1df526f93 | ||
|
|
9f3f644b83 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -3,3 +3,7 @@ target
|
|||||||
*.iml
|
*.iml
|
||||||
*.ipr
|
*.ipr
|
||||||
*.iws
|
*.iws
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
.settings/
|
||||||
|
.DS_Store
|
||||||
|
|||||||
24
pom.xml
24
pom.xml
@@ -3,11 +3,11 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.kohsuke</groupId>
|
<groupId>org.kohsuke</groupId>
|
||||||
<artifactId>pom</artifactId>
|
<artifactId>pom</artifactId>
|
||||||
<version>14</version>
|
<version>17</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>github-api</artifactId>
|
<artifactId>github-api</artifactId>
|
||||||
<version>1.81</version>
|
<version>1.89</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.81</tag>
|
<tag>github-api-1.89</tag>
|
||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
<distributionManagement>
|
<distributionManagement>
|
||||||
@@ -34,6 +34,12 @@
|
|||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<rerunFailingTestsCount>2</rerunFailingTestsCount>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>animal-sniffer-maven-plugin</artifactId>
|
<artifactId>animal-sniffer-maven-plugin</artifactId>
|
||||||
@@ -105,6 +111,12 @@
|
|||||||
<version>4.11</version>
|
<version>4.11</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hamcrest</groupId>
|
||||||
|
<artifactId>hamcrest-all</artifactId>
|
||||||
|
<version>1.3</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
@@ -138,6 +150,12 @@
|
|||||||
<version>2.7.5</version>
|
<version>2.7.5</version>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
<artifactId>okhttp-urlconnection</artifactId>
|
||||||
|
<version>3.4.0</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.kohsuke</groupId>
|
<groupId>org.kohsuke</groupId>
|
||||||
<artifactId>wordnet-random-name</artifactId>
|
<artifactId>wordnet-random-name</artifactId>
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
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>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,8 +3,11 @@ package org.kohsuke.github;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* This was added during preview API period but it has changed since then.
|
||||||
|
*
|
||||||
* @author Kohsuke Kawaguchi
|
* @author Kohsuke Kawaguchi
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public enum EnforcementLevel {
|
public enum EnforcementLevel {
|
||||||
OFF, NON_ADMINS, EVERYONE;
|
OFF, NON_ADMINS, EVERYONE;
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
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.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
64
src/main/java/org/kohsuke/github/GHBlob.java
Normal file
64
src/main/java/org/kohsuke/github/GHBlob.java
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Base64InputStream;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kanstantsin Shautsou
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
* @see GHTreeEntry#asBlob()
|
||||||
|
* @see GHRepository#getBlob(String)
|
||||||
|
* @see <a href="https://developer.github.com/v3/git/blobs/#get-a-blob">Get a blob</a>
|
||||||
|
*/
|
||||||
|
public class GHBlob {
|
||||||
|
private String content, encoding, url, sha;
|
||||||
|
private long size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API URL of this blob.
|
||||||
|
*/
|
||||||
|
public URL getUrl() {
|
||||||
|
return GitHub.parseURL(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSha() {
|
||||||
|
return sha;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of bytes in this blob.
|
||||||
|
*/
|
||||||
|
public long getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEncoding() {
|
||||||
|
return encoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encoded content. You probably want {@link #read()}
|
||||||
|
*/
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the actual bytes of the blob.
|
||||||
|
*/
|
||||||
|
public InputStream read() {
|
||||||
|
if (encoding.equals("base64")) {
|
||||||
|
try {
|
||||||
|
return new Base64InputStream(new ByteArrayInputStream(content.getBytes("US-ASCII")), false);
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new AssertionError(e); // US-ASCII is mandatory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException("Unrecognized encoding: "+encoding);
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/main/java/org/kohsuke/github/GHBlobBuilder.java
Normal file
49
src/main/java/org/kohsuke/github/GHBlobBuilder.java
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder pattern for creating a new blob.
|
||||||
|
* Based on https://developer.github.com/v3/git/blobs/#create-a-blob
|
||||||
|
*/
|
||||||
|
public class GHBlobBuilder {
|
||||||
|
private final GHRepository repo;
|
||||||
|
private final Requester req;
|
||||||
|
|
||||||
|
GHBlobBuilder(GHRepository repo) {
|
||||||
|
this.repo = repo;
|
||||||
|
req = new Requester(repo.root);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures a blob with the specified text {@code content}.
|
||||||
|
*/
|
||||||
|
public GHBlobBuilder textContent(String content) {
|
||||||
|
req.with("content", content);
|
||||||
|
req.with("encoding", "utf-8");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures a blob with the specified binary {@code content}.
|
||||||
|
*/
|
||||||
|
public GHBlobBuilder binaryContent(byte[] content) {
|
||||||
|
String base64Content = Base64.encodeBase64String(content);
|
||||||
|
req.with("content", base64Content);
|
||||||
|
req.with("encoding", "base64");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getApiTail() {
|
||||||
|
return String.format("/repos/%s/%s/git/blobs", repo.getOwnerName(), repo.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a blob based on the parameters specified thus far.
|
||||||
|
*/
|
||||||
|
public GHBlob create() throws IOException {
|
||||||
|
return req.method("POST").to(getApiTail(), GHBlob.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,20 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
import org.kohsuke.github.BranchProtection.RequiredStatusChecks;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.net.URL;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import static org.kohsuke.github.Previews.LOKI;
|
import static org.kohsuke.github.Previews.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A branch in a repository.
|
* A branch in a repository.
|
||||||
*
|
*
|
||||||
* @author Yusuke Kokubo
|
* @author Yusuke Kokubo
|
||||||
*/
|
*/
|
||||||
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
|
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
|
||||||
"NP_UNWRITTEN_FIELD", "URF_UNREAD_FIELD"}, justification = "JSON API")
|
"NP_UNWRITTEN_FIELD", "URF_UNREAD_FIELD"}, justification = "JSON API")
|
||||||
public class GHBranch {
|
public class GHBranch {
|
||||||
private GitHub root;
|
private GitHub root;
|
||||||
@@ -22,10 +22,14 @@ public class GHBranch {
|
|||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private Commit commit;
|
private Commit commit;
|
||||||
|
@JsonProperty("protected")
|
||||||
|
private boolean protection;
|
||||||
|
private String protection_url;
|
||||||
|
|
||||||
|
|
||||||
public static class Commit {
|
public static class Commit {
|
||||||
String sha;
|
String sha;
|
||||||
|
|
||||||
@SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now")
|
@SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now")
|
||||||
String url;
|
String url;
|
||||||
}
|
}
|
||||||
@@ -45,6 +49,27 @@ public class GHBranch {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the push to this branch is restricted via branch protection.
|
||||||
|
*/
|
||||||
|
@Preview @Deprecated
|
||||||
|
public boolean isProtected() {
|
||||||
|
return protection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns API URL that deals with the protection of this branch.
|
||||||
|
*/
|
||||||
|
@Preview @Deprecated
|
||||||
|
public URL getProtectionUrl() {
|
||||||
|
return GitHub.parseURL(protection_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview @Deprecated
|
||||||
|
public GHBranchProtection getProtection() throws IOException {
|
||||||
|
return root.retrieve().withPreview(LOKI).to(protection_url, GHBranchProtection.class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The commit that this branch currently points to.
|
* The commit that this branch currently points to.
|
||||||
*/
|
*/
|
||||||
@@ -57,9 +82,7 @@ public class GHBranch {
|
|||||||
*/
|
*/
|
||||||
@Preview @Deprecated
|
@Preview @Deprecated
|
||||||
public void disableProtection() throws IOException {
|
public void disableProtection() throws IOException {
|
||||||
BranchProtection bp = new BranchProtection();
|
new Requester(root).method("DELETE").withPreview(LOKI).to(protection_url);
|
||||||
bp.enabled = false;
|
|
||||||
setProtection(bp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,28 +91,31 @@ public class GHBranch {
|
|||||||
* @see GHCommitStatus#getContext()
|
* @see GHCommitStatus#getContext()
|
||||||
*/
|
*/
|
||||||
@Preview @Deprecated
|
@Preview @Deprecated
|
||||||
|
public GHBranchProtectionBuilder enableProtection() {
|
||||||
|
return new GHBranchProtectionBuilder(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// backward compatibility with previous signature
|
||||||
|
@Deprecated
|
||||||
public void enableProtection(EnforcementLevel level, Collection<String> contexts) throws IOException {
|
public void enableProtection(EnforcementLevel level, Collection<String> contexts) throws IOException {
|
||||||
BranchProtection bp = new BranchProtection();
|
switch (level) {
|
||||||
bp.enabled = true;
|
case OFF:
|
||||||
bp.requiredStatusChecks = new RequiredStatusChecks();
|
disableProtection();
|
||||||
bp.requiredStatusChecks.enforcement_level = level;
|
break;
|
||||||
bp.requiredStatusChecks.contexts.addAll(contexts);
|
case NON_ADMINS:
|
||||||
setProtection(bp);
|
case EVERYONE:
|
||||||
}
|
enableProtection()
|
||||||
|
.addRequiredChecks(contexts)
|
||||||
@Preview @Deprecated
|
.includeAdmins(level==EnforcementLevel.EVERYONE)
|
||||||
public void enableProtection(EnforcementLevel level, String... contexts) throws IOException {
|
.enable();
|
||||||
enableProtection(level, Arrays.asList(contexts));
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setProtection(BranchProtection bp) throws IOException {
|
|
||||||
new Requester(root).method("PATCH").withPreview(LOKI)._with("protection",bp).to(getApiRoute());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String getApiRoute() {
|
String getApiRoute() {
|
||||||
return owner.getApiTailUrl("/branches/"+name);
|
return owner.getApiTailUrl("/branches/"+name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
final String url = owner != null ? owner.getUrl().toString() : "unknown";
|
final String url = owner != null ? owner.getUrl().toString() : "unknown";
|
||||||
|
|||||||
151
src/main/java/org/kohsuke/github/GHBranchProtection.java
Normal file
151
src/main/java/org/kohsuke/github/GHBranchProtection.java
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@SuppressFBWarnings(value = { "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD",
|
||||||
|
"URF_UNREAD_FIELD" }, justification = "JSON API")
|
||||||
|
public class GHBranchProtection {
|
||||||
|
@JsonProperty("enforce_admins")
|
||||||
|
private EnforceAdmins enforceAdmins;
|
||||||
|
|
||||||
|
@JsonProperty("required_pull_request_reviews")
|
||||||
|
private RequiredReviews requiredReviews;
|
||||||
|
|
||||||
|
@JsonProperty("required_status_checks")
|
||||||
|
private RequiredStatusChecks requiredStatusChecks;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private Restrictions restrictions;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
public EnforceAdmins getEnforceAdmins() {
|
||||||
|
return enforceAdmins;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RequiredReviews getRequiredReviews() {
|
||||||
|
return requiredReviews;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RequiredStatusChecks getRequiredStatusChecks() {
|
||||||
|
return requiredStatusChecks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Restrictions getRestrictions() {
|
||||||
|
return restrictions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EnforceAdmins {
|
||||||
|
@JsonProperty
|
||||||
|
private boolean enabled;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RequiredReviews {
|
||||||
|
@JsonProperty("dismissal_restrictions")
|
||||||
|
private Restrictions dismissalRestriction;
|
||||||
|
|
||||||
|
@JsonProperty("dismiss_stale_reviews")
|
||||||
|
private boolean dismissStaleReviews;
|
||||||
|
|
||||||
|
@JsonProperty("require_code_owner_reviews")
|
||||||
|
private boolean requireCodeOwnerReviews;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
public Restrictions getDismissalRestrictions() {
|
||||||
|
return dismissalRestriction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDismissStaleReviews() {
|
||||||
|
return dismissStaleReviews;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRequireCodeOwnerReviews() {
|
||||||
|
return requireCodeOwnerReviews;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RequiredStatusChecks {
|
||||||
|
@JsonProperty
|
||||||
|
private Collection<String> contexts;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private boolean strict;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
public Collection<String> getContexts() {
|
||||||
|
return contexts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRequiresBranchUpToDate() {
|
||||||
|
return strict;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Restrictions {
|
||||||
|
@JsonProperty
|
||||||
|
private Collection<GHTeam> teams;
|
||||||
|
|
||||||
|
@JsonProperty("teams_url")
|
||||||
|
private String teamsUrl;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private Collection<GHUser> users;
|
||||||
|
|
||||||
|
@JsonProperty("users_url")
|
||||||
|
private String usersUrl;
|
||||||
|
|
||||||
|
public Collection<GHTeam> getTeams() {
|
||||||
|
return teams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTeamsUrl() {
|
||||||
|
return teamsUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<GHUser> getUsers() {
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsersUrl() {
|
||||||
|
return usersUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
203
src/main/java/org/kohsuke/github/GHBranchProtectionBuilder.java
Normal file
203
src/main/java/org/kohsuke/github/GHBranchProtectionBuilder.java
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.kohsuke.github.Previews.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder to configure the branch protection settings.
|
||||||
|
*
|
||||||
|
* @see GHBranch#enableProtection()
|
||||||
|
*/
|
||||||
|
@SuppressFBWarnings(value = { "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD",
|
||||||
|
"URF_UNREAD_FIELD" }, justification = "JSON API")
|
||||||
|
public class GHBranchProtectionBuilder {
|
||||||
|
private final GHBranch branch;
|
||||||
|
|
||||||
|
private boolean enforceAdmins;
|
||||||
|
private Map<String, Object> prReviews;
|
||||||
|
private Restrictions restrictions;
|
||||||
|
private StatusChecks statusChecks;
|
||||||
|
|
||||||
|
GHBranchProtectionBuilder(GHBranch branch) {
|
||||||
|
this.branch = branch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder addRequiredChecks(Collection<String> checks) {
|
||||||
|
getStatusChecks().contexts.addAll(checks);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder addRequiredChecks(String... checks) {
|
||||||
|
addRequiredChecks(Arrays.asList(checks));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder dismissStaleReviews() {
|
||||||
|
getPrReviews().put("dismiss_stale_reviews", true);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtection enable() throws IOException {
|
||||||
|
return requester().method("PUT")
|
||||||
|
.withNullable("required_status_checks", statusChecks)
|
||||||
|
.withNullable("required_pull_request_reviews", prReviews)
|
||||||
|
.withNullable("restrictions", restrictions)
|
||||||
|
.withNullable("enforce_admins", enforceAdmins)
|
||||||
|
.to(branch.getProtectionUrl().toString(), GHBranchProtection.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder includeAdmins() {
|
||||||
|
return includeAdmins(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder includeAdmins(boolean v) {
|
||||||
|
enforceAdmins = v;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder requireBranchIsUpToDate() {
|
||||||
|
return requireBranchIsUpToDate(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder requireBranchIsUpToDate(boolean v) {
|
||||||
|
getStatusChecks().strict = v;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder requireCodeOwnReviews() {
|
||||||
|
return requireCodeOwnReviews(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder requireCodeOwnReviews(boolean v) {
|
||||||
|
getPrReviews().put("require_code_owner_reviews", v);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder requireReviews() {
|
||||||
|
getPrReviews();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder restrictPushAccess() {
|
||||||
|
getRestrictions();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder teamPushAccess(Collection<GHTeam> teams) {
|
||||||
|
for (GHTeam team : teams) {
|
||||||
|
teamPushAccess(team);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder teamPushAccess(GHTeam... teams) {
|
||||||
|
for (GHTeam team : teams) {
|
||||||
|
getRestrictions().teams.add(team.getSlug());
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder teamReviewDismissals(Collection<GHTeam> teams) {
|
||||||
|
for (GHTeam team : teams) {
|
||||||
|
teamReviewDismissals(team);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder teamReviewDismissals(GHTeam... teams) {
|
||||||
|
for (GHTeam team : teams) {
|
||||||
|
addReviewRestriction(team.getSlug(), true);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder userPushAccess(Collection<GHUser> users) {
|
||||||
|
for (GHUser user : users) {
|
||||||
|
userPushAccess(user);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder userPushAccess(GHUser... users) {
|
||||||
|
for (GHUser user : users) {
|
||||||
|
getRestrictions().users.add(user.getLogin());
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder userReviewDismissals(Collection<GHUser> users) {
|
||||||
|
for (GHUser team : users) {
|
||||||
|
userReviewDismissals(team);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBranchProtectionBuilder userReviewDismissals(GHUser... users) {
|
||||||
|
for (GHUser user : users) {
|
||||||
|
addReviewRestriction(user.getLogin(), false);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addReviewRestriction(String restriction, boolean isTeam) {
|
||||||
|
getPrReviews();
|
||||||
|
|
||||||
|
if (!prReviews.containsKey("dismissal_restrictions")) {
|
||||||
|
prReviews.put("dismissal_restrictions", new Restrictions());
|
||||||
|
}
|
||||||
|
|
||||||
|
Restrictions restrictions = (Restrictions) prReviews.get("dismissal_restrictions");
|
||||||
|
|
||||||
|
if (isTeam) {
|
||||||
|
restrictions.teams.add(restriction);
|
||||||
|
} else {
|
||||||
|
restrictions.users.add(restriction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> getPrReviews() {
|
||||||
|
if (prReviews == null) {
|
||||||
|
prReviews = new HashMap<String, Object>();
|
||||||
|
}
|
||||||
|
return prReviews;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Restrictions getRestrictions() {
|
||||||
|
if (restrictions == null) {
|
||||||
|
restrictions = new Restrictions();
|
||||||
|
}
|
||||||
|
return restrictions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private StatusChecks getStatusChecks() {
|
||||||
|
if (statusChecks == null) {
|
||||||
|
statusChecks = new StatusChecks();
|
||||||
|
}
|
||||||
|
return statusChecks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Requester requester() {
|
||||||
|
return new Requester(branch.getRoot()).withPreview(LOKI);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Restrictions {
|
||||||
|
private Set<String> teams = new HashSet<String>();
|
||||||
|
private Set<String> users = new HashSet<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class StatusChecks {
|
||||||
|
final List<String> contexts = new ArrayList<String>();
|
||||||
|
boolean strict;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package org.kohsuke.github;
|
|||||||
|
|
||||||
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 java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.AbstractList;
|
import java.util.AbstractList;
|
||||||
@@ -37,6 +38,12 @@ public class GHCommit {
|
|||||||
|
|
||||||
private int comment_count;
|
private int comment_count;
|
||||||
|
|
||||||
|
static class Tree {
|
||||||
|
String sha;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Tree tree;
|
||||||
|
|
||||||
@WithBridgeMethods(value = GHAuthor.class, castRequired = true)
|
@WithBridgeMethods(value = GHAuthor.class, castRequired = true)
|
||||||
public GitUser getAuthor() {
|
public GitUser getAuthor() {
|
||||||
return author;
|
return author;
|
||||||
@@ -224,6 +231,13 @@ public class GHCommit {
|
|||||||
return stats.deletions;
|
return stats.deletions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this method to walk the tree
|
||||||
|
*/
|
||||||
|
public GHTree getTree() throws IOException {
|
||||||
|
return owner.getTree(getCommitShortInfo().tree.sha);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL of this commit like "https://github.com/kohsuke/sandbox-ant/commit/8ae38db0ea5837313ab5f39d43a6f73de3bd9000"
|
* URL of this commit like "https://github.com/kohsuke/sandbox-ant/commit/8ae38db0ea5837313ab5f39d43a6f73de3bd9000"
|
||||||
*/
|
*/
|
||||||
|
|||||||
92
src/main/java/org/kohsuke/github/GHCommitBuilder.java
Normal file
92
src/main/java/org/kohsuke/github/GHCommitBuilder.java
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder pattern for creating a new commit.
|
||||||
|
* Based on https://developer.github.com/v3/git/commits/#create-a-commit
|
||||||
|
*/
|
||||||
|
public class GHCommitBuilder {
|
||||||
|
private final GHRepository repo;
|
||||||
|
private final Requester req;
|
||||||
|
|
||||||
|
private final List<String> parents = new ArrayList<String>();
|
||||||
|
|
||||||
|
private static final class UserInfo {
|
||||||
|
private final String name;
|
||||||
|
private final String email;
|
||||||
|
private final String date;
|
||||||
|
|
||||||
|
private UserInfo(String name, String email, Date date) {
|
||||||
|
this.name = name;
|
||||||
|
this.email = email;
|
||||||
|
TimeZone tz = TimeZone.getTimeZone("UTC");
|
||||||
|
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||||
|
df.setTimeZone(tz);
|
||||||
|
this.date = df.format((date != null) ? date : new Date());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GHCommitBuilder(GHRepository repo) {
|
||||||
|
this.repo = repo;
|
||||||
|
req = new Requester(repo.root);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param message the commit message
|
||||||
|
*/
|
||||||
|
public GHCommitBuilder message(String message) {
|
||||||
|
req.with("message", message);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tree the SHA of the tree object this commit points to
|
||||||
|
*/
|
||||||
|
public GHCommitBuilder tree(String tree) {
|
||||||
|
req.with("tree", tree);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param parent the SHA of a parent commit.
|
||||||
|
*/
|
||||||
|
public GHCommitBuilder parent(String parent) {
|
||||||
|
parents.add(parent);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the author of this commit.
|
||||||
|
*/
|
||||||
|
public GHCommitBuilder author(String name, String email, Date date) {
|
||||||
|
req._with("author", new UserInfo(name, email, date));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the committer of this commit.
|
||||||
|
*/
|
||||||
|
public GHCommitBuilder committer(String name, String email, Date date) {
|
||||||
|
req._with("committer", new UserInfo(name, email, date));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getApiTail() {
|
||||||
|
return String.format("/repos/%s/%s/git/commits", repo.getOwnerName(), repo.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a blob based on the parameters specified thus far.
|
||||||
|
*/
|
||||||
|
public GHCommit create() throws IOException {
|
||||||
|
req._with("parents", parents);
|
||||||
|
return req.method("POST").to(getApiTail(), GHCommit.class).wrapUp(repo);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import static org.kohsuke.github.Previews.SQUIRREL_GIRL;
|
import static org.kohsuke.github.Previews.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A comment attached to a commit (or a specific line in a specific file of a commit.)
|
* A comment attached to a commit (or a specific line in a specific file of a commit.)
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ public class GHCommitPointer {
|
|||||||
* This points to the user who owns
|
* This points to the user who owns
|
||||||
* the {@link #getRepository()}.
|
* the {@link #getRepository()}.
|
||||||
*/
|
*/
|
||||||
public GHUser getUser() {
|
public GHUser getUser() throws IOException {
|
||||||
|
if (user != null) return user.root.intern(user);
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
137
src/main/java/org/kohsuke/github/GHCommitSearchBuilder.java
Normal file
137
src/main/java/org/kohsuke/github/GHCommitSearchBuilder.java
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search commits.
|
||||||
|
*
|
||||||
|
* @author Marc de Verdelhan
|
||||||
|
* @see GitHub#searchCommits()
|
||||||
|
*/
|
||||||
|
@Preview @Deprecated
|
||||||
|
public class GHCommitSearchBuilder extends GHSearchBuilder<GHCommit> {
|
||||||
|
/*package*/ GHCommitSearchBuilder(GitHub root) {
|
||||||
|
super(root,CommitSearchResult.class);
|
||||||
|
req.withPreview(Previews.CLOAK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search terms.
|
||||||
|
*/
|
||||||
|
public GHCommitSearchBuilder q(String term) {
|
||||||
|
super.q(term);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder author(String v) {
|
||||||
|
return q("author:"+v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder committer(String v) {
|
||||||
|
return q("committer:"+v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder authorName(String v) {
|
||||||
|
return q("author-name:"+v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder committerName(String v) {
|
||||||
|
return q("committer-name:"+v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder authorEmail(String v) {
|
||||||
|
return q("author-email:"+v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder committerEmail(String v) {
|
||||||
|
return q("committer-email:"+v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder authorDate(String v) {
|
||||||
|
return q("author-date:"+v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder committerDate(String v) {
|
||||||
|
return q("committer-date:"+v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder merge(boolean merge) {
|
||||||
|
return q("merge:"+Boolean.valueOf(merge).toString().toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder hash(String v) {
|
||||||
|
return q("hash:"+v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder parent(String v) {
|
||||||
|
return q("parent:"+v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder tree(String v) {
|
||||||
|
return q("tree:"+v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder is(String v) {
|
||||||
|
return q("is:"+v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder user(String v) {
|
||||||
|
return q("user:"+v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder org(String v) {
|
||||||
|
return q("org:"+v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder repo(String v) {
|
||||||
|
return q("repo:"+v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder order(GHDirection v) {
|
||||||
|
req.with("order",v);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitSearchBuilder sort(Sort sort) {
|
||||||
|
req.with("sort",sort);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Sort { AUTHOR_DATE, COMMITTER_DATE }
|
||||||
|
|
||||||
|
private static class CommitSearchResult extends SearchResult<GHCommit> {
|
||||||
|
private GHCommit[] items;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
/*package*/ GHCommit[] getItems(GitHub root) {
|
||||||
|
for (GHCommit commit : items) {
|
||||||
|
String repoName = getRepoName(commit.url);
|
||||||
|
try {
|
||||||
|
GHRepository repo = root.getRepository(repoName);
|
||||||
|
commit.wrapUp(repo);
|
||||||
|
} catch (IOException ioe) {}
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param commitUrl a commit URL
|
||||||
|
* @return the repo name ("username/reponame")
|
||||||
|
*/
|
||||||
|
private static String getRepoName(String commitUrl) {
|
||||||
|
if (StringUtils.isBlank(commitUrl)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int indexOfUsername = (GitHub.GITHUB_URL + "/repos/").length();
|
||||||
|
String[] tokens = commitUrl.substring(indexOfUsername).split("/", 3);
|
||||||
|
return tokens[0] + '/' + tokens[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getApiUrl() {
|
||||||
|
return "/search/commits";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,8 +46,8 @@ public class GHCommitStatus extends GHObject {
|
|||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GHUser getCreator() {
|
public GHUser getCreator() throws IOException {
|
||||||
return creator;
|
return root.intern(creator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getContext() {
|
public String getContext() {
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import org.apache.commons.io.IOUtils;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
import javax.xml.bind.DatatypeConverter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Content of a repository.
|
* A Content of a repository.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
public class GHDeployKey {
|
public class GHDeployKey {
|
||||||
|
|
||||||
protected String url, key, title;
|
protected String url, key, title;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
public class GHDeployment extends GHObject {
|
public class GHDeployment extends GHObject {
|
||||||
@@ -41,8 +41,8 @@ public class GHDeployment extends GHObject {
|
|||||||
public String getEnvironment() {
|
public String getEnvironment() {
|
||||||
return environment;
|
return environment;
|
||||||
}
|
}
|
||||||
public GHUser getCreator() {
|
public GHUser getCreator() throws IOException {
|
||||||
return creator;
|
return root.intern(creator);
|
||||||
}
|
}
|
||||||
public String getRef() {
|
public String getRef() {
|
||||||
return ref;
|
return ref;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
public class GHDeploymentStatusBuilder {
|
public class GHDeploymentStatusBuilder {
|
||||||
private final Requester builder;
|
private final Requester builder;
|
||||||
|
|||||||
@@ -21,17 +21,30 @@ public enum GHEvent {
|
|||||||
FORK_APPLY,
|
FORK_APPLY,
|
||||||
GIST,
|
GIST,
|
||||||
GOLLUM,
|
GOLLUM,
|
||||||
|
INSTALLATION,
|
||||||
|
INSTALLATION_REPOSITORIES,
|
||||||
ISSUE_COMMENT,
|
ISSUE_COMMENT,
|
||||||
ISSUES,
|
ISSUES,
|
||||||
|
LABEL,
|
||||||
|
MARKETPLACE_PURCHASE,
|
||||||
MEMBER,
|
MEMBER,
|
||||||
|
MEMBERSHIP,
|
||||||
|
MILESTONE,
|
||||||
|
ORGANIZATION,
|
||||||
|
ORG_BLOCK,
|
||||||
PAGE_BUILD,
|
PAGE_BUILD,
|
||||||
|
PROJECT_CARD,
|
||||||
|
PROJECT_COLUMN,
|
||||||
|
PROJECT,
|
||||||
PUBLIC,
|
PUBLIC,
|
||||||
PULL_REQUEST,
|
PULL_REQUEST,
|
||||||
|
PULL_REQUEST_REVIEW,
|
||||||
PULL_REQUEST_REVIEW_COMMENT,
|
PULL_REQUEST_REVIEW_COMMENT,
|
||||||
PUSH,
|
PUSH,
|
||||||
RELEASE,
|
RELEASE,
|
||||||
REPOSITORY, // only valid for org hooks
|
REPOSITORY, // only valid for org hooks
|
||||||
STATUS,
|
STATUS,
|
||||||
|
TEAM,
|
||||||
TEAM_ADD,
|
TEAM_ADD,
|
||||||
WATCH,
|
WATCH,
|
||||||
PING,
|
PING,
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an event.
|
* Represents an event.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.kohsuke.github;
|
|||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.annotation.JsonSetter;
|
import com.fasterxml.jackson.annotation.JsonSetter;
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ public abstract class GHEventPayload {
|
|||||||
throw new IllegalStateException("Expected pull_request payload, but got something else. Maybe we've got another type of event?");
|
throw new IllegalStateException("Expected pull_request payload, but got something else. Maybe we've got another type of event?");
|
||||||
if (repository!=null) {
|
if (repository!=null) {
|
||||||
repository.wrap(root);
|
repository.wrap(root);
|
||||||
pull_request.wrap(repository);
|
pull_request.wrapUp(repository);
|
||||||
} else {
|
} else {
|
||||||
pull_request.wrapUp(root);
|
pull_request.wrapUp(root);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import javax.annotation.CheckForNull;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request/responce contains useful metadata.
|
||||||
|
* Custom exception allows store info for next diagnostics.
|
||||||
|
*
|
||||||
|
* @author Kanstantsin Shautsou
|
||||||
|
*/
|
||||||
|
public class GHFileNotFoundException extends FileNotFoundException {
|
||||||
|
protected Map<String, List<String>> responseHeaderFields;
|
||||||
|
|
||||||
|
public GHFileNotFoundException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHFileNotFoundException(String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CheckForNull
|
||||||
|
public Map<String, List<String>> getResponseHeaderFields() {
|
||||||
|
return responseHeaderFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
GHFileNotFoundException withResponseHeaderFields(HttpURLConnection urlConnection) {
|
||||||
|
this.responseHeaderFields = urlConnection.getHeaderFields();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,8 +38,8 @@ public class GHGist extends GHObject {
|
|||||||
/**
|
/**
|
||||||
* User that owns this Gist.
|
* User that owns this Gist.
|
||||||
*/
|
*/
|
||||||
public GHUser getOwner() {
|
public GHUser getOwner() throws IOException {
|
||||||
return owner;
|
return root.intern(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getForksUrl() {
|
public String getForksUrl() {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -41,6 +42,13 @@ public abstract class GHHook extends GHObject {
|
|||||||
return Collections.unmodifiableMap(config);
|
return Collections.unmodifiableMap(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see <a href="https://developer.github.com/v3/repos/hooks/#ping-a-hook">Ping hook</a>
|
||||||
|
*/
|
||||||
|
public void ping() throws IOException {
|
||||||
|
new Requester(getRoot()).method("POST").to(getApiRoute() + "/pings");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes this hook.
|
* Deletes this hook.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
34
src/main/java/org/kohsuke/github/GHIOException.java
Normal file
34
src/main/java/org/kohsuke/github/GHIOException.java
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import javax.annotation.CheckForNull;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request/responce contains useful metadata.
|
||||||
|
* Custom exception allows store info for next diagnostics.
|
||||||
|
*
|
||||||
|
* @author Kanstantsin Shautsou
|
||||||
|
*/
|
||||||
|
public class GHIOException extends IOException {
|
||||||
|
protected Map<String, List<String>> responseHeaderFields;
|
||||||
|
|
||||||
|
public GHIOException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHIOException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CheckForNull
|
||||||
|
public Map<String, List<String>> getResponseHeaderFields() {
|
||||||
|
return responseHeaderFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
GHIOException withResponseHeaderFields(HttpURLConnection urlConnection) {
|
||||||
|
this.responseHeaderFields = urlConnection.getHeaderFields();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -288,8 +288,8 @@ public class GHIssue extends GHObject implements Reactable{
|
|||||||
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/issues/"+number;
|
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/issues/"+number;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GHUser getAssignee() {
|
public GHUser getAssignee() throws IOException {
|
||||||
return assignee;
|
return root.intern(assignee);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<GHUser> getAssignees() {
|
public List<GHUser> getAssignees() {
|
||||||
@@ -299,8 +299,8 @@ public class GHIssue extends GHObject implements Reactable{
|
|||||||
/**
|
/**
|
||||||
* User who submitted the issue.
|
* User who submitted the issue.
|
||||||
*/
|
*/
|
||||||
public GHUser getUser() {
|
public GHUser getUser() throws IOException {
|
||||||
return user;
|
return root.intern(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -311,12 +311,16 @@ public class GHIssue extends GHObject implements Reactable{
|
|||||||
* even for an issue that's already closed. See
|
* even for an issue that's already closed. See
|
||||||
* https://github.com/kohsuke/github-api/issues/60.
|
* https://github.com/kohsuke/github-api/issues/60.
|
||||||
*/
|
*/
|
||||||
public GHUser getClosedBy() {
|
public GHUser getClosedBy() throws IOException {
|
||||||
if(!"closed".equals(state)) return null;
|
if(!"closed".equals(state)) return null;
|
||||||
if(closed_by != null) return closed_by;
|
|
||||||
|
//TODO
|
||||||
//TODO closed_by = owner.getIssue(number).getClosed_by();
|
/*
|
||||||
return closed_by;
|
if (closed_by==null) {
|
||||||
|
closed_by = owner.getIssue(number).getClosed_by();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return root.intern(closed_by);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCommentsCount(){
|
public int getCommentsCount(){
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ package org.kohsuke.github;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
import static org.kohsuke.github.Previews.SQUIRREL_GIRL;
|
import static org.kohsuke.github.Previews.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comment to the issue
|
* Comment to the issue
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search issues.
|
* Search issues.
|
||||||
*
|
*
|
||||||
@@ -41,6 +39,11 @@ public class GHIssueSearchBuilder extends GHSearchBuilder<GHIssue> {
|
|||||||
return q("is:merged");
|
return q("is:merged");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GHIssueSearchBuilder order(GHDirection v) {
|
||||||
|
req.with("order",v);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public GHIssueSearchBuilder sort(Sort sort) {
|
public GHIssueSearchBuilder sort(Sort sort) {
|
||||||
req.with("sort",sort);
|
req.with("sort",sort);
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import java.net.URL;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.kohsuke.github.Previews.DRAX;
|
import static org.kohsuke.github.Previews.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The GitHub Preview API's license information
|
* The GitHub Preview API's license information
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ public class GHMilestone extends GHObject {
|
|||||||
return owner;
|
return owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GHUser getCreator() {
|
public GHUser getCreator() throws IOException {
|
||||||
return creator;
|
return root.intern(creator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getDueOn() {
|
public Date getDueOn() {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|||||||
@@ -3,14 +3,15 @@ package org.kohsuke.github;
|
|||||||
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.lang.builder.ReflectionToStringBuilder;
|
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.builder.ToStringStyle;
|
||||||
import org.apache.commons.lang.reflect.FieldUtils;
|
|
||||||
|
|
||||||
|
import javax.annotation.CheckForNull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Most (all?) domain objects in GitHub seems to have these 4 properties.
|
* Most (all?) domain objects in GitHub seems to have these 4 properties.
|
||||||
@@ -18,6 +19,11 @@ import java.util.Date;
|
|||||||
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
|
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
|
||||||
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
|
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
|
||||||
public abstract class GHObject {
|
public abstract class GHObject {
|
||||||
|
/**
|
||||||
|
* Capture response HTTP headers on the state object.
|
||||||
|
*/
|
||||||
|
protected Map<String, List<String>> responseHeaderFields;
|
||||||
|
|
||||||
protected String url;
|
protected String url;
|
||||||
protected int id;
|
protected int id;
|
||||||
protected String created_at;
|
protected String created_at;
|
||||||
@@ -26,6 +32,21 @@ public abstract class GHObject {
|
|||||||
/*package*/ GHObject() {
|
/*package*/ GHObject() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the HTTP response headers given along with the state of this object.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Some of the HTTP headers have nothing to do with the object, for example "Cache-Control"
|
||||||
|
* and others are different depending on how this object was retrieved.
|
||||||
|
*
|
||||||
|
* This method was added as a kind of hack to allow the caller to retrieve OAuth scopes and such.
|
||||||
|
* Use with caution. The method might be removed in the future.
|
||||||
|
*/
|
||||||
|
@CheckForNull @Deprecated
|
||||||
|
public Map<String, List<String>> getResponseHeaderFields() {
|
||||||
|
return responseHeaderFields;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When was this resource created?
|
* When was this resource created?
|
||||||
*/
|
*/
|
||||||
|
|||||||
59
src/main/java/org/kohsuke/github/GHPermission.java
Normal file
59
src/main/java/org/kohsuke/github/GHPermission.java
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License
|
||||||
|
*
|
||||||
|
* Copyright 2016 CloudBees, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permission for a user in a repository.
|
||||||
|
* @see <a href="https://developer.github.com/v3/repos/collaborators/#review-a-users-permission-level">API</a>
|
||||||
|
*/
|
||||||
|
/*package*/ class GHPermission {
|
||||||
|
|
||||||
|
private String permission;
|
||||||
|
private GHUser user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return one of {@code admin}, {@code write}, {@code read}, or {@code none}
|
||||||
|
*/
|
||||||
|
public String getPermission() {
|
||||||
|
return permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHPermissionType getPermissionType() {
|
||||||
|
return Enum.valueOf(GHPermissionType.class, permission.toUpperCase(Locale.ENGLISH));
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHUser getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wrapUp(GitHub root) {
|
||||||
|
if (user != null) {
|
||||||
|
user.root = root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
11
src/main/java/org/kohsuke/github/GHPermissionType.java
Normal file
11
src/main/java/org/kohsuke/github/GHPermissionType.java
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
*/
|
||||||
|
public enum GHPermissionType {
|
||||||
|
ADMIN,
|
||||||
|
WRITE,
|
||||||
|
READ,
|
||||||
|
NONE
|
||||||
|
}
|
||||||
@@ -93,10 +93,10 @@ public abstract class GHPerson extends GHObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads repository list in a pagenated fashion.
|
* Loads repository list in a paginated fashion.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* For a person with a lot of repositories, GitHub returns the list of repositories in a pagenated fashion.
|
* For a person with a lot of repositories, GitHub returns the list of repositories in a paginated fashion.
|
||||||
* Unlike {@link #getRepositories()}, this method allows the caller to start processing data as it arrives.
|
* Unlike {@link #getRepositories()}, this method allows the caller to start processing data as it arrives.
|
||||||
*
|
*
|
||||||
* Every {@link Iterator#next()} call results in I/O. Exceptions that occur during the processing is wrapped
|
* Every {@link Iterator#next()} call results in I/O. Exceptions that occur during the processing is wrapped
|
||||||
|
|||||||
@@ -23,10 +23,16 @@
|
|||||||
*/
|
*/
|
||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import javax.annotation.CheckForNull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.kohsuke.github.Previews.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pull request.
|
* A pull request.
|
||||||
@@ -200,7 +206,7 @@ public class GHPullRequest extends GHIssue {
|
|||||||
* Depending on the original API call where this object is created, it may not contain everything.
|
* Depending on the original API call where this object is created, it may not contain everything.
|
||||||
*/
|
*/
|
||||||
private void populate() throws IOException {
|
private void populate() throws IOException {
|
||||||
if (merged_by!=null) return; // already populated
|
if (mergeable_state!=null) return; // already populated
|
||||||
if (root.isOffline()) {
|
if (root.isOffline()) {
|
||||||
return; // cannot populate, will have to live with what we have
|
return; // cannot populate, will have to live with what we have
|
||||||
}
|
}
|
||||||
@@ -208,12 +214,12 @@ public class GHPullRequest extends GHIssue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves all the commits associated to this pull request.
|
* Retrieves all the files associated to this pull request.
|
||||||
*/
|
*/
|
||||||
public PagedIterable<GHPullRequestFileDetail> listFiles() {
|
public PagedIterable<GHPullRequestFileDetail> listFiles() {
|
||||||
return new PagedIterable<GHPullRequestFileDetail>() {
|
return new PagedIterable<GHPullRequestFileDetail>() {
|
||||||
public PagedIterator<GHPullRequestFileDetail> _iterator(int pageSize) {
|
public PagedIterator<GHPullRequestFileDetail> _iterator(int pageSize) {
|
||||||
return new PagedIterator<GHPullRequestFileDetail>(root.retrieve().asIterator(String.format("%s/files", getApiURL()),
|
return new PagedIterator<GHPullRequestFileDetail>(root.retrieve().asIterator(String.format("%s/files", getApiRoute()),
|
||||||
GHPullRequestFileDetail[].class, pageSize)) {
|
GHPullRequestFileDetail[].class, pageSize)) {
|
||||||
@Override
|
@Override
|
||||||
protected void wrapUp(GHPullRequestFileDetail[] page) {
|
protected void wrapUp(GHPullRequestFileDetail[] page) {
|
||||||
@@ -223,6 +229,27 @@ public class GHPullRequest extends GHIssue {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves all the reviews associated to this pull request.
|
||||||
|
*/
|
||||||
|
public PagedIterable<GHPullRequestReview> listReviews() {
|
||||||
|
return new PagedIterable<GHPullRequestReview>() {
|
||||||
|
public PagedIterator<GHPullRequestReview> _iterator(int pageSize) {
|
||||||
|
return new PagedIterator<GHPullRequestReview>(root.retrieve()
|
||||||
|
.withPreview(BLACK_CAT)
|
||||||
|
.asIterator(String.format("%s/reviews", getApiRoute()),
|
||||||
|
GHPullRequestReview[].class, pageSize)) {
|
||||||
|
@Override
|
||||||
|
protected void wrapUp(GHPullRequestReview[] page) {
|
||||||
|
for (GHPullRequestReview r: page) {
|
||||||
|
r.wrapUp(GHPullRequest.this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains all the review comments associated with this pull request.
|
* Obtains all the review comments associated with this pull request.
|
||||||
*/
|
*/
|
||||||
@@ -247,7 +274,7 @@ public class GHPullRequest extends GHIssue {
|
|||||||
return new PagedIterable<GHPullRequestCommitDetail>() {
|
return new PagedIterable<GHPullRequestCommitDetail>() {
|
||||||
public PagedIterator<GHPullRequestCommitDetail> _iterator(int pageSize) {
|
public PagedIterator<GHPullRequestCommitDetail> _iterator(int pageSize) {
|
||||||
return new PagedIterator<GHPullRequestCommitDetail>(root.retrieve().asIterator(
|
return new PagedIterator<GHPullRequestCommitDetail>(root.retrieve().asIterator(
|
||||||
String.format("%s/commits", getApiURL()),
|
String.format("%s/commits", getApiRoute()),
|
||||||
GHPullRequestCommitDetail[].class, pageSize)) {
|
GHPullRequestCommitDetail[].class, pageSize)) {
|
||||||
@Override
|
@Override
|
||||||
protected void wrapUp(GHPullRequestCommitDetail[] page) {
|
protected void wrapUp(GHPullRequestCommitDetail[] page) {
|
||||||
@@ -259,6 +286,34 @@ public class GHPullRequest extends GHIssue {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Deprecated
|
||||||
|
public GHPullRequestReview createReview(String body, @CheckForNull GHPullRequestReviewState event,
|
||||||
|
GHPullRequestReviewComment... comments)
|
||||||
|
throws IOException {
|
||||||
|
return createReview(body, event, Arrays.asList(comments));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Deprecated
|
||||||
|
public GHPullRequestReview createReview(String body, @CheckForNull GHPullRequestReviewState event,
|
||||||
|
List<GHPullRequestReviewComment> comments)
|
||||||
|
throws IOException {
|
||||||
|
// if (event == null) {
|
||||||
|
// event = GHPullRequestReviewState.PENDING;
|
||||||
|
// }
|
||||||
|
List<DraftReviewComment> draftComments = new ArrayList<DraftReviewComment>(comments.size());
|
||||||
|
for (GHPullRequestReviewComment c : comments) {
|
||||||
|
draftComments.add(new DraftReviewComment(c.getBody(), c.getPath(), c.getPosition()));
|
||||||
|
}
|
||||||
|
return new Requester(root).method("POST")
|
||||||
|
.with("body", body)
|
||||||
|
//.with("event", event.name())
|
||||||
|
._with("comments", draftComments)
|
||||||
|
.withPreview(BLACK_CAT)
|
||||||
|
.to(getApiRoute() + "/reviews", GHPullRequestReview.class).wrapUp(this);
|
||||||
|
}
|
||||||
|
|
||||||
public GHPullRequestReviewComment createReviewComment(String body, String sha, String path, int position) throws IOException {
|
public GHPullRequestReviewComment createReviewComment(String body, String sha, String path, int position) throws IOException {
|
||||||
return new Requester(root).method("POST")
|
return new Requester(root).method("POST")
|
||||||
.with("body", body)
|
.with("body", body)
|
||||||
@@ -291,13 +346,57 @@ public class GHPullRequest extends GHIssue {
|
|||||||
* SHA that pull request head must match to allow merge.
|
* SHA that pull request head must match to allow merge.
|
||||||
*/
|
*/
|
||||||
public void merge(String msg, String sha) throws IOException {
|
public void merge(String msg, String sha) throws IOException {
|
||||||
new Requester(root).method("PUT").with("commit_message",msg).with("sha",sha).to(getApiRoute()+"/merge");
|
merge(msg, sha, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge this pull request, using the specified merge method.
|
||||||
|
*
|
||||||
|
* The equivalent of the big green "Merge pull request" button.
|
||||||
|
*
|
||||||
|
* @param msg
|
||||||
|
* Commit message. If null, the default one will be used.
|
||||||
|
* @param method
|
||||||
|
* SHA that pull request head must match to allow merge.
|
||||||
|
*/
|
||||||
|
public void merge(String msg, String sha, MergeMethod method) throws IOException {
|
||||||
|
new Requester(root).method("PUT")
|
||||||
|
.with("commit_message",msg)
|
||||||
|
.with("sha",sha)
|
||||||
|
.with("merge_method",method)
|
||||||
|
.to(getApiRoute()+"/merge");
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum MergeMethod{ MERGE, SQUASH, REBASE }
|
||||||
|
|
||||||
private void fetchIssue() throws IOException {
|
private void fetchIssue() throws IOException {
|
||||||
if (!fetchedIssueDetails) {
|
if (!fetchedIssueDetails) {
|
||||||
new Requester(root).to(getIssuesApiRoute(), this);
|
new Requester(root).to(getIssuesApiRoute(), this);
|
||||||
fetchedIssueDetails = true;
|
fetchedIssueDetails = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class DraftReviewComment {
|
||||||
|
private String body;
|
||||||
|
private String path;
|
||||||
|
private int position;
|
||||||
|
|
||||||
|
public DraftReviewComment(String body, String path, int position) {
|
||||||
|
this.body = body;
|
||||||
|
this.path = path;
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBody() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
149
src/main/java/org/kohsuke/github/GHPullRequestReview.java
Normal file
149
src/main/java/org/kohsuke/github/GHPullRequestReview.java
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017, CloudBees, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import static org.kohsuke.github.Previews.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Review to the pull request
|
||||||
|
*
|
||||||
|
* @see GHPullRequest#listReviews()
|
||||||
|
* @see GHPullRequest#createReview(String, GHPullRequestReviewState, GHPullRequestReviewComment...)
|
||||||
|
*/
|
||||||
|
public class GHPullRequestReview extends GHObject {
|
||||||
|
GHPullRequest owner;
|
||||||
|
|
||||||
|
private String body;
|
||||||
|
private GHUser user;
|
||||||
|
private String commit_id;
|
||||||
|
private GHPullRequestReviewState state;
|
||||||
|
|
||||||
|
/*package*/ GHPullRequestReview wrapUp(GHPullRequest owner) {
|
||||||
|
this.owner = owner;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the pull request to which this review is associated.
|
||||||
|
*/
|
||||||
|
public GHPullRequest getParent() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The comment itself.
|
||||||
|
*/
|
||||||
|
public String getBody() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the user who posted this review.
|
||||||
|
*/
|
||||||
|
public GHUser getUser() throws IOException {
|
||||||
|
return owner.root.getUser(user.getLogin());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCommitId() {
|
||||||
|
return commit_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHPullRequestReviewState getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getHtmlUrl() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getApiRoute() {
|
||||||
|
return owner.getApiRoute()+"/reviews/"+id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the comment.
|
||||||
|
*/
|
||||||
|
@Preview
|
||||||
|
@Deprecated
|
||||||
|
public void submit(String body, GHPullRequestReviewState event) throws IOException {
|
||||||
|
new Requester(owner.root).method("POST")
|
||||||
|
.with("body", body)
|
||||||
|
.with("event", event.action())
|
||||||
|
.withPreview("application/vnd.github.black-cat-preview+json")
|
||||||
|
.to(getApiRoute()+"/events",this);
|
||||||
|
this.body = body;
|
||||||
|
this.state = event;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes this review.
|
||||||
|
*/
|
||||||
|
@Preview
|
||||||
|
@Deprecated
|
||||||
|
public void delete() throws IOException {
|
||||||
|
new Requester(owner.root).method("DELETE")
|
||||||
|
.withPreview(BLACK_CAT)
|
||||||
|
.to(getApiRoute());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dismisses this review.
|
||||||
|
*/
|
||||||
|
@Preview
|
||||||
|
@Deprecated
|
||||||
|
public void dismiss(String message) throws IOException {
|
||||||
|
new Requester(owner.root).method("PUT")
|
||||||
|
.with("message", message)
|
||||||
|
.withPreview(BLACK_CAT)
|
||||||
|
.to(getApiRoute()+"/dismissals");
|
||||||
|
state = GHPullRequestReviewState.DISMISSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains all the review comments associated with this pull request review.
|
||||||
|
*/
|
||||||
|
@Preview
|
||||||
|
@Deprecated
|
||||||
|
public PagedIterable<GHPullRequestReviewComment> listReviewComments() throws IOException {
|
||||||
|
return new PagedIterable<GHPullRequestReviewComment>() {
|
||||||
|
public PagedIterator<GHPullRequestReviewComment> _iterator(int pageSize) {
|
||||||
|
return new PagedIterator<GHPullRequestReviewComment>(
|
||||||
|
owner.root.retrieve()
|
||||||
|
.withPreview(BLACK_CAT)
|
||||||
|
.asIterator(getApiRoute() + "/comments",
|
||||||
|
GHPullRequestReviewComment[].class, pageSize)) {
|
||||||
|
protected void wrapUp(GHPullRequestReviewComment[] page) {
|
||||||
|
for (GHPullRequestReviewComment c : page)
|
||||||
|
c.wrapUp(owner);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -44,6 +44,14 @@ public class GHPullRequestReviewComment extends GHObject implements Reactable {
|
|||||||
private int position;
|
private int position;
|
||||||
private int originalPosition;
|
private int originalPosition;
|
||||||
|
|
||||||
|
public static GHPullRequestReviewComment draft(String body, String path, int position) {
|
||||||
|
GHPullRequestReviewComment result = new GHPullRequestReviewComment();
|
||||||
|
result.body = body;
|
||||||
|
result.path = path;
|
||||||
|
result.position = position;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*package*/ GHPullRequestReviewComment wrapUp(GHPullRequest owner) {
|
/*package*/ GHPullRequestReviewComment wrapUp(GHPullRequest owner) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
public enum GHPullRequestReviewState {
|
||||||
|
PENDING(null),
|
||||||
|
APPROVED("APPROVE"),
|
||||||
|
REQUEST_CHANGES("REQUEST_CHANGES"),
|
||||||
|
COMMENTED("COMMENT"),
|
||||||
|
DISMISSED(null);
|
||||||
|
|
||||||
|
private final String _action;
|
||||||
|
|
||||||
|
GHPullRequestReviewState(String action) {
|
||||||
|
_action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String action() {
|
||||||
|
return _action;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package org.kohsuke.github;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
import static org.kohsuke.github.Previews.SQUIRREL_GIRL;
|
import static org.kohsuke.github.Previews.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reaction to issue, comment, PR, and so on.
|
* Reaction to issue, comment, PR, and so on.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import java.util.Arrays;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static java.lang.String.format;
|
import static java.lang.String.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release in a github repository.
|
* Release in a github repository.
|
||||||
@@ -45,10 +45,12 @@ public class GHRelease extends GHObject {
|
|||||||
return draft;
|
return draft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* Use {@link #update()}
|
||||||
|
*/
|
||||||
public GHRelease setDraft(boolean draft) throws IOException {
|
public GHRelease setDraft(boolean draft) throws IOException {
|
||||||
edit("draft", draft);
|
return update().draft(draft).update();
|
||||||
this.draft = draft;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public URL getHtmlUrl() {
|
public URL getHtmlUrl() {
|
||||||
@@ -121,9 +123,7 @@ public class GHRelease extends GHObject {
|
|||||||
* Java 7 or greater. Options for fixing this for earlier JVMs can be found here
|
* Java 7 or greater. Options for fixing this for earlier JVMs can be found here
|
||||||
* http://stackoverflow.com/questions/12361090/server-name-indication-sni-on-java but involve more complicated
|
* http://stackoverflow.com/questions/12361090/server-name-indication-sni-on-java but involve more complicated
|
||||||
* handling of the HTTP requests to github's API.
|
* handling of the HTTP requests to github's API.
|
||||||
*
|
*/
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public GHAsset uploadAsset(File file, String contentType) throws IOException {
|
public GHAsset uploadAsset(File file, String contentType) throws IOException {
|
||||||
Requester builder = new Requester(owner.root);
|
Requester builder = new Requester(owner.root);
|
||||||
|
|
||||||
@@ -151,10 +151,10 @@ public class GHRelease extends GHObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edit this release.
|
* Updates this release via a builder.
|
||||||
*/
|
*/
|
||||||
private void edit(String key, Object value) throws IOException {
|
public GHReleaseUpdater update() {
|
||||||
new Requester(root)._with(key, value).method("PATCH").to(owner.getApiTailUrl("releases/"+id));
|
return new GHReleaseUpdater(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getApiTailUrl(String end) {
|
private String getApiTailUrl(String end) {
|
||||||
|
|||||||
@@ -21,9 +21,7 @@ public class GHReleaseBuilder {
|
|||||||
* @param body The release notes body.
|
* @param body The release notes body.
|
||||||
*/
|
*/
|
||||||
public GHReleaseBuilder body(String body) {
|
public GHReleaseBuilder body(String body) {
|
||||||
if (body != null) {
|
builder.with("body", body);
|
||||||
builder.with("body", body);
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,12 +31,9 @@ public class GHReleaseBuilder {
|
|||||||
*
|
*
|
||||||
* @param commitish Defaults to the repository’s default branch (usually "master"). Unused if the Git tag
|
* @param commitish Defaults to the repository’s default branch (usually "master"). Unused if the Git tag
|
||||||
* already exists.
|
* already exists.
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public GHReleaseBuilder commitish(String commitish) {
|
public GHReleaseBuilder commitish(String commitish) {
|
||||||
if (commitish != null) {
|
builder.with("target_commitish", commitish);
|
||||||
builder.with("target_commitish", commitish);
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,9 +52,7 @@ public class GHReleaseBuilder {
|
|||||||
* @param name the name of the release
|
* @param name the name of the release
|
||||||
*/
|
*/
|
||||||
public GHReleaseBuilder name(String name) {
|
public GHReleaseBuilder name(String name) {
|
||||||
if (name != null) {
|
builder.with("name", name);
|
||||||
builder.with("name", name);
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
81
src/main/java/org/kohsuke/github/GHReleaseUpdater.java
Normal file
81
src/main/java/org/kohsuke/github/GHReleaseUpdater.java
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifies {@link GHRelease}.
|
||||||
|
*
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
* @see GHRelease#update()
|
||||||
|
*/
|
||||||
|
public class GHReleaseUpdater {
|
||||||
|
private final GHRelease base;
|
||||||
|
private final Requester builder;
|
||||||
|
|
||||||
|
GHReleaseUpdater(GHRelease base) {
|
||||||
|
this.base = base;
|
||||||
|
this.builder = new Requester(base.root);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHReleaseUpdater tag(String tag) {
|
||||||
|
builder.with("tag_name",tag);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param body The release notes body.
|
||||||
|
*/
|
||||||
|
public GHReleaseUpdater body(String body) {
|
||||||
|
builder.with("body", body);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the commitish value that determines where the Git tag is created from. Can be any branch or
|
||||||
|
* commit SHA.
|
||||||
|
*
|
||||||
|
* @param commitish Defaults to the repository’s default branch (usually "master"). Unused if the Git tag
|
||||||
|
* already exists.
|
||||||
|
*/
|
||||||
|
public GHReleaseUpdater commitish(String commitish) {
|
||||||
|
builder.with("target_commitish", commitish);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional.
|
||||||
|
*
|
||||||
|
* @param draft {@code true} to create a draft (unpublished) release, {@code false} to create a published one.
|
||||||
|
* Default is {@code false}.
|
||||||
|
*/
|
||||||
|
public GHReleaseUpdater draft(boolean draft) {
|
||||||
|
builder.with("draft", draft);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name the name of the release
|
||||||
|
*/
|
||||||
|
public GHReleaseUpdater name(String name) {
|
||||||
|
builder.with("name", name);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional
|
||||||
|
*
|
||||||
|
* @param prerelease {@code true} to identify the release as a prerelease. {@code false} to identify the release
|
||||||
|
* as a full release. Default is {@code false}.
|
||||||
|
*/
|
||||||
|
public GHReleaseUpdater prerelease(boolean prerelease) {
|
||||||
|
builder.with("prerelease", prerelease);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHRelease update() throws IOException {
|
||||||
|
return builder
|
||||||
|
.method("PATCH")
|
||||||
|
.to(base.owner.getApiTailUrl("releases/"+base.id), GHRelease.class).wrap(base.owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -31,6 +31,7 @@ import org.apache.commons.lang.StringUtils;
|
|||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.InterruptedIOException;
|
import java.io.InterruptedIOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
@@ -59,7 +60,7 @@ import static org.kohsuke.github.Previews.*;
|
|||||||
* @author Kohsuke Kawaguchi
|
* @author Kohsuke Kawaguchi
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"UnusedDeclaration"})
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
|
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
|
||||||
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
|
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
|
||||||
public class GHRepository extends GHObject {
|
public class GHRepository extends GHObject {
|
||||||
/*package almost final*/ GitHub root;
|
/*package almost final*/ GitHub root;
|
||||||
@@ -297,6 +298,14 @@ public class GHRepository extends GHObject {
|
|||||||
public List<GHRelease> getReleases() throws IOException {
|
public List<GHRelease> getReleases() throws IOException {
|
||||||
return listReleases().asList();
|
return listReleases().asList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GHRelease getLatestRelease() throws IOException {
|
||||||
|
try {
|
||||||
|
return root.retrieve().to(getApiTailUrl("releases/latest"), GHRelease.class).wrap(this);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
return null; // no latest release
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public PagedIterable<GHRelease> listReleases() throws IOException {
|
public PagedIterable<GHRelease> listReleases() throws IOException {
|
||||||
return new PagedIterable<GHRelease>() {
|
return new PagedIterable<GHRelease>() {
|
||||||
@@ -433,8 +442,8 @@ public class GHRepository extends GHObject {
|
|||||||
public int getSize() {
|
public int getSize() {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the collaborators on this repository.
|
* Gets the collaborators on this repository.
|
||||||
* This set always appear to include the owner.
|
* This set always appear to include the owner.
|
||||||
@@ -448,7 +457,6 @@ public class GHRepository extends GHObject {
|
|||||||
* Lists up the collaborators on this repository.
|
* Lists up the collaborators on this repository.
|
||||||
*
|
*
|
||||||
* @return Users
|
* @return Users
|
||||||
* @throws IOException
|
|
||||||
*/
|
*/
|
||||||
public PagedIterable<GHUser> listCollaborators() throws IOException {
|
public PagedIterable<GHUser> listCollaborators() throws IOException {
|
||||||
return listUsers("collaborators");
|
return listUsers("collaborators");
|
||||||
@@ -480,6 +488,27 @@ public class GHRepository extends GHObject {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain permission for a given user in this repository.
|
||||||
|
* @param user a {@link GHUser#getLogin}
|
||||||
|
* @throws FileNotFoundException under some conditions (e.g., private repo you can see but are not an admin of); treat as unknown
|
||||||
|
* @throws HttpException with a 403 under other conditions (e.g., public repo you have no special rights to); treat as unknown
|
||||||
|
*/
|
||||||
|
public GHPermissionType getPermission(String user) throws IOException {
|
||||||
|
GHPermission perm = root.retrieve().to(getApiTailUrl("collaborators/" + user + "/permission"), GHPermission.class);
|
||||||
|
perm.wrapUp(root);
|
||||||
|
return perm.getPermissionType();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain permission for a given user in this repository.
|
||||||
|
* @throws FileNotFoundException under some conditions (e.g., private repo you can see but are not an admin of); treat as unknown
|
||||||
|
* @throws HttpException with a 403 under other conditions (e.g., public repo you have no special rights to); treat as unknown
|
||||||
|
*/
|
||||||
|
public GHPermissionType getPermission(GHUser u) throws IOException {
|
||||||
|
return getPermission(u.getLogin());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this repository belongs to an organization, return a set of teams.
|
* If this repository belongs to an organization, return a set of teams.
|
||||||
*/
|
*/
|
||||||
@@ -504,7 +533,6 @@ public class GHRepository extends GHObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void modifyCollaborators(Collection<GHUser> users, String method) throws IOException {
|
private void modifyCollaborators(Collection<GHUser> users, String method) throws IOException {
|
||||||
verifyMine();
|
|
||||||
for (GHUser user : users) {
|
for (GHUser user : users) {
|
||||||
new Requester(root).method(method).to(getApiTailUrl("collaborators/" + user.getLogin()));
|
new Requester(root).method(method).to(getApiTailUrl("collaborators/" + user.getLogin()));
|
||||||
}
|
}
|
||||||
@@ -762,6 +790,26 @@ public class GHRepository extends GHObject {
|
|||||||
return GHRef.wrap(root.retrieve().to(String.format("/repos/%s/%s/git/refs", getOwnerName(), name), GHRef[].class), root);
|
return GHRef.wrap(root.retrieve().to(String.format("/repos/%s/%s/git/refs", getOwnerName(), name), GHRef[].class), root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves all refs for the github repository.
|
||||||
|
*
|
||||||
|
* @return paged iterable of all refs
|
||||||
|
* @throws IOException on failure communicating with GitHub, potentially due to an invalid ref type being requested
|
||||||
|
*/
|
||||||
|
public PagedIterable<GHRef> listRefs() throws IOException {
|
||||||
|
final String url = String.format("/repos/%s/%s/git/refs", getOwnerName(), name);
|
||||||
|
return new PagedIterable<GHRef>() {
|
||||||
|
public PagedIterator<GHRef> _iterator(int pageSize) {
|
||||||
|
return new PagedIterator<GHRef>(root.retrieve().asIterator(url, GHRef[].class, pageSize)) {
|
||||||
|
protected void wrapUp(GHRef[] page) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves all refs of the given type for the current GitHub repository.
|
* Retrieves all refs of the given type for the current GitHub repository.
|
||||||
* @param refType the type of reg to search for e.g. <tt>tags</tt> or <tt>commits</tt>
|
* @param refType the type of reg to search for e.g. <tt>tags</tt> or <tt>commits</tt>
|
||||||
@@ -771,6 +819,27 @@ public class GHRepository extends GHObject {
|
|||||||
public GHRef[] getRefs(String refType) throws IOException {
|
public GHRef[] getRefs(String refType) throws IOException {
|
||||||
return GHRef.wrap(root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType), GHRef[].class),root);
|
return GHRef.wrap(root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType), GHRef[].class),root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves all refs of the given type for the current GitHub repository.
|
||||||
|
*
|
||||||
|
* @param refType the type of reg to search for e.g. <tt>tags</tt> or <tt>commits</tt>
|
||||||
|
* @return paged iterable of all refs of the specified type
|
||||||
|
* @throws IOException on failure communicating with GitHub, potentially due to an invalid ref type being requested
|
||||||
|
*/
|
||||||
|
public PagedIterable<GHRef> listRefs(String refType) throws IOException {
|
||||||
|
final String url = String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType);
|
||||||
|
return new PagedIterable<GHRef>() {
|
||||||
|
public PagedIterator<GHRef> _iterator(int pageSize) {
|
||||||
|
return new PagedIterator<GHRef>(root.retrieve().asIterator(url, GHRef[].class, pageSize)) {
|
||||||
|
protected void wrapUp(GHRef[] page) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrive a ref of the given type for the current GitHub repository.
|
* Retrive a ref of the given type for the current GitHub repository.
|
||||||
*
|
*
|
||||||
@@ -788,6 +857,18 @@ public class GHRepository extends GHObject {
|
|||||||
refName = refName.replaceAll("#", "%23");
|
refName = refName.replaceAll("#", "%23");
|
||||||
return root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refName), GHRef.class).wrap(root);
|
return root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refName), GHRef.class).wrap(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the <strong>annotated</strong> tag object. Only valid if the {@link GHRef#getObject()} has a
|
||||||
|
* {@link GHRef.GHObject#getType()} of {@code tag}.
|
||||||
|
*
|
||||||
|
* @param sha the sha of the tag object
|
||||||
|
* @return the annotated tag object
|
||||||
|
*/
|
||||||
|
public GHTagObject getTagObject(String sha) throws IOException {
|
||||||
|
return root.retrieve().to(getApiTailUrl("git/tags/" + sha), GHTagObject.class).wrap(this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrive a tree of the given type for the current GitHub repository.
|
* Retrive a tree of the given type for the current GitHub repository.
|
||||||
*
|
*
|
||||||
@@ -799,7 +880,11 @@ public class GHRepository extends GHObject {
|
|||||||
*/
|
*/
|
||||||
public GHTree getTree(String sha) throws IOException {
|
public GHTree getTree(String sha) throws IOException {
|
||||||
String url = String.format("/repos/%s/%s/git/trees/%s", getOwnerName(), name, sha);
|
String url = String.format("/repos/%s/%s/git/trees/%s", getOwnerName(), name, sha);
|
||||||
return root.retrieve().to(url, GHTree.class).wrap(root);
|
return root.retrieve().to(url, GHTree.class).wrap(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHTreeBuilder createTree() {
|
||||||
|
return new GHTreeBuilder(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -814,7 +899,36 @@ public class GHRepository extends GHObject {
|
|||||||
*/
|
*/
|
||||||
public GHTree getTreeRecursive(String sha, int recursive) throws IOException {
|
public GHTree getTreeRecursive(String sha, int recursive) throws IOException {
|
||||||
String url = String.format("/repos/%s/%s/git/trees/%s?recursive=%d", getOwnerName(), name, sha, recursive);
|
String url = String.format("/repos/%s/%s/git/trees/%s?recursive=%d", getOwnerName(), name, sha, recursive);
|
||||||
return root.retrieve().to(url, GHTree.class).wrap(root);
|
return root.retrieve().to(url, GHTree.class).wrap(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the metadata & the content of a blob.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This method retrieves the whole content in memory, so beware when you are dealing with large BLOB.
|
||||||
|
*
|
||||||
|
* @see <a href="https://developer.github.com/v3/git/blobs/#get-a-blob">Get a blob</a>
|
||||||
|
* @see #readBlob(String)
|
||||||
|
*/
|
||||||
|
public GHBlob getBlob(String blobSha) throws IOException {
|
||||||
|
String target = getApiTailUrl("git/blobs/" + blobSha);
|
||||||
|
return root.retrieve().to(target, GHBlob.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHBlobBuilder createBlob() {
|
||||||
|
return new GHBlobBuilder(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the content of a blob as a stream for better efficiency.
|
||||||
|
*
|
||||||
|
* @see <a href="https://developer.github.com/v3/git/blobs/#get-a-blob">Get a blob</a>
|
||||||
|
* @see #getBlob(String)
|
||||||
|
*/
|
||||||
|
public InputStream readBlob(String blobSha) throws IOException {
|
||||||
|
String target = getApiTailUrl("git/blobs/" + blobSha);
|
||||||
|
return root.retrieve().withHeader("Accept","application/vnd.github.VERSION.raw").asStream(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -829,6 +943,10 @@ public class GHRepository extends GHObject {
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GHCommitBuilder createCommit() {
|
||||||
|
return new GHCommitBuilder(this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists all the commits.
|
* Lists all the commits.
|
||||||
*/
|
*/
|
||||||
@@ -1092,11 +1210,6 @@ public class GHRepository extends GHObject {
|
|||||||
// return root.retrieveWithAuth("/pulls/"+owner+'/'+name,JsonPullRequests.class).wrap(root);
|
// return root.retrieveWithAuth("/pulls/"+owner+'/'+name,JsonPullRequests.class).wrap(root);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
private void verifyMine() throws IOException {
|
|
||||||
if (!root.login.equals(getOwnerName()))
|
|
||||||
throw new IOException("Operation not applicable to a repository owned by someone else: " + getOwnerName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a set that represents the post-commit hook URLs.
|
* Returns a set that represents the post-commit hook URLs.
|
||||||
* The returned set is live, and changes made to them are reflected to GitHub.
|
* The returned set is live, and changes made to them are reflected to GitHub.
|
||||||
@@ -1104,7 +1217,7 @@ public class GHRepository extends GHObject {
|
|||||||
* @deprecated
|
* @deprecated
|
||||||
* Use {@link #getHooks()} and {@link #createHook(String, Map, Collection, boolean)}
|
* Use {@link #getHooks()} and {@link #createHook(String, Map, Collection, boolean)}
|
||||||
*/
|
*/
|
||||||
@SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS",
|
@SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS",
|
||||||
justification = "It causes a performance degradation, but we have already exposed it to the API")
|
justification = "It causes a performance degradation, but we have already exposed it to the API")
|
||||||
public Set<URL> getPostCommitHooks() {
|
public Set<URL> getPostCommitHooks() {
|
||||||
return postCommitHooks;
|
return postCommitHooks;
|
||||||
@@ -1113,7 +1226,7 @@ public class GHRepository extends GHObject {
|
|||||||
/**
|
/**
|
||||||
* Live set view of the post-commit hook.
|
* Live set view of the post-commit hook.
|
||||||
*/
|
*/
|
||||||
@SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS",
|
@SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS",
|
||||||
justification = "It causes a performance degradation, but we have already exposed it to the API")
|
justification = "It causes a performance degradation, but we have already exposed it to the API")
|
||||||
@SkipFromToString
|
@SkipFromToString
|
||||||
private final Set<URL> postCommitHooks = new AbstractSet<URL>() {
|
private final Set<URL> postCommitHooks = new AbstractSet<URL>() {
|
||||||
@@ -1181,7 +1294,7 @@ public class GHRepository extends GHObject {
|
|||||||
*/
|
*/
|
||||||
public Map<String,GHBranch> getBranches() throws IOException {
|
public Map<String,GHBranch> getBranches() throws IOException {
|
||||||
Map<String,GHBranch> r = new TreeMap<String,GHBranch>();
|
Map<String,GHBranch> r = new TreeMap<String,GHBranch>();
|
||||||
for (GHBranch p : root.retrieve().to(getApiTailUrl("branches"), GHBranch[].class)) {
|
for (GHBranch p : root.retrieve().withPreview(LOKI).to(getApiTailUrl("branches"), GHBranch[].class)) {
|
||||||
p.wrap(this);
|
p.wrap(this);
|
||||||
r.put(p.getName(),p);
|
r.put(p.getName(),p);
|
||||||
}
|
}
|
||||||
@@ -1189,7 +1302,7 @@ public class GHRepository extends GHObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public GHBranch getBranch(String name) throws IOException {
|
public GHBranch getBranch(String name) throws IOException {
|
||||||
return root.retrieve().to(getApiTailUrl("branches/"+name),GHBranch.class).wrap(this);
|
return root.retrieve().withPreview(LOKI).to(getApiTailUrl("branches/"+name),GHBranch.class).wrap(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1411,7 +1524,7 @@ public class GHRepository extends GHObject {
|
|||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
// We ignore contributions in the calculation
|
// We ignore contributions in the calculation
|
||||||
return super.equals(obj);
|
return super.equals(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1439,6 +1552,19 @@ public class GHRepository extends GHObject {
|
|||||||
return new GHNotificationStream(root,getApiTailUrl("/notifications"));
|
return new GHNotificationStream(root,getApiTailUrl("/notifications"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <a href="https://developer.github.com/v3/repos/traffic/#views">https://developer.github.com/v3/repos/traffic/#views</a>
|
||||||
|
*/
|
||||||
|
public GHRepositoryViewTraffic getViewTraffic() throws IOException{
|
||||||
|
return root.retrieve().to(getApiTailUrl("/traffic/views"), GHRepositoryViewTraffic.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <a href="https://developer.github.com/v3/repos/traffic/#clones">https://developer.github.com/v3/repos/traffic/#clones</a>
|
||||||
|
*/
|
||||||
|
public GHRepositoryCloneTraffic getCloneTraffic() throws IOException{
|
||||||
|
return root.retrieve().to(getApiTailUrl("/traffic/clones"), GHRepositoryCloneTraffic.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repository clone statistics.
|
||||||
|
*
|
||||||
|
* @see GHRepository#getCloneTraffic()
|
||||||
|
*/
|
||||||
|
public class GHRepositoryCloneTraffic extends GHRepositoryTraffic {
|
||||||
|
private List<DailyInfo> clones;
|
||||||
|
|
||||||
|
/*package*/ GHRepositoryCloneTraffic() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ GHRepositoryCloneTraffic(Integer count, Integer uniques, List<DailyInfo> clones) {
|
||||||
|
super(count, uniques);
|
||||||
|
this.clones = clones;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DailyInfo> getClones() {
|
||||||
|
return clones;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DailyInfo> getDailyInfo() {
|
||||||
|
return getClones();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DailyInfo extends GHRepositoryTraffic.DailyInfo {
|
||||||
|
/*package*/ DailyInfo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ DailyInfo(String timestamp, int count, int uniques) {
|
||||||
|
super(timestamp, count, uniques);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search repositories.
|
* Search repositories.
|
||||||
*
|
*
|
||||||
@@ -57,6 +55,11 @@ public class GHRepositorySearchBuilder extends GHSearchBuilder<GHRepository> {
|
|||||||
return q("stars:"+v);
|
return q("stars:"+v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GHRepositorySearchBuilder order(GHDirection v) {
|
||||||
|
req.with("order",v);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public GHRepositorySearchBuilder sort(Sort sort) {
|
public GHRepositorySearchBuilder sort(Sort sort) {
|
||||||
req.with("sort",sort);
|
req.with("sort",sort);
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
54
src/main/java/org/kohsuke/github/GHRepositoryTraffic.java
Normal file
54
src/main/java/org/kohsuke/github/GHRepositoryTraffic.java
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class GHRepositoryTraffic implements TrafficInfo {
|
||||||
|
private int count;
|
||||||
|
private int uniques;
|
||||||
|
|
||||||
|
/*package*/ GHRepositoryTraffic() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ GHRepositoryTraffic(int count, int uniques) {
|
||||||
|
this.count = count;
|
||||||
|
this.uniques = uniques;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUniques() {
|
||||||
|
return uniques;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract List<? extends DailyInfo> getDailyInfo();
|
||||||
|
|
||||||
|
public static abstract class DailyInfo implements TrafficInfo {
|
||||||
|
private String timestamp;
|
||||||
|
private int count;
|
||||||
|
private int uniques;
|
||||||
|
|
||||||
|
public Date getTimestamp() {
|
||||||
|
return GitHub.parseDate(timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUniques() {
|
||||||
|
return uniques;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ DailyInfo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ DailyInfo(String timestamp, Integer count, Integer uniques) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.count = count;
|
||||||
|
this.uniques = uniques;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repository view statistics.
|
||||||
|
*
|
||||||
|
* @see GHRepository#getViewTraffic()
|
||||||
|
*/
|
||||||
|
public class GHRepositoryViewTraffic extends GHRepositoryTraffic {
|
||||||
|
private List<DailyInfo> views;
|
||||||
|
|
||||||
|
/*package*/ GHRepositoryViewTraffic() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ GHRepositoryViewTraffic(int count, int uniques, List<DailyInfo> views) {
|
||||||
|
super(count, uniques);
|
||||||
|
this.views = views;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DailyInfo> getViews() {
|
||||||
|
return views;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DailyInfo> getDailyInfo() {
|
||||||
|
return getViews();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DailyInfo extends GHRepositoryTraffic.DailyInfo {
|
||||||
|
/*package*/ DailyInfo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ DailyInfo(String timestamp, int count, int uniques) {
|
||||||
|
super(timestamp, count, uniques);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/main/java/org/kohsuke/github/GHTagObject.java
Normal file
60
src/main/java/org/kohsuke/github/GHTagObject.java
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an annotated tag in a {@link GHRepository}
|
||||||
|
*
|
||||||
|
* @see GHRepository#getTagObject(String)
|
||||||
|
*/
|
||||||
|
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
|
||||||
|
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
|
||||||
|
public class GHTagObject {
|
||||||
|
private GHRepository owner;
|
||||||
|
private GitHub root;
|
||||||
|
|
||||||
|
private String tag;
|
||||||
|
private String sha;
|
||||||
|
private String url;
|
||||||
|
private String message;
|
||||||
|
private GitUser tagger;
|
||||||
|
private GHRef.GHObject object;
|
||||||
|
|
||||||
|
/*package*/ GHTagObject wrap(GHRepository owner) {
|
||||||
|
this.owner = owner;
|
||||||
|
this.root = owner.root;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHRepository getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GitHub getRoot() {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTag() {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSha() {
|
||||||
|
return sha;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GitUser getTagger() {
|
||||||
|
return tagger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHRef.GHObject getObject() {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|||||||
@@ -10,10 +10,12 @@ import java.util.List;
|
|||||||
* https://developer.github.com/v3/git/trees/
|
* https://developer.github.com/v3/git/trees/
|
||||||
*
|
*
|
||||||
* @author Daniel Teixeira - https://github.com/ddtxra
|
* @author Daniel Teixeira - https://github.com/ddtxra
|
||||||
|
* @see GHCommit#getTree()
|
||||||
* @see GHRepository#getTree(String)
|
* @see GHRepository#getTree(String)
|
||||||
|
* @see GHTreeEntry#asTree()
|
||||||
*/
|
*/
|
||||||
public class GHTree {
|
public class GHTree {
|
||||||
/* package almost final */GitHub root;
|
/* package almost final */GHRepository repo;
|
||||||
|
|
||||||
private boolean truncated;
|
private boolean truncated;
|
||||||
private String sha, url;
|
private String sha, url;
|
||||||
@@ -28,12 +30,24 @@ public class GHTree {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an array of entries of the trees
|
* Return an array of entries of the trees
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public List<GHTreeEntry> getTree() {
|
public List<GHTreeEntry> getTree() {
|
||||||
return Collections.unmodifiableList(Arrays.asList(tree));
|
return Collections.unmodifiableList(Arrays.asList(tree));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a tree entry by its name.
|
||||||
|
*
|
||||||
|
* IOW, find a directory entry by a file name.
|
||||||
|
*/
|
||||||
|
public GHTreeEntry getEntry(String path) {
|
||||||
|
for (GHTreeEntry e : tree) {
|
||||||
|
if (e.getPath().equals(path))
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the number of items in the tree array exceeded the GitHub maximum limit.
|
* Returns true if the number of items in the tree array exceeded the GitHub maximum limit.
|
||||||
* @return true true if the number of items in the tree array exceeded the GitHub maximum limit otherwise false.
|
* @return true true if the number of items in the tree array exceeded the GitHub maximum limit otherwise false.
|
||||||
@@ -50,8 +64,11 @@ public class GHTree {
|
|||||||
return GitHub.parseURL(url);
|
return GitHub.parseURL(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */GHTree wrap(GitHub root) {
|
/* package */GHTree wrap(GHRepository repo) {
|
||||||
this.root = root;
|
this.repo = repo;
|
||||||
|
for (GHTreeEntry e : tree) {
|
||||||
|
e.tree = this;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
90
src/main/java/org/kohsuke/github/GHTreeBuilder.java
Normal file
90
src/main/java/org/kohsuke/github/GHTreeBuilder.java
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder pattern for creating a new tree.
|
||||||
|
* Based on https://developer.github.com/v3/git/trees/#create-a-tree
|
||||||
|
*/
|
||||||
|
public class GHTreeBuilder {
|
||||||
|
private final GHRepository repo;
|
||||||
|
private final Requester req;
|
||||||
|
|
||||||
|
private final List<TreeEntry> treeEntries = new ArrayList<TreeEntry>();
|
||||||
|
|
||||||
|
@SuppressFBWarnings("URF_UNREAD_FIELD")
|
||||||
|
private static final class TreeEntry {
|
||||||
|
private final String path;
|
||||||
|
private final String mode;
|
||||||
|
private final String type;
|
||||||
|
private String sha;
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
private TreeEntry(String path, String mode, String type) {
|
||||||
|
this.path = path;
|
||||||
|
this.mode = mode;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GHTreeBuilder(GHRepository repo) {
|
||||||
|
this.repo = repo;
|
||||||
|
req = new Requester(repo.root);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param baseTree the SHA of tree you want to update with new data
|
||||||
|
*/
|
||||||
|
public GHTreeBuilder baseTree(String baseTree) {
|
||||||
|
req.with("base_tree", baseTree);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new entry to the tree.
|
||||||
|
* Exactly one of the parameters {@code sha} and {@code content} must be non-null.
|
||||||
|
*/
|
||||||
|
public GHTreeBuilder entry(String path, String mode, String type, String sha, String content) {
|
||||||
|
TreeEntry entry = new TreeEntry(path, mode, type);
|
||||||
|
entry.sha = sha;
|
||||||
|
entry.content = content;
|
||||||
|
treeEntries.add(entry);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialized version of {@link #entry(String, String, String, String, String)} for adding an existing blob referred by its SHA.
|
||||||
|
*/
|
||||||
|
public GHTreeBuilder shaEntry(String path, String sha, boolean executable) {
|
||||||
|
TreeEntry entry = new TreeEntry(path, executable ? "100755" : "100644", "blob");
|
||||||
|
entry.sha = sha;
|
||||||
|
treeEntries.add(entry);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialized version of {@link #entry(String, String, String, String, String)} for adding a text file with the specified {@code content}.
|
||||||
|
*/
|
||||||
|
public GHTreeBuilder textEntry(String path, String content, boolean executable) {
|
||||||
|
TreeEntry entry = new TreeEntry(path, executable ? "100755" : "100644", "blob");
|
||||||
|
entry.content = content;
|
||||||
|
treeEntries.add(entry);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getApiTail() {
|
||||||
|
return String.format("/repos/%s/%s/git/trees", repo.getOwnerName(), repo.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a tree based on the parameters specified thus far.
|
||||||
|
*/
|
||||||
|
public GHTree create() throws IOException {
|
||||||
|
req._with("tree", treeEntries);
|
||||||
|
return req.method("POST").to(getApiTail(), GHTree.class).wrap(repo);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,6 +12,8 @@ import java.net.URL;
|
|||||||
* @see GHTree
|
* @see GHTree
|
||||||
*/
|
*/
|
||||||
public class GHTreeEntry {
|
public class GHTreeEntry {
|
||||||
|
/* package almost final */GHTree tree;
|
||||||
|
|
||||||
private String path, mode, type, sha, url;
|
private String path, mode, type, sha, url;
|
||||||
private long size;
|
private long size;
|
||||||
|
|
||||||
@@ -44,7 +48,7 @@ public class GHTreeEntry {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the type such as:
|
* Gets the type such as:
|
||||||
* "blob"
|
* "blob", "tree", etc.
|
||||||
*
|
*
|
||||||
* @return The type
|
* @return The type
|
||||||
*/
|
*/
|
||||||
@@ -68,4 +72,37 @@ public class GHTreeEntry {
|
|||||||
public URL getUrl() {
|
public URL getUrl() {
|
||||||
return GitHub.parseURL(url);
|
return GitHub.parseURL(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this tree entry represents a file, then return its information.
|
||||||
|
* Otherwise null.
|
||||||
|
*/
|
||||||
|
public GHBlob asBlob() throws IOException {
|
||||||
|
if (type.equals("blob"))
|
||||||
|
return tree.repo.getBlob(sha);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this tree entry represents a file, then return its content.
|
||||||
|
* Otherwise null.
|
||||||
|
*/
|
||||||
|
public InputStream readAsBlob() throws IOException {
|
||||||
|
if (type.equals("blob"))
|
||||||
|
return tree.repo.readBlob(sha);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this tree entry represents a directory, then return it.
|
||||||
|
* Otherwise null.
|
||||||
|
*/
|
||||||
|
public GHTree asTree() throws IOException {
|
||||||
|
if (type.equals("tree"))
|
||||||
|
return tree.repo.getTree(sha);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search users.
|
* Search users.
|
||||||
*
|
*
|
||||||
@@ -49,6 +47,11 @@ public class GHUserSearchBuilder extends GHSearchBuilder<GHUser> {
|
|||||||
return q("followers:"+v);
|
return q("followers:"+v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GHUserSearchBuilder order(GHDirection v) {
|
||||||
|
req.with("order",v);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public GHUserSearchBuilder sort(Sort sort) {
|
public GHUserSearchBuilder sort(Sort sort) {
|
||||||
req.with("sort",sort);
|
req.with("sort",sort);
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -23,12 +23,16 @@
|
|||||||
*/
|
*/
|
||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import static java.util.logging.Level.FINE;
|
import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std;
|
||||||
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
|
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||||
import static org.kohsuke.github.Previews.DRAX;
|
import org.apache.commons.codec.Charsets;
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
|
import javax.annotation.CheckForNull;
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -49,18 +53,15 @@ 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.ConcurrentHashMap;
|
||||||
import org.apache.commons.codec.Charsets;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
|
||||||
|
|
||||||
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 javax.annotation.Nonnull;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.*;
|
||||||
|
import static java.net.HttpURLConnection.*;
|
||||||
|
import static java.util.logging.Level.*;
|
||||||
|
import static org.kohsuke.github.Previews.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Root of the GitHub API.
|
* Root of the GitHub API.
|
||||||
*
|
*
|
||||||
@@ -80,9 +81,10 @@ public class GitHub {
|
|||||||
*/
|
*/
|
||||||
/*package*/ final String encodedAuthorization;
|
/*package*/ final String encodedAuthorization;
|
||||||
|
|
||||||
private final Map<String,GHUser> users = new Hashtable<String, GHUser>();
|
private final ConcurrentMap<String,GHUser> users;
|
||||||
private final Map<String,GHOrganization> orgs = new Hashtable<String, GHOrganization>();
|
private final ConcurrentMap<String,GHOrganization> orgs;
|
||||||
|
// Cache of myself object.
|
||||||
|
private GHMyself myself;
|
||||||
private final String apiUrl;
|
private final String apiUrl;
|
||||||
|
|
||||||
/*package*/ final RateLimitHandler rateLimitHandler;
|
/*package*/ final RateLimitHandler rateLimitHandler;
|
||||||
@@ -90,6 +92,10 @@ public class GitHub {
|
|||||||
|
|
||||||
private HttpConnector connector = HttpConnector.DEFAULT;
|
private HttpConnector connector = HttpConnector.DEFAULT;
|
||||||
|
|
||||||
|
private final Object headerRateLimitLock = new Object();
|
||||||
|
private GHRateLimit headerRateLimit = null;
|
||||||
|
private volatile GHRateLimit rateLimit = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a client API root object.
|
* Creates a client API root object.
|
||||||
*
|
*
|
||||||
@@ -143,6 +149,8 @@ public class GitHub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
users = new ConcurrentHashMap<String, GHUser>();
|
||||||
|
orgs = new ConcurrentHashMap<String, GHOrganization>();
|
||||||
this.rateLimitHandler = rateLimitHandler;
|
this.rateLimitHandler = rateLimitHandler;
|
||||||
this.abuseLimitHandler = abuseLimitHandler;
|
this.abuseLimitHandler = abuseLimitHandler;
|
||||||
|
|
||||||
@@ -254,6 +262,10 @@ public class GitHub {
|
|||||||
return connector;
|
return connector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getApiUrl() {
|
||||||
|
return apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the custom connector used to make requests to GitHub.
|
* Sets the custom connector used to make requests to GitHub.
|
||||||
*/
|
*/
|
||||||
@@ -287,32 +299,78 @@ public class GitHub {
|
|||||||
*/
|
*/
|
||||||
public GHRateLimit getRateLimit() throws IOException {
|
public GHRateLimit getRateLimit() throws IOException {
|
||||||
try {
|
try {
|
||||||
return retrieve().to("/rate_limit", JsonRateLimit.class).rate;
|
return rateLimit = retrieve().to("/rate_limit", JsonRateLimit.class).rate;
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
// GitHub Enterprise doesn't have the rate limit, so in that case
|
// GitHub Enterprise doesn't have the rate limit, so in that case
|
||||||
// return some big number that's not too big.
|
// return some big number that's not too big.
|
||||||
// see issue #78
|
// see issue #78
|
||||||
GHRateLimit r = new GHRateLimit();
|
GHRateLimit r = new GHRateLimit();
|
||||||
r.limit = r.remaining = 1000000;
|
r.limit = r.remaining = 1000000;
|
||||||
long hours = 1000L * 60 * 60;
|
long hour = 60L * 60L; // this is madness, storing the date as seconds in a Date object
|
||||||
r.reset = new Date(System.currentTimeMillis() + 1 * hours );
|
r.reset = new Date(System.currentTimeMillis() / 1000L + hour);
|
||||||
return r;
|
return rateLimit = r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*package*/ void updateRateLimit(@Nonnull GHRateLimit observed) {
|
||||||
|
synchronized (headerRateLimitLock) {
|
||||||
|
if (headerRateLimit == null
|
||||||
|
|| headerRateLimit.getResetDate().getTime() < observed.getResetDate().getTime()
|
||||||
|
|| headerRateLimit.remaining > observed.remaining) {
|
||||||
|
headerRateLimit = observed;
|
||||||
|
LOGGER.log(FINE, "Rate limit now: {0}", headerRateLimit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the most recently observed rate limit data or {@code null} if either there is no rate limit
|
||||||
|
* (for example GitHub Enterprise) or if no requests have been made.
|
||||||
|
*
|
||||||
|
* @return the most recently observed rate limit data or {@code null}.
|
||||||
|
*/
|
||||||
|
@CheckForNull
|
||||||
|
public GHRateLimit lastRateLimit() {
|
||||||
|
synchronized (headerRateLimitLock) {
|
||||||
|
return headerRateLimit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current rate limit while trying not to actually make any remote requests unless absolutely necessary.
|
||||||
|
*
|
||||||
|
* @return the current rate limit data.
|
||||||
|
* @throws IOException if we couldn't get the current rate limit data.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public GHRateLimit rateLimit() throws IOException {
|
||||||
|
synchronized (headerRateLimitLock) {
|
||||||
|
if (headerRateLimit != null) {
|
||||||
|
return headerRateLimit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GHRateLimit rateLimit = this.rateLimit;
|
||||||
|
if (rateLimit == null || rateLimit.getResetDate().getTime() < System.currentTimeMillis()) {
|
||||||
|
rateLimit = getRateLimit();
|
||||||
|
}
|
||||||
|
return rateLimit;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the {@link GHUser} that represents yourself.
|
* Gets the {@link GHUser} that represents yourself.
|
||||||
*/
|
*/
|
||||||
@WithBridgeMethods(GHUser.class)
|
@WithBridgeMethods(GHUser.class)
|
||||||
public GHMyself getMyself() throws IOException {
|
public GHMyself getMyself() throws IOException {
|
||||||
requireCredential();
|
requireCredential();
|
||||||
|
synchronized (this) {
|
||||||
|
if (this.myself != null) return myself;
|
||||||
|
|
||||||
|
GHMyself u = retrieve().to("/user", GHMyself.class);
|
||||||
|
|
||||||
GHMyself u = retrieve().to("/user", GHMyself.class);
|
u.root = this;
|
||||||
|
this.myself = u;
|
||||||
u.root = this;
|
return u;
|
||||||
users.put(u.getLogin(), u);
|
}
|
||||||
|
|
||||||
return u;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -328,7 +386,7 @@ public class GitHub {
|
|||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clears all cached data in order for external changes (modifications and del
|
* clears all cached data in order for external changes (modifications and del
|
||||||
*/
|
*/
|
||||||
@@ -416,7 +474,6 @@ public class GitHub {
|
|||||||
*
|
*
|
||||||
* @param key The license key provided from the API
|
* @param key The license key provided from the API
|
||||||
* @return The license details
|
* @return The license details
|
||||||
* @throws IOException
|
|
||||||
* @see GHLicense#getKey()
|
* @see GHLicense#getKey()
|
||||||
*/
|
*/
|
||||||
@Preview @Deprecated
|
@Preview @Deprecated
|
||||||
@@ -591,6 +648,18 @@ public class GitHub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*package*/ GHUser intern(GHUser user) throws IOException {
|
||||||
|
if (user==null) return user;
|
||||||
|
|
||||||
|
// if we already have this user in our map, use it
|
||||||
|
GHUser u = users.get(user.getLogin());
|
||||||
|
if (u!=null) return u;
|
||||||
|
|
||||||
|
// if not, remember this new user
|
||||||
|
users.putIfAbsent(user.getLogin(),user);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
private static class GHApiInfo {
|
private static class GHApiInfo {
|
||||||
private String rate_limit_url;
|
private String rate_limit_url;
|
||||||
|
|
||||||
@@ -652,13 +721,31 @@ public class GitHub {
|
|||||||
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
|
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
|
||||||
X-Content-Type-Options: nosniff
|
X-Content-Type-Options: nosniff
|
||||||
*/
|
*/
|
||||||
return uc.getResponseCode() == HTTP_UNAUTHORIZED
|
try {
|
||||||
&& uc.getHeaderField("X-GitHub-Media-Type") != null;
|
return uc.getResponseCode() == HTTP_UNAUTHORIZED
|
||||||
|
&& uc.getHeaderField("X-GitHub-Media-Type") != null;
|
||||||
|
} finally {
|
||||||
|
// ensure that the connection opened by getResponseCode gets closed
|
||||||
|
try {
|
||||||
|
IOUtils.closeQuietly(uc.getInputStream());
|
||||||
|
} catch (IOException ignore) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
IOUtils.closeQuietly(uc.getErrorStream());
|
||||||
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search commits.
|
||||||
|
*/
|
||||||
|
@Preview @Deprecated
|
||||||
|
public GHCommitSearchBuilder searchCommits() {
|
||||||
|
return new GHCommitSearchBuilder(this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search issues.
|
* Search issues.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import org.kohsuke.github.extras.ImpatientHttpConnector;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pluggability for customizing HTTP request behaviors or using altogether different library.
|
* Pluggability for customizing HTTP request behaviors or using altogether different library.
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import javax.annotation.CheckForNull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
import javax.annotation.CheckForNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link IOException} for http exceptions because {@link HttpURLConnection} throws un-discerned
|
* {@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
|
* {@link IOException} and it can help to know the http response code to decide how to handle an
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import java.util.List;
|
|||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterator over a pagenated data source.
|
* Iterator over a paginated data source.
|
||||||
*
|
*
|
||||||
* Aside from the normal iterator operation, this method exposes {@link #nextPage()}
|
* Aside from the normal iterator operation, this method exposes {@link #nextPage()}
|
||||||
* that allows the caller to retrieve items per page.
|
* that allows the caller to retrieve items per page.
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.kohsuke.github;
|
|||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,4 +7,6 @@ package org.kohsuke.github;
|
|||||||
static final String LOKI = "application/vnd.github.loki-preview+json";
|
static final String LOKI = "application/vnd.github.loki-preview+json";
|
||||||
static final String DRAX = "application/vnd.github.drax-preview+json";
|
static final String DRAX = "application/vnd.github.drax-preview+json";
|
||||||
static final String SQUIRREL_GIRL = "application/vnd.github.squirrel-girl-preview";
|
static final String SQUIRREL_GIRL = "application/vnd.github.squirrel-girl-preview";
|
||||||
|
static final String CLOAK = "application/vnd.github.cloak-preview";
|
||||||
|
static final String BLACK_CAT = "application/vnd.github.black-cat-preview+json";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,10 @@ package org.kohsuke.github;
|
|||||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
|
||||||
|
import javax.annotation.CheckForNull;
|
||||||
|
import javax.annotation.WillClose;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -38,10 +41,12 @@ import java.lang.reflect.Field;
|
|||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.ProtocolException;
|
import java.net.ProtocolException;
|
||||||
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@@ -49,15 +54,15 @@ import java.util.List;
|
|||||||
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.Level;
|
||||||
import java.util.logging.Logger;
|
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;
|
||||||
|
|
||||||
import javax.annotation.WillClose;
|
import static java.util.Arrays.*;
|
||||||
|
import static java.util.logging.Level.*;
|
||||||
import static java.util.Arrays.asList;
|
import static org.apache.commons.lang.StringUtils.*;
|
||||||
import static java.util.logging.Level.FINE;
|
|
||||||
import static org.kohsuke.github.GitHub.*;
|
import static org.kohsuke.github.GitHub.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,7 +79,7 @@ class Requester {
|
|||||||
* Request method.
|
* Request method.
|
||||||
*/
|
*/
|
||||||
private String method = "POST";
|
private String method = "POST";
|
||||||
private String contentType = "application/x-www-form-urlencoded";
|
private String contentType = null;
|
||||||
private InputStream body;
|
private InputStream body;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,6 +173,11 @@ class Requester {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Requester withNullable(String key, Object value) {
|
||||||
|
args.add(new Entry(key, value));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Requester _with(String key, Object value) {
|
public Requester _with(String key, Object value) {
|
||||||
if (value!=null) {
|
if (value!=null) {
|
||||||
args.add(new Entry(key,value));
|
args.add(new Entry(key,value));
|
||||||
@@ -268,7 +278,7 @@ class Requester {
|
|||||||
if (nextLinkMatcher.find()) {
|
if (nextLinkMatcher.find()) {
|
||||||
final String link = nextLinkMatcher.group(1);
|
final String link = nextLinkMatcher.group(1);
|
||||||
T nextResult = _to(link, type, instance);
|
T nextResult = _to(link, type, instance);
|
||||||
|
setResponseHeaders(nextResult);
|
||||||
final int resultLength = Array.getLength(result);
|
final int resultLength = Array.getLength(result);
|
||||||
final int nextResultLength = Array.getLength(nextResult);
|
final int nextResultLength = Array.getLength(nextResult);
|
||||||
T concatResult = (T) Array.newInstance(type.getComponentType(), resultLength + nextResultLength);
|
T concatResult = (T) Array.newInstance(type.getComponentType(), resultLength + nextResultLength);
|
||||||
@@ -278,9 +288,11 @@ class Requester {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return setResponseHeaders(result);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
handleApiError(e);
|
handleApiError(e);
|
||||||
|
} finally {
|
||||||
|
noteRateLimit(tailApiUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -299,6 +311,8 @@ class Requester {
|
|||||||
return uc.getResponseCode();
|
return uc.getResponseCode();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
handleApiError(e);
|
handleApiError(e);
|
||||||
|
} finally {
|
||||||
|
noteRateLimit(tailApiUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -308,11 +322,64 @@ class Requester {
|
|||||||
setupConnection(root.getApiURL(tailApiUrl));
|
setupConnection(root.getApiURL(tailApiUrl));
|
||||||
|
|
||||||
buildRequest();
|
buildRequest();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return wrapStream(uc.getInputStream());
|
return wrapStream(uc.getInputStream());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
handleApiError(e);
|
handleApiError(e);
|
||||||
|
} finally {
|
||||||
|
noteRateLimit(tailApiUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void noteRateLimit(String tailApiUrl) {
|
||||||
|
if ("/rate_limit".equals(tailApiUrl)) {
|
||||||
|
// the rate_limit API is "free"
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (tailApiUrl.startsWith("/search")) {
|
||||||
|
// the search API uses a different rate limit
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String limit = uc.getHeaderField("X-RateLimit-Limit");
|
||||||
|
if (StringUtils.isBlank(limit)) {
|
||||||
|
// if we are missing a header, return fast
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String remaining = uc.getHeaderField("X-RateLimit-Remaining");
|
||||||
|
if (StringUtils.isBlank(remaining)) {
|
||||||
|
// if we are missing a header, return fast
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String reset = uc.getHeaderField("X-RateLimit-Reset");
|
||||||
|
if (StringUtils.isBlank(reset)) {
|
||||||
|
// if we are missing a header, return fast
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GHRateLimit observed = new GHRateLimit();
|
||||||
|
try {
|
||||||
|
observed.limit = Integer.parseInt(limit);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
if (LOGGER.isLoggable(FINEST)) {
|
||||||
|
LOGGER.log(FINEST, "Malformed X-RateLimit-Limit header value " + limit, e);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
observed.remaining = Integer.parseInt(remaining);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
if (LOGGER.isLoggable(FINEST)) {
|
||||||
|
LOGGER.log(FINEST, "Malformed X-RateLimit-Remaining header value " + remaining, e);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
observed.reset = new Date(Long.parseLong(reset)); // this is madness, storing the date as seconds
|
||||||
|
root.updateRateLimit(observed);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
if (LOGGER.isLoggable(FINEST)) {
|
||||||
|
LOGGER.log(FINEST, "Malformed X-RateLimit-Reset header value " + reset, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -328,18 +395,19 @@ class Requester {
|
|||||||
private void buildRequest() throws IOException {
|
private void buildRequest() throws IOException {
|
||||||
if (isMethodWithBody()) {
|
if (isMethodWithBody()) {
|
||||||
uc.setDoOutput(true);
|
uc.setDoOutput(true);
|
||||||
uc.setRequestProperty("Content-type", contentType);
|
|
||||||
|
|
||||||
if (body == null) {
|
if (body == null) {
|
||||||
|
uc.setRequestProperty("Content-type", defaultString(contentType,"application/json"));
|
||||||
Map json = new HashMap();
|
Map json = new HashMap();
|
||||||
for (Entry e : args) {
|
for (Entry e : args) {
|
||||||
json.put(e.key, e.value);
|
json.put(e.key, e.value);
|
||||||
}
|
}
|
||||||
MAPPER.writeValue(uc.getOutputStream(), json);
|
MAPPER.writeValue(uc.getOutputStream(), json);
|
||||||
} else {
|
} else {
|
||||||
|
uc.setRequestProperty("Content-type", defaultString(contentType,"application/x-www-form-urlencoded"));
|
||||||
try {
|
try {
|
||||||
byte[] bytes = new byte[32768];
|
byte[] bytes = new byte[32768];
|
||||||
int read = 0;
|
int read;
|
||||||
while ((read = body.read(bytes)) != -1) {
|
while ((read = body.read(bytes)) != -1) {
|
||||||
uc.getOutputStream().write(bytes, 0, read);
|
uc.getOutputStream().write(bytes, 0, read);
|
||||||
}
|
}
|
||||||
@@ -355,7 +423,7 @@ class Requester {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads pagenated resources.
|
* Loads paginated resources.
|
||||||
*
|
*
|
||||||
* Every iterator call reports a new batch.
|
* Every iterator call reports a new batch.
|
||||||
*/
|
*/
|
||||||
@@ -382,7 +450,7 @@ class Requester {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new PagingIterator<T>(type, root.getApiURL(s.toString()));
|
return new PagingIterator<T>(type, tailApiUrl, root.getApiURL(s.toString()));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new Error(e);
|
throw new Error(e);
|
||||||
}
|
}
|
||||||
@@ -391,6 +459,7 @@ class Requester {
|
|||||||
class PagingIterator<T> implements Iterator<T> {
|
class PagingIterator<T> implements Iterator<T> {
|
||||||
|
|
||||||
private final Class<T> type;
|
private final Class<T> type;
|
||||||
|
private final String tailApiUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The next batch to be returned from {@link #next()}.
|
* The next batch to be returned from {@link #next()}.
|
||||||
@@ -402,9 +471,10 @@ class Requester {
|
|||||||
*/
|
*/
|
||||||
private URL url;
|
private URL url;
|
||||||
|
|
||||||
PagingIterator(Class<T> type, URL url) {
|
PagingIterator(Class<T> type, String tailApiUrl, URL url) {
|
||||||
this.url = url;
|
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.tailApiUrl = tailApiUrl;
|
||||||
|
this.url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
@@ -438,6 +508,8 @@ class Requester {
|
|||||||
return;
|
return;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
handleApiError(e);
|
handleApiError(e);
|
||||||
|
} finally {
|
||||||
|
noteRateLimit(tailApiUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -517,7 +589,12 @@ class Requester {
|
|||||||
throw new IllegalStateException("Failed to set the request method to "+method);
|
throw new IllegalStateException("Failed to set the request method to "+method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CheckForNull
|
||||||
private <T> T parse(Class<T> type, T instance) throws IOException {
|
private <T> T parse(Class<T> type, T instance) throws IOException {
|
||||||
|
return parse(type, instance, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T parse(Class<T> type, T instance, int timeouts) throws IOException {
|
||||||
InputStreamReader r = null;
|
InputStreamReader r = null;
|
||||||
int responseCode = -1;
|
int responseCode = -1;
|
||||||
String responseMessage = null;
|
String responseMessage = null;
|
||||||
@@ -536,24 +613,44 @@ class Requester {
|
|||||||
String data = IOUtils.toString(r);
|
String data = IOUtils.toString(r);
|
||||||
if (type!=null)
|
if (type!=null)
|
||||||
try {
|
try {
|
||||||
return MAPPER.readValue(data,type);
|
return setResponseHeaders(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 setResponseHeaders(MAPPER.readerForUpdating(instance).<T>readValue(data));
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
// java.net.URLConnection handles 404 exception has FileNotFoundException, don't wrap exception in HttpException
|
// java.net.URLConnection handles 404 exception has FileNotFoundException, don't wrap exception in HttpException
|
||||||
// to preserve backward compatibility
|
// to preserve backward compatibility
|
||||||
throw e;
|
throw e;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
if (e instanceof SocketTimeoutException && timeouts > 0) {
|
||||||
|
LOGGER.log(INFO, "timed out accessing " + uc.getURL() + "; will try " + timeouts + " more time(s)", e);
|
||||||
|
return parse(type, instance, timeouts - 1);
|
||||||
|
}
|
||||||
throw new HttpException(responseCode, responseMessage, uc.getURL(), e);
|
throw new HttpException(responseCode, responseMessage, uc.getURL(), e);
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(r);
|
IOUtils.closeQuietly(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <T> T setResponseHeaders(T readValue) {
|
||||||
|
if (readValue instanceof GHObject[]) {
|
||||||
|
for (GHObject ghObject : (GHObject[]) readValue) {
|
||||||
|
setResponseHeaders(ghObject);
|
||||||
|
}
|
||||||
|
} else if (readValue instanceof GHObject) {
|
||||||
|
setResponseHeaders((GHObject) readValue);
|
||||||
|
}
|
||||||
|
return readValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setResponseHeaders(GHObject readValue) {
|
||||||
|
readValue.responseHeaderFields = uc.getHeaderFields();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the "Content-Encoding" header.
|
* Handles the "Content-Encoding" header.
|
||||||
*/
|
*/
|
||||||
@@ -580,6 +677,24 @@ class Requester {
|
|||||||
" handling exception " + e, e);
|
" handling exception " + e, e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
InputStream es = wrapStream(uc.getErrorStream());
|
||||||
|
if (es != null) {
|
||||||
|
try {
|
||||||
|
String error = IOUtils.toString(es, "UTF-8");
|
||||||
|
if (e instanceof FileNotFoundException) {
|
||||||
|
// pass through 404 Not Found to allow the caller to handle it intelligently
|
||||||
|
e = (IOException) new GHFileNotFoundException(error).withResponseHeaderFields(uc).initCause(e);
|
||||||
|
} else if (e instanceof HttpException) {
|
||||||
|
HttpException http = (HttpException) e;
|
||||||
|
e = new HttpException(error, http.getResponseCode(), http.getResponseMessage(),
|
||||||
|
http.getUrl(), e);
|
||||||
|
} else {
|
||||||
|
e = (IOException) new GHIOException(error).withResponseHeaderFields(uc).initCause(e);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(es);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) // 401 / Unauthorized == bad creds
|
if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) // 401 / Unauthorized == bad creds
|
||||||
throw e;
|
throw e;
|
||||||
|
|
||||||
@@ -595,19 +710,7 @@ class Requester {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputStream es = wrapStream(uc.getErrorStream());
|
throw e;
|
||||||
try {
|
|
||||||
if (es!=null) {
|
|
||||||
if (e instanceof FileNotFoundException) {
|
|
||||||
// pass through 404 Not Found to allow the caller to handle it intelligently
|
|
||||||
throw (IOException) new FileNotFoundException(IOUtils.toString(es, "UTF-8")).initCause(e);
|
|
||||||
} else
|
|
||||||
throw (IOException) new IOException(IOUtils.toString(es, "UTF-8")).initCause(e);
|
|
||||||
} else
|
|
||||||
throw e;
|
|
||||||
} finally {
|
|
||||||
IOUtils.closeQuietly(es);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final List<String> METHODS_WITHOUT_BODY = asList("GET", "DELETE");
|
private static final List<String> METHODS_WITHOUT_BODY = asList("GET", "DELETE");
|
||||||
|
|||||||
16
src/main/java/org/kohsuke/github/TrafficInfo.java
Normal file
16
src/main/java/org/kohsuke/github/TrafficInfo.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
*/
|
||||||
|
public interface TrafficInfo {
|
||||||
|
/**
|
||||||
|
* Total count of hits.
|
||||||
|
*/
|
||||||
|
int getCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique visitors.
|
||||||
|
*/
|
||||||
|
int getUniques();
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package org.kohsuke.github.extras;
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.OkUrlFactory;
|
||||||
|
import org.kohsuke.github.HttpConnector;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link HttpConnector} for {@link OkHttpClient}.
|
||||||
|
*
|
||||||
|
* Unlike {@link #DEFAULT}, OkHttp does response caching.
|
||||||
|
* Making a conditional request against GitHubAPI and receiving a 304
|
||||||
|
* response does not count against the rate limit.
|
||||||
|
* See http://developer.github.com/v3/#conditional-requests
|
||||||
|
*
|
||||||
|
* @author Roberto Tyley
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
*/
|
||||||
|
public class OkHttp3Connector implements HttpConnector {
|
||||||
|
private final OkUrlFactory urlFactory;
|
||||||
|
|
||||||
|
public OkHttp3Connector(OkUrlFactory urlFactory) {
|
||||||
|
this.urlFactory = urlFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpURLConnection connect(URL url) throws IOException {
|
||||||
|
return urlFactory.open(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
import org.kohsuke.github.GHRepository;
|
|
||||||
import org.kohsuke.github.GHRepository.Contributor;
|
import org.kohsuke.github.GHRepository.Contributor;
|
||||||
import org.kohsuke.github.GHUser;
|
import org.kohsuke.github.GHUser;
|
||||||
import org.kohsuke.github.GitHub;
|
import org.kohsuke.github.GitHub;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kohsuke Kawaguchi
|
* @author Kohsuke Kawaguchi
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.util.Properties;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
import org.junit.Assume;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.kohsuke.randname.RandomNameGenerator;
|
import org.kohsuke.randname.RandomNameGenerator;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kohsuke Kawaguchi
|
* @author Kohsuke Kawaguchi
|
||||||
@@ -17,13 +22,34 @@ public abstract class AbstractGitHubApiTestBase extends Assert {
|
|||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
File f = new File(System.getProperty("user.home"), ".github.kohsuke2");
|
File f = new File(System.getProperty("user.home"), ".github.kohsuke2");
|
||||||
if (f.exists()) {
|
if (f.exists()) {
|
||||||
|
Properties props = new Properties();
|
||||||
|
FileInputStream in = null;
|
||||||
|
try {
|
||||||
|
in = new FileInputStream(f);
|
||||||
|
props.load(in);
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(in);
|
||||||
|
}
|
||||||
// use the non-standard credential preferentially, so that developers of this library do not have
|
// use the non-standard credential preferentially, so that developers of this library do not have
|
||||||
// to clutter their event stream.
|
// to clutter their event stream.
|
||||||
gitHub = GitHubBuilder.fromPropertyFile(f.getPath()).withRateLimitHandler(RateLimitHandler.FAIL).build();
|
gitHub = GitHubBuilder.fromProperties(props).withRateLimitHandler(RateLimitHandler.FAIL).build();
|
||||||
} else {
|
} else {
|
||||||
gitHub = GitHubBuilder.fromCredentials().withRateLimitHandler(RateLimitHandler.FAIL).build();
|
gitHub = GitHubBuilder.fromCredentials().withRateLimitHandler(RateLimitHandler.FAIL).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected GHUser getUser() {
|
||||||
|
try {
|
||||||
|
return gitHub.getMyself();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void kohsuke() {
|
||||||
|
String login = getUser().getLogin();
|
||||||
|
Assume.assumeTrue(login.equals("kohsuke") || login.equals("kohsuke2"));
|
||||||
|
}
|
||||||
|
|
||||||
protected static final RandomNameGenerator rnd = new RandomNameGenerator();
|
protected static final RandomNameGenerator rnd = new RandomNameGenerator();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,17 +5,15 @@ import com.google.common.collect.Iterables;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.hamcrest.CoreMatchers;
|
|
||||||
import org.junit.Assume;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.kohsuke.github.GHCommit.File;
|
import org.kohsuke.github.GHCommit.File;
|
||||||
import org.kohsuke.github.GHOrganization.Permission;
|
import org.kohsuke.github.GHOrganization.Permission;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
import static org.hamcrest.CoreMatchers.*;
|
||||||
@@ -172,14 +170,6 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
|||||||
return repository;
|
return repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
private GHUser getUser() {
|
|
||||||
try {
|
|
||||||
return gitHub.getMyself();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListIssues() throws IOException {
|
public void testListIssues() throws IOException {
|
||||||
GHUser u = getUser();
|
GHUser u = getUser();
|
||||||
@@ -362,6 +352,11 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
|||||||
assertEquals(48,f.getLinesChanged());
|
assertEquals(48,f.getLinesChanged());
|
||||||
assertEquals("modified",f.getStatus());
|
assertEquals("modified",f.getStatus());
|
||||||
assertEquals("changelog.html", f.getFileName());
|
assertEquals("changelog.html", f.getFileName());
|
||||||
|
|
||||||
|
// walk the tree
|
||||||
|
GHTree t = commit.getTree();
|
||||||
|
assertThat(IOUtils.toString(t.getEntry("todo.txt").readAsBlob()), containsString("executor rendering"));
|
||||||
|
assertNotNull(t.getEntry("war").asTree());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -687,6 +682,15 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
|||||||
assertFalse(all.isEmpty());
|
assertFalse(all.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCommitSearch() throws IOException {
|
||||||
|
PagedSearchIterable<GHCommit> r = gitHub.searchCommits().author("kohsuke").list();
|
||||||
|
assertTrue(r.getTotalCount() > 0);
|
||||||
|
|
||||||
|
GHCommit firstCommit = r.iterator().next();
|
||||||
|
assertTrue(firstCommit.getFiles().size() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIssueSearch() throws IOException {
|
public void testIssueSearch() throws IOException {
|
||||||
PagedSearchIterable<GHIssue> r = gitHub.searchIssues().mentions("kohsuke").isOpen().list();
|
PagedSearchIterable<GHIssue> r = gitHub.searchIssues().mentions("kohsuke").isOpen().list();
|
||||||
@@ -903,8 +907,23 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void kohsuke() {
|
@Test
|
||||||
String login = getUser().getLogin();
|
public void blob() throws Exception {
|
||||||
Assume.assumeTrue(login.equals("kohsuke") || login.equals("kohsuke2"));
|
GHRepository r = gitHub.getRepository("kohsuke/github-api");
|
||||||
|
String sha1 = "a12243f2fc5b8c2ba47dd677d0b0c7583539584d";
|
||||||
|
|
||||||
|
assertBlobContent(r.readBlob(sha1));
|
||||||
|
|
||||||
|
GHBlob blob = r.getBlob(sha1);
|
||||||
|
assertBlobContent(blob.read());
|
||||||
|
assertThat(blob.getSha(),is("a12243f2fc5b8c2ba47dd677d0b0c7583539584d"));
|
||||||
|
assertThat(blob.getSize(),is(1104L));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertBlobContent(InputStream is) throws Exception {
|
||||||
|
String content = new String(IOUtils.toByteArray(is),"UTF-8");
|
||||||
|
assertThat(content,containsString("Copyright (c) 2011- Kohsuke Kawaguchi and other contributors"));
|
||||||
|
assertThat(content,containsString("FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR"));
|
||||||
|
assertThat(content.length(),is(1104));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Iterators;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|||||||
82
src/test/java/org/kohsuke/github/GHBranchProtectionTest.java
Normal file
82
src/test/java/org/kohsuke/github/GHBranchProtectionTest.java
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.kohsuke.github.GHBranchProtection.EnforceAdmins;
|
||||||
|
import org.kohsuke.github.GHBranchProtection.RequiredReviews;
|
||||||
|
import org.kohsuke.github.GHBranchProtection.RequiredStatusChecks;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
|
||||||
|
public class GHBranchProtectionTest extends AbstractGitHubApiTestBase {
|
||||||
|
private static final String BRANCH = "bp-test";
|
||||||
|
private static final String BRANCH_REF = "heads/" + BRANCH;
|
||||||
|
|
||||||
|
private GHBranch branch;
|
||||||
|
|
||||||
|
private GHRepository repo;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
repo = gitHub.getRepository("github-api-test-org/GHContentIntegrationTest").fork();
|
||||||
|
|
||||||
|
try {
|
||||||
|
repo.getRef(BRANCH_REF);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
repo.createRef("refs/" + BRANCH_REF, repo.getBranch("master").getSHA1());
|
||||||
|
}
|
||||||
|
|
||||||
|
branch = repo.getBranch(BRANCH);
|
||||||
|
|
||||||
|
if (branch.isProtected()) {
|
||||||
|
branch.disableProtection();
|
||||||
|
}
|
||||||
|
|
||||||
|
branch = repo.getBranch(BRANCH);
|
||||||
|
assertFalse(branch.isProtected());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableBranchProtections() throws Exception {
|
||||||
|
// team/user restrictions require an organization repo to test against
|
||||||
|
GHBranchProtection protection = branch.enableProtection()
|
||||||
|
.addRequiredChecks("test-status-check")
|
||||||
|
.requireBranchIsUpToDate()
|
||||||
|
.requireCodeOwnReviews()
|
||||||
|
.dismissStaleReviews()
|
||||||
|
.includeAdmins()
|
||||||
|
.enable();
|
||||||
|
|
||||||
|
RequiredStatusChecks statusChecks = protection.getRequiredStatusChecks();
|
||||||
|
assertNotNull(statusChecks);
|
||||||
|
assertTrue(statusChecks.isRequiresBranchUpToDate());
|
||||||
|
assertTrue(statusChecks.getContexts().contains("test-status-check"));
|
||||||
|
|
||||||
|
RequiredReviews requiredReviews = protection.getRequiredReviews();
|
||||||
|
assertNotNull(requiredReviews);
|
||||||
|
assertTrue(requiredReviews.isDismissStaleReviews());
|
||||||
|
assertTrue(requiredReviews.isRequireCodeOwnerReviews());
|
||||||
|
|
||||||
|
EnforceAdmins enforceAdmins = protection.getEnforceAdmins();
|
||||||
|
assertNotNull(enforceAdmins);
|
||||||
|
assertTrue(enforceAdmins.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableProtectionOnly() throws Exception {
|
||||||
|
branch.enableProtection().enable();
|
||||||
|
assertTrue(repo.getBranch(BRANCH).isProtected());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnableRequireReviewsOnly() throws Exception {
|
||||||
|
GHBranchProtection protection = branch.enableProtection()
|
||||||
|
.requireReviews()
|
||||||
|
.enable();
|
||||||
|
|
||||||
|
assertNotNull(protection.getRequiredReviews());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,13 +20,6 @@ public class GHContentIntegrationTest extends AbstractGitHubApiTestBase {
|
|||||||
repo = gitHub.getRepository("github-api-test-org/GHContentIntegrationTest").fork();
|
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
|
@Test
|
||||||
public void testGetFileContent() throws Exception {
|
public void testGetFileContent() throws Exception {
|
||||||
GHContent content = repo.getFileContent("ghcontent-ro/a-file-with-content");
|
GHContent content = repo.getFileContent("ghcontent-ro/a-file-with-content");
|
||||||
|
|||||||
78
src/test/java/org/kohsuke/github/GHHookTest.java
Normal file
78
src/test/java/org/kohsuke/github/GHHookTest.java
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
import static java.util.Collections.singletonMap;
|
||||||
|
import static org.hamcrest.Matchers.hasItem;
|
||||||
|
import static org.hamcrest.Matchers.hasKey;
|
||||||
|
import static org.hamcrest.Matchers.hasValue;
|
||||||
|
import static org.hamcrest.core.IsInstanceOf.instanceOf;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kanstantsin Shautsou
|
||||||
|
*/
|
||||||
|
public class GHHookTest {
|
||||||
|
|
||||||
|
@Ignore
|
||||||
|
@Test
|
||||||
|
public void exposeResponceHeaders() throws Exception {
|
||||||
|
String user1Login = "KostyaSha-auto";
|
||||||
|
String user1Pass = "secret";
|
||||||
|
|
||||||
|
String clientId = "90140219451";
|
||||||
|
String clientSecret = "1451245425";
|
||||||
|
|
||||||
|
String orgRepo = "KostyaSha-org/test";
|
||||||
|
|
||||||
|
// some login based user that has access to application
|
||||||
|
final GitHub gitHub = GitHub.connectUsingPassword(user1Login, user1Pass);
|
||||||
|
gitHub.getMyself();
|
||||||
|
|
||||||
|
// we request read
|
||||||
|
final List<String> scopes = Arrays.asList("repo", "read:org", "user:email", "read:repo_hook");
|
||||||
|
|
||||||
|
// application creates token with scopes
|
||||||
|
final GHAuthorization auth = gitHub.createOrGetAuth(clientId, clientSecret, scopes, "", "");
|
||||||
|
String token = auth.getToken();
|
||||||
|
if (StringUtils.isEmpty(token)) {
|
||||||
|
gitHub.deleteAuth(auth.getId());
|
||||||
|
token = gitHub.createOrGetAuth(clientId, clientSecret, scopes, "", "").getToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// now create connection using token
|
||||||
|
final GitHub gitHub2 = GitHub.connectUsingOAuth(token);
|
||||||
|
// some repo in organisation
|
||||||
|
final GHRepository repository = gitHub2.getRepository(orgRepo);
|
||||||
|
|
||||||
|
// doesn't fail because we have read access
|
||||||
|
final List<GHHook> hooks = repository.getHooks();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// fails because application isn't approved in organisation and you can find it only after doing real call
|
||||||
|
final GHHook hook = repository.createHook(
|
||||||
|
"my-hook",
|
||||||
|
singletonMap("url", "http://localhost"),
|
||||||
|
singletonList(GHEvent.PUSH),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
assertThat(ex, instanceOf(GHFileNotFoundException.class));
|
||||||
|
final GHFileNotFoundException ghFileNotFoundException = (GHFileNotFoundException) ex;
|
||||||
|
final Map<String, List<String>> responseHeaderFields = ghFileNotFoundException.getResponseHeaderFields();
|
||||||
|
assertThat(responseHeaderFields, hasKey("X-Accepted-OAuth-Scopes"));
|
||||||
|
assertThat(responseHeaderFields.get("X-Accepted-OAuth-Scopes"),
|
||||||
|
hasItem("admin:repo_hook, public_repo, repo, write:repo_hook")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,6 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Iterators;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import java.io.IOException;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kohsuke Kawaguchi
|
* @author Kohsuke Kawaguchi
|
||||||
*/
|
*/
|
||||||
@@ -26,6 +29,33 @@ public class PullRequestTest extends AbstractGitHubApiTestBase {
|
|||||||
p.comment("Some comment");
|
p.comment("Some comment");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPullRequestReviews() throws Exception {
|
||||||
|
String name = rnd.next();
|
||||||
|
GHPullRequest p = getRepository().createPullRequest(name, "stable", "master", "## test");
|
||||||
|
GHPullRequestReview draftReview = p.createReview("Some draft review", null,
|
||||||
|
GHPullRequestReviewComment.draft("Some niggle", "changelog.html", 1)
|
||||||
|
);
|
||||||
|
assertThat(draftReview.getState(), is(GHPullRequestReviewState.PENDING));
|
||||||
|
assertThat(draftReview.getBody(), is("Some draft review"));
|
||||||
|
assertThat(draftReview.getCommitId(), notNullValue());
|
||||||
|
List<GHPullRequestReview> reviews = p.listReviews().asList();
|
||||||
|
assertThat(reviews.size(), is(1));
|
||||||
|
GHPullRequestReview review = reviews.get(0);
|
||||||
|
assertThat(review.getState(), is(GHPullRequestReviewState.PENDING));
|
||||||
|
assertThat(review.getBody(), is("Some draft review"));
|
||||||
|
assertThat(review.getCommitId(), notNullValue());
|
||||||
|
review.submit("Some review comment", GHPullRequestReviewState.COMMENTED);
|
||||||
|
List<GHPullRequestReviewComment> comments = review.listReviewComments().asList();
|
||||||
|
assertEquals(1, comments.size());
|
||||||
|
GHPullRequestReviewComment comment = comments.get(0);
|
||||||
|
assertEquals("Some niggle", comment.getBody());
|
||||||
|
review = p.createReview("Some new review", null,
|
||||||
|
GHPullRequestReviewComment.draft("Some niggle", "changelog.html", 1)
|
||||||
|
);
|
||||||
|
review.delete();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPullRequestReviewComments() throws Exception {
|
public void testPullRequestReviewComments() throws Exception {
|
||||||
String name = rnd.next();
|
String name = rnd.next();
|
||||||
@@ -69,6 +99,19 @@ public class PullRequestTest extends AbstractGitHubApiTestBase {
|
|||||||
fail();
|
fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSquashMerge() throws Exception {
|
||||||
|
String name = rnd.next();
|
||||||
|
GHRef masterRef = getRepository().getRef("heads/master");
|
||||||
|
GHRef branchRef = getRepository().createRef("refs/heads/" + name, masterRef.getObject().getSha());
|
||||||
|
getRepository().createContent(name, name, name, name);
|
||||||
|
Thread.sleep(1000);
|
||||||
|
GHPullRequest p = getRepository().createPullRequest(name, name, "master", "## test squash");
|
||||||
|
Thread.sleep(1000);
|
||||||
|
p.merge("squash merge", null, GHPullRequest.MergeMethod.SQUASH);
|
||||||
|
branchRef.delete();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
// Requires push access to the test repo to pass
|
// Requires push access to the test repo to pass
|
||||||
public void setLabels() throws Exception {
|
public void setLabels() throws Exception {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.kohsuke.github;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.kohsuke.github.GHRepository.Contributor;
|
import org.kohsuke.github.GHRepository.Contributor;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,6 +41,59 @@ public class RepositoryTest extends AbstractGitHubApiTestBase {
|
|||||||
assertTrue(kohsuke);
|
assertTrue(kohsuke);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPermission() throws Exception {
|
||||||
|
kohsuke();
|
||||||
|
GHRepository r = gitHub.getRepository("github-api-test-org/test-permission");
|
||||||
|
assertEquals(GHPermissionType.ADMIN, r.getPermission("kohsuke"));
|
||||||
|
assertEquals(GHPermissionType.READ, r.getPermission("dude"));
|
||||||
|
r = gitHub.getOrganization("apache").getRepository("groovy");
|
||||||
|
try {
|
||||||
|
r.getPermission("jglick");
|
||||||
|
fail();
|
||||||
|
} catch (HttpException x) {
|
||||||
|
x.printStackTrace(); // good
|
||||||
|
assertEquals(403, x.getResponseCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false) {
|
||||||
|
// can't easily test this; there's no private repository visible to the test user
|
||||||
|
r = gitHub.getOrganization("cloudbees").getRepository("private-repo-not-writable-by-me");
|
||||||
|
try {
|
||||||
|
r.getPermission("jglick");
|
||||||
|
fail();
|
||||||
|
} catch (FileNotFoundException x) {
|
||||||
|
x.printStackTrace(); // good
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void LatestRepositoryExist() {
|
||||||
|
try {
|
||||||
|
// add the repository that have latest release
|
||||||
|
GHRelease release = gitHub.getRepository("kamontat/CheckIDNumber").getLatestRelease();
|
||||||
|
assertEquals("v3.0", release.getTagName());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void LatestRepositoryNotExist() {
|
||||||
|
try {
|
||||||
|
// add the repository that `NOT` have latest release
|
||||||
|
GHRelease release = gitHub.getRepository("kamontat/Java8Example").getLatestRelease();
|
||||||
|
assertNull(release);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private GHRepository getRepository() throws IOException {
|
private GHRepository getRepository() throws IOException {
|
||||||
return gitHub.getOrganization("github-api-test-org").getRepository("jenkins");
|
return gitHub.getOrganization("github-api-test-org").getRepository("jenkins");
|
||||||
}
|
}
|
||||||
|
|||||||
167
src/test/java/org/kohsuke/github/RepositoryTrafficTest.java
Normal file
167
src/test/java/org/kohsuke/github/RepositoryTrafficTest.java
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.kohsuke.github.GHRepositoryTraffic.DailyInfo;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
public class RepositoryTrafficTest {
|
||||||
|
final private String login = "kohsuke", repositoryName = "github-api";
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T extends GHRepositoryTraffic> void checkResponse(T expected, T actual){
|
||||||
|
Assert.assertEquals(expected.getCount(), actual.getCount());
|
||||||
|
Assert.assertEquals(expected.getUniques(), actual.getUniques());
|
||||||
|
|
||||||
|
List<? extends DailyInfo> expectedList = expected.getDailyInfo();
|
||||||
|
List<? extends DailyInfo> actualList = actual.getDailyInfo();
|
||||||
|
Iterator<? extends DailyInfo> expectedIt;
|
||||||
|
Iterator<? extends DailyInfo> actualIt;
|
||||||
|
|
||||||
|
Assert.assertEquals(expectedList.size(), actualList.size());
|
||||||
|
expectedIt = expectedList.iterator();
|
||||||
|
actualIt = actualList.iterator();
|
||||||
|
|
||||||
|
while(expectedIt.hasNext() && actualIt.hasNext()) {
|
||||||
|
DailyInfo expectedDailyInfo = expectedIt.next();
|
||||||
|
DailyInfo actualDailyInfo = actualIt.next();
|
||||||
|
Assert.assertEquals(expectedDailyInfo.getCount(), actualDailyInfo.getCount());
|
||||||
|
Assert.assertEquals(expectedDailyInfo.getUniques(), actualDailyInfo.getUniques());
|
||||||
|
Assert.assertEquals(expectedDailyInfo.getTimestamp(), actualDailyInfo.getTimestamp());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends GHRepositoryTraffic> void testTraffic(T expectedResult) throws IOException{
|
||||||
|
SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||||
|
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||||
|
ObjectMapper mapper = new ObjectMapper().setDateFormat(dateFormat);
|
||||||
|
String mockedResponse = mapper.writeValueAsString(expectedResult);
|
||||||
|
|
||||||
|
|
||||||
|
GitHub gitHub = GitHub.connect(login, null);
|
||||||
|
GitHub gitHubSpy = Mockito.spy(gitHub);
|
||||||
|
GHRepository repo = gitHubSpy.getUser(login).getRepository(repositoryName);
|
||||||
|
|
||||||
|
|
||||||
|
// accessing traffic info requires push access to the repo
|
||||||
|
// since we don't have that, let the mocking begin...
|
||||||
|
|
||||||
|
HttpConnector connectorSpy = Mockito.spy(gitHubSpy.getConnector());
|
||||||
|
Mockito.doReturn(connectorSpy).when(gitHubSpy).getConnector();
|
||||||
|
|
||||||
|
|
||||||
|
// also known as the "uc" in the Requester class
|
||||||
|
HttpURLConnection mockHttpURLConnection = Mockito.mock(HttpURLConnection.class);
|
||||||
|
|
||||||
|
|
||||||
|
// needed for Requester.setRequestMethod
|
||||||
|
Mockito.doReturn("GET").when(mockHttpURLConnection).getRequestMethod();
|
||||||
|
|
||||||
|
|
||||||
|
// this covers calls on "uc" in Requester.setupConnection and Requester.buildRequest
|
||||||
|
URL trafficURL = new URL(
|
||||||
|
"https://api.github.com/repos/"+login+"/"+repositoryName+"/traffic/" +
|
||||||
|
((expectedResult instanceof GHRepositoryViewTraffic) ? "views" : "clones")
|
||||||
|
);
|
||||||
|
Mockito.doReturn(mockHttpURLConnection).when(connectorSpy).connect(Mockito.eq(trafficURL));
|
||||||
|
|
||||||
|
|
||||||
|
// make Requester.parse work
|
||||||
|
Mockito.doReturn(200).when(mockHttpURLConnection).getResponseCode();
|
||||||
|
Mockito.doReturn("OK").when(mockHttpURLConnection).getResponseMessage();
|
||||||
|
InputStream stubInputStream = IOUtils.toInputStream(mockedResponse, "UTF-8");
|
||||||
|
Mockito.doReturn(stubInputStream).when(mockHttpURLConnection).getInputStream();
|
||||||
|
|
||||||
|
if(expectedResult instanceof GHRepositoryViewTraffic){
|
||||||
|
GHRepositoryViewTraffic views = repo.getViewTraffic();
|
||||||
|
checkResponse(expectedResult, views);
|
||||||
|
}
|
||||||
|
else if(expectedResult instanceof GHRepositoryCloneTraffic) {
|
||||||
|
GHRepositoryCloneTraffic clones = repo.getCloneTraffic();
|
||||||
|
checkResponse(expectedResult, clones);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetViews() throws IOException{
|
||||||
|
GHRepositoryViewTraffic expectedResult = new GHRepositoryViewTraffic(
|
||||||
|
21523359,
|
||||||
|
65534,
|
||||||
|
Arrays.asList(
|
||||||
|
new GHRepositoryViewTraffic.DailyInfo("2016-10-10T00:00:00Z", 3, 2),
|
||||||
|
new GHRepositoryViewTraffic.DailyInfo("2016-10-11T00:00:00Z", 9, 4),
|
||||||
|
new GHRepositoryViewTraffic.DailyInfo("2016-10-12T00:00:00Z", 27, 8),
|
||||||
|
new GHRepositoryViewTraffic.DailyInfo("2016-10-13T00:00:00Z", 81, 16),
|
||||||
|
new GHRepositoryViewTraffic.DailyInfo("2016-10-14T00:00:00Z", 243, 32),
|
||||||
|
new GHRepositoryViewTraffic.DailyInfo("2016-10-15T00:00:00Z", 729, 64),
|
||||||
|
new GHRepositoryViewTraffic.DailyInfo("2016-10-16T00:00:00Z", 2187, 128),
|
||||||
|
new GHRepositoryViewTraffic.DailyInfo("2016-10-17T00:00:00Z", 6561, 256),
|
||||||
|
new GHRepositoryViewTraffic.DailyInfo("2016-10-18T00:00:00Z", 19683, 512),
|
||||||
|
new GHRepositoryViewTraffic.DailyInfo("2016-10-19T00:00:00Z", 59049, 1024),
|
||||||
|
new GHRepositoryViewTraffic.DailyInfo("2016-10-20T00:00:00Z", 177147, 2048),
|
||||||
|
new GHRepositoryViewTraffic.DailyInfo("2016-10-21T00:00:00Z", 531441, 4096),
|
||||||
|
new GHRepositoryViewTraffic.DailyInfo("2016-10-22T00:00:00Z", 1594323, 8192),
|
||||||
|
new GHRepositoryViewTraffic.DailyInfo("2016-10-23T00:00:00Z", 4782969, 16384),
|
||||||
|
new GHRepositoryViewTraffic.DailyInfo("2016-10-24T00:00:00Z", 14348907, 32768)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
testTraffic(expectedResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetClones() throws IOException{
|
||||||
|
GHRepositoryCloneTraffic expectedResult = new GHRepositoryCloneTraffic(
|
||||||
|
1500,
|
||||||
|
455,
|
||||||
|
Arrays.asList(
|
||||||
|
new GHRepositoryCloneTraffic.DailyInfo("2016-10-10T00:00:00Z", 10,3),
|
||||||
|
new GHRepositoryCloneTraffic.DailyInfo("2016-10-11T00:00:00Z", 20,6),
|
||||||
|
new GHRepositoryCloneTraffic.DailyInfo("2016-10-12T00:00:00Z", 30,5),
|
||||||
|
new GHRepositoryCloneTraffic.DailyInfo("2016-10-13T00:00:00Z", 40,7),
|
||||||
|
new GHRepositoryCloneTraffic.DailyInfo("2016-10-14T00:00:00Z", 50,11),
|
||||||
|
new GHRepositoryCloneTraffic.DailyInfo("2016-10-15T00:00:00Z", 60,12),
|
||||||
|
new GHRepositoryCloneTraffic.DailyInfo("2016-10-16T00:00:00Z", 70,19),
|
||||||
|
new GHRepositoryCloneTraffic.DailyInfo("2016-10-17T00:00:00Z", 170,111),
|
||||||
|
new GHRepositoryCloneTraffic.DailyInfo("2016-10-18T00:00:00Z", 180,70),
|
||||||
|
new GHRepositoryCloneTraffic.DailyInfo("2016-10-19T00:00:00Z", 190,10),
|
||||||
|
new GHRepositoryCloneTraffic.DailyInfo("2016-10-20T00:00:00Z", 200,18),
|
||||||
|
new GHRepositoryCloneTraffic.DailyInfo("2016-10-21T00:00:00Z", 210,8),
|
||||||
|
new GHRepositoryCloneTraffic.DailyInfo("2016-10-22T00:00:00Z", 220,168),
|
||||||
|
new GHRepositoryCloneTraffic.DailyInfo("2016-10-23T00:00:00Z", 5,2),
|
||||||
|
new GHRepositoryCloneTraffic.DailyInfo("2016-10-24T00:00:00Z", 45,5)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
testTraffic(expectedResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetTrafficStatsAccessFailureDueToInsufficientPermissions() throws IOException {
|
||||||
|
String errorMsg = "Exception should be thrown, since we don't have permission to access repo traffic info.";
|
||||||
|
GitHub gitHub = GitHub.connect(login, null);
|
||||||
|
GHRepository repo = gitHub.getUser(login).getRepository(repositoryName);
|
||||||
|
try {
|
||||||
|
repo.getViewTraffic();
|
||||||
|
Assert.fail(errorMsg);
|
||||||
|
}
|
||||||
|
catch (HttpException ex){
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
repo.getCloneTraffic();
|
||||||
|
Assert.fail(errorMsg);
|
||||||
|
}
|
||||||
|
catch (HttpException ex){
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -65,8 +65,7 @@
|
|||||||
"issues_url": "https://api.github.com/repos/baxterandthehackers/public-repo/issues{/number}",
|
"issues_url": "https://api.github.com/repos/baxterandthehackers/public-repo/issues{/number}",
|
||||||
"pulls_url": "https://api.github.com/repos/baxterandthehackers/public-repo/pulls{/number}",
|
"pulls_url": "https://api.github.com/repos/baxterandthehackers/public-repo/pulls{/number}",
|
||||||
"milestones_url": "https://api.github.com/repos/baxterandthehackers/public-repo/milestones{/number}",
|
"milestones_url": "https://api.github.com/repos/baxterandthehackers/public-repo/milestones{/number}",
|
||||||
"notifications_url": "https://api.github.com/repos/baxterandthehackers/public-repo/notifications{?since,all,
|
"notifications_url": "https://api.github.com/repos/baxterandthehackers/public-repo/notifications{?since,all,participating}",
|
||||||
participating}",
|
|
||||||
"labels_url": "https://api.github.com/repos/baxterandthehackers/public-repo/labels{/name}",
|
"labels_url": "https://api.github.com/repos/baxterandthehackers/public-repo/labels{/name}",
|
||||||
"releases_url": "https://api.github.com/repos/baxterandthehackers/public-repo/releases{/id}",
|
"releases_url": "https://api.github.com/repos/baxterandthehackers/public-repo/releases{/id}",
|
||||||
"deployments_url": "https://api.github.com/repos/baxterandthehackers/public-repo/deployments",
|
"deployments_url": "https://api.github.com/repos/baxterandthehackers/public-repo/deployments",
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
"action": "created",
|
"action": "created",
|
||||||
"milestone": {
|
"milestone": {
|
||||||
"url": "https://api.github.com/repos/baxterandthehackers/public-repo/milestones/3",
|
"url": "https://api.github.com/repos/baxterandthehackers/public-repo/milestones/3",
|
||||||
"html_url": "https://github.com/baxterandthehackers/public-repo/milestones/Test%20milestone%20creation%20webhook
|
"html_url": "https://github.com/baxterandthehackers/public-repo/milestones/Test%20milestone%20creation%20webhook%20from%20command%20line2",
|
||||||
%20from%20command%20line2",
|
|
||||||
"labels_url": "https://api.github.com/repos/baxterandthehackers/public-repo/milestones/3/labels",
|
"labels_url": "https://api.github.com/repos/baxterandthehackers/public-repo/milestones/3/labels",
|
||||||
"id": 2055681,
|
"id": 2055681,
|
||||||
"number": 3,
|
"number": 3,
|
||||||
@@ -96,8 +95,7 @@
|
|||||||
"issues_url": "https://api.github.com/repos/baxterandthehackers/public-repo/issues{/number}",
|
"issues_url": "https://api.github.com/repos/baxterandthehackers/public-repo/issues{/number}",
|
||||||
"pulls_url": "https://api.github.com/repos/baxterandthehackers/public-repo/pulls{/number}",
|
"pulls_url": "https://api.github.com/repos/baxterandthehackers/public-repo/pulls{/number}",
|
||||||
"milestones_url": "https://api.github.com/repos/baxterandthehackers/public-repo/milestones{/number}",
|
"milestones_url": "https://api.github.com/repos/baxterandthehackers/public-repo/milestones{/number}",
|
||||||
"notifications_url": "https://api.github.com/repos/baxterandthehackers/public-repo/notifications{?since,all,
|
"notifications_url": "https://api.github.com/repos/baxterandthehackers/public-repo/notifications{?since,all,participating}",
|
||||||
participating}",
|
|
||||||
"labels_url": "https://api.github.com/repos/baxterandthehackers/public-repo/labels{/name}",
|
"labels_url": "https://api.github.com/repos/baxterandthehackers/public-repo/labels{/name}",
|
||||||
"releases_url": "https://api.github.com/repos/baxterandthehackers/public-repo/releases{/id}",
|
"releases_url": "https://api.github.com/repos/baxterandthehackers/public-repo/releases{/id}",
|
||||||
"deployments_url": "https://api.github.com/repos/baxterandthehackers/public-repo/deployments",
|
"deployments_url": "https://api.github.com/repos/baxterandthehackers/public-repo/deployments",
|
||||||
|
|||||||
Reference in New Issue
Block a user