Compare commits

...

140 Commits

Author SHA1 Message Date
Kohsuke Kawaguchi
6df5a0d47b Added a test 2015-02-14 10:13:25 -08:00
Kohsuke Kawaguchi
15c18c5547 Improved the search API 2015-02-14 10:08:46 -08:00
Kohsuke Kawaguchi
4b6981c2e7 Added issue-search capability 2015-02-14 09:53:29 -08:00
Kohsuke Kawaguchi
1b4025300c Merge remote-tracking branch 'origin/master' 2015-02-14 09:32:53 -08:00
Kohsuke Kawaguchi
983c871bff More compilation error fix 2015-02-14 09:30:50 -08:00
Kohsuke Kawaguchi
609f532f8c Merge pull request #143 2015-02-14 08:29:09 -08:00
Kohsuke Kawaguchi
c6fc03c73a In this library domain objects should be immutable. 2015-02-14 08:28:55 -08:00
Kohsuke Kawaguchi
b6e48cc4f9 Use GHObject as much as we can 2015-02-14 08:27:20 -08:00
Kohsuke Kawaguchi
50f43cc178 Inserted backward compatibility methods 2015-02-14 08:26:49 -08:00
Kohsuke Kawaguchi
f421067a0d Looks like Windows line ends have crept in. 2015-02-14 07:01:32 -08:00
Kohsuke Kawaguchi
edd9a2d5b6 Using newly added GHObject in more places. 2015-02-14 06:59:46 -08:00
Kohsuke Kawaguchi
41e0329f55 doc improvement 2015-02-14 06:52:48 -08:00
Kohsuke Kawaguchi
21ea916e0d Pull request #143 introduced wrong file permissions 2015-02-14 06:48:56 -08:00
Kohsuke Kawaguchi
3b6ca3020e Pull request #143 introduced wrong file permissions 2015-02-14 06:47:52 -08:00
Kohsuke Kawaguchi
3737845b78 Merge pull request #143 2015-02-14 06:47:26 -08:00
Kohsuke Kawaguchi
a30c78cd12 restored backward compatibility in the public API 2015-02-14 06:46:27 -08:00
Kohsuke Kawaguchi
f8fba41a30 Merge pull request #141 from alvaro1728/master
Trivial change to enable creating/updating binary content (files).
2015-02-14 09:42:55 -05:00
Kohsuke Kawaguchi
052902fb49 Merge pull request #146 2015-02-14 06:41:06 -08:00
Surya Gaddipati
58143c26bc Use GHCommitState for deployment status state 2015-01-12 10:04:01 -06:00
Surya Gaddipati
5d83894056 Add method for listing deployments 2015-01-02 16:46:56 -06:00
Rob Schoening
e35667525f fix #145 GHTeam.getMembers() does not page properly 2014-12-28 15:47:57 -08:00
Surya Gaddipati
2f318152d8 Complete api implementation for setting/retriving deployment status on a deployment 2014-12-20 17:09:59 -06:00
Surya Gaddipati
bc518a9ae8 Complete implementation of create deployment api 2014-12-20 11:52:49 -06:00
Kohsuke Kawaguchi
425ae2d536 Merge pull request #142 from suryagaddipati/master
Add code for creating deployments for a repo
2014-12-19 11:45:15 -08:00
Kohsuke Kawaguchi
a6cacd4aba Merge pull request #137 from simonecarriero/master
added 'diverged' constant to GHCompare.Status enum
2014-12-19 11:44:10 -08:00
Kohsuke Kawaguchi
5a7083537c Merge pull request #136 from rtyley/page-team-repositories
Add paging support for Team's Repositories
2014-12-19 11:43:56 -08:00
Surya Gaddipati
e15f7a59fd Merge pull request #139 from farmdawgnation/mocking-scope
Put mockito in the test scope.
2014-12-19 12:53:15 -06:00
Surya Gaddipati
a2fa526aa0 Add code for creating deployments for a repo 2014-12-19 12:47:00 -06:00
mendeza
7e959d6a87 Added binary content support - without tabs. 2014-12-18 21:15:29 -08:00
mendeza
5121fe1cbf Added binary content support. 2014-12-18 21:03:28 -08:00
Matt Farmer
3c3d4fc151 Put mockito in the test scope. 2014-11-16 15:31:04 -05:00
Simone Carriero
a7f75c9a6c added 'diverged' constant to GHCompare.Status enum 2014-11-06 12:18:16 +01:00
Roberto Tyley
e7262b8fbe Add paging support for Team's Repositories
The team repositories endpoint does do paging, so gotta support that.
2014-11-06 09:40:37 +00:00
Kohsuke Kawaguchi
af3099c526 [maven-release-plugin] prepare for next development iteration 2014-10-08 12:17:53 -07:00
Kohsuke Kawaguchi
2b9d47cea8 [maven-release-plugin] prepare release github-api-1.59 2014-10-08 12:17:49 -07:00
Kohsuke Kawaguchi
5db90d3fc4 This test is invalid if ~/.github file exists, which is quite common 2014-10-08 12:15:32 -07:00
Kohsuke Kawaguchi
372d5ff758 Fixed a test regression
Presumably due to the behaviour change on GitHub API?
2014-10-08 12:07:09 -07:00
Kohsuke Kawaguchi
ebf39eaea1 [INFRA-142]
Reworked version of https://github.com/kohsuke/github-api/pull/133/files
2014-10-08 11:29:17 -07:00
Michael O'Cleirigh
556786f2e1 Merge pull request #131 from mocleiri/resolve-credentials-from-environment
Modify GitHubBuilder to resolve user credentials from the system environ...
2014-09-30 14:07:35 -04:00
Michael O'Cleirigh
0f64994537 Make Github.connect() fail if no credentials are setup
With the previous change if no credentials were defined Github.connect() would
fall back on an anonymous connection.

This commit changes the behaviour back to what it was before so that if there
are no credentials defined in the ~/.github file and no credentials defined
in the environment an IOException is thrown to alert the method caller.

The caller can call Github.connectAnonymously() if that scenario is allowed.

This should handle most cases unless callers are depending on the
FileNotFoundException being specifically thrown instead of an IOException.
2014-09-30 13:58:06 -04:00
Michael O'Cleirigh
ac64c2022b Merge pull request #132 from mocleiri/add-getFiles-method-to-GHCompare
Add GHCompare.getFiles() method to be able to see the precise files chan...
2014-09-30 12:03:54 -04:00
Michael O'Cleirigh
9802132b6f Add GHCompare.getFiles() method to be able to see the precise files changed.
There is a file field inside of GHCompare but no getter to extract the values
for analysis.

There are contents in that field so I've added a new get method so that they
can be extracted.
2014-09-30 11:51:57 -04:00
Michael O'Cleirigh
4d6c5c14f1 Modify GitHubBuilder to resolve user credentials from the system environment
Using the Jenkins EnvInject or Credentials Binding Plugins its possible to
pass credentials as Environment Variables.

Its useful for Github.connect() to be able to directly read the values of the
'login', 'password' and 'oauth' properties directly from the environment.

This commit modifies the base Github.connect() method to resolve credentials
in two steps:

1. ~/.github credentials file if it exists.
2. login, password or oauth variables from the environment

A further fromEnvironment() method is provided to support
loading from non-standard variable names.

The old Github.connect() method would throw an IOException if the ~/.github file
did not exist.  Now it will fail silently instead dropping back to the anonymous
users access level.

Added new unit tests into GitHubTest.
2014-09-29 13:42:28 -04:00
Kohsuke Kawaguchi
d228a5fb93 Merge pull request #128 from ndeloof/patch-1
Update github scopes according to https://developer.github.com/v3/oauth/#scopes
2014-09-26 18:10:15 -07:00
Michael O'Cleirigh
7b46ef10c8 Merge pull request #129 from mocleiri/fix-pull-request-remote-repo-get-commit
Allow pullRequest.getHead().getRepository().getCommit(headSha1) to work
2014-09-26 15:14:25 -04:00
Michael O'Cleirigh
8eb9fba051 Allow pullRequest.getHead().getRepository().getCommit(headSha1) to work
The wrong .wrap method was used for pull requests initialized by state
(GHRepository.getPullReqests).

The wrong wrap call was introduced in 9fd34aec7f

This commit sets it back to the .wrapUp method which makes sure the pull request
substructure has the repo object set properly.

Without this change a NullPointerException is thrown on the last line of this
code because the repo object inside of the remoteRepository object is null:

GHRepository repo = github.getRepository(targetRepository);

List<GHPullRequest> openPullRequests = repo.getPullRequests(GHIssueState.OPEN);

for (GHPullRequest pullRequest : openPullRequests) {

    GHCommitPointer head = pullRequest.getHead();

	GHRepository remoteRepository = head.getRepository();

	String commitId = head.getSha();

	GHCommit headCommit = remoteRepository.getCommit(commitId);
2014-09-22 10:53:13 -04:00
Nicolas De loof
7b58182683 Update github scopes according to https://developer.github.com/v3/oauth/#scopes 2014-09-12 23:16:43 +02:00
Kohsuke Kawaguchi
95fbf9274b Merge pull request #124 from ohtake/connector
Allow to use custom HttpConnector when only OAuth token is given
2014-09-04 10:32:11 -07:00
Kohsuke Kawaguchi
09557dfa0f Merge pull request #123 from rtyley/use-issues-endpoints-for-pull-requests
Use issues endpoints for pull requests
2014-09-04 10:31:25 -07:00
Kohsuke Kawaguchi
4029fcc1ca Merge pull request #122 from tbruyelle/browserDownloadUrl
Add missing field browser_download_url in GHAsset
2014-09-04 10:29:23 -07:00
OHTAKE Tomohiro
d6627b1e34 Use custom HttpConnector when only OAuth token is given 2014-09-04 13:18:35 +09:00
OHTAKE Tomohiro
86d75fd767 Introduce GitHubBuilder for flexible GitHub instance creation 2014-09-04 13:17:43 +09:00
Roberto Tyley
e2220bb3b3 Fix setting labels and assignee on PullRequests
Setting labels and assignee on Pull requests failed silently, because
the API endpoint being hit contained '/pulls/' rather than '/issues/'.

"Every pull request is an issue, but not every issue is a pull request.
For this reason, “shared” actions for both features, like manipulating
assignees, labels and milestones, are provided within the Issues API."

https://developer.github.com/v3/pulls/#labels-assignees-and-milestones
2014-09-03 23:34:58 +01:00
Roberto Tyley
1a9b8bd1da Separate out clean-up of Pull requests created during test
If the test assertion fails, we want the pull-request to be closed anyway.
You can't have more than one pull-request merging a given branch into
another, so leaving the PR hanging will cause subsequent test runs to fail
in setup.
2014-09-03 23:18:22 +01:00
Thomas Bruyelle
9eda2d3f77 Add missing field browser_download_url in GHAsset 2014-09-03 22:01:43 +02:00
Kohsuke Kawaguchi
e6d59df705 [maven-release-plugin] prepare for next development iteration 2014-08-30 14:15:29 -07:00
Kohsuke Kawaguchi
db845850b2 [maven-release-plugin] prepare release github-api-1.58 2014-08-30 14:15:25 -07:00
Kohsuke Kawaguchi
d516597659 See if this will get me release with Maven 3.1 2014-08-30 14:13:45 -07:00
Kohsuke Kawaguchi
3af5a8145a Merge branch 'pull-117' 2014-08-30 14:03:58 -07:00
Kohsuke Kawaguchi
31bebd4a7a Design pattern in this library demands that these methods be on GHRef 2014-08-30 14:03:34 -07:00
Kohsuke Kawaguchi
ccb87258b0 Merge pull request #116 from DavidTanner/patch-1
Remove getPath()
2014-08-30 13:54:05 -07:00
Kohsuke Kawaguchi
2ab71e88bd Merge pull request #115 from bernd/add-missing-event-types
Add missing GitHub event types.
2014-08-30 13:53:23 -07:00
Kohsuke Kawaguchi
78bd7585bb Merge pull request #114 from ndeloof/master
get repository full name (including owner)
2014-08-30 13:53:02 -07:00
Kohsuke Kawaguchi
92cc81d9b8 Merge pull request #107 from msperisen/general-pagination
General pagination
2014-08-30 13:52:35 -07:00
Matt Farmer
97a1c741de Implement support for deleting a ref using the GitHub API. 2014-08-22 23:33:04 -04:00
Matt Farmer
077d693959 Add support for updating a ref using the API. 2014-08-22 23:30:22 -04:00
David Tanner
94831fc10a Remove getPath()
When getting the path and providing an enterprise url for the apiUrl, the /api/v3 portion gets duplicated.  Since they will be combined on line 231 of GitHub.java there is no point just grabbing the path.  See https://github.com/janinko/ghprb/issues/178, and https://issues.jenkins-ci.org/browse/JENKINS-24145?focusedCommentId=208270#comment-208270
2014-08-19 13:22:25 -06:00
Surya Gaddipati
1f298a88b0 [maven-release-plugin] prepare for next development iteration 2014-08-19 13:29:40 -05:00
Surya Gaddipati
7e49946bed [maven-release-plugin] prepare release github-api-1.57 2014-08-19 13:29:37 -05:00
Surya Gaddipati
1e81ab1017 Merge pull request #112 from lucamilanesio/master
Get all orgs/teams/permissions in a single GitHub API call
2014-08-19 12:57:39 -05:00
Bernd Ahlers
311180d12e Add missing DEPLOYMENT, DEPLOYMENT_STATUS, RELEASE and STATUS events. 2014-08-18 16:54:17 +02:00
Nicolas De Loof
0efb206881 get repository full name (including owner) 2014-08-06 04:48:46 +02:00
Luca Milanesio
0b92fa5615 Get all orgs/teams/permissions in a single GitHub API call
Exposes a new API call at GitHub root level to build the complete
set of organisations and teams that current user belongs to.

This change allows to massively reduce the number of calls to GitHub 
especially for people that belongs to multiple organisations with 
lots of teams and members.

Signed-off-by: Luca Milanesio <luca.milanesio@gmail.com>
2014-07-24 23:42:37 +01:00
t865095
a58a5b56b2 Merge branch 'master' of https://github.com/kohsuke/github-api 2014-07-08 14:14:59 +02:00
t865095
b9764c0a44 introduce pagination for all paged api calls and introduce cache invalidation 2014-07-08 13:52:53 +02:00
Kohsuke Kawaguchi
590f7ba511 Merge pull request #106 from lucamilanesio/master
Implement pagination on list of private+public repos of a user.
2014-07-04 19:13:04 -07:00
Luca Milanesio
449909b0e8 Implement pagination on list of private+public repos of a user.
The paginated version of listRepositories() was 
missing at GHMyself: as side-effect of this bug
when requesting a paginated list of repositories
the ones privately owned by a user were not shown.

This was caused by the missing override of the 
listRepositories(final int pageSize) at GHMyself
that caused the GHPerson implementation to invoked.

The GHPerson version uses the /users/:org/repos?per_page=x
URL which *works fine* for organisations but unfortunately
*does not return* private repositories for users.

IMHO GitHub API are quite inconsistent form this 
point of view, but they are documented in this way
so that work (inconsistently) as designed.
2014-07-03 10:05:17 +01:00
Kohsuke Kawaguchi
40780525f8 Bumping up the version in the hope of fixing site plugin problem 2014-07-02 21:39:13 -07:00
Kohsuke Kawaguchi
0e3707d1c3 [maven-release-plugin] prepare for next development iteration 2014-07-02 21:28:38 -07:00
Kohsuke Kawaguchi
8ddbef093b [maven-release-plugin] prepare release github-api-1.56 2014-07-02 21:28:34 -07:00
Kohsuke Kawaguchi
4ccdfccdf0 Oops forgot to commit this change 2014-07-02 21:27:11 -07:00
Kohsuke Kawaguchi
3c8aa0c630 Convention dictates that the method name be "listXyz"
getCollaborators() only fetching the first page is a bug, so we should fix that too.
2014-07-02 21:24:17 -07:00
Kohsuke Kawaguchi
ba519f996a Extracted non-formatting changes from pull request #98
The original commit has too many whitespace noise changes.

Reference: https://github.com/kohsuke/github-api/pull/98
2014-07-02 21:22:17 -07:00
Kohsuke Kawaguchi
62d9b92e6e Merge pull request #103 from rtyley/okhttp-2.0.0
Update to OkHttp 2.0.0, which has a new OkUrlFactory
2014-07-02 21:13:37 -07:00
Kohsuke Kawaguchi
d2c909584d Merge pull request #102 from jglick/clearer-FNFE
Better FNFE from delete()
2014-07-02 21:13:16 -07:00
Kohsuke Kawaguchi
219916eb14 Merge pull request #101 from farmdawgnation/final-answer
Un-finalize a handful of classes.
2014-07-02 21:12:59 -07:00
Roberto Tyley
0a37ac901f Update to OkHttp 2.0.0, which has a new OkUrlFactory
OkHttp changed API with v2.0.0, and the `client.open(url)` method no
longer exists:

"URLConnection support has moved to the okhttp-urlconnection module.
If you're upgrading from 1.x, this change will impact you. You will
need to add the okhttp-urlconnection module to your project and use
the OkUrlFactory to create new instances of HttpURLConnection"

https://github.com/square/okhttp/blob/master/CHANGELOG.md#version-200-rc1
2014-06-28 11:12:25 +01:00
Jesse Glick
4586baea27 Explain what a FNFE from delete() may just mean your token is lacking delete_repo. 2014-06-24 10:38:13 -04:00
Matt Farmer
d83961e85b Un-finalize a handful of classes. 2014-06-14 19:34:42 -04:00
Kohsuke Kawaguchi
7e35716ff0 [maven-release-plugin] prepare for next development iteration 2014-06-08 10:37:21 -07:00
Kohsuke Kawaguchi
d0cf1ac605 [maven-release-plugin] prepare release github-api-1.55 2014-06-08 10:37:17 -07:00
Kohsuke Kawaguchi
9a19d07ab8 I'm getting "the key is already in use" error.
Creating a new thro-away key
2014-06-08 10:36:05 -07:00
Kohsuke Kawaguchi
922be0b164 make sure the key gets deleted no matter what 2014-06-08 10:31:15 -07:00
Kohsuke Kawaguchi
d0b8e2e37e Merge pull request #97 from suryagaddipati/add_context_to_commit_status
Add support for adding context to commit status.
2014-06-08 10:21:43 -07:00
Surya Gaddipati
e3d6e08b6a Preserve api compatablity with previous version.
Support adding commitstatus without context.
2014-06-07 14:43:09 -05:00
Surya Gaddipati
16a6623095 Add support for adding context to commit status.
This groups statuses from multiple contexts to return single combined
status. More information here:
https://developer.github.com/changes/2014-03-27-combined-status-api/
2014-06-07 14:29:25 -05:00
Kohsuke Kawaguchi
7bf31ca149 [maven-release-plugin] prepare for next development iteration 2014-06-05 10:30:01 -07:00
Kohsuke Kawaguchi
030f2360ca [maven-release-plugin] prepare release github-api-1.54 2014-06-05 10:29:56 -07:00
Kohsuke Kawaguchi
08eafc4214 Merge pull request #94 from suryagaddipati/master
Add support for adding deploykeys to repo
2014-06-05 10:28:19 -07:00
Kohsuke Kawaguchi
134ece9385 Merge pull request #95 from suryagaddipati/ghref
Add support for retriving a single ref
2014-06-05 10:27:42 -07:00
Surya Gaddipati
3e4b06e959 Add support for retriving a single ref
Implements the following api method
https://developer.github.com/v3/git/refs/#get-a-reference
2014-06-04 15:11:27 -05:00
Surya Gaddipati
3e3c6f70ba Add support for adding deploykeys to repo
Implements https://developer.github.com/v3/repos/keys/
2014-06-03 15:26:04 -05:00
Kohsuke Kawaguchi
3097378a10 Merge pull request #93 from vr100/master
Upgrading to 1.12 version for bridge-method-annotation and bridge-method-injector - fix for #91
2014-05-28 20:52:07 -07:00
vr100
53f7a0f78a Upgrading to 1.12 version for bridge-method-annotation and bridge-method-injector - fix for #91 2014-05-28 12:41:19 +05:30
Kohsuke Kawaguchi
45a6841772 added a method to visit sub-directory 2014-05-27 20:57:42 -07:00
Kohsuke Kawaguchi
80b93a6e33 doc improvement 2014-05-27 20:44:44 -07:00
Kohsuke Kawaguchi
6aaab641be Using the latest 2014-05-10 15:57:56 -07:00
Kohsuke Kawaguchi
4999490c06 [maven-release-plugin] prepare for next development iteration 2014-05-10 15:52:17 -07:00
Kohsuke Kawaguchi
c7c1cd8bb3 [maven-release-plugin] prepare release github-api-1.53 2014-05-10 15:52:12 -07:00
Kohsuke Kawaguchi
8a1f116305 Renamed to avoid colliding with LifecycleTest 2014-05-10 15:49:31 -07:00
Kohsuke Kawaguchi
f8fe1dda6d Presence check needs to run on the same repo 2014-05-10 15:46:14 -07:00
Kohsuke Kawaguchi
bf44232d5c Updated test case 2014-05-10 15:43:15 -07:00
Kohsuke Kawaguchi
8c8ba47ef9 Fork into an org to simplify access control 2014-05-10 15:38:13 -07:00
Kohsuke Kawaguchi
b3580002d0 doc improvement 2014-05-10 15:37:21 -07:00
Kohsuke Kawaguchi
1249199b22 push fails with HTTPS 2014-05-10 15:34:57 -07:00
Kohsuke Kawaguchi
f39a47f354 This test seems to fail randomly 2014-05-10 15:32:58 -07:00
Kohsuke Kawaguchi
f58f15925f Fake a big rate limit
This fixes issue #78
2014-05-10 15:30:33 -07:00
Kohsuke Kawaguchi
a071f8bb86 Exposed more endpoints.
This fixes issue #64.
2014-05-10 15:21:59 -07:00
Kohsuke Kawaguchi
d33609ee57 Make sure getRepositories() for the user himself returns private repositories
This fixes issue #88
2014-05-10 15:16:12 -07:00
Kohsuke Kawaguchi
f2c08bc1e8 Added ability to create a pull request.
This fixes issue #79.
2014-05-10 15:05:48 -07:00
Kohsuke Kawaguchi
688d8ed7bc Added databinding for files 2014-05-10 14:11:41 -07:00
Kohsuke Kawaguchi
2ddb4018b8 added data binding for a file in gist 2014-05-10 14:07:53 -07:00
Kohsuke Kawaguchi
3ec25683f7 doc improvement 2014-05-10 14:03:49 -07:00
Kohsuke Kawaguchi
25d426f483 Bug fix based on tests 2014-05-10 14:03:12 -07:00
Kohsuke Kawaguchi
9d91ebc47a Not sure why tests weren't in the right package 2014-05-10 13:53:13 -07:00
Kohsuke Kawaguchi
c784ab6632 Added Gist support 2014-05-10 13:52:36 -07:00
Kohsuke Kawaguchi
ed5e3f13a1 exposed via getter.
This fixes issue #52.
2014-05-10 13:25:33 -07:00
Kohsuke Kawaguchi
3dcd82745e Resolved issue #54 2014-05-10 12:52:00 -07:00
Kohsuke Kawaguchi
c564dc5f29 All tests should use the secondary account 2014-05-10 12:47:28 -07:00
Kohsuke Kawaguchi
d64453b661 Fixing tests 2014-05-10 12:44:52 -07:00
Kohsuke Kawaguchi
834ed7db0e Merge branch 'pull-84' 2014-05-10 12:42:34 -07:00
Kohsuke Kawaguchi
db1dde533f Updated tests to use a separate account 2014-05-10 12:42:19 -07:00
Kohsuke Kawaguchi
9c66d9465e Added removal of release 2014-05-10 12:27:18 -07:00
Kohsuke Kawaguchi
8c193d004e Updated test cases to reflect my changes 2014-05-10 12:11:20 -07:00
Kohsuke Kawaguchi
7cbd7f999a Pointless to define a builder that doesn't take parameters 2014-05-10 12:08:17 -07:00
Kohsuke Kawaguchi
4340c8cb00 Support pagination in releases just like tags 2014-05-10 12:00:44 -07:00
Kohsuke Kawaguchi
6f6583772d Should support pagination 2014-05-10 11:59:46 -07:00
Kohsuke Kawaguchi
c62bc8d5da subsumed by GHRepository.queryCommits() 2014-05-10 11:58:22 -07:00
Kohsuke Kawaguchi
f68bfcb3e2 [maven-release-plugin] prepare for next development iteration 2014-05-09 18:39:33 -07:00
Francois Berthault
2e5a9479a8 create a Release & Branch 2014-04-21 10:45:10 +02:00
50 changed files with 2204 additions and 463 deletions

25
pom.xml
View File

@@ -3,11 +3,11 @@
<parent>
<groupId>org.kohsuke</groupId>
<artifactId>pom</artifactId>
<version>6</version>
<version>10</version>
</parent>
<artifactId>github-api</artifactId>
<version>1.52</version>
<version>1.60-SNAPSHOT</version>
<name>GitHub API for Java</name>
<url>http://github-api.kohsuke.org/</url>
<description>GitHub API for Java</description>
@@ -35,7 +35,7 @@
<plugin>
<groupId>com.infradna.tool</groupId>
<artifactId>bridge-method-injector</artifactId>
<version>1.8</version>
<version>1.14</version>
<executions>
<execution>
<goals>
@@ -77,8 +77,7 @@
<dependency>
<groupId>com.infradna.tool</groupId>
<artifactId>bridge-method-annotation</artifactId>
<version>1.8</version>
<optional>true</optional>
<version>1.14</version>
</dependency>
<dependency>
<groupId>org.kohsuke.stapler</groupId>
@@ -94,10 +93,22 @@
</dependency>
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>okhttp</artifactId>
<version>1.5.3</version>
<artifactId>okhttp-urlconnection</artifactId>
<version>2.0.0</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.kohsuke</groupId>
<artifactId>wordnet-random-name</artifactId>
<version>1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>

View File

@@ -1,26 +1,22 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Date;
/**
* Asset in a release.
*
* @see GHRelease#getAssets()
*/
public class GHAsset {
public class GHAsset extends GHObject {
GitHub root;
GHRepository owner;
private String url;
private String id;
private String name;
private String label;
private String state;
private String content_type;
private long size;
private long download_count;
private Date created_at;
private Date updated_at;
private String browser_download_url;
public String getContentType() {
return content_type;
@@ -31,18 +27,10 @@ public class GHAsset {
this.content_type = contentType;
}
public Date getCreatedAt() {
return created_at;
}
public long getDownloadCount() {
return download_count;
}
public String getId() {
return id;
}
public String getLabel() {
return label;
}
@@ -72,12 +60,8 @@ public class GHAsset {
return state;
}
public Date getUpdatedAt() {
return updated_at;
}
public String getUrl() {
return url;
public String getBrowserDownloadUrl() {
return browser_download_url;
}
private void edit(String key, Object value) throws IOException {

View File

@@ -12,7 +12,7 @@ import java.util.List;
* @see GitHub#createToken(Collection, String, String)
* @see http://developer.github.com/v3/oauth/#create-a-new-authorization
*/
public class GHAuthorization {
public class GHAuthorization extends GHObject {
public static final String USER = "user";
public static final String USER_EMAIL = "user:email";
public static final String USER_FOLLOW = "user:follow";
@@ -22,26 +22,27 @@ public class GHAuthorization {
public static final String DELETE_REPO = "delete_repo";
public static final String NOTIFICATIONS = "notifications";
public static final String GIST = "gist";
public static final String READ_HOOK = "read:repo_hook";
public static final String WRITE_HOOK = "write:repo_hook";
public static final String AMIN_HOOK = "admin:repo_hook";
public static final String READ_ORG = "read:org";
public static final String WRITE_ORG = "write:org";
public static final String ADMIN_ORG = "admin:org";
public static final String READ_KEY = "read:public_key";
public static final String WRITE_KEY = "write:public_key";
public static final String ADMIN_KEY = "admin:public_key";
private GitHub root;
private int id;
private String url;
private List<String> scopes;
private String token;
private App app;
private String note;
private String note_url;
private String updated_at;
private String created_at;
public GitHub getRoot() {
return root;
}
public int getId() {
return id;
}
public List<String> getScopes() {
return scopes;
}
@@ -69,14 +70,6 @@ public class GHAuthorization {
public URL getNoteUrl(){
return GitHub.parseURL(note_url);
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public Date getUpdatedAt() {
return GitHub.parseDate(updated_at);
}
/*package*/ GHAuthorization wrap(GitHub root) {
this.root = root;

View File

@@ -12,13 +12,11 @@ import java.util.Date;
* @see GHCommit#listComments()
* @see GHCommit#createComment(String, String, Integer, Integer)
*/
public class GHCommitComment {
public class GHCommitComment extends GHObject {
private GHRepository owner;
String updated_at, created_at;
String body, url, html_url, commit_id;
String body, html_url, commit_id;
Integer line;
int id;
String path;
User user;
@@ -32,14 +30,6 @@ public class GHCommitComment {
return owner;
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public Date getUpdatedAt() {
return GitHub.parseDate(updated_at);
}
/**
* URL like 'https://github.com/kohsuke/sandbox-ant/commit/8ae38db0ea5837313ab5f39d43a6f73de3bd9000#commitcomment-1252827' to
* show this commit comment in a browser.
@@ -75,10 +65,6 @@ public class GHCommitComment {
return line!=null ? line : -1;
}
public int getId() {
return id;
}
/**
* Gets the user who put this comment.
*/

View File

@@ -10,12 +10,10 @@ import java.util.Date;
* @see GHRepository#getCommitStatus(String)
* @see GHCommit#getStatus()
*/
public class GHCommitStatus {
String created_at, updated_at;
public class GHCommitStatus extends GHObject {
String state;
String target_url,description;
int id;
String url;
String context;
GHUser creator;
private GitHub root;
@@ -26,14 +24,6 @@ public class GHCommitStatus {
return this;
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public Date getUpdatedAt() {
return GitHub.parseDate(updated_at);
}
public GHCommitState getState() {
for (GHCommitState s : GHCommitState.values()) {
if (s.name().equalsIgnoreCase(state))
@@ -55,18 +45,11 @@ public class GHCommitStatus {
return description;
}
public int getId() {
return id;
}
/**
* API URL of this commit status.
*/
public String getUrl() {
return url;
}
public GHUser getCreator() {
return creator;
}
public String getContext() {
return context;
}
}

View File

@@ -68,9 +68,12 @@ public class GHCompare {
public Commit[] getCommits() {
return commits;
}
public GHCommit.File[] getFiles() {
return files;
}
public GHCompare wrap(GHRepository owner) {
public GHCompare wrap(GHRepository owner) {
this.owner = owner;
for (Commit commit : commits) {
commit.wrapUp(owner);
@@ -145,6 +148,6 @@ public class GHCompare {
}
public static enum Status {
behind, ahead, identical
behind, ahead, identical, diverged
}
}

View File

@@ -1,6 +1,8 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.xml.bind.DatatypeConverter;
@@ -8,7 +10,9 @@ import javax.xml.bind.DatatypeConverter;
* A Content of a repository.
*
* @author Alexandre COLLIGNON
* @see GHRepository#getFileContent(String)
*/
@SuppressWarnings({"UnusedDeclaration"})
public class GHContent {
private GHRepository owner;
@@ -105,12 +109,39 @@ public class GHContent {
return "dir".equals(type);
}
/**
* List immediate children of this directory.
*/
public PagedIterable<GHContent> listDirectoryContent() throws IOException {
if (!isDirectory())
throw new IllegalStateException(path+" is not a directory");
return new PagedIterable<GHContent>() {
public PagedIterator<GHContent> iterator() {
return new PagedIterator<GHContent>(owner.root.retrieve().asIterator(url, GHContent[].class)) {
@Override
protected void wrapUp(GHContent[] page) {
GHContent.wrap(page,owner);
}
};
}
};
}
public GHContentUpdateResponse update(String newContent, String commitMessage) throws IOException {
return update(newContent, commitMessage, null);
return update(newContent.getBytes(), commitMessage, null);
}
public GHContentUpdateResponse update(String newContent, String commitMessage, String branch) throws IOException {
String encodedContent = DatatypeConverter.printBase64Binary(newContent.getBytes());
return update(newContent.getBytes(), commitMessage, branch);
}
public GHContentUpdateResponse update(byte[] newContentBytes, String commitMessage) throws IOException {
return update(newContentBytes, commitMessage, null);
}
public GHContentUpdateResponse update(byte[] newContentBytes, String commitMessage, String branch) throws IOException {
String encodedContent = DatatypeConverter.printBase64Binary(newContentBytes);
Requester requester = new Requester(owner.root)
.with("path", path)

View File

@@ -4,7 +4,7 @@ package org.kohsuke.github;
* The response that is returned when updating
* repository content.
**/
public final class GHContentUpdateResponse {
public class GHContentUpdateResponse {
private GHContent content;
private GHCommit commit;

View File

@@ -0,0 +1,46 @@
package org.kohsuke.github;
import java.io.IOException;
import org.apache.commons.lang.builder.ToStringBuilder;
public class GHDeployKey {
protected String url, key, title;
protected boolean verified;
protected int id;
private GHRepository owner;
public int getId() {
return id;
}
public String getKey() {
return key;
}
public String getTitle() {
return title;
}
public String getUrl() {
return url;
}
public boolean isVerified() {
return verified;
}
public GHDeployKey wrap(GHRepository repo) {
this.owner = repo;
return this;
}
public String toString() {
return new ToStringBuilder(this).append("title",title).append("id",id).append("key",key).toString();
}
public void delete() throws IOException {
new Requester(owner.root).method("DELETE").to(String.format("/repos/%s/%s/keys/%d", owner.getOwnerName(), owner.getName(), id));
}
}

View File

@@ -0,0 +1,53 @@
package org.kohsuke.github;
import java.net.URL;
public class GHDeployment extends GHObject {
private GHRepository owner;
private GitHub root;
protected String sha;
protected String ref;
protected String task;
protected Object payload;
protected String environment;
protected String description;
protected String statuses_url;
protected String repository_url;
protected GHUser creator;
GHDeployment wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
if(creator != null) creator.wrapUp(root);
return this;
}
public URL getStatusesUrl() {
return GitHub.parseURL(statuses_url);
}
public URL getRepositoryUrl() {
return GitHub.parseURL(repository_url);
}
public String getTask() {
return task;
}
public String getPayload() {
return (String) payload;
}
public String getEnvironment() {
return environment;
}
public GHUser getCreator() {
return creator;
}
public String getRef() {
return ref;
}
public String getSha(){
return sha;
}
}

View File

@@ -0,0 +1,55 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.List;
//Based on https://developer.github.com/v3/repos/deployments/#create-a-deployment
public class GHDeploymentBuilder {
private final GHRepository repo;
private final Requester builder;
public GHDeploymentBuilder(GHRepository repo) {
this.repo = repo;
this.builder = new Requester(repo.root);
}
public GHDeploymentBuilder(GHRepository repo, String ref) {
this(repo);
ref(ref);
}
public GHDeploymentBuilder ref(String branch) {
builder.with("ref",branch);
return this;
}
public GHDeploymentBuilder task(String task) {
builder.with("task",task);
return this;
}
public GHDeploymentBuilder autoMerge(boolean autoMerge) {
builder.with("auto_merge",autoMerge);
return this;
}
public GHDeploymentBuilder requiredContexts(List<String> requiredContexts) {
builder.with("required_contexts",requiredContexts);
return this;
}
public GHDeploymentBuilder payload(String payload) {
builder.with("payload",payload);
return this;
}
public GHDeploymentBuilder environment(String environment) {
builder.with("environment",environment);
return this;
}
public GHDeploymentBuilder description(String description) {
builder.with("description",description);
return this;
}
public GHDeployment create() throws IOException {
return builder.to(repo.getApiTailUrl("deployments"),GHDeployment.class).wrap(repo);
}
}

View File

@@ -0,0 +1,8 @@
package org.kohsuke.github;
/**
* Represents the state of deployment
*/
public enum GHDeploymentState {
PENDING, SUCCESS, ERROR, FAILURE
}

View File

@@ -0,0 +1,36 @@
package org.kohsuke.github;
import java.net.URL;
public class GHDeploymentStatus extends GHObject {
private GHRepository owner;
private GitHub root;
protected GHUser creator;
protected String state;
protected String description;
protected String target_url;
protected String deployment_url;
protected String repository_url;
public GHDeploymentStatus wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
if(creator != null) creator.wrapUp(root);
return this;
}
public URL getTargetUrl() {
return GitHub.parseURL(target_url);
}
public URL getDeploymentUrl() {
return GitHub.parseURL(deployment_url);
}
public URL getRepositoryUrl() {
return GitHub.parseURL(repository_url);
}
public GHDeploymentState getState() {
return GHDeploymentState.valueOf(state.toUpperCase());
}
}

View File

@@ -0,0 +1,30 @@
package org.kohsuke.github;
import java.io.IOException;
public class GHDeploymentStatusBuilder {
private final Requester builder;
private GHRepository repo;
private int deploymentId;
public GHDeploymentStatusBuilder(GHRepository repo, int deploymentId, GHDeploymentState state) {
this.repo = repo;
this.deploymentId = deploymentId;
this.builder = new Requester(repo.root);
this.builder.with("state",state.toString().toLowerCase());
}
public GHDeploymentStatusBuilder description(String description) {
this.builder.with("description",description);
return this;
}
public GHDeploymentStatusBuilder targetUrl(String targetUrl) {
this.builder.with("target_url",targetUrl);
return this;
}
public GHDeploymentStatus create() throws IOException {
return builder.to(repo.getApiTailUrl("deployments")+"/"+deploymentId+"/statuses",GHDeploymentStatus.class).wrap(repo);
}
}

View File

@@ -12,6 +12,8 @@ public enum GHEvent {
COMMIT_COMMENT,
CREATE,
DELETE,
DEPLOYMENT,
DEPLOYMENT_STATUS,
DOWNLOAD,
FOLLOW,
FORK,
@@ -25,6 +27,8 @@ public enum GHEvent {
PULL_REQUEST,
PULL_REQUEST_REVIEW_COMMENT,
PUSH,
RELEASE,
STATUS,
TEAM_ADD,
WATCH
}

View File

@@ -0,0 +1,177 @@
package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
/**
* Gist
*
* @author Kohsuke Kawaguchi
* @see GHUser#listGists()
* @see GitHub#getGist(String)
* @see GitHub#createGist()
*/
public class GHGist extends GHObject {
/*package almost final*/ GHUser owner;
/*package almost final*/ GitHub root;
private String forks_url, commits_url, id, git_pull_url, git_push_url, html_url;
@JsonProperty("public")
private boolean _public;
private String description;
private int comments;
private String comments_url;
private Map<String,GHGistFile> files = new HashMap<String, GHGistFile>();
/**
* User that owns this Gist.
*/
public GHUser getOwner() {
return owner;
}
public String getForksUrl() {
return forks_url;
}
public String getCommitsUrl() {
return commits_url;
}
/**
* URL like https://gist.github.com/gists/12345.git
*/
public String getGitPullUrl() {
return git_pull_url;
}
public String getGitPushUrl() {
return git_push_url;
}
public String getHtmlUrl() {
return html_url;
}
public boolean isPublic() {
return _public;
}
public String getDescription() {
return description;
}
public int getCommentCount() {
return comments;
}
/**
* API URL of listing comments.
*/
public String getCommentsUrl() {
return comments_url;
}
public GHGistFile getFile(String name) {
return files.get(name);
}
public Map<String,GHGistFile> getFiles() {
return Collections.unmodifiableMap(files);
}
/*package*/ GHGist wrapUp(GHUser owner) {
this.owner = owner;
this.root = owner.root;
wrapUp();
return this;
}
/**
* Used when caller obtains {@link GHGist} without knowing its owner.
* A partially constructed owner object is interned.
*/
/*package*/ GHGist wrapUp(GitHub root) throws IOException {
this.owner = root.getUser(owner);
this.root = root;
wrapUp();
return this;
}
private void wrapUp() {
for (Entry<String, GHGistFile> e : files.entrySet()) {
e.getValue().fileName = e.getKey();
}
}
String getApiTailUrl(String tail) {
return "/gists/" + id + '/' + tail;
}
public void star() throws IOException {
new Requester(root).method("PUT").to(getApiTailUrl("star"));
}
public void unstar() throws IOException {
new Requester(root).method("DELETE").to(getApiTailUrl("star"));
}
public boolean isStarred() throws IOException {
return root.retrieve().asHttpStatusCode(getApiTailUrl("star"))/100==2;
}
/**
* Forks this gist into your own.
*/
public GHGist fork() throws IOException {
return new Requester(root).to(getApiTailUrl("forks"),GHGist.class).wrapUp(root);
}
public PagedIterable<GHGist> listForks() {
return new PagedIterable<GHGist>() {
public PagedIterator<GHGist> iterator() {
return new PagedIterator<GHGist>(root.retrieve().asIterator(getApiTailUrl("forks"), GHGist[].class)) {
@Override
protected void wrapUp(GHGist[] page) {
try {
for (GHGist c : page)
c.wrapUp(root);
} catch (IOException e) {
throw new Error(e);
}
}
};
}
};
}
/**
* Deletes this gist.
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").to("/gists/" + id);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GHGist ghGist = (GHGist) o;
return id.equals(ghGist.id);
}
@Override
public int hashCode() {
return id.hashCode();
}
}

View File

@@ -0,0 +1,48 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
/**
* Builder pattern for creating a new Gist.
*
* @author Kohsuke Kawaguchi
* @see GitHub#createGist()
*/
public class GHGistBuilder {
private final GitHub root;
private final Requester req;
private final LinkedHashMap<String,Object> files = new LinkedHashMap<String, Object>();
public GHGistBuilder(GitHub root) {
this.root = root;
req = new Requester(root);
}
public GHGistBuilder description(String desc) {
req.with("description",desc);
return this;
}
public GHGistBuilder public_(boolean v) {
req.with("public",v);
return this;
}
/**
* Adds a new file.
*/
public GHGistBuilder file(String fileName, String content) {
files.put(fileName, Collections.singletonMap("content", content));
return this;
}
/**
* Creates a Gist based on the parameters specified thus far.
*/
public GHGist create() throws IOException {
req._with("files",files);
return req.to("/gists",GHGist.class).wrapUp(root);
}
}

View File

@@ -0,0 +1,60 @@
package org.kohsuke.github;
/**
* A file inside {@link GHGist}
*
* @author Kohsuke Kawaguchi
* @see GHGist#getFile(String)
* @see GHGist#getFiles()
*/
public class GHGistFile {
/*package almost final*/ String fileName;
private int size;
private String raw_url, type, language, content;
private boolean truncated;
public String getFileName() {
return fileName;
}
/**
* File size in bytes.
*/
public int getSize() {
return size;
}
/**
* URL that serves this file as-is.
*/
public String getRawUrl() {
return raw_url;
}
/**
* Content type of this Gist, such as "text/plain"
*/
public String getType() {
return type;
}
public String getLanguage() {
return language;
}
/**
* Content of this file.
*/
public String getContent() {
return content;
}
/**
* (?) indicates if {@link #getContent()} contains a truncated content.
*/
public boolean isTruncated() {
return truncated;
}
}

View File

@@ -10,18 +10,17 @@ import java.util.Map;
/**
* @author Kohsuke Kawaguchi
*/
public final class GHHook {
public class GHHook extends GHObject {
/**
* Repository that the hook belongs to.
*/
/*package*/ transient GHRepository repository;
String created_at, updated_at, name;
String name;
List<String> events;
boolean active;
Map<String,String> config;
int id;
/*package*/ GHHook wrap(GHRepository owner) {
this.repository = owner;
return this;
@@ -46,10 +45,6 @@ public final class GHHook {
return Collections.unmodifiableMap(config);
}
public int getId() {
return id;
}
/**
* Deletes this hook.
*/

View File

@@ -37,8 +37,11 @@ import java.util.Locale;
*
* @author Eric Maupin
* @author Kohsuke Kawaguchi
* @see GHRepository#getIssue(int)
* @see GitHub#searchIssues()
* @see GHIssueSearchBuilder
*/
public class GHIssue {
public class GHIssue extends GHObject {
GitHub root;
GHRepository owner;
@@ -51,11 +54,9 @@ public class GHIssue {
protected String body;
protected List<Label> labels;
protected GHUser user;
protected String title, created_at, html_url;
protected String title, html_url;
protected GHIssue.PullRequest pull_request;
protected GHMilestone milestone;
protected String url, updated_at;
protected int id;
protected GHUser closed_by;
public static class Label {
@@ -78,8 +79,12 @@ public class GHIssue {
/*package*/ GHIssue wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
if(milestone != null) milestone.wrap(owner);
if(milestone != null) milestone.wrap(owner);
return wrap(owner.root);
}
/*package*/ GHIssue wrap(GitHub root) {
this.root = root;
if(assignee != null) assignee.wrapUp(root);
if(user != null) user.wrapUp(root);
if(closed_by != null) closed_by.wrapUp(root);
@@ -117,7 +122,7 @@ public class GHIssue {
* The HTML page of this issue,
* like https://github.com/jenkinsci/jenkins/issues/100
*/
public URL getUrl() {
public URL getHtmlUrl() {
return GitHub.parseURL(html_url);
}
@@ -129,21 +134,13 @@ public class GHIssue {
return Enum.valueOf(GHIssueState.class, state.toUpperCase(Locale.ENGLISH));
}
public Collection<Label> getLabels() {
public Collection<Label> getLabels() throws IOException {
if(labels == null){
return Collections.EMPTY_LIST;
}
return Collections.unmodifiableList(labels);
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public Date getUpdatedAt() {
return GitHub.parseDate(updated_at);
}
public Date getClosedAt() {
return GitHub.parseDate(closed_at);
}
@@ -163,6 +160,10 @@ public class GHIssue {
new Requester(root)._with(key, value).method("PATCH").to(getApiRoute());
}
private void editIssue(String key, Object value) throws IOException {
new Requester(root)._with(key, value).method("PATCH").to(getIssuesApiRoute());
}
/**
* Closes this issue.
*/
@@ -186,11 +187,11 @@ public class GHIssue {
}
public void assignTo(GHUser user) throws IOException {
edit("assignee",user.getLogin());
editIssue("assignee",user.getLogin());
}
public void setLabels(String... labels) throws IOException {
edit("labels",labels);
editIssue("labels",labels);
}
/**
@@ -222,7 +223,7 @@ public class GHIssue {
return getIssuesApiRoute();
}
private String getIssuesApiRoute() {
protected String getIssuesApiRoute() {
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/issues/"+number;
}

View File

@@ -32,12 +32,10 @@ import java.util.Date;
*
* @author Kohsuke Kawaguchi
*/
public class GHIssueComment {
public class GHIssueComment extends GHObject {
GHIssue owner;
private String body, gravatar_id, created_at, updated_at;
private URL url;
private int id;
private String body, gravatar_id;
private GHUser user;
/*package*/ GHIssueComment wrapUp(GHIssue owner) {
@@ -59,22 +57,6 @@ public class GHIssueComment {
return body;
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public Date getUpdatedAt() {
return GitHub.parseDate(updated_at);
}
public int getId() {
return id;
}
public URL getUrl() {
return url;
}
/**
* Gets the ID of the user who posted this comment.
*/

View File

@@ -0,0 +1,85 @@
package org.kohsuke.github;
import org.apache.commons.lang.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
* Search issues.
*
* @author Kohsuke Kawaguchi
* @see GitHub#searchIssues()
*/
public class GHIssueSearchBuilder {
private final GitHub root;
private final Requester req;
private final List<String> terms = new ArrayList<String>();
/*package*/ GHIssueSearchBuilder(GitHub root) {
this.root = root;
req = root.retrieve();
}
/**
* Search terms.
*/
public GHIssueSearchBuilder q(String term) {
terms.add(term);
return this;
}
public GHIssueSearchBuilder mentions(GHUser u) {
return mentions(u.getLogin());
}
public GHIssueSearchBuilder mentions(String login) {
return q("mentions:"+login);
}
public GHIssueSearchBuilder isOpen() {
return q("is:open");
}
public GHIssueSearchBuilder isClosed() {
return q("is:closed");
}
public GHIssueSearchBuilder isMerged() {
return q("is:merged");
}
public GHIssueSearchBuilder sort(Sort sort) {
req.with("sort",sort.toString().toLowerCase(Locale.ENGLISH));
return this;
}
public enum Sort { COMMENTS, CREATED, UPDATED }
private static class IssueSearchResult extends SearchResult<GHIssue> {
private GHIssue[] items;
@Override
public GHIssue[] getItems() {
return items;
}
}
/**
* Lists up the issues with the criteria built so far.
*/
public PagedSearchIterable<GHIssue> list() {
return new PagedSearchIterable<GHIssue>() {
public PagedIterator<GHIssue> iterator() {
req.set("q", StringUtils.join(terms," "));
return new PagedIterator<GHIssue>(adapt(req.asIterator("/search/issues", IssueSearchResult.class))) {
protected void wrapUp(GHIssue[] page) {
for (GHIssue c : page)
c.wrap(root);
}
};
}
};
}
}

View File

@@ -9,12 +9,12 @@ import java.util.Locale;
* @author Yusuke Kokubo
*
*/
public class GHMilestone {
public class GHMilestone extends GHObject {
GitHub root;
GHRepository owner;
GHUser creator;
private String state, due_on, title, url, created_at, description;
private String state, due_on, title, description;
private int closed_issues, open_issues, number;
public GitHub getRoot() {
@@ -38,14 +38,6 @@ public class GHMilestone {
return title;
}
public String getUrl() {
return url;
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public String getDescription() {
return description;
}

View File

@@ -101,11 +101,24 @@ public class GHMyself extends GHUser {
* Lists up all repositories this user owns (public and private).
*
* Unlike {@link #getAllRepositories()}, this does not wait until all the repositories are returned.
* Repositories are returned by GitHub API with a 30 items per page.
*/
public PagedIterable<GHRepository> listAllRepositories() {
@Override
public PagedIterable<GHRepository> listRepositories() {
return listRepositories(30);
}
/**
* Lists up all the repositories this user owns (public and private) using the specified page size.
*
* @param pageSize size for each page of items returned by GitHub. Maximum page size is 100.
*
* Unlike {@link #getRepositories()}, this does not wait until all the repositories are returned.
*/
public PagedIterable<GHRepository> listRepositories(final int pageSize) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> iterator() {
return new PagedIterator<GHRepository>(root.retrieve().asIterator("/user/repos", GHRepository[].class)) {
return new PagedIterator<GHRepository>(root.retrieve().asIterator("/user/repos?per_page=" + pageSize, GHRepository[].class)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
@@ -116,6 +129,14 @@ public class GHMyself extends GHUser {
};
}
/**
* @deprecated
* Use {@link #listRepositories()}
*/
public PagedIterable<GHRepository> listAllRepositories() {
return listRepositories();
}
// public void addEmails(Collection<String> emails) throws IOException {
//// new Requester(root,ApiVersion.V3).withCredential().to("/user/emails");
// root.retrieveWithAuth3()

View File

@@ -0,0 +1,63 @@
package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import java.io.IOException;
import java.net.URL;
import java.util.Date;
/**
* Most (all?) domain objects in GitHub seems to have these 4 properties.
*/
public abstract class GHObject {
protected String url;
protected int id;
protected String created_at;
protected String updated_at;
/*package*/ GHObject() {
}
/**
* When was this resource created?
*/
@WithBridgeMethods(value=String.class, adapterMethod="createdAtStr")
public Date getCreatedAt() throws IOException {
return GitHub.parseDate(created_at);
}
private Object createdAtStr(Date id, Class type) {
return created_at;
}
/**
* API URL of this object.
*/
@WithBridgeMethods(value=String.class, adapterMethod="urlToString")
public URL getUrl() {
return GitHub.parseURL(url);
}
/**
* When was this resource last updated?
*/
public Date getUpdatedAt() throws IOException {
return GitHub.parseDate(updated_at);
}
/**
* Unique ID number of this resource.
*/
@WithBridgeMethods(value=String.class, adapterMethod="intToString")
public int getId() {
return id;
}
private Object intToString(int id, Class type) {
return String.valueOf(id);
}
private Object urlToString(URL url, Class type) {
return url==null ? null : url.toString();
}
}

View File

@@ -4,6 +4,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -14,15 +15,14 @@ import java.util.TreeMap;
*
* @author Kohsuke Kawaguchi
*/
public abstract class GHPerson {
public abstract class GHPerson extends GHObject {
/*package almost final*/ GitHub root;
// core data fields that exist even for "small" user data (such as the user info in pull request)
protected String login, avatar_url, url, gravatar_id;
protected int id;
protected String login, avatar_url, gravatar_id;
// other fields (that only show up in full data)
protected String location,blog,email,name,created_at,company;
protected String location,blog,email,name,company;
protected String html_url;
protected int followers,following,public_repos,public_gists;
@@ -43,13 +43,16 @@ public abstract class GHPerson {
}
/**
* Gets the repositories this user owns.
* Gets the public repositories this user owns.
*
* <p>
* To list your own repositories, including private repositories,
* use {@link GHMyself#listRepositories()}
*/
public synchronized Map<String,GHRepository> getRepositories() throws IOException {
Map<String,GHRepository> repositories = new TreeMap<String, GHRepository>();
for (List<GHRepository> batch : iterateRepositories(100)) {
for (GHRepository r : batch)
repositories.put(r.getName(),r);
for (GHRepository r : listRepositories()) {
repositories.put(r.getName(),r);
}
return Collections.unmodifiableMap(repositories);
}
@@ -193,9 +196,14 @@ public abstract class GHPerson {
return location;
}
public String getCreatedAt() throws IOException {
public Date getCreatedAt() throws IOException {
populate();
return created_at;
return super.getCreatedAt();
}
public Date getUpdatedAt() throws IOException {
populate();
return super.getCreatedAt();
}
/**
@@ -206,6 +214,10 @@ public abstract class GHPerson {
return blog;
}
public String getHtmlUrl() {
return html_url;
}
/**
* Gets the e-mail address of the user.
*/
@@ -229,13 +241,6 @@ public abstract class GHPerson {
return following;
}
/**
* What appears to be a GitHub internal unique number that identifies this user.
*/
public int getId() {
return id;
}
public int getFollowersCount() throws IOException {
populate();
return followers;

View File

@@ -9,7 +9,7 @@ import java.util.HashSet;
*
* @author Kohsuke Kawaguchi
*/
public final class GHPersonSet<T extends GHPerson> extends HashSet<T> {
public class GHPersonSet<T extends GHPerson> extends HashSet<T> {
public GHPersonSet() {
}

View File

@@ -52,6 +52,13 @@ public class GHPullRequest extends GHIssue {
private String mergeable_state;
private int changed_files;
/**
* GitHub doesn't return some properties of {@link GHIssue} when requesting the GET on the 'pulls' API
* route as opposed to 'issues' API route. This flag remembers whether we made the GET call on the 'issues' route
* on this object to fill in those missing details
*/
private transient boolean fetchedIssueDetails;
GHPullRequest wrapUp(GHRepository owner) {
this.wrap(owner);
@@ -103,7 +110,7 @@ public class GHPullRequest extends GHIssue {
}
@Deprecated
public Date getIssueUpdatedAt() {
public Date getIssueUpdatedAt() throws IOException {
return super.getUpdatedAt();
}
@@ -120,11 +127,12 @@ public class GHPullRequest extends GHIssue {
}
@Override
public Collection<Label> getLabels() {
public Collection<Label> getLabels() throws IOException {
fetchIssue();
return super.getLabels();
}
@Override
@Override
public GHUser getClosedBy() {
return null;
}
@@ -196,7 +204,7 @@ public class GHPullRequest extends GHIssue {
return new PagedIterable<GHPullRequestCommitDetail>() {
public PagedIterator<GHPullRequestCommitDetail> iterator() {
return new PagedIterator<GHPullRequestCommitDetail>(root.retrieve().asIterator(
String.format("%s/commits", getApiURL().getPath()),
String.format("%s/commits", getApiURL()),
GHPullRequestCommitDetail[].class)) {
@Override
protected void wrapUp(GHPullRequestCommitDetail[] page) {
@@ -218,4 +226,10 @@ public class GHPullRequest extends GHIssue {
new Requester(root).method("PUT").with("commit_message",msg).to(getApiRoute()+"/merge");
}
private void fetchIssue() throws IOException {
if (!fetchedIssueDetails) {
new Requester(root).to(getIssuesApiRoute(), this);
fetchedIssueDetails = true;
}
}
}

View File

@@ -1,5 +1,6 @@
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
/**
@@ -8,6 +9,7 @@ import java.net.URL;
* @author Michael Clarke
*/
public class GHRef {
/*package almost final*/ GitHub root;
private String ref, url;
private GHObject object;
@@ -33,6 +35,48 @@ public class GHRef {
return object;
}
/**
* Updates this ref to the specified commit.
*
* @param sha
* The SHA1 value to set this reference to
*/
public void updateTo(String sha) throws IOException {
updateTo(sha, false);
}
/**
* Updates this ref to the specified commit.
*
* @param sha
* The SHA1 value to set this reference to
* @param force
* Whether or not to force this ref update.
*/
public void updateTo(String sha, Boolean force) throws IOException {
new Requester(root)
.with("sha", sha).with("force", force).method("PATCH").to(url, GHRef.class).wrap(root);
}
/**
* Deletes this ref from the repository using the GitHub API.
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").to(url);
}
/*package*/ GHRef wrap(GitHub root) {
this.root = root;
return this;
}
/*package*/ static GHRef[] wrap(GHRef[] in, GitHub root) {
for (GHRef r : in) {
r.wrap(root);
}
return in;
}
public static class GHObject {
private String type, sha, url;

View File

@@ -15,22 +15,19 @@ import static java.lang.String.format;
* @see GHRepository#getReleases()
* @see GHRepository#createRelease(String)
*/
public class GHRelease {
public class GHRelease extends GHObject {
GitHub root;
GHRepository owner;
private String url;
private String html_url;
private String assets_url;
private String upload_url;
private long id;
private String tag_name;
private String target_commitish;
private String name;
private String body;
private boolean draft;
private boolean prerelease;
private Date created_at;
private Date published_at;
private String tarball_url;
private String zipball_url;
@@ -39,50 +36,18 @@ public class GHRelease {
return assets_url;
}
public void setAssetsUrl(String assets_url) {
this.assets_url = assets_url;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public Date getCreatedAt() {
return created_at;
}
public void setCreatedAt(Date created_at) {
this.created_at = created_at;
}
public boolean isDraft() {
return draft;
}
public void setDraft(boolean draft) {
this.draft = draft;
}
public String getHtmlUrl() {
return html_url;
}
public void setHtmlUrl(String html_url) {
this.html_url = html_url;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
@@ -103,74 +68,34 @@ public class GHRelease {
return prerelease;
}
public void setPrerelease(boolean prerelease) {
this.prerelease = prerelease;
}
public Date getPublished_at() {
return published_at;
}
public void setPublished_at(Date published_at) {
this.published_at = published_at;
}
public GitHub getRoot() {
return root;
}
public void setRoot(GitHub root) {
this.root = root;
}
public String getTagName() {
return tag_name;
}
public void setTagName(String tag_name) {
this.tag_name = tag_name;
}
public String getTargetCommitish() {
return target_commitish;
}
public void setTargetCommitish(String target_commitish) {
this.target_commitish = target_commitish;
}
public String getUploadUrl() {
return upload_url;
}
public void setUploadUrl(String upload_url) {
this.upload_url = upload_url;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getZipballUrl() {
return zipball_url;
}
public void setZipballUrl(String zipballUrl) {
this.zipball_url = zipballUrl;
}
public String getTarballUrl() {
return tarball_url;
}
public void setTarballUrl(String tarballUrl) {
this.tarball_url = tarballUrl;
}
GHRelease wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
@@ -207,7 +132,18 @@ public class GHRelease {
GHAsset[] assets = builder
.method("GET")
.to(owner.getApiTailUrl(format("releases/%d/assets", id)), GHAsset[].class);
.to(getApiTailUrl("assets"), GHAsset[].class);
return Arrays.asList(GHAsset.wrap(assets, this));
}
/**
* Deletes this release.
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").to(owner.getApiTailUrl("releases/"+id));
}
private String getApiTailUrl(String end) {
return owner.getApiTailUrl(format("releases/%s/%s",id,end));
}
}

View File

@@ -25,27 +25,16 @@ package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import org.apache.commons.lang.StringUtils;
import javax.xml.bind.DatatypeConverter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.URL;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.*;
import static java.util.Arrays.*;
import static java.util.Arrays.asList;
/**
* A repository on GitHub.
@@ -53,18 +42,18 @@ import static java.util.Arrays.*;
* @author Kohsuke Kawaguchi
*/
@SuppressWarnings({"UnusedDeclaration"})
public class GHRepository {
public class GHRepository extends GHObject {
/*package almost final*/ GitHub root;
private String description, homepage, name;
private String url; // this is the API url
private String description, homepage, name, full_name;
private String html_url; // this is the UI
private String git_url, ssh_url, clone_url, svn_url;
private GHUser owner; // not fully populated. beware.
private boolean has_issues, has_wiki, fork, has_downloads;
@JsonProperty("private")
private boolean _private;
private int watchers,forks,open_issues,size,network_count,subscribers_count;
private String created_at, pushed_at;
private String pushed_at;
private Map<Integer,GHMilestone> milestones = new HashMap<Integer, GHMilestone>();
private String default_branch,language;
@@ -72,6 +61,59 @@ public class GHRepository {
private GHRepoPermission permissions;
public GHDeploymentBuilder createDeployment(String ref) {
return new GHDeploymentBuilder(this,ref);
}
public PagedIterable<GHDeploymentStatus> getDeploymentStatuses(final int id) {
return new PagedIterable<GHDeploymentStatus>() {
public PagedIterator<GHDeploymentStatus> iterator() {
return new PagedIterator<GHDeploymentStatus>(root.retrieve().asIterator(getApiTailUrl("deployments")+"/"+id+"/statuses", GHDeploymentStatus[].class)) {
@Override
protected void wrapUp(GHDeploymentStatus[] page) {
for (GHDeploymentStatus c : page)
c.wrap(GHRepository.this);
}
};
}
};
}
public PagedIterable<GHDeployment> listDeployments(String sha,String ref,String task,String environment){
List<String> params = Arrays.asList(getParam("sha", sha), getParam("ref", ref), getParam("task", task), getParam("environment", environment));
final String deploymentsUrl = getApiTailUrl("deployments") + "?"+ join(params,"&");
return new PagedIterable<GHDeployment>() {
public PagedIterator<GHDeployment> iterator() {
return new PagedIterator<GHDeployment>(root.retrieve().asIterator(deploymentsUrl, GHDeployment[].class)) {
@Override
protected void wrapUp(GHDeployment[] page) {
for (GHDeployment c : page)
c.wrap(GHRepository.this);
}
};
}
};
}
private String join(List<String> params, String joinStr) {
StringBuilder output = new StringBuilder();
for(String param: params){
if(param != null){
output.append(param+joinStr);
}
}
return output.toString();
}
private String getParam(String name, String value) {
return StringUtils.trimToNull(value)== null? null: name+"="+value;
}
public GHDeploymentStatusBuilder createDeployStatus(int deploymentId, GHDeploymentState ghDeploymentState) {
return new GHDeploymentStatusBuilder(this,deploymentId,ghDeploymentState);
}
private static class GHRepoPermission {
boolean pull,push,admin;
}
@@ -85,19 +127,12 @@ public class GHRepository {
return homepage;
}
/**
* URL of this repository, like 'http://github.com/kohsuke/jenkins'
*/
public String getUrl() {
return html_url;
}
/**
* Gets the git:// URL to this repository, such as "git://github.com/kohsuke/jenkins.git"
* This URL is read-only.
*/
public String getGitTransportUrl() {
return "git://github.com/"+getOwnerName()+"/"+name+".git";
return git_url;
}
/**
@@ -105,7 +140,21 @@ public class GHRepository {
* This URL is read-only.
*/
public String gitHttpTransportUrl() {
return "https://github.com/"+getOwnerName()+"/"+name+".git";
return clone_url;
}
/**
* Gets the Subversion URL to access this repository: https://github.com/rails/rails
*/
public String getSvnUrl() {
return svn_url;
}
/**
* Gets the SSH URL to access this repository, such as git@github.com:rails/rails.git
*/
public String getSshUrl() {
return ssh_url;
}
/**
@@ -115,6 +164,13 @@ public class GHRepository {
return name;
}
/**
* Full repository name including the owner or organization. For example 'jenkinsci/jenkins' in case of http://github.com/jenkinsci/jenkins
*/
public String getFullName() {
return full_name;
}
public boolean hasPullAccess() {
return permissions!=null && permissions.pull;
}
@@ -153,7 +209,7 @@ public class GHRepository {
public List<GHIssue> getIssues(GHIssueState state, GHMilestone milestone) throws IOException {
return Arrays.asList(GHIssue.wrap(root.retrieve()
.to(String.format("/repos/%s/%s/issues?state=%s&milestone=%s", owner.login, name,
state.toString().toLowerCase(), milestone == null ? "none" : "" + milestone.getNumber()),
state.toString().toLowerCase(), milestone == null ? "none" : "" + milestone.getNumber()),
GHIssue[].class
), this));
}
@@ -179,9 +235,54 @@ public class GHRepository {
return new GHReleaseBuilder(this,tag);
}
/**
* Creates a named ref, such as tag, branch, etc.
*
* @param name
* The name of the fully qualified reference (ie: refs/heads/master).
* If it doesn't start with 'refs' and have at least two slashes, it will be rejected.
* @param sha
* The SHA1 value to set this reference to
*/
public GHRef createRef(String name, String sha) throws IOException {
return new Requester(root)
.with("ref", name).with("sha", sha).method("POST").to(getApiTailUrl("git/refs"), GHRef.class).wrap(root);
}
/**
* @deprecated
* use {@link #listReleases()}
*/
public List<GHRelease> getReleases() throws IOException {
return Arrays.asList(GHRelease.wrap(root.retrieve().to("/repos/" + owner.login + "/" + name + "/releases",
GHRelease[].class), this));
return listReleases().asList();
}
public PagedIterable<GHRelease> listReleases() throws IOException {
return new PagedIterable<GHRelease>() {
public PagedIterator<GHRelease> iterator() {
return new PagedIterator<GHRelease>(root.retrieve().asIterator(getApiTailUrl("releases"), GHRelease[].class)) {
@Override
protected void wrapUp(GHRelease[] page) {
for (GHRelease c : page)
c.wrap(GHRepository.this);
}
};
}
};
}
public PagedIterable<GHTag> listTags() throws IOException {
return new PagedIterable<GHTag>() {
public PagedIterator<GHTag> iterator() {
return new PagedIterator<GHTag>(root.retrieve().asIterator(getApiTailUrl("tags"), GHTag[].class)) {
@Override
protected void wrapUp(GHTag[] page) {
for (GHTag c : page)
c.wrap(GHRepository.this);
}
};
}
};
}
protected String getOwnerName() {
@@ -237,10 +338,6 @@ public class GHRepository {
return GitHub.parseDate(pushed_at);
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
/**
* Returns the primary branch you'll configure in the "Admin > Options" config page.
*
@@ -261,7 +358,32 @@ public class GHRepository {
*/
@WithBridgeMethods(Set.class)
public GHPersonSet<GHUser> getCollaborators() throws IOException {
return new GHPersonSet<GHUser>(GHUser.wrap(root.retrieve().to("/repos/" + owner.login + "/" + name + "/collaborators", GHUser[].class),root));
return new GHPersonSet<GHUser>(listCollaborators().asList());
}
/**
* Lists up the collaborators on this repository.
*
* @return Users
* @throws IOException
*/
public PagedIterable<GHUser> listCollaborators() throws IOException {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> iterator() {
return new PagedIterator<GHUser>(root.retrieve().asIterator("/repos/" + owner.login + "/" + name + "/collaborators", GHUser[].class)) {
@Override
protected void wrapUp(GHUser[] users) {
for (GHUser user : users) {
user.wrapUp(root);
}
}
};
}
};
}
/**
@@ -356,7 +478,11 @@ public class GHRepository {
* Deletes this repository.
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").to("/repos/" + owner.login + "/" + name);
try {
new Requester(root).method("DELETE").to("/repos/" + owner.login + "/" + name);
} catch (FileNotFoundException x) {
throw (FileNotFoundException) new FileNotFoundException("Failed to delete " + owner.login + "/" + name + "; might not exist, or you might need the delete_repo scope in your token: http://stackoverflow.com/a/19327004/12916").initCause(x);
}
}
/**
@@ -417,13 +543,36 @@ public class GHRepository {
@Override
protected void wrapUp(GHPullRequest[] page) {
for (GHPullRequest pr : page)
pr.wrap(GHRepository.this);
pr.wrapUp(GHRepository.this);
}
};
}
};
}
/**
* Creates a new pull request.
*
* @param title
* Required. The title of the pull request.
* @param head
* Required. The name of the branch where your changes are implemented.
* For cross-repository pull requests in the same network,
* namespace head with a user like this: username:branch.
* @param base
* Required. The name of the branch you want your changes pulled into.
* This should be an existing branch on the current repository.
* @param body
* The contents of the pull request. This is the markdown description
* of a pull request.
*/
public GHPullRequest createPullRequest(String title, String head, String base, String body) throws IOException {
return new Requester(root).with("title",title)
.with("head",head)
.with("base",base)
.with("body",body).to(getApiTailUrl("pulls"),GHPullRequest.class).wrapUp(this);
}
/**
* Retrieves the currently configured hooks.
*/
@@ -453,7 +602,7 @@ public class GHRepository {
}
public GHCompare getCompare(GHCommit id1, GHCommit id2) throws IOException {
return getCompare(id1.getSHA1(),id2.getSHA1());
return getCompare(id1.getSHA1(), id2.getSHA1());
}
public GHCompare getCompare(GHBranch id1, GHBranch id2) throws IOException {
@@ -466,19 +615,31 @@ public class GHRepository {
* @throws IOException on failure communicating with GitHub
*/
public GHRef[] getRefs() throws IOException {
return root.retrieve().to(String.format("/repos/%s/%s/git/refs", owner.login, name), GHRef[].class);
return GHRef.wrap(root.retrieve().to(String.format("/repos/%s/%s/git/refs", owner.login, name), GHRef[].class),root);
}
/**
* Retrienved all refs of the given type for the current GitHub repository.
* Retrieves all refs of the given type for the current GitHub repository.
* @param refType the type of reg to search for e.g. <tt>tags</tt> or <tt>commits</tt>
* @return an array of all refs matching the request type
* @throws IOException on failure communicating with GitHub, potentially due to an invalid ref type being requested
*/
public GHRef[] getRefs(String refType) throws IOException {
return root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", owner.login, name, refType), GHRef[].class);
return GHRef.wrap(root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", owner.login, name, refType), GHRef[].class),root);
}
/**
* Retrive a ref of the given type for the current GitHub repository.
*
* @param refName
* eg: heads/branch
* @return refs matching the request type
* @throws IOException
* on failure communicating with GitHub, potentially due to an
* invalid ref type being requested
*/
public GHRef getRef(String refName) throws IOException {
return root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", owner.login, name, refName), GHRef.class).wrap(root);
}
/**
* Gets a commit object in this repository.
*/
@@ -563,14 +724,24 @@ public class GHRepository {
* Optional parameter that points to the URL that has more details.
* @param description
* Optional short description.
* @param context
* Optinal commit status context.
*/
public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description) throws IOException {
public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description, String context) throws IOException {
return new Requester(root)
.with("state", state.name().toLowerCase(Locale.ENGLISH))
.with("target_url", targetUrl)
.with("description", description)
.with("context", context)
.to(String.format("/repos/%s/%s/statuses/%s",owner.login,this.name,sha1),GHCommitStatus.class).wrapUp(root);
}
/**
* @see {@link #createCommitStatus(String, GHCommitState,String,String,String) createCommitStatus}
*/
public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description) throws IOException {
return createCommitStatus(sha1, state, targetUrl, description,null);
}
/**
* Lists repository events.
@@ -798,14 +969,22 @@ public class GHRepository {
}
public GHContentUpdateResponse createContent(String content, String commitMessage, String path) throws IOException {
return createContent(content, commitMessage, path, null);
return createContent(content.getBytes(), commitMessage, path, null);
}
public GHContentUpdateResponse createContent(String content, String commitMessage, String path, String branch) throws IOException {
return createContent(content.getBytes(), commitMessage, path, branch);
}
public GHContentUpdateResponse createContent(byte[] contentBytes, String commitMessage, String path) throws IOException {
return createContent(contentBytes, commitMessage, path, null);
}
public GHContentUpdateResponse createContent(byte[] contentBytes, String commitMessage, String path, String branch) throws IOException {
Requester requester = new Requester(root)
.with("path", path)
.with("message", commitMessage)
.with("content", DatatypeConverter.printBase64Binary(content.getBytes()))
.with("content", DatatypeConverter.printBase64Binary(contentBytes))
.method("PUT");
if (branch != null) {
@@ -824,6 +1003,22 @@ public class GHRepository {
return new Requester(root)
.with("title", title).with("description", description).method("POST").to(getApiTailUrl("milestones"), GHMilestone.class).wrap(this);
}
public GHDeployKey addDeployKey(String title,String key) throws IOException {
return new Requester(root)
.with("title", title).with("key", key).method("POST").to(getApiTailUrl("keys"), GHDeployKey.class).wrap(this);
}
public List<GHDeployKey> getDeployKeys() throws IOException{
List<GHDeployKey> list = new ArrayList<GHDeployKey>(Arrays.asList(
root.retrieve().to(String.format("/repos/%s/%s/keys", owner.login, name), GHDeployKey[].class)));
for (GHDeployKey h : list)
h.wrap(this);
return list;
}
@Override
public String toString() {

View File

@@ -0,0 +1,36 @@
package org.kohsuke.github;
/**
* Represents a tag in {@link GHRepository}
*
* @see GHRepository#listTags()
*/
public class GHTag {
private GHRepository owner;
private GitHub root;
private String name;
private GHCommit commit;
/*package*/ GHTag wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
return this;
}
public GHRepository getOwner() {
return owner;
}
public GitHub getRoot() {
return root;
}
public String getName() {
return name;
}
public GHCommit getCommit() {
return commit;
}
}

View File

@@ -1,8 +1,7 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
@@ -15,6 +14,7 @@ import java.util.TreeMap;
public class GHTeam {
private String name,permission;
private int id;
private GHOrganization organization; // populated by GET /user/teams where Teams+Orgs are returned together
protected /*final*/ GHOrganization org;
@@ -23,6 +23,11 @@ public class GHTeam {
return this;
}
/*package*/ GHTeam wrapUp(GitHub root) { // auto-wrapUp when organization is known from GET /user/teams
this.organization.wrapUp(root);
return wrapUp(organization);
}
/*package*/ static GHTeam[] wrapUp(GHTeam[] teams, GHOrganization owner) {
for (GHTeam t : teams) {
t.wrapUp(owner);
@@ -42,13 +47,26 @@ public class GHTeam {
return id;
}
/**
* Retrieves the current members.
*/
public Set<GHUser> getMembers() throws IOException {
return new HashSet<GHUser>(Arrays.asList(GHUser.wrap(org.root.retrieve().to(api("/members"), GHUser[].class), org.root)));
/**
* Retrieves the current members.
*/
public PagedIterable<GHUser> listMembers() throws IOException {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> iterator() {
return new PagedIterator<GHUser>(org.root.retrieve().asIterator(api("/members"), GHUser[].class)) {
@Override
protected void wrapUp(GHUser[] page) {
GHUser.wrap(page, org.root);
}
};
}
};
}
public Set<GHUser> getMembers() throws IOException {
return Collections.unmodifiableSet(listMembers().asSet());
}
/**
* Checks if this team has the specified user as a member.
*/
@@ -62,19 +80,36 @@ public class GHTeam {
}
public Map<String,GHRepository> getRepositories() throws IOException {
GHRepository[] repos = org.root.retrieve().to(api("/repos"), GHRepository[].class);
Map<String,GHRepository> m = new TreeMap<String, GHRepository>();
for (GHRepository r : repos) {
m.put(r.getName(),r.wrap(org.root));
for (GHRepository r : listRepositories()) {
m.put(r.getName(), r);
}
return m;
}
public PagedIterable<GHRepository> listRepositories() {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> iterator() {
return new PagedIterator<GHRepository>(org.root.retrieve().asIterator(api("/repos"), GHRepository[].class)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository r : page)
r.wrap(org.root);
}
};
}
};
}
/**
* Adds a member to the team.
*
* The user will be invited to the organization if required.
*
* @since 1.59
*/
public void add(GHUser u) throws IOException {
org.root.retrieve().method("PUT").to(api("/members/" + u.getLogin()), null);
org.root.retrieve().method("PUT").to(api("/memberships/" + u.getLogin()), null);
}
/**
@@ -95,4 +130,8 @@ public class GHTeam {
private String api(String tail) {
return "/teams/"+id+tail;
}
public GHOrganization getOrganization() {
return org;
}
}

View File

@@ -127,6 +127,23 @@ public class GHUser extends GHPerson {
};
}
/**
* Lists Gists created by this user.
*/
public PagedIterable<GHGist> listGists() throws IOException {
return new PagedIterable<GHGist>() {
public PagedIterator<GHGist> iterator() {
return new PagedIterator<GHGist>(root.retrieve().asIterator(String.format("/users/%s/gists", login), GHGist[].class)) {
@Override
protected void wrapUp(GHGist[] page) {
for (GHGist c : page)
c.wrapUp(GHUser.this);
}
};
}
};
}
@Override
public String toString() {
return "User:"+login;

View File

@@ -23,10 +23,10 @@
*/
package org.kohsuke.github;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.*;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Reader;
import java.net.MalformedURLException;
@@ -37,13 +37,13 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TimeZone;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -70,13 +70,6 @@ public class GitHub {
private HttpConnector connector = HttpConnector.DEFAULT;
/**
* Connects to GitHub.com
*/
private GitHub(String login, String oauthAccessToken, String password) throws IOException {
this (GITHUB_URL, login, oauthAccessToken, password);
}
/**
* Creates a client API root object.
*
@@ -110,10 +103,13 @@ public class GitHub {
* Secret OAuth token.
* @param password
* User's password. Always used in conjunction with the {@code login} parameter
* @param connector
* HttpConnector to use. Pass null to use default connector.
*/
private GitHub(String apiUrl, String login, String oauthAccessToken, String password) throws IOException {
/* package */ GitHub(String apiUrl, String login, String oauthAccessToken, String password, HttpConnector connector) throws IOException {
if (apiUrl.endsWith("/")) apiUrl = apiUrl.substring(0, apiUrl.length()-1); // normalize
this.apiUrl = apiUrl;
if (null != connector) this.connector = connector;
if (oauthAccessToken!=null) {
encodedAuthorization = "token "+oauthAccessToken;
@@ -132,18 +128,10 @@ public class GitHub {
}
/**
* Obtains the credential from "~/.github"
* Obtains the credential from "~/.github" or from the System Environment Properties.
*/
public static GitHub connect() throws IOException {
Properties props = new Properties();
File homeDir = new File(System.getProperty("user.home"));
FileInputStream in = new FileInputStream(new File(homeDir, ".github"));
try {
props.load(in);
} finally {
IOUtils.closeQuietly(in);
}
return new GitHub(GITHUB_URL,props.getProperty("login"), props.getProperty("oauth"),props.getProperty("password"));
return GitHubBuilder.fromCredentials().build();
}
/**
@@ -155,15 +143,15 @@ public class GitHub {
* 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 connectUsingOAuth(apiUrl, oauthAccessToken);
return new GitHubBuilder().withEndpoint(apiUrl).withOAuthToken(oauthAccessToken).build();
}
public static GitHub connectToEnterprise(String apiUrl, String login, String password) throws IOException {
return new GitHub(apiUrl, login, null, password);
return new GitHubBuilder().withEndpoint(apiUrl).withPassword(login, password).build();
}
public static GitHub connect(String login, String oauthAccessToken) throws IOException {
return new GitHub(login,oauthAccessToken,null);
return new GitHubBuilder().withOAuthToken(oauthAccessToken, login).build();
}
/**
@@ -172,19 +160,19 @@ public class GitHub {
* Use {@link #connectUsingPassword(String, String)} or {@link #connectUsingOAuth(String)}.
*/
public static GitHub connect(String login, String oauthAccessToken, String password) throws IOException {
return new GitHub(login,oauthAccessToken,password);
return new GitHubBuilder().withOAuthToken(oauthAccessToken, login).withPassword(login, password).build();
}
public static GitHub connectUsingPassword(String login, String password) throws IOException {
return new GitHub(login,null,password);
return new GitHubBuilder().withPassword(login, password).build();
}
public static GitHub connectUsingOAuth(String oauthAccessToken) throws IOException {
return new GitHub(null, oauthAccessToken, null);
return new GitHubBuilder().withOAuthToken(oauthAccessToken).build();
}
public static GitHub connectUsingOAuth(String githubServer, String oauthAccessToken) throws IOException {
return new GitHub(githubServer,null, oauthAccessToken,null);
return new GitHubBuilder().withEndpoint(githubServer).withOAuthToken(oauthAccessToken).build();
}
/**
* Connects to GitHub anonymously.
@@ -192,7 +180,7 @@ public class GitHub {
* All operations that requires authentication will fail.
*/
public static GitHub connectAnonymously() throws IOException {
return new GitHub(null,null,null);
return new GitHubBuilder().build();
}
/**
@@ -239,7 +227,16 @@ public class GitHub {
* Gets the current rate limit.
*/
public GHRateLimit getRateLimit() throws IOException {
return retrieve().to("/rate_limit", JsonRateLimit.class).rate;
try {
return retrieve().to("/rate_limit", JsonRateLimit.class).rate;
} catch (FileNotFoundException e) {
// GitHub Enterprise doesn't have the rate limit, so in that case
// return some big number that's not too big.
// see issue #78
GHRateLimit r = new GHRateLimit();
r.limit = r.remaining = 1000000;
return r;
}
}
/**
@@ -270,6 +267,15 @@ public class GitHub {
return u;
}
/**
* clears all cached data in order for external changes (modifications and del
*/
public void refreshCache() {
users.clear();
orgs.clear();
}
/**
* Interns the given {@link GHUser}.
*/
@@ -318,17 +324,49 @@ public class GitHub {
return r;
}
/**
* Gets complete map of organizations/teams that current user belongs to.
*
* Leverages the new GitHub API /user/teams made available recently to
* get in a single call the complete set of organizations, teams and permissions
* in a single call.
*/
public Map<String, Set<GHTeam>> getMyTeams() throws IOException {
Map<String, Set<GHTeam>> allMyTeams = new HashMap<String, Set<GHTeam>>();
for (GHTeam team : retrieve().to("/user/teams", GHTeam[].class)) {
team.wrapUp(this);
String orgLogin = team.getOrganization().getLogin();
Set<GHTeam> teamsPerOrg = allMyTeams.get(orgLogin);
if (teamsPerOrg == null) {
teamsPerOrg = new HashSet<GHTeam>();
}
teamsPerOrg.add(team);
allMyTeams.put(orgLogin, teamsPerOrg);
}
return allMyTeams;
}
/**
* Public events visible to you. Equivalent of what's displayed on https://github.com/
*/
public List<GHEventInfo> getEvents() throws IOException {
// TODO: pagination
GHEventInfo[] events = retrieve().to("/events", GHEventInfo[].class);
for (GHEventInfo e : events)
e.wrapUp(this);
return Arrays.asList(events);
}
/**
* Gets a sigle gist by ID.
*/
public GHGist getGist(String id) throws IOException {
return retrieve().to("/gists/"+id,GHGist.class).wrapUp(this);
}
public GHGistBuilder createGist() {
return new GHGistBuilder(this);
}
/**
* Parses the GitHub event object.
*
@@ -345,6 +383,9 @@ public class GitHub {
/**
* Creates a new repository.
*
* To create a repository in an organization, see
* {@link GHOrganization#createRepository(String, String, String, GHTeam, boolean)}
*
* @return
* Newly created repository.
*/
@@ -383,6 +424,14 @@ public class GitHub {
}
}
/**
* Search issues.
*/
public GHIssueSearchBuilder searchIssues() {
return new GHIssueSearchBuilder(this);
}
/*package*/ static URL parseURL(String s) {
try {
return s==null ? null : new URL(s);
@@ -418,5 +467,5 @@ public class GitHub {
MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
private static final String GITHUB_URL = "https://api.github.com";
/* package */ static final String GITHUB_URL = "https://api.github.com";
}

View File

@@ -0,0 +1,159 @@
package org.kohsuke.github;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
/**
* @since 1.59
*/
public class GitHubBuilder {
private String endpoint = GitHub.GITHUB_URL;
// default scoped so unit tests can read them.
/* private */ String user;
/* private */ String password;
/* private */ String oauthToken;
private HttpConnector connector;
public GitHubBuilder() {
}
/**
* First check if the credentials are configured using the ~/.github properties file.
*
* If no user is specified it means there is no configuration present so check the environment instead.
*
* If there is still no user it means there are no credentials defined and throw an IOException.
*
* @return the configured Builder from credentials defined on the system or in the environment.
*
* @throws IOException If there are no credentials defined in the ~/.github properties file or the process environment.
*/
public static GitHubBuilder fromCredentials() throws IOException {
GitHubBuilder builder;
try {
builder = fromPropertyFile();
if (builder.user != null)
return builder;
else {
// this is the case where the ~/.github file exists but has no content.
builder = fromEnvironment();
if (builder.user != null)
return builder;
else
throw new IOException("Failed to resolve credentials from ~/.github or the environment.");
}
} catch (FileNotFoundException e) {
builder = fromEnvironment();
if (builder.user != null)
return builder;
else
throw new IOException("Failed to resolve credentials from ~/.github or the environment.", e);
}
}
public static GitHubBuilder fromEnvironment(String loginVariableName, String passwordVariableName, String oauthVariableName) throws IOException {
Properties env = new Properties();
Object loginValue = System.getenv(loginVariableName);
if (loginValue != null)
env.put("login", loginValue);
Object passwordValue = System.getenv(passwordVariableName);
if (passwordValue != null)
env.put("password", passwordValue);
Object oauthValue = System.getenv(oauthVariableName);
if (oauthValue != null)
env.put("oauth", oauthValue);
return fromProperties(env);
}
public static GitHubBuilder fromEnvironment() throws IOException {
Properties props = new Properties();
Map<String, String> env = System.getenv();
for (Map.Entry<String, String> element : env.entrySet()) {
props.put(element.getKey(), element.getValue());
}
return fromProperties(props);
}
public static GitHubBuilder fromPropertyFile() throws IOException {
File homeDir = new File(System.getProperty("user.home"));
File propertyFile = new File(homeDir, ".github");
return fromPropertyFile(propertyFile.getPath());
}
public static GitHubBuilder fromPropertyFile(String propertyFileName) throws IOException {
Properties props = new Properties();
FileInputStream in = null;
try {
in = new FileInputStream(propertyFileName);
props.load(in);
} finally {
IOUtils.closeQuietly(in);
}
return fromProperties(props);
}
public static GitHubBuilder fromProperties(Properties props) {
GitHubBuilder self = new GitHubBuilder();
self.withOAuthToken(props.getProperty("oauth"), props.getProperty("login"));
self.withPassword(props.getProperty("login"), props.getProperty("password"));
return self;
}
public GitHubBuilder withEndpoint(String endpoint) {
this.endpoint = endpoint;
return this;
}
public GitHubBuilder withPassword(String user, String password) {
this.user = user;
this.password = password;
return this;
}
public GitHubBuilder withOAuthToken(String oauthToken) {
return withOAuthToken(oauthToken, null);
}
public GitHubBuilder withOAuthToken(String oauthToken, String user) {
this.oauthToken = oauthToken;
this.user = user;
return this;
}
public GitHubBuilder withConnector(HttpConnector connector) {
this.connector = connector;
return this;
}
public GitHub build() throws IOException {
return new GitHub(endpoint, user, oauthToken, password, connector);
}
}

View File

@@ -1,7 +1,9 @@
package org.kohsuke.github;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
/**
* {@link Iterable} that returns {@link PagedIterator}
@@ -21,4 +23,15 @@ public abstract class PagedIterable<T> implements Iterable<T> {
}
return r;
}
/**
* Eagerly walk {@link Iterable} and return the result in a set.
*/
public Set<T> asSet() {
LinkedHashSet<T> r = new LinkedHashSet<T>();
for(PagedIterator<T> i = iterator(); i.hasNext();) {
r.addAll(i.nextPage());
}
return r;
}
}

View File

@@ -0,0 +1,54 @@
package org.kohsuke.github;
import java.util.Iterator;
/**
* {@link PagedIterable} enhanced to report search result specific information.
*
* @author Kohsuke Kawaguchi
*/
public abstract class PagedSearchIterable<T> extends PagedIterable<T> {
/**
* As soon as we have any result fetched, it's set here so that we can report the total count.
*/
private SearchResult<T> result;
/**
* Returns the total number of hit, including the results that's not yet fetched.
*/
public int getTotalCount() {
populate();
return result.total_count;
}
public boolean isIncomplete() {
populate();
return result.incomplete_results;
}
private void populate() {
if (result==null)
iterator().hasNext();
}
/**
* Adapts {@link Iterator}.
*/
protected Iterator<T[]> adapt(final Iterator<? extends SearchResult<T>> base) {
return new Iterator<T[]>() {
public boolean hasNext() {
return base.hasNext();
}
public T[] next() {
SearchResult<T> v = base.next();
if (result==null) result = v;
return v.getItems();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}

View File

@@ -32,6 +32,7 @@ import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
@@ -47,10 +48,14 @@ import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import org.apache.commons.io.IOUtils;
import javax.net.ssl.HttpsURLConnection;
/**
* A builder pattern for making HTTP call and parsing its output.
*
@@ -129,6 +134,19 @@ class Requester {
return this;
}
/**
* Unlike {@link #with(String, String)}, overrides the existing value
*/
public Requester set(String key, Object value) {
for (Entry e : args) {
if (e.key.equals(key)) {
e.value = value;
return this;
}
}
return _with(key,value);
}
public Requester method(String method) {
this.method = method;
return this;
@@ -174,37 +192,77 @@ class Requester {
while (true) {// loop while API rate limit is hit
HttpURLConnection uc = setupConnection(root.getApiURL(tailApiUrl));
if (!method.equals("GET")) {
uc.setDoOutput(true);
uc.setRequestProperty("Content-type", contentType);
if (body == null) {
Map json = new HashMap();
for (Entry e : args) {
json.put(e.key, e.value);
}
MAPPER.writeValue(uc.getOutputStream(), json);
} else {
try {
byte[] bytes = new byte[32768];
int read = 0;
while ((read = body.read(bytes)) != -1) {
uc.getOutputStream().write(bytes, 0, read);
}
} finally {
body.close();
}
}
}
buildRequest(uc);
try {
return parse(uc,type,instance);
T result = parse(uc, type, instance);
if (type != null && type.isArray()) { // we might have to loop for pagination - done through recursion
final String links = uc.getHeaderField("link");
if (links != null && links.contains("rel=\"next\"")) {
Pattern nextLinkPattern = Pattern.compile(".*<(.*)>; rel=\"next\"");
Matcher nextLinkMatcher = nextLinkPattern.matcher(links);
if (nextLinkMatcher.find()) {
final String link = nextLinkMatcher.group(1);
T nextResult = _to(link, type, instance);
final int resultLength = Array.getLength(result);
final int nextResultLength = Array.getLength(nextResult);
T concatResult = (T) Array.newInstance(type.getComponentType(), resultLength + nextResultLength);
System.arraycopy(result, 0, concatResult, 0, resultLength);
System.arraycopy(nextResult, 0, concatResult, resultLength, nextResultLength);
result = concatResult;
}
}
}
return result;
} catch (IOException e) {
handleApiError(e,uc);
}
}
}
/**
* Makes a request and just obtains the HTTP status code.
*/
public int asHttpStatusCode(String tailApiUrl) throws IOException {
while (true) {// loop while API rate limit is hit
HttpURLConnection uc = setupConnection(root.getApiURL(tailApiUrl));
buildRequest(uc);
try {
return uc.getResponseCode();
} catch (IOException e) {
handleApiError(e,uc);
}
}
}
private void buildRequest(HttpURLConnection uc) throws IOException {
if (!method.equals("GET")) {
uc.setDoOutput(true);
uc.setRequestProperty("Content-type", contentType);
if (body == null) {
Map json = new HashMap();
for (Entry e : args) {
json.put(e.key, e.value);
}
MAPPER.writeValue(uc.getOutputStream(), json);
} else {
try {
byte[] bytes = new byte[32768];
int read = 0;
while ((read = body.read(bytes)) != -1) {
uc.getOutputStream().write(bytes, 0, read);
}
} finally {
body.close();
}
}
}
}
/**
* Loads pagenated resources.
*

View File

@@ -0,0 +1,13 @@
package org.kohsuke.github;
/**
* Represents the result of a search
*
* @author Kohsuke Kawaguchi
*/
abstract class SearchResult<T> {
int total_count;
boolean incomplete_results;
public abstract T[] getItems();
}

View File

@@ -1,6 +1,7 @@
package org.kohsuke.github.extras;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.OkUrlFactory;
import org.kohsuke.github.HttpConnector;
import java.io.IOException;
@@ -19,13 +20,13 @@ import java.net.URL;
* @author Kohsuke Kawaguchi
*/
public class OkHttpConnector implements HttpConnector {
private final OkHttpClient client;
private final OkUrlFactory urlFactory;
public OkHttpConnector(OkHttpClient client) {
this.client = client;
public OkHttpConnector(OkUrlFactory urlFactory) {
this.urlFactory = urlFactory;
}
public HttpURLConnection connect(URL url) throws IOException {
return client.open(url);
return urlFactory.open(url);
}
}

View File

@@ -1,6 +1,9 @@
import org.kohsuke.github.GHIssue;
import org.kohsuke.github.GHOrganization;
import org.kohsuke.github.GHTeam;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.PagedIterable;
import org.kohsuke.github.PagedSearchIterable;
import java.util.Arrays;
import java.util.Map;
@@ -10,14 +13,10 @@ import java.util.Map;
*/
public class Foo {
public static void main(String[] args) throws Exception {
GHOrganization org = GitHub.connect().getOrganization("jenkinsci");
Map<String, GHTeam> teams = org.getTeams();
System.out.println(teams.size());
int sz = 0;
for (GHTeam t : org.listTeams()) {
sz++;
PagedSearchIterable<GHIssue> reviewbybees = GitHub.connect().searchIssues().mentions("reviewbybees").isOpen().list();
for (GHIssue r : reviewbybees) {
System.out.println(r.getTitle());
}
System.out.println(sz);
System.out.println("total="+reviewbybees.getTotalCount());
}
}

View File

@@ -0,0 +1,36 @@
package org.kohsuke.github;
import org.apache.commons.io.IOUtils;
import org.junit.Assert;
import org.junit.Before;
import org.kohsuke.randname.RandomNameGenerator;
import java.io.FileInputStream;
import java.util.Properties;
/**
* @author Kohsuke Kawaguchi
*/
public abstract class AbstractGitHubApiTestBase extends Assert {
protected GitHub gitHub;
@Before
public void setUp() throws Exception {
Properties props = new Properties();
java.io.File f = new java.io.File(System.getProperty("user.home"), ".github.kohsuke2");
if (f.exists()) {
FileInputStream in = new FileInputStream(f);
try {
props.load(in);
gitHub = GitHub.connect(props.getProperty("login"),props.getProperty("oauth"));
} finally {
IOUtils.closeQuietly(in);
}
} else {
gitHub = GitHub.connect();
}
}
protected static final RandomNameGenerator rnd = new RandomNameGenerator();
}

View File

@@ -1,65 +1,22 @@
package org.kohsuke;
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.kohsuke.github.GHBranch;
import org.kohsuke.github.GHCommit;
import org.kohsuke.github.GHCommit.File;
import org.kohsuke.github.GHCommitComment;
import org.kohsuke.github.GHCommitState;
import org.kohsuke.github.GHCommitStatus;
import org.kohsuke.github.GHEvent;
import org.kohsuke.github.GHEventInfo;
import org.kohsuke.github.GHEventPayload;
import org.kohsuke.github.GHHook;
import org.kohsuke.github.GHIssue;
import org.kohsuke.github.GHIssueComment;
import org.kohsuke.github.GHIssueState;
import org.kohsuke.github.GHKey;
import org.kohsuke.github.GHMilestone;
import org.kohsuke.github.GHMyself;
import org.kohsuke.github.GHOrganization;
import org.kohsuke.github.GHOrganization.Permission;
import org.kohsuke.github.GHPullRequest;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GHTeam;
import org.kohsuke.github.GHUser;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.PagedIterable;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.List;
import java.util.*;
import java.util.Map.Entry;
/**
* Unit test for simple App.
*/
public class AppTest {
private GitHub gitHub;
@Before
public void setUp() throws Exception {
gitHub = GitHub.connect();
}
public class AppTest extends AbstractGitHubApiTestBase {
private String getTestRepositoryName() throws IOException {
return getUser().getLogin() + "/github-api-test";
}
@@ -120,6 +77,51 @@ public class AppTest {
o.close();
}
@Test
public void testCreateDeployment() throws IOException {
GHRepository repository = getTestRepository();
GHDeployment deployment = repository.createDeployment("master")
.payload("{\"user\":\"atmos\",\"room_id\":123456}")
.description("question")
.create();
assertNotNull(deployment.getCreator());
assertNotNull(deployment.getId());
}
@Test
public void testListDeployments() throws IOException {
GHRepository repository = getTestRepository();
GHDeployment deployment = repository.createDeployment("master")
.payload("{\"user\":\"atmos\",\"room_id\":123456}")
.description("question")
.environment("unittest")
.create();
assertNotNull(deployment.getCreator());
assertNotNull(deployment.getId());
ArrayList<GHDeployment> deployments = Lists.newArrayList(repository.listDeployments(null, "master", null, "unittest"));
assertNotNull(deployments);
assertFalse(Iterables.isEmpty(deployments));
GHDeployment unitTestDeployment = deployments.get(0);
assertEquals("unittest",unitTestDeployment.getEnvironment());
assertEquals("master", unitTestDeployment.getRef());
}
@Test
public void testGetDeploymentStatuses() throws IOException {
GHRepository repository = getTestRepository();
GHDeployment deployment = repository.createDeployment("master")
.description("question")
.payload("{\"user\":\"atmos\",\"room_id\":123456}")
.create();
GHDeploymentStatus ghDeploymentStatus = repository.createDeployStatus(deployment.getId(), GHDeploymentState.SUCCESS)
.description("success")
.targetUrl("http://www.github.com").create();
Iterable<GHDeploymentStatus> deploymentStatuses = repository.getDeploymentStatuses(deployment.getId());
assertNotNull(deploymentStatuses);
assertEquals(1,Iterables.size(deploymentStatuses));
assertEquals(ghDeploymentStatus.getId(), Iterables.get(deploymentStatuses, 0).getId());
}
@Test
public void testGetIssues() throws Exception {
List<GHIssue> closedIssues = gitHub.getUser("kohsuke").getRepository("github-api").getIssues(GHIssueState.CLOSED);
@@ -200,6 +202,35 @@ public class AppTest {
System.out.println(org);
}
@Test
public void testMyTeamsContainsAllMyOrganizations() throws IOException {
Map<String, Set<GHTeam>> teams = gitHub.getMyTeams();
Map<String, GHOrganization> myOrganizations = gitHub.getMyOrganizations();
assertEquals(teams.keySet(), myOrganizations.keySet());
}
@Test
public void testMyTeamsShouldIncludeMyself() throws IOException {
Map<String, Set<GHTeam>> teams = gitHub.getMyTeams();
for (Entry<String, Set<GHTeam>> teamsPerOrg : teams.entrySet()) {
String organizationName = teamsPerOrg.getKey();
for (GHTeam team : teamsPerOrg.getValue()) {
String teamName = team.getName();
assertTrue("Team " + teamName + " in organization " + organizationName
+ " does not contain myself",
shouldBelongToTeam(organizationName, teamName));
}
}
}
private boolean shouldBelongToTeam(String organizationName, String teamName) throws IOException {
GHOrganization org = gitHub.getOrganization(organizationName);
assertNotNull(org);
GHTeam team = org.getTeamByName(teamName);
assertNotNull(team);
return team.hasMember(gitHub.getMyself());
}
@Test
public void testFetchPullRequest() throws Exception {
GHRepository r = gitHub.getOrganization("jenkinsci").getRepository("jenkins");
@@ -246,13 +277,13 @@ public class AppTest {
@Test
public void testOrgFork() throws Exception {
kohsuke();
getUser().getRepository("rubywm").forkTo(gitHub.getOrganization("jenkinsci"));
gitHub.getRepository("kohsuke/rubywm").forkTo(gitHub.getOrganization("github-api-test-org"));
}
@Test
public void testGetTeamsForRepo() throws Exception {
kohsuke();
assertEquals(1,gitHub.getOrganization("stapler").getRepository("stapler").getTeams().size());
assertEquals(1, gitHub.getOrganization("github-api-test-org").getRepository("testGetTeamsForRepo").getTeams().size());
}
@Test
@@ -271,16 +302,17 @@ public class AppTest {
public void testOrgTeams() throws Exception {
kohsuke();
int sz=0;
for (GHTeam t : gitHub.getOrganization("jenkinsci").listTeams()) {
for (GHTeam t : gitHub.getOrganization("github-api-test-org").listTeams()) {
assertNotNull(t.getName());
sz++;
}
assertTrue(sz>1000);
assertTrue(sz < 100);
}
@Test
public void testOrgTeamByName() throws Exception {
kohsuke();
GHTeam e = gitHub.getOrganization("jenkinsci").getTeamByName("Everyone");
GHTeam e = gitHub.getOrganization("github-api-test-org").getTeamByName("Core Developers");
assertNotNull(e);
}
@@ -466,13 +498,13 @@ public class AppTest {
long start = System.currentTimeMillis();
Map<String, GHRepository> repos = j.getRepositories();
long end = System.currentTimeMillis();
System.out.printf("%d repositories in %dms\n",repos.size(),end-start);
System.out.printf("%d repositories in %dms\n", repos.size(), end - start);
}
@Test
public void testOrganization() throws IOException {
kohsuke();
GHOrganization j = gitHub.getOrganization("jenkinsci");
GHOrganization j = gitHub.getOrganization("github-api-test-org");
GHTeam t = j.getTeams().get("Core Developers");
assertNotNull(j.getRepository("jenkins"));
@@ -492,7 +524,7 @@ public class AppTest {
state = lst.get(0);
System.out.println(state);
assertEquals("testing!",state.getDescription());
assertEquals("http://kohsuke.org/",state.getTargetUrl());
assertEquals("http://kohsuke.org/", state.getTargetUrl());
}
@Test
@@ -525,7 +557,109 @@ public class AppTest {
assertFalse(j.hasPublicMember(b));
}
@Test
public void testCreateRelease() throws Exception {
kohsuke();
GHRepository r = gitHub.getRepository("kohsuke2/testCreateRelease");
String tagName = UUID.randomUUID().toString();
String releaseName = "release-" + tagName;
GHRelease rel = r.createRelease(tagName)
.name(releaseName)
.prerelease(false)
.create();
try {
for (GHTag tag : r.listTags()) {
if (tagName.equals(tag.getName())) {
String ash = tag.getCommit().getSHA1();
GHRef ref = r.createRef("refs/heads/"+releaseName, ash);
assertEquals(ref.getRef(),"refs/heads/"+releaseName);
for (Map.Entry<String, GHBranch> entry : r.getBranches().entrySet()) {
System.out.println(entry.getKey() + "/" + entry.getValue());
if (releaseName.equals(entry.getValue().getName())) {
return;
}
}
fail("branch not found");
}
}
fail("release creation failed! tag not found");
} finally {
rel.delete();
}
}
@Test
public void testRef() throws IOException {
GHRef masterRef = gitHub.getRepository("jenkinsci/jenkins").getRef("heads/master");
assertEquals("https://api.github.com/repos/jenkinsci/jenkins/git/refs/heads/master", masterRef.getUrl().toString());
}
@Test
public void directoryListing() throws IOException {
List<GHContent> children = gitHub.getRepository("jenkinsci/jenkins").getDirectoryContent("core");
for (GHContent c : children) {
System.out.println(c.getName());
if (c.isDirectory()) {
for (GHContent d : c.listDirectoryContent()) {
System.out.println(" "+d.getName());
}
}
}
}
@Test
public void testAddDeployKey() throws IOException {
GHRepository myRepository = Iterables.get(gitHub.getMyself().getRepositories().values(),0);
final GHDeployKey newDeployKey = myRepository.addDeployKey("test", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUt0RAycC5cS42JKh6SecfFZBR1RrF+2hYMctz4mk74/arBE+wFb7fnSHGzdGKX2h5CFOWODifRCJVhB7hlVxodxe+QkQQYAEL/x1WVCJnGgTGQGOrhOMj95V3UE5pQKhsKD608C+u5tSofcWXLToP1/wZ7U4/AHjqYi08OLsWToHCax55TZkvdt2jo0hbIoYU+XI9Q8Uv4ONDN1oabiOdgeKi8+crvHAuvNleiBhWVBzFh8KdfzaH5uNdw7ihhFjEd1vzqACsjCINCjdMfzl6jD9ExuWuE92nZJnucls2cEoNC6k2aPmrZDg9hA32FXVpyseY+bDUWFU6LO2LG6PB kohsuke@atlas");
try {
assertNotNull(newDeployKey.getId());
GHDeployKey k = Iterables.find(myRepository.getDeployKeys(), new Predicate<GHDeployKey>() {
public boolean apply(GHDeployKey deployKey) {
return newDeployKey.getId() == deployKey.getId();
}
});
assertNotNull(k);
} finally {
newDeployKey.delete();
}
}
@Test
public void testCommitStatusContext() throws IOException {
GHRepository myRepository = Iterables.get(gitHub.getMyself().getRepositories().values(), 0);
GHRef masterRef = myRepository.getRef("heads/master");
GHCommitStatus commitStatus = myRepository.createCommitStatus(masterRef.getObject().getSha(), GHCommitState.SUCCESS, "http://www.example.com", "test", "test/context");
assertEquals("test/context", commitStatus.getContext());
}
@Test
public void testMemberPagenation() throws IOException {
Set<GHUser> all = new HashSet<GHUser>();
for (GHUser u : gitHub.getOrganization("github-api-test-org").getTeamByName("Core Developers").listMembers()) {
System.out.println(u.getLogin());
all.add(u);
}
assertFalse(all.isEmpty());
}
@Test
public void testIssueSearch() throws IOException {
PagedSearchIterable<GHIssue> r = gitHub.searchIssues().mentions("kohsuke").isOpen().list();
for (GHIssue i : r) {
System.out.println(i.getTitle());
}
}
private void kohsuke() {
Assume.assumeTrue(getUser().getLogin().equals("kohsuke"));
String login = getUser().getLogin();
Assume.assumeTrue(login.equals("kohsuke") || login.equals("kohsuke2"));
}
}

View File

@@ -1,28 +1,26 @@
package org.kohsuke.github;
import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
import java.util.UUID;
/**
* Integration test for {@link GHContent}.
*/
public class GHContentIntegrationTest extends TestCase {
public class GHContentIntegrationTest extends AbstractGitHubApiTestBase {
private GitHub gitHub;
private GHRepository repo;
private String createdFilename;
private String createdFilename = rnd.next();
@Before
@Override
public void setUp() throws Exception {
super.setUp();
gitHub = GitHub.connect();
repo = gitHub.getRepository("acollign/github-api-test").fork();
createdFilename = UUID.randomUUID().toString();
repo = gitHub.getRepository("github-api-test-org/GHContentIntegrationTest").fork();
}
@Test
public void testGetFileContent() throws Exception {
GHContent content = repo.getFileContent("ghcontent-ro/a-file-with-content");
@@ -30,6 +28,7 @@ public class GHContentIntegrationTest extends TestCase {
assertEquals("thanks for reading me\n", content.getContent());
}
@Test
public void testGetEmptyFileContent() throws Exception {
GHContent content = repo.getFileContent("ghcontent-ro/an-empty-file");
@@ -37,12 +36,14 @@ public class GHContentIntegrationTest extends TestCase {
assertEquals("", content.getContent());
}
@Test
public void testGetDirectoryContent() throws Exception {
List<GHContent> entries = repo.getDirectoryContent("ghcontent-ro/a-dir-with-3-entries");
assertTrue(entries.size() == 3);
}
@Test
public void testCRUDContent() throws Exception {
GHContentUpdateResponse created = repo.createContent("this is an awesome file I created\n", "Creating a file for integration tests.", createdFilename);
GHContent createdContent = created.getContent();

View File

@@ -0,0 +1,73 @@
package org.kohsuke.github;
import org.junit.Test;
/**
* @author Kohsuke Kawaguchi
*/
public class GistTest extends AbstractGitHubApiTestBase {
/**
* CRUD operation.
*/
@Test
public void lifecycleTest() throws Exception {
GHGist gist = gitHub.createGist()
.public_(false)
.description("Test Gist")
.file("abc.txt","abc")
.file("def.txt","def")
.create();
assertNotNull(gist.getCreatedAt());
assertNotNull(gist.getUpdatedAt());
assertNotNull(gist.getCommentsUrl());
assertNotNull(gist.getCommitsUrl());
assertNotNull(gist.getGitPullUrl());
assertNotNull(gist.getGitPushUrl());
assertNotNull(gist.getHtmlUrl());
gist.delete();
}
@Test
public void starTest() throws Exception {
GHGist gist = gitHub.getGist("9903708");
assertEquals("rtyler",gist.getOwner().getLogin());
gist.star();
assertTrue(gist.isStarred());
gist.unstar();
assertFalse(gist.isStarred());
GHGist newGist = gist.fork();
try {
for (GHGist g : gist.listForks()) {
if (g.equals(newGist)) {
// expected to find it in the clone list
return;
}
}
fail("Expected to find a newly cloned gist");
} finally {
newGist.delete();
}
}
@Test
public void gistFile() throws Exception {
GHGist gist = gitHub.getGist("9903708");
assertTrue(gist.isPublic());
assertEquals(1,gist.getFiles().size());
GHGistFile f = gist.getFile("keybase.md");
assertEquals("text/plain", f.getType());
assertEquals("Markdown", f.getLanguage());
assertTrue(f.getContent().contains("### Keybase proof"));
assertNotNull(f.getContent());
}
}

View File

@@ -1,5 +1,12 @@
package org.kohsuke.github;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import junit.framework.TestCase;
/**
@@ -21,4 +28,85 @@ public class GitHubTest extends TestCase {
GitHub hub = GitHub.connectUsingPassword("kohsuke", "bogus");
assertEquals("https://api.github.com/test", hub.getApiURL("/test").toString());
}
public void testGitHubBuilderFromEnvironment() throws IOException {
Map<String, String>props = new HashMap<String, String>();
props.put("login", "bogus");
props.put("oauth", "bogus");
props.put("password", "bogus");
setupEnvironment(props);
GitHubBuilder builder = GitHubBuilder.fromEnvironment();
assertEquals("bogus", builder.user);
assertEquals("bogus", builder.oauthToken);
assertEquals("bogus", builder.password);
}
/*
* Copied from StackOverflow: http://stackoverflow.com/a/7201825/2336755
*
* This allows changing the in memory process environment.
*
* Its used to wire in values for the github credentials to test that the GitHubBuilder works properly to resolve them.
*/
private void setupEnvironment(Map<String, String> newenv) {
try
{
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
theEnvironmentField.setAccessible(true);
Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
env.putAll(newenv);
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
theCaseInsensitiveEnvironmentField.setAccessible(true);
Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
cienv.putAll(newenv);
}
catch (NoSuchFieldException e)
{
try {
Class[] classes = Collections.class.getDeclaredClasses();
Map<String, String> env = System.getenv();
for(Class cl : classes) {
if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Object obj = field.get(env);
Map<String, String> map = (Map<String, String>) obj;
map.clear();
map.putAll(newenv);
}
}
} catch (Exception e2) {
e2.printStackTrace();
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
public void testGitHubBuilderFromCustomEnvironment() throws IOException {
Map<String, String>props = new HashMap<String, String>();
props.put("customLogin", "bogusLogin");
props.put("customOauth", "bogusOauth");
props.put("customPassword", "bogusPassword");
setupEnvironment(props);
GitHubBuilder builder = GitHubBuilder.fromEnvironment("customLogin", "customPassword", "customOauth");
assertEquals("bogusLogin", builder.user);
assertEquals("bogusOauth", builder.oauthToken);
assertEquals("bogusPassword", builder.password);
}
}

View File

@@ -1,18 +1,11 @@
package org.kohsuke;
package org.kohsuke.github;
import junit.framework.TestCase;
import org.apache.commons.io.IOUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.kohsuke.github.GHAsset;
import org.kohsuke.github.GHIssue;
import org.kohsuke.github.GHMilestone;
import org.kohsuke.github.GHMyself;
import org.kohsuke.github.GHRelease;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GitHub;
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
@@ -22,24 +15,19 @@ import java.io.PrintWriter;
import java.util.List;
import java.util.Properties;
public class LifecycleTest extends TestCase {
private GitHub gitHub;
@Override
public void setUp() throws Exception {
super.setUp();
gitHub = GitHub.connect();
}
public class LifecycleTest extends AbstractGitHubApiTestBase {
@Test
public void testCreateRepository() throws IOException, GitAPIException, InterruptedException {
GHMyself myself = gitHub.getMyself();
GHRepository repository = myself.getRepository("github-api-test");
GHOrganization org = gitHub.getOrganization("github-api-test-org");
GHRepository repository = org.getRepository("github-api-test");
if (repository != null) {
repository.delete();
Thread.sleep(1000);
}
repository = gitHub.createRepository("github-api-test",
"a test repository used to test kohsuke's github-api", "http://github-api.kohsuke.org/", true);
repository = org.createRepository("github-api-test",
"a test repository used to test kohsuke's github-api", "http://github-api.kohsuke.org/", "Core Developers", true);
Thread.sleep(1000); // wait for the repository to become ready
assertTrue(repository.getReleases().isEmpty());
try {
@@ -54,7 +42,7 @@ public class LifecycleTest extends TestCase {
delete(repoDir);
Git origin = Git.cloneRepository()
.setBare(false)
.setURI(repository.gitHttpTransportUrl())
.setURI(repository.getSshUrl())
.setDirectory(repoDir)
.setCredentialsProvider(getCredentialsProvider(myself))
.call();

View File

@@ -0,0 +1,51 @@
package org.kohsuke.github;
import org.junit.After;
import org.junit.Test;
import java.io.IOException;
import java.util.Collection;
/**
* @author Kohsuke Kawaguchi
*/
public class PullRequestTest extends AbstractGitHubApiTestBase {
@Test
public void createPullRequest() throws Exception {
String name = rnd.next();
GHPullRequest p = getRepository().createPullRequest(name, "stable", "master", "## test");
System.out.println(p.getUrl());
assertEquals(name, p.getTitle());
}
@Test // Requires push access to the test repo to pass
public void setLabels() throws Exception {
GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test");
String label = rnd.next();
p.setLabels(label);
Collection<GHIssue.Label> labels = getRepository().getPullRequest(p.getNumber()).getLabels();
assertEquals(1, labels.size());
assertEquals(label, labels.iterator().next().getName());
}
@Test // Requires push access to the test repo to pass
public void setAssignee() throws Exception {
GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test");
GHMyself user = gitHub.getMyself();
p.assignTo(user);
assertEquals(user, getRepository().getPullRequest(p.getNumber()).getAssignee());
}
@After
public void cleanUp() throws Exception {
for (GHPullRequest pr : getRepository().getPullRequests(GHIssueState.OPEN)) {
pr.close();
}
}
private GHRepository getRepository() throws IOException {
return gitHub.getOrganization("github-api-test-org").getRepository("jenkins");
}
}

View File

@@ -0,0 +1,91 @@
package org.kohsuke.github;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.Iterator;
import static org.mockito.Mockito.when;
/**
* @author Luciano P. Sabenca (luciano.sabenca [at] movile [com] | lucianosabenca [at] gmail [dot] com
*/
public class RepositoryTest {
@Mock
GitHub mockGitHub;
@Mock
Iterator<GHUser[]> iterator;
@Mock
GHRepository mockRepository;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void listCollaborators() throws Exception {
GHUser user1 = new GHUser();
user1.login = "login1";
GHUser user2 = new GHUser();
user2.login = "login2";
when(iterator.hasNext()).thenReturn(true, false, true);
when(iterator.next()).thenReturn(new GHUser[]{user1}, new GHUser[]{user2});
Requester requester = Mockito.mock(Requester.class);
when(mockGitHub.retrieve()).thenReturn(requester);
when(requester.asIterator("/repos/*/*/collaborators",
GHUser[].class)).thenReturn(iterator, iterator);
PagedIterable<GHUser> pagedIterable = Mockito.mock(PagedIterable.class);
when(mockRepository.listCollaborators()).thenReturn(pagedIterable);
PagedIterator<GHUser> userPagedIterator = new PagedIterator<GHUser>(iterator) {
@Override
protected void wrapUp(GHUser[] page) {
}
};
PagedIterator<GHUser> userPagedIterator2 = new PagedIterator<GHUser>(iterator) {
@Override
protected void wrapUp(GHUser[] page) {
}
};
when(pagedIterable.iterator()).thenReturn(userPagedIterator, userPagedIterator2);
Iterator<GHUser> returnIterator1 = mockRepository.listCollaborators().iterator();
Assert.assertTrue(returnIterator1.hasNext());
GHUser user = returnIterator1.next();
Assert.assertEquals(user, user1);
Assert.assertFalse(returnIterator1.hasNext());
Iterator returnIterator2 = mockRepository.listCollaborators().iterator();
Assert.assertTrue(returnIterator2.hasNext());
user = returnIterator1.next();
Assert.assertEquals(user, user2);
}
}