Compare commits

...

98 Commits

Author SHA1 Message Date
Kohsuke Kawaguchi
188245fa7f [maven-release-plugin] prepare release github-api-1.91 2018-01-13 10:36:45 -08:00
Kohsuke Kawaguchi
e10b747d6a Re-retried the object.
It looks like the format has changed a bit since this payload was
retrieved originally?
2018-01-13 10:30:48 -08:00
Kohsuke Kawaguchi
f2bb6a05a5 Merge pull request #384 2018-01-13 10:19:12 -08:00
Kohsuke Kawaguchi
f41da19db5 Further restoration of the compatibility 2018-01-13 09:54:14 -08:00
Kohsuke Kawaguchi
d0a56dbb21 Merge pull request #406
... with some further changes
2018-01-13 09:47:37 -08:00
Kohsuke Kawaguchi
acbf286e59 Massaged the changes
- Restored binary compatibility. The draft API has changed in some
  significant way when it became public, and the PR took the liberty to
  delete removed constants and method signatures. I brought them back so
  that older clients can keep functioning.

- Introduced a builder pattern to create PR review

- replying to a review comment should be an instance method, not a
  static method.

- GHPullRequestReview and GHPullRequestReviewDraft was not making sense
  to me, since GitHub API doesn't differentiate them. It creates a
  practical problem of not being able to submit a review comment unless
  you created the review comment in the same JVM session. That said, I
  don't understand the point of this two phase approach in the GitHub
  API to begin with!
2018-01-13 09:43:44 -08:00
Kohsuke Kawaguchi
0f7c160409 Based on issue #399, adjusting the behaviour.
This ends up changing the behaviour cloes to that of #394.
2018-01-12 21:33:03 -08:00
Kohsuke Kawaguchi
5113aacb89 Issue #403: Typo in method name 2018-01-12 21:28:37 -08:00
Kohsuke Kawaguchi
4e31636181 Allow the caller to wait for the mergeable state to change.
This approaches #394 differently. The problem with the original #394 is
that the supposed behaviour is only useful for people waiting for
`getMergeable()` to return non-null in a busy loop, yet it impacts all
the other methods of this object.
2018-01-12 21:25:30 -08:00
Kohsuke Kawaguchi
1e497d2c44 Merge branch 'master' into bridge-method-annotation 2018-01-12 21:13:49 -08:00
Kohsuke Kawaguchi
70bd4fa161 Merge pull request #379 2018-01-12 21:12:48 -08:00
Kohsuke Kawaguchi
65996050d5 Massaged changes to follow the convention 2018-01-12 21:12:40 -08:00
Kohsuke Kawaguchi
7f52031199 Merge branch 'master' of github.com:kohsuke/github-api 2018-01-12 21:07:11 -08:00
Kohsuke Kawaguchi
5430f3d33c Merge pull request #391 2018-01-12 21:06:55 -08:00
Kohsuke Kawaguchi
43075faaf8 By convention we use "listXyz" method names 2018-01-12 21:06:47 -08:00
Kohsuke Kawaguchi
f3a1272e31 Merge pull request #397 from mizoguche/set-milestone
Add GHIssue#setMilestone
2018-01-12 21:04:18 -08:00
Kohsuke Kawaguchi
41c028d4d9 Merge pull request #401 2018-01-12 21:00:56 -08:00
Kohsuke Kawaguchi
a17ce04552 Adjustment to compensate 2018-01-12 21:00:25 -08:00
Björn Häuser
d0b4652dcd Replace "new Error" with GHException
(rolled back some of the hunks from the original PR)
2018-01-12 19:44:25 -08:00
Kohsuke Kawaguchi
e66f71c76e Merge pull request #407 from notsudo/GHCreateRepositoryBuilder_Add_Merge_Settings
Adding merge settings to GHCreateRepositoryBuilder
2018-01-12 19:39:03 -08:00
Kohsuke Kawaguchi
6effd4b846 Merge pull request #396 from Rechi/fixGHPersonNullPointer
[fix] GHPerson: check if root is null
2018-01-12 08:45:02 -08:00
Timothy McNally
df861f5403 Adding methods to GHCreateRepositoryBuilder to allow setting the allowed merge methods for pull requests. 2018-01-09 17:32:54 -08:00
Sébastien Lesaint
e74346fed6 support create PR review in single API call & remove @Preview 2018-01-09 14:13:25 +01:00
Sébastien Lesaint
6961c467a6 create review comment reply from GHPullRequest 2018-01-09 14:13:25 +01:00
Sébastien Lesaint
892d305165 add Requester#with override for long value 2018-01-09 14:13:25 +01:00
Sébastien Lesaint
fa16261d7a position of pr comment can be null and original_position is not parsed
position of pr comment is null when comment is outdated (ie. not located in diff patch anymore)
2018-01-09 14:13:25 +01:00
Sébastien Lesaint
15991fd2f7 PullRequest review state and event do not have same values
this fixes parsing of response of WS call submitting a review to fail
when event of new review is REQUEST_CHANGES
also, specifying event when creating a pending PR review is useless and
providing it when submitting the review is enough
2018-01-09 14:13:25 +01:00
Michiaki Mizoguchi
c80b8f60f8 Add GHIssue#setMilestone 2017-11-16 12:42:52 +09:00
Rechi
ab6253cbd0 [fix] GHPerson: check if root is null 2017-11-09 22:41:49 +01:00
sg012265
35ba267115 Revert wildcard usage for imports 2017-10-30 15:38:19 -05:00
sg012265
ab24e6e1c1 Add get for all orgs 2017-10-30 15:32:25 -05:00
Kohsuke Kawaguchi
e25ae27a15 [maven-release-plugin] prepare for next development iteration 2017-10-28 15:54:44 -07:00
Kohsuke Kawaguchi
2b7c524908 [maven-release-plugin] prepare release github-api-1.90 2017-10-28 15:54:33 -07:00
Kohsuke Kawaguchi
0b069df9ce Pick up the version that fixes int->long adaption 2017-10-28 15:48:26 -07:00
Kohsuke Kawaguchi
60c9ba88ae Updated tests 2017-10-28 15:27:38 -07:00
Kohsuke Kawaguchi
cc2e60c84a Merge pull request #388 2017-10-28 09:01:01 -07:00
Kohsuke Kawaguchi
83c2c4e92e Fixed the broken design of how GHDeploymentStatus get exposed. 2017-10-28 08:59:41 -07:00
Kohsuke Kawaguchi
ab3d9e82ef A little better version of the bridge method 2017-10-28 08:43:48 -07:00
Kohsuke Kawaguchi
b6063dd534 Restored binary compatibility 2017-10-28 08:42:27 -07:00
Kohsuke Kawaguchi
e6754354e4 Merge pull request #389 2017-10-28 07:54:47 -07:00
Kohsuke Kawaguchi
4849619d67 None of the connectToEnterprise methods are preferrable so document accordingly 2017-10-28 07:54:41 -07:00
Kohsuke Kawaguchi
9b0ace242a Merge pull request #390 2017-10-28 07:45:14 -07:00
Kohsuke Kawaguchi
e94ba74058 Convention is to call these methods setXyz. Plus doc 2017-10-28 07:44:23 -07:00
Baptiste Mathus
569fa06d2d Labels: add method to update color 2017-10-25 14:06:28 +02:00
iraleigh
46dce17abc Fixed Typo 2017-10-24 14:53:23 -07:00
iraleigh
40d8f4a352 Fixed OAuth connection to enterprise API 2017-10-24 14:24:25 -07:00
Arne Burmeister
6415785220 boyscout: updated dependencies 2017-10-23 17:05:31 +02:00
Arne Burmeister
7735edeae8 extend id from int to long 2017-10-23 17:05:02 +02:00
Matt Nelson
0f81d1dbb3 Add support for pr review/review comment events 2017-10-05 18:14:15 -05:00
Anton Zagorskii
ae1ec8b558 Roles for team members 2017-09-20 13:22:30 +01:00
Jesse Glick
09c2b39530 bridge-method-annotation should be an optional dep. 2017-09-13 15:14:42 -04:00
Kohsuke Kawaguchi
b443e866f9 Added lock/unlock op and additional properties
Issue #355
2017-09-09 20:38:40 -07:00
Kohsuke Kawaguchi
d4404713a8 [maven-release-plugin] prepare for next development iteration 2017-09-09 13:28:40 -07:00
Kohsuke Kawaguchi
47409a9a99 [maven-release-plugin] prepare release github-api-1.89 2017-09-09 13:28:31 -07:00
Kohsuke Kawaguchi
60bfea2d3b Bug fix 2017-09-09 13:22:16 -07:00
Kohsuke Kawaguchi
d3ed8eaed5 Merge pull request #339 2017-09-09 13:07:18 -07:00
Kohsuke Kawaguchi
692dccf110 Massaging the change a bit 2017-09-09 13:03:18 -07:00
Kohsuke Kawaguchi
92caf98683 Reverting java1.6 change which I assume is accidental.
Not that I really care about Java5 but I think that change should
be done separatel & intentionally
2017-09-09 12:57:52 -07:00
Kohsuke Kawaguchi
6178d38895 connector usage is unsynchronized 2017-09-09 12:47:18 -07:00
Kohsuke Kawaguchi
40fb38a9ba Window focus problem 2017-09-09 12:45:58 -07:00
Kohsuke Kawaguchi
20e68d53fd Merge pull request #283 2017-09-09 12:45:02 -07:00
Kohsuke Kawaguchi
2d3557e049 Improved the intern logic
if the user record does not exist yet, there's no need to fetch that
eagerly, as they are fetched on demand via the populate() method.
2017-09-09 12:44:12 -07:00
Kohsuke Kawaguchi
d8f4bc7395 Added updater
This solves #331 differently
2017-09-09 12:31:10 -07:00
Kohsuke Kawaguchi
353f9bb809 pointless null check since the with method already does it 2017-09-09 12:23:40 -07:00
Kohsuke Kawaguchi
ccfe3ad4f7 Merge pull request #333 2017-09-09 12:17:39 -07:00
Kohsuke Kawaguchi
9012820c03 Massage the signature a bit.
AFAICT sha and merge_method are not mutually exclusive.
2017-09-09 12:17:21 -07:00
Kohsuke Kawaguchi
fe2af19e42 Unused constant 2017-09-09 12:15:21 -07:00
Kohsuke Kawaguchi
f721e053f1 Added convenience connector for OkHttp3
Note that the existing one needs to be kept for compatibility with OkHttp2
2017-09-09 12:11:36 -07:00
Kohsuke Kawaguchi
e6ad9feb84 Keeping Findbugs happy 2017-09-09 12:05:39 -07:00
Kohsuke Kawaguchi
635350c40e Additional naming consistency change 2017-09-09 12:02:44 -07:00
Kohsuke Kawaguchi
17edd33703 Reorganized imports following #337 2017-09-09 12:00:23 -07:00
Kohsuke Kawaguchi
b0f2a871c6 Merge pull request #337 2017-09-09 11:58:13 -07:00
Kohsuke Kawaguchi
8928a8a1dc Content type should be JSON by default when sending JSON.
This solves #350 a little differently.
2017-09-09 11:51:55 -07:00
Kohsuke Kawaguchi
2b6f37a6cc Merge pull request #361 2017-09-09 11:48:33 -07:00
Kohsuke Kawaguchi
f3a3b87861 Defined entry points 2017-09-09 11:48:25 -07:00
Kohsuke Kawaguchi
9cf6ee78d4 Pointless string conversion 2017-09-09 11:44:09 -07:00
Kohsuke Kawaguchi
bbc2f3962f Proper access control modifier 2017-09-09 11:44:02 -07:00
Kohsuke Kawaguchi
be49eb22d2 Merge pull request #368 2017-09-09 11:40:41 -07:00
Kohsuke Kawaguchi
fb47067215 Naming changes to emphasize that these are just traffic info 2017-09-09 11:40:28 -07:00
Kohsuke Kawaguchi
2c80ef178d Capture commonality between total and daily 2017-09-09 11:39:12 -07:00
Kohsuke Kawaguchi
9af8112148 Tightening up access control and use primitive type 2017-09-09 11:37:18 -07:00
Kohsuke Kawaguchi
57c36f437a [maven-release-plugin] prepare for next development iteration 2017-09-09 08:19:29 -07:00
Kohsuke Kawaguchi
5ed8a34566 [maven-release-plugin] prepare release github-api-1.88 2017-09-09 08:19:20 -07:00
Kohsuke Kawaguchi
ea8df9bd61 javadoc fix 2017-09-09 08:13:51 -07:00
Kohsuke Kawaguchi
b0c51e03b7 [maven-release-plugin] prepare for next development iteration 2017-09-09 08:06:27 -07:00
Matt Mitchell
f2a2ad90b7 Switch to a concurrent hash map 2017-08-29 11:30:25 -07:00
Matt Mitchell
cfe4c0c510 Merge remote-tracking branch 'upstream/master' into synchro-api 2017-08-29 10:38:54 -07:00
adw1n
a1819bf232 Added getClones method to GHRepository (https://developer.github.com/v3/repos/traffic/#clones). 2017-08-01 06:38:28 +02:00
adw1n
8accf07d46 Changed timestamp (GHRepositoryViews.DayViews.timestamp) field type from String to Date. 2017-08-01 04:02:10 +02:00
adw1n
6dcbace572 Added getViews method to GHRepository.
getViews implements https://developer.github.com/v3/repos/traffic/#views
2017-08-01 03:38:46 +02:00
Greg Gianforcaro
e90c86ec2f Remove Preview status, merge_method is now out of preview 2017-07-18 11:36:38 -04:00
Greg Gianforcaro
971ae1fa4d Merge branch 'master' into pr-merge-method 2017-07-18 11:33:20 -04:00
Serban Iordache
b537f9925b issue #360: Add support for committing multiple files 2017-07-07 16:21:11 +02:00
Kanstantsin Shautsou
be081eec3f Inject responce headers in GHObject and Exceptions.
GH has specific to GET/POST headers required for analysing in case of error.

Signed-off-by: Kanstantsin Shautsou <kanstantsin.sha@gmail.com>
2017-02-10 04:11:20 +03:00
Kanstantsin Shautsou
55b00a87f6 Set 1.6 level. I'm not so old.
Signed-off-by: Kanstantsin Shautsou <kanstantsin.sha@gmail.com>
2017-02-10 03:28:06 +03:00
Sebastian Kürten
fafe6b0ff7 Remove unused imports
Especially also remove the unsued import of
javax.xml.bind.DatatypeConverter from GHContent which is non-public API
as of Java 8
2017-02-09 18:15:20 +01:00
Greg Gianforcaro
5b156006fb Add 'Preview' support for MergeMethod on GHPullRequest
- Add 'polaris' preview
- Add MergeMethod Enum
- Add merge method to GHPullRequest which takes a MergeMethod
2017-01-27 23:36:54 -05:00
Matt Mitchell
9f3f644b83 Add some level of synchronization to the root of the API
This adds some synchronization to the maps at the root of the API to avoid duplicated calls to the actual GH REST API.  Specifically this is targeted around the two maps, orgs and users.  This fix makes the GHPRB jenkins plugin behave much better when there are lots of projects that could build for a specific repo (even if only a few are actually triggered)

There are also a few fixes around GHUser and GHPullRequest
* GHPullRequest was checking a field that may be null (merged_by) when determining whether to fetch details.  An unmerged PR would make a bunch of Github API calls for each property accessed.
* Where GHUser was returned in various objects, we weren't going through the caching mechanism at the root, so calls to APIs on GHUSer often resulted in new REST calls.  Instead, return from the cache wherever possible.
2016-06-08 10:43:40 -07:00
75 changed files with 1732 additions and 287 deletions

33
pom.xml
View File

@@ -7,7 +7,7 @@
</parent>
<artifactId>github-api</artifactId>
<version>1.87</version>
<version>1.91</version>
<name>GitHub API for Java</name>
<url>http://github-api.kohsuke.org/</url>
<description>GitHub API for Java</description>
@@ -16,7 +16,7 @@
<connection>scm:git:git@github.com/kohsuke/${project.artifactId}.git</connection>
<developerConnection>scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git</developerConnection>
<url>http://${project.artifactId}.kohsuke.org/</url>
<tag>github-api-1.87</tag>
<tag>github-api-1.91</tag>
</scm>
<distributionManagement>
@@ -64,7 +64,7 @@
<plugin>
<groupId>com.infradna.tool</groupId>
<artifactId>bridge-method-injector</artifactId>
<version>1.14</version>
<version>1.18</version>
<executions>
<execution>
<goals>
@@ -108,13 +108,19 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.2.3</version>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
@@ -124,7 +130,8 @@
<dependency>
<groupId>com.infradna.tool</groupId>
<artifactId>bridge-method-annotation</artifactId>
<version>1.14</version>
<version>1.17</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.kohsuke.stapler</groupId>
@@ -135,7 +142,7 @@
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>3.1.0.201310021548-r</version>
<version>4.9.0.201710071750-r</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -144,22 +151,28 @@
<version>2.7.5</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp-urlconnection</artifactId>
<version>3.9.0</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.kohsuke</groupId>
<artifactId>wordnet-random-name</artifactId>
<version>1.2</version>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>annotations</artifactId>
<version>3.0.0</version>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>

View File

@@ -1,9 +1,9 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.net.URL;
import java.util.Collection;
import java.util.Date;
import java.util.List;
/**

View 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);
}
}

View File

@@ -1,14 +1,13 @@
package org.kohsuke.github;
import static org.kohsuke.github.Previews.LOKI;
import com.fasterxml.jackson.annotation.JsonProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.net.URL;
import java.util.Collection;
import com.fasterxml.jackson.annotation.JsonProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import static org.kohsuke.github.Previews.*;
/**
* A branch in a repository.

View File

@@ -1,11 +1,10 @@
package org.kohsuke.github;
import java.util.Collection;
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 {

View File

@@ -1,6 +1,6 @@
package org.kohsuke.github;
import static org.kohsuke.github.Previews.LOKI;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.util.ArrayList;
@@ -12,7 +12,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import static org.kohsuke.github.Previews.*;
/**
* Builder to configure the branch protection settings.

View File

@@ -2,6 +2,7 @@ package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.net.URL;
import java.util.AbstractList;

View 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);
}
}

View File

@@ -1,11 +1,11 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
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.)

View File

@@ -39,7 +39,8 @@ public class GHCommitPointer {
* This points to the user who owns
* the {@link #getRepository()}.
*/
public GHUser getUser() {
public GHUser getUser() throws IOException {
if (user != null) return user.root.intern(user);
return user;
}

View File

@@ -1,9 +1,9 @@
package org.kohsuke.github;
import java.io.IOException;
import org.apache.commons.lang.StringUtils;
import java.io.IOException;
/**
* Search commits.
*

View File

@@ -1,5 +1,6 @@
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
/**
@@ -45,8 +46,8 @@ public class GHCommitStatus extends GHObject {
return description;
}
public GHUser getCreator() {
return creator;
public GHUser getCreator() throws IOException {
return root.intern(creator);
}
public String getContext() {

View File

@@ -7,8 +7,6 @@ import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.bind.DatatypeConverter;
/**
* A Content of a repository.
*

View File

@@ -21,8 +21,8 @@ public class GHCreateRepositoryBuilder {
}
public GHCreateRepositoryBuilder description(String description) {
this.builder.with("description",description);
return this;
this.builder.with("description",description);
return this;
}
public GHCreateRepositoryBuilder homepage(URL homepage) {
@@ -74,6 +74,30 @@ public class GHCreateRepositoryBuilder {
return this;
}
/**
* Allow or disallow squash-merging pull requests.
*/
public GHCreateRepositoryBuilder allowSquashMerge(boolean b) {
this.builder.with("allow_squash_merge",b);
return this;
}
/**
* Allow or disallow merging pull requests with a merge commit.
*/
public GHCreateRepositoryBuilder allowMergeCommit(boolean b) {
this.builder.with("allow_merge_commit",b);
return this;
}
/**
* Allow or disallow rebase-merging pull requests.
*/
public GHCreateRepositoryBuilder allowRebaseMerge(boolean b) {
this.builder.with("allow_rebase_merge",b);
return this;
}
/**
* Creates a default .gitignore
*

View File

@@ -1,9 +1,9 @@
package org.kohsuke.github;
import java.io.IOException;
import org.apache.commons.lang.builder.ToStringBuilder;
import java.io.IOException;
public class GHDeployKey {
protected String url, key, title;

View File

@@ -1,8 +1,15 @@
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
/**
* Represents a deployment
*
* @see <a href="https://developer.github.com/v3/repos/deployments/">documentation</a>
* @see GHRepository#listDeployments(String, String, String, String)
* @see GHRepository#getDeployment(long)
*/
public class GHDeployment extends GHObject {
private GHRepository owner;
private GitHub root;
@@ -41,8 +48,8 @@ public class GHDeployment extends GHObject {
public String getEnvironment() {
return environment;
}
public GHUser getCreator() {
return creator;
public GHUser getCreator() throws IOException {
return root.intern(creator);
}
public String getRef() {
return ref;
@@ -58,4 +65,23 @@ public class GHDeployment extends GHObject {
public URL getHtmlUrl() {
return null;
}
public GHDeploymentStatusBuilder createStatus(GHDeploymentState state) {
return new GHDeploymentStatusBuilder(owner,id,state);
}
public PagedIterable<GHDeploymentStatus> listStatuses() {
return new PagedIterable<GHDeploymentStatus>() {
public PagedIterator<GHDeploymentStatus> _iterator(int pageSize) {
return new PagedIterator<GHDeploymentStatus>(root.retrieve().asIterator(statuses_url, GHDeploymentStatus[].class, pageSize)) {
@Override
protected void wrapUp(GHDeploymentStatus[] page) {
for (GHDeploymentStatus c : page)
c.wrap(owner);
}
};
}
};
}
}

View File

@@ -1,14 +1,27 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Locale;
/**
* Creates a new deployment status.
*
* @see
* GHDeployment#createStatus(GHDeploymentState)
*/
public class GHDeploymentStatusBuilder {
private final Requester builder;
private GHRepository repo;
private int deploymentId;
private long deploymentId;
/**
* @deprecated
* Use {@link GHDeployment#createStatus(GHDeploymentState)}
*/
public GHDeploymentStatusBuilder(GHRepository repo, int deploymentId, GHDeploymentState state) {
this(repo,(long)deploymentId,state);
}
/*package*/ GHDeploymentStatusBuilder(GHRepository repo, long deploymentId, GHDeploymentState state) {
this.repo = repo;
this.deploymentId = deploymentId;
this.builder = new Requester(repo.root);
@@ -26,6 +39,6 @@ public class GHDeploymentStatusBuilder {
}
public GHDeploymentStatus create() throws IOException {
return builder.to(repo.getApiTailUrl("deployments")+"/"+deploymentId+"/statuses",GHDeploymentStatus.class).wrap(repo);
return builder.to(repo.getApiTailUrl("deployments/"+deploymentId+"/statuses"),GHDeploymentStatus.class).wrap(repo);
}
}

View File

@@ -1,11 +1,11 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Date;
import com.fasterxml.jackson.databind.node.ObjectNode;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.util.Date;
/**
* Represents an event.
*

View File

@@ -3,6 +3,7 @@ package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.Reader;
import java.util.List;
@@ -77,7 +78,96 @@ public abstract class GHEventPayload {
throw new IllegalStateException("Expected pull_request payload, but got something else. Maybe we've got another type of event?");
if (repository!=null) {
repository.wrap(root);
pull_request.wrap(repository);
pull_request.wrapUp(repository);
} else {
pull_request.wrapUp(root);
}
}
}
/**
* A review was added to a pull request
*
* @see <a href="https://developer.github.com/v3/activity/events/types/#pullrequestreviewevent">authoritative source</a>
*/
public static class PullRequestReview extends GHEventPayload {
private String action;
private GHPullRequestReview review;
private GHPullRequest pull_request;
private GHRepository repository;
public String getAction() {
return action;
}
public GHPullRequestReview getReview() {
return review;
}
public GHPullRequest getPullRequest() {
return pull_request;
}
public GHRepository getRepository() {
return repository;
}
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
if (review==null)
throw new IllegalStateException("Expected pull_request_review payload, but got something else. Maybe we've got another type of event?");
review.wrapUp(pull_request);
if (repository!=null) {
repository.wrap(root);
pull_request.wrapUp(repository);
} else {
pull_request.wrapUp(root);
}
}
}
/**
* A review comment was added to a pull request
*
* @see <a href="https://developer.github.com/v3/activity/events/types/#pullrequestreviewcommentevent">authoritative source</a>
*/
public static class PullRequestReviewComment extends GHEventPayload {
private String action;
private GHPullRequestReviewComment comment;
private GHPullRequest pull_request;
private GHRepository repository;
public String getAction() {
return action;
}
public GHPullRequestReviewComment getComment() {
return comment;
}
public GHPullRequest getPullRequest() {
return pull_request;
}
public GHRepository getRepository() {
return repository;
}
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
if (comment==null)
throw new IllegalStateException("Expected pull_request_review_comment payload, but got something else. Maybe we've got another type of event?");
comment.wrapUp(pull_request);
if (repository!=null) {
repository.wrap(root);
pull_request.wrapUp(repository);
} else {
pull_request.wrapUp(root);
}

View File

@@ -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;
}
}

View File

@@ -38,8 +38,8 @@ public class GHGist extends GHObject {
/**
* User that owns this Gist.
*/
public GHUser getOwner() {
return owner;
public GHUser getOwner() throws IOException {
return root.intern(owner);
}
public String getForksUrl() {
@@ -103,7 +103,7 @@ public class GHGist extends GHObject {
* Used when caller obtains {@link GHGist} without knowing its owner.
* A partially constructed owner object is interned.
*/
/*package*/ GHGist wrapUp(GitHub root) throws IOException {
/*package*/ GHGist wrapUp(GitHub root) {
this.owner = root.getUser(owner);
this.root = root;
wrapUp();
@@ -144,12 +144,8 @@ public class GHGist extends GHObject {
return new PagedIterator<GHGist>(root.retrieve().asIterator(getApiTailUrl("forks"), GHGist[].class, pageSize)) {
@Override
protected void wrapUp(GHGist[] page) {
try {
for (GHGist c : page)
c.wrapUp(root);
} catch (IOException e) {
throw new Error(e);
}
for (GHGist c : page)
c.wrapUp(root);
}
};
}

View File

@@ -1,6 +1,7 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.net.URL;
import java.util.Collections;

View File

@@ -5,7 +5,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**

View 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;
}
}

View File

@@ -68,6 +68,7 @@ public class GHIssue extends GHObject implements Reactable{
protected GHIssue.PullRequest pull_request;
protected GHMilestone milestone;
protected GHUser closed_by;
protected boolean locked;
/**
* @deprecated use {@link GHLabel}
@@ -129,6 +130,10 @@ public class GHIssue extends GHObject implements Reactable{
return title;
}
public boolean isLocked() {
return locked;
}
public GHIssueState getState() {
return Enum.valueOf(GHIssueState.class, state.toUpperCase(Locale.ENGLISH));
}
@@ -148,6 +153,14 @@ public class GHIssue extends GHObject implements Reactable{
return GitHub.parseURL(url);
}
public void lock() throws IOException {
new Requester(root).method("PUT").to(getApiRoute()+"/lock");
}
public void unlock() throws IOException {
new Requester(root).method("PUT").to(getApiRoute()+"/lock");
}
/**
* Updates the issue by adding a comment.
*
@@ -190,6 +203,10 @@ public class GHIssue extends GHObject implements Reactable{
edit("body",body);
}
public void setMilestone(GHMilestone milestone) throws IOException {
edit("milestone",milestone.getNumber());
}
public void assignTo(GHUser user) throws IOException {
setAssignees(user);
}
@@ -288,8 +305,8 @@ public class GHIssue extends GHObject implements Reactable{
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/issues/"+number;
}
public GHUser getAssignee() {
return assignee;
public GHUser getAssignee() throws IOException {
return root.intern(assignee);
}
public List<GHUser> getAssignees() {
@@ -299,8 +316,8 @@ public class GHIssue extends GHObject implements Reactable{
/**
* User who submitted the issue.
*/
public GHUser getUser() {
return user;
public GHUser getUser() throws IOException {
return root.intern(user);
}
/**
@@ -311,12 +328,16 @@ public class GHIssue extends GHObject implements Reactable{
* even for an issue that's already closed. See
* https://github.com/kohsuke/github-api/issues/60.
*/
public GHUser getClosedBy() {
public GHUser getClosedBy() throws IOException {
if(!"closed".equals(state)) return null;
if(closed_by != null) return closed_by;
//TODO closed_by = owner.getIssue(number).getClosed_by();
return closed_by;
//TODO
/*
if (closed_by==null) {
closed_by = owner.getIssue(number).getClosed_by();
}
*/
return root.intern(closed_by);
}
public int getCommentsCount(){

View File

@@ -26,7 +26,7 @@ package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
import static org.kohsuke.github.Previews.SQUIRREL_GIRL;
import static org.kohsuke.github.Previews.*;
/**
* Comment to the issue

View File

@@ -1,7 +1,5 @@
package org.kohsuke.github;
import java.util.Locale;
/**
* Search issues.
*

View File

@@ -34,4 +34,12 @@ public class GHLabel {
public void delete() throws IOException {
repo.root.retrieve().method("DELETE").to(url);
}
/**
* @param newColor
* 6-letter hex color code, like "f29513"
*/
public void setColor(String newColor) throws IOException {
repo.root.retrieve().method("PATCH").with("name", name).with("color", newColor).to(url);
}
}

View File

@@ -32,7 +32,7 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import static org.kohsuke.github.Previews.DRAX;
import static org.kohsuke.github.Previews.*;
/**
* The GitHub Preview API's license information

View File

@@ -27,8 +27,8 @@ public class GHMilestone extends GHObject {
return owner;
}
public GHUser getCreator() {
return creator;
public GHUser getCreator() throws IOException {
return root.intern(creator);
}
public Date getDueOn() {

View File

@@ -6,7 +6,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

View File

@@ -3,14 +3,15 @@ package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.lang.reflect.FieldUtils;
import javax.annotation.CheckForNull;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* Most (all?) domain objects in GitHub seems to have these 4 properties.
@@ -18,14 +19,34 @@ import java.util.Date;
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public abstract class GHObject {
/**
* Capture response HTTP headers on the state object.
*/
protected Map<String, List<String>> responseHeaderFields;
protected String url;
protected int id;
protected long id;
protected String created_at;
protected String updated_at;
/*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?
*/
@@ -63,14 +84,18 @@ public abstract class GHObject {
/**
* Unique ID number of this resource.
*/
@WithBridgeMethods(value=String.class, adapterMethod="intToString")
public int getId() {
@WithBridgeMethods(value={String.class,int.class}, adapterMethod="longToStringOrInt")
public long getId() {
return id;
}
@SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD", justification = "Bridge method of getId")
private Object intToString(int id, Class type) {
return String.valueOf(id);
private Object longToStringOrInt(long id, Class type) {
if (type==String.class)
return String.valueOf(id);
if (type==int.class)
return (int)id;
throw new AssertionError("Unexpected type: "+type);
}
@SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD", justification = "Bridge method of getHtmlUrl")

View File

@@ -41,7 +41,7 @@ public abstract class GHPerson extends GHObject {
if (created_at!=null) {
return; // already populated
}
if (root.isOffline()) {
if (root == null || root.isOffline()) {
return; // cannot populate, will have to live with what we have
}
root.retrieve().to(url, this);

View File

@@ -23,26 +23,25 @@
*/
package org.kohsuke.github;
import javax.annotation.CheckForNull;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import javax.annotation.CheckForNull;
import static org.kohsuke.github.Previews.BLACK_CAT;
/**
* A pull request.
*
*
* @author Kohsuke Kawaguchi
* @see GHRepository#getPullRequest(int)
*/
@SuppressWarnings({"UnusedDeclaration"})
public class GHPullRequest extends GHIssue {
private static final String COMMENTS_ACTION = "/comments";
private String patch_url, diff_url, issue_url;
private GHCommitPointer base;
private String merged_at;
@@ -50,8 +49,8 @@ public class GHPullRequest extends GHIssue {
// details that are only available when obtained from ID
private GHUser merged_by;
private int review_comments, additions;
private boolean merged;
private int review_comments, additions, commits;
private boolean merged, maintainer_can_modify;
private Boolean mergeable;
private int deletions;
private String mergeable_state;
@@ -91,7 +90,7 @@ public class GHPullRequest extends GHIssue {
public URL getPatchUrl() {
return GitHub.parseURL(patch_url);
}
/**
* The URL of the patch file.
* like https://github.com/jenkinsci/jenkins/pull/100.patch
@@ -114,7 +113,7 @@ public class GHPullRequest extends GHIssue {
public GHCommitPointer getHead() {
return head;
}
@Deprecated
public Date getIssueUpdatedAt() throws IOException {
return super.getUpdatedAt();
@@ -167,13 +166,32 @@ public class GHPullRequest extends GHIssue {
return additions;
}
public int getCommits() throws IOException {
populate();
return commits;
}
public boolean isMerged() throws IOException {
populate();
return merged;
}
public Boolean getMergeable() throws IOException {
public boolean canMaintainerModify() throws IOException {
populate();
return maintainer_can_modify;
}
/**
* Is this PR mergeable?
*
* @return
* null if the state has not been determined yet, for example when a PR is newly created.
* If this method is called on an instance whose mergeable state is not yet known,
* API call is made to retrieve the latest state.
*/
public Boolean getMergeable() throws IOException {
if (mergeable==null)
refresh();
return mergeable;
}
@@ -206,7 +224,14 @@ public class GHPullRequest extends GHIssue {
* Depending on the original API call where this object is created, it may not contain everything.
*/
private void populate() throws IOException {
if (merged_by!=null) return; // already populated
if (mergeable_state!=null) return; // already populated
refresh();
}
/**
* Repopulates this object.
*/
public void refresh() throws IOException {
if (root.isOffline()) {
return; // cannot populate, will have to live with what we have
}
@@ -236,7 +261,6 @@ public class GHPullRequest extends GHIssue {
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
@@ -256,7 +280,7 @@ public class GHPullRequest extends GHIssue {
public PagedIterable<GHPullRequestReviewComment> listReviewComments() throws IOException {
return new PagedIterable<GHPullRequestReviewComment>() {
public PagedIterator<GHPullRequestReviewComment> _iterator(int pageSize) {
return new PagedIterator<GHPullRequestReviewComment>(root.retrieve().asIterator(getApiRoute() + "/comments",
return new PagedIterator<GHPullRequestReviewComment>(root.retrieve().asIterator(getApiRoute() + COMMENTS_ACTION,
GHPullRequestReviewComment[].class, pageSize)) {
protected void wrapUp(GHPullRequestReviewComment[] page) {
for (GHPullRequestReviewComment c : page)
@@ -286,32 +310,30 @@ public class GHPullRequest extends GHIssue {
};
}
@Preview
@Deprecated
/**
* @deprecated
* Use {@link #createReview()}
*/
public GHPullRequestReview createReview(String body, @CheckForNull GHPullRequestReviewState event,
GHPullRequestReviewComment... comments)
throws IOException {
GHPullRequestReviewComment... comments) throws IOException {
return createReview(body, event, Arrays.asList(comments));
}
@Preview
@Deprecated
/**
* @deprecated
* Use {@link #createReview()}
*/
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());
List<GHPullRequestReviewComment> comments) throws IOException {
GHPullRequestReviewBuilder b = createReview().body(body);
for (GHPullRequestReviewComment c : comments) {
draftComments.add(new DraftReviewComment(c.getBody(), c.getPath(), c.getPosition()));
b.comment(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);
return b.create();
}
public GHPullRequestReviewBuilder createReview() {
return new GHPullRequestReviewBuilder(this);
}
public GHPullRequestReviewComment createReviewComment(String body, String sha, String path, int position) throws IOException {
@@ -320,7 +342,7 @@ public class GHPullRequest extends GHIssue {
.with("commit_id", sha)
.with("path", path)
.with("position", position)
.to(getApiRoute() + "/comments", GHPullRequestReviewComment.class).wrapUp(this);
.to(getApiRoute() + COMMENTS_ACTION, GHPullRequestReviewComment.class).wrapUp(this);
}
/**
@@ -346,37 +368,33 @@ public class GHPullRequest extends GHIssue {
* SHA that pull request head must match to allow merge.
*/
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 {
if (!fetchedIssueDetails) {
new Requester(root).to(getIssuesApiRoute(), this);
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;
}
}
}

View File

@@ -23,17 +23,19 @@
*/
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import javax.annotation.CheckForNull;
import java.io.IOException;
import java.net.URL;
import static org.kohsuke.github.Previews.BLACK_CAT;
/**
* Review to the pull request
* Review to a pull request.
*
* @see GHPullRequest#listReviews()
* @see GHPullRequest#createReview(String, GHPullRequestReviewState, GHPullRequestReviewComment...)
* @see GHPullRequestReviewBuilder
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_FIELD"}, justification = "JSON API")
public class GHPullRequestReview extends GHObject {
GHPullRequest owner;
@@ -72,6 +74,7 @@ public class GHPullRequestReview extends GHObject {
return commit_id;
}
@CheckForNull
public GHPullRequestReviewState getState() {
return state;
}
@@ -85,41 +88,41 @@ public class GHPullRequestReview extends GHObject {
return owner.getApiRoute()+"/reviews/"+id;
}
/**
* @deprecated
* Former preview method that changed when it got public. Left here for backward compatibility.
* Use {@link #submit(String, GHPullRequestReviewEvent)}
*/
public void submit(String body, GHPullRequestReviewState state) throws IOException {
submit(body,state.toEvent());
}
/**
* Updates the comment.
*/
@Preview
@Deprecated
public void submit(String body, GHPullRequestReviewState event) throws IOException {
public void submit(String body, GHPullRequestReviewEvent 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;
this.state = event.toState();
}
/**
* 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;
}
@@ -127,14 +130,11 @@ public class GHPullRequestReview extends GHObject {
/**
* 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) {
@@ -145,5 +145,4 @@ public class GHPullRequestReview extends GHObject {
}
};
}
}

View File

@@ -0,0 +1,91 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Builds up a creation of new {@link GHPullRequestReview}.
*
* @author Kohsuke Kawaguchi
* @see GHPullRequest#createReview()
*/
public class GHPullRequestReviewBuilder {
private final GHPullRequest pr;
private final Requester builder;
private final List<DraftReviewComment> comments = new ArrayList<DraftReviewComment>();
/*package*/ GHPullRequestReviewBuilder(GHPullRequest pr) {
this.pr = pr;
this.builder = new Requester(pr.root);
}
// public GHPullRequestReview createReview(@Nullable String commitId, String body, GHPullRequestReviewEvent event,
// List<GHPullRequestReviewComment> comments) throws IOException
/**
* The SHA of the commit that needs a review. Not using the latest commit SHA may render your review comment outdated if a subsequent commit modifies the line you specify as the position. Defaults to the most recent commit in the pull request when you do not specify a value.
*/
public GHPullRequestReviewBuilder commitId(String commitId) {
builder.with("commit_id",commitId);
return this;
}
/**
* Required when using REQUEST_CHANGES or COMMENT for the event parameter. The body text of the pull request review.
*/
public GHPullRequestReviewBuilder body(String body) {
builder.with("body",body);
return this;
}
/**
* The review action you want to perform. The review actions include: APPROVE, REQUEST_CHANGES, or COMMENT.
* By leaving this blank, you set the review action state to PENDING,
* which means you will need to {@linkplain GHPullRequestReview#submit() submit the pull request review} when you are ready.
*/
public GHPullRequestReviewBuilder event(GHPullRequestReviewEvent event) {
builder.with("event",event.action());
return this;
}
/**
* @param body The relative path to the file that necessitates a review comment.
* @param path The position in the diff where you want to add a review comment. Note this value is not the same as the line number in the file. For help finding the position value, read the note below.
* @param position Text of the review comment.
*/
public GHPullRequestReviewBuilder comment(String body, String path, int position) {
comments.add(new DraftReviewComment(body,path,position));
return this;
}
public GHPullRequestReview create() throws IOException {
return builder.method("POST")._with("comments",comments)
.to(pr.getApiRoute() + "/reviews", GHPullRequestReview.class)
.wrapUp(pr);
}
private static class DraftReviewComment {
private String body;
private String path;
private int position;
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;
}
}
}

View File

@@ -25,6 +25,7 @@ package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
import javax.annotation.CheckForNull;
import static org.kohsuke.github.Previews.*;
@@ -41,9 +42,15 @@ public class GHPullRequestReviewComment extends GHObject implements Reactable {
private String body;
private GHUser user;
private String path;
private int position;
private int originalPosition;
private int position = -1;
private int original_position = -1;
private long in_reply_to_id = -1L;
/**
* @deprecated
* You should be using {@link GHPullRequestReviewBuilder#comment(String, String, int)}
*/
public static GHPullRequestReviewComment draft(String body, String path, int position) {
GHPullRequestReviewComment result = new GHPullRequestReviewComment();
result.body = body;
@@ -82,12 +89,18 @@ public class GHPullRequestReviewComment extends GHObject implements Reactable {
return path;
}
@CheckForNull
public int getPosition() {
return position;
}
public int getOriginalPosition() {
return originalPosition;
return original_position;
}
@CheckForNull
public long getInReplyToId() {
return in_reply_to_id;
}
@Override
@@ -114,6 +127,17 @@ public class GHPullRequestReviewComment extends GHObject implements Reactable {
new Requester(owner.root).method("DELETE").to(getApiRoute());
}
/**
* Create a new comment that replies to this comment.
*/
public GHPullRequestReviewComment reply(String body) throws IOException {
return new Requester(owner.root).method("POST")
.with("body", body)
.with("in_reply_to", getId())
.to(getApiRoute() + "/comments", GHPullRequestReviewComment.class)
.wrapUp(owner);
}
@Preview @Deprecated
public GHReaction createReaction(ReactionContent content) throws IOException {
return new Requester(owner.root)
@@ -126,7 +150,7 @@ public class GHPullRequestReviewComment extends GHObject implements Reactable {
public PagedIterable<GHReaction> listReactions() {
return new PagedIterable<GHReaction>() {
public PagedIterator<GHReaction> _iterator(int pageSize) {
return new PagedIterator<GHReaction>(owner.root.retrieve().withPreview(SQUIRREL_GIRL).asIterator(getApiRoute()+"/reactions", GHReaction[].class, pageSize)) {
return new PagedIterator<GHReaction>(owner.root.retrieve().withPreview(SQUIRREL_GIRL).asIterator(getApiRoute() + "/reactions", GHReaction[].class, pageSize)) {
@Override
protected void wrapUp(GHReaction[] page) {
for (GHReaction c : page)

View File

@@ -0,0 +1,51 @@
/*
* The MIT License
*
* Copyright (c) 2011, Eric Maupin
*
* 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;
/**
* Action to perform on {@link GHPullRequestReview}.
*/
public enum GHPullRequestReviewEvent {
PENDING,
APPROVE,
REQUEST_CHANGES,
COMMENT;
/*package*/ String action() {
return this==PENDING ? null : name();
}
/**
* When a {@link GHPullRequestReview} is submitted with this event, it should transition to this state.
*/
/*package*/ GHPullRequestReviewState toState() {
switch (this) {
case PENDING: return GHPullRequestReviewState.PENDING;
case APPROVE: return GHPullRequestReviewState.APPROVED;
case REQUEST_CHANGES: return GHPullRequestReviewState.CHANGES_REQUESTED;
case COMMENT: return GHPullRequestReviewState.COMMENTED;
}
throw new IllegalStateException();
}
}

View File

@@ -1,19 +1,39 @@
package org.kohsuke.github;
/**
* Current state of {@link GHPullRequestReview}
*/
public enum GHPullRequestReviewState {
PENDING(null),
APPROVED("APPROVE"),
REQUEST_CHANGES("REQUEST_CHANGES"),
COMMENTED("COMMENT"),
DISMISSED(null);
PENDING,
APPROVED,
CHANGES_REQUESTED,
/**
* @deprecated
* This was the thing when this API was in preview, but it changed when it became public.
* Use {@link #CHANGES_REQUESTED}. Left here for compatibility.
*/
REQUEST_CHANGES,
COMMENTED,
DISMISSED;
private final String _action;
GHPullRequestReviewState(String action) {
_action = action;
/**
* @deprecated
* This was an internal method accidentally exposed.
* Left here for compatibility.
*/
public String action() {
GHPullRequestReviewEvent e = toEvent();
return e==null ? null : e.action();
}
public String action() {
return _action;
/*package*/ GHPullRequestReviewEvent toEvent() {
switch (this) {
case PENDING: return GHPullRequestReviewEvent.PENDING;
case APPROVED: return GHPullRequestReviewEvent.APPROVE;
case CHANGES_REQUESTED: return GHPullRequestReviewEvent.REQUEST_CHANGES;
case REQUEST_CHANGES: return GHPullRequestReviewEvent.REQUEST_CHANGES;
case COMMENTED: return GHPullRequestReviewEvent.COMMENT;
}
return null;
}
}

View File

@@ -1,6 +1,7 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Date;
/**

View File

@@ -3,7 +3,7 @@ package org.kohsuke.github;
import java.io.IOException;
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.

View File

@@ -1,6 +1,7 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.net.URL;

View File

@@ -8,7 +8,7 @@ import java.util.Arrays;
import java.util.Date;
import java.util.List;
import static java.lang.String.format;
import static java.lang.String.*;
/**
* Release in a github repository.
@@ -45,10 +45,12 @@ public class GHRelease extends GHObject {
return draft;
}
/**
* @deprecated
* Use {@link #update()}
*/
public GHRelease setDraft(boolean draft) throws IOException {
edit("draft", draft);
this.draft = draft;
return this;
return update().draft(draft).update();
}
public URL getHtmlUrl() {
@@ -149,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 {
new Requester(root)._with(key, value).method("PATCH").to(owner.getApiTailUrl("releases/"+id));
public GHReleaseUpdater update() {
return new GHReleaseUpdater(this);
}
private String getApiTailUrl(String end) {

View File

@@ -21,9 +21,7 @@ public class GHReleaseBuilder {
* @param body The release notes body.
*/
public GHReleaseBuilder body(String body) {
if (body != null) {
builder.with("body", body);
}
builder.with("body", body);
return this;
}
@@ -35,9 +33,7 @@ public class GHReleaseBuilder {
* already exists.
*/
public GHReleaseBuilder commitish(String commitish) {
if (commitish != null) {
builder.with("target_commitish", commitish);
}
builder.with("target_commitish", commitish);
return this;
}
@@ -56,9 +52,7 @@ public class GHReleaseBuilder {
* @param name the name of the release
*/
public GHReleaseBuilder name(String name) {
if (name != null) {
builder.with("name", name);
}
builder.with("name", name);
return this;
}

View 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 repositorys 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);
}
}

View File

@@ -95,18 +95,12 @@ public class GHRepository extends GHObject {
return new GHDeploymentBuilder(this,ref);
}
public PagedIterable<GHDeploymentStatus> getDeploymentStatuses(final int id) {
return new PagedIterable<GHDeploymentStatus>() {
public PagedIterator<GHDeploymentStatus> _iterator(int pageSize) {
return new PagedIterator<GHDeploymentStatus>(root.retrieve().asIterator(getApiTailUrl("deployments")+"/"+id+"/statuses", GHDeploymentStatus[].class, pageSize)) {
@Override
protected void wrapUp(GHDeploymentStatus[] page) {
for (GHDeploymentStatus c : page)
c.wrap(GHRepository.this);
}
};
}
};
/**
* @deprecated
* Use {@code getDeployment(id).listStatuses()}
*/
public PagedIterable<GHDeploymentStatus> getDeploymentStatuses(final int id) throws IOException {
return getDeployment(id).listStatuses();
}
public PagedIterable<GHDeployment> listDeployments(String sha,String ref,String task,String environment){
@@ -123,7 +117,13 @@ public class GHRepository extends GHObject {
};
}
};
}
/**
* Obtains a single {@link GHDeployment} by its ID.
*/
public GHDeployment getDeployment(long id) throws IOException {
return root.retrieve().to("deployments/" + id, GHDeployment.class).wrap(this);
}
private String join(List<String> params, String joinStr) {
@@ -140,8 +140,12 @@ public class GHRepository extends GHObject {
return StringUtils.trimToNull(value)== null? null: name+"="+value;
}
public GHDeploymentStatusBuilder createDeployStatus(int deploymentId, GHDeploymentState ghDeploymentState) {
return new GHDeploymentStatusBuilder(this,deploymentId,ghDeploymentState);
/**
* @deprecated
* Use {@code getDeployment(deploymentId).createStatus(ghDeploymentState)}
*/
public GHDeploymentStatusBuilder createDeployStatus(int deploymentId, GHDeploymentState ghDeploymentState) throws IOException {
return getDeployment(deploymentId).createStatus(ghDeploymentState);
}
private static class GHRepoPermission {
@@ -169,6 +173,14 @@ public class GHRepository extends GHObject {
* Gets the HTTPS URL to this repository, such as "https://github.com/kohsuke/jenkins.git"
* This URL is read-only.
*/
public String getHttpTransportUrl() {
return clone_url;
}
/**
* @deprecated
* Typo of {@link #getHttpTransportUrl()}
*/
public String gitHttpTransportUrl() {
return clone_url;
}
@@ -883,6 +895,10 @@ public class GHRepository extends GHObject {
return root.retrieve().to(url, GHTree.class).wrap(this);
}
public GHTreeBuilder createTree() {
return new GHTreeBuilder(this);
}
/**
* Retrieves the tree for the current GitHub repository, recursively as described in here:
* https://developer.github.com/v3/git/trees/#get-a-tree-recursively
@@ -912,6 +928,10 @@ public class GHRepository extends GHObject {
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.
*
@@ -935,6 +955,10 @@ public class GHRepository extends GHObject {
return c;
}
public GHCommitBuilder createCommit() {
return new GHCommitBuilder(this);
}
/**
* Lists all the commits.
*/
@@ -1540,6 +1564,19 @@ public class GHRepository extends GHObject {
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
public int hashCode() {

View File

@@ -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);
}
}
}

View File

@@ -1,7 +1,5 @@
package org.kohsuke.github;
import java.util.Locale;
/**
* Search repositories.
*

View 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;
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -5,7 +5,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* Represents an annotated tag in a {@link GHRepository}
*
* @see GHRepository#getAnnotatedTag()
* @see GHRepository#getTagObject(String)
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")

View File

@@ -18,6 +18,18 @@ public class GHTeam {
protected /*final*/ GHOrganization org;
/** Member's role in a team */
public enum Role {
/**
* A normal member of the team
*/
MEMBER,
/**
* Able to add/remove other team members, promote other team members to team maintainer, and edit the team's name and description.
*/
MAINTAINER
}
/*package*/ GHTeam wrapUp(GHOrganization owner) {
this.org = owner;
return this;
@@ -116,6 +128,22 @@ public class GHTeam {
org.root.retrieve().method("PUT").to(api("/memberships/" + u.getLogin()), null);
}
/**
* Adds a member to the team
*
* The user will be invited to the organization if required.
*
* @param user github user
* @param role role for the new member
*
* @throws IOException
*/
public void add(GHUser user, Role role) throws IOException {
org.root.retrieve().method("PUT")
.with("role", role.name())
.to(api("/memberships/" + user.getLogin()), null);
}
/**
* Removes a member to the team.
*/
@@ -129,7 +157,7 @@ public class GHTeam {
public void add(GHRepository r, GHOrganization.Permission permission) throws IOException {
org.root.retrieve().method("PUT")
.with("permission",permission)
.with("permission", permission)
.to(api("/repos/" + r.getOwnerName() + '/' + r.getName()), null);
}
@@ -145,7 +173,7 @@ public class GHTeam {
}
private String api(String tail) {
return "/teams/"+id+tail;
return "/teams/" + id + tail;
}
public GHOrganization getOrganization() {

View File

@@ -1,6 +1,7 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;

View 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);
}
}

View File

@@ -1,7 +1,5 @@
package org.kohsuke.github;
import java.util.Locale;
/**
* Search users.
*

View File

@@ -27,6 +27,12 @@ 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 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.FileNotFoundException;
import java.io.IOException;
@@ -42,23 +48,18 @@ import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
import static java.util.logging.Level.FINE;
import static org.kohsuke.github.Previews.DRAX;
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.
@@ -79,9 +80,10 @@ public class GitHub {
*/
/*package*/ final String encodedAuthorization;
private final Map<String,GHUser> users = new Hashtable<String, GHUser>();
private final Map<String,GHOrganization> orgs = new Hashtable<String, GHOrganization>();
private final ConcurrentMap<String,GHUser> users;
private final ConcurrentMap<String,GHOrganization> orgs;
// Cache of myself object.
private GHMyself myself;
private final String apiUrl;
/*package*/ final RateLimitHandler rateLimitHandler;
@@ -146,6 +148,8 @@ public class GitHub {
}
}
users = new ConcurrentHashMap<String, GHUser>();
orgs = new ConcurrentHashMap<String, GHOrganization>();
this.rateLimitHandler = rateLimitHandler;
this.abuseLimitHandler = abuseLimitHandler;
@@ -161,6 +165,16 @@ public class GitHub {
return GitHubBuilder.fromCredentials().build();
}
/**
* Version that connects to GitHub Enterprise.
*
* @deprecated
* Use {@link #connectToEnterpriseWithOAuth(String, String, String)}
*/
public static GitHub connectToEnterprise(String apiUrl, String oauthAccessToken) throws IOException {
return connectToEnterpriseWithOAuth(apiUrl,null,oauthAccessToken);
}
/**
* Version that connects to GitHub Enterprise.
*
@@ -169,10 +183,16 @@ public class GitHub {
* "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has <tt>/api/v3</tt> in the URL.
* For historical reasons, this parameter still accepts the bare domain name, but that's considered deprecated.
*/
public static GitHub connectToEnterprise(String apiUrl, String oauthAccessToken) throws IOException {
return new GitHubBuilder().withEndpoint(apiUrl).withOAuthToken(oauthAccessToken).build();
public static GitHub connectToEnterpriseWithOAuth(String apiUrl, String login, String oauthAccessToken) throws IOException {
return new GitHubBuilder().withEndpoint(apiUrl).withOAuthToken(oauthAccessToken, login).build();
}
/**
* Version that connects to GitHub Enterprise.
*
* @deprecated
* Use with caution. Login with password is not a preferred method.
*/
public static GitHub connectToEnterprise(String apiUrl, String login, String password) throws IOException {
return new GitHubBuilder().withEndpoint(apiUrl).withPassword(login, password).build();
}
@@ -357,13 +377,15 @@ public class GitHub {
@WithBridgeMethods(GHUser.class)
public GHMyself getMyself() throws IOException {
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;
users.put(u.getLogin(), u);
return u;
u.root = this;
this.myself = u;
return u;
}
}
/**
@@ -379,7 +401,7 @@ public class GitHub {
return u;
}
/**
* clears all cached data in order for external changes (modifications and del
*/
@@ -401,6 +423,9 @@ public class GitHub {
return u;
}
/**
* Gets {@link GHOrganization} specified by name.
*/
public GHOrganization getOrganization(String name) throws IOException {
GHOrganization o = orgs.get(name);
if (o==null) {
@@ -410,6 +435,35 @@ public class GitHub {
return o;
}
/**
* Gets a list of all organizations.
*/
public PagedIterable<GHOrganization> listOrganizations() {
return listOrganizations(null);
}
/**
* Gets a list of all organizations starting after the organization identifier specified by 'since'.
*
* @see <a href="https://developer.github.com/v3/orgs/#parameters">List All Orgs - Parameters</a>
*/
public PagedIterable<GHOrganization> listOrganizations(final String since) {
return new PagedIterable<GHOrganization>() {
@Override
public PagedIterator<GHOrganization> _iterator(int pageSize) {
System.out.println("page size: " + pageSize);
return new PagedIterator<GHOrganization>(retrieve().with("since",since)
.asIterator("/organizations", GHOrganization[].class, pageSize)) {
@Override
protected void wrapUp(GHOrganization[] page) {
for (GHOrganization c : page)
c.wrapUp(GitHub.this);
}
};
}
};
}
/**
* Gets the repository object from 'user/reponame' string that GitHub calls as "repository name"
*
@@ -641,6 +695,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 String rate_limit_url;
@@ -774,7 +840,7 @@ public class GitHub {
* This provides a dump of every public repository, in the order that they were created.
*
* @param since
* The integer ID of the last Repository that youve seen. See {@link GHRepository#getId()}
* The numeric ID of the last Repository that youve seen. See {@link GHRepository#getId()}
* @see <a href="https://developer.github.com/v3/repos/#list-all-public-repositories">documentation</a>
*/
public PagedIterable<GHRepository> listAllPublicRepositories(final String since) {

View File

@@ -154,6 +154,12 @@ public class GitHubBuilder {
return self;
}
/**
* @param endpoint
* The URL of GitHub (or GitHub enterprise) API endpoint, such as "https://api.github.com" or
* "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has <tt>/api/v3</tt> in the URL.
* For historical reasons, this parameter still accepts the bare domain name, but that's considered deprecated.
*/
public GitHubBuilder withEndpoint(String endpoint) {
this.endpoint = endpoint;
return this;

View File

@@ -1,6 +1,7 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Date;
/**

View File

@@ -5,7 +5,6 @@ import org.kohsuke.github.extras.ImpatientHttpConnector;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.TimeUnit;
/**
* Pluggability for customizing HTTP request behaviors or using altogether different library.

View File

@@ -1,11 +1,10 @@
package org.kohsuke.github;
import javax.annotation.CheckForNull;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.annotation.CheckForNull;
/**
* {@link IOException} for http exceptions because {@link HttpURLConnection} throws un-discerned
* {@link IOException} and it can help to know the http response code to decide how to handle an

View File

@@ -1,6 +1,5 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;

View File

@@ -2,7 +2,6 @@ package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.util.Iterator;
/**

View File

@@ -8,5 +8,4 @@ package org.kohsuke.github;
static final String DRAX = "application/vnd.github.drax-preview+json";
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";
}

View File

@@ -25,6 +25,11 @@ package org.kohsuke.github;
import com.fasterxml.jackson.databind.JsonMappingException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
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.IOException;
import java.io.InputStream;
@@ -53,13 +58,12 @@ import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import javax.annotation.WillClose;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import static java.util.Arrays.asList;
import java.util.logging.Level;
import static java.util.logging.Level.*;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.FINEST;
import static java.util.logging.Level.INFO;
import static org.apache.commons.lang.StringUtils.defaultString;
import static org.kohsuke.github.GitHub.MAPPER;
/**
@@ -76,7 +80,7 @@ class Requester {
* Request method.
*/
private String method = "POST";
private String contentType = "application/x-www-form-urlencoded";
private String contentType = null;
private InputStream body;
/**
@@ -131,6 +135,10 @@ class Requester {
return _with(key, value);
}
public Requester with(String key, long value) {
return _with(key, value);
}
public Requester with(String key, Integer value) {
if (value!=null)
_with(key, value);
@@ -275,7 +283,7 @@ class Requester {
if (nextLinkMatcher.find()) {
final String link = nextLinkMatcher.group(1);
T nextResult = _to(link, type, instance);
setResponseHeaders(nextResult);
final int resultLength = Array.getLength(result);
final int nextResultLength = Array.getLength(nextResult);
T concatResult = (T) Array.newInstance(type.getComponentType(), resultLength + nextResultLength);
@@ -285,7 +293,7 @@ class Requester {
}
}
}
return result;
return setResponseHeaders(result);
} catch (IOException e) {
handleApiError(e);
} finally {
@@ -392,18 +400,19 @@ class Requester {
private void buildRequest() throws IOException {
if (isMethodWithBody()) {
uc.setDoOutput(true);
uc.setRequestProperty("Content-type", contentType);
if (body == null) {
uc.setRequestProperty("Content-type", defaultString(contentType,"application/json"));
Map json = new HashMap();
for (Entry e : args) {
json.put(e.key, e.value);
}
MAPPER.writeValue(uc.getOutputStream(), json);
} else {
uc.setRequestProperty("Content-type", defaultString(contentType,"application/x-www-form-urlencoded"));
try {
byte[] bytes = new byte[32768];
int read = 0;
int read;
while ((read = body.read(bytes)) != -1) {
uc.getOutputStream().write(bytes, 0, read);
}
@@ -448,7 +457,7 @@ class Requester {
try {
return new PagingIterator<T>(type, tailApiUrl, root.getApiURL(s.toString()));
} catch (IOException e) {
throw new Error(e);
throw new GHException("Unable to build github Api URL",e);
}
}
@@ -509,7 +518,7 @@ class Requester {
}
}
} catch (IOException e) {
throw new Error(e);
throw new GHException("Failed to retrieve "+url);
}
}
@@ -585,6 +594,7 @@ class Requester {
throw new IllegalStateException("Failed to set the request method to "+method);
}
@CheckForNull
private <T> T parse(Class<T> type, T instance) throws IOException {
return parse(type, instance, 2);
}
@@ -608,12 +618,13 @@ class Requester {
String data = IOUtils.toString(r);
if (type!=null)
try {
return MAPPER.readValue(data,type);
return setResponseHeaders(MAPPER.readValue(data, type));
} catch (JsonMappingException e) {
throw (IOException)new IOException("Failed to deserialize " +data).initCause(e);
}
if (instance!=null)
return MAPPER.readerForUpdating(instance).<T>readValue(data);
if (instance!=null) {
return setResponseHeaders(MAPPER.readerForUpdating(instance).<T>readValue(data));
}
return null;
} catch (FileNotFoundException e) {
// java.net.URLConnection handles 404 exception has FileNotFoundException, don't wrap exception in HttpException
@@ -621,7 +632,7 @@ class Requester {
throw e;
} catch (IOException e) {
if (e instanceof SocketTimeoutException && timeouts > 0) {
LOGGER.log(Level.INFO, "timed out accessing " + uc.getURL() + "; will try " + timeouts + " more time(s)", e);
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);
@@ -630,6 +641,21 @@ class Requester {
}
}
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.
*/
@@ -662,13 +688,13 @@ class Requester {
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 FileNotFoundException(error).initCause(e);
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 IOException(error).initCause(e);
e = (IOException) new GHIOException(error).withResponseHeaderFields(uc).initCause(e);
}
} finally {
IOUtils.closeQuietly(es);

View 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();
}

View File

@@ -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);
}
}

View File

@@ -1,10 +1,7 @@
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GHRepository.Contributor;
import org.kohsuke.github.GHUser;
import org.kohsuke.github.GitHub;
import java.util.Collection;
/**
* @author Kohsuke Kawaguchi
*/

View File

@@ -5,8 +5,6 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.apache.commons.io.IOUtils;
import org.hamcrest.CoreMatchers;
import org.junit.Assume;
import org.junit.Test;
import org.kohsuke.github.GHCommit.File;
import org.kohsuke.github.GHOrganization.Permission;
@@ -16,7 +14,6 @@ import java.io.InputStream;
import java.net.URL;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
import java.util.regex.Pattern;
import static org.hamcrest.CoreMatchers.*;
@@ -137,10 +134,10 @@ public class AppTest extends AbstractGitHubApiTestBase {
.description("question")
.payload("{\"user\":\"atmos\",\"room_id\":123456}")
.create();
GHDeploymentStatus ghDeploymentStatus = repository.createDeployStatus(deployment.getId(), GHDeploymentState.SUCCESS)
GHDeploymentStatus ghDeploymentStatus = deployment.createStatus(GHDeploymentState.SUCCESS)
.description("success")
.targetUrl("http://www.github.com").create();
Iterable<GHDeploymentStatus> deploymentStatuses = repository.getDeploymentStatuses(deployment.getId());
Iterable<GHDeploymentStatus> deploymentStatuses = deployment.listStatuses();
assertNotNull(deploymentStatuses);
assertEquals(1,Iterables.size(deploymentStatuses));
assertEquals(ghDeploymentStatus.getId(), Iterables.get(deploymentStatuses, 0).getId());
@@ -756,6 +753,10 @@ public class AppTest extends AbstractGitHubApiTestBase {
assertEquals(t.getColor(), "123456");
assertEquals(t.getColor(), t2.getColor());
assertEquals(t.getUrl(), t2.getUrl());
t.setColor("000000");
GHLabel t3 = r.getLabel("test");
assertEquals(t3.getColor(), "000000");
t.delete();
}
}
@@ -787,7 +788,7 @@ public class AppTest extends AbstractGitHubApiTestBase {
GHRepository r = itr.next();
System.out.println(r.getFullName());
assertNotNull(r.getUrl());
assertNotEquals(0,r.getId());
assertNotEquals(0L,r.getId());
}
}

View File

@@ -1,7 +1,6 @@
package org.kohsuke.github;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import org.junit.Test;
import java.io.IOException;

View File

@@ -187,13 +187,61 @@ public class GHEventPayloadTest {
assertThat(event.getSender().getLogin(), is("baxterthehacker"));
}
// TODO implement support classes and write test
// @Test
// public void pull_request_review() throws Exception {}
@Test
public void pull_request_review() throws Exception {
GHEventPayload.PullRequestReview event =
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.PullRequestReview.class);
assertThat(event.getAction(), is("submitted"));
assertThat(event.getReview().getId(), is(2626884L));
assertThat(event.getReview().getBody(), is("Looks great!\n"));
assertThat(event.getReview().getState(), is(GHPullRequestReviewState.APPROVED));
assertThat(event.getPullRequest().getNumber(), is(8));
assertThat(event.getPullRequest().getTitle(), is("Add a README description"));
assertThat(event.getPullRequest().getBody(), is("Just a few more details"));
assertThat(event.getPullRequest().getUser().getLogin(), is("skalnik"));
assertThat(event.getPullRequest().getHead().getUser().getLogin(), is("skalnik"));
assertThat(event.getPullRequest().getHead().getRef(), is("patch-2"));
assertThat(event.getPullRequest().getHead().getLabel(), is("skalnik:patch-2"));
assertThat(event.getPullRequest().getHead().getSha(), is("b7a1f9c27caa4e03c14a88feb56e2d4f7500aa63"));
assertThat(event.getPullRequest().getBase().getUser().getLogin(), is("baxterthehacker"));
assertThat(event.getPullRequest().getBase().getRef(), is("master"));
assertThat(event.getPullRequest().getBase().getLabel(), is("baxterthehacker:master"));
assertThat(event.getPullRequest().getBase().getSha(), is("9049f1265b7d61be4a8904a9a27120d2064dab3b"));
assertThat(event.getRepository().getName(), is("public-repo"));
assertThat(event.getRepository().getOwner().getLogin(), is("baxterthehacker"));
assertThat(event.getSender().getLogin(), is("baxterthehacker"));
}
// TODO implement support classes and write test
// @Test
// public void pull_request_review_comment() throws Exception {}
@Test
public void pull_request_review_comment() throws Exception {
GHEventPayload.PullRequestReviewComment event =
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.PullRequestReviewComment.class);
assertThat(event.getAction(), is("created"));
assertThat(event.getComment().getBody(), is("Maybe you should use more emojji on this line."));
assertThat(event.getPullRequest().getNumber(), is(1));
assertThat(event.getPullRequest().getTitle(), is("Update the README with new information"));
assertThat(event.getPullRequest().getBody(), is("This is a pretty simple change that we need to pull into master."));
assertThat(event.getPullRequest().getUser().getLogin(), is("baxterthehacker"));
assertThat(event.getPullRequest().getHead().getUser().getLogin(), is("baxterthehacker"));
assertThat(event.getPullRequest().getHead().getRef(), is("changes"));
assertThat(event.getPullRequest().getHead().getLabel(), is("baxterthehacker:changes"));
assertThat(event.getPullRequest().getHead().getSha(), is("0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c"));
assertThat(event.getPullRequest().getBase().getUser().getLogin(), is("baxterthehacker"));
assertThat(event.getPullRequest().getBase().getRef(), is("master"));
assertThat(event.getPullRequest().getBase().getLabel(), is("baxterthehacker:master"));
assertThat(event.getPullRequest().getBase().getSha(), is("9049f1265b7d61be4a8904a9a27120d2064dab3b"));
assertThat(event.getRepository().getName(), is("public-repo"));
assertThat(event.getRepository().getOwner().getLogin(), is("baxterthehacker"));
assertThat(event.getSender().getLogin(), is("baxterthehacker"));
}
@Test
public void push() throws Exception {

View 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")
);
}
}
}

View File

@@ -5,12 +5,14 @@ import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
@@ -156,4 +158,16 @@ public class GitHubTest {
System.out.println(u.getName());
}
}
@Test
public void getOrgs() throws IOException {
GitHub hub = GitHub.connect();
int iterations = 10;
Set<Long> orgIds = new HashSet<Long>();
for (GHOrganization org : Iterables.limit(hub.listOrganizations().withPageSize(2), iterations)) {
orgIds.add(org.getId());
System.out.println(org.getName());
}
assertThat(orgIds.size(), equalTo(iterations));
}
}

View File

@@ -7,8 +7,7 @@ import java.io.IOException;
import java.util.Collection;
import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.*;
/**
* @author Kohsuke Kawaguchi
@@ -33,9 +32,10 @@ public class PullRequestTest extends AbstractGitHubApiTestBase {
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)
);
GHPullRequestReview draftReview = p.createReview()
.body("Some draft review")
.comment("Some niggle", "changelog.html", 1)
.create();
assertThat(draftReview.getState(), is(GHPullRequestReviewState.PENDING));
assertThat(draftReview.getBody(), is("Some draft review"));
assertThat(draftReview.getCommitId(), notNullValue());
@@ -45,15 +45,16 @@ public class PullRequestTest extends AbstractGitHubApiTestBase {
assertThat(review.getState(), is(GHPullRequestReviewState.PENDING));
assertThat(review.getBody(), is("Some draft review"));
assertThat(review.getCommitId(), notNullValue());
review.submit("Some review comment", GHPullRequestReviewState.COMMENTED);
draftReview.submit("Some review comment", GHPullRequestReviewEvent.COMMENT);
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();
draftReview = p.createReview()
.body("Some new review")
.comment("Some niggle", "changelog.html", 1)
.create();
draftReview.delete();
}
@Test
@@ -99,6 +100,19 @@ public class PullRequestTest extends AbstractGitHubApiTestBase {
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
// Requires push access to the test repo to pass
public void setLabels() throws Exception {

View 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){
}
}
}

View File

@@ -5,7 +5,7 @@
"user": {
"login": "baxterthehacker",
"id": 6752317,
"avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3",
"avatar_url": "https://avatars3.githubusercontent.com/u/6752317?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/baxterthehacker",
"html_url": "https://github.com/baxterthehacker",
@@ -21,11 +21,11 @@
"type": "User",
"site_admin": false
},
"body": "Looks great!",
"submitted_at": "2016-10-03T23:39:09Z",
"state": "approved",
"body": "Looks great!\n",
"state": "APPROVED",
"html_url": "https://github.com/baxterthehacker/public-repo/pull/8#pullrequestreview-2626884",
"pull_request_url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/8",
"author_association": "OWNER",
"_links": {
"html": {
"href": "https://github.com/baxterthehacker/public-repo/pull/8#pullrequestreview-2626884"
@@ -33,7 +33,9 @@
"pull_request": {
"href": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/8"
}
}
},
"submitted_at": "2016-10-03T23:39:09Z",
"commit_id": "b7a1f9c27caa4e03c14a88feb56e2d4f7500aa63"
},
"pull_request": {
"url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/8",