Compare commits

...

151 Commits

Author SHA1 Message Date
Liam Newman
3dae361d7b [maven-release-plugin] prepare release github-api-1.103 2020-01-22 11:56:59 -08:00
Liam Newman
967831388e Relocate shaded dependecies and generate separate shaded artifact 2020-01-22 09:59:10 -08:00
Liam Newman
f9794f20d4 Use Https 2020-01-21 17:22:58 -08:00
Liam Newman
f98efd6af0 Update site.xml 2020-01-21 16:56:44 -08:00
Liam Newman
69bf0641f8 Update site.xml
Closes #671
2020-01-21 16:55:46 -08:00
Liam Newman
5791843d16 [maven-release-plugin] prepare for next development iteration 2020-01-21 15:40:09 -08:00
Liam Newman
58d0a20074 [maven-release-plugin] prepare release github-api-1.102 2020-01-21 15:40:00 -08:00
Liam Newman
5884c7b3ba Re-enable jacoco during ci 2020-01-21 14:44:47 -08:00
Liam Newman
dd1da268a2 Additional checks and clean up to GHRateLimit and tests 2020-01-21 13:30:08 -08:00
Liam Newman
98b606287d Add more validation to rate limit
Downstream tests are doing some strange Json.  Give better output when they do something invalid.
2020-01-18 23:33:44 -08:00
Liam Newman
9792fc0daa Fix missing version 2020-01-18 19:20:21 -08:00
Liam Newman
a9bb9302bc Move cached 404 retry to main code path 2020-01-18 18:53:31 -08:00
Liam Newman
30c70bc8d4 Merge pull request #651 from martinvanzijl/issue_500_create_tag_method
Add createTag() method to GHRepository
2020-01-18 14:02:39 -08:00
Liam Newman
0df48c37ac Merge branch 'master' into issue_500_create_tag_method 2020-01-17 22:43:07 -08:00
Liam Newman
ec31e94e7a Merge pull request #665 from bitwiseman/task/cache-error-test
Workaround for `If-Modified-Since` HTTP request header causing cache corruption
2020-01-17 22:42:09 -08:00
Liam Newman
ea631d0e88 Merge pull request #633 from bitwiseman/task/shade
Add shading of dependencies
2020-01-17 22:41:29 -08:00
Liam Newman
66a180346e Improve commenting of workaround 2020-01-17 17:52:50 -08:00
Liam Newman
63ee878789 Merge remote-tracking branch 'github-api/master' into task/cache-error-test 2020-01-17 17:27:12 -08:00
Liam Newman
3479e4f2fd Clean up and formatting 2020-01-17 17:05:45 -08:00
Liam Newman
54f4152f89 Template data files to make okhttp2 test runnable in CI
OkHttp2 doesn't invalidate caches sometimes when it probably should
2020-01-17 17:00:40 -08:00
Liam Newman
06334bf272 Template data files to make okhttp3 test runnable in CI 2020-01-17 16:58:54 -08:00
Liam Newman
839f096f39 Add caching error test for OkHttp 2020-01-17 15:57:14 -08:00
Liam Newman
f3b2fdc4fc Update test and resources using new workaround 2020-01-17 15:53:55 -08:00
Liam Newman
16d34f3268 Workaround for #669 - retry with cache overridden
This is much more reasonable way to address this issue.
When the Requester detects a 404 response with an ETag (only happpens when the server's 304
is bogus and would cause cache corruption), try the query again with new request header
that forces the server to not return 304 and return new data instead.

Ths solution is transparent to users of this library and autmatically fixes a situation that
was causing cache corruption. If GitHub ever fixes the issue and begins providing accurate
ETags to their 404 responses, this will result in two calls being made for each 404 response.
While that would be unfortunate, it would still be better than the current situation.
2020-01-17 15:53:55 -08:00
Liam Newman
61e8dd09d6 Revert "Workaround for #669 - remove If-Modified-Since header"
This reverts commit 90d7fea7aa.
2020-01-17 14:46:31 -08:00
Liam Newman
90d7fea7aa Workaround for #669 - remove If-Modified-Since header
This is a first cut at working round #669.  It is hacky as hell and I hate it.
2020-01-17 14:46:10 -08:00
Liam Newman
b9c8bf07ea Restore correct exception throwing for getArray 2020-01-15 19:42:42 -08:00
Liam Newman
a3ba07d45f Inline toIterable 2020-01-15 19:33:22 -08:00
Liam Newman
5a6a29cbb5 Add array and iterator tests 2020-01-15 19:31:30 -08:00
Liam Newman
72aedbb76c JENKINS-54126 - Repro of github caching error 2020-01-14 00:29:43 -08:00
Liam Newman
e7e3be6ea7 Merge pull request #662 from sullis/github-actions-checkout-v2
GitHub Actions checkout v2
2020-01-13 11:29:25 -08:00
Liam Newman
62e1b9eb01 Merge pull request #663 from sullis/jackson-2.10.2
jackson 2.10.2
2020-01-13 11:22:29 -08:00
Sean C. Sullivan
3fff92dc35 jackson 2.10.2 2020-01-12 16:09:57 -08:00
Sean C. Sullivan
352d77719e GitHub Actions checkout v2 2020-01-12 15:23:13 -08:00
Martin van Zijl
ff397dfa4d Correction per "mvn install site". 2020-01-11 13:03:41 +13:00
Martin van Zijl
34d64c0dff Added comment to JavaDoc as advised per GitHub Maven test. 2020-01-11 12:53:54 +13:00
Martin van Zijl
b5fdc2f956 Merge branch 'master' of https://github.com/kohsuke/github-api into issue_500_create_tag_method 2020-01-11 12:46:08 +13:00
Martin van Zijl
38602965db Merge branch 'issue_500_create_tag_method' of https://github.com/martinvanzijl/github-api into issue_500_create_tag_method 2020-01-11 12:31:28 +13:00
Martin van Zijl
df1ea62883 Removed wiremock files for old test case. 2020-01-11 12:24:12 +13:00
Martin van Zijl
afaff52888 Removed test from GHRepositoryTest and added to GHTagTest. 2020-01-11 12:23:41 +13:00
Liam Newman
5b7829c288 Merge branch 'master' into task/shade 2020-01-10 11:14:18 -08:00
Liam Newman
2462eb2c79 Merge pull request #652 from github-api/dependabot/maven/com.squareup.okio-okio-2.4.3
Bump okio from 2.4.2 to 2.4.3
2020-01-10 11:13:59 -08:00
Liam Newman
edc26b0a55 Fix site 2020-01-10 10:11:31 -08:00
Liam Newman
cc94e8b0ca Merge branch 'master' into dependabot/maven/com.squareup.okio-okio-2.4.3 2020-01-10 09:24:04 -08:00
Liam Newman
80f3a6e507 Merge pull request #659 from github-api/dependabot/maven/com.squareup.okhttp3-okhttp-4.3.1
Bump okhttp from 4.2.2 to 4.3.1
2020-01-10 09:23:03 -08:00
Liam Newman
5709be7ff7 Merge branch 'master' into issue_500_create_tag_method 2020-01-10 09:19:05 -08:00
Liam Newman
46fce8cf4b Merge branch 'master' into dependabot/maven/com.squareup.okio-okio-2.4.3 2020-01-10 09:18:51 -08:00
Liam Newman
e84049367e Merge branch 'master' into dependabot/maven/com.squareup.okhttp3-okhttp-4.3.1 2020-01-10 09:18:05 -08:00
Liam Newman
f213ead595 Move shade to ci and release profiles 2020-01-09 11:36:24 -08:00
Liam Newman
ba540b0725 Remove parent pom 2020-01-09 08:27:06 -08:00
Liam Newman
eb55691c89 Add shading of dependencies
Fixes #630
2020-01-09 08:26:49 -08:00
Liam Newman
dd508e7dea Rerecord GHTreeBuilder for test org 2020-01-08 19:44:23 -08:00
dependabot-preview[bot]
66357866c5 Bump okio from 2.4.2 to 2.4.3
Bumps [okio](https://github.com/square/okio) from 2.4.2 to 2.4.3.
- [Release notes](https://github.com/square/okio/releases)
- [Changelog](https://github.com/square/okio/blob/master/CHANGELOG.md)
- [Commits](https://github.com/square/okio/compare/parent-2.4.2...parent-2.4.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-09 03:22:54 +00:00
dependabot-preview[bot]
6e3728b458 Bump okhttp from 4.2.2 to 4.3.1
Bumps [okhttp](https://github.com/square/okhttp) from 4.2.2 to 4.3.1.
- [Release notes](https://github.com/square/okhttp/releases)
- [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md)
- [Commits](https://github.com/square/okhttp/compare/parent-4.2.2...parent-4.3.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-09 03:22:54 +00:00
Liam Newman
31d4eef4b1 Merge pull request #642 from asthinasthi/create-tree-null-sha-field
Post only non-null values in request body for createTree
2020-01-08 19:21:43 -08:00
Liam Newman
f58f32a7a8 Merge branch 'master' into create-tree-null-sha-field 2020-01-08 17:36:36 -08:00
Liam Newman
28d8fb686a Merge pull request #653 from github-api/dependabot/maven/org.apache.maven.plugins-maven-source-plugin-3.2.1
Bump maven-source-plugin from 3.2.0 to 3.2.1
2020-01-07 11:26:07 -08:00
dependabot-preview[bot]
4c7fc2ef47 Bump maven-source-plugin from 3.2.0 to 3.2.1
Bumps [maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.2.0 to 3.2.1.
- [Release notes](https://github.com/apache/maven-source-plugin/releases)
- [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.2.0...maven-source-plugin-3.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-07 00:00:39 +00:00
Liam Newman
a3f99978c2 Merge pull request #657 from github-api/dependabot/maven/junit-junit-4.13
Bump junit from 4.12 to 4.13
2020-01-06 15:59:26 -08:00
Liam Newman
136b55d310 Merge pull request #650 from bitwiseman/issue/mime-base64-638
Do not MIME encode Base64 content for sending
2020-01-06 09:23:44 -08:00
dependabot-preview[bot]
617e90259b Bump junit from 4.12 to 4.13
Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.
- [Release notes](https://github.com/junit-team/junit4/releases)
- [Changelog](https://github.com/junit-team/junit4/blob/master/doc/ReleaseNotes4.12.md)
- [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-02 06:36:48 +00:00
Martin van Zijl
959eb46162 Deleted unit test cleanup method.
This method failed in the automated GitHub build online with a null
pointer exception.

I tried to make it a @Before/@After method, but that fails on
my local PC.
2020-01-02 13:21:27 +13:00
Martin van Zijl
998bda9de7 Add createTag() method.
Fixes #500.
2019-12-23 05:43:48 +13:00
Liam Newman
37a2018fe3 Do not MIME encode Base64 content for sending
Fixes #638
2019-12-20 19:48:17 -08:00
Liam Newman
2c80e07c9d Merge branch 'master' into create-tree-null-sha-field 2019-12-19 19:11:09 -08:00
Liam Newman
a115f34766 Merge pull request #637 from PauloMigAlmeida/marketplace_endpoints_patch2
[Patch 2/2] :: Add support to Marketplace endpoints
2019-12-19 19:10:00 -08:00
Liam Newman
cd66c1e7c3 Add Accept header 2019-12-19 18:59:50 -08:00
Liam Newman
4f9975dc6d Merge remote-tracking branch 'github-api/master' into marketplace_endpoints_patch2 2019-12-19 18:44:48 -08:00
Liam Newman
9da487d962 Merge pull request #635 from PauloMigAlmeida/marketplace_endpoints
[Patch 1/2] :: Add support to Marketplace endpoints
2019-12-19 18:26:16 -08:00
Liam Newman
c7123b016b Update for Accept header 2019-12-19 18:21:09 -08:00
PauloMigAlmeida
efb13ddaf0 Fix errors caught during the build
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-19 18:06:14 -08:00
PauloMigAlmeida
3539b73c08 Implement changes requested for patch 1
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-19 18:06:14 -08:00
PauloMigAlmeida
2c084ef4d5 improve docs related to credentials requirements for some methods
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-19 18:06:14 -08:00
PauloMigAlmeida
754e66f4dd Additional tests for list accounts with a few parameters combinations
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-19 18:06:14 -08:00
PauloMigAlmeida
41b698f0a8 Add tests for listing GitHub marketplace accounts
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-19 18:06:14 -08:00
PauloMigAlmeida
de78da4fa6 Implement listing all GitHub Marketplace accounts given a plan
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-19 18:06:14 -08:00
PauloMigAlmeida
3d241d6fa1 formatting improvements
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-19 18:06:14 -08:00
PauloMigAlmeida
1d983a0090 Implement list marketplace plans
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-19 18:06:13 -08:00
Liam Newman
78fb860305 Merge pull request #648 from bitwiseman/task/accept-header
Enforce 'Accept' request header values
2019-12-19 18:04:55 -08:00
Liam Newman
c699a84f42 Enforce 'Accept' request header values
The 'Accept' header on requests can change what data is returned, so we need to
only match requests with the correct value.
2019-12-19 17:56:32 -08:00
PauloMigAlmeida
d8a178d93d Implement changes requested for patch 2
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-20 13:27:40 +13:00
PauloMigAlmeida
ada4243548 Merge branch 'marketplace_endpoints' of https://github.com/PauloMigAlmeida/github-api into marketplace_endpoints_patch2
 Conflicts:
	src/main/java/org/kohsuke/github/GHMarketplaceAccount.java
	src/main/java/org/kohsuke/github/GHMarketplaceListAccountBuilder.java
	src/test/java/org/kohsuke/github/GHMarketplacePlanTest.java
2019-12-20 13:14:12 +13:00
PauloMigAlmeida
fa2e3aad6c Fix errors caught during the build
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-20 12:58:11 +13:00
PauloMigAlmeida
0cf457a46f Merge branch 'master' of https://github.com/kohsuke/github-api into marketplace_endpoints 2019-12-20 12:46:48 +13:00
PauloMigAlmeida
bb7b98d448 Merge remote-tracking branch 'origin/marketplace_endpoints' into marketplace_endpoints 2019-12-20 12:38:16 +13:00
PauloMigAlmeida
e8d90848f2 Implement changes requested for patch 1
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-20 12:37:59 +13:00
Liam Newman
7c791451ba Merge pull request #647 from halkeye/patch-1
Labels with description are not preview anymore
2019-12-19 13:57:07 -08:00
Liam Newman
16d8c2b221 Remove Symmetra preview 2019-12-19 13:50:18 -08:00
Gavin Mogan
dceecbef0a Labels with description are not preview anymore
https://developer.github.com/v3/issues/labels/#create-a-label
2019-12-19 13:50:07 -08:00
Liam Newman
3cbddf1de9 Merge pull request #646 from PauloMigAlmeida/issue_628
Implement App createToken with empty body
2019-12-19 13:47:22 -08:00
PauloMigAlmeida
650340fcb3 Fix example on the docs
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-20 01:47:39 +13:00
PauloMigAlmeida
ce5b893224 Add example on the docs
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-20 01:44:09 +13:00
PauloMigAlmeida
7869afa4ff Implement test for createToken method with no json property
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-20 01:09:34 +13:00
Paulo Miguel Almeida
9085606082 Fix GHObjectTest test broken on PR #644
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-20 00:08:23 +13:00
Paulo Miguel Almeida
1e3f646814 Refactor GHAppCreateTokenBuilder;
Add docs;

Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-20 00:05:31 +13:00
PauloMigAlmeida
933f0cb4b8 Merge branch 'master' of https://github.com/github-api/github-api into issue_628
 Conflicts:
	src/main/java/org/kohsuke/github/GHAppCreateTokenBuilder.java
2019-12-19 22:59:44 +13:00
PauloMigAlmeida
7497761fcc Implement create token variation 2019-12-19 19:42:22 +13:00
Liam Newman
12b3d4ec7a Merge branch 'master' into marketplace_endpoints 2019-12-17 17:27:10 -08:00
Liam Newman
8fd5ed57c4 Merge pull request #644 from martinvanzijl/issue_126_add_type_and_site_admin_fields
Add type and site_admin fields to GHPerson
2019-12-17 17:23:54 -08:00
Liam Newman
7bc301bc70 Merge pull request #634 from bitwiseman/task/minimum-coverage
Task/minimum coverage
2019-12-17 17:23:30 -08:00
Liam Newman
30321d3a0e Update coverage excludes and bars 2019-12-17 17:16:23 -08:00
Liam Newman
511a0ae503 Exclude deprecated classes 2019-12-17 17:16:22 -08:00
Liam Newman
1057636666 Add wiremock data 2019-12-17 17:16:22 -08:00
Liam Newman
564b1d2a98 Enable event tests 2019-12-17 17:16:22 -08:00
Liam Newman
20cd0e2de2 Turn Traffic tests back on 2019-12-17 17:16:22 -08:00
Liam Newman
6bc617c488 Merge pull request #623 from bitwiseman/task/iterator
Move array population to single iterator code path
2019-12-17 15:01:12 -08:00
Liam Newman
049db83423 Merge remote-tracking branch 'github-api/master' into task/iterator 2019-12-17 14:35:37 -08:00
Liam Newman
52dd90e85d Additional tweaks to reduce the number of code paths 2019-12-17 14:15:38 -08:00
Liam Newman
305267d07f Rename methods for better clarity 2019-12-17 12:41:23 -08:00
Liam Newman
20369aa1b5 Merge pull request #622 from alexanderrtaylor/GHEventAddition
[JENKINS-57430] Added some new GH Event Types
2019-12-17 11:32:45 -08:00
Liam Newman
40f05e4dbb Clean up request method calls 2019-12-17 10:02:55 -08:00
Liam Newman
a23d19f208 Merge pull request #645 from github-api/dependabot/maven/org.mockito-mockito-core-3.2.4
Bump mockito-core from 3.2.0 to 3.2.4
2019-12-17 09:06:48 -08:00
dependabot-preview[bot]
cb1d1e8ed7 Bump mockito-core from 3.2.0 to 3.2.4
Bumps [mockito-core](https://github.com/mockito/mockito) from 3.2.0 to 3.2.4.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v3.2.0...v3.2.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-17 06:37:39 +00:00
Alex Taylor
4f67f32719 Update src/main/java/org/kohsuke/github/GHCheckRun.java 2019-12-16 14:53:38 -05:00
Alex Taylor
a80b5b6abc Fixed the findbugs errors 2019-12-14 15:38:34 -05:00
Liam Newman
0be3d88872 Merge pull request #643 from github-api/dependabot/maven/com.squareup.okio-okio-2.4.2
Bump okio from 2.4.1 to 2.4.2
2019-12-13 19:42:09 +00:00
Liam Newman
48bb996350 Merge pull request #640 from github-api/dependabot/maven/org.eclipse.jgit-org.eclipse.jgit-5.6.0.201912101111-r
Bump org.eclipse.jgit from 5.5.1.201910021850-r to 5.6.0.201912101111-r
2019-12-13 19:41:52 +00:00
Martin van Zijl
ee2dde4cd1 Add type and site_admin fields to GHPerson.
Helps with #126.
2019-12-14 07:24:23 +13:00
dependabot-preview[bot]
c10a31c933 Bump okio from 2.4.1 to 2.4.2
Bumps [okio](https://github.com/square/okio) from 2.4.1 to 2.4.2.
- [Release notes](https://github.com/square/okio/releases)
- [Changelog](https://github.com/square/okio/blob/master/CHANGELOG.md)
- [Commits](https://github.com/square/okio/compare/2.4.1...parent-2.4.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-12 06:33:01 +00:00
Anirudh Mathad
d6a846f58d Post only non-null values in request body for createTree 2019-12-11 15:25:24 -08:00
dependabot-preview[bot]
945873231d Bump org.eclipse.jgit from 5.5.1.201910021850-r to 5.6.0.201912101111-r
Bumps org.eclipse.jgit from 5.5.1.201910021850-r to 5.6.0.201912101111-r.

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-11 06:36:08 +00:00
PauloMigAlmeida
5dc494978e Implement tests
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-10 13:21:52 +13:00
PauloMigAlmeida
c870ec10c0 Implement /user/marketplace_purchases endpoint
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-10 13:21:06 +13:00
PauloMigAlmeida
2085b8fd14 Split GHMarketplaceAccount.java into 2 pieces for re-utilisation purposes
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-10 13:19:19 +13:00
PauloMigAlmeida
e065b6435c improve docs related to credentials requirements for some methods
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-09 20:59:03 +13:00
PauloMigAlmeida
da5331ceb0 Additional tests for list accounts with a few parameters combinations
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-09 20:07:32 +13:00
PauloMigAlmeida
8f81982de4 Add tests for listing GitHub marketplace accounts
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-09 19:36:13 +13:00
PauloMigAlmeida
499b46ecf3 Implement listing all GitHub Marketplace accounts given a plan
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-09 15:53:46 +13:00
PauloMigAlmeida
a7d232e15f formatting improvements
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-08 20:26:37 +13:00
PauloMigAlmeida
8fdb394ec5 Implement list marketplace plans
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-12-08 20:13:54 +13:00
PauloMigAlmeida
7a1da64bf2 Merge branch 'master' of https://github.com/kohsuke/github-api 2019-12-08 15:42:54 +13:00
PauloMigAlmeida
95ae155fc0 Merge branch 'master' of https://github.com/PauloMigAlmeida/github-api 2019-12-08 15:42:34 +13:00
Liam Newman
d1507f2666 Merge pull request #631 from bitwiseman/task/base64
Remove dependency on apache commons-codec
2019-12-04 10:56:08 +00:00
Liam Newman
7e4f98d328 Remove dependency on apache commons-codec 2019-12-03 11:39:05 +00:00
Liam Newman
f9a956905e Merge pull request #629 from sullis/mockito-3.2.0
mockito 3.2.0
2019-11-30 13:20:54 -08:00
Sean C. Sullivan
e7d95f9da6 mockito 3.2.0 2019-11-29 13:33:54 -05:00
Alex Taylor
bc8f0aa223 Update GHEventPayload.java
updated to meet standards
2019-11-27 15:18:43 -05:00
Liam Newman
6f2ae94e12 Changelog for v1.101 2019-11-27 10:47:25 -08:00
Alex Taylor
8f787e9976 Added the Check Run event
Added the check run event and the objects used there along with a valid test
2019-11-27 13:30:45 -05:00
Liam Newman
321d8240a2 [maven-release-plugin] prepare for next development iteration 2019-11-27 10:27:31 -08:00
Liam Newman
d667b2f822 [maven-release-plugin] prepare release github-api-1.101 2019-11-27 10:27:24 -08:00
Liam Newman
d7f511363d Merge pull request #627 from alecharp/fix-cache-control-packagename
Fixed CacheControl package name
2019-11-27 10:14:12 -08:00
Adrien Lecharpentier
39e7c5c3de Fixed CacheControl package name
With okhttp 3, the package name changed. In the okhttp3.OkHttpConnector,
the incorrect class is loaded, creating a ClassNotFoundException at
runtime when okhttp3 only is loaded.
2019-11-27 18:30:06 +01:00
Liam Newman
60acd5c864 Update CHANGELOG.md 2019-11-26 19:08:00 -08:00
Liam Newman
b92cf6fd35 [maven-release-plugin] prepare for next development iteration 2019-11-26 17:53:42 -08:00
Liam Newman
0f9482864c Move url to separate method 2019-11-26 15:26:46 -08:00
Liam Newman
60700d59fe Force URI encoding for api paths starting with slash 2019-11-26 15:14:36 -08:00
Liam Newman
3296cef02d Change requester to GET by default 2019-11-25 18:15:21 -08:00
Liam Newman
1b55b5fa3c Move array population to single iterator code path
This remove a second code path throught pagination.
2019-11-25 18:15:21 -08:00
Alex Taylor
b2701f5ba4 [JENKINS-57430] Added some new GH Event Types
Added some new GH Event types so that it does not throw errors
2019-11-22 14:26:35 -05:00
PauloMigAlmeida
5d9a4b42a6 Merge branch 'master' of https://github.com/kohsuke/github-api 2019-11-14 15:56:42 +13:00
1403 changed files with 56122 additions and 3134 deletions

View File

@@ -7,4 +7,4 @@ We love getting PRs, but we hate asking people for the same basic changes every
- [ ] Push your changes to a branch other than `master`. Create your PR from that branch.
- [ ] Add JavaDocs and other comments
- [ ] Write tests that run and pass in CI. See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to capture snapshot data.
- [ ] Run `mvn install site` locally. This may reformat your code, commit those changes. If this command doesn't succeed, your change will not pass CI.
- [ ] Run `mvn -P ci install site` locally. This may reformat your code, commit those changes. If this command doesn't succeed, your change will not pass CI.

View File

@@ -11,12 +11,12 @@ jobs:
matrix:
java: [ '1.8.0', '11.0.x', '13.0.x' ]
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.java }}
- name: Maven Download all dependencies
run: mvn -B org.apache.maven.plugins:maven-dependency-plugin:3.1.1:go-offline
run: mvn -B org.apache.maven.plugins:maven-dependency-plugin:3.1.1:go-offline -P ci
- name: Maven Build
run: mvn -B install site -P ci --file pom.xml

2
.gitignore vendored
View File

@@ -7,3 +7,5 @@ target
.project
.settings/
.DS_Store
dependency-reduced-pom.xml

View File

@@ -1,29 +1,37 @@
# Changelog
## [github-api-1.100](https://github.com/github-api/github-api/tree/github-api-1.100) (2019-11-27)
## [github-api-1.101](https://github.com/github-api/github-api/tree/github-api-1.101) (2019-11-27)
[Full Changelog](https://github.com/github-api/github-api/compare/github-api-1.100...github-api-1.101)
### Fixes
- Fixed `ClassNotFoundException` when creating `okhttp3.OkHttpConnector` with `Cache` @alecharp [\#627](https://github.com/github-api/github-api/issues/627)
## [github-api-1.100](https://github.com/github-api/github-api/tree/github-api-1.100) (2019-11-26)
[Full Changelog](https://github.com/github-api/github-api/compare/github-api-1.99...github-api-1.100)
### Features and Fixes
- Add method to set repository topics @martinvanzijl (#594)
- Adjust GHRateLimit to system time instead of depending on synchronization @bitwiseman (#595)
- Add Functionality of OTP to support user 2fa @madhephaestus (#603)
- Implement Meta endpoint @PauloMigAlmeida (#611)
- fix and unit tests for issue #504 @siordache (#620)
- Fixed GHContent to allow spaces in path @bitwiseman (#625)
- Add method to set repository topics @martinvanzijl [\#594](https://github.com/github-api/github-api/issues/594)
- Adjust GHRateLimit to system time instead of depending on synchronization @bitwiseman [#595](https://github.com/github-api/github-api/issues/595)
- Add Functionality of OTP to support user 2fa @madhephaestus [\#603](https://github.com/github-api/github-api/issues/603)
- Implement Meta endpoint @PauloMigAlmeida [\#611](https://github.com/github-api/github-api/issues/611)
- fix and unit tests for issue #504 @siordache [\#620](https://github.com/github-api/github-api/issues/620)
- Fixed GHContent to allow spaces in path @bitwiseman [\#625](https://github.com/github-api/github-api/issues/625)
### Internals
- Clean up Requester interface a bit @bitwiseman (#614)
- Javadoc fail on warning during CI build @bitwiseman (#613)
- Code style fixes @bitwiseman (#609)
- Re-enable Lifecycle test @bitwiseman (#621)
- Removed permission field in createTeam. It is deprecated in the API @asthinasthi (#619)
- Cleanup imports @bitwiseman (#616)
- Branch missing @alexanderrtaylor (#615)
- jackson 2.10.1 @sullis (#604)
- Bump okhttp from 3.14.2 to 4.2.2 @dependabot-preview (#593)
- Bump okhttp3 from 3.14.2 to 4.2.2 @dependabot-preview [\#593](https://github.com/github-api/github-api/issues/593)
- jackson 2.10.1 @sullis [\#604](https://github.com/github-api/github-api/issues/604)
- Code style fixes @bitwiseman [\#609](https://github.com/github-api/github-api/issues/609)
- Javadoc fail on warning during CI build @bitwiseman [\#613](https://github.com/github-api/github-api/issues/613)
- Clean up Requester interface a bit @bitwiseman [\#614](https://github.com/github-api/github-api/issues/614)
- Branch missing @alexanderrtaylor [\#615](https://github.com/github-api/github-api/issues/615)
- Cleanup imports @bitwiseman [\#616](https://github.com/github-api/github-api/issues/616)
- Removed permission field in createTeam. It is deprecated in the API @asthinasthi [\#619](https://github.com/github-api/github-api/issues/619)
- Re-enable Lifecycle test @bitwiseman [\#621](https://github.com/github-api/github-api/issues/621)
## [github-api-1.99](https://github.com/github-api/github-api/tree/github-api-1.99) (2019-11-04)

419
pom.xml
View File

@@ -1,14 +1,8 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.kohsuke</groupId>
<artifactId>pom</artifactId>
<version>21</version>
<relativePath />
</parent>
<groupId>org.kohsuke</groupId>
<artifactId>github-api</artifactId>
<version>1.100</version>
<version>1.103</version>
<name>GitHub API for Java</name>
<url>https://github-api.kohsuke.org/</url>
<description>GitHub API for Java</description>
@@ -17,10 +11,20 @@
<connection>scm:git:git@github.com/github-api/${project.artifactId}.git</connection>
<developerConnection>scm:git:ssh://git@github.com/github-api/${project.artifactId}.git</developerConnection>
<url>https://${project.artifactId}.kohsuke.org/</url>
<tag>github-api-1.100</tag>
<tag>github-api-1.103</tag>
</scm>
<distributionManagement>
<snapshotRepository>
<id>sonatype-nexus-snapshots</id>
<name>Sonatype Nexus Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</snapshotRepository>
<repository>
<id>sonatype-nexus-staging</id>
<name>Nexus Release Repository</name>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
<site>
<id>github-pages</id>
<url>gitsite:git@github.com/github-api/${project.artifactId}.git</url>
@@ -33,14 +37,13 @@
<spotbugs.version>3.1.12</spotbugs.version>
<spotbugs-maven-plugin.failOnError>true</spotbugs-maven-plugin.failOnError>
<hamcrest.version>2.2</hamcrest.version>
<okhttp3.version>4.2.2</okhttp3.version>
<okio.version>2.4.1</okio.version>
<okhttp3.version>4.3.1</okhttp3.version>
<okio.version>2.4.3</okio.version>
<formatter-maven-plugin.goal>format</formatter-maven-plugin.goal>
<impsort-maven-plugin.goal>sort</impsort-maven-plugin.goal>
<jacoco.coverage.target.class>.80</jacoco.coverage.target.class>
<jacoco.coverage.target.method>0.20</jacoco.coverage.target.method>
<jacoco.coverage.target.line>0.50</jacoco.coverage.target.line>
<jacoco.coverage.target.other>0.50</jacoco.coverage.target.other>
<!-- Using this as the minimum bar for code coverage. Adding methods without covering them will fail this. -->
<jacoco.coverage.target.bundle.method>0.556</jacoco.coverage.target.bundle.method>
<jacoco.coverage.target.class.method>0.25</jacoco.coverage.target.class.method>
<!-- For non-ci builds we'd like the build to still complete if jacoco metrics aren't met. -->
<jacoco.haltOnFailure>false</jacoco.haltOnFailure>
</properties>
@@ -57,6 +60,14 @@
<artifactId>maven-scm-manager-plexus</artifactId>
<version>1.11.2</version>
</extension>
<!-- Doing site publishing manually for now -->
<!--
<extension>
<groupId>org.kohsuke</groupId>
<artifactId>wagon-gitsite</artifactId>
<version>0.3.5</version>
</extension>
-->
</extensions>
<testResources>
<testResource>
@@ -68,11 +79,184 @@
</testResources>
<pluginManagement>
<plugins>
<!-- adds jacoco coverage -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>shaded-jar</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>com.fasterxml.jackson</pattern>
<shadedPattern>hidden.com.fasterxml.jackson</shadedPattern>
</relocation>
<relocation>
<pattern>org.apache</pattern>
<shadedPattern>hidden.org.apache</shadedPattern>
</relocation>
</relocations>
<artifactSet>
<excludes>
<exclude>com.infradna.tool:bridge-method-annotation</exclude>
<exclude>org.jenkins-ci:annotation-indexer</exclude>
<exclude>com.squareup.*:*</exclude>
<exclude>org.jetbrains*:*</exclude>
<exclude>com.github.spotbugs:*</exclude>
<exclude>com.google.code.findbugs:*</exclude>
</excludes>
</artifactSet>
<shadedArtifactAttached>true</shadedArtifactAttached>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>module-info.class</exclude>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.5</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<!-- attached to Maven test phase -->
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>check</id>
<phase>test</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>METHOD</counter>
<value>COVEREDRATIO</value>
<minimum>${jacoco.coverage.target.bundle.method}</minimum>
</limit>
</limits>
</rule>
<rule>
<!--We end up with chatty logs, but it shows us which particular classes -->
<!--are lacking in coverage. If this is too much, just remove the -->
<!--<element>CLASS</element> tag below. -->
<element>CLASS</element>
<limits>
<limit>
<counter>METHOD</counter>
<value>COVEREDRATIO</value>
<minimum>${jacoco.coverage.target.class.method}</minimum>
</limit>
</limits>
<excludes>
<!-- Code implemented externally -->
<exclude>org.kohsuke.github.extras.okhttp3.ObsoleteUrlFactory.**</exclude>
<exclude>org.kohsuke.github.extras.okhttp3.ObsoleteUrlFactory</exclude>
<!-- Sample only -->
<exclude>org.kohsuke.github.example.*</exclude>
<!-- No methods -->
<exclude>org.kohsuke.github.DeleteToken</exclude>
<exclude>org.kohsuke.github.Previews</exclude>
<!-- Deprecated -->
<exclude>org.kohsuke.github.extras.OkHttp3Connector</exclude>
<exclude>org.kohsuke.github.EnforcementLevel</exclude>
<exclude>org.kohsuke.github.GHPerson.1</exclude>
<exclude>org.kohsuke.github.GHPerson.1.1</exclude>
<!-- TODO: These still need test coverage -->
<exclude>org.kohsuke.github.GHBranchProtection.RequiredSignatures</exclude>
<exclude>org.kohsuke.github.GHBranchProtectionBuilder.Restrictions</exclude>
<exclude>org.kohsuke.github.GHBranchProtection.Restrictions</exclude>
<exclude>org.kohsuke.github.GHCommentAuthorAssociation</exclude>
<exclude>org.kohsuke.github.GHCommitBuilder.UserInfo</exclude>
<exclude>org.kohsuke.github.GHCommitSearchBuilder.CommitSearchResult</exclude>
<exclude>org.kohsuke.github.GHCommitSearchBuilder.Sort</exclude>
<exclude>org.kohsuke.github.GHCommitSearchBuilder</exclude>
<exclude>org.kohsuke.github.GHCommitState</exclude>
<exclude>org.kohsuke.github.GHCompare.Commit</exclude>
<exclude>org.kohsuke.github.GHCompare.InnerCommit</exclude>
<exclude>org.kohsuke.github.GHCompare.Status</exclude>
<exclude>org.kohsuke.github.GHCompare.Tree</exclude>
<exclude>org.kohsuke.github.GHCompare.User</exclude>
<exclude>org.kohsuke.github.GHCompare</exclude>
<exclude>org.kohsuke.github.GHDeployKey</exclude>
<exclude>org.kohsuke.github.GHDeploymentStatusBuilder</exclude>
<exclude>org.kohsuke.github.GHDirection</exclude>
<exclude>org.kohsuke.github.GHEmail</exclude>
<exclude>org.kohsuke.github.GHEventPayload.Ping</exclude>
<exclude>org.kohsuke.github.GHEventPayload.Release</exclude>
<exclude>org.kohsuke.github.GHException</exclude>
<exclude>org.kohsuke.github.GHHook</exclude>
<exclude>org.kohsuke.github.GHHooks.OrgContext</exclude>
<exclude>org.kohsuke.github.GHInvitation</exclude>
<exclude>org.kohsuke.github.GHIssueSearchBuilder.IssueSearchResult</exclude>
<exclude>org.kohsuke.github.GHIssueSearchBuilder.Sort</exclude>
<exclude>org.kohsuke.github.GHIssueSearchBuilder</exclude>
<exclude>org.kohsuke.github.GHMilestoneState</exclude>
<exclude>org.kohsuke.github.GHOrgHook</exclude>
<exclude>org.kohsuke.github.GHProject.ProjectStateFilter</exclude>
<exclude>org.kohsuke.github.GHPullRequestCommitDetail.Authorship</exclude>
<exclude>org.kohsuke.github.GHPullRequestCommitDetail.Commit</exclude>
<exclude>org.kohsuke.github.GHPullRequestCommitDetail.CommitPointer</exclude>
<exclude>org.kohsuke.github.GHPullRequestCommitDetail.Tree</exclude>
<exclude>org.kohsuke.github.GHPullRequestCommitDetail</exclude>
<exclude>org.kohsuke.github.GHPullRequestFileDetail</exclude>
<exclude>org.kohsuke.github.GHPullRequestQueryBuilder.Sort</exclude>
<exclude>org.kohsuke.github.GHReleaseUpdater</exclude>
<exclude>org.kohsuke.github.GHRepository.ForkSort</exclude>
<exclude>org.kohsuke.github.GHRequestedAction</exclude>
<exclude>org.kohsuke.github.GHStargazer</exclude>
<exclude>org.kohsuke.github.GHTagObject</exclude>
<exclude>org.kohsuke.github.GHTeam.Role</exclude>
<exclude>org.kohsuke.github.GHUserSearchBuilder.Sort</exclude>
<exclude>org.kohsuke.github.GHVerifiedKey</exclude>
<exclude>org.kohsuke.github.GitHubBuilder.1</exclude>
</excludes>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -81,6 +265,18 @@
<configuration>
<source>8</source>
<failOnWarnings>true</failOnWarnings>
<doclint>all</doclint>
</configuration>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.8</version>
<extensions>true</extensions>
<configuration>
<serverId>sonatype-nexus-staging</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
</plugins>
@@ -102,6 +298,10 @@
<goals>deploy</goals>
</configuration>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
@@ -225,17 +425,6 @@
</dependency>
</dependencies>
</plugin>
<!-- Do not use gmaven plugin -->
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<executions>
<execution>
<goals>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
@@ -245,11 +434,6 @@
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.13</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
@@ -272,13 +456,13 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.1</version>
<version>2.10.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
@@ -291,6 +475,27 @@
<version>1.18</version>
<optional>true</optional>
</dependency>
<!-- for stapler-jetty -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
<scope>test</scope>
</dependency>
<!-- for stapler-jetty -->
<dependency>
<groupId>commons-discovery</groupId>
<artifactId>commons-discovery</artifactId>
<version>0.5</version>
<scope>test</scope>
</dependency>
<!-- for stapler-jetty -->
<dependency>
<groupId>org.kohsuke.stapler</groupId>
<artifactId>stapler</artifactId>
<version>1.258</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.kohsuke.stapler</groupId>
<artifactId>stapler-jetty</artifactId>
@@ -300,7 +505,7 @@
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>5.5.1.201910021850-r</version>
<version>5.6.0.201912101111-r</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -338,14 +543,14 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.1.0</version>
<version>3.2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-annotations</artifactId>
<version>${spotbugs.version}</version>
<optional>true</optional>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
@@ -375,118 +580,44 @@
<profiles>
<profile>
<id>ci</id>
<activation>
<property>
<name>enable-ci</name>
</property>
</activation>
<properties>
<formatter-maven-plugin.goal>validate</formatter-maven-plugin.goal>
<impsort-maven-plugin.goal>check</impsort-maven-plugin.goal>
<jacoco.haltOnFailure>true</jacoco.haltOnFailure>
</properties>
<build>
</build>
</profile>
<profile>
<id>jacoco</id>
<activation>
<property>
<name>enable-jacoco</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.5</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<!-- attached to Maven test phase -->
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>check</id>
<phase>install</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<!--We end up with chatty logs, but it shows us which particular classes -->
<!--are lacking in coverage. If this is too much, just remove the -->
<!--<element>CLASS</element> tag below. -->
<element>CLASS</element>
<limits>
<!-- These limits can be overridden, in the form of `0.50` for -->
<!-- 50%, as necessary. Using a property just puts it in one spot. -->
<!--
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>${jacoco.coverage.target.lines}</minimum>
</limit>
-->
<!--
<limit>
<counter>BRANCH</counter>
<value>COVEREDRATIO</value>
<minimum>${jacoco.coverage.target.other}</minimum>
</limit>
-->
<!--
<limit>
<counter>INSTRUCTION</counter>
<value>COVEREDRATIO</value>
<minimum>${jacoco.coverage.target.other}</minimum>
</limit>
-->
<!--
<limit>
<counter>COMPLEXITY</counter>
<value>COVEREDRATIO</value>
<minimum>${jacoco.coverage.target.other}</minimum>
</limit>
-->
<limit>
<counter>METHOD</counter>
<value>COVEREDRATIO</value>
<minimum>${jacoco.coverage.target.method}</minimum>
</limit>
<!-- <limit>-->
<!-- <counter>CLASS</counter>-->
<!-- <value>COVEREDRATIO</value>-->
<!-- <minimum>${jacoco.coverage.target.class}</minimum>-->
<!-- </limit>-->
</limits>
<excludes>
<exclude>org.kohsuke.github.extras.okhttp3.ObsoleteUrlFactory.**</exclude>
<exclude>org.kohsuke.github.extras.okhttp3.ObsoleteUrlFactory</exclude>
<exclude>org.kohsuke.github.extras.OkHttp3Connector</exclude>
<!--<exclude>io.jenkins.plugins.todeclarative.converter.api.*</exclude>-->
</excludes>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>release</id>
<properties>
<formatter-maven-plugin.goal>validate</formatter-maven-plugin.goal>
<impsort-maven-plugin.goal>check</impsort-maven-plugin.goal>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
@@ -506,7 +637,26 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
@@ -540,4 +690,13 @@
<archive>https://groups.google.com/forum/#!forum/github-api</archive>
</mailingList>
</mailingLists>
<developers>
<developer>
<name>Kohsuke Kawaguchi</name>
<id>kohsuke</id>
<email>kk@kohsuke.org</email>
</developer>
</developers>
</project>

View File

@@ -178,9 +178,10 @@ public class GHApp extends GHObject {
@Preview
@Deprecated
public PagedIterable<GHAppInstallation> listInstallations() {
return root.retrieve()
return root.createRequest()
.withPreview(MACHINE_MAN)
.asPagedIterable("/app/installations", GHAppInstallation[].class, item -> item.wrapUp(root));
.withUrlPath("/app/installations")
.toIterable(GHAppInstallation[].class, item -> item.wrapUp(root));
}
/**
@@ -198,9 +199,10 @@ public class GHApp extends GHObject {
@Preview
@Deprecated
public GHAppInstallation getInstallationById(long id) throws IOException {
return root.retrieve()
return root.createRequest()
.withPreview(MACHINE_MAN)
.to(String.format("/app/installations/%d", id), GHAppInstallation.class)
.withUrlPath(String.format("/app/installations/%d", id))
.fetch(GHAppInstallation.class)
.wrapUp(root);
}
@@ -220,9 +222,10 @@ public class GHApp extends GHObject {
@Preview
@Deprecated
public GHAppInstallation getInstallationByOrganization(String name) throws IOException {
return root.retrieve()
return root.createRequest()
.withPreview(MACHINE_MAN)
.to(String.format("/orgs/%s/installation", name), GHAppInstallation.class)
.withUrlPath(String.format("/orgs/%s/installation", name))
.fetch(GHAppInstallation.class)
.wrapUp(root);
}
@@ -244,9 +247,10 @@ public class GHApp extends GHObject {
@Preview
@Deprecated
public GHAppInstallation getInstallationByRepository(String ownerName, String repositoryName) throws IOException {
return root.retrieve()
return root.createRequest()
.withPreview(MACHINE_MAN)
.to(String.format("/repos/%s/%s/installation", ownerName, repositoryName), GHAppInstallation.class)
.withUrlPath(String.format("/repos/%s/%s/installation", ownerName, repositoryName))
.fetch(GHAppInstallation.class)
.wrapUp(root);
}
@@ -265,9 +269,10 @@ public class GHApp extends GHObject {
@Preview
@Deprecated
public GHAppInstallation getInstallationByUser(String name) throws IOException {
return root.retrieve()
return root.createRequest()
.withPreview(MACHINE_MAN)
.to(String.format("/users/%s/installation", name), GHAppInstallation.class)
.withUrlPath(String.format("/users/%s/installation", name))
.fetch(GHAppInstallation.class)
.wrapUp(root);
}

View File

@@ -12,6 +12,7 @@ import static org.kohsuke.github.Previews.MACHINE_MAN;
*
* @author Paulo Miguel Almeida
* @see GHAppInstallation#createToken(Map) GHAppInstallation#createToken(Map)
* @see GHAppInstallation#createToken() GHAppInstallation#createToken()
*/
public class GHAppCreateTokenBuilder {
private final GitHub root;
@@ -20,11 +21,17 @@ public class GHAppCreateTokenBuilder {
@Preview
@Deprecated
GHAppCreateTokenBuilder(GitHub root, String apiUrlTail, Map<String, GHPermissionType> permissions) {
GHAppCreateTokenBuilder(GitHub root, String apiUrlTail) {
this.root = root;
this.apiUrlTail = apiUrlTail;
this.builder = new Requester(root);
withPermissions(builder, permissions);
this.builder = root.createRequest();
}
@Preview
@Deprecated
GHAppCreateTokenBuilder(GitHub root, String apiUrlTail, Map<String, GHPermissionType> permissions) {
this(root, apiUrlTail);
permissions(permissions);
}
/**
@@ -43,6 +50,25 @@ public class GHAppCreateTokenBuilder {
return this;
}
/**
* Set the permissions granted to the access token. The permissions object includes the permission names and their
* access type.
*
* @param permissions
* Map containing the permission names and types.
* @return a GHAppCreateTokenBuilder
*/
@Preview
@Deprecated
public GHAppCreateTokenBuilder permissions(Map<String, GHPermissionType> permissions) {
Map<String, String> retMap = new HashMap<>();
for (Map.Entry<String, GHPermissionType> entry : permissions.entrySet()) {
retMap.put(entry.getKey(), Requester.transformEnum(entry.getValue()));
}
builder.with("permissions", retMap);
return this;
}
/**
* Creates an app token with all the parameters.
* <p>
@@ -57,16 +83,9 @@ public class GHAppCreateTokenBuilder {
public GHAppInstallationToken create() throws IOException {
return builder.method("POST")
.withPreview(MACHINE_MAN)
.to(apiUrlTail, GHAppInstallationToken.class)
.withUrlPath(apiUrlTail)
.fetch(GHAppInstallationToken.class)
.wrapUp(root);
}
private static Requester withPermissions(Requester builder, Map<String, GHPermissionType> value) {
Map<String, String> retMap = new HashMap<String, String>();
for (Map.Entry<String, GHPermissionType> entry : value.entrySet()) {
retMap.put(entry.getKey(), Requester.transformEnum(entry.getValue()));
}
return builder.with("permissions", retMap);
}
}

View File

@@ -271,7 +271,11 @@ public class GHAppInstallation extends GHObject {
@Preview
@Deprecated
public void deleteInstallation() throws IOException {
root.retrieve().method("DELETE").withPreview(GAMBIT).to(String.format("/app/installations/%d", id));
root.createRequest()
.method("DELETE")
.withPreview(GAMBIT)
.withUrlPath(String.format("/app/installations/%d", id))
.send();
}
/**
@@ -283,11 +287,27 @@ public class GHAppInstallation extends GHObject {
*
* @param permissions
* map of permissions for the created token
* @return a GHAppCreateTokenBuilder on error
* @return a GHAppCreateTokenBuilder instance
* @deprecated Use {@link GHAppInstallation#createToken()} instead.
*/
@Preview
@Deprecated
public GHAppCreateTokenBuilder createToken(Map<String, GHPermissionType> permissions) {
return new GHAppCreateTokenBuilder(root, String.format("/app/installations/%d/access_tokens", id), permissions);
}
/**
* Starts a builder that creates a new App Installation Token.
*
* <p>
* You use the returned builder to set various properties, then call {@link GHAppCreateTokenBuilder#create()} to
* finally create an access token.
*
* @return a GHAppCreateTokenBuilder instance
*/
@Preview
@Deprecated
public GHAppCreateTokenBuilder createToken() {
return new GHAppCreateTokenBuilder(root, String.format("/app/installations/%d/access_tokens", id));
}
}

View File

@@ -135,7 +135,7 @@ public class GHAsset extends GHObject {
}
private void edit(String key, Object value) throws IOException {
new Requester(root).with(key, value).method("PATCH").to(getApiRoute());
root.createRequest().with(key, value).method("PATCH").withUrlPath(getApiRoute()).send();
}
/**
@@ -145,7 +145,7 @@ public class GHAsset extends GHObject {
* the io exception
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").to(getApiRoute());
root.createRequest().method("DELETE").withUrlPath(getApiRoute()).send();
}
private String getApiRoute() {

View File

@@ -1,11 +1,9 @@
package org.kohsuke.github;
import org.apache.commons.codec.binary.Base64InputStream;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.Base64;
/**
* The type GHBlob.
@@ -73,8 +71,9 @@ public class GHBlob {
public InputStream read() {
if (encoding.equals("base64")) {
try {
return new Base64InputStream(new ByteArrayInputStream(content.getBytes("US-ASCII")), false);
} catch (UnsupportedEncodingException e) {
Base64.Decoder decoder = Base64.getMimeDecoder();
return new ByteArrayInputStream(decoder.decode(content));
} catch (IllegalArgumentException e) {
throw new AssertionError(e); // US-ASCII is mandatory
}
}

View File

@@ -1,8 +1,7 @@
package org.kohsuke.github;
import org.apache.commons.codec.binary.Base64;
import java.io.IOException;
import java.util.Base64;
/**
* Builder pattern for creating a new blob. Based on https://developer.github.com/v3/git/blobs/#create-a-blob
@@ -13,7 +12,7 @@ public class GHBlobBuilder {
GHBlobBuilder(GHRepository repo) {
this.repo = repo;
req = new Requester(repo.root);
req = repo.root.createRequest();
}
/**
@@ -37,7 +36,7 @@ public class GHBlobBuilder {
* @return a GHBlobBuilder
*/
public GHBlobBuilder binaryContent(byte[] content) {
String base64Content = Base64.encodeBase64String(content);
String base64Content = Base64.getEncoder().encodeToString(content);
req.with("content", base64Content);
req.with("encoding", "base64");
return this;
@@ -55,6 +54,6 @@ public class GHBlobBuilder {
* if the blob cannot be created.
*/
public GHBlob create() throws IOException {
return req.method("POST").to(getApiTail(), GHBlob.class);
return req.method("POST").withUrlPath(getApiTail()).fetch(GHBlob.class);
}
}

View File

@@ -9,8 +9,6 @@ import java.net.URL;
import java.util.Collection;
import java.util.Objects;
import static org.kohsuke.github.Previews.*;
/**
* A branch in a repository.
*
@@ -103,7 +101,7 @@ public class GHBranch {
* the io exception
*/
public GHBranchProtection getProtection() throws IOException {
return root.retrieve().to(protection_url, GHBranchProtection.class).wrap(this);
return root.createRequest().withUrlPath(protection_url).fetch(GHBranchProtection.class).wrap(this);
}
/**
@@ -122,7 +120,7 @@ public class GHBranch {
* if disabling protection fails
*/
public void disableProtection() throws IOException {
new Requester(root).method("DELETE").to(protection_url);
root.createRequest().method("DELETE").withUrlPath(protection_url).send();
}
/**

View File

@@ -44,7 +44,7 @@ public class GHBranchProtection {
@Preview
@Deprecated
public void enabledSignedCommits() throws IOException {
requester().method("POST").to(url + REQUIRE_SIGNATURES_URI, RequiredSignatures.class);
requester().method("POST").withUrlPath(url + REQUIRE_SIGNATURES_URI).fetch(RequiredSignatures.class);
}
/**
@@ -56,7 +56,7 @@ public class GHBranchProtection {
@Preview
@Deprecated
public void disableSignedCommits() throws IOException {
requester().method("DELETE").to(url + REQUIRE_SIGNATURES_URI);
requester().method("DELETE").withUrlPath(url + REQUIRE_SIGNATURES_URI).send();
}
/**
@@ -87,7 +87,7 @@ public class GHBranchProtection {
@Preview
@Deprecated
public boolean getRequiredSignatures() throws IOException {
return requester().method("GET").to(url + REQUIRE_SIGNATURES_URI, RequiredSignatures.class).enabled;
return requester().withUrlPath(url + REQUIRE_SIGNATURES_URI).fetch(RequiredSignatures.class).enabled;
}
/**
@@ -123,7 +123,7 @@ public class GHBranchProtection {
}
private Requester requester() {
return new Requester(root).withPreview(ZZZAX);
return root.createRequest().withPreview(ZZZAX);
}
/**

View File

@@ -93,7 +93,8 @@ public class GHBranchProtectionBuilder {
.withNullable("required_pull_request_reviews", prReviews)
.withNullable("restrictions", restrictions)
.withNullable("enforce_admins", enforceAdmins)
.to(branch.getProtectionUrl().toString(), GHBranchProtection.class)
.withUrlPath(branch.getProtectionUrl().toString())
.fetch(GHBranchProtection.class)
.wrap(branch);
}
@@ -352,7 +353,7 @@ public class GHBranchProtectionBuilder {
}
private Requester requester() {
return new Requester(branch.getRoot()).withPreview(LUKE_CAGE);
return branch.getRoot().createRequest().withPreview(LUKE_CAGE);
}
private static class Restrictions {

View File

@@ -0,0 +1,72 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.net.URL;
/**
* Represents a deployment
*
* @see <a href="https://developer.github.com/v3/checks/runs/">documentation</a>
*/
@SuppressFBWarnings(value = { "UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD", "URF_UNREAD_FIELD" },
justification = "JSON API")
public class GHCheckRun extends GHObject {
GHRepository owner;
GitHub root;
private String status;
private String conclusion;
private String name;
private GHPullRequest[] pullRequests;
GHCheckRun wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
return this;
}
GHCheckRun wrap(GitHub root) {
this.root = root;
if (owner != null) {
owner.wrap(root);
}
return this;
}
GHPullRequest[] wrap() {
return pullRequests;
}
public String getStatus() {
return status;
}
public String getConclusion() {
return conclusion;
}
public String getName() {
return name;
}
GHPullRequest[] getPullRequests() throws IOException {
if (pullRequests != null && pullRequests.length != 0) {
for (GHPullRequest singlePull : pullRequests) {
singlePull.refresh();
}
}
return pullRequests;
}
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
}

View File

@@ -441,11 +441,10 @@ public class GHCommit {
* @return {@link PagedIterable} with all the commit comments in this repository.
*/
public PagedIterable<GHCommitComment> listComments() {
return owner.root.retrieve()
.asPagedIterable(
String.format("/repos/%s/%s/commits/%s/comments", owner.getOwnerName(), owner.getName(), sha),
GHCommitComment[].class,
item -> item.wrap(owner));
return owner.root.createRequest()
.withUrlPath(
String.format("/repos/%s/%s/commits/%s/comments", owner.getOwnerName(), owner.getName(), sha))
.toIterable(GHCommitComment[].class, item -> item.wrap(owner));
}
/**
@@ -466,12 +465,15 @@ public class GHCommit {
* if comment is not created
*/
public GHCommitComment createComment(String body, String path, Integer line, Integer position) throws IOException {
GHCommitComment r = new Requester(owner.root).with("body", body)
GHCommitComment r = owner.root.createRequest()
.method("POST")
.with("body", body)
.with("path", path)
.with("line", line)
.with("position", position)
.to(String.format("/repos/%s/%s/commits/%s/comments", owner.getOwnerName(), owner.getName(), sha),
GHCommitComment.class);
.withUrlPath(
String.format("/repos/%s/%s/commits/%s/comments", owner.getOwnerName(), owner.getName(), sha))
.fetch(GHCommitComment.class);
return r.wrap(owner);
}
@@ -518,7 +520,7 @@ public class GHCommit {
*/
void populate() throws IOException {
if (files == null && stats == null)
owner.root.retrieve().to(owner.getApiTailUrl("commits/" + sha), this);
owner.root.createRequest().withUrlPath(owner.getApiTailUrl("commits/" + sha)).fetchInto(this);
}
GHCommit wrapUp(GHRepository owner) {

View File

@@ -34,7 +34,7 @@ public class GHCommitBuilder {
GHCommitBuilder(GHRepository repo) {
this.repo = repo;
req = new Requester(repo.root);
req = repo.root.createRequest().method("POST");
}
/**
@@ -118,6 +118,6 @@ public class GHCommitBuilder {
*/
public GHCommit create() throws IOException {
req.with("parents", parents);
return req.method("POST").to(getApiTail(), GHCommit.class).wrapUp(repo);
return req.method("POST").withUrlPath(getApiTail()).fetch(GHCommit.class).wrapUp(repo);
}
}

View File

@@ -113,25 +113,33 @@ public class GHCommitComment extends GHObject implements Reactable {
* the io exception
*/
public void update(String body) throws IOException {
new Requester(owner.root).with("body", body).method("PATCH").to(getApiTail(), GHCommitComment.class);
owner.root.createRequest()
.method("PATCH")
.with("body", body)
.withUrlPath(getApiTail())
.fetch(GHCommitComment.class);
this.body = body;
}
@Preview
@Deprecated
public GHReaction createReaction(ReactionContent content) throws IOException {
return new Requester(owner.root).withPreview(SQUIRREL_GIRL)
return owner.root.createRequest()
.method("POST")
.withPreview(SQUIRREL_GIRL)
.with("content", content.getContent())
.to(getApiTail() + "/reactions", GHReaction.class)
.withUrlPath(getApiTail() + "/reactions")
.fetch(GHReaction.class)
.wrap(owner.root);
}
@Preview
@Deprecated
public PagedIterable<GHReaction> listReactions() {
return owner.root.retrieve()
return owner.root.createRequest()
.withPreview(SQUIRREL_GIRL)
.asPagedIterable(getApiTail() + "/reactions", GHReaction[].class, item -> item.wrap(owner.root));
.withUrlPath(getApiTail() + "/reactions")
.toIterable(GHReaction[].class, item -> item.wrap(owner.root));
}
/**
@@ -141,7 +149,7 @@ public class GHCommitComment extends GHObject implements Reactable {
* the io exception
*/
public void delete() throws IOException {
new Requester(owner.root).method("DELETE").to(getApiTail());
owner.root.createRequest().method("DELETE").withUrlPath(getApiTail()).send();
}
private String getApiTail() {

View File

@@ -24,7 +24,7 @@ public class GHCommitQueryBuilder {
GHCommitQueryBuilder(GHRepository repo) {
this.repo = repo;
this.req = repo.root.retrieve(); // requester to build up
this.req = repo.root.createRequest(); // requester to build up
}
/**
@@ -127,6 +127,6 @@ public class GHCommitQueryBuilder {
* @return the paged iterable
*/
public PagedIterable<GHCommit> list() {
return req.asPagedIterable(repo.getApiTailUrl("commits"), GHCommit[].class, item -> item.wrapUp(repo));
return req.withUrlPath(repo.getApiTailUrl("commits")).toIterable(GHCommit[].class, item -> item.wrapUp(repo));
}
}

View File

@@ -1,13 +1,12 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Base64InputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
/**
* A Content of a repository.
@@ -114,7 +113,7 @@ public class GHContent implements Refreshable {
*/
@SuppressFBWarnings("DM_DEFAULT_ENCODING")
public String getContent() throws IOException {
return new String(Base64.decodeBase64(getEncodedContent()));
return new String(Base64.getMimeDecoder().decode(getEncodedContent()));
}
/**
@@ -175,8 +174,9 @@ public class GHContent implements Refreshable {
refresh(content);
if (encoding.equals("base64")) {
try {
return new Base64InputStream(new ByteArrayInputStream(content.getBytes("US-ASCII")), false);
} catch (UnsupportedEncodingException e) {
Base64.Decoder decoder = Base64.getMimeDecoder();
return new ByteArrayInputStream(decoder.decode(content.getBytes(StandardCharsets.US_ASCII)));
} catch (IllegalArgumentException e) {
throw new AssertionError(e); // US-ASCII is mandatory
}
}
@@ -223,7 +223,7 @@ public class GHContent implements Refreshable {
* the io exception
*/
protected synchronized void populate() throws IOException {
root.retrieve().to(url, this);
root.createRequest().withUrlPath(url).fetchInto(this);
}
/**
@@ -237,7 +237,7 @@ public class GHContent implements Refreshable {
if (!isDirectory())
throw new IllegalStateException(path + " is not a directory");
return root.retrieve().asPagedIterable(url, GHContent[].class, item -> item.wrap(repository));
return root.createRequest().setRawUrlPath(url).toIterable(GHContent[].class, item -> item.wrap(repository));
}
/**
@@ -304,9 +304,11 @@ public class GHContent implements Refreshable {
*/
public GHContentUpdateResponse update(byte[] newContentBytes, String commitMessage, String branch)
throws IOException {
String encodedContent = Base64.encodeBase64String(newContentBytes);
String encodedContent = Base64.getEncoder().encodeToString(newContentBytes);
Requester requester = new Requester(root).with("path", path)
Requester requester = root.createRequest()
.method("POST")
.with("path", path)
.with("message", commitMessage)
.with("sha", sha)
.with("content", encodedContent)
@@ -316,7 +318,8 @@ public class GHContent implements Refreshable {
requester.with("branch", branch);
}
GHContentUpdateResponse response = requester.to(getApiRoute(repository, path), GHContentUpdateResponse.class);
GHContentUpdateResponse response = requester.withUrlPath(getApiRoute(repository, path))
.fetch(GHContentUpdateResponse.class);
response.getContent().wrap(repository);
response.getCommit().wrapUp(repository);
@@ -350,7 +353,9 @@ public class GHContent implements Refreshable {
* the io exception
*/
public GHContentUpdateResponse delete(String commitMessage, String branch) throws IOException {
Requester requester = new Requester(root).with("path", path)
Requester requester = root.createRequest()
.method("POST")
.with("path", path)
.with("message", commitMessage)
.with("sha", sha)
.method("DELETE");
@@ -359,7 +364,8 @@ public class GHContent implements Refreshable {
requester.with("branch", branch);
}
GHContentUpdateResponse response = requester.to(getApiRoute(repository, path), GHContentUpdateResponse.class);
GHContentUpdateResponse response = requester.withUrlPath(getApiRoute(repository, path))
.fetch(GHContentUpdateResponse.class);
response.getCommit().wrapUp(repository);
return response;
@@ -405,6 +411,6 @@ public class GHContent implements Refreshable {
*/
@Override
public synchronized void refresh() throws IOException {
root.retrieve().to(url, this);
root.createRequest().setRawUrlPath(url).fetchInto(this);
}
}

View File

@@ -1,9 +1,8 @@
package org.kohsuke.github;
import org.apache.commons.codec.binary.Base64;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
/**
* Used to create/update content.
@@ -21,7 +20,7 @@ public final class GHContentBuilder {
GHContentBuilder(GHRepository repo) {
this.repo = repo;
this.req = new Requester(repo.root).method("PUT");
this.req = repo.root.createRequest().method("PUT");
}
/**
@@ -50,7 +49,7 @@ public final class GHContentBuilder {
}
/**
* Used when updating (but not creating a new content) to specify Thetblob SHA of the file being replaced.
* Used when updating (but not creating a new content) to specify the blob SHA of the file being replaced.
*
* @param sha
* the sha
@@ -69,7 +68,7 @@ public final class GHContentBuilder {
* @return the gh content builder
*/
public GHContentBuilder content(byte[] content) {
req.with("content", Base64.encodeBase64String(content));
req.with("content", Base64.getEncoder().encodeToString(content));
return this;
}
@@ -81,11 +80,7 @@ public final class GHContentBuilder {
* @return the gh content builder
*/
public GHContentBuilder content(String content) {
try {
return content(content.getBytes("UTF-8"));
} catch (UnsupportedEncodingException x) {
throw new AssertionError();
}
return content(content.getBytes(StandardCharsets.UTF_8));
}
/**
@@ -108,7 +103,8 @@ public final class GHContentBuilder {
* the io exception
*/
public GHContentUpdateResponse commit() throws IOException {
GHContentUpdateResponse response = req.to(GHContent.getApiRoute(repo, path), GHContentUpdateResponse.class);
GHContentUpdateResponse response = req.withUrlPath(GHContent.getApiRoute(repo, path))
.fetch(GHContentUpdateResponse.class);
response.getContent().wrap(repo);
response.getCommit().wrapUp(repo);

View File

@@ -16,7 +16,7 @@ public class GHCreateRepositoryBuilder {
GHCreateRepositoryBuilder(GitHub root, String apiUrlTail, String name) {
this.root = root;
this.apiUrlTail = apiUrlTail;
this.builder = new Requester(root);
this.builder = root.createRequest();
this.builder.with("name", name);
}
@@ -196,7 +196,7 @@ public class GHCreateRepositoryBuilder {
* if repsitory cannot be created
*/
public GHRepository create() throws IOException {
return builder.method("POST").to(apiUrlTail, GHRepository.class).wrap(root);
return builder.method("POST").withUrlPath(apiUrlTail).fetch(GHRepository.class).wrap(root);
}
}

View File

@@ -82,7 +82,9 @@ public class GHDeployKey {
* the io exception
*/
public void delete() throws IOException {
new Requester(owner.root).method("DELETE")
.to(String.format("/repos/%s/%s/keys/%d", owner.getOwnerName(), owner.getName(), id));
owner.root.createRequest()
.method("DELETE")
.withUrlPath(String.format("/repos/%s/%s/keys/%d", owner.getOwnerName(), owner.getName(), id))
.send();
}
}

View File

@@ -131,7 +131,9 @@ public class GHDeployment extends GHObject {
* @return the paged iterable
*/
public PagedIterable<GHDeploymentStatus> listStatuses() {
return root.retrieve().asPagedIterable(statuses_url, GHDeploymentStatus[].class, item -> item.wrap(owner));
return root.createRequest()
.withUrlPath(statuses_url)
.toIterable(GHDeploymentStatus[].class, item -> item.wrap(owner));
}
}

View File

@@ -19,7 +19,7 @@ public class GHDeploymentBuilder {
*/
public GHDeploymentBuilder(GHRepository repo) {
this.repo = repo;
this.builder = new Requester(repo.root);
this.builder = repo.root.createRequest().method("POST");
}
/**
@@ -127,6 +127,6 @@ public class GHDeploymentBuilder {
* the io exception
*/
public GHDeployment create() throws IOException {
return builder.to(repo.getApiTailUrl("deployments"), GHDeployment.class).wrap(repo);
return builder.withUrlPath(repo.getApiTailUrl("deployments")).fetch(GHDeployment.class).wrap(repo);
}
}

View File

@@ -30,7 +30,7 @@ public class GHDeploymentStatusBuilder {
GHDeploymentStatusBuilder(GHRepository repo, long deploymentId, GHDeploymentState state) {
this.repo = repo;
this.deploymentId = deploymentId;
this.builder = new Requester(repo.root);
this.builder = repo.root.createRequest().method("POST");
this.builder.with("state", state);
}
@@ -66,7 +66,8 @@ public class GHDeploymentStatusBuilder {
* the io exception
*/
public GHDeploymentStatus create() throws IOException {
return builder.to(repo.getApiTailUrl("deployments/" + deploymentId + "/statuses"), GHDeploymentStatus.class)
return builder.withUrlPath(repo.getApiTailUrl("deployments/" + deploymentId + "/statuses"))
.fetch(GHDeploymentStatus.class)
.wrap(repo);
}
}

View File

@@ -10,50 +10,58 @@ import java.util.Locale;
* @see <a href="https://developer.github.com/v3/activity/events/types/">Event type reference</a>
*/
public enum GHEvent {
CHECK_RUN,
CHECK_SUITE,
COMMIT_COMMENT,
CONTENT_REFERENCE,
CREATE,
DELETE,
DEPLOY_KEY,
DEPLOYMENT,
DEPLOYMENT_STATUS,
DOWNLOAD,
FOLLOW,
FORK,
FORK_APPLY,
GITHUB_APP_AUTHORIZATION,
GIST,
GOLLUM,
INSTALLATION,
INSTALLATION_REPOSITORIES,
INTEGRATION_INSTALLATION_REPOSITORIES,
CHECK_SUITE,
ISSUE_COMMENT,
ISSUES,
LABEL,
MARKETPLACE_PURCHASE,
MEMBER,
MEMBERSHIP,
META,
MILESTONE,
ORGANIZATION,
ORG_BLOCK,
PACKAGE,
PAGE_BUILD,
PROJECT_CARD,
PROJECT_COLUMN,
PROJECT,
PING,
PUBLIC,
PULL_REQUEST,
PULL_REQUEST_REVIEW,
PULL_REQUEST_REVIEW_COMMENT,
PUSH,
RELEASE,
REPOSITORY, // only
// valid
// for
// org
// hooks
REPOSITORY_DISPATCH, // only valid for org hooks
REPOSITORY,
REPOSITORY_IMPORT,
REPOSITORY_VULNERABILITY_ALERT,
SECURITY_ADVISORY,
STAR,
STATUS,
TEAM,
TEAM_ADD,
WATCH,
PING,
/**
* Special event type that means "every possible event"
*/

View File

@@ -47,6 +47,109 @@ public abstract class GHEventPayload {
}
}
// List of events that still need to be added:
// CheckRunEvent CheckSuiteEvent ContentReferenceEvent
// DeployKeyEvent DownloadEvent FollowEvent ForkApplyEvent GitHubAppAuthorizationEvent GistEvent GollumEvent
// InstallationEvent InstallationRepositoriesEvent IssuesEvent LabelEvent MarketplacePurchaseEvent MemberEvent
// MembershipEvent MetaEvent MilestoneEvent OrganizationEvent OrgBlockEvent PackageEvent PageBuildEvent
// ProjectCardEvent ProjectColumnEvent ProjectEvent RepositoryDispatchEvent RepositoryImportEvent
// RepositoryVulnerabilityAlertEvent SecurityAdvisoryEvent StarEvent StatusEvent TeamEvent TeamAddEvent WatchEvent
/**
* A check run event has been created, rerequested, completed, or has a requested_action.
*
* @see <a href="https://developer.github.com/v3/activity/events/types/#checkrunevent">authoritative source</a>
*/
@SuppressFBWarnings(
value = { "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD" },
justification = "JSON API")
public static class CheckRun extends GHEventPayload {
private String action;
private int number;
private GHCheckRun checkRun;
private GHRequestedAction requestedAction;
private GHRepository repository;
/**
* Gets action.
*
* @return the action
*/
public String getAction() {
return action;
}
/**
* Gets number.
*
* @return the number
*/
public int getNumber() {
return number;
}
/**
* Sets Check Run object
*
* @param currentCheckRun
* the check run object
*/
public void setCheckRun(GHCheckRun currentCheckRun) {
this.checkRun = currentCheckRun;
}
/**
* Gets Check Run object
*
* @return the current checkRun object
*/
public GHCheckRun getCheckRun() {
return checkRun;
}
/**
* Sets the Requested Action object
*
* @param currentRequestedAction
* the current action
*/
public void setCheckRun(GHRequestedAction currentRequestedAction) {
this.requestedAction = currentRequestedAction;
}
/**
* Gets the Requested Action object
*
* @return the requested action
*/
public GHRequestedAction getRequestedAction() {
return requestedAction;
}
/**
* Gets repository.
*
* @return the repository
*/
public GHRepository getRepository() {
return repository;
}
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
if (checkRun == null)
throw new IllegalStateException(
"Expected check_run payload, but got something else. Maybe we've got another type of event?");
if (repository != null) {
repository.wrap(root);
checkRun.wrap(repository);
} else {
checkRun.wrap(root);
}
}
}
/**
* A pull request status has changed.
*

View File

@@ -182,7 +182,7 @@ public class GHGist extends GHObject {
* the io exception
*/
public void star() throws IOException {
new Requester(root).method("PUT").to(getApiTailUrl("star"));
root.createRequest().method("PUT").withUrlPath(getApiTailUrl("star")).send();
}
/**
@@ -192,7 +192,7 @@ public class GHGist extends GHObject {
* the io exception
*/
public void unstar() throws IOException {
new Requester(root).method("DELETE").to(getApiTailUrl("star"));
root.createRequest().method("DELETE").withUrlPath(getApiTailUrl("star")).send();
}
/**
@@ -203,7 +203,7 @@ public class GHGist extends GHObject {
* the io exception
*/
public boolean isStarred() throws IOException {
return root.retrieve().asHttpStatusCode(getApiTailUrl("star")) / 100 == 2;
return root.createRequest().withUrlPath(getApiTailUrl("star")).fetchHttpStatusCode() / 100 == 2;
}
/**
@@ -214,7 +214,7 @@ public class GHGist extends GHObject {
* the io exception
*/
public GHGist fork() throws IOException {
return new Requester(root).to(getApiTailUrl("forks"), GHGist.class).wrapUp(root);
return root.createRequest().method("POST").withUrlPath(getApiTailUrl("forks")).fetch(GHGist.class).wrapUp(root);
}
/**
@@ -223,7 +223,9 @@ public class GHGist extends GHObject {
* @return the paged iterable
*/
public PagedIterable<GHGist> listForks() {
return root.retrieve().asPagedIterable(getApiTailUrl("forks"), GHGist[].class, item -> item.wrapUp(root));
return root.createRequest()
.withUrlPath(getApiTailUrl("forks"))
.toIterable(GHGist[].class, item -> item.wrapUp(root));
}
/**
@@ -233,7 +235,7 @@ public class GHGist extends GHObject {
* the io exception
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").to("/gists/" + id);
root.createRequest().method("DELETE").withUrlPath("/gists/" + id).send();
}
/**

View File

@@ -23,7 +23,7 @@ public class GHGistBuilder {
*/
public GHGistBuilder(GitHub root) {
this.root = root;
req = new Requester(root);
req = root.createRequest().method("POST");
}
/**
@@ -73,6 +73,6 @@ public class GHGistBuilder {
*/
public GHGist create() throws IOException {
req.with("files", files);
return req.to("/gists", GHGist.class).wrapUp(root);
return req.withUrlPath("/gists").fetch(GHGist.class).wrapUp(root);
}
}

View File

@@ -16,7 +16,7 @@ public class GHGistUpdater {
GHGistUpdater(GHGist base) {
this.base = base;
this.builder = new Requester(base.root);
this.builder = base.root.createRequest();
files = new LinkedHashMap<>();
}
@@ -96,6 +96,6 @@ public class GHGistUpdater {
*/
public GHGist update() throws IOException {
builder.with("files", files);
return builder.method("PATCH").to(base.getApiTailUrl(""), GHGist.class).wrap(base.owner);
return builder.method("PATCH").withUrlPath(base.getApiTailUrl("")).fetch(GHGist.class).wrap(base.owner);
}
}

View File

@@ -74,7 +74,7 @@ public abstract class GHHook extends GHObject {
* @see <a href="https://developer.github.com/v3/repos/hooks/#ping-a-hook">Ping hook</a>
*/
public void ping() throws IOException {
new Requester(getRoot()).method("POST").to(getApiRoute() + "/pings");
getRoot().createRequest().method("POST").withUrlPath(getApiRoute() + "/pings").send();
}
/**
@@ -84,7 +84,7 @@ public abstract class GHHook extends GHObject {
* the io exception
*/
public void delete() throws IOException {
new Requester(getRoot()).method("DELETE").to(getApiRoute());
getRoot().createRequest().method("DELETE").withUrlPath(getApiRoute()).send();
}
/**

View File

@@ -28,8 +28,10 @@ class GHHooks {
*/
public List<GHHook> getHooks() throws IOException {
GHHook[] hookArray = root.retrieve().to(collection(), collectionClass()); // jdk/eclipse bug requires this
// to be on separate line
GHHook[] hookArray = root.createRequest().withUrlPath(collection()).fetch(collectionClass()); // jdk/eclipse
// bug
// requires this
// to be on separate line
List<GHHook> list = new ArrayList<GHHook>(Arrays.asList(hookArray));
for (GHHook h : list)
wrap(h);
@@ -46,7 +48,7 @@ class GHHooks {
* the io exception
*/
public GHHook getHook(int id) throws IOException {
GHHook hook = root.retrieve().to(collection() + "/" + id, clazz());
GHHook hook = root.createRequest().withUrlPath(collection() + "/" + id).fetch(clazz());
return wrap(hook);
}
@@ -74,11 +76,14 @@ class GHHooks {
ea.add(e.symbol());
}
GHHook hook = new Requester(root).with("name", name)
GHHook hook = root.createRequest()
.method("POST")
.with("name", name)
.with("active", active)
.with("config", config)
.with("events", ea)
.to(collection(), clazz());
.withUrlPath(collection())
.fetch(clazz());
return wrap(hook);
}

View File

@@ -36,7 +36,7 @@ public class GHInvitation extends GHObject {
* the io exception
*/
public void accept() throws IOException {
root.retrieve().method("PATCH").to("/user/repository_invitations/" + id);
root.createRequest().method("PATCH").withUrlPath("/user/repository_invitations/" + id).send();
}
/**
@@ -46,7 +46,7 @@ public class GHInvitation extends GHObject {
* the io exception
*/
public void decline() throws IOException {
root.retrieve().method("DELETE").to("/user/repository_invitations/" + id);
root.createRequest().method("DELETE").withUrlPath("/user/repository_invitations/" + id).send();
}
@Override

View File

@@ -206,7 +206,7 @@ public class GHIssue extends GHObject implements Reactable {
* the io exception
*/
public void lock() throws IOException {
new Requester(root).method("PUT").to(getApiRoute() + "/lock");
root.createRequest().method("PUT").withUrlPath(getApiRoute() + "/lock").send();
}
/**
@@ -216,7 +216,7 @@ public class GHIssue extends GHObject implements Reactable {
* the io exception
*/
public void unlock() throws IOException {
new Requester(root).method("PUT").to(getApiRoute() + "/lock");
root.createRequest().method("PUT").withUrlPath(getApiRoute() + "/lock").send();
}
/**
@@ -230,17 +230,20 @@ public class GHIssue extends GHObject implements Reactable {
*/
@WithBridgeMethods(void.class)
public GHIssueComment comment(String message) throws IOException {
GHIssueComment r = new Requester(root).with("body", message)
.to(getIssuesApiRoute() + "/comments", GHIssueComment.class);
GHIssueComment r = root.createRequest()
.method("POST")
.with("body", message)
.withUrlPath(getIssuesApiRoute() + "/comments")
.fetch(GHIssueComment.class);
return r.wrapUp(this);
}
private void edit(String key, Object value) throws IOException {
new Requester(root).with(key, value).method("PATCH").to(getApiRoute());
root.createRequest().with(key, value).method("PATCH").withUrlPath(getApiRoute()).send();
}
private void editIssue(String key, Object value) throws IOException {
new Requester(root).with(key, value).method("PATCH").to(getIssuesApiRoute());
root.createRequest().with(key, value).method("PATCH").withUrlPath(getIssuesApiRoute()).send();
}
/**
@@ -442,27 +445,30 @@ public class GHIssue extends GHObject implements Reactable {
* the io exception
*/
public PagedIterable<GHIssueComment> listComments() throws IOException {
return root.retrieve()
.asPagedIterable(getIssuesApiRoute() + "/comments",
GHIssueComment[].class,
item -> item.wrapUp(GHIssue.this));
return root.createRequest()
.withUrlPath(getIssuesApiRoute() + "/comments")
.toIterable(GHIssueComment[].class, item -> item.wrapUp(this));
}
@Preview
@Deprecated
public GHReaction createReaction(ReactionContent content) throws IOException {
return new Requester(owner.root).withPreview(SQUIRREL_GIRL)
return owner.root.createRequest()
.method("POST")
.withPreview(SQUIRREL_GIRL)
.with("content", content.getContent())
.to(getApiRoute() + "/reactions", GHReaction.class)
.withUrlPath(getApiRoute() + "/reactions")
.fetch(GHReaction.class)
.wrap(root);
}
@Preview
@Deprecated
public PagedIterable<GHReaction> listReactions() {
return owner.root.retrieve()
return owner.root.createRequest()
.withPreview(SQUIRREL_GIRL)
.asPagedIterable(getApiRoute() + "/reactions", GHReaction[].class, item -> item.wrap(owner.root));
.withUrlPath(getApiRoute() + "/reactions")
.toIterable(GHReaction[].class, item -> item.wrap(owner.root));
}
/**
@@ -486,10 +492,11 @@ public class GHIssue extends GHObject implements Reactable {
* the io exception
*/
public void addAssignees(Collection<GHUser> assignees) throws IOException {
root.retrieve()
root.createRequest()
.method("POST")
.with(ASSIGNEES, getLogins(assignees))
.to(getIssuesApiRoute() + "/assignees", this);
.withUrlPath(getIssuesApiRoute() + "/assignees")
.fetchInto(this);
}
/**
@@ -513,7 +520,11 @@ public class GHIssue extends GHObject implements Reactable {
* the io exception
*/
public void setAssignees(Collection<GHUser> assignees) throws IOException {
new Requester(root).with(ASSIGNEES, getLogins(assignees)).method("PATCH").to(getIssuesApiRoute());
root.createRequest()
.method("PATCH")
.with(ASSIGNEES, getLogins(assignees))
.withUrlPath(getIssuesApiRoute())
.send();
}
/**
@@ -537,11 +548,12 @@ public class GHIssue extends GHObject implements Reactable {
* the io exception
*/
public void removeAssignees(Collection<GHUser> assignees) throws IOException {
root.retrieve()
root.createRequest()
.method("DELETE")
.with(ASSIGNEES, getLogins(assignees))
.inBody()
.to(getIssuesApiRoute() + "/assignees", this);
.withUrlPath(getIssuesApiRoute() + "/assignees")
.fetchInto(this);
}
/**
@@ -703,9 +715,8 @@ public class GHIssue extends GHObject implements Reactable {
* the io exception
*/
public PagedIterable<GHIssueEvent> listEvents() throws IOException {
return root.retrieve()
.asPagedIterable(owner.getApiTailUrl(String.format("/issues/%s/events", number)),
GHIssueEvent[].class,
item -> item.wrapUp(GHIssue.this));
return root.createRequest()
.withUrlPath(owner.getApiTailUrl(String.format("/issues/%s/events", number)))
.toIterable(GHIssueEvent[].class, item -> item.wrapUp(this));
}
}

View File

@@ -17,7 +17,7 @@ public class GHIssueBuilder {
GHIssueBuilder(GHRepository repo, String title) {
this.repo = repo;
this.builder = new Requester(repo.root);
this.builder = repo.root.createRequest().method("POST");
builder.with("title", title);
}
@@ -95,7 +95,8 @@ public class GHIssueBuilder {
public GHIssue create() throws IOException {
return builder.with("labels", labels)
.with("assignees", assignees)
.to(repo.getApiTailUrl("issues"), GHIssue.class)
.withUrlPath(repo.getApiTailUrl("issues"))
.fetch(GHIssue.class)
.wrap(repo);
}
}

View File

@@ -108,7 +108,11 @@ public class GHIssueComment extends GHObject implements Reactable {
* the io exception
*/
public void update(String body) throws IOException {
new Requester(owner.root).with("body", body).method("PATCH").to(getApiRoute(), GHIssueComment.class);
owner.root.createRequest()
.method("PATCH")
.with("body", body)
.withUrlPath(getApiRoute())
.fetch(GHIssueComment.class);
this.body = body;
}
@@ -119,24 +123,28 @@ public class GHIssueComment extends GHObject implements Reactable {
* the io exception
*/
public void delete() throws IOException {
new Requester(owner.root).method("DELETE").to(getApiRoute());
owner.root.createRequest().method("DELETE").withUrlPath(getApiRoute()).send();
}
@Preview
@Deprecated
public GHReaction createReaction(ReactionContent content) throws IOException {
return new Requester(owner.root).withPreview(SQUIRREL_GIRL)
return owner.root.createRequest()
.method("POST")
.withPreview(SQUIRREL_GIRL)
.with("content", content.getContent())
.to(getApiRoute() + "/reactions", GHReaction.class)
.withUrlPath(getApiRoute() + "/reactions")
.fetch(GHReaction.class)
.wrap(owner.root);
}
@Preview
@Deprecated
public PagedIterable<GHReaction> listReactions() {
return owner.root.retrieve()
return owner.root.createRequest()
.withPreview(SQUIRREL_GIRL)
.asPagedIterable(getApiRoute() + "/reactions", GHReaction[].class, item -> item.wrap(owner.root));
.withUrlPath(getApiRoute() + "/reactions")
.toIterable(GHReaction[].class, item -> item.wrap(owner.root));
}
private String getApiRoute() {

View File

@@ -6,8 +6,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Objects;
import static org.kohsuke.github.Previews.SYMMETRA;
/**
* The type GHLabel.
*
@@ -51,8 +49,6 @@ public class GHLabel {
*
* @return the description
*/
@Preview
@Deprecated
public String getDescription() {
return description;
}
@@ -69,7 +65,7 @@ public class GHLabel {
* the io exception
*/
public void delete() throws IOException {
repo.root.retrieve().method("DELETE").to(url);
repo.root.createRequest().method("DELETE").setRawUrlPath(url).send();
}
/**
@@ -81,13 +77,13 @@ public class GHLabel {
* the io exception
*/
public void setColor(String newColor) throws IOException {
repo.root.retrieve()
repo.root.createRequest()
.method("PATCH")
.withPreview(SYMMETRA)
.with("name", name)
.with("color", newColor)
.with("description", description)
.to(url);
.setRawUrlPath(url)
.send();
}
/**
@@ -98,16 +94,14 @@ public class GHLabel {
* @throws IOException
* the io exception
*/
@Preview
@Deprecated
public void setDescription(String newDescription) throws IOException {
repo.root.retrieve()
repo.root.createRequest()
.method("PATCH")
.withPreview(SYMMETRA)
.with("name", name)
.with("color", color)
.with("description", newDescription)
.to(url);
.setRawUrlPath(url)
.send();
}
static Collection<String> toNames(Collection<GHLabel> labels) {

View File

@@ -199,7 +199,7 @@ public class GHLicense extends GHObject {
if (description != null)
return; // already populated
root.retrieve().to(url, this);
root.createRequest().withUrlPath(url).fetchInto(this);
}
@Override

View File

@@ -0,0 +1,88 @@
package org.kohsuke.github;
import java.net.URL;
/**
* Base class for Github Marketplace Account.
*
* @author Paulo Miguel Almeida
* @see GitHub#getMyMarketplacePurchases()
* @see GHMarketplaceListAccountBuilder#createRequest()
*/
public class GHMarketplaceAccount {
protected GitHub root;
private String url;
private long id;
private String login;
private String email;
private String organizationBillingEmail;
private GHMarketplaceAccountType type;
/**
* Wrap up gh marketplace account.
*
* @param root
* the root
* @return an instance of the GHMarketplaceAccount class
*/
GHMarketplaceAccount wrapUp(GitHub root) {
this.root = root;
return this;
}
/**
* Gets url.
*
* @return the url
*/
public URL getUrl() {
return GitHub.parseURL(url);
}
/**
* Gets id.
*
* @return the id
*/
public long getId() {
return id;
}
/**
* Gets login.
*
* @return the login
*/
public String getLogin() {
return login;
}
/**
* Gets email.
*
* @return the email
*/
public String getEmail() {
return email;
}
/**
* Gets organization billing email.
*
* @return the organization billing email
*/
public String getOrganizationBillingEmail() {
return organizationBillingEmail;
}
/**
* Gets type.
*
* @return the type
*/
public GHMarketplaceAccountType getType() {
return type;
}
}

View File

@@ -0,0 +1,53 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* A Github Marketplace Account Plan.
*
* @author Paulo Miguel Almeida
* @see GHMarketplaceListAccountBuilder#createRequest()
*/
public class GHMarketplaceAccountPlan extends GHMarketplaceAccount {
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Field comes from JSON deserialization")
private GHMarketplacePendingChange marketplacePendingChange;
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Field comes from JSON deserialization")
private GHMarketplacePurchase marketplacePurchase;
/**
* Wrap up gh marketplace account.
*
* @param root
* the root
* @return an instance of the GHMarketplaceAccount class
*/
GHMarketplaceAccountPlan wrapUp(GitHub root) {
super.wrapUp(root);
if (this.marketplacePendingChange != null)
this.marketplacePendingChange.wrapUp(this.root);
if (this.marketplacePurchase != null)
this.marketplacePurchase.wrapUp(this.root);
return this;
}
/**
* Gets marketplace pending change.
*
* @return the marketplace pending change
*/
public GHMarketplacePendingChange getMarketplacePendingChange() {
return marketplacePendingChange;
}
/**
* Gets marketplace purchase.
*
* @return the marketplace purchase
*/
public GHMarketplacePurchase getMarketplacePurchase() {
return marketplacePurchase;
}
}

View File

@@ -0,0 +1,22 @@
package org.kohsuke.github;
import org.apache.commons.lang3.StringUtils;
import java.util.Locale;
/**
* GitHub Marketplace Account type.
*
* @author Paulo Miguel Almeida
* @see GHMarketplaceAccount
*/
public enum GHMarketplaceAccountType {
ORGANIZATION, USER;
/**
* Returns GitHub's internal representation of this event.
*/
String symbol() {
return StringUtils.capitalize(name().toLowerCase(Locale.ENGLISH));
}
}

View File

@@ -0,0 +1,71 @@
package org.kohsuke.github;
import java.io.IOException;
/**
* Returns any accounts associated with a plan, including free plans
*
* @author Paulo Miguel Almeida
* @see GHMarketplacePlan#listAccounts()
*/
public class GHMarketplaceListAccountBuilder {
private final GitHub root;
private final Requester builder;
private final long planId;
GHMarketplaceListAccountBuilder(GitHub root, long planId) {
this.root = root;
this.builder = root.createRequest();
this.planId = planId;
}
/**
* Sorts the GitHub accounts by the date they were created or last updated. Can be one of created or updated.
* <p>
* If omitted, the default sorting strategy will be "CREATED"
*
* @param sort
* the sort strategy
* @return a GHMarketplaceListAccountBuilder
*/
public GHMarketplaceListAccountBuilder sort(Sort sort) {
this.builder.with("sort", sort);
return this;
}
/**
* Orders the GitHub accounts results, Can be one of asc or desc. Ignored without the sort parameter.
*
* @param direction
* the order strategy
* @return a GHMarketplaceListAccountBuilder
*/
public GHMarketplaceListAccountBuilder direction(GHDirection direction) {
this.builder.with("direction", direction);
return this;
}
/**
* The enum Sort.
*/
public enum Sort {
CREATED, UPDATED
}
/**
* List any accounts associated with the plan specified on construction with all the order/sort parameters set.
* <p>
* GitHub Apps must use a JWT to access this endpoint.
* <p>
* OAuth Apps must use basic authentication with their client ID and client secret to access this endpoint.
*
* @return a paged iterable instance of GHMarketplaceAccountPlan
* @throws IOException
* on error
*/
public PagedIterable<GHMarketplaceAccountPlan> createRequest() throws IOException {
return builder.withUrlPath(String.format("/marketplace_listing/plans/%d/accounts", this.planId))
.toIterable(GHMarketplaceAccountPlan[].class, item -> item.wrapUp(root));
}
}

View File

@@ -0,0 +1,74 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Date;
/**
* A Github Marketplace purchase pending change.
*
* @author Paulo Miguel Almeida
* @see GHMarketplaceListAccountBuilder#createRequest()
*/
public class GHMarketplacePendingChange {
private GitHub root;
private long id;
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Field comes from JSON deserialization")
private Long unitCount;
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Field comes from JSON deserialization")
private GHMarketplacePlan plan;
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Field comes from JSON deserialization")
private String effectiveDate;
/**
* Wrap up gh marketplace pending change.
*
* @param root
* the root
* @return an instance of the GHMarketplacePendingChange class
*/
GHMarketplacePendingChange wrapUp(GitHub root) {
this.root = root;
if (plan != null) { // sanity check
this.plan.wrapUp(this.root);
}
return this;
}
/**
* Gets id.
*
* @return the id
*/
public long getId() {
return id;
}
/**
* Gets unit count.
*
* @return the unit count
*/
public Long getUnitCount() {
return unitCount;
}
/**
* Gets plan.
*
* @return the plan
*/
public GHMarketplacePlan getPlan() {
return plan;
}
/**
* Gets effective date.
*
* @return the effective date
*/
public Date getEffectiveDate() {
return GitHub.parseDate(effectiveDate);
}
}

View File

@@ -0,0 +1,184 @@
package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.net.URL;
import java.util.List;
/**
* A Github Marketplace plan.
*
* @author Paulo Miguel Almeida
* @see GitHub#listMarketplacePlans()
*/
public class GHMarketplacePlan {
private GitHub root;
private String url;
private String accountsUrl;
private long id;
private long number;
private String name;
private String description;
private long monthlyPriceInCents;
private long yearlyPriceInCents;
private GHMarketplacePriceModel priceModel;
@JsonProperty("has_free_trial")
private boolean freeTrial; // JavaBeans Spec 1.01 section 8.3.2 forces us to have is<propertyName>
private String unitName;
private String state;
private List<String> bullets;
/**
* Wrap up gh marketplace plan.
*
* @param root
* the root
* @return an instance of the GHMarketplacePlan class
*/
GHMarketplacePlan wrapUp(GitHub root) {
this.root = root;
return this;
}
/**
* Gets url.
*
* @return the url
*/
public URL getUrl() {
return GitHub.parseURL(url);
}
/**
* Gets accounts url.
*
* @return the accounts url
*/
public String getAccountsUrl() {
return accountsUrl;
}
/**
* Gets id.
*
* @return the id
*/
public long getId() {
return id;
}
/**
* Gets number.
*
* @return the number
*/
public long getNumber() {
return number;
}
/**
* Gets name.
*
* @return the name
*/
public String getName() {
return name;
}
/**
* Gets description.
*
* @return the description
*/
public String getDescription() {
return description;
}
/**
* Gets monthly price in cents.
*
* @return the monthly price in cents
*/
public long getMonthlyPriceInCents() {
return monthlyPriceInCents;
}
/**
* Gets yearly price in cents.
*
* @return the yearly price in cents
*/
public long getYearlyPriceInCents() {
return yearlyPriceInCents;
}
/**
* Gets price model.
*
* @return the price model
*/
public GHMarketplacePriceModel getPriceModel() {
return priceModel;
}
/**
* Is free trial boolean.
*
* @return the boolean
*/
public boolean isFreeTrial() {
return freeTrial;
}
/**
* Gets unit name.
*
* @return the unit name
*/
public String getUnitName() {
return unitName;
}
/**
* Gets state.
*
* @return the state
*/
public String getState() {
return state;
}
/**
* Gets bullets.
*
* @return the bullets
*/
public List<String> getBullets() {
return bullets;
}
/**
* Starts a builder that list any accounts associated with a plan, including free plans. For per-seat pricing, you
* see the list of accounts that have purchased the plan, including the number of seats purchased. When someone
* submits a plan change that won't be processed until the end of their billing cycle, you will also see the
* upcoming pending change.
*
* <p>
* You use the returned builder to set various properties, then call
* {@link GHMarketplaceListAccountBuilder#createRequest()} to finally list the accounts related to this plan.
*
* <p>
* GitHub Apps must use a JWT to access this endpoint.
* <p>
* OAuth Apps must use basic authentication with their client ID and client secret to access this endpoint.
*
* @return a GHMarketplaceListAccountBuilder instance
* @see <a href=
* "https://developer.github.com/v3/apps/marketplace/#list-all-github-accounts-user-or-organization-on-a-specific-plan">List
* all GitHub accounts (user or organization) on a specific plan</a>
*/
public GHMarketplaceListAccountBuilder listAccounts() {
return new GHMarketplaceListAccountBuilder(root, this.id);
}
}

View File

@@ -0,0 +1,29 @@
package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonValue;
/**
* GitHub Marketplace plan pricing model.
*
* @author Paulo Miguel Almeida
* @see GHMarketplacePlan
*/
public enum GHMarketplacePriceModel {
FREE("free"), PER_UNIT("per-unit"), FLAT_RATE("flat-rate");
@JsonValue
private final String internalName;
GHMarketplacePriceModel(String internalName) {
this.internalName = internalName;
}
/**
* Returns GitHub's internal representation of this event.
*
* @return a string containing GitHub's internal representation of this event.
*/
public String symbol() {
return internalName;
}
}

View File

@@ -0,0 +1,102 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Date;
/**
* A Github Marketplace purchase.
*
* @author Paulo Miguel Almeida
* @see GHMarketplaceListAccountBuilder#createRequest() GHMarketplaceListAccountBuilder#createRequest()
*/
public class GHMarketplacePurchase {
private GitHub root;
private String billingCycle;
private String nextBillingDate;
private boolean onFreeTrial;
private String freeTrialEndsOn;
private Long unitCount;
private String updatedAt;
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Field comes from JSON deserialization")
private GHMarketplacePlan plan;
/**
* Wrap up gh marketplace purchase.
*
* @param root
* the root
* @return an instance of the GHMarketplacePurchase class
*/
GHMarketplacePurchase wrapUp(GitHub root) {
this.root = root;
if (plan != null) { // sanity check
this.plan.wrapUp(this.root);
}
return this;
}
/**
* Gets billing cycle.
*
* @return the billing cycle
*/
public String getBillingCycle() {
return billingCycle;
}
/**
* Gets next billing date.
*
* @return the next billing date
*/
public Date getNextBillingDate() {
return GitHub.parseDate(nextBillingDate);
}
/**
* Is on free trial boolean.
*
* @return the boolean
*/
public boolean isOnFreeTrial() {
return onFreeTrial;
}
/**
* Gets free trial ends on.
*
* @return the free trial ends on
*/
public Date getFreeTrialEndsOn() {
return GitHub.parseDate(freeTrialEndsOn);
}
/**
* Gets unit count.
*
* @return the unit count
*/
public Long getUnitCount() {
return unitCount;
}
/**
* Gets updated at.
*
* @return the updated at
*/
public Date getUpdatedAt() {
return GitHub.parseDate(updatedAt);
}
/**
* Gets plan.
*
* @return the plan
*/
public GHMarketplacePlan getPlan() {
return plan;
}
}

View File

@@ -0,0 +1,113 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Date;
/**
* Github Marketplace User Purchase
*
* @author Paulo Miguel Almeida
* @see GitHub#getMyMarketplacePurchases()
*/
public class GHMarketplaceUserPurchase {
protected GitHub root;
private String billingCycle;
private String nextBillingDate;
private boolean onFreeTrial;
private String freeTrialEndsOn;
private Long unitCount;
private String updatedAt;
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Field comes from JSON deserialization")
private GHMarketplaceAccount account;
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "Field comes from JSON deserialization")
private GHMarketplacePlan plan;
/**
* Wrap up GHMarketplaceUserPurchase.
*
* @param root
* the root
* @return an instance of the GHMarketplaceUserPurchase class
*/
GHMarketplaceUserPurchase wrapUp(GitHub root) {
this.root = root;
if (this.account != null)
this.account.wrapUp(this.root);
if (this.plan != null)
this.plan.wrapUp(this.root);
return this;
}
/**
* Gets billing cycle.
*
* @return the billing cycle
*/
public String getBillingCycle() {
return billingCycle;
}
/**
* Gets next billing date.
*
* @return the next billing date
*/
public Date getNextBillingDate() {
return GitHub.parseDate(nextBillingDate);
}
/**
* Is on free trial boolean.
*
* @return the boolean
*/
public boolean isOnFreeTrial() {
return onFreeTrial;
}
/**
* Gets free trial ends on.
*
* @return the free trial ends on
*/
public Date getFreeTrialEndsOn() {
return GitHub.parseDate(freeTrialEndsOn);
}
/**
* Gets unit count.
*
* @return the unit count
*/
public Long getUnitCount() {
return unitCount;
}
/**
* Gets updated at.
*
* @return the updated at
*/
public Date getUpdatedAt() {
return GitHub.parseDate(updatedAt);
}
/**
* Gets account.
*
* @return the account
*/
public GHMarketplaceAccount getAccount() {
return account;
}
/**
* Gets plan.
*
* @return the plan
*/
public GHMarketplacePlan getPlan() {
return plan;
}
}

View File

@@ -72,7 +72,7 @@ public class GHMembership /* extends GHObject --- but it doesn't have id, create
* @see GHMyself#getMembership(GHOrganization) GHMyself#getMembership(GHOrganization)
*/
public void activate() throws IOException {
root.retrieve().method("PATCH").with("state", State.ACTIVE).to(url, this);
root.createRequest().method("PATCH").with("state", State.ACTIVE).withUrlPath(url).fetchInto(this);
}
GHMembership wrap(GitHub root) {

View File

@@ -155,11 +155,11 @@ public class GHMilestone extends GHObject {
* the io exception
*/
public void delete() throws IOException {
root.retrieve().method("DELETE").to(getApiRoute());
root.createRequest().method("DELETE").withUrlPath(getApiRoute()).send();
}
private void edit(String key, Object value) throws IOException {
new Requester(root).with(key, value).method("PATCH").to(getApiRoute());
root.createRequest().with(key, value).method("PATCH").withUrlPath(getApiRoute()).send();
}
/**

View File

@@ -71,7 +71,7 @@ public class GHMyself extends GHUser {
* the io exception
*/
public List<GHEmail> getEmails2() throws IOException {
GHEmail[] addresses = root.retrieve().to("/user/emails", GHEmail[].class);
GHEmail[] addresses = root.createRequest().withUrlPath("/user/emails").fetchArray(GHEmail[].class);
return Collections.unmodifiableList(Arrays.asList(addresses));
}
@@ -86,7 +86,8 @@ public class GHMyself extends GHUser {
* the io exception
*/
public List<GHKey> getPublicKeys() throws IOException {
return Collections.unmodifiableList(Arrays.asList(root.retrieve().to("/user/keys", GHKey[].class)));
return Collections.unmodifiableList(
Arrays.asList(root.createRequest().withUrlPath("/user/keys").fetchArray(GHKey[].class)));
}
/**
@@ -100,8 +101,8 @@ public class GHMyself extends GHUser {
* the io exception
*/
public List<GHVerifiedKey> getPublicVerifiedKeys() throws IOException {
return Collections.unmodifiableList(
Arrays.asList(root.retrieve().to("/users/" + getLogin() + "/keys", GHVerifiedKey[].class)));
return Collections.unmodifiableList(Arrays.asList(
root.createRequest().withUrlPath("/users/" + getLogin() + "/keys").fetchArray(GHVerifiedKey[].class)));
}
/**
@@ -114,7 +115,7 @@ public class GHMyself extends GHUser {
public GHPersonSet<GHOrganization> getAllOrganizations() throws IOException {
GHPersonSet<GHOrganization> orgs = new GHPersonSet<GHOrganization>();
Set<String> names = new HashSet<String>();
for (GHOrganization o : root.retrieve().to("/user/orgs", GHOrganization[].class)) {
for (GHOrganization o : root.createRequest().withUrlPath("/user/orgs").fetchArray(GHOrganization[].class)) {
if (names.add(o.getLogin())) // in case of rumoured duplicates in the data
orgs.add(root.getOrganization(o.getLogin()));
}
@@ -175,9 +176,10 @@ public class GHMyself extends GHUser {
* @return the paged iterable
*/
public PagedIterable<GHRepository> listRepositories(final int pageSize, final RepositoryListFilter repoType) {
return root.retrieve()
return root.createRequest()
.with("type", repoType)
.asPagedIterable("/user/repos", GHRepository[].class, item -> item.wrap(root))
.withUrlPath("/user/repos")
.toIterable(GHRepository[].class, item -> item.wrap(root))
.withPageSize(pageSize);
}
@@ -208,9 +210,10 @@ public class GHMyself extends GHUser {
* @return the paged iterable
*/
public PagedIterable<GHMembership> listOrgMemberships(final GHMembership.State state) {
return root.retrieve()
return root.createRequest()
.with("state", state)
.asPagedIterable("/user/memberships/orgs", GHMembership[].class, item -> item.wrap(root));
.withUrlPath("/user/memberships/orgs")
.toIterable(GHMembership[].class, item -> item.wrap(root));
}
/**
@@ -223,7 +226,10 @@ public class GHMyself extends GHUser {
* the io exception
*/
public GHMembership getMembership(GHOrganization o) throws IOException {
return root.retrieve().to("/user/memberships/orgs/" + o.getLogin(), GHMembership.class).wrap(root);
return root.createRequest()
.withUrlPath("/user/memberships/orgs/" + o.getLogin())
.fetch(GHMembership.class)
.wrap(root);
}
// public void addEmails(Collection<String> emails) throws IOException {

View File

@@ -101,7 +101,7 @@ public class GHNotificationStream implements Iterable<GHThread> {
*/
public Iterator<GHThread> iterator() {
// capture the configuration setting here
final Requester req = new Requester(root).method("GET")
final Requester req = root.createRequest()
.with("all", all)
.with("participating", participating)
.with("since", since);
@@ -180,7 +180,7 @@ public class GHNotificationStream implements Iterable<GHThread> {
req.setHeader("If-Modified-Since", lastModified);
threads = req.to(apiUrl, GHThread[].class);
threads = req.withUrlPath(apiUrl).fetchArray(GHThread[].class);
if (threads == null) {
threads = EMPTY_ARRAY; // if unmodified, we get empty array
} else {
@@ -232,10 +232,10 @@ public class GHNotificationStream implements Iterable<GHThread> {
* the io exception
*/
public void markAsRead(long timestamp) throws IOException {
final Requester req = new Requester(root).method("PUT");
final Requester req = root.createRequest();
if (timestamp >= 0)
req.with("last_read_at", GitHub.printDate(new Date(timestamp)));
req.asHttpStatusCode(apiUrl);
req.withUrlPath(apiUrl).fetchHttpStatusCode();
}
private static final GHThread[] EMPTY_ARRAY = new GHThread[0];

View File

@@ -121,10 +121,9 @@ public class GHOrganization extends GHPerson {
* the io exception
*/
public PagedIterable<GHTeam> listTeams() throws IOException {
return root.retrieve()
.asPagedIterable(String.format("/orgs/%s/teams", login),
GHTeam[].class,
item -> item.wrapUp(GHOrganization.this));
return root.createRequest()
.withUrlPath(String.format("/orgs/%s/teams", login))
.toIterable(GHTeam[].class, item -> item.wrapUp(this));
}
/**
@@ -183,10 +182,11 @@ public class GHOrganization extends GHPerson {
* "https://developer.github.com/v3/orgs/members/#add-or-update-organization-membership">documentation</a>
*/
public void add(GHUser user, Role role) throws IOException {
root.retrieve()
root.createRequest()
.method("PUT")
.with("role", role.name().toLowerCase())
.to("/orgs/" + login + "/memberships/" + user.getLogin());
.withUrlPath("/orgs/" + login + "/memberships/" + user.getLogin())
.send();
}
/**
@@ -198,7 +198,7 @@ public class GHOrganization extends GHPerson {
*/
public boolean hasMember(GHUser user) {
try {
root.retrieve().to("/orgs/" + login + "/members/" + user.getLogin());
root.createRequest().withUrlPath("/orgs/" + login + "/members/" + user.getLogin()).send();
return true;
} catch (IOException ignore) {
return false;
@@ -215,7 +215,7 @@ public class GHOrganization extends GHPerson {
* the io exception
*/
public void remove(GHUser user) throws IOException {
root.retrieve().method("DELETE").to("/orgs/" + login + "/members/" + user.getLogin());
root.createRequest().method("DELETE").withUrlPath("/orgs/" + login + "/members/" + user.getLogin()).send();
}
/**
@@ -227,7 +227,7 @@ public class GHOrganization extends GHPerson {
*/
public boolean hasPublicMember(GHUser user) {
try {
root.retrieve().to("/orgs/" + login + "/public_members/" + user.getLogin());
root.createRequest().withUrlPath("/orgs/" + login + "/public_members/" + user.getLogin()).send();
return true;
} catch (IOException ignore) {
return false;
@@ -243,7 +243,7 @@ public class GHOrganization extends GHPerson {
* the io exception
*/
public void publicize(GHUser u) throws IOException {
root.retrieve().method("PUT").to("/orgs/" + login + "/public_members/" + u.getLogin(), null);
root.createRequest().method("PUT").withUrlPath("/orgs/" + login + "/public_members/" + u.getLogin()).send();
}
/**
@@ -299,10 +299,9 @@ public class GHOrganization extends GHPerson {
private PagedIterable<GHUser> listMembers(final String suffix, final String filter) throws IOException {
String filterParams = (filter == null) ? "" : ("?filter=" + filter);
return root.retrieve()
.asPagedIterable(String.format("/orgs/%s/%s%s", login, suffix, filterParams),
GHUser[].class,
item -> item.wrapUp(root));
return root.createRequest()
.withUrlPath(String.format("/orgs/%s/%s%s", login, suffix, filterParams))
.toIterable(GHUser[].class, item -> item.wrapUp(root));
}
/**
@@ -314,7 +313,7 @@ public class GHOrganization extends GHPerson {
* the io exception
*/
public void conceal(GHUser u) throws IOException {
root.retrieve().method("DELETE").to("/orgs/" + login + "/public_members/" + u.getLogin(), null);
root.createRequest().method("DELETE").withUrlPath("/orgs/" + login + "/public_members/" + u.getLogin()).send();
}
/**
@@ -327,10 +326,11 @@ public class GHOrganization extends GHPerson {
* the io exception
*/
public PagedIterable<GHProject> listProjects(final GHProject.ProjectStateFilter status) throws IOException {
return root.retrieve()
return root.createRequest()
.withPreview(INERTIA)
.with("state", status)
.asPagedIterable(String.format("/orgs/%s/projects", login), GHProject[].class, item -> item.wrap(root));
.withUrlPath(String.format("/orgs/%s/projects", login))
.toIterable(GHProject[].class, item -> item.wrap(root));
}
/**
@@ -356,12 +356,13 @@ public class GHOrganization extends GHPerson {
* the io exception
*/
public GHProject createProject(String name, String body) throws IOException {
return root.retrieve()
return root.createRequest()
.method("POST")
.withPreview(INERTIA)
.with("name", name)
.with("body", body)
.to(String.format("/orgs/%s/projects", login), GHProject.class)
.withUrlPath(String.format("/orgs/%s/projects", login))
.fetch(GHProject.class)
.wrap(root);
}
@@ -389,13 +390,13 @@ public class GHOrganization extends GHPerson {
*/
@Deprecated
public GHTeam createTeam(String name, Permission p, Collection<GHRepository> repositories) throws IOException {
Requester post = new Requester(root).with("name", name).with("permission", p);
Requester post = root.createRequest().method("POST").with("name", name).with("permission", p);
List<String> repo_names = new ArrayList<String>();
for (GHRepository r : repositories) {
repo_names.add(login + "/" + r.getName());
}
post.with("repo_names", repo_names);
return post.method("POST").to("/orgs/" + login + "/teams", GHTeam.class).wrapUp(this);
return post.withUrlPath("/orgs/" + login + "/teams").fetch(GHTeam.class).wrapUp(this);
}
/**
@@ -430,13 +431,13 @@ public class GHOrganization extends GHPerson {
* the io exception
*/
public GHTeam createTeam(String name, Collection<GHRepository> repositories) throws IOException {
Requester post = new Requester(root).with("name", name);
Requester post = root.createRequest().method("POST").with("name", name);
List<String> repo_names = new ArrayList<String>();
for (GHRepository r : repositories) {
repo_names.add(login + "/" + r.getName());
}
post.with("repo_names", repo_names);
return post.method("POST").to("/orgs/" + login + "/teams", GHTeam.class).wrapUp(this);
return post.withUrlPath("/orgs/" + login + "/teams").fetch(GHTeam.class).wrapUp(this);
}
/**
@@ -495,10 +496,9 @@ public class GHOrganization extends GHPerson {
* Lists events performed by a user (this includes private events if the caller is authenticated.
*/
public PagedIterable<GHEventInfo> listEvents() throws IOException {
return root.retrieve()
.asPagedIterable(String.format("/orgs/%s/events", login),
GHEventInfo[].class,
item -> item.wrapUp(root));
return root.createRequest()
.withUrlPath(String.format("/orgs/%s/events", login))
.toIterable(GHEventInfo[].class, item -> item.wrapUp(root));
}
/**
@@ -511,8 +511,9 @@ public class GHOrganization extends GHPerson {
*/
@Override
public PagedIterable<GHRepository> listRepositories(final int pageSize) {
return root.retrieve()
.asPagedIterable("/orgs/" + login + "/repos", GHRepository[].class, item -> item.wrap(root))
return root.createRequest()
.withUrlPath("/orgs/" + login + "/repos")
.toIterable(GHRepository[].class, item -> item.wrap(root))
.withPageSize(pageSize);
}

View File

@@ -23,9 +23,10 @@ public abstract class GHPerson extends GHObject {
protected String login, avatar_url, gravatar_id;
// other fields (that only show up in full data)
protected String location, blog, email, name, company;
protected String location, blog, email, name, company, type;
protected String html_url;
protected int followers, following, public_repos, public_gists;
protected boolean site_admin;
GHPerson wrapUp(GitHub root) {
this.root = root;
@@ -47,7 +48,7 @@ public abstract class GHPerson extends GHObject {
if (root == null || root.isOffline()) {
return; // cannot populate, will have to live with what we have
}
root.retrieve().to(url, this);
root.createRequest().withUrlPath(url).fetchInto(this);
}
/**
@@ -88,8 +89,9 @@ public abstract class GHPerson extends GHObject {
* @return the paged iterable
*/
public PagedIterable<GHRepository> listRepositories(final int pageSize) {
return root.retrieve()
.asPagedIterable("/users/" + login + "/repos", GHRepository[].class, item -> item.wrap(root))
return root.createRequest()
.withUrlPath("/users/" + login + "/repos")
.toIterable(GHRepository[].class, item -> item.wrap(root))
.withPageSize(pageSize);
}
@@ -112,8 +114,9 @@ public abstract class GHPerson extends GHObject {
public synchronized Iterable<List<GHRepository>> iterateRepositories(final int pageSize) {
return new Iterable<List<GHRepository>>() {
public Iterator<List<GHRepository>> iterator() {
final Iterator<GHRepository[]> pager = root.retrieve()
.asIterator("/users/" + login + "/repos", GHRepository[].class, pageSize);
final Iterator<GHRepository[]> pager = root.createRequest()
.withUrlPath("users", login, "repos")
.asIterator(GHRepository[].class, pageSize);
return new Iterator<List<GHRepository>>() {
public boolean hasNext() {
@@ -146,7 +149,10 @@ public abstract class GHPerson extends GHObject {
*/
public GHRepository getRepository(String name) throws IOException {
try {
return root.retrieve().to("/repos/" + login + '/' + name, GHRepository.class).wrap(root);
return root.createRequest()
.withUrlPath("/repos/" + login + '/' + name)
.fetch(GHRepository.class)
.wrap(root);
} catch (FileNotFoundException e) {
return null;
}
@@ -316,4 +322,28 @@ public abstract class GHPerson extends GHObject {
populate();
return followers;
}
/**
* Gets the type. This is either "User" or "Organization".
*
* @return the type
* @throws IOException
* the io exception
*/
public String getType() throws IOException {
populate();
return type;
}
/**
* Gets the site_admin field
*
* @return the site_admin field
* @throws IOException
* the io exception
*/
public boolean isSiteAdmin() throws IOException {
populate();
return site_admin;
}
}

View File

@@ -74,11 +74,17 @@ public class GHProject extends GHObject {
if (owner == null) {
try {
if (owner_url.contains("/orgs/")) {
owner = root.retrieve().to(getOwnerUrl().getPath(), GHOrganization.class).wrapUp(root);
owner = root.createRequest()
.withUrlPath(getOwnerUrl().getPath())
.fetch(GHOrganization.class)
.wrapUp(root);
} else if (owner_url.contains("/users/")) {
owner = root.retrieve().to(getOwnerUrl().getPath(), GHUser.class).wrapUp(root);
owner = root.createRequest().withUrlPath(getOwnerUrl().getPath()).fetch(GHUser.class).wrapUp(root);
} else if (owner_url.contains("/repos/")) {
owner = root.retrieve().to(getOwnerUrl().getPath(), GHRepository.class).wrap(root);
owner = root.createRequest()
.withUrlPath(getOwnerUrl().getPath())
.fetch(GHRepository.class)
.wrap(root);
}
} catch (FileNotFoundException e) {
return null;
@@ -176,7 +182,7 @@ public class GHProject extends GHObject {
}
private void edit(String key, Object value) throws IOException {
new Requester(root).withPreview(INERTIA).with(key, value).method("PATCH").to(getApiRoute());
root.createRequest().method("PATCH").withPreview(INERTIA).with(key, value).withUrlPath(getApiRoute()).send();
}
/**
@@ -270,7 +276,7 @@ public class GHProject extends GHObject {
* the io exception
*/
public void delete() throws IOException {
new Requester(root).withPreview(INERTIA).method("DELETE").to(getApiRoute());
root.createRequest().withPreview(INERTIA).method("DELETE").withUrlPath(getApiRoute()).send();
}
/**
@@ -282,11 +288,10 @@ public class GHProject extends GHObject {
*/
public PagedIterable<GHProjectColumn> listColumns() throws IOException {
final GHProject project = this;
return root.retrieve()
return root.createRequest()
.withPreview(INERTIA)
.asPagedIterable(String.format("/projects/%d/columns", id),
GHProjectColumn[].class,
item -> item.wrap(project));
.withUrlPath(String.format("/projects/%d/columns", id))
.toIterable(GHProjectColumn[].class, item -> item.wrap(project));
}
/**
@@ -299,11 +304,12 @@ public class GHProject extends GHObject {
* the io exception
*/
public GHProjectColumn createColumn(String name) throws IOException {
return root.retrieve()
return root.createRequest()
.method("POST")
.withPreview(INERTIA)
.with("name", name)
.to(String.format("/projects/%d/columns", id), GHProjectColumn.class)
.withUrlPath(String.format("/projects/%d/columns", id))
.fetch(GHProjectColumn.class)
.wrap(this);
}
}

View File

@@ -72,7 +72,7 @@ public class GHProjectCard extends GHObject {
public GHProject getProject() throws IOException {
if (project == null) {
try {
project = root.retrieve().to(getProjectUrl().getPath(), GHProject.class).wrap(root);
project = root.createRequest().withUrlPath(getProjectUrl().getPath()).fetch(GHProject.class).wrap(root);
} catch (FileNotFoundException e) {
return null;
}
@@ -90,7 +90,10 @@ public class GHProjectCard extends GHObject {
public GHProjectColumn getColumn() throws IOException {
if (column == null) {
try {
column = root.retrieve().to(getColumnUrl().getPath(), GHProjectColumn.class).wrap(root);
column = root.createRequest()
.withUrlPath(getColumnUrl().getPath())
.fetch(GHProjectColumn.class)
.wrap(root);
} catch (FileNotFoundException e) {
return null;
}
@@ -110,9 +113,12 @@ public class GHProjectCard extends GHObject {
return null;
try {
if (content_url.contains("/pulls")) {
return root.retrieve().to(getContentUrl().getPath(), GHPullRequest.class).wrap(root);
return root.createRequest()
.withUrlPath(getContentUrl().getPath())
.fetch(GHPullRequest.class)
.wrap(root);
} else {
return root.retrieve().to(getContentUrl().getPath(), GHIssue.class).wrap(root);
return root.createRequest().withUrlPath(getContentUrl().getPath()).fetch(GHIssue.class).wrap(root);
}
} catch (FileNotFoundException e) {
return null;
@@ -198,7 +204,7 @@ public class GHProjectCard extends GHObject {
}
private void edit(String key, Object value) throws IOException {
new Requester(root).withPreview(INERTIA).with(key, value).method("PATCH").to(getApiRoute());
root.createRequest().method("PATCH").withPreview(INERTIA).with(key, value).withUrlPath(getApiRoute()).send();
}
/**
@@ -217,6 +223,6 @@ public class GHProjectCard extends GHObject {
* the io exception
*/
public void delete() throws IOException {
new Requester(root).withPreview(INERTIA).method("DELETE").to(getApiRoute());
root.createRequest().withPreview(INERTIA).method("DELETE").withUrlPath(getApiRoute()).send();
}
}

View File

@@ -67,7 +67,7 @@ public class GHProjectColumn extends GHObject {
public GHProject getProject() throws IOException {
if (project == null) {
try {
project = root.retrieve().to(getProjectUrl().getPath(), GHProject.class).wrap(root);
project = root.createRequest().withUrlPath(getProjectUrl().getPath()).fetch(GHProject.class).wrap(root);
} catch (FileNotFoundException e) {
return null;
}
@@ -106,7 +106,7 @@ public class GHProjectColumn extends GHObject {
}
private void edit(String key, Object value) throws IOException {
new Requester(root).withPreview(INERTIA).with(key, value).method("PATCH").to(getApiRoute());
root.createRequest().method("PATCH").withPreview(INERTIA).with(key, value).withUrlPath(getApiRoute()).send();
}
/**
@@ -125,7 +125,7 @@ public class GHProjectColumn extends GHObject {
* the io exception
*/
public void delete() throws IOException {
new Requester(root).withPreview(INERTIA).method("DELETE").to(getApiRoute());
root.createRequest().withPreview(INERTIA).method("DELETE").withUrlPath(getApiRoute()).send();
}
/**
@@ -137,11 +137,10 @@ public class GHProjectColumn extends GHObject {
*/
public PagedIterable<GHProjectCard> listCards() throws IOException {
final GHProjectColumn column = this;
return root.retrieve()
return root.createRequest()
.withPreview(INERTIA)
.asPagedIterable(String.format("/projects/columns/%d/cards", id),
GHProjectCard[].class,
item -> item.wrap(column));
.withUrlPath(String.format("/projects/columns/%d/cards", id))
.toIterable(GHProjectCard[].class, item -> item.wrap(column));
}
/**
@@ -154,11 +153,12 @@ public class GHProjectColumn extends GHObject {
* the io exception
*/
public GHProjectCard createCard(String note) throws IOException {
return root.retrieve()
return root.createRequest()
.method("POST")
.withPreview(INERTIA)
.with("note", note)
.to(String.format("/projects/columns/%d/cards", id), GHProjectCard.class)
.withUrlPath(String.format("/projects/columns/%d/cards", id))
.fetch(GHProjectCard.class)
.wrap(this);
}
@@ -172,12 +172,13 @@ public class GHProjectColumn extends GHObject {
* the io exception
*/
public GHProjectCard createCard(GHIssue issue) throws IOException {
return root.retrieve()
return root.createRequest()
.method("POST")
.withPreview(INERTIA)
.with("content_type", issue instanceof GHPullRequest ? "PullRequest" : "Issue")
.with("content_id", issue.getId())
.to(String.format("/projects/columns/%d/cards", id), GHProjectCard.class)
.withUrlPath(String.format("/projects/columns/%d/cards", id))
.fetch(GHProjectCard.class)
.wrap(this);
}
}

View File

@@ -384,7 +384,7 @@ public class GHPullRequest extends GHIssue implements Refreshable {
if (root.isOffline()) {
return; // cannot populate, will have to live with what we have
}
root.retrieve().withPreview(SHADOW_CAT).to(url, this).wrapUp(owner);
root.createRequest().withPreview(SHADOW_CAT).withUrlPath(url).fetchInto(this).wrapUp(owner);
}
/**
@@ -393,8 +393,9 @@ public class GHPullRequest extends GHIssue implements Refreshable {
* @return the paged iterable
*/
public PagedIterable<GHPullRequestFileDetail> listFiles() {
return root.retrieve()
.asPagedIterable(String.format("%s/files", getApiRoute()), GHPullRequestFileDetail[].class, null);
return root.createRequest()
.withUrlPath(String.format("%s/files", getApiRoute()))
.toIterable(GHPullRequestFileDetail[].class, null);
}
/**
@@ -403,10 +404,9 @@ public class GHPullRequest extends GHIssue implements Refreshable {
* @return the paged iterable
*/
public PagedIterable<GHPullRequestReview> listReviews() {
return root.retrieve()
.asPagedIterable(String.format("%s/reviews", getApiRoute()),
GHPullRequestReview[].class,
item -> item.wrapUp(GHPullRequest.this));
return root.createRequest()
.withUrlPath(String.format("%s/reviews", getApiRoute()))
.toIterable(GHPullRequestReview[].class, item -> item.wrapUp(this));
}
/**
@@ -417,10 +417,9 @@ public class GHPullRequest extends GHIssue implements Refreshable {
* the io exception
*/
public PagedIterable<GHPullRequestReviewComment> listReviewComments() throws IOException {
return root.retrieve()
.asPagedIterable(getApiRoute() + COMMENTS_ACTION,
GHPullRequestReviewComment[].class,
item -> item.wrapUp(GHPullRequest.this));
return root.createRequest()
.withUrlPath(getApiRoute() + COMMENTS_ACTION)
.toIterable(GHPullRequestReviewComment[].class, item -> item.wrapUp(this));
}
/**
@@ -429,10 +428,9 @@ public class GHPullRequest extends GHIssue implements Refreshable {
* @return the paged iterable
*/
public PagedIterable<GHPullRequestCommitDetail> listCommits() {
return root.retrieve()
.asPagedIterable(String.format("%s/commits", getApiRoute()),
GHPullRequestCommitDetail[].class,
item -> item.wrapUp(GHPullRequest.this));
return root.createRequest()
.withUrlPath(String.format("%s/commits", getApiRoute()))
.toIterable(GHPullRequestCommitDetail[].class, item -> item.wrapUp(this));
}
/**
@@ -505,12 +503,14 @@ public class GHPullRequest extends GHIssue implements Refreshable {
*/
public GHPullRequestReviewComment createReviewComment(String body, String sha, String path, int position)
throws IOException {
return new Requester(root).method("POST")
return root.createRequest()
.method("POST")
.with("body", body)
.with("commit_id", sha)
.with("path", path)
.with("position", position)
.to(getApiRoute() + COMMENTS_ACTION, GHPullRequestReviewComment.class)
.withUrlPath(getApiRoute() + COMMENTS_ACTION)
.fetch(GHPullRequestReviewComment.class)
.wrapUp(this);
}
@@ -523,9 +523,11 @@ public class GHPullRequest extends GHIssue implements Refreshable {
* the io exception
*/
public void requestReviewers(List<GHUser> reviewers) throws IOException {
new Requester(root).method("POST")
root.createRequest()
.method("POST")
.with("reviewers", getLogins(reviewers))
.to(getApiRoute() + REQUEST_REVIEWERS);
.withUrlPath(getApiRoute() + REQUEST_REVIEWERS)
.send();
}
/**
@@ -541,7 +543,11 @@ public class GHPullRequest extends GHIssue implements Refreshable {
for (GHTeam team : teams) {
teamReviewers.add(team.getSlug());
}
new Requester(root).method("POST").with("team_reviewers", teamReviewers).to(getApiRoute() + REQUEST_REVIEWERS);
root.createRequest()
.method("POST")
.with("team_reviewers", teamReviewers)
.withUrlPath(getApiRoute() + REQUEST_REVIEWERS)
.send();
}
/**
@@ -589,11 +595,13 @@ public class GHPullRequest extends GHIssue implements Refreshable {
* the io exception
*/
public void merge(String msg, String sha, MergeMethod method) throws IOException {
new Requester(root).method("PUT")
root.createRequest()
.method("PUT")
.with("commit_message", msg)
.with("sha", sha)
.with("merge_method", method)
.to(getApiRoute() + "/merge");
.withUrlPath(getApiRoute() + "/merge")
.send();
}
/**
@@ -605,7 +613,7 @@ public class GHPullRequest extends GHIssue implements Refreshable {
private void fetchIssue() throws IOException {
if (!fetchedIssueDetails) {
new Requester(root).method("GET").to(getIssuesApiRoute(), this);
root.createRequest().withUrlPath(getIssuesApiRoute()).fetchInto(this);
fetchedIssueDetails = true;
}
}

View File

@@ -89,6 +89,7 @@ public class GHPullRequestQueryBuilder extends GHQueryBuilder<GHPullRequest> {
@Override
public PagedIterable<GHPullRequest> list() {
return req.withPreview(SHADOW_CAT)
.asPagedIterable(repo.getApiTailUrl("pulls"), GHPullRequest[].class, item -> item.wrapUp(repo));
.withUrlPath(repo.getApiTailUrl("pulls"))
.toIterable(GHPullRequest[].class, item -> item.wrapUp(repo));
}
}

View File

@@ -160,10 +160,12 @@ public class GHPullRequestReview extends GHObject {
* the io exception
*/
public void submit(String body, GHPullRequestReviewEvent event) throws IOException {
new Requester(owner.root).method("POST")
owner.root.createRequest()
.method("POST")
.with("body", body)
.with("event", event.action())
.to(getApiRoute() + "/events", this);
.withUrlPath(getApiRoute() + "/events")
.fetchInto(this);
this.body = body;
this.state = event.toState();
}
@@ -175,7 +177,7 @@ public class GHPullRequestReview extends GHObject {
* the io exception
*/
public void delete() throws IOException {
new Requester(owner.root).method("DELETE").to(getApiRoute());
owner.root.createRequest().method("DELETE").withUrlPath(getApiRoute()).send();
}
/**
@@ -187,7 +189,11 @@ public class GHPullRequestReview extends GHObject {
* the io exception
*/
public void dismiss(String message) throws IOException {
new Requester(owner.root).method("PUT").with("message", message).to(getApiRoute() + "/dismissals");
owner.root.createRequest()
.method("PUT")
.with("message", message)
.withUrlPath(getApiRoute() + "/dismissals")
.send();
state = GHPullRequestReviewState.DISMISSED;
}
@@ -199,9 +205,8 @@ public class GHPullRequestReview extends GHObject {
* the io exception
*/
public PagedIterable<GHPullRequestReviewComment> listReviewComments() throws IOException {
return owner.root.retrieve()
.asPagedIterable(getApiRoute() + "/comments",
GHPullRequestReviewComment[].class,
item -> item.wrapUp(owner));
return owner.root.createRequest()
.withUrlPath(getApiRoute() + "/comments")
.toIterable(GHPullRequestReviewComment[].class, item -> item.wrapUp(owner));
}
}

View File

@@ -17,7 +17,7 @@ public class GHPullRequestReviewBuilder {
GHPullRequestReviewBuilder(GHPullRequest pr) {
this.pr = pr;
this.builder = new Requester(pr.root);
this.builder = pr.root.createRequest();
}
// public GHPullRequestReview createReview(@Nullable String commitId, String body, GHPullRequestReviewEvent event,
@@ -91,7 +91,8 @@ public class GHPullRequestReviewBuilder {
public GHPullRequestReview create() throws IOException {
return builder.method("POST")
.with("comments", comments)
.to(pr.getApiRoute() + "/reviews", GHPullRequestReview.class)
.withUrlPath(pr.getApiRoute() + "/reviews")
.fetch(GHPullRequestReview.class)
.wrapUp(pr);
}

View File

@@ -163,7 +163,7 @@ public class GHPullRequestReviewComment extends GHObject implements Reactable {
* the io exception
*/
public void update(String body) throws IOException {
new Requester(owner.root).method("PATCH").with("body", body).to(getApiRoute(), this);
owner.root.createRequest().method("PATCH").with("body", body).withUrlPath(getApiRoute()).fetchInto(this);
this.body = body;
}
@@ -174,7 +174,7 @@ public class GHPullRequestReviewComment extends GHObject implements Reactable {
* the io exception
*/
public void delete() throws IOException {
new Requester(owner.root).method("DELETE").to(getApiRoute());
owner.root.createRequest().method("DELETE").withUrlPath(getApiRoute()).send();
}
/**
@@ -187,27 +187,33 @@ public class GHPullRequestReviewComment extends GHObject implements Reactable {
* the io exception
*/
public GHPullRequestReviewComment reply(String body) throws IOException {
return new Requester(owner.root).method("POST")
return owner.root.createRequest()
.method("POST")
.with("body", body)
.with("in_reply_to", getId())
.to(getApiRoute() + "/comments", GHPullRequestReviewComment.class)
.withUrlPath(getApiRoute() + "/comments")
.fetch(GHPullRequestReviewComment.class)
.wrapUp(owner);
}
@Preview
@Deprecated
public GHReaction createReaction(ReactionContent content) throws IOException {
return new Requester(owner.root).withPreview(SQUIRREL_GIRL)
return owner.root.createRequest()
.method("POST")
.withPreview(SQUIRREL_GIRL)
.with("content", content.getContent())
.to(getApiRoute() + "/reactions", GHReaction.class)
.withUrlPath(getApiRoute() + "/reactions")
.fetch(GHReaction.class)
.wrap(owner.root);
}
@Preview
@Deprecated
public PagedIterable<GHReaction> listReactions() {
return owner.root.retrieve()
return owner.root.createRequest()
.withPreview(SQUIRREL_GIRL)
.asPagedIterable(getApiRoute() + "/reactions", GHReaction[].class, item -> item.wrap(owner.root));
.withUrlPath(getApiRoute() + "/reactions")
.toIterable(GHReaction[].class, item -> item.wrap(owner.root));
}
}

View File

@@ -13,7 +13,7 @@ public abstract class GHQueryBuilder<T> {
GHQueryBuilder(GitHub root) {
this.root = root;
this.req = root.retrieve();
this.req = root.createRequest();
}
/**

View File

@@ -12,6 +12,7 @@ import java.util.Date;
import java.util.Objects;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import static java.util.logging.Level.FINEST;
@@ -41,7 +42,10 @@ public class GHRateLimit {
public int limit;
/**
* The time at which the current rate limit window resets in UTC epoch seconds. NOTE: that means to
* The time at which the current rate limit window resets in UTC epoch seconds. WARNING: this field was implemented
* using {@link Date#Date(long)} which expects UTC epoch milliseconds, so this Date instance is meaningless as a
* date. To use this field in any meaningful way, it must be converted to a long using {@link Date#getTime()}
* multiplied by 1000.
*
* @deprecated This value should never have been made public. Use {@link #getResetDate()}
*/
@@ -60,6 +64,7 @@ public class GHRateLimit {
@Nonnull
private final Record integrationManifest;
@Nonnull
static GHRateLimit Unknown() {
return new GHRateLimit(new UnknownLimitRecord(),
new UnknownLimitRecord(),
@@ -67,6 +72,7 @@ public class GHRateLimit {
new UnknownLimitRecord());
}
@Nonnull
static GHRateLimit fromHeaderRecord(Record header) {
return new GHRateLimit(header, new UnknownLimitRecord(), new UnknownLimitRecord(), new UnknownLimitRecord());
}
@@ -76,6 +82,12 @@ public class GHRateLimit {
@Nonnull @JsonProperty("search") Record search,
@Nonnull @JsonProperty("graphql") Record graphql,
@Nonnull @JsonProperty("integration_manifest") Record integrationManifest) {
// The Nonnull annotation is ignored by Jackson, we have to check manually
Objects.requireNonNull(core);
Objects.requireNonNull(search);
Objects.requireNonNull(graphql);
Objects.requireNonNull(integrationManifest);
this.core = core;
this.search = search;
this.graphql = graphql;
@@ -84,6 +96,7 @@ public class GHRateLimit {
// Deprecated fields
this.remaining = core.getRemaining();
this.limit = core.getLimit();
// This is wrong but is how this was implemented. Kept for backward compat.
this.reset = new Date(core.getResetEpochSeconds());
}
@@ -270,9 +283,9 @@ public class GHRateLimit {
* the reset epoch seconds
*/
@JsonCreator
public Record(@JsonProperty("limit") int limit,
@JsonProperty("remaining") int remaining,
@JsonProperty("reset") long resetEpochSeconds) {
public Record(@JsonProperty(value = "limit", required = true) int limit,
@JsonProperty(value = "remaining", required = true) int remaining,
@JsonProperty(value = "reset", required = true) long resetEpochSeconds) {
this(limit, remaining, resetEpochSeconds, null);
}
@@ -289,7 +302,7 @@ public class GHRateLimit {
* the updated at
*/
@SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD", justification = "Deprecated")
public Record(int limit, int remaining, long resetEpochSeconds, String updatedAt) {
public Record(int limit, int remaining, long resetEpochSeconds, @CheckForNull String updatedAt) {
this.limit = limit;
this.remaining = remaining;
this.resetEpochSeconds = resetEpochSeconds;
@@ -304,7 +317,7 @@ public class GHRateLimit {
* a string date in RFC 1123
* @return reset date based on the passed date
*/
Date recalculateResetDate(String updatedAt) {
Date recalculateResetDate(@CheckForNull String updatedAt) {
long updatedAtEpochSeconds = createdAtEpochSeconds;
if (!StringUtils.isBlank(updatedAt)) {
try {
@@ -319,7 +332,7 @@ public class GHRateLimit {
}
// This may seem odd but it results in an accurate or slightly pessimistic reset date
// based on system time rather than on the system being in sync with the server
// based on system time rather than assuming the system time synchronized with the server
long calculatedSecondsUntilReset = resetEpochSeconds - updatedAtEpochSeconds;
return resetDate = new Date((createdAtEpochSeconds + calculatedSecondsUntilReset) * 1000);
}
@@ -352,7 +365,7 @@ public class GHRateLimit {
}
/**
* Whether the rate limit reset date indicated by this instance is in the
* Whether the rate limit reset date indicated by this instance is expired
*
* @return true if the rate limit reset date has passed. Otherwise false.
*/

View File

@@ -58,6 +58,6 @@ public class GHReaction extends GHObject {
* the io exception
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").withPreview(SQUIRREL_GIRL).to("/reactions/" + id);
root.createRequest().method("DELETE").withPreview(SQUIRREL_GIRL).withUrlPath("/reactions/" + id).send();
}
}

View File

@@ -66,7 +66,13 @@ public class GHRef {
* the io exception
*/
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);
root.createRequest()
.method("PATCH")
.with("sha", sha)
.with("force", force)
.withUrlPath(url)
.fetch(GHRef.class)
.wrap(root);
}
/**
@@ -76,7 +82,7 @@ public class GHRef {
* the io exception
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").to(url);
root.createRequest().method("DELETE").withUrlPath(url).send();
}
GHRef wrap(GitHub root) {

View File

@@ -240,12 +240,12 @@ public class GHRelease extends GHObject {
* the io exception
*/
public GHAsset uploadAsset(String filename, InputStream stream, String contentType) throws IOException {
Requester builder = new Requester(owner.root);
Requester builder = owner.root.createRequest().method("POST");
String url = getUploadUrl();
// strip the helpful garbage from the url
url = url.substring(0, url.indexOf('{'));
url += "?name=" + URLEncoder.encode(filename, "UTF-8");
return builder.contentType(contentType).with(stream).to(url, GHAsset.class).wrap(this);
return builder.contentType(contentType).with(stream).withUrlPath(url).fetch(GHAsset.class).wrap(this);
}
/**
@@ -256,9 +256,9 @@ public class GHRelease extends GHObject {
* the io exception
*/
public List<GHAsset> getAssets() throws IOException {
Requester builder = new Requester(owner.root);
Requester builder = owner.root.createRequest();
GHAsset[] assets = builder.method("GET").to(getApiTailUrl("assets"), GHAsset[].class);
GHAsset[] assets = builder.withUrlPath(getApiTailUrl("assets")).fetchArray(GHAsset[].class);
return Arrays.asList(GHAsset.wrap(assets, this));
}
@@ -269,7 +269,7 @@ public class GHRelease extends GHObject {
* the io exception
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").to(owner.getApiTailUrl("releases/" + id));
root.createRequest().method("DELETE").withUrlPath(owner.getApiTailUrl("releases/" + id)).send();
}
/**

View File

@@ -21,7 +21,7 @@ public class GHReleaseBuilder {
*/
public GHReleaseBuilder(GHRepository ghRepository, String tag) {
this.repo = ghRepository;
this.builder = new Requester(repo.root);
this.builder = repo.root.createRequest().method("POST");
builder.with("tag_name", tag);
}
@@ -95,6 +95,6 @@ public class GHReleaseBuilder {
* the io exception
*/
public GHRelease create() throws IOException {
return builder.to(repo.getApiTailUrl("releases"), GHRelease.class).wrap(repo);
return builder.withUrlPath(repo.getApiTailUrl("releases")).fetch(GHRelease.class).wrap(repo);
}
}

View File

@@ -14,7 +14,7 @@ public class GHReleaseUpdater {
GHReleaseUpdater(GHRelease base) {
this.base = base;
this.builder = new Requester(base.root);
this.builder = base.root.createRequest();
}
/**
@@ -100,7 +100,8 @@ public class GHReleaseUpdater {
*/
public GHRelease update() throws IOException {
return builder.method("PATCH")
.to(base.owner.getApiTailUrl("releases/" + base.id), GHRelease.class)
.withUrlPath(base.owner.getApiTailUrl("releases/" + base.id))
.fetch(GHRelease.class)
.wrap(base.owner);
}

View File

@@ -134,13 +134,13 @@ public class GHRepository extends GHObject {
* @return the paged iterable
*/
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 root.retrieve()
.asPagedIterable(deploymentsUrl, GHDeployment[].class, item -> item.wrap(GHRepository.this));
return root.createRequest()
.with("sha", sha)
.with("ref", ref)
.with("task", task)
.with("environment", environment)
.withUrlPath(getApiTailUrl("deployments"))
.toIterable(GHDeployment[].class, item -> item.wrap(this));
}
/**
@@ -153,21 +153,10 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHDeployment getDeployment(long id) throws IOException {
return root.retrieve().to(getApiTailUrl("deployments/" + id), GHDeployment.class).wrap(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;
return root.createRequest()
.withUrlPath(getApiTailUrl("deployments/" + id))
.fetch(GHDeployment.class)
.wrap(this);
}
/**
@@ -345,7 +334,7 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHIssue getIssue(int id) throws IOException {
return root.retrieve().to(getApiTailUrl("issues/" + id), GHIssue.class).wrap(this);
return root.createRequest().withUrlPath(getApiTailUrl("issues/" + id)).fetch(GHIssue.class).wrap(this);
}
/**
@@ -384,10 +373,11 @@ public class GHRepository extends GHObject {
* the io exception
*/
public List<GHIssue> getIssues(GHIssueState state, GHMilestone milestone) throws IOException {
return Arrays.asList(GHIssue.wrap(root.retrieve()
Requester requester = root.createRequest()
.with("state", state)
.with("milestone", milestone == null ? "none" : "" + milestone.getNumber())
.to(getApiTailUrl("issues"), GHIssue[].class), this));
.with("milestone", milestone == null ? "none" : "" + milestone.getNumber());
return Arrays
.asList(GHIssue.wrap(requester.withUrlPath(getApiTailUrl("issues")).fetchArray(GHIssue[].class), this));
}
/**
@@ -398,9 +388,10 @@ public class GHRepository extends GHObject {
* @return the paged iterable
*/
public PagedIterable<GHIssue> listIssues(final GHIssueState state) {
return root.retrieve()
return root.createRequest()
.with("state", state)
.asPagedIterable(getApiTailUrl("issues"), GHIssue[].class, item -> item.wrap(GHRepository.this));
.withUrlPath(getApiTailUrl("issues"))
.toIterable(GHIssue[].class, item -> item.wrap(this));
}
/**
@@ -427,10 +418,12 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHRef createRef(String name, String sha) throws IOException {
return new Requester(root).with("ref", name)
.with("sha", sha)
return root.createRequest()
.method("POST")
.to(getApiTailUrl("git/refs"), GHRef.class)
.with("ref", name)
.with("sha", sha)
.withUrlPath(getApiTailUrl("git/refs"))
.fetch(GHRef.class)
.wrap(root);
}
@@ -457,7 +450,7 @@ public class GHRepository extends GHObject {
*/
public GHRelease getRelease(long id) throws IOException {
try {
return root.retrieve().to(getApiTailUrl("releases/" + id), GHRelease.class).wrap(this);
return root.createRequest().withUrlPath(getApiTailUrl("releases/" + id)).fetch(GHRelease.class).wrap(this);
} catch (FileNotFoundException e) {
return null; // no release for this id
}
@@ -474,7 +467,10 @@ public class GHRepository extends GHObject {
*/
public GHRelease getReleaseByTagName(String tag) throws IOException {
try {
return root.retrieve().to(getApiTailUrl("releases/tags/" + tag), GHRelease.class).wrap(this);
return root.createRequest()
.withUrlPath(getApiTailUrl("releases/tags/" + tag))
.fetch(GHRelease.class)
.wrap(this);
} catch (FileNotFoundException e) {
return null; // no release for this tag
}
@@ -489,7 +485,7 @@ public class GHRepository extends GHObject {
*/
public GHRelease getLatestRelease() throws IOException {
try {
return root.retrieve().to(getApiTailUrl("releases/latest"), GHRelease.class).wrap(this);
return root.createRequest().withUrlPath(getApiTailUrl("releases/latest")).fetch(GHRelease.class).wrap(this);
} catch (FileNotFoundException e) {
return null; // no latest release
}
@@ -503,8 +499,9 @@ public class GHRepository extends GHObject {
* the io exception
*/
public PagedIterable<GHRelease> listReleases() throws IOException {
return root.retrieve()
.asPagedIterable(getApiTailUrl("releases"), GHRelease[].class, item -> item.wrap(GHRepository.this));
return root.createRequest()
.withUrlPath(getApiTailUrl("releases"))
.toIterable(GHRelease[].class, item -> item.wrap(this));
}
/**
@@ -515,8 +512,9 @@ public class GHRepository extends GHObject {
* the io exception
*/
public PagedIterable<GHTag> listTags() throws IOException {
return root.retrieve()
.asPagedIterable(getApiTailUrl("tags"), GHTag[].class, item -> item.wrap(GHRepository.this));
return root.createRequest()
.withUrlPath(getApiTailUrl("tags"))
.toIterable(GHTag[].class, item -> item.wrap(this));
}
/**
@@ -528,7 +526,7 @@ public class GHRepository extends GHObject {
* the io exception
*/
public Map<String, Long> listLanguages() throws IOException {
return root.retrieve().to(getApiTailUrl("languages"), HashMap.class);
return root.createRequest().withUrlPath(getApiTailUrl("languages")).fetch(HashMap.class);
}
/**
@@ -773,7 +771,8 @@ public class GHRepository extends GHObject {
* the io exception
*/
public boolean hasAssignee(GHUser u) throws IOException {
return root.retrieve().asHttpStatusCode(getApiTailUrl("assignees/" + u.getLogin())) / 100 == 2;
return root.createRequest().withUrlPath(getApiTailUrl("assignees/" + u.getLogin())).fetchHttpStatusCode()
/ 100 == 2;
}
/**
@@ -786,7 +785,9 @@ public class GHRepository extends GHObject {
*/
public Set<String> getCollaboratorNames() throws IOException {
Set<String> r = new HashSet<String>();
for (GHUser u : GHUser.wrap(root.retrieve().to(getApiTailUrl("collaborators"), GHUser[].class), root))
for (GHUser u : GHUser.wrap(
root.createRequest().withUrlPath(getApiTailUrl("collaborators")).fetchArray(GHUser[].class),
root))
r.add(u.login);
return r;
}
@@ -801,8 +802,9 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHPermissionType getPermission(String user) throws IOException {
GHPermission perm = root.retrieve()
.to(getApiTailUrl("collaborators/" + user + "/permission"), GHPermission.class);
GHPermission perm = root.createRequest()
.withUrlPath(getApiTailUrl("collaborators/" + user + "/permission"))
.fetch(GHPermission.class);
perm.wrapUp(root);
return perm.getPermissionType();
}
@@ -828,8 +830,8 @@ public class GHRepository extends GHObject {
* the io exception
*/
public Set<GHTeam> getTeams() throws IOException {
return Collections.unmodifiableSet(new HashSet<GHTeam>(
Arrays.asList(GHTeam.wrapUp(root.retrieve().to(getApiTailUrl("teams"), GHTeam[].class),
return Collections.unmodifiableSet(new HashSet<GHTeam>(Arrays.asList(
GHTeam.wrapUp(root.createRequest().withUrlPath(getApiTailUrl("teams")).fetchArray(GHTeam[].class),
root.getOrganization(getOwnerName())))));
}
@@ -883,7 +885,7 @@ public class GHRepository extends GHObject {
private void modifyCollaborators(Collection<GHUser> users, String method) throws IOException {
for (GHUser user : users) {
new Requester(root).method(method).to(getApiTailUrl("collaborators/" + user.getLogin()));
root.createRequest().method(method).withUrlPath(getApiTailUrl("collaborators/" + user.getLogin())).send();
}
}
@@ -898,18 +900,20 @@ public class GHRepository extends GHObject {
public void setEmailServiceHook(String address) throws IOException {
Map<String, String> config = new HashMap<String, String>();
config.put("address", address);
new Requester(root).method("POST")
root.createRequest()
.method("POST")
.with("name", "email")
.with("config", config)
.with("active", true)
.to(getApiTailUrl("hooks"));
.withUrlPath(getApiTailUrl("hooks"))
.send();
}
private void edit(String key, String value) throws IOException {
Requester requester = new Requester(root);
Requester requester = root.createRequest();
if (!key.equals("name"))
requester.with("name", name); // even when we don't change the name, we need to send it in
requester.with(key, value).method("PATCH").to(getApiTailUrl(""));
requester.with(key, value).method("PATCH").withUrlPath(getApiTailUrl("")).send();
}
/**
@@ -1052,7 +1056,7 @@ public class GHRepository extends GHObject {
*/
public void delete() throws IOException {
try {
new Requester(root).method("DELETE").to(getApiTailUrl(""));
root.createRequest().method("DELETE").withUrlPath(getApiTailUrl("")).send();
} catch (FileNotFoundException x) {
throw (FileNotFoundException) new FileNotFoundException("Failed to delete " + getOwnerName() + "/" + name
+ "; might not exist, or you might need the delete_repo scope in your token: http://stackoverflow.com/a/19327004/12916")
@@ -1110,9 +1114,10 @@ public class GHRepository extends GHObject {
* @return the paged iterable
*/
public PagedIterable<GHRepository> listForks(final ForkSort sort) {
return root.retrieve()
return root.createRequest()
.with("sort", sort)
.asPagedIterable(getApiTailUrl("forks"), GHRepository[].class, item -> item.wrap(root));
.withUrlPath(getApiTailUrl("forks"))
.toIterable(GHRepository[].class, item -> item.wrap(root));
}
/**
@@ -1123,7 +1128,7 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHRepository fork() throws IOException {
new Requester(root).method("POST").to(getApiTailUrl("forks"), null);
root.createRequest().method("POST").withUrlPath(getApiTailUrl("forks")).send();
// this API is asynchronous. we need to wait for a bit
for (int i = 0; i < 10; i++) {
@@ -1149,7 +1154,11 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHRepository forkTo(GHOrganization org) throws IOException {
new Requester(root).to(getApiTailUrl("forks?org=" + org.getLogin()));
root.createRequest()
.method("POST")
.with("organization", org.getLogin())
.withUrlPath(getApiTailUrl("forks"))
.send();
// this API is asynchronous. we need to wait for a bit
for (int i = 0; i < 10; i++) {
@@ -1175,9 +1184,10 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHPullRequest getPullRequest(int i) throws IOException {
return root.retrieve()
return root.createRequest()
.withPreview(SHADOW_CAT)
.to(getApiTailUrl("pulls/" + i), GHPullRequest.class)
.withUrlPath(getApiTailUrl("pulls/" + i))
.fetch(GHPullRequest.class)
.wrapUp(this);
}
@@ -1291,14 +1301,17 @@ public class GHRepository extends GHObject {
String body,
boolean maintainerCanModify,
boolean draft) throws IOException {
return new Requester(root).withPreview(SHADOW_CAT)
return root.createRequest()
.method("POST")
.withPreview(SHADOW_CAT)
.with("title", title)
.with("head", head)
.with("base", base)
.with("body", body)
.with("maintainer_can_modify", maintainerCanModify)
.with("draft", draft)
.to(getApiTailUrl("pulls"), GHPullRequest.class)
.withUrlPath(getApiTailUrl("pulls"))
.fetch(GHPullRequest.class)
.wrapUp(this);
}
@@ -1340,8 +1353,9 @@ public class GHRepository extends GHObject {
* on failure communicating with GitHub
*/
public GHCompare getCompare(String id1, String id2) throws IOException {
GHCompare compare = root.retrieve()
.to(getApiTailUrl(String.format("compare/%s...%s", id1, id2)), GHCompare.class);
GHCompare compare = root.createRequest()
.withUrlPath(getApiTailUrl(String.format("compare/%s...%s", id1, id2)))
.fetch(GHCompare.class);
return compare.wrap(this);
}
@@ -1399,9 +1413,9 @@ public class GHRepository extends GHObject {
* on failure communicating with GitHub
*/
public GHRef[] getRefs() throws IOException {
return GHRef.wrap(
root.retrieve().to(String.format("/repos/%s/%s/git/refs", getOwnerName(), name), GHRef[].class),
root);
return GHRef.wrap(root.createRequest()
.withUrlPath(String.format("/repos/%s/%s/git/refs", getOwnerName(), name))
.fetchArray(GHRef[].class), root);
}
/**
@@ -1413,7 +1427,7 @@ public class GHRepository extends GHObject {
*/
public PagedIterable<GHRef> listRefs() throws IOException {
final String url = String.format("/repos/%s/%s/git/refs", getOwnerName(), name);
return root.retrieve().asPagedIterable(url, GHRef[].class, item -> item.wrap(root));
return root.createRequest().withUrlPath(url).toIterable(GHRef[].class, item -> item.wrap(root));
}
/**
@@ -1426,10 +1440,9 @@ public class GHRepository extends GHObject {
* on failure communicating with GitHub, potentially due to an invalid ref type being requested
*/
public GHRef[] getRefs(String refType) throws IOException {
return GHRef.wrap(
root.retrieve()
.to(String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType), GHRef[].class),
root);
return GHRef.wrap(root.createRequest()
.withUrlPath(String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType))
.fetchArray(GHRef[].class), root);
}
/**
@@ -1443,7 +1456,7 @@ public class GHRepository extends GHObject {
*/
public PagedIterable<GHRef> listRefs(String refType) throws IOException {
final String url = String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType);
return root.retrieve().asPagedIterable(url, GHRef[].class, item -> item.wrap(root));
return root.createRequest().withUrlPath(url).toIterable(GHRef[].class, item -> item.wrap(root));
}
/**
@@ -1456,7 +1469,10 @@ public class GHRepository extends GHObject {
* 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(getApiTailUrl(String.format("git/refs/%s", refName)), GHRef.class).wrap(root);
return root.createRequest()
.withUrlPath(getApiTailUrl(String.format("git/refs/%s", refName)))
.fetch(GHRef.class)
.wrap(root);
}
/**
@@ -1470,7 +1486,7 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHTagObject getTagObject(String sha) throws IOException {
return root.retrieve().to(getApiTailUrl("git/tags/" + sha), GHTagObject.class).wrap(this);
return root.createRequest().withUrlPath(getApiTailUrl("git/tags/" + sha)).fetch(GHTagObject.class).wrap(this);
}
/**
@@ -1484,7 +1500,7 @@ public class GHRepository extends GHObject {
*/
public GHTree getTree(String sha) throws IOException {
String url = String.format("/repos/%s/%s/git/trees/%s", getOwnerName(), name, sha);
return root.retrieve().to(url, GHTree.class).wrap(this);
return root.createRequest().withUrlPath(url).fetch(GHTree.class).wrap(this);
}
/**
@@ -1509,8 +1525,8 @@ public class GHRepository extends GHObject {
* on failure communicating with GitHub, potentially due to an invalid tree type being requested
*/
public GHTree getTreeRecursive(String sha, int recursive) throws IOException {
String url = String.format("/repos/%s/%s/git/trees/%s?recursive=%d", getOwnerName(), name, sha, recursive);
return root.retrieve().to(url, GHTree.class).wrap(this);
String url = String.format("/repos/%s/%s/git/trees/%s", getOwnerName(), name, sha);
return root.createRequest().with("recursive", recursive).withUrlPath(url).fetch(GHTree.class).wrap(this);
}
/**
@@ -1529,7 +1545,7 @@ public class GHRepository extends GHObject {
*/
public GHBlob getBlob(String blobSha) throws IOException {
String target = getApiTailUrl("git/blobs/" + blobSha);
return root.retrieve().to(target, GHBlob.class);
return root.createRequest().withUrlPath(target).fetch(GHBlob.class);
}
/**
@@ -1554,7 +1570,12 @@ public class GHRepository extends GHObject {
*/
public InputStream readBlob(String blobSha) throws IOException {
String target = getApiTailUrl("git/blobs/" + blobSha);
return root.retrieve().withHeader("Accept", "application/vnd.github.VERSION.raw").asStream(target);
// https://developer.github.com/v3/media/ describes this media type
return root.createRequest()
.withHeader("Accept", "application/vnd.github.v3.raw")
.withUrlPath(target)
.fetchStream();
}
/**
@@ -1569,8 +1590,9 @@ public class GHRepository extends GHObject {
public GHCommit getCommit(String sha1) throws IOException {
GHCommit c = commits.get(sha1);
if (c == null) {
c = root.retrieve()
.to(String.format("/repos/%s/%s/commits/%s", getOwnerName(), name, sha1), GHCommit.class)
c = root.createRequest()
.withUrlPath(String.format("/repos/%s/%s/commits/%s", getOwnerName(), name, sha1))
.fetch(GHCommit.class)
.wrapUp(this);
commits.put(sha1, c);
}
@@ -1592,10 +1614,9 @@ public class GHRepository extends GHObject {
* @return the paged iterable
*/
public PagedIterable<GHCommit> listCommits() {
return root.retrieve()
.asPagedIterable(String.format("/repos/%s/%s/commits", getOwnerName(), name),
GHCommit[].class,
item -> item.wrapUp(GHRepository.this));
return root.createRequest()
.withUrlPath(String.format("/repos/%s/%s/commits", getOwnerName(), name))
.toIterable(GHCommit[].class, item -> item.wrapUp(this));
}
/**
@@ -1613,10 +1634,9 @@ public class GHRepository extends GHObject {
* @return the paged iterable
*/
public PagedIterable<GHCommitComment> listCommitComments() {
return root.retrieve()
.asPagedIterable(String.format("/repos/%s/%s/comments", getOwnerName(), name),
GHCommitComment[].class,
item -> item.wrap(GHRepository.this));
return root.createRequest()
.withUrlPath(String.format("/repos/%s/%s/comments", getOwnerName(), name))
.toIterable(GHCommitComment[].class, item -> item.wrap(this));
}
/**
@@ -1646,7 +1666,10 @@ public class GHRepository extends GHObject {
private GHContentWithLicense getLicenseContent_() throws IOException {
try {
return root.retrieve().to(getApiTailUrl("license"), GHContentWithLicense.class).wrap(this);
return root.createRequest()
.withUrlPath(getApiTailUrl("license"))
.fetch(GHContentWithLicense.class)
.wrap(this);
} catch (FileNotFoundException e) {
return null;
}
@@ -1662,10 +1685,9 @@ public class GHRepository extends GHObject {
* the io exception
*/
public PagedIterable<GHCommitStatus> listCommitStatuses(final String sha1) throws IOException {
return root.retrieve()
.asPagedIterable(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), name, sha1),
GHCommitStatus[].class,
item -> item.wrapUp(root));
return root.createRequest()
.withUrlPath(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), name, sha1))
.toIterable(GHCommitStatus[].class, item -> item.wrapUp(root));
}
/**
@@ -1704,11 +1726,14 @@ public class GHRepository extends GHObject {
String targetUrl,
String description,
String context) throws IOException {
return new Requester(root).with("state", state)
return root.createRequest()
.method("POST")
.with("state", state)
.with("target_url", targetUrl)
.with("description", description)
.with("context", context)
.to(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), this.name, sha1), GHCommitStatus.class)
.withUrlPath(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), this.name, sha1))
.fetch(GHCommitStatus.class)
.wrapUp(root);
}
@@ -1742,10 +1767,9 @@ public class GHRepository extends GHObject {
* the io exception
*/
public PagedIterable<GHEventInfo> listEvents() throws IOException {
return root.retrieve()
.asPagedIterable(String.format("/repos/%s/%s/events", getOwnerName(), name),
GHEventInfo[].class,
item -> item.wrapUp(root));
return root.createRequest()
.withUrlPath(String.format("/repos/%s/%s/events", getOwnerName(), name))
.toIterable(GHEventInfo[].class, item -> item.wrapUp(root));
}
/**
@@ -1758,9 +1782,9 @@ public class GHRepository extends GHObject {
* the io exception
*/
public PagedIterable<GHLabel> listLabels() throws IOException {
return root.retrieve()
.withPreview(SYMMETRA)
.asPagedIterable(getApiTailUrl("labels"), GHLabel[].class, item -> item.wrapUp(GHRepository.this));
return root.createRequest()
.withUrlPath(getApiTailUrl("labels"))
.toIterable(GHLabel[].class, item -> item.wrapUp(this));
}
/**
@@ -1773,7 +1797,7 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHLabel getLabel(String name) throws IOException {
return root.retrieve().withPreview(SYMMETRA).to(getApiTailUrl("labels/" + name), GHLabel.class).wrapUp(this);
return root.createRequest().withUrlPath(getApiTailUrl("labels/" + name)).fetch(GHLabel.class).wrapUp(this);
}
/**
@@ -1804,16 +1828,14 @@ public class GHRepository extends GHObject {
* @throws IOException
* the io exception
*/
@Preview
@Deprecated
public GHLabel createLabel(String name, String color, String description) throws IOException {
return root.retrieve()
return root.createRequest()
.method("POST")
.withPreview(SYMMETRA)
.with("name", name)
.with("color", color)
.with("description", description)
.to(getApiTailUrl("labels"), GHLabel.class)
.withUrlPath(getApiTailUrl("labels"))
.fetch(GHLabel.class)
.wrapUp(this);
}
@@ -1823,10 +1845,9 @@ public class GHRepository extends GHObject {
* @return the paged iterable
*/
public PagedIterable<GHInvitation> listInvitations() {
return root.retrieve()
.asPagedIterable(String.format("/repos/%s/%s/invitations", getOwnerName(), name),
GHInvitation[].class,
item -> item.wrapUp(root));
return root.createRequest()
.withUrlPath(String.format("/repos/%s/%s/invitations", getOwnerName(), name))
.toIterable(GHInvitation[].class, item -> item.wrapUp(root));
}
/**
@@ -1857,15 +1878,16 @@ public class GHRepository extends GHObject {
* @return the paged iterable
*/
public PagedIterable<GHStargazer> listStargazers2() {
return root.retrieve()
return root.createRequest()
.withPreview("application/vnd.github.v3.star+json")
.asPagedIterable(getApiTailUrl("stargazers"),
GHStargazer[].class,
item -> item.wrapUp(GHRepository.this));
.withUrlPath(getApiTailUrl("stargazers"))
.toIterable(GHStargazer[].class, item -> item.wrapUp(this));
}
private PagedIterable<GHUser> listUsers(final String suffix) {
return root.retrieve().asPagedIterable(getApiTailUrl(suffix), GHUser[].class, item -> item.wrapUp(root));
return root.createRequest()
.withUrlPath(getApiTailUrl(suffix))
.toIterable(GHUser[].class, item -> item.wrapUp(root));
}
/**
@@ -2013,7 +2035,7 @@ public class GHRepository extends GHObject {
*/
public Map<String, GHBranch> getBranches() throws IOException {
Map<String, GHBranch> r = new TreeMap<String, GHBranch>();
for (GHBranch p : root.retrieve().to(getApiTailUrl("branches"), GHBranch[].class)) {
for (GHBranch p : root.createRequest().withUrlPath(getApiTailUrl("branches")).fetchArray(GHBranch[].class)) {
p.wrap(this);
r.put(p.getName(), p);
}
@@ -2030,7 +2052,7 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHBranch getBranch(String name) throws IOException {
return root.retrieve().to(getApiTailUrl("branches/" + name), GHBranch.class).wrap(this);
return root.createRequest().withUrlPath(getApiTailUrl("branches/" + name)).fetch(GHBranch.class).wrap(this);
}
/**
@@ -2057,11 +2079,10 @@ public class GHRepository extends GHObject {
* @return the paged iterable
*/
public PagedIterable<GHMilestone> listMilestones(final GHIssueState state) {
return root.retrieve()
return root.createRequest()
.with("state", state)
.asPagedIterable(getApiTailUrl("milestones"),
GHMilestone[].class,
item -> item.wrap(GHRepository.this));
.withUrlPath(getApiTailUrl("milestones"))
.toIterable(GHMilestone[].class, item -> item.wrap(this));
}
/**
@@ -2076,7 +2097,7 @@ public class GHRepository extends GHObject {
public GHMilestone getMilestone(int number) throws IOException {
GHMilestone m = milestones.get(number);
if (m == null) {
m = root.retrieve().to(getApiTailUrl("milestones/" + number), GHMilestone.class);
m = root.createRequest().withUrlPath(getApiTailUrl("milestones/" + number)).fetch(GHMilestone.class);
m.owner = this;
m.root = root;
milestones.put(m.getNumber(), m);
@@ -2109,10 +2130,10 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHContent getFileContent(String path, String ref) throws IOException {
Requester requester = root.retrieve();
Requester requester = root.createRequest();
String target = getApiTailUrl("contents/" + path);
return requester.with("ref", ref).to(target, GHContent.class).wrap(this);
return requester.with("ref", ref).withUrlPath(target).fetch(GHContent.class).wrap(this);
}
/**
@@ -2140,13 +2161,13 @@ public class GHRepository extends GHObject {
* the io exception
*/
public List<GHContent> getDirectoryContent(String path, String ref) throws IOException {
Requester requester = root.retrieve();
Requester requester = root.createRequest();
while (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
String target = getApiTailUrl("contents/" + path);
GHContent[] files = requester.with("ref", ref).to(target, GHContent[].class);
GHContent[] files = requester.with("ref", ref).withUrlPath(target).fetchArray(GHContent[].class);
GHContent.wrap(files, this);
@@ -2161,8 +2182,8 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHContent getReadme() throws IOException {
Requester requester = root.retrieve();
return requester.to(getApiTailUrl("readme"), GHContent.class).wrap(this);
Requester requester = root.createRequest();
return requester.withUrlPath(getApiTailUrl("readme")).fetch(GHContent.class).wrap(this);
}
/**
@@ -2265,10 +2286,12 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHMilestone createMilestone(String title, String description) throws IOException {
return new Requester(root).with("title", title)
.with("description", description)
return root.createRequest()
.method("POST")
.to(getApiTailUrl("milestones"), GHMilestone.class)
.with("title", title)
.with("description", description)
.withUrlPath(getApiTailUrl("milestones"))
.fetch(GHMilestone.class)
.wrap(this);
}
@@ -2284,10 +2307,12 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHDeployKey addDeployKey(String title, String key) throws IOException {
return new Requester(root).with("title", title)
.with("key", key)
return root.createRequest()
.method("POST")
.to(getApiTailUrl("keys"), GHDeployKey.class)
.with("title", title)
.with("key", key)
.withUrlPath(getApiTailUrl("keys"))
.fetch(GHDeployKey.class)
.wrap(this);
}
@@ -2301,7 +2326,7 @@ public class GHRepository extends GHObject {
*/
public List<GHDeployKey> getDeployKeys() throws IOException {
List<GHDeployKey> list = new ArrayList<GHDeployKey>(
Arrays.asList(root.retrieve().to(getApiTailUrl("keys"), GHDeployKey[].class)));
Arrays.asList(root.createRequest().withUrlPath(getApiTailUrl("keys")).fetchArray(GHDeployKey[].class)));
for (GHDeployKey h : list)
h.wrap(this);
return list;
@@ -2354,10 +2379,12 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHSubscription subscribe(boolean subscribed, boolean ignored) throws IOException {
return new Requester(root).with("subscribed", subscribed)
.with("ignored", ignored)
return root.createRequest()
.method("PUT")
.to(getApiTailUrl("subscription"), GHSubscription.class)
.with("subscribed", subscribed)
.with("ignored", ignored)
.withUrlPath(getApiTailUrl("subscription"))
.fetch(GHSubscription.class)
.wrapUp(this);
}
@@ -2370,7 +2397,10 @@ public class GHRepository extends GHObject {
*/
public GHSubscription getSubscription() throws IOException {
try {
return root.retrieve().to(getApiTailUrl("subscription"), GHSubscription.class).wrapUp(this);
return root.createRequest()
.withUrlPath(getApiTailUrl("subscription"))
.fetch(GHSubscription.class)
.wrapUp(this);
} catch (FileNotFoundException e) {
return null;
}
@@ -2384,8 +2414,9 @@ public class GHRepository extends GHObject {
* the io exception
*/
public PagedIterable<Contributor> listContributors() throws IOException {
return root.retrieve()
.asPagedIterable(getApiTailUrl("contributors"), Contributor[].class, item -> item.wrapUp(root));
return root.createRequest()
.withUrlPath(getApiTailUrl("contributors"))
.toIterable(Contributor[].class, item -> item.wrapUp(root));
}
/**
@@ -2439,12 +2470,13 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHProject createProject(String name, String body) throws IOException {
return root.retrieve()
return root.createRequest()
.method("POST")
.withPreview(INERTIA)
.with("name", name)
.with("body", body)
.to(getApiTailUrl("projects"), GHProject.class)
.withUrlPath(getApiTailUrl("projects"))
.fetch(GHProject.class)
.wrap(this);
}
@@ -2458,10 +2490,11 @@ public class GHRepository extends GHObject {
* the io exception
*/
public PagedIterable<GHProject> listProjects(final GHProject.ProjectStateFilter status) throws IOException {
return root.retrieve()
return root.createRequest()
.withPreview(INERTIA)
.with("state", status)
.asPagedIterable(getApiTailUrl("projects"), GHProject[].class, item -> item.wrap(GHRepository.this));
.withUrlPath(getApiTailUrl("projects"))
.toIterable(GHProject[].class, item -> item.wrap(this));
}
/**
@@ -2490,10 +2523,15 @@ public class GHRepository extends GHObject {
* @see GitHub#renderMarkdown(String) GitHub#renderMarkdown(String)
*/
public Reader renderMarkdown(String text, MarkdownMode mode) throws IOException {
return new InputStreamReader(new Requester(root).with("text", text)
.with("mode", mode == null ? null : mode.toString())
.with("context", getFullName())
.asStream("/markdown"), "UTF-8");
return new InputStreamReader(
root.createRequest()
.method("POST")
.with("text", text)
.with("mode", mode == null ? null : mode.toString())
.with("context", getFullName())
.withUrlPath("/markdown")
.fetchStream(),
"UTF-8");
}
/**
@@ -2514,7 +2552,7 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHRepositoryViewTraffic getViewTraffic() throws IOException {
return root.retrieve().to(getApiTailUrl("/traffic/views"), GHRepositoryViewTraffic.class);
return root.createRequest().withUrlPath(getApiTailUrl("/traffic/views")).fetch(GHRepositoryViewTraffic.class);
}
/**
@@ -2526,7 +2564,7 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHRepositoryCloneTraffic getCloneTraffic() throws IOException {
return root.retrieve().to(getApiTailUrl("/traffic/clones"), GHRepositoryCloneTraffic.class);
return root.createRequest().withUrlPath(getApiTailUrl("/traffic/clones")).fetch(GHRepositoryCloneTraffic.class);
}
@Override
@@ -2546,7 +2584,7 @@ public class GHRepository extends GHObject {
String getApiTailUrl(String tail) {
if (tail.length() > 0 && !tail.startsWith("/"))
tail = '/' + tail;
return Requester.urlPathEncode("/repos/" + getOwnerName() + "/" + name + tail);
return "/repos/" + getOwnerName() + "/" + name + tail;
}
/**
@@ -2558,8 +2596,9 @@ public class GHRepository extends GHObject {
* the io exception
*/
public PagedIterable<GHIssueEvent> listIssueEvents() throws IOException {
return root.retrieve()
.asPagedIterable(getApiTailUrl("issues/events"), GHIssueEvent[].class, item -> item.wrapUp(root));
return root.createRequest()
.withUrlPath(getApiTailUrl("issues/events"))
.toIterable(GHIssueEvent[].class, item -> item.wrapUp(root));
}
/**
@@ -2572,7 +2611,10 @@ public class GHRepository extends GHObject {
* the io exception
*/
public GHIssueEvent getIssueEvent(long id) throws IOException {
return root.retrieve().to(getApiTailUrl("issues/events/" + id), GHIssueEvent.class).wrapUp(root);
return root.createRequest()
.withUrlPath(getApiTailUrl("issues/events/" + id))
.fetch(GHIssueEvent.class)
.wrapUp(root);
}
// Only used within listTopics().
@@ -2589,7 +2631,10 @@ public class GHRepository extends GHObject {
* the io exception
*/
public List<String> listTopics() throws IOException {
Topics topics = root.retrieve().withPreview(MERCY).to(getApiTailUrl("topics"), Topics.class);
Topics topics = root.createRequest()
.withPreview(MERCY)
.withUrlPath(getApiTailUrl("topics"))
.fetch(Topics.class);
return topics.names;
}
@@ -2603,8 +2648,38 @@ public class GHRepository extends GHObject {
* the io exception
*/
public void setTopics(List<String> topics) throws IOException {
Requester requester = new Requester(root);
requester.with("names", topics);
requester.method("PUT").withPreview(MERCY).to(getApiTailUrl("topics"));
root.createRequest()
.method("PUT")
.with("names", topics)
.withPreview(MERCY)
.withUrlPath(getApiTailUrl("topics"))
.send();
}
/**
* Create a tag. See https://developer.github.com/v3/git/tags/#create-a-tag-object
*
* @param tag
* The tag's name.
* @param message
* The tag message.
* @param object
* The SHA of the git object this is tagging.
* @param type
* The type of the object we're tagging: "commit", "tree" or "blob".
* @return The newly created tag.
* @throws java.io.IOException
* The IO exception.
*/
public GHTagObject createTag(String tag, String message, String object, String type) throws IOException {
return root.createRequest()
.method("POST")
.with("tag", tag)
.with("message", message)
.with("object", object)
.with("type", type)
.withUrlPath(getApiTailUrl("git/tags"))
.fetch(GHTagObject.class)
.wrap(this);
}
}

View File

@@ -87,8 +87,9 @@ public class GHRepositoryStatistics {
* This gets the actual statistics from the server. Returns null if they are still being cached.
*/
private PagedIterable<ContributorStats> getContributorStatsImpl() throws IOException {
return root.retrieve()
.asPagedIterable(getApiTailUrl("contributors"), ContributorStats[].class, item -> item.wrapUp(root));
return root.createRequest()
.withUrlPath(getApiTailUrl("contributors"))
.toIterable(ContributorStats[].class, item -> item.wrapUp(root));
}
/**
@@ -243,8 +244,9 @@ public class GHRepositoryStatistics {
* the io exception
*/
public PagedIterable<CommitActivity> getCommitActivity() throws IOException {
return root.retrieve()
.asPagedIterable(getApiTailUrl("commit_activity"), CommitActivity[].class, item -> item.wrapUp(root));
return root.createRequest()
.withUrlPath(getApiTailUrl("commit_activity"))
.toIterable(CommitActivity[].class, item -> item.wrapUp(root));
}
/**
@@ -318,7 +320,7 @@ public class GHRepositoryStatistics {
// Map to ArrayLists first, since there are no field names in the
// returned JSON.
try {
InputStream stream = root.retrieve().asStream(getApiTailUrl("code_frequency"));
InputStream stream = root.createRequest().withUrlPath(getApiTailUrl("code_frequency")).fetchStream();
ObjectMapper mapper = new ObjectMapper();
TypeReference<ArrayList<ArrayList<Integer>>> typeRef = new TypeReference<ArrayList<ArrayList<Integer>>>() {
@@ -400,7 +402,7 @@ public class GHRepositoryStatistics {
* the io exception
*/
public Participation getParticipation() throws IOException {
return root.retrieve().to(getApiTailUrl("participation"), Participation.class);
return root.createRequest().withUrlPath(getApiTailUrl("participation")).fetch(Participation.class);
}
/**
@@ -460,7 +462,7 @@ public class GHRepositoryStatistics {
public List<PunchCardItem> getPunchCard() throws IOException {
// Map to ArrayLists first, since there are no field names in the
// returned JSON.
InputStream stream = root.retrieve().asStream(getApiTailUrl("punch_card"));
InputStream stream = root.createRequest().withUrlPath(getApiTailUrl("punch_card")).fetchStream();
ObjectMapper mapper = new ObjectMapper();
TypeReference<ArrayList<ArrayList<Integer>>> typeRef = new TypeReference<ArrayList<ArrayList<Integer>>>() {

View File

@@ -0,0 +1,49 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.net.URL;
@SuppressFBWarnings(value = { "UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD", "URF_UNREAD_FIELD" },
justification = "JSON API")
public class GHRequestedAction extends GHObject {
private GHRepository owner;
private GitHub root;
private String identifier;
private String label;
private String description;
GHRequestedAction wrap(GHRepository owner) {
this.owner = owner;
wrap(owner.root);
return this;
}
GHRequestedAction wrap(GitHub root) {
this.root = root;
if (owner != null) {
owner.wrap(root);
}
return this;
}
String getIdentifier() {
return identifier;
}
String getLabel() {
return label;
}
String getDescription() {
return description;
}
/**
* @deprecated This object has no HTML URL.
*/
@Override
public URL getHtmlUrl() {
return null;
}
}

View File

@@ -45,7 +45,7 @@ public abstract class GHSearchBuilder<T> extends GHQueryBuilder<T> {
return new PagedSearchIterable<T>(root) {
public PagedIterator<T> _iterator(int pageSize) {
req.set("q", StringUtils.join(terms, " "));
return new PagedIterator<T>(adapt(req.asIterator(getApiUrl(), receiverType, pageSize))) {
return new PagedIterator<T>(adapt(req.withUrlPath(getApiUrl()).asIterator(receiverType, pageSize))) {
protected void wrapUp(T[] page) {
// SearchResult.getItems() should do it
}

View File

@@ -87,7 +87,7 @@ public class GHSubscription {
* the io exception
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").to(repo.getApiTailUrl("subscription"));
root.createRequest().method("DELETE").withUrlPath(repo.getApiTailUrl("subscription")).send();
}
GHSubscription wrapUp(GHRepository repo) {

View File

@@ -103,7 +103,7 @@ public class GHTeam implements Refreshable {
* the io exception
*/
public void setDescription(String description) throws IOException {
root.retrieve().method("PATCH").with("description", description).to(api(""));
root.createRequest().method("PATCH").with("description", description).withUrlPath(api("")).send();
}
/**
@@ -123,7 +123,7 @@ public class GHTeam implements Refreshable {
* the io exception
*/
public PagedIterable<GHUser> listMembers() throws IOException {
return root.retrieve().asPagedIterable(api("/members"), GHUser[].class, item -> item.wrapUp(root));
return root.createRequest().withUrlPath(api("/members")).toIterable(GHUser[].class, item -> item.wrapUp(root));
}
/**
@@ -146,7 +146,7 @@ public class GHTeam implements Refreshable {
*/
public boolean hasMember(GHUser user) {
try {
root.retrieve().to("/teams/" + id + "/members/" + user.getLogin());
root.createRequest().withUrlPath("/teams/" + id + "/members/" + user.getLogin()).send();
return true;
} catch (IOException ignore) {
return false;
@@ -174,7 +174,9 @@ public class GHTeam implements Refreshable {
* @return the paged iterable
*/
public PagedIterable<GHRepository> listRepositories() {
return root.retrieve().asPagedIterable(api("/repos"), GHRepository[].class, item -> item.wrap(root));
return root.createRequest()
.withUrlPath(api("/repos"))
.toIterable(GHRepository[].class, item -> item.wrap(root));
}
/**
@@ -189,7 +191,7 @@ public class GHTeam implements Refreshable {
* @since 1.59
*/
public void add(GHUser u) throws IOException {
root.retrieve().method("PUT").to(api("/memberships/" + u.getLogin()), null);
root.createRequest().method("PUT").withUrlPath(api("/memberships/" + u.getLogin())).send();
}
/**
@@ -205,7 +207,11 @@ public class GHTeam implements Refreshable {
* the io exception
*/
public void add(GHUser user, Role role) throws IOException {
root.retrieve().method("PUT").with("role", role).to(api("/memberships/" + user.getLogin()), null);
root.createRequest()
.method("PUT")
.with("role", role)
.withUrlPath(api("/memberships/" + user.getLogin()))
.send();
}
/**
@@ -217,7 +223,7 @@ public class GHTeam implements Refreshable {
* the io exception
*/
public void remove(GHUser u) throws IOException {
root.retrieve().method("DELETE").to(api("/members/" + u.getLogin()), null);
root.createRequest().method("DELETE").withUrlPath(api("/members/" + u.getLogin())).send();
}
/**
@@ -243,10 +249,11 @@ public class GHTeam implements Refreshable {
* the io exception
*/
public void add(GHRepository r, GHOrganization.Permission permission) throws IOException {
root.retrieve()
root.createRequest()
.method("PUT")
.with("permission", permission)
.to(api("/repos/" + r.getOwnerName() + '/' + r.getName()), null);
.withUrlPath(api("/repos/" + r.getOwnerName() + '/' + r.getName()))
.send();
}
/**
@@ -258,7 +265,7 @@ public class GHTeam implements Refreshable {
* the io exception
*/
public void remove(GHRepository r) throws IOException {
root.retrieve().method("DELETE").to(api("/repos/" + r.getOwnerName() + '/' + r.getName()), null);
root.createRequest().method("DELETE").withUrlPath(api("/repos/" + r.getOwnerName() + '/' + r.getName())).send();
}
/**
@@ -268,7 +275,7 @@ public class GHTeam implements Refreshable {
* the io exception
*/
public void delete() throws IOException {
root.retrieve().method("DELETE").to(api(""));
root.createRequest().method("DELETE").withUrlPath(api("")).send();
}
private String api(String tail) {
@@ -289,6 +296,6 @@ public class GHTeam implements Refreshable {
@Override
public void refresh() throws IOException {
root.retrieve().to(api(""), this).wrapUp(root);
root.createRequest().withUrlPath(api("")).fetchInto(this).wrapUp(root);
}
}

View File

@@ -161,7 +161,7 @@ public class GHThread extends GHObject {
* the io exception
*/
public void markAsRead() throws IOException {
new Requester(root).method("PATCH").to(url);
root.createRequest().method("PATCH").withUrlPath(url).send();
}
/**
@@ -176,10 +176,12 @@ public class GHThread extends GHObject {
* the io exception
*/
public GHSubscription subscribe(boolean subscribed, boolean ignored) throws IOException {
return new Requester(root).with("subscribed", subscribed)
.with("ignored", ignored)
return root.createRequest()
.method("PUT")
.to(subscription_url, GHSubscription.class)
.with("subscribed", subscribed)
.with("ignored", ignored)
.withUrlPath(subscription_url)
.fetch(GHSubscription.class)
.wrapUp(root);
}
@@ -192,7 +194,11 @@ public class GHThread extends GHObject {
*/
public GHSubscription getSubscription() throws IOException {
try {
return new Requester(root).to(subscription_url, GHSubscription.class).wrapUp(root);
return root.createRequest()
.method("POST")
.withUrlPath(subscription_url)
.fetch(GHSubscription.class)
.wrapUp(root);
} catch (FileNotFoundException e) {
return null;
}

View File

@@ -1,5 +1,7 @@
package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
@@ -16,8 +18,11 @@ public class GHTreeBuilder {
private final List<TreeEntry> treeEntries = new ArrayList<TreeEntry>();
// Issue #636: Create Tree no longer accepts null value in sha field
@JsonInclude(Include.NON_NULL)
@SuppressFBWarnings("URF_UNREAD_FIELD")
private static final class TreeEntry {
private final String path;
private final String mode;
private final String type;
@@ -33,7 +38,7 @@ public class GHTreeBuilder {
GHTreeBuilder(GHRepository repo) {
this.repo = repo;
req = new Requester(repo.root);
req = repo.root.createRequest();
}
/**
@@ -163,6 +168,6 @@ public class GHTreeBuilder {
*/
public GHTree create() throws IOException {
req.with("tree", treeEntries);
return req.method("POST").to(getApiTail(), GHTree.class).wrap(repo);
return req.method("POST").withUrlPath(getApiTail()).fetch(GHTree.class).wrap(repo);
}
}

View File

@@ -43,7 +43,8 @@ public class GHUser extends GHPerson {
* the io exception
*/
public List<GHKey> getKeys() throws IOException {
return Collections.unmodifiableList(Arrays.asList(root.retrieve().to(getApiTailUrl("keys"), GHKey[].class)));
return Collections.unmodifiableList(
Arrays.asList(root.createRequest().withUrlPath(getApiTailUrl("keys")).fetchArray(GHKey[].class)));
}
/**
@@ -53,7 +54,7 @@ public class GHUser extends GHPerson {
* the io exception
*/
public void follow() throws IOException {
new Requester(root).method("PUT").to("/user/following/" + login);
root.createRequest().method("PUT").withUrlPath("/user/following/" + login).send();
}
/**
@@ -63,7 +64,7 @@ public class GHUser extends GHPerson {
* the io exception
*/
public void unfollow() throws IOException {
new Requester(root).method("DELETE").to("/user/following/" + login);
root.createRequest().method("DELETE").withUrlPath("/user/following/" + login).send();
}
/**
@@ -109,7 +110,9 @@ public class GHUser extends GHPerson {
}
private PagedIterable<GHUser> listUser(final String suffix) {
return root.retrieve().asPagedIterable(getApiTailUrl(suffix), GHUser[].class, item -> item.wrapUp(root));
return root.createRequest()
.withUrlPath(getApiTailUrl(suffix))
.toIterable(GHUser[].class, item -> item.wrapUp(root));
}
/**
@@ -133,7 +136,9 @@ public class GHUser extends GHPerson {
}
private PagedIterable<GHRepository> listRepositories(final String suffix) {
return root.retrieve().asPagedIterable(getApiTailUrl(suffix), GHRepository[].class, item -> item.wrap(root));
return root.createRequest()
.withUrlPath(getApiTailUrl(suffix))
.toIterable(GHRepository[].class, item -> item.wrap(root));
}
/**
@@ -186,7 +191,9 @@ public class GHUser extends GHPerson {
public GHPersonSet<GHOrganization> getOrganizations() throws IOException {
GHPersonSet<GHOrganization> orgs = new GHPersonSet<GHOrganization>();
Set<String> names = new HashSet<String>();
for (GHOrganization o : root.retrieve().to("/users/" + login + "/orgs", GHOrganization[].class)) {
for (GHOrganization o : root.createRequest()
.withUrlPath("/users/" + login + "/orgs")
.fetchArray(GHOrganization[].class)) {
if (names.add(o.getLogin())) // I've seen some duplicates in the data
orgs.add(root.getOrganization(o.getLogin()));
}
@@ -197,10 +204,9 @@ public class GHUser extends GHPerson {
* Lists events performed by a user (this includes private events if the caller is authenticated.
*/
public PagedIterable<GHEventInfo> listEvents() throws IOException {
return root.retrieve()
.asPagedIterable(String.format("/users/%s/events", login),
GHEventInfo[].class,
item -> item.wrapUp(root));
return root.createRequest()
.withUrlPath(String.format("/users/%s/events", login))
.toIterable(GHEventInfo[].class, item -> item.wrapUp(root));
}
/**
@@ -211,10 +217,9 @@ public class GHUser extends GHPerson {
* the io exception
*/
public PagedIterable<GHGist> listGists() throws IOException {
return root.retrieve()
.asPagedIterable(String.format("/users/%s/gists", login),
GHGist[].class,
item -> item.wrapUp(GHUser.this));
return root.createRequest()
.withUrlPath(String.format("/users/%s/gists", login))
.toIterable(GHGist[].class, item -> item.wrapUp(this));
}
@Override

View File

@@ -29,17 +29,17 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Base64;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Supplier;
@@ -151,9 +151,9 @@ public class GitHub {
encodedAuthorization = "Bearer " + jwtToken;
} else if (password != null) {
String authorization = (login + ':' + password);
String charsetName = Charsets.UTF_8.name();
String charsetName = StandardCharsets.UTF_8.name();
encodedAuthorization = "Basic "
+ new String(Base64.encodeBase64(authorization.getBytes(charsetName)), charsetName);
+ Base64.getEncoder().encodeToString(authorization.getBytes(charsetName));
} else {// anonymous access
encodedAuthorization = null;
}
@@ -424,8 +424,8 @@ public class GitHub {
}
}
Requester retrieve() {
return new Requester(this).method("GET");
Requester createRequest() {
return new Requester(this);
}
/**
@@ -438,7 +438,7 @@ public class GitHub {
public GHRateLimit getRateLimit() throws IOException {
GHRateLimit rateLimit;
try {
rateLimit = retrieve().to("/rate_limit", JsonRateLimit.class).resources;
rateLimit = createRequest().withUrlPath("/rate_limit").fetch(JsonRateLimit.class).resources;
} catch (FileNotFoundException e) {
// GitHub Enterprise doesn't have the rate limit
// return a default rate limit that
@@ -544,7 +544,7 @@ public class GitHub {
if (this.myself != null)
return myself;
GHMyself u = retrieve().to("/user", GHMyself.class);
GHMyself u = createRequest().withUrlPath("/user").fetch(GHMyself.class);
u.root = this;
this.myself = u;
@@ -564,7 +564,7 @@ public class GitHub {
public GHUser getUser(String login) throws IOException {
GHUser u = users.get(login);
if (u == null) {
u = retrieve().to("/users/" + login, GHUser.class);
u = createRequest().withUrlPath("/users/" + login).fetch(GHUser.class);
u.root = this;
users.put(u.getLogin(), u);
}
@@ -608,7 +608,7 @@ public class GitHub {
public GHOrganization getOrganization(String name) throws IOException {
GHOrganization o = orgs.get(name);
if (o == null) {
o = retrieve().to("/orgs/" + name, GHOrganization.class).wrapUp(this);
o = createRequest().withUrlPath("/orgs/" + name).fetch(GHOrganization.class).wrapUp(this);
orgs.put(name, o);
}
return o;
@@ -632,8 +632,9 @@ public class GitHub {
* @see <a href="https://developer.github.com/v3/orgs/#parameters">List All Orgs - Parameters</a>
*/
public PagedIterable<GHOrganization> listOrganizations(final String since) {
return retrieve().with("since", since)
.asPagedIterable("/organizations", GHOrganization[].class, item -> item.wrapUp(GitHub.this));
return createRequest().with("since", since)
.withUrlPath("/organizations")
.toIterable(GHOrganization[].class, item -> item.wrapUp(this));
}
/**
@@ -648,7 +649,9 @@ public class GitHub {
*/
public GHRepository getRepository(String name) throws IOException {
String[] tokens = name.split("/");
return retrieve().to("/repos/" + tokens[0] + '/' + tokens[1], GHRepository.class).wrap(this);
return createRequest().withUrlPath("/repos/" + tokens[0] + '/' + tokens[1])
.fetch(GHRepository.class)
.wrap(this);
}
/**
@@ -661,7 +664,7 @@ public class GitHub {
* the io exception
*/
public GHRepository getRepositoryById(String id) throws IOException {
return retrieve().to("/repositories/" + id, GHRepository.class).wrap(this);
return createRequest().withUrlPath("/repositories/" + id).fetch(GHRepository.class).wrap(this);
}
/**
@@ -673,7 +676,7 @@ public class GitHub {
* @see <a href="https://developer.github.com/v3/licenses/">GitHub API - Licenses</a>
*/
public PagedIterable<GHLicense> listLicenses() throws IOException {
return retrieve().asPagedIterable("/licenses", GHLicense[].class, item -> item.wrap(GitHub.this));
return createRequest().withUrlPath("/licenses").toIterable(GHLicense[].class, item -> item.wrap(this));
}
/**
@@ -684,7 +687,7 @@ public class GitHub {
* the io exception
*/
public PagedIterable<GHUser> listUsers() throws IOException {
return retrieve().asPagedIterable("/users", GHUser[].class, item -> item.wrapUp(GitHub.this));
return createRequest().withUrlPath("/users").toIterable(GHUser[].class, item -> item.wrapUp(this));
}
/**
@@ -698,7 +701,25 @@ public class GitHub {
* @see GHLicense#getKey() GHLicense#getKey()
*/
public GHLicense getLicense(String key) throws IOException {
return retrieve().to("/licenses/" + key, GHLicense.class);
return createRequest().withUrlPath("/licenses/" + key).fetch(GHLicense.class);
}
/**
* Returns a list all plans for your Marketplace listing
* <p>
* GitHub Apps must use a JWT to access this endpoint.
* <p>
* OAuth Apps must use basic authentication with their client ID and client secret to access this endpoint.
*
* @return the paged iterable
* @throws IOException
* the io exception
* @see <a href="https://developer.github.com/v3/apps/marketplace/#list-all-plans-for-your-marketplace-listing">List
* Plans</a>
*/
public PagedIterable<GHMarketplacePlan> listMarketplacePlans() throws IOException {
return createRequest().withUrlPath("/marketplace_listing/plans")
.toIterable(GHMarketplacePlan[].class, item -> item.wrapUp(this));
}
/**
@@ -709,7 +730,8 @@ public class GitHub {
* the io exception
*/
public List<GHInvitation> getMyInvitations() throws IOException {
GHInvitation[] invitations = retrieve().to("/user/repository_invitations", GHInvitation[].class);
GHInvitation[] invitations = createRequest().withUrlPath("/user/repository_invitations")
.fetchArray(GHInvitation[].class);
for (GHInvitation i : invitations) {
i.wrapUp(this);
}
@@ -727,7 +749,7 @@ public class GitHub {
* the io exception
*/
public Map<String, GHOrganization> getMyOrganizations() throws IOException {
GHOrganization[] orgs = retrieve().to("/user/orgs", GHOrganization[].class);
GHOrganization[] orgs = createRequest().withUrlPath("/user/orgs").fetchArray(GHOrganization[].class);
Map<String, GHOrganization> r = new HashMap<String, GHOrganization>();
for (GHOrganization o : orgs) {
// don't put 'o' into orgs because they are shallow
@@ -736,6 +758,25 @@ public class GitHub {
return r;
}
/**
* Returns only active subscriptions.
* <p>
* You must use a user-to-server OAuth access token, created for a user who has authorized your GitHub App, to
* access this endpoint
* <p>
* OAuth Apps must authenticate using an OAuth token.
*
* @return the paged iterable of GHMarketplaceUserPurchase
* @throws IOException
* the io exception
* @see <a href="https://developer.github.com/v3/apps/marketplace/#get-a-users-marketplace-purchases">Get a user's
* Marketplace purchases</a>
*/
public PagedIterable<GHMarketplaceUserPurchase> getMyMarketplacePurchases() throws IOException {
return createRequest().withUrlPath("/user/marketplace_purchases")
.toIterable(GHMarketplaceUserPurchase[].class, item -> item.wrapUp(this));
}
/**
* Alias for {@link #getUserPublicOrganizations(String)}.
*
@@ -761,7 +802,8 @@ public class GitHub {
* the io exception
*/
public Map<String, GHOrganization> getUserPublicOrganizations(String login) throws IOException {
GHOrganization[] orgs = retrieve().to("/users/" + login + "/orgs", GHOrganization[].class);
GHOrganization[] orgs = createRequest().withUrlPath("/users/" + login + "/orgs")
.fetchArray(GHOrganization[].class);
Map<String, GHOrganization> r = new HashMap<String, GHOrganization>();
for (GHOrganization o : orgs) {
// don't put 'o' into orgs because they are shallow
@@ -782,7 +824,7 @@ public class GitHub {
*/
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)) {
for (GHTeam team : createRequest().withUrlPath("/user/teams").fetchArray(GHTeam[].class)) {
team.wrapUp(this);
String orgLogin = team.getOrganization().getLogin();
Set<GHTeam> teamsPerOrg = allMyTeams.get(orgLogin);
@@ -805,7 +847,7 @@ public class GitHub {
* the io exception
*/
public GHTeam getTeam(int id) throws IOException {
return retrieve().to("/teams/" + id, GHTeam.class).wrapUp(this);
return createRequest().withUrlPath("/teams/" + id).fetch(GHTeam.class).wrapUp(this);
}
/**
@@ -816,7 +858,7 @@ public class GitHub {
* the io exception
*/
public List<GHEventInfo> getEvents() throws IOException {
GHEventInfo[] events = retrieve().to("/events", GHEventInfo[].class);
GHEventInfo[] events = createRequest().withUrlPath("/events").fetchArray(GHEventInfo[].class);
for (GHEventInfo e : events)
e.wrapUp(this);
return Arrays.asList(events);
@@ -832,7 +874,7 @@ public class GitHub {
* the io exception
*/
public GHGist getGist(String id) throws IOException {
return retrieve().to("/gists/" + id, GHGist.class).wrapUp(this);
return createRequest().withUrlPath("/gists/" + id).fetch(GHGist.class).wrapUp(this);
}
/**
@@ -924,9 +966,9 @@ public class GitHub {
* @see <a href="http://developer.github.com/v3/oauth/#create-a-new-authorization">Documentation</a>
*/
public GHAuthorization createToken(Collection<String> scope, String note, String noteUrl) throws IOException {
Requester requester = new Requester(this).with("scopes", scope).with("note", note).with("note_url", noteUrl);
Requester requester = createRequest().with("scopes", scope).with("note", note).with("note_url", noteUrl);
return requester.method("POST").to("/authorizations", GHAuthorization.class).wrap(this);
return requester.method("POST").withUrlPath("/authorizations").fetch(GHAuthorization.class).wrap(this);
}
/**
@@ -957,12 +999,10 @@ public class GitHub {
return createToken(scope, note, noteUrl);
} catch (GHOTPRequiredException ex) {
String OTPstring = OTP.get();
Requester requester = new Requester(this).with("scopes", scope)
.with("note", note)
.with("note_url", noteUrl);
Requester requester = createRequest().with("scopes", scope).with("note", note).with("note_url", noteUrl);
// Add the OTP from the user
requester.setHeader("x-github-otp", OTPstring);
return requester.method("POST").to("/authorizations", GHAuthorization.class).wrap(this);
return requester.method("POST").withUrlPath("/authorizations").fetch(GHAuthorization.class).wrap(this);
}
}
@@ -990,12 +1030,12 @@ public class GitHub {
List<String> scopes,
String note,
String note_url) throws IOException {
Requester requester = new Requester(this).with("client_secret", clientSecret)
Requester requester = createRequest().with("client_secret", clientSecret)
.with("scopes", scopes)
.with("note", note)
.with("note_url", note_url);
return requester.method("PUT").to("/authorizations/clients/" + clientId, GHAuthorization.class);
return requester.method("PUT").withUrlPath("/authorizations/clients/" + clientId).fetch(GHAuthorization.class);
}
/**
@@ -1009,7 +1049,7 @@ public class GitHub {
* authorization</a>
*/
public void deleteAuth(long id) throws IOException {
retrieve().method("DELETE").to("/authorizations/" + id);
createRequest().method("DELETE").withUrlPath("/authorizations/" + id).send();
}
/**
@@ -1026,7 +1066,8 @@ public class GitHub {
* authorization</a>
*/
public GHAuthorization checkAuth(@Nonnull String clientId, @Nonnull String accessToken) throws IOException {
return retrieve().to("/applications/" + clientId + "/tokens/" + accessToken, GHAuthorization.class);
return createRequest().withUrlPath("/applications/" + clientId + "/tokens/" + accessToken)
.fetch(GHAuthorization.class);
}
/**
@@ -1043,8 +1084,9 @@ public class GitHub {
* authorization</a>
*/
public GHAuthorization resetAuth(@Nonnull String clientId, @Nonnull String accessToken) throws IOException {
return retrieve().method("POST")
.to("/applications/" + clientId + "/tokens/" + accessToken, GHAuthorization.class);
return createRequest().method("POST")
.withUrlPath("/applications/" + clientId + "/tokens/" + accessToken)
.fetch(GHAuthorization.class);
}
/**
@@ -1057,7 +1099,8 @@ public class GitHub {
* authorizations</a>
*/
public PagedIterable<GHAuthorization> listMyAuthorizations() throws IOException {
return retrieve().asPagedIterable("/authorizations", GHAuthorization[].class, item -> item.wrap(GitHub.this));
return createRequest().withUrlPath("/authorizations")
.toIterable(GHAuthorization[].class, item -> item.wrap(this));
}
/**
@@ -1074,7 +1117,7 @@ public class GitHub {
@Preview
@Deprecated
public GHApp getApp() throws IOException {
return retrieve().withPreview(MACHINE_MAN).to("/app", GHApp.class).wrapUp(this);
return createRequest().withPreview(MACHINE_MAN).withUrlPath("/app").fetch(GHApp.class).wrapUp(this);
}
/**
@@ -1084,7 +1127,7 @@ public class GitHub {
*/
public boolean isCredentialValid() {
try {
retrieve().to("/user", GHUser.class);
createRequest().withUrlPath("/user").fetch(GHUser.class);
return true;
} catch (IOException e) {
if (LOGGER.isLoggable(FINE))
@@ -1105,7 +1148,7 @@ public class GitHub {
* @see <a href="https://developer.github.com/v3/meta/#meta">Get Meta</a>
*/
public GHMeta getMeta() throws IOException {
return retrieve().to("/meta", GHMeta.class);
return createRequest().withUrlPath("/meta").fetch(GHMeta.class);
}
GHUser intern(GHUser user) throws IOException {
@@ -1132,7 +1175,7 @@ public class GitHub {
* the io exception
*/
public GHProject getProject(long id) throws IOException {
return retrieve().withPreview(INERTIA).to("/projects/" + id, GHProject.class).wrap(this);
return createRequest().withPreview(INERTIA).withUrlPath("/projects/" + id).fetch(GHProject.class).wrap(this);
}
/**
@@ -1145,7 +1188,10 @@ public class GitHub {
* the io exception
*/
public GHProjectColumn getProjectColumn(long id) throws IOException {
return retrieve().withPreview(INERTIA).to("/projects/columns/" + id, GHProjectColumn.class).wrap(this);
return createRequest().withPreview(INERTIA)
.withUrlPath("/projects/columns/" + id)
.fetch(GHProjectColumn.class)
.wrap(this);
}
/**
@@ -1158,7 +1204,10 @@ public class GitHub {
* the io exception
*/
public GHProjectCard getProjectCard(long id) throws IOException {
return retrieve().withPreview(INERTIA).to("/projects/columns/cards/" + id, GHProjectCard.class).wrap(this);
return createRequest().withPreview(INERTIA)
.withUrlPath("/projects/columns/cards/" + id)
.fetch(GHProjectCard.class)
.wrap(this);
}
private static class GHApiInfo {
@@ -1188,7 +1237,7 @@ public class GitHub {
*/
public void checkApiUrlValidity() throws IOException {
try {
retrieve().to("/", GHApiInfo.class).check(apiUrl);
createRequest().withUrlPath("/").fetch(GHApiInfo.class).check(apiUrl);
} catch (IOException e) {
if (isPrivateModeEnabled()) {
throw (IOException) new IOException(
@@ -1320,8 +1369,9 @@ public class GitHub {
* @see <a href="https://developer.github.com/v3/repos/#list-all-public-repositories">documentation</a>
*/
public PagedIterable<GHRepository> listAllPublicRepositories(final String since) {
return retrieve().with("since", since)
.asPagedIterable("/repositories", GHRepository[].class, item -> item.wrap(GitHub.this));
return createRequest().with("since", since)
.withUrlPath("/repositories")
.toIterable(GHRepository[].class, item -> item.wrap(this));
}
/**
@@ -1339,9 +1389,13 @@ public class GitHub {
* @see GHRepository#renderMarkdown(String, MarkdownMode) GHRepository#renderMarkdown(String, MarkdownMode)
*/
public Reader renderMarkdown(String text) throws IOException {
return new InputStreamReader(new Requester(this).with(new ByteArrayInputStream(text.getBytes("UTF-8")))
.contentType("text/plain;charset=UTF-8")
.asStream("/markdown/raw"), "UTF-8");
return new InputStreamReader(
createRequest().method("POST")
.with(new ByteArrayInputStream(text.getBytes("UTF-8")))
.contentType("text/plain;charset=UTF-8")
.withUrlPath("/markdown/raw")
.fetchStream(),
"UTF-8");
}
static URL parseURL(String s) {

View File

@@ -1,10 +1,23 @@
package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Objects;
import javax.annotation.Nonnull;
/**
* @author Kohsuke Kawaguchi
*/
class JsonRateLimit {
GHRateLimit resources;
@Nonnull
final GHRateLimit resources;
@JsonCreator
private JsonRateLimit(@Nonnull @JsonProperty(value = "resources", required = true) GHRateLimit resources) {
Objects.requireNonNull(resources);
this.resources = resources;
}
}

View File

@@ -5,6 +5,8 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Nonnull;
/**
* {@link Iterable} that returns {@link PagedIterator}
*
@@ -33,6 +35,12 @@ public abstract class PagedIterable<T> implements Iterable<T> {
return this;
}
/**
* Returns an iterator over elements of type {@code T}.
*
* @return an Iterator.
*/
@Nonnull
public final PagedIterator<T> iterator() {
return _iterator(size);
}
@@ -44,6 +52,7 @@ public abstract class PagedIterable<T> implements Iterable<T> {
* the page size
* @return the paged iterator
*/
@Nonnull
public abstract PagedIterator<T> _iterator(int pageSize);
/**
@@ -52,7 +61,7 @@ public abstract class PagedIterable<T> implements Iterable<T> {
* @return the list
*/
public List<T> asList() {
List<T> r = new ArrayList<T>();
ArrayList<T> r = new ArrayList<>();
for (PagedIterator<T> i = iterator(); i.hasNext();) {
r.addAll(i.nextPage());
}
@@ -65,7 +74,7 @@ public abstract class PagedIterable<T> implements Iterable<T> {
* @return the set
*/
public Set<T> asSet() {
LinkedHashSet<T> r = new LinkedHashSet<T>();
LinkedHashSet<T> r = new LinkedHashSet<>();
for (PagedIterator<T> i = iterator(); i.hasNext();) {
r.addAll(i.nextPage());
}

View File

@@ -64,15 +64,7 @@ class Previews {
*
* @see <a href="https://developer.github.com/v3/previews/#reactions">GitHub API Previews</a>
*/
static final String SQUIRREL_GIRL = "application/vnd.github.squirrel-girl-preview";
/**
* Label emoji, search, and descriptions
*
* @see <a href="https://developer.github.com/v3/previews/#label-emoji-search-and-descriptions">GitHub API
* Previews</a>
*/
static final String SYMMETRA = "application/vnd.github.symmetra-preview+json";
static final String SQUIRREL_GIRL = "application/vnd.github.squirrel-girl-preview+json";
/**
* Require signed commits

View File

@@ -24,7 +24,6 @@
package org.kohsuke.github;
import com.fasterxml.jackson.databind.JsonMappingException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
@@ -44,6 +43,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -53,19 +53,20 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.WillClose;
import static java.util.Arrays.asList;
import static java.util.logging.Level.*;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.kohsuke.github.GitHub.MAPPER;
import static org.kohsuke.github.GitHub.connect;
/**
* A builder pattern for making HTTP call and parsing its output.
@@ -77,10 +78,13 @@ class Requester {
private final List<Entry> args = new ArrayList<Entry>();
private final Map<String, String> headers = new LinkedHashMap<String, String>();
@Nonnull
private String urlPath = "/";
/**
* Request method.
*/
private String method = "POST";
private String method = "GET";
private String contentType = null;
private InputStream body;
@@ -91,8 +95,8 @@ class Requester {
private boolean forceBody;
private static class Entry {
String key;
Object value;
final String key;
final Object value;
private Entry(String key, Object value) {
this.key = key;
@@ -281,9 +285,9 @@ class Requester {
* @return the requester
*/
public Requester set(String key, Object value) {
for (Entry e : args) {
if (e.key.equals(key)) {
e.value = value;
for (int index = 0; index < args.size(); index++) {
if (args.get(index).key.equals(key)) {
args.set(index, new Entry(key, value));
return this;
}
}
@@ -314,6 +318,56 @@ class Requester {
return this;
}
/**
* NOT FOR PUBLIC USE. Do not make this method public.
* <p>
* Sets the path component of api URL without URI encoding.
* <p>
* Should only be used when passing a literal URL field from a GHObject, such as {@link GHContent#refresh()} or when
* needing to set query parameters on requests methods that don't usually have them, such as
* {@link GHRelease#uploadAsset(String, InputStream, String)}.
*
* @param urlOrPath
* the content type
* @return the requester
*/
Requester setRawUrlPath(String urlOrPath) {
Objects.requireNonNull(urlOrPath);
this.urlPath = urlOrPath;
return this;
}
/**
* Path component of api URL. Appended to api url.
* <p>
* If urlPath starts with a slash, it will be URI encoded as a path. If it starts with anything else, it will be
* used as is.
*
* @param urlPathItems
* the content type
* @return the requester
*/
public Requester withUrlPath(String... urlPathItems) {
if (!this.urlPath.startsWith("/")) {
throw new GHException("Cannot append to url path after setting a raw path");
}
if (urlPathItems.length == 1 && !urlPathItems[0].startsWith("/")) {
return setRawUrlPath(urlPathItems[0]);
}
String tailUrlPath = String.join("/", urlPathItems);
if (this.urlPath.endsWith("/")) {
tailUrlPath = StringUtils.stripStart(tailUrlPath, "/");
} else {
tailUrlPath = StringUtils.prependIfMissing(tailUrlPath, "/");
}
this.urlPath += urlPathEncode(tailUrlPath);
return this;
}
/**
* Small number of GitHub APIs use HTTP methods somewhat inconsistently, and use a body where it's not expected.
* Normally whether parameters go as query parameters or a body depends on the HTTP verb in use, but this method
@@ -325,143 +379,120 @@ class Requester {
}
/**
* To.
* Sends a request to the specified URL and checks that it is sucessful.
*
* @param tailApiUrl
* the tail api url
* @throws IOException
* the io exception
*/
public void to(String tailApiUrl) throws IOException {
_to(tailApiUrl, null, null);
public void send() throws IOException {
_fetch(() -> parse(null, null));
}
/**
* Sends a request to the specified URL, and parses the response into the given type via databinding.
* Sends a request and parses the response into the given type via databinding.
*
* @param <T>
* the type parameter
* @param tailApiUrl
* the tail api url
* @param type
* the type
* @return {@link Reader} that reads the response.
* @throws IOException
* if the server returns 4xx/5xx responses.
*/
public <T> T to(String tailApiUrl, Class<T> type) throws IOException {
return _to(tailApiUrl, type, null);
public <T> T fetch(@Nonnull Class<T> type) throws IOException {
return _fetch(() -> parse(type, null));
}
/**
* Like {@link #to(String, Class)} but updates an existing object instead of creating a new instance.
* Sends a request and parses the response into an array of the given type via databinding.
*
* @param <T>
* the type parameter
* @param type
* the type
* @return {@link Reader} that reads the response.
* @throws IOException
* if the server returns 4xx/5xx responses.
*/
public <T> T[] fetchArray(@Nonnull Class<T[]> type) throws IOException {
T[] result = null;
try {
// for arrays we might have to loop for pagination
// use the iterator to handle it
List<T[]> pages = new ArrayList<>();
int totalSize = 0;
for (Iterator<T[]> iterator = asIterator(type, 0); iterator.hasNext();) {
T[] nextResult = iterator.next();
totalSize += Array.getLength(nextResult);
pages.add(nextResult);
}
result = concatenatePages(type, pages, totalSize);
} catch (GHException e) {
// if there was an exception inside the iterator it is wrapped as a GHException
// if the wrapped exception is an IOException, throw that
if (e.getCause() instanceof IOException) {
throw (IOException) e.getCause();
} else {
throw e;
}
}
return result;
}
/**
* Like {@link #fetch(Class)} but updates an existing object instead of creating a new instance.
*
* @param <T>
* the type parameter
* @param tailApiUrl
* the tail api url
* @param existingInstance
* the existing instance
* @return the t
* @throws IOException
* the io exception
*/
public <T> T to(String tailApiUrl, T existingInstance) throws IOException {
return _to(tailApiUrl, null, existingInstance);
}
@SuppressFBWarnings("SBSC_USE_STRINGBUFFER_CONCATENATION")
private <T> T _to(String tailApiUrl, Class<T> type, T instance) throws IOException {
if (!isMethodWithBody() && !args.isEmpty()) {
boolean questionMarkFound = tailApiUrl.indexOf('?') != -1;
tailApiUrl += questionMarkFound ? '&' : '?';
for (Iterator<Entry> it = args.listIterator(); it.hasNext();) {
Entry arg = it.next();
tailApiUrl += arg.key + '=' + URLEncoder.encode(arg.value.toString(), "UTF-8");
if (it.hasNext()) {
tailApiUrl += '&';
}
}
}
while (true) {// loop while API rate limit is hit
setupConnection(root.getApiURL(tailApiUrl));
buildRequest();
try {
T result = parse(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);
setResponseHeaders(nextResult);
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 setResponseHeaders(result);
} catch (IOException e) {
handleApiError(e);
} finally {
noteRateLimit(tailApiUrl);
}
}
public <T> T fetchInto(@Nonnull T existingInstance) throws IOException {
return _fetch(() -> parse(null, existingInstance));
}
/**
* Makes a request and just obtains the HTTP status code.
* Makes a request and just obtains the HTTP status code. Method does not throw exceptions for many status codes
* that would otherwise throw.
*
* @param tailApiUrl
* the tail api url
* @return the int
* @throws IOException
* the io exception
*/
public int asHttpStatusCode(String tailApiUrl) throws IOException {
while (true) {// loop while API rate limit is hit
method("GET");
setupConnection(root.getApiURL(tailApiUrl));
buildRequest();
try {
return uc.getResponseCode();
} catch (IOException e) {
handleApiError(e);
} finally {
noteRateLimit(tailApiUrl);
}
}
public int fetchHttpStatusCode() throws IOException {
return _fetch(() -> uc.getResponseCode());
}
/**
* As stream input stream.
*
* @param tailApiUrl
* the tail api url
* @return the input stream
* @throws IOException
* the io exception
*/
public InputStream asStream(String tailApiUrl) throws IOException {
while (true) {// loop while API rate limit is hit
setupConnection(root.getApiURL(tailApiUrl));
public InputStream fetchStream() throws IOException {
return _fetch(() -> parse(InputStream.class, null));
}
buildRequest();
private <T> T _fetch(SupplierThrows<T, IOException> supplier) throws IOException {
String tailApiUrl = buildTailApiUrl(urlPath);
URL url = root.getApiURL(tailApiUrl);
return _fetch(tailApiUrl, url, supplier);
}
private <T> T _fetch(String tailApiUrl, URL url, SupplierThrows<T, IOException> supplier) throws IOException {
while (true) {// loop while API rate limit is hit
uc = setupConnection(url);
try {
return wrapStream(uc.getInputStream());
retryInvalidCached404Response();
return supplier.get();
} catch (IOException e) {
handleApiError(e);
} finally {
@@ -470,11 +501,52 @@ class Requester {
}
}
private <T> T[] concatenatePages(Class<T[]> type, List<T[]> pages, int totalLength) {
T[] result = type.cast(Array.newInstance(type.getComponentType(), totalLength));
int position = 0;
for (T[] page : pages) {
final int pageLength = Array.getLength(page);
System.arraycopy(page, 0, result, position, pageLength);
position += pageLength;
}
return result;
}
private String buildTailApiUrl(String tailApiUrl) {
if (!isMethodWithBody() && !args.isEmpty()) {
try {
boolean questionMarkFound = tailApiUrl.indexOf('?') != -1;
StringBuilder argString = new StringBuilder();
argString.append(questionMarkFound ? '&' : '?');
for (Iterator<Entry> it = args.listIterator(); it.hasNext();) {
Entry arg = it.next();
argString.append(URLEncoder.encode(arg.key, StandardCharsets.UTF_8.name()));
argString.append('=');
argString.append(URLEncoder.encode(arg.value.toString(), StandardCharsets.UTF_8.name()));
if (it.hasNext()) {
argString.append('&');
}
}
tailApiUrl += argString;
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e); // UTF-8 is mandatory
}
}
return tailApiUrl;
}
private void noteRateLimit(String tailApiUrl) {
if (uc == null) {
return;
}
if (tailApiUrl.startsWith("/search")) {
// the search API uses a different rate limit
return;
}
String limitString = uc.getHeaderField("X-RateLimit-Limit");
if (StringUtils.isBlank(limitString)) {
// if we are missing a header, return fast
@@ -538,24 +610,25 @@ class Requester {
/**
* Set up the request parameters or POST payload.
*/
private void buildRequest() throws IOException {
private void buildRequest(HttpURLConnection connection) throws IOException {
if (isMethodWithBody()) {
uc.setDoOutput(true);
connection.setDoOutput(true);
if (body == null) {
uc.setRequestProperty("Content-type", defaultString(contentType, "application/json"));
connection.setRequestProperty("Content-type", defaultString(contentType, "application/json"));
Map json = new HashMap();
for (Entry e : args) {
json.put(e.key, e.value);
}
MAPPER.writeValue(uc.getOutputStream(), json);
MAPPER.writeValue(connection.getOutputStream(), json);
} else {
uc.setRequestProperty("Content-type", defaultString(contentType, "application/x-www-form-urlencoded"));
connection.setRequestProperty("Content-type",
defaultString(contentType, "application/x-www-form-urlencoded"));
try {
byte[] bytes = new byte[32768];
int read;
while ((read = body.read(bytes)) != -1) {
uc.getOutputStream().write(bytes, 0, read);
connection.getOutputStream().write(bytes, 0, read);
}
} finally {
body.close();
@@ -568,32 +641,28 @@ class Requester {
return forceBody || !METHODS_WITHOUT_BODY.contains(method);
}
<T> PagedIterable<T> asPagedIterable(String tailApiUrl, Class<T[]> type, Consumer<T> consumer) {
return new PagedIterableWithConsumer<>(type, this, tailApiUrl, consumer);
<T> PagedIterable<T> toIterable(Class<T[]> type, Consumer<T> consumer) {
return new PagedIterableWithConsumer<>(type, consumer);
}
static class PagedIterableWithConsumer<S> extends PagedIterable<S> {
class PagedIterableWithConsumer<T> extends PagedIterable<T> {
private final Class<S[]> clazz;
private final Requester requester;
private final String tailApiUrl;
private final Consumer<S> consumer;
private final Class<T[]> clazz;
private final Consumer<T> consumer;
PagedIterableWithConsumer(Class<S[]> clazz, Requester requester, String tailApiUrl, Consumer<S> consumer) {
PagedIterableWithConsumer(Class<T[]> clazz, Consumer<T> consumer) {
this.clazz = clazz;
this.tailApiUrl = tailApiUrl;
this.requester = requester;
this.consumer = consumer;
}
@Override
public PagedIterator<S> _iterator(int pageSize) {
final Iterator<S[]> iterator = requester.asIterator(tailApiUrl, clazz, pageSize);
return new PagedIterator<S>(iterator) {
public PagedIterator<T> _iterator(int pageSize) {
final Iterator<T[]> iterator = asIterator(clazz, pageSize);
return new PagedIterator<T>(iterator) {
@Override
protected void wrapUp(S[] page) {
protected void wrapUp(T[] page) {
if (consumer != null) {
for (S item : page) {
for (T item : page) {
consumer.accept(item);
}
}
@@ -605,37 +674,40 @@ class Requester {
/**
* Loads paginated resources.
*
* Every iterator call reports a new batch.
* @param type
* type of each page (not the items in the page).
* @param pageSize
* the size of the
* @param <T>
* type of each page (not the items in the page).
* @return
*/
<T> Iterator<T> asIterator(String tailApiUrl, Class<T> type, int pageSize) {
method("GET");
if (pageSize != 0)
args.add(new Entry("per_page", pageSize));
StringBuilder s = new StringBuilder(tailApiUrl);
if (!args.isEmpty()) {
boolean first = true;
try {
for (Entry a : args) {
s.append(first ? '?' : '&');
first = false;
s.append(URLEncoder.encode(a.key, "UTF-8"));
s.append('=');
s.append(URLEncoder.encode(a.value.toString(), "UTF-8"));
}
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e); // UTF-8 is mandatory
}
<T> Iterator<T> asIterator(Class<T> type, int pageSize) {
if (!"GET".equals(method)) {
throw new IllegalStateException("Request method \"GET\" is required for iterator.");
}
if (pageSize > 0)
args.add(new Entry("per_page", pageSize));
String tailApiUrl = buildTailApiUrl(urlPath);
try {
return new PagingIterator<T>(type, tailApiUrl, root.getApiURL(s.toString()));
return new PagingIterator<>(type, tailApiUrl, root.getApiURL(tailApiUrl));
} catch (IOException e) {
throw new GHException("Unable to build github Api URL", e);
}
}
/**
* May be used for any item that has pagination information.
*
* Works for array responses, also works for search results which are single instances with an array of items
* inside.
*
* @param <T>
* type of each page (not the items in the page).
*/
class PagingIterator<T> implements Iterator<T> {
private final Class<T> type;
@@ -682,19 +754,9 @@ class Requester {
return; // no more data to fetch
try {
while (true) {// loop while API rate limit is hit
setupConnection(url);
try {
next = parse(type, null);
assert next != null;
findNextURL();
return;
} catch (IOException e) {
handleApiError(e);
} finally {
noteRateLimit(tailApiUrl);
}
}
next = _fetch(tailApiUrl, url, () -> parse(type, null));
assert next != null;
findNextURL();
} catch (IOException e) {
throw new GHException("Failed to retrieve " + url, e);
}
@@ -723,46 +785,49 @@ class Requester {
}
}
private void setupConnection(URL url) throws IOException {
private HttpURLConnection setupConnection(URL url) throws IOException {
if (LOGGER.isLoggable(FINE)) {
LOGGER.log(FINE,
"GitHub API request [" + (root.login == null ? "anonymous" : root.login) + "]: " + method + " "
+ url.toString());
}
uc = root.getConnector().connect(url);
HttpURLConnection connection = root.getConnector().connect(url);
// if the authentication is needed but no credential is given, try it anyway (so that some calls
// that do work with anonymous access in the reduced form should still work.)
if (root.encodedAuthorization != null)
uc.setRequestProperty("Authorization", root.encodedAuthorization);
connection.setRequestProperty("Authorization", root.encodedAuthorization);
for (Map.Entry<String, String> e : headers.entrySet()) {
String v = e.getValue();
if (v != null)
uc.setRequestProperty(e.getKey(), v);
connection.setRequestProperty(e.getKey(), v);
}
setRequestMethod(uc);
uc.setRequestProperty("Accept-Encoding", "gzip");
setRequestMethod(connection);
connection.setRequestProperty("Accept-Encoding", "gzip");
buildRequest(connection);
return connection;
}
private void setRequestMethod(HttpURLConnection uc) throws IOException {
private void setRequestMethod(HttpURLConnection connection) throws IOException {
try {
uc.setRequestMethod(method);
connection.setRequestMethod(method);
} catch (ProtocolException e) {
// JDK only allows one of the fixed set of verbs. Try to override that
try {
Field $method = HttpURLConnection.class.getDeclaredField("method");
$method.setAccessible(true);
$method.set(uc, method);
$method.set(connection, method);
} catch (Exception x) {
throw (IOException) new IOException("Failed to set the custom verb").initCause(x);
}
// sun.net.www.protocol.https.DelegatingHttpsURLConnection delegates to another HttpURLConnection
try {
Field $delegate = uc.getClass().getDeclaredField("delegate");
Field $delegate = connection.getClass().getDeclaredField("delegate");
$delegate.setAccessible(true);
Object delegate = $delegate.get(uc);
Object delegate = $delegate.get(connection);
if (delegate instanceof HttpURLConnection) {
HttpURLConnection nested = (HttpURLConnection) delegate;
setRequestMethod(nested);
@@ -773,7 +838,7 @@ class Requester {
throw (IOException) new IOException("Failed to set the custom verb").initCause(x);
}
}
if (!uc.getRequestMethod().equals(method))
if (!connection.getRequestMethod().equals(method))
throw new IllegalStateException("Failed to set the request method to " + method);
}
@@ -815,22 +880,26 @@ class Requester {
return null;
}
r = new InputStreamReader(wrapStream(uc.getInputStream()), "UTF-8");
if (type != null && type.equals(InputStream.class)) {
return type.cast(wrapStream(uc.getInputStream()));
}
r = new InputStreamReader(wrapStream(uc.getInputStream()), StandardCharsets.UTF_8);
String data = IOUtils.toString(r);
if (type != null)
try {
return setResponseHeaders(MAPPER.readValue(data, type));
} catch (JsonMappingException e) {
throw (IOException) new IOException("Failed to deserialize " + data).initCause(e);
String message = "Failed to deserialize " + data;
throw (IOException) new IOException(message).initCause(e);
}
if (instance != null) {
return setResponseHeaders(MAPPER.readerForUpdating(instance).<T>readValue(data));
}
return null;
} catch (FileNotFoundException e) {
// java.net.URLConnection handles 404 exception has FileNotFoundException, don't wrap exception in
// HttpException
// to preserve backward compatibility
// java.net.URLConnection handles 404 exception as FileNotFoundException,
// don't wrap exception in HttpException to preserve backward compatibility
throw e;
} catch (IOException e) {
if (e instanceof SocketTimeoutException && timeouts > 0) {
@@ -843,6 +912,29 @@ class Requester {
}
}
private void retryInvalidCached404Response() throws IOException {
// WORKAROUND FOR ISSUE #669:
// When the Requester detects a 404 response with an ETag (only happpens when the server's 304
// is bogus and would cause cache corruption), try the query again with new request header
// that forces the server to not return 304 and return new data instead.
//
// This solution is transparent to users of this library and automatically handles a
// situation that was cause insidious and hard to debug bad responses in caching
// scenarios. If GitHub ever fixes their issue and/or begins providing accurate ETags to
// their 404 responses, this will result in at worst two requests being made for each 404
// responses. However, only the second request will count against rate limit.
int responseCode = uc.getResponseCode();
if (responseCode == 404 && Objects.equals(uc.getRequestMethod(), "GET") && uc.getHeaderField("ETag") != null
&& !Objects.equals(uc.getRequestProperty("Cache-Control"), "no-cache")) {
uc = setupConnection(uc.getURL());
// Setting "Cache-Control" to "no-cache" stops the cache from supplying
// "If-Modified-Since" or "If-None-Match" values.
// This makes GitHub give us current data (not incorrectly cached data)
uc.setRequestProperty("Cache-Control", "no-cache");
uc.getResponseCode();
}
}
private <T> T setResponseHeaders(T readValue) {
if (readValue instanceof GHObject[]) {
for (GHObject ghObject : (GHObject[]) readValue) {
@@ -894,7 +986,7 @@ class Requester {
InputStream es = wrapStream(uc.getErrorStream());
if (es != null) {
try {
String error = IOUtils.toString(es, "UTF-8");
String error = IOUtils.toString(es, StandardCharsets.UTF_8);
if (e instanceof FileNotFoundException) {
// pass through 404 Not Found to allow the caller to handle it intelligently
e = (IOException) new GHFileNotFoundException(error).withResponseHeaderFields(uc).initCause(e);
@@ -961,4 +1053,27 @@ class Requester {
private static final List<String> METHODS_WITHOUT_BODY = asList("GET", "DELETE");
private static final Logger LOGGER = Logger.getLogger(Requester.class.getName());
/**
* Represents a supplier of results that can throw.
*
* <p>
* This is a <a href="package-summary.html">functional interface</a> whose functional method is {@link #get()}.
*
* @param <T>
* the type of results supplied by this supplier
* @param <E>
* the type of throwable that could be thrown
*/
@FunctionalInterface
interface SupplierThrows<T, E extends Throwable> {
/**
* Gets a result.
*
* @return a result
* @throws E
*/
T get() throws E;
}
}

View File

@@ -7,6 +7,7 @@ import com.fasterxml.jackson.annotation.JsonSetter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import javax.annotation.Nonnull;
@@ -482,12 +483,15 @@ public final class ReadOnlyObjects {
* <li>Fields final and lists unmodifiable</li>
* <li>Construction behavior can be controlled - if values depended on each other or needed to be set in a specific
* order, this could do that.</li>
* <li>JsonProrperty "required" works on JsonCreator constructors - lets annotation define required values</li>
* </ul>
* Con:
* <ul>
* <li>There is no way you'd know about this without some research</li>
* <li>Specific annotations needed</li>
* <li>Brittle and verbose - not friendly to optional fields or large number of fields</li>
* <li>Nonnull annotations are misleading - null value is not checked even for "required" constructor
* parameters</li>
* <li>Brittle and verbose - not friendly to large number of fields</li>
* </ul>
*
* @author Liam Newman
@@ -503,14 +507,37 @@ public final class ReadOnlyObjects {
private final List<String> pages;
private final List<String> importer;
/**
*
* @param hooks
* the hooks - required property works, but only on creator json properties like this, ignores
* Nonnull, checked manually
* @param git
* the git list - required property works, but only on creator json properties like this, misleading
* Nonnull annotation
* @param web
* the web list - misleading Nonnull annotation
* @param api
* the api list - misleading Nonnull annotation
* @param pages
* the pages list - misleading Nonnull annotation
* @param importer
* the importer list - misleading Nonnull annotation
* @param verifiablePasswordAuthentication
* true or false
*/
@JsonCreator
private GHMetaGettersFinalCreator(@Nonnull @JsonProperty("hooks") List<String> hooks,
@Nonnull @JsonProperty("git") List<String> git,
private GHMetaGettersFinalCreator(@Nonnull @JsonProperty(value = "hooks", required = true) List<String> hooks,
@Nonnull @JsonProperty(value = "git", required = true) List<String> git,
@Nonnull @JsonProperty("web") List<String> web,
@Nonnull @JsonProperty("api") List<String> api,
@Nonnull @JsonProperty("pages") List<String> pages,
@Nonnull @JsonProperty("importer") List<String> importer,
@JsonProperty("verifiable_password_authentication") boolean verifiablePasswordAuthentication) {
// to ensure a value is actually not null we still have to do a null check
Objects.requireNonNull(hooks);
this.verifiablePasswordAuthentication = verifiablePasswordAuthentication;
this.hooks = Collections.unmodifiableList(hooks);
this.git = Collections.unmodifiableList(git);

View File

@@ -1,6 +1,6 @@
package org.kohsuke.github.extras.okhttp3;
import com.squareup.okhttp.CacheControl;
import okhttp3.CacheControl;
import okhttp3.ConnectionSpec;
import okhttp3.OkHttpClient;
import org.kohsuke.github.HttpConnector;

View File

@@ -25,4 +25,8 @@ permissions.put("pull_requests", GHPermissionType.WRITE);
GHAppInstallationToken appInstallationToken = appInstallation
.createToken(permissions)
.create();
// Or
GHAppInstallationToken appInstallationToken = appInstallation.createToken().create();
+-----+

View File

@@ -17,7 +17,7 @@ GitHub github = GitHub.connect();
GHRepository repo = github.createRepository(
"new-repository","this is my new repository",
"http://www.kohsuke.org/",true/*public*/);
"https://www.kohsuke.org/",true/*public*/);
repo.addCollaborators(github.getUser("abayer"),github.getUser("rtyler"));
repo.delete();
+-----+
@@ -139,10 +139,10 @@ GitHub github = GitHubBuilder.fromEnvironment().build();
Pluggable HTTP client
This library comes with a pluggable connector to use different HTTP client implementations
through <<<HttpConnector>>>. In particular, this means you can use {{{http://square.github.io/okhttp/}OkHttp}},
through <<<HttpConnector>>>. In particular, this means you can use {{{https://square.github.io/okhttp/}OkHttp}},
so we can make use of it's HTTP response cache.
Making a conditional request against the GitHub API and receiving a 304 response
{{{http://developer.github.com/v3/#conditional-requests}does not count against the rate limit}}.
{{{https://developer.github.com/v3/#conditional-requests}does not count against the rate limit}}.
The following code shows an example of how to set up persistent cache on the disk:

View File

@@ -2,7 +2,7 @@
<project name="GitHub API for Java">
<bannerLeft>
<name>GitHub API for Java</name>
<href>http://github-api.kohsuke.org/</href>
<href>https://github-api.kohsuke.org/</href>
</bannerLeft>
<skin>
<groupId>org.kohsuke</groupId>
@@ -13,7 +13,7 @@
<body>
<menu name="Git Hub API for Java">
<item name="Introduction" href="/index.html"/>
<item name="Download" href="http://mvnrepository.com/artifact/${project.groupId}/${project.artifactId}"/>
<item name="Download" href="https://mvnrepository.com/artifact/${project.groupId}/${project.artifactId}"/>
<item name="Source code" href="https://github.com/github-api/${project.artifactId}"/>
<item name="Mailing List" href="https://groups.google.com/forum/#!forum/github-api"/>
</menu>

View File

@@ -1,25 +0,0 @@
package org.kohsuke.github;
import org.junit.Before;
import org.kohsuke.randname.RandomNameGenerator;
import static org.junit.Assume.assumeTrue;
/**
* @author Kohsuke Kawaguchi
*/
public abstract class AbstractGitHubApiTestBase extends AbstractGitHubWireMockTest {
@Before
public void setUp() throws Exception {
assumeTrue("All tests inheriting from this class are not guaranteed to work without proxy",
mockGitHub.isUseProxy());
}
protected void kohsuke() {
String login = getUser().getLogin();
assumeTrue(login.equals("kohsuke") || login.equals("kohsuke2"));
}
protected static final RandomNameGenerator rnd = new RandomNameGenerator();
}

View File

@@ -11,6 +11,7 @@ import org.kohsuke.github.GHOrganization.Permission;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Pattern;
@@ -154,40 +155,19 @@ public class AppTest extends AbstractGitHubWireMockTest {
return getTempRepository(GITHUB_API_TEST_REPO);
}
@Ignore("Needs to be rewritten to not create new issues just to check that they can be found.")
@Test
public void testListIssues() throws IOException {
GHUser u = getUser();
GHRepository repository = getTestRepository();
Iterable<GHIssue> closedIssues = gitHub.getOrganization("github-api")
.getRepository("github-api")
.listIssues(GHIssueState.CLOSED);
GHMilestone milestone = repository.createMilestone(System.currentTimeMillis() + "", "Test Milestone");
milestone.close();
GHIssue unhomed = null;
GHIssue homed = null;
try {
unhomed = repository.createIssue("testing")
.body("this is body")
.assignee(u)
.label("bug")
.label("question")
.create();
assertEquals(unhomed.getNumber(), repository.getIssues(GHIssueState.OPEN, null).get(0).getNumber());
homed = repository.createIssue("testing")
.body("this is body")
.assignee(u)
.label("bug")
.label("question")
.milestone(milestone)
.create();
assertEquals(homed.getNumber(), repository.getIssues(GHIssueState.OPEN, milestone).get(0).getNumber());
} finally {
if (unhomed != null) {
unhomed.close();
}
if (homed != null) {
homed.close();
}
int x = 0;
for (GHIssue issue : closedIssues) {
assertNotNull(issue);
x++;
}
assertTrue(x > 150);
}
@Test
@@ -312,11 +292,9 @@ public class AppTest extends AbstractGitHubWireMockTest {
assertFalse(keys.isEmpty());
}
@Ignore("Needs mocking check")
@Test
public void testOrgFork() throws Exception {
kohsuke();
cleanupRepository(GITHUB_API_TEST_ORG + "/rubywm");
gitHub.getRepository("kohsuke/rubywm").forkTo(gitHub.getOrganization(GITHUB_API_TEST_ORG));
}
@@ -930,7 +908,7 @@ public class AppTest extends AbstractGitHubWireMockTest {
}
private void assertBlobContent(InputStream is) throws Exception {
String content = new String(IOUtils.toByteArray(is), "UTF-8");
String content = new String(IOUtils.toByteArray(is), StandardCharsets.UTF_8);
assertThat(content, containsString("Copyright (c) 2011- Kohsuke Kawaguchi and other contributors"));
assertThat(content, containsString("FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR"));
assertThat(content.length(), is(1104));

View File

@@ -4,6 +4,7 @@ import org.junit.Test;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -101,8 +102,9 @@ public class GHAppTest extends AbstractGitHubWireMockTest {
permissions.put("contents", GHPermissionType.READ);
permissions.put("metadata", GHPermissionType.READ);
// Create token specifying both permissions and repository ids
GHAppInstallationToken installationToken = installation.createToken(permissions)
.repositoryIds(Arrays.asList((long) 111111111))
.repositoryIds(Collections.singletonList((long) 111111111))
.create();
assertThat(installationToken.getToken(), is("bogus"));
@@ -114,6 +116,16 @@ public class GHAppTest extends AbstractGitHubWireMockTest {
assertThat(installationToken.getRepositories().size(), is(1));
assertThat(repository.getId(), is((long) 111111111));
assertThat(repository.getName(), is("bogus"));
// Create token with no payload
GHAppInstallationToken installationToken2 = installation.createToken().create();
assertThat(installationToken2.getToken(), is("bogus"));
assertThat(installationToken2.getPermissions().size(), is(4));
assertThat(installationToken2.getRepositorySelection(), is(GHRepositorySelection.ALL));
assertThat(installationToken2.getExpiresAt(), is(GitHub.parseDate("2019-12-19T12:27:59Z")));
assertNull(installationToken2.getRepositories());;
}
private void testAppInstallation(GHAppInstallation appInstallation) throws IOException {

View File

@@ -125,4 +125,36 @@ public class GHContentIntegrationTest extends AbstractGitHubWireMockTest {
equalTo("{\"message\":\"Not Found\",\"documentation_url\":\"https://developer.github.com/v3/repos/contents/#get-contents\"}"));
}
}
@Test
public void testMIMESmall() throws IOException {
GHRepository ghRepository = getTempRepository();
GHContentBuilder ghContentBuilder = ghRepository.createContent();
ghContentBuilder.message("Some commit msg");
ghContentBuilder.path("MIME-Small.md");
ghContentBuilder.content("123456789012345678901234567890123456789012345678901234567");
ghContentBuilder.commit();
}
@Test
public void testMIMELong() throws IOException {
GHRepository ghRepository = getTempRepository();
GHContentBuilder ghContentBuilder = ghRepository.createContent();
ghContentBuilder.message("Some commit msg");
ghContentBuilder.path("MIME-Long.md");
ghContentBuilder.content("1234567890123456789012345678901234567890123456789012345678");
ghContentBuilder.commit();
}
@Test
public void testMIMELonger() throws IOException {
GHRepository ghRepository = getTempRepository();
GHContentBuilder ghContentBuilder = ghRepository.createContent();
ghContentBuilder.message("Some commit msg");
ghContentBuilder.path("MIME-Long.md");
ghContentBuilder.content("123456789012345678901234567890123456789012345678901234567890"
+ "123456789012345678901234567890123456789012345678901234567890"
+ "123456789012345678901234567890123456789012345678901234567890"
+ "123456789012345678901234567890123456789012345678901234567890");
ghContentBuilder.commit();
}
}

View File

@@ -306,4 +306,14 @@ public class GHEventPayloadTest {
// @Test
// public void watch() throws Exception {}
@Test
@Payload("check-run")
public void checkRunEvent() throws Exception {
GHEventPayload.CheckRun event = GitHub.offline()
.parseEventPayload(payload.asReader(), GHEventPayload.CheckRun.class);
assertThat(event.getRepository().getName(), is("Hello-World"));
assertThat(event.getAction(), is("created"));
assertThat(event.getCheckRun().getName(), is("Octocoders-linter"));
}
}

View File

@@ -8,7 +8,7 @@ import java.util.List;
/**
* @author Martin van Zijl
*/
public class GHIssueEventTest extends AbstractGitHubApiTestBase {
public class GHIssueEventTest extends AbstractGitHubWireMockTest {
@Test
public void testEventsForSingleIssue() throws Exception {

View File

@@ -0,0 +1,158 @@
package org.kohsuke.github;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
import static org.kohsuke.github.GHDirection.DESC;
import static org.kohsuke.github.GHMarketplaceAccountType.ORGANIZATION;
import static org.kohsuke.github.GHMarketplaceListAccountBuilder.Sort.UPDATED;
/**
* Tests for the GitHub MarketPlace Plan API methods
*
* @author Paulo Miguel Almeida
*/
public class GHMarketplacePlanTest extends AbstractGitHubWireMockTest {
protected GitHubBuilder getGitHubBuilder() {
return super.getGitHubBuilder()
// ensure that only JWT will be used against the tests below
.withPassword(null, null)
.withJwtToken("bogus");
}
@Test
public void listMarketplacePlans() throws IOException {
List<GHMarketplacePlan> plans = gitHub.listMarketplacePlans().asList();
assertEquals(3, plans.size());
plans.forEach(this::testMarketplacePlan);
}
@Test
public void listAccounts() throws IOException {
List<GHMarketplacePlan> plans = gitHub.listMarketplacePlans().asList();
assertEquals(3, plans.size());
List<GHMarketplaceAccountPlan> marketplaceUsers = plans.get(0).listAccounts().createRequest().asList();
assertEquals(2, marketplaceUsers.size());
marketplaceUsers.forEach(this::testMarketplaceAccount);
}
@Test
public void listAccountsWithDirection() throws IOException {
List<GHMarketplacePlan> plans = gitHub.listMarketplacePlans().asList();
assertEquals(3, plans.size());
for (GHMarketplacePlan plan : plans) {
List<GHMarketplaceAccountPlan> marketplaceUsers = plan.listAccounts()
.direction(DESC)
.createRequest()
.asList();
assertEquals(2, marketplaceUsers.size());
marketplaceUsers.forEach(this::testMarketplaceAccount);
}
}
@Test
public void listAccountsWithSortAndDirection() throws IOException {
List<GHMarketplacePlan> plans = gitHub.listMarketplacePlans().asList();
assertEquals(3, plans.size());
for (GHMarketplacePlan plan : plans) {
List<GHMarketplaceAccountPlan> marketplaceUsers = plan.listAccounts()
.sort(UPDATED)
.direction(DESC)
.createRequest()
.asList();
assertEquals(2, marketplaceUsers.size());
marketplaceUsers.forEach(this::testMarketplaceAccount);
}
}
private void testMarketplacePlan(GHMarketplacePlan plan) {
// Non-nullable fields
assertNotNull(plan.getUrl());
assertNotNull(plan.getAccountsUrl());
assertNotNull(plan.getName());
assertNotNull(plan.getDescription());
assertNotNull(plan.getPriceModel());
assertNotNull(plan.getState());
// primitive fields
assertNotEquals(0L, plan.getId());
assertNotEquals(0L, plan.getNumber());
assertTrue(plan.getMonthlyPriceInCents() >= 0);
// list
assertEquals(2, plan.getBullets().size());
}
private void testMarketplaceAccount(GHMarketplaceAccountPlan account) {
// Non-nullable fields
assertNotNull(account.getLogin());
assertNotNull(account.getUrl());
assertNotNull(account.getType());
assertNotNull(account.getMarketplacePurchase());
testMarketplacePurchase(account.getMarketplacePurchase());
// primitive fields
assertNotEquals(0L, account.getId());
/* logical combination tests */
// Rationale: organization_billing_email is only set when account type is ORGANIZATION.
if (account.getType() == ORGANIZATION)
assertNotNull(account.getOrganizationBillingEmail());
else
assertNull(account.getOrganizationBillingEmail());
// Rationale: marketplace_pending_change isn't always set... This is what GitHub says about it:
// "When someone submits a plan change that won't be processed until the end of their billing cycle,
// you will also see the upcoming pending change."
if (account.getMarketplacePendingChange() != null)
testMarketplacePendingChange(account.getMarketplacePendingChange());
}
private void testMarketplacePurchase(GHMarketplacePurchase marketplacePurchase) {
// Non-nullable fields
assertNotNull(marketplacePurchase.getBillingCycle());
assertNotNull(marketplacePurchase.getNextBillingDate());
assertNotNull(marketplacePurchase.getUpdatedAt());
testMarketplacePlan(marketplacePurchase.getPlan());
/* logical combination tests */
// Rationale: if onFreeTrial is true, then we should see free_trial_ends_on property set to something
// different than null
if (marketplacePurchase.isOnFreeTrial())
assertNotNull(marketplacePurchase.getFreeTrialEndsOn());
else
assertNull(marketplacePurchase.getFreeTrialEndsOn());
// Rationale: if price model is PER_UNIT then unit_count can't be null
if (marketplacePurchase.getPlan().getPriceModel() == GHMarketplacePriceModel.PER_UNIT)
assertNotNull(marketplacePurchase.getUnitCount());
else
assertNull(marketplacePurchase.getUnitCount());
}
private void testMarketplacePendingChange(GHMarketplacePendingChange marketplacePendingChange) {
// Non-nullable fields
assertNotNull(marketplacePendingChange.getEffectiveDate());
testMarketplacePlan(marketplacePendingChange.getPlan());
// primitive fields
assertNotEquals(0L, marketplacePendingChange.getId());
/* logical combination tests */
// Rationale: if price model is PER_UNIT then unit_count can't be null
if (marketplacePendingChange.getPlan().getPriceModel() == GHMarketplacePriceModel.PER_UNIT)
assertNotNull(marketplacePendingChange.getUnitCount());
else
assertNull(marketplacePendingChange.getUnitCount());
}
}

View File

@@ -0,0 +1,16 @@
package org.kohsuke.github;
import org.junit.Test;
import static org.hamcrest.Matchers.*;
public class GHObjectTest extends org.kohsuke.github.AbstractGitHubWireMockTest {
@Test
public void test_toString() throws Exception {
GHOrganization org = gitHub.getOrganization(GITHUB_API_TEST_ORG);
assertThat(org.toString(),
containsString(
"login=github-api-test-org,location=<null>,blog=<null>,email=<null>,name=<null>,company=<null>,type=Organization,followers=0,following=0"));
}
}

View File

@@ -0,0 +1,33 @@
package org.kohsuke.github;
import org.junit.Test;
import java.io.IOException;
/**
* @author Martin van Zijl
*/
public class GHPersonTest extends AbstractGitHubWireMockTest {
@Test
public void testFieldsForOrganization() throws Exception {
GHRepository repo = getRepository();
GHUser owner = repo.getOwner();
assertEquals("Organization", owner.getType());
assertNotNull(owner.isSiteAdmin());
}
@Test
public void testFieldsForUser() throws Exception {
GHUser user = gitHub.getUser("kohsuke2");
assertEquals("User", user.getType());
assertNotNull(user.isSiteAdmin());
}
protected GHRepository getRepository() throws IOException {
return getRepository(gitHub);
}
private GHRepository getRepository(GitHub gitHub) throws IOException {
return gitHub.getOrganization("github-api-test-org").getRepository("github-api");
}
}

View File

@@ -1,10 +1,11 @@
package org.kohsuke.github;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import com.fasterxml.jackson.databind.exc.ValueInstantiationException;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer;
import org.hamcrest.CoreMatchers;
import org.junit.Test;
import org.kohsuke.github.extras.okhttp3.OkHttpConnector;
import java.io.IOException;
import java.util.Date;
@@ -34,6 +35,9 @@ import static org.hamcrest.Matchers.greaterThanOrEqualTo;
*/
public class GHRateLimitTest extends AbstractGitHubWireMockTest {
GHRateLimit rateLimit = null;
GHRateLimit previousLimit = null;
public GHRateLimitTest() {
useDefaultGitHub = false;
}
@@ -50,10 +54,10 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest {
snapshotNotAllowed();
assertThat(mockGitHub.getRequestCount(), equalTo(0));
GHRateLimit rateLimit = null;
Date lastReset = new Date(System.currentTimeMillis() / 1000L);
int lastRemaining = 5000;
// 4897 is just the what the limit was when the snapshot was taken
previousLimit = GHRateLimit
.fromHeaderRecord(new GHRateLimit.Record(5000, 4897, System.currentTimeMillis() / 1000L));
// Give this a moment
Thread.sleep(1000);
@@ -67,12 +71,8 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest {
// Since we already had rate limit info these don't request again
rateLimit = gitHub.lastRateLimit();
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.limit, equalTo(5000));
assertThat(rateLimit.getLimit(), equalTo(5000));
lastRemaining = rateLimit.getRemaining();
assertThat(rateLimit.getResetDate().compareTo(lastReset), greaterThanOrEqualTo(0));
lastReset = rateLimit.getResetDate();
verifyRateLimitValues(previousLimit, previousLimit.getRemaining());
previousLimit = rateLimit;
GHRateLimit headerRateLimit = rateLimit;
@@ -91,13 +91,9 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest {
rateLimit = gitHub.getRateLimit();
assertThat(mockGitHub.getRequestCount(), equalTo(2));
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.limit, equalTo(5000));
assertThat(rateLimit.getLimit(), equalTo(5000));
// rate limit request is free
assertThat(rateLimit.remaining, equalTo(lastRemaining));
assertThat(rateLimit.getRemaining(), equalTo(lastRemaining));
assertThat(rateLimit.getResetDate().compareTo(lastReset), greaterThanOrEqualTo(0));
// rate limit request is free, remaining is unchanged
verifyRateLimitValues(previousLimit, previousLimit.getRemaining());
previousLimit = rateLimit;
// Give this a moment
Thread.sleep(1000);
@@ -106,27 +102,20 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest {
rateLimit = gitHub.getRateLimit();
assertThat(mockGitHub.getRequestCount(), equalTo(3));
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.limit, equalTo(5000));
assertThat(rateLimit.getLimit(), equalTo(5000));
// rate limit request is free
assertThat(rateLimit.remaining, equalTo(lastRemaining));
assertThat(rateLimit.getRemaining(), equalTo(lastRemaining));
assertThat(rateLimit.getResetDate().compareTo(lastReset), greaterThanOrEqualTo(0));
// rate limit request is free, remaining is unchanged
verifyRateLimitValues(previousLimit, previousLimit.getRemaining());
previousLimit = rateLimit;
gitHub.getOrganization(GITHUB_API_TEST_ORG);
assertThat(mockGitHub.getRequestCount(), equalTo(4));
assertThat(gitHub.lastRateLimit(), not(equalTo(headerRateLimit)));
rateLimit = gitHub.lastRateLimit();
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.limit, equalTo(5000));
assertThat(rateLimit.getLimit(), equalTo(5000));
// Org costs limit to query
assertThat(rateLimit.remaining, equalTo(lastRemaining - 1));
assertThat(rateLimit.getRemaining(), equalTo(lastRemaining - 1));
assertThat(rateLimit.getResetDate().compareTo(lastReset), greaterThanOrEqualTo(0));
lastReset = rateLimit.getResetDate();
verifyRateLimitValues(previousLimit, previousLimit.getRemaining() - 1);
previousLimit = rateLimit;
headerRateLimit = rateLimit;
// ratelimit() should prefer headerRateLimit when it is most recent and not expired
@@ -141,13 +130,9 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest {
rateLimit = gitHub.getRateLimit();
assertThat(mockGitHub.getRequestCount(), equalTo(5));
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.limit, equalTo(5000));
assertThat(rateLimit.getLimit(), equalTo(5000));
// Org costs limit to query
assertThat(rateLimit.remaining, equalTo(lastRemaining - 1));
assertThat(rateLimit.getRemaining(), equalTo(lastRemaining - 1));
assertThat(rateLimit.getResetDate().compareTo(lastReset), greaterThanOrEqualTo(0));
// rate limit request is free, remaining is unchanged
verifyRateLimitValues(previousLimit, previousLimit.getRemaining());
previousLimit = rateLimit;
// When getRateLimit() succeeds, headerRateLimit updates as usual as well (if needed)
// These are separate instances, but should be equal
@@ -166,6 +151,27 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest {
assertThat(mockGitHub.getRequestCount(), equalTo(5));
}
private void verifyRateLimitValues(GHRateLimit previousLimit, int remaining) {
// Basic checks of values
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.getLimit(), equalTo(previousLimit.getLimit()));
assertThat(rateLimit.getRemaining(), equalTo(remaining));
// Check that the reset date of the current limit is not older than the previous one
assertThat(rateLimit.getResetDate().compareTo(previousLimit.getResetDate()), greaterThanOrEqualTo(0));
// Additional checks for record values
assertThat(rateLimit.getCore().getLimit(), equalTo(rateLimit.getLimit()));
assertThat(rateLimit.getCore().getRemaining(), equalTo(rateLimit.getRemaining()));
assertThat(rateLimit.getCore().getResetEpochSeconds(), equalTo(rateLimit.getResetEpochSeconds()));
assertThat(rateLimit.getCore().getResetDate(), equalTo(rateLimit.getResetDate()));
// Additional checks for deprecated values
assertThat(rateLimit.limit, equalTo(rateLimit.getLimit()));
assertThat(rateLimit.remaining, equalTo(rateLimit.getRemaining()));
assertThat(rateLimit.reset.getTime(), equalTo(rateLimit.getResetEpochSeconds()));
}
@Test
public void testGitHubEnterpriseDoesNotHaveRateLimit() throws Exception {
// Customized response that results in file not found the same as GitHub Enterprise
@@ -187,9 +193,7 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest {
rateLimit = gitHub.rateLimit();
assertThat(rateLimit.getCore(), instanceOf(GHRateLimit.UnknownLimitRecord.class));
assertThat(rateLimit.limit, equalTo(GHRateLimit.UnknownLimitRecord.unknownLimit));
assertThat(rateLimit.getLimit(), equalTo(GHRateLimit.UnknownLimitRecord.unknownLimit));
assertThat(rateLimit.remaining, equalTo(GHRateLimit.UnknownLimitRecord.unknownRemaining));
assertThat(rateLimit.getRemaining(), equalTo(GHRateLimit.UnknownLimitRecord.unknownRemaining));
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(1));
lastReset = rateLimit.getResetDate();
@@ -214,9 +218,7 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest {
rateLimit = gitHub.rateLimit();
assertThat(rateLimit.getCore(), instanceOf(GHRateLimit.UnknownLimitRecord.class));
assertThat(rateLimit.limit, equalTo(GHRateLimit.UnknownLimitRecord.unknownLimit));
assertThat(rateLimit.getLimit(), equalTo(GHRateLimit.UnknownLimitRecord.unknownLimit));
assertThat(rateLimit.remaining, equalTo(GHRateLimit.UnknownLimitRecord.unknownRemaining));
assertThat(rateLimit.getRemaining(), equalTo(GHRateLimit.UnknownLimitRecord.unknownRemaining));
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(1));
lastReset = rateLimit.getResetDate();
@@ -231,9 +233,7 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest {
assertThat(mockGitHub.getRequestCount(), equalTo(4));
assertThat(rateLimit.getCore(), instanceOf(GHRateLimit.UnknownLimitRecord.class));
assertThat(rateLimit.limit, equalTo(GHRateLimit.UnknownLimitRecord.unknownLimit));
assertThat(rateLimit.getLimit(), equalTo(GHRateLimit.UnknownLimitRecord.unknownLimit));
assertThat(rateLimit.remaining, equalTo(GHRateLimit.UnknownLimitRecord.unknownRemaining));
assertThat(rateLimit.getRemaining(), equalTo(GHRateLimit.UnknownLimitRecord.unknownRemaining));
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(1));
@@ -256,9 +256,7 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest {
// Since we already had rate limit info these don't request again
rateLimit = gitHub.lastRateLimit();
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.limit, equalTo(5000));
assertThat(rateLimit.getLimit(), equalTo(5000));
assertThat(rateLimit.remaining, equalTo(4978));
assertThat(rateLimit.getRemaining(), equalTo(4978));
assertThat(rateLimit.getResetDate().compareTo(lastReset), greaterThanOrEqualTo(0));
lastReset = rateLimit.getResetDate();
@@ -281,9 +279,7 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest {
assertThat(mockGitHub.getRequestCount(), equalTo(6));
assertThat(rateLimit.getCore(), instanceOf(GHRateLimit.UnknownLimitRecord.class));
assertThat(rateLimit.limit, equalTo(GHRateLimit.UnknownLimitRecord.unknownLimit));
assertThat(rateLimit.getLimit(), equalTo(GHRateLimit.UnknownLimitRecord.unknownLimit));
assertThat(rateLimit.remaining, equalTo(GHRateLimit.UnknownLimitRecord.unknownRemaining));
assertThat(rateLimit.getRemaining(), equalTo(GHRateLimit.UnknownLimitRecord.unknownRemaining));
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(1));
@@ -296,6 +292,36 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest {
Thread.sleep(1000);
}
@Test
public void testGitHubRateLimitWithBadData() throws Exception {
snapshotNotAllowed();
gitHub = getGitHubBuilder().withEndpoint(mockGitHub.apiServer().baseUrl()).build();
gitHub.getMyself();
try {
gitHub.getRateLimit();
fail("Invalid rate limit missing some records should throw");
} catch (Exception e) {
assertThat(e, instanceOf(HttpException.class));
assertThat(e.getCause(), instanceOf(IOException.class));
assertThat(e.getCause().getCause(), instanceOf(ValueInstantiationException.class));
assertThat(e.getCause().getCause().getMessage(),
containsString(
"Cannot construct instance of `org.kohsuke.github.GHRateLimit`, problem: `java.lang.NullPointerException`"));
}
try {
gitHub.getRateLimit();
fail("Invalid rate limit record missing a value should throw");
} catch (Exception e) {
assertThat(e, instanceOf(HttpException.class));
assertThat(e.getCause(), instanceOf(IOException.class));
assertThat(e.getCause().getCause(), instanceOf(MismatchedInputException.class));
assertThat(e.getCause().getCause().getMessage(),
containsString("Missing required creator property 'reset' (index 2)"));
}
}
// These tests should behave the same, showing server time adjustment working
@Test
public void testGitHubRateLimitExpirationServerFiveMinutesAhead() throws Exception {

View File

@@ -5,12 +5,13 @@ import org.junit.Test;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.*;
/**
* @author Liam Newman
@@ -327,4 +328,100 @@ public class GHRepositoryTest extends AbstractGitHubWireMockTest {
repo.setTopics(topics);
assertTrue("Topics can be set to empty", repo.listTopics().isEmpty());
}
@Test
public void getCollaborators() throws Exception {
GHRepository repo = getRepository(gitHub);
GHPersonSet<GHUser> collaborators = repo.getCollaborators();
assertThat(collaborators.size(), greaterThan(0));
}
@Test
public void getPostCommitHooks() throws Exception {
GHRepository repo = getRepository(gitHub);
Set<URL> postcommitHooks = repo.getPostCommitHooks();
assertThat(postcommitHooks.size(), equalTo(0));
}
@Test
public void getRefs() throws Exception {
GHRepository repo = getTempRepository();
GHRef[] refs = repo.getRefs();
assertThat(refs, notNullValue());
assertThat(refs.length, equalTo(1));
assertThat(refs[0].getRef(), equalTo("refs/heads/master"));
}
@Test
public void getRefsHeads() throws Exception {
GHRepository repo = getTempRepository();
GHRef[] refs = repo.getRefs("heads");
assertThat(refs, notNullValue());
assertThat(refs.length, equalTo(1));
assertThat(refs[0].getRef(), equalTo("refs/heads/master"));
}
@Test
public void getRefsEmptyTags() throws Exception {
GHRepository repo = getTempRepository();
try {
repo.getRefs("tags");
fail();
} catch (Exception e) {
assertThat(e, instanceOf(GHFileNotFoundException.class));
assertThat(e.getMessage(),
containsString(
"{\"message\":\"Not Found\",\"documentation_url\":\"https://developer.github.com/v3/git/refs/#get-a-reference\"}"));
assertThat(e.getCause(), instanceOf(FileNotFoundException.class));
}
}
@Test
public void listRefs() throws Exception {
GHRepository repo = getTempRepository();
List<GHRef> refs = repo.listRefs().asList();
assertThat(refs, notNullValue());
assertThat(refs.size(), equalTo(1));
assertThat(refs.get(0).getRef(), equalTo("refs/heads/master"));
}
@Test
public void listRefsHeads() throws Exception {
GHRepository repo = getTempRepository();
List<GHRef> refs = repo.listRefs("heads").asList();
assertThat(refs, notNullValue());
assertThat(refs.size(), equalTo(1));
assertThat(refs.get(0).getRef(), equalTo("refs/heads/master"));
}
@Test
public void listRefsEmptyTags() throws Exception {
try {
GHRepository repo = getTempRepository();
repo.listRefs("tags").asList();
fail();
} catch (Exception e) {
assertThat(e, instanceOf(GHException.class));
assertThat(e.getMessage(), containsString("Failed to retrieve "));
assertThat(e.getMessage(),
containsString("/repos/github-api-test-org/temp-listRefsEmptyTags/git/refs/tags"));
assertThat(e.getCause(), instanceOf(GHFileNotFoundException.class));
}
}
@Test
public void listTagsEmpty() throws Exception {
GHRepository repo = getTempRepository();
List<GHTag> refs = repo.listTags().asList();
assertThat(refs, notNullValue());
assertThat(refs.size(), equalTo(0));
}
@Test
public void listTags() throws Exception {
GHRepository repo = getRepository();
List<GHTag> refs = repo.listTags().withPageSize(33).asList();
assertThat(refs, notNullValue());
assertThat(refs.size(), greaterThan(90));
}
}

View File

@@ -0,0 +1,63 @@
package org.kohsuke.github;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
*
* @author Martin van Zijl
*/
public class GHTagTest extends AbstractGitHubWireMockTest {
@Before
@After
public void cleanUpTags() throws Exception {
// Cleanup is only needed when proxying
if (!mockGitHub.isUseProxy()) {
return;
}
try {
GHRef ref = getRepository(this.gitHubBeforeAfter).getRef("tags/create_tag_test");
if (ref != null) {
ref.delete();
}
} catch (IOException e) {
// The reference probably does not exist.
// This is safe to ignore.
}
}
@Test
public void testCreateTag() throws Exception {
GHRepository repo = getRepository();
String commitSha = "dfe47235cfdcaa12292dab3b1a84ca53a1ceadaf";
String tagName = "create_tag_test";
String tagMessage = "Test Tag";
String tagType = "commit";
GHTagObject tag = repo.createTag(tagName, tagMessage, commitSha, tagType);
assertEquals(tagName, tag.getTag());
assertEquals(tagMessage, tag.getMessage());
assertEquals(commitSha, tag.getObject().getSha());
// Make a reference to the newly created tag.
GHRef ref = repo.createRef("refs/tags/" + tagName, tag.getSha());
assertNotNull(ref);
}
protected GHRepository getRepository() throws IOException {
return getRepository(gitHub);
}
private GHRepository getRepository(GitHub gitHub) throws IOException {
return gitHub.getOrganization("github-api-test-org").getRepository("github-api");
}
}

Some files were not shown because too many files have changed in this diff Show More