Compare commits

...

345 Commits

Author SHA1 Message Date
Liam Newman
eff48dfe67 [maven-release-plugin] prepare release github-api-1.99 2019-11-04 10:08:55 -08:00
Liam Newman
0c38bdc068 Merge pull request #590 from github-api/dependabot/maven/org.apache.maven.plugins-maven-source-plugin-3.2.0
Bump maven-source-plugin from 3.1.0 to 3.2.0
2019-11-04 09:35:00 -08:00
Liam Newman
b8e1736696 [maven-release-plugin] prepare for next development iteration 2019-11-04 09:16:45 -08:00
Liam Newman
c2f36444d0 [maven-release-plugin] prepare release github-api-1.98 2019-11-04 09:16:39 -08:00
Liam Newman
5dc74f5b4d [maven-release-plugin] prepare for next development iteration 2019-11-04 08:30:58 -08:00
Liam Newman
9694dfe4cc [maven-release-plugin] prepare release github-api-1.97 2019-11-04 08:30:51 -08:00
Liam Newman
734125ea14 [maven-release-plugin] prepare for next development iteration 2019-11-04 08:07:30 -08:00
Liam Newman
438f5d1b87 [maven-release-plugin] prepare release github-api-1.96 2019-11-04 08:07:19 -08:00
dependabot-preview[bot]
fadd6d7978 Bump maven-source-plugin from 3.1.0 to 3.2.0
Bumps [maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.1.0 to 3.2.0.
- [Release notes](https://github.com/apache/maven-source-plugin/releases)
- [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.1.0...maven-source-plugin-3.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-04 13:12:37 +00:00
Liam Newman
5026262273 Merge pull request #578 from martinvanzijl/issue_457_create_team_with_repo_access_fix
GHOrganization.createTeam now adds team to specified repositories
2019-11-01 10:50:53 -07:00
Liam Newman
5b53fba020 Merge pull request #581 from martinvanzijl/issue_546_list_repository_topics
Add method to list repository topics
2019-11-01 09:33:10 -07:00
Liam Newman
3892e6e16f Merge branch 'master' into issue_457_create_team_with_repo_access_fix 2019-11-01 09:30:50 -07:00
Liam Newman
33467de763 Formatting and snapshot cleanup 2019-11-01 09:30:33 -07:00
Martin van Zijl
f3528d97c2 Move team cleanup to @Before method as per GitHub review.
Removed constant for TEAM_NAME as it is now only used once in
the method.
2019-11-01 14:48:20 +13:00
Liam Newman
6fb3b01bf0 Fix gpg signing 2019-10-31 18:10:04 -07:00
Martin van Zijl
e3c9cec440 Fixed typo in comment: listTopics() not getTopics(). 2019-11-01 13:48:20 +13:00
Liam Newman
0e011425fb Merge pull request #586 from PauloMigAlmeida/master
[Documentation] :: Add GitHub App Developer Guide
2019-10-31 17:47:23 -07:00
Liam Newman
ba658f7fea Merge branch 'master' into master 2019-10-31 17:47:12 -07:00
Liam Newman
0e6087143b Merge pull request #587 from bitwiseman/site-build
Fix site errors
2019-10-31 17:46:45 -07:00
Liam Newman
5f967e6307 Fix javadoc on java 11 2019-10-31 17:41:05 -07:00
Martin van Zijl
2eb8ce632c Merge branch 'master' into issue_546_list_repository_topics 2019-11-01 13:35:57 +13:00
Liam Newman
f25dbd15d9 Stabilize time check 2019-10-31 16:10:34 -07:00
PauloMigAlmeida
cc5ea77170 Merge branch 'master' of https://github.com/kohsuke/github-api 2019-11-01 12:02:34 +13:00
PauloMigAlmeida
e323644af2 Correcting typos as pointed out during the code review
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-11-01 11:58:16 +13:00
Liam Newman
61f3a3219f Fix tt incompatible tags 2019-10-31 15:41:09 -07:00
Liam Newman
4dcf5dbc13 More pom fixes 2019-10-31 14:24:29 -07:00
Liam Newman
8faecba0a2 Fix site errors 2019-10-31 13:33:14 -07:00
Liam Newman
739551cbe3 Remove old index 2019-10-31 13:01:58 -07:00
PauloMigAlmeida
24a2e42881 [Documentation] :: Add GitHub Developer Guide
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-11-01 02:02:07 +13:00
Liam Newman
6921754c99 Merge pull request #585 from github-api/add-code-of-conduct-1
Create CODE_OF_CONDUCT.md
2019-10-30 17:22:09 -07:00
Liam Newman
d8827a0b44 Create CODE_OF_CONDUCT.md 2019-10-30 17:21:56 -07:00
Liam Newman
a48091988f Update release-drafter.yml 2019-10-30 17:04:40 -07:00
Liam Newman
9bd9c9cf1f Create release-drafter.yml 2019-10-30 16:29:26 -07:00
Liam Newman
695692285b Merge pull request #579 from martinvanzijl/issue_512_methods_to_update_milestones
Add methods to update and delete milestones.
2019-10-30 15:47:50 -07:00
Liam Newman
03edacf7b6 Enable test for Milestone due date update 2019-10-30 15:05:35 -07:00
Liam Newman
4802c97e89 Fix GitHub.printDate()
GitHub.printDate() was not setting GMT timezone resulting in completely bogus output.
2019-10-30 14:57:56 -07:00
Liam Newman
9fc24d1981 Merge branch 'master' into issue_512_methods_to_update_milestones 2019-10-30 12:57:18 -07:00
Liam Newman
d4ddf453b0 Merge pull request #580 from martinvanzijl/issue_529_fix_get_deployment_by_id
Fix for getting deployment by id
2019-10-30 12:55:58 -07:00
Liam Newman
c0117f07cf Merge pull request #583 from PauloMigAlmeida/master
Convenience method to auth with app installation token && documentation examples
2019-10-30 12:54:28 -07:00
Paulo Miguel Almeida
8a88c14b13 Add convenience method to authenticate with app installation tokens;
Convert existing markdown doc to APT due to formatting features;
Replace occurrences of kohsuke user to github-api org where applicable;
Fix repositoryIds method on GHAppCreateTokenBuilder;

Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-10-30 22:18:12 +13:00
Martin van Zijl
a5b6302a69 Add method to list repository topics.
For #546.

The method to update repository topics does not work yet. It may
not have been implemented in the underlying API.
2019-10-30 15:05:09 +13:00
Martin van Zijl
9f29d4619d Fix for getting deployment by id.
Fixes #529.
2019-10-30 13:13:06 +13:00
Martin van Zijl
f4b9dd7d7b Add methods to update and delete milestones.
Fixes #512.
2019-10-30 12:20:06 +13:00
Martin van Zijl
c0a4152b00 GHOrganization.createTeam now adds team to specified repositories.
Fixes #457.
2019-10-29 17:49:41 +13:00
Liam Newman
efb87c5a9e Adjust Jacoco targets to further point to untouched classes. 2019-10-25 19:09:26 -07:00
Liam Newman
061e8bb662 Stop printing to System 2019-10-25 18:33:54 -07:00
Liam Newman
a4f42b2948 Add more tests from AppTest 2019-10-25 18:31:40 -07:00
Liam Newman
cb2fcd3a9e Enable Jacoco on at has-it-been-touched reporting 2019-10-25 18:19:13 -07:00
Liam Newman
1d004a35a0 Merge pull request #510 from awittha/get-user-orgs
Added getUserPublicOrganizations method
2019-10-24 18:32:09 -07:00
Austin Witt
c763c02018 [added] unit tests for getUserPublicOrganizations(...) 2019-10-24 11:03:37 -05:00
Austin Witt
eb36cb4436 Merge remote-tracking branch 'upstream/master' into get-user-orgs 2019-10-23 14:39:54 -05:00
Liam Newman
72d4b9bf62 Merge pull request #525 from vbehar/draft-pr
Add support for draft pull requests
2019-10-21 16:01:02 -07:00
Liam Newman
81ea138f41 Test and fixes for draft pull request 2019-10-21 15:38:04 -07:00
Liam Newman
1bbc66ad62 Merge remote-tracking branch 'github-api/master' into draft-pr 2019-10-21 14:34:40 -07:00
Liam Newman
e7348df372 Merge pull request #575 from romani/patch-1
bump jackson-databind to 2.10.0 to avoid security alert
2019-10-21 12:56:12 -07:00
Roman Ivanov
550e060647 bump jackson-databind to 2.10.0 to avoid security alert 2019-10-20 06:37:28 -07:00
Liam Newman
2970a58e95 Merge branch 'master' into draft-pr 2019-10-18 13:00:39 -07:00
Liam Newman
e0efa04fd4 Merge pull request #574 from github-api/dependabot/maven/com.github.tomakehurst-wiremock-jre8-standalone-2.25.1
Bump wiremock-jre8-standalone from 2.25.0 to 2.25.1
2019-10-18 13:00:14 -07:00
dependabot-preview[bot]
4d24088982 Bump wiremock-jre8-standalone from 2.25.0 to 2.25.1
Bumps [wiremock-jre8-standalone](https://github.com/tomakehurst/wiremock) from 2.25.0 to 2.25.1.
- [Release notes](https://github.com/tomakehurst/wiremock/releases)
- [Commits](https://github.com/tomakehurst/wiremock/compare/2.25.0...2.25.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-18 19:58:47 +00:00
Liam Newman
baba9f5de6 Merge pull request #573 from github-api/dependabot/maven/hamcrest.version-2.2
Bump hamcrest.version from 2.1 to 2.2
2019-10-18 12:57:35 -07:00
dependabot-preview[bot]
c35cd63d0e Bump hamcrest.version from 2.1 to 2.2
Bumps `hamcrest.version` from 2.1 to 2.2.

Updates `hamcrest` from 2.1 to 2.2
- [Release notes](https://github.com/hamcrest/JavaHamcrest/releases)
- [Changelog](https://github.com/hamcrest/JavaHamcrest/blob/master/CHANGES.md)
- [Commits](https://github.com/hamcrest/JavaHamcrest/compare/v2.1...v2.2)

Updates `hamcrest-core` from 2.1 to 2.2
- [Release notes](https://github.com/hamcrest/JavaHamcrest/releases)
- [Changelog](https://github.com/hamcrest/JavaHamcrest/blob/master/CHANGES.md)
- [Commits](https://github.com/hamcrest/JavaHamcrest/compare/v2.1...v2.2)

Updates `hamcrest-library` from 2.1 to 2.2
- [Release notes](https://github.com/hamcrest/JavaHamcrest/releases)
- [Changelog](https://github.com/hamcrest/JavaHamcrest/blob/master/CHANGES.md)
- [Commits](https://github.com/hamcrest/JavaHamcrest/compare/v2.1...v2.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-16 23:05:29 +00:00
Liam Newman
80fa389ce3 Fix GHContent.read()
Fixes #487
2019-10-11 15:21:57 -07:00
Liam Newman
8ec861c9fe Merge pull request #563 from bitwiseman/paged_iterable_closure
Simplify creation of PagedIterables from requests
2019-10-11 13:20:17 -07:00
Liam Newman
837400fb5e Merge pull request #572 from sullis/java-matrix-jdk13
GitHub workflow: add JDK 13 to build matrix
2019-10-11 13:18:00 -07:00
Liam Newman
ec4525b8ff Merge branch 'master' into java-matrix-jdk13 2019-10-11 13:13:09 -07:00
Liam Newman
281c927971 Update GHIssueEvent PagedIterable 2019-10-11 13:11:08 -07:00
Liam Newman
9dd44c13e4 Update for AuthorizationList 2019-10-11 13:05:13 -07:00
Liam Newman
f28edbcf8f Simplify creation of PagedIterables from requests 2019-10-11 13:05:13 -07:00
Liam Newman
29e147f992 wrupUp() package private 2019-10-11 13:02:42 -07:00
Sean C. Sullivan
830f4231e1 GitHub workflow: add JDK 13 to build matrix 2019-10-11 12:08:03 -07:00
Liam Newman
7d65e31055 Merge pull request #484 from martinvanzijl/issue_466_edit_gists
Add support for editing Gists
2019-10-11 11:46:56 -07:00
Liam Newman
dec7a91b5b Merge pull request #479 from martinvanzijl/issue_376_issue_events
Add issue events API
2019-10-11 11:44:03 -07:00
Liam Newman
1ba630c221 Minor Gist updater improvement 2019-10-11 11:21:11 -07:00
Martin van Zijl
7d3387fb96 Updated unit tests. 2019-10-11 16:37:08 +13:00
Liam Newman
a0c0de28d7 Move a few more tests to use temp repo 2019-10-09 13:41:00 -07:00
Liam Newman
dc31d52f83 Add facility to create and auto-cleanup temp repos 2019-10-09 13:00:21 -07:00
Martin van Zijl
620c822dac Updates per review on GitHub:
- Created class GHGistUpdater to do the updating.
- Added unit tests.
2019-10-10 07:08:05 +13:00
Liam Newman
5990f5ae22 Merge pull request #567 from jberglund-BSFT/master
Add merge options to GHRepository
2019-10-09 11:02:54 -07:00
Martin van Zijl
37329a50d4 Merge branch 'master' into issue_466_edit_gists 2019-10-10 05:43:10 +13:00
Martin van Zijl
550597f72e Make unit test output neater. 2019-10-09 15:11:02 +13:00
Martin van Zijl
2aa4022e2c Updated per review.
- Created separate class for GHIssueEvent instead of nested classes.
- Renamed test class accordingly.

Other fixes:

- Changed id type to long.
- Updated test cases.
- Added toString() method.
2019-10-09 14:59:08 +13:00
Martin van Zijl
b40741b14d Merge branch 'issue_376_issue_events' of https://github.com/martinvanzijl/github-api into issue_376_issue_events 2019-10-09 14:03:27 +13:00
Joey Berglund
3c739d889e Merge branch 'master' into master 2019-10-08 15:04:55 -05:00
Liam Newman
24a92a133e Merge branch 'master' into issue_376_issue_events 2019-10-08 11:04:22 -07:00
Liam Newman
ce97eb5b40 Merge pull request #482 from martinvanzijl/issue_467_add_user_to_org
Add method to invite user to organization
2019-10-08 11:04:01 -07:00
Liam Newman
7a4e3c480e Merge branch 'master' into issue_467_add_user_to_org 2019-10-08 10:59:27 -07:00
Liam Newman
eefa710839 Merge branch 'master' into issue_466_edit_gists 2019-10-08 10:59:09 -07:00
Liam Newman
4c3e1afcca Merge branch 'master' into get-user-orgs 2019-10-08 10:57:48 -07:00
Liam Newman
c1a77ada5d Merge branch 'master' into draft-pr 2019-10-08 10:55:51 -07:00
Liam Newman
5671e5ed67 Merge branch 'master' into master 2019-10-08 10:54:23 -07:00
Liam Newman
2fdc5a8541 Merge pull request #562 from sullis/github-workflow-java-matrix
GitHub workflow: enable Java matrix [ '1.8.0', '11.0.x' ]
2019-10-08 10:51:37 -07:00
Liam Newman
297dbae247 Merge branch 'master' into github-workflow-java-matrix 2019-10-08 10:47:19 -07:00
Liam Newman
0910cdf3a4 Add test for bridge method 2019-10-08 10:37:51 -07:00
jberglund
6877fb5c74 add unit test 2019-10-08 11:20:34 -05:00
Liam Newman
2d65daa8c9 Merge branch 'master' into master 2019-10-08 08:21:54 -07:00
Sean C. Sullivan
dab4cb6186 cleanup pom.xml 2019-10-07 22:46:40 -07:00
Sean C. Sullivan
40773a2b49 GitHub workflow: enable Java matrix [ '1.8.0', '11.0.x' ] 2019-10-07 22:37:58 -07:00
Liam Newman
7e0d61a6fc Merge pull request #481 from martinvanzijl/issue_459_list_authorizations
Added method to list authorizations
2019-10-07 19:04:00 -07:00
Liam Newman
7f9620d75f Delete Foo.java 2019-10-07 18:46:02 -07:00
Martin van Zijl
3559aef1a1 Fixes per review.
- Added missing brace at end of listMyAuthorizations().
- Added unit test for listMyAuthorizations().
2019-10-08 13:21:48 +13:00
Martin van Zijl
94ceb5eaaf Merge branch 'master' into issue_459_list_authorizations 2019-10-08 12:42:18 +13:00
Martin van Zijl
778ca76d22 Merge branch 'issue_376_issue_events' of https://github.com/martinvanzijl/github-api into issue_376_issue_events 2019-10-08 12:34:44 +13:00
Martin van Zijl
b1c0e41c5c Merge branch 'master' into issue_376_issue_events 2019-10-08 12:31:30 +13:00
Liam Newman
f826edd097 Merge pull request #564 from github-api/dependabot/maven/com.squareup.okio-okio-2.4.1
Bump okio from 2.4.0 to 2.4.1
2019-10-07 14:09:42 -07:00
Liam Newman
edc7c4a4b8 Merge pull request #565 from github-api/dependabot/maven/com.google.code.gson-gson-2.8.6
Bump gson from 2.8.5 to 2.8.6
2019-10-07 14:09:11 -07:00
Liam Newman
dafdc66d25 Merge pull request #568 from bitwiseman/more-tests
More tests
2019-10-07 14:08:45 -07:00
Liam Newman
0d135f14bb Add more CI tests 2019-10-07 14:01:32 -07:00
Liam Newman
568c08d0e9 Separate connection sensitive tests 2019-10-07 13:09:27 -07:00
Liam Newman
87410e295e Add more tests to ci 2019-10-07 13:04:13 -07:00
Joey Berglund
b163e68950 Merge branch 'master' into master 2019-10-07 08:41:56 -05:00
Joey Berglund
88b006e957 Update GHRepository.java 2019-10-07 08:39:38 -05:00
dependabot-preview[bot]
477f2f2814 Bump gson from 2.8.5 to 2.8.6
Bumps [gson](https://github.com/google/gson) from 2.8.5 to 2.8.6.
- [Release notes](https://github.com/google/gson/releases)
- [Changelog](https://github.com/google/gson/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/gson/compare/gson-parent-2.8.5...gson-parent-2.8.6)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-07 08:09:06 +00:00
dependabot-preview[bot]
933d99c23b Bump okio from 2.4.0 to 2.4.1
Bumps [okio](https://github.com/square/okio) from 2.4.0 to 2.4.1.
- [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.0...2.4.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-07 08:08:48 +00:00
Martin van Zijl
d3a0c5ded1 Added unit test for adding user to organization. 2019-10-07 15:34:13 +13:00
Martin van Zijl
1e173ddc24 Merge branch 'master' of https://github.com/kohsuke/github-api into issue_467_add_user_to_org 2019-10-07 13:56:08 +13:00
Liam Newman
ca404cb33b Merge branch 'master' into issue_466_edit_gists 2019-10-05 19:40:56 -07:00
Liam Newman
f0dc7d5b02 Merge pull request #532 from farmdawgnation/team-pr-review-requests
Add support for team pr review requests
2019-10-05 19:39:55 -07:00
Liam Newman
933702376f Update Tests to check for lazy loading and refresh 2019-10-05 14:35:13 -07:00
Liam Newman
e08896775b Add Refreshable interfrace and use it in GHTeam and GHPullRequest 2019-10-05 14:17:17 -07:00
Matt Farmer
d610e46f8e Add a test for team review requests 2019-10-05 09:19:28 -04:00
Matt Farmer
7d1989f5a2 Materialize requested_teams from the teams API
We don't get the full object when we retrieve a PR, so when we see
requested teams we need to materialize them from the API
2019-10-05 09:13:13 -04:00
Matt Farmer
5c1e371427 Rebuild wiremock for test review requests 2019-10-05 08:35:12 -04:00
Matt Farmer
dbd9d51747 Merge remote-tracking branch 'upstream/master' into team-pr-review-requests 2019-10-05 08:29:27 -04:00
Liam Newman
fdf5d3f72d Merge pull request #475 from immanuelqrw/label-description
Adding Label description property
2019-10-04 22:28:11 -07:00
Liam Newman
2719867a86 Fix up Label Description and tests 2019-10-04 22:23:53 -07:00
Liam Newman
0240412ad2 Merge remote-tracking branch 'github-api/master' into label-description 2019-10-04 21:44:06 -07:00
Liam Newman
7c065c1205 Merge pull request #477 from martinvanzijl/issue_330_statistics
Add statistics API.
2019-10-04 21:38:08 -07:00
Liam Newman
f9aa1ad1f2 Fix JSON API FB warning 2019-10-04 21:34:55 -07:00
Liam Newman
5feffdf544 Minor fixups after merge from master
Rerecorded WireMock files with newer framework
2019-10-04 21:29:08 -07:00
Liam Newman
4e56b8bb78 Merge branch 'master' into issue_330_statistics 2019-10-04 21:12:35 -07:00
Liam Newman
845017313c Merge pull request #545 from gskjold/issue_425_projects_columns_cards
Support for projects
2019-10-04 21:10:51 -07:00
Liam Newman
dc2830d94f Enable Content test 2019-10-04 21:06:15 -07:00
Liam Newman
552edf8698 Switch to WireMockMultiServerRule as base 2019-10-04 21:06:00 -07:00
Liam Newman
41c51646fe Rename GitHubApiWireMockRule to GitHubWireMockRule 2019-10-04 21:02:44 -07:00
Joey Berglund
a42024bdbc Update GHRepository.java 2019-10-04 16:28:28 -05:00
Liam Newman
20cfb26a7f Disable Licence content test
Need to mock raw.githubusercontent.com to make this work
2019-10-04 11:09:05 -07:00
Liam Newman
3972d11827 WireMock License Test 2019-10-04 10:30:22 -07:00
Liam Newman
5cc88a0075 WireMock Project Tests 2019-10-04 10:27:47 -07:00
Gunnar Skjold
fc08711111 Expanded GHProject with columns and cards. Also added tests for projects, columns and cards 2019-10-04 10:11:18 -07:00
Martin van Zijl
b20c2babec Added support for projects.
Fixes issue #425
2019-10-04 10:11:18 -07:00
Martin van Zijl
cb0facc6ef Updates per GH review.
- Marked getContributorStats(bool) as deprecated, preview
- Moved "stats/" string to getApiTailUrl()
2019-10-05 05:43:23 +13:00
Liam Newman
78abb2edcb Merge pull request #530 from bozaro/request-log
Add GitHub API requests logging
2019-10-04 09:15:09 -07:00
Liam Newman
7d350d9def Merge pull request #561 from github-api/dependabot/maven/org.eclipse.jgit-org.eclipse.jgit-5.5.1.201910021850-r
Bump org.eclipse.jgit from 5.5.0.201909110433-r to 5.5.1.201910021850-r
2019-10-04 08:15:48 -07:00
dependabot-preview[bot]
48d7daf2c4 Bump org.eclipse.jgit from 5.5.0.201909110433-r to 5.5.1.201910021850-r
Bumps org.eclipse.jgit from 5.5.0.201909110433-r to 5.5.1.201910021850-r.

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-04 08:22:03 +00:00
Liam Newman
2782059d88 Merge branch 'master' into request-log 2019-10-04 00:44:21 -07:00
Liam Newman
0ca10bc2ac Merge branch 'master' into issue_459_list_authorizations 2019-10-04 00:43:14 -07:00
Liam Newman
880abe2305 Merge branch 'master' into issue_467_add_user_to_org 2019-10-04 00:41:50 -07:00
Liam Newman
22f61d6225 Merge branch 'master' into issue_376_issue_events 2019-10-04 00:41:15 -07:00
Liam Newman
4fbaa425fb Merge branch 'master' into issue_466_edit_gists 2019-10-04 00:36:18 -07:00
Liam Newman
e81e228f03 Merge branch 'master' into issue_330_statistics 2019-10-04 00:01:36 -07:00
Liam Newman
1076f89954 Merge branch 'master' into label-description 2019-10-03 23:56:27 -07:00
Liam Newman
9c6f977202 Merge branch 'master' into get-user-orgs 2019-10-03 23:55:56 -07:00
Martin van Zijl
bd23ba6077 Added Wiremock test files. 2019-10-04 16:27:41 +13:00
Martin van Zijl
c7af56d0ed Changes per review on GitHub.
- Moved statistics methods from GHRepository to new class GHRepositoryStatistics
- Updated StatisticsTest to suit.
- For ContributorStats, put the "wait-till-ready" loop in the accessor method.
  I'm planning to do something similar for the rest.
2019-10-04 16:23:26 +13:00
Liam Newman
8da6db9fcc Merge pull request #522 from PauloMigAlmeida/master
Implement GitHub App API methods
2019-10-03 19:29:37 -07:00
Liam Newman
2fe7342fd7 Merge branch 'master' into master 2019-10-03 19:07:40 -07:00
Liam Newman
f6221144a8 Merge pull request #478 from martinvanzijl/issue_460_team_description_field
Added description field to GHTeam class.
2019-10-03 17:37:52 -07:00
Liam Newman
872d713e50 Fix one more case of connecting outside the proxy 2019-10-03 17:34:52 -07:00
Liam Newman
d5b04f572b Fixed list traversal for paged queries 2019-10-03 17:23:31 -07:00
PauloMigAlmeida
0f7a5f1c08 Merge from upstream;
Remove servlet exclusion due to previous JDK version;

Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-10-04 11:59:58 +13:00
PauloMigAlmeida
a163c565a8 Merge branch 'master' of https://github.com/kohsuke/github-api
 Conflicts:
	src/main/java/org/kohsuke/github/GitHubBuilder.java
	src/test/java/org/kohsuke/github/GitHubTest.java
2019-10-04 11:56:38 +13:00
Liam Newman
413a316b15 Record snapshot for test 2019-10-03 14:51:46 -07:00
Liam Newman
65a92a49b5 Merge remote-tracking branch 'github-api/master' into issue_460_team_description_field 2019-10-03 14:44:04 -07:00
Sharath Babu
563507ca21 add setPrivate functionality on repos 2019-10-03 14:38:26 -07:00
Liam Newman
21b2d02f0a Enable GHOrganizationTest in CI 2019-10-03 14:20:18 -07:00
Liam Newman
19e1a00fd7 Rename mapping files to include index 2019-10-03 14:05:15 -07:00
Liam Newman
a02a6a22d0 Move to Gson for formatting json 2019-10-03 13:49:53 -07:00
Liam Newman
3488421f67 More WireMock tests 2019-10-03 12:34:32 -07:00
Liam Newman
34a961088c Initial attempt at auto-format of JSON 2019-10-03 09:06:31 -07:00
Liam Newman
b35509150a Enable part of AppTest in CI 2019-10-02 15:27:22 -07:00
Liam Newman
d096aa2065 Merge pull request #558 from github-api/dependabot/maven/com.squareup.okio-okio-2.4.0
Bump okio from 2.2.2 to 2.4.0
2019-10-02 09:12:45 -07:00
dependabot-preview[bot]
efd5bef102 Bump okio from 2.2.2 to 2.4.0
Bumps [okio](https://github.com/square/okio) from 2.2.2 to 2.4.0.
- [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.2.2...parent-2.4.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-02 15:57:35 +00:00
Liam Newman
b8c6e44ab6 Update okhttp3 (with Java 8)
This version of okhttp3 is the last to suppurt UrlFactory, but we've replaced it anyway in preparation for future updates.
2019-10-01 14:05:50 -07:00
Liam Newman
9a91cc43e2 Merge pull request #542 from bitwiseman/cache-fix
Improved OkHttpConnector caching behavior
2019-10-01 13:11:26 -07:00
Liam Newman
f4cbab52a7 Merge branch 'master' into cache-fix 2019-10-01 13:07:35 -07:00
Liam Newman
57b58cf203 Merge pull request #557 from github-api/dependabot/maven/org.mockito-mockito-core-3.1.0
Bump mockito-core from 3.0.0 to 3.1.0
2019-10-01 08:25:59 -07:00
dependabot-preview[bot]
9ba8ae08a1 Bump mockito-core from 3.0.0 to 3.1.0
Bumps [mockito-core](https://github.com/mockito/mockito) from 3.0.0 to 3.1.0.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v3.0.0...v3.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-10-01 12:54:01 +00:00
Liam Newman
dfe81f510e Add None and Zero Cache tests to CI 2019-09-30 16:23:08 -07:00
Liam Newman
f3a0b35442 Updated Tests to have non-cache tests run in CI 2019-09-30 11:05:11 -07:00
Liam Newman
64e3be3bc7 Merge branch 'master' into cache-fix 2019-09-30 09:13:52 -07:00
Liam Newman
4c82d1c56e Merge pull request #556 from github-api/dependabot/maven/com.github.tomakehurst-wiremock-jre8-standalone-2.25.0
Bump wiremock-jre8-standalone from 2.24.1 to 2.25.0
2019-09-30 09:13:06 -07:00
Liam Newman
d8451fc2f5 Implement new abstract methods from Admin 2019-09-30 09:00:55 -07:00
dependabot-preview[bot]
8078423252 Bump wiremock-jre8-standalone from 2.24.1 to 2.25.0
Bumps [wiremock-jre8-standalone](https://github.com/tomakehurst/wiremock) from 2.24.1 to 2.25.0.
- [Release notes](https://github.com/tomakehurst/wiremock/releases)
- [Commits](https://github.com/tomakehurst/wiremock/compare/2.24.1...2.25.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-30 08:40:16 +00:00
Liam Newman
68176b5695 Merge branch 'master' into draft-pr 2019-09-29 18:36:34 -07:00
Liam Newman
1bf7833959 Merge branch 'master' into request-log 2019-09-29 18:35:53 -07:00
Liam Newman
89770b922d Change listKeys to getKeys 2019-09-29 18:33:08 -07:00
Liam Newman
716947bbb1 Merge branch 'master' into draft-pr 2019-09-27 10:38:23 -07:00
Liam Newman
47e0d7786b Merge branch 'master' into cache-fix 2019-09-27 10:37:26 -07:00
Arngrimur Bjarnason
55f9c40bba Merge branch 'master' into getKeysForUser 2019-09-27 08:24:49 +02:00
Martin van Zijl
51afa30732 Added unit tests. 2019-09-26 14:32:30 +12:00
Liam Newman
23c07316ee Merge branch 'master' into label-description 2019-09-25 17:28:23 -07:00
Liam Newman
e740f52e5e Merge pull request #480 from martinvanzijl/issue_381_branch_url_escaping
Escape special characters in branch URLs
2019-09-25 17:15:50 -07:00
Liam Newman
a731109747 Add tests for URLEncoding 2019-09-25 17:11:46 -07:00
Martin van Zijl
a50a011eb3 Issue #381 - Escape branch URL.
This is using the "old" HTTP.UTF_8 Charset, since the new
StandardCharsets doesn't compile.
2019-09-25 16:59:58 -07:00
Liam Newman
e22c6d3a94 Merge branch 'master' into issue_330_statistics 2019-09-25 16:57:36 -07:00
Liam Newman
50fb9c1795 Merge pull request #473 from joaoe/issue-472-archive-repository
Implemented GitHub.doArchive
2019-09-25 16:55:12 -07:00
Liam Newman
22575c9a01 Add test for archive method 2019-09-25 16:48:54 -07:00
João Eiras
2934922cb5 Implemented GitHub.doArchive
doArchive() will mark a repository as archived.

Issue #472
2019-09-25 16:30:44 -07:00
Liam Newman
9042ff46c7 Clean up Previews 2019-09-25 15:47:07 -07:00
Liam Newman
a1a91539c2 Merge branch 'master' into getKeysForUser 2019-09-25 10:13:39 -07:00
Liam Newman
468f4f94a3 Merge pull request #554 from github-api/dependabot/maven/org.apache.maven.plugins-maven-surefire-plugin-2.22.2
Bump maven-surefire-plugin from 2.22.1 to 2.22.2
2019-09-25 10:10:02 -07:00
Liam Newman
3ebd35437e Merge pull request #552 from github-api/dependabot/maven/org.apache.commons-commons-lang3-3.9
Bump commons-lang3 from 3.7 to 3.9
2019-09-25 10:09:33 -07:00
dependabot-preview[bot]
a166bbadad Bump maven-surefire-plugin from 2.22.1 to 2.22.2
Bumps [maven-surefire-plugin](https://github.com/apache/maven-surefire) from 2.22.1 to 2.22.2.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-2.22.1...surefire-2.22.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-25 17:08:56 +00:00
Liam Newman
7ff07a132a Merge branch 'master' into dependabot/maven/org.apache.commons-commons-lang3-3.9 2019-09-25 10:08:33 -07:00
Liam Newman
6f297bcbb8 Merge pull request #555 from github-api/dependabot/maven/commons-io-commons-io-2.6
Bump commons-io from 1.4 to 2.6
2019-09-25 10:07:45 -07:00
dependabot-preview[bot]
1c023e15af Bump commons-io from 1.4 to 2.6
Bumps commons-io from 1.4 to 2.6.

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-25 07:33:21 +00:00
dependabot-preview[bot]
37f96848a7 Bump commons-lang3 from 3.7 to 3.9
Bumps commons-lang3 from 3.7 to 3.9.

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-25 07:32:00 +00:00
Liam Newman
3d04765f51 Merge branch 'master' into issue_330_statistics 2019-09-24 18:19:35 -07:00
Liam Newman
e1152fa549 Merge branch 'master' into issue_466_edit_gists 2019-09-24 14:34:15 -07:00
Liam Newman
ab47896f17 Merge branch 'master' into cache-fix 2019-09-24 14:29:36 -07:00
Liam Newman
4f13565e51 Merge pull request #549 from github-api/dependabot/maven/com.infradna.tool-bridge-method-annotation-1.18
Bump bridge-method-annotation from 1.17 to 1.18
2019-09-24 14:29:03 -07:00
dependabot-preview[bot]
7ab93a59e2 Bump bridge-method-annotation from 1.17 to 1.18
Bumps [bridge-method-annotation](https://github.com/infradna/bridge-method-injector) from 1.17 to 1.18.
- [Release notes](https://github.com/infradna/bridge-method-injector/releases)
- [Commits](https://github.com/infradna/bridge-method-injector/compare/bridge-method-injector-parent-1.17...bridge-method-injector-parent-1.18)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-24 21:26:18 +00:00
Liam Newman
943c0d022b Merge pull request #551 from github-api/dependabot/maven/commons-codec-commons-codec-1.13
Bump commons-codec from 1.7 to 1.13
2019-09-24 14:24:58 -07:00
dependabot-preview[bot]
bea8922c39 Bump commons-codec from 1.7 to 1.13
Bumps [commons-codec](https://github.com/apache/commons-codec) from 1.7 to 1.13.
- [Release notes](https://github.com/apache/commons-codec/releases)
- [Changelog](https://github.com/apache/commons-codec/blob/master/RELEASE-NOTES.txt)
- [Commits](https://github.com/apache/commons-codec/compare/1.7...commons-codec-1.13)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-24 21:23:03 +00:00
Liam Newman
97c96a7ee1 Merge pull request #550 from github-api/dependabot/maven/com.github.spotbugs-spotbugs-maven-plugin-3.1.12.2
Bump spotbugs-maven-plugin from 3.1.11 to 3.1.12.2
2019-09-24 14:21:43 -07:00
dependabot-preview[bot]
3d831ba7e8 Bump spotbugs-maven-plugin from 3.1.11 to 3.1.12.2
Bumps [spotbugs-maven-plugin](https://github.com/spotbugs/spotbugs-maven-plugin) from 3.1.11 to 3.1.12.2.
- [Release notes](https://github.com/spotbugs/spotbugs-maven-plugin/releases)
- [Commits](https://github.com/spotbugs/spotbugs-maven-plugin/compare/spotbugs-maven-plugin-3.1.11...spotbugs-maven-plugin-3.1.12.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-24 21:19:00 +00:00
Liam Newman
df749a98cb Merge pull request #547 from github-api/dependabot/maven/org.eclipse.jgit-org.eclipse.jgit-5.5.0.201909110433-r
Bump org.eclipse.jgit from 4.9.0.201710071750-r to 5.5.0.201909110433-r
2019-09-24 14:17:31 -07:00
dependabot-preview[bot]
22bbc9c621 Bump org.eclipse.jgit from 4.9.0.201710071750-r to 5.5.0.201909110433-r
Bumps org.eclipse.jgit from 4.9.0.201710071750-r to 5.5.0.201909110433-r.

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-24 19:46:06 +00:00
Liam Newman
30def4e515 Update jackson-databind to 2.9.10 2019-09-24 12:43:43 -07:00
Matt Farmer
cf8be37310 Correct test run + add sample data 2019-09-21 10:29:48 -04:00
Matt Farmer
12409df446 Merge remote-tracking branch 'upstream/master' into team-pr-review-requests 2019-09-21 09:56:12 -04:00
Martin van Zijl
3452a08de3 Added more detail to unit tests.
Added another accessor method.
2019-09-20 16:27:32 +12:00
Liam Newman
425ea0579e Merge branch 'master' into label-description 2019-09-17 13:33:50 -07:00
Arngrimur Bjarnason
22afb769af Adding wiremocks 2019-09-17 14:56:43 +02:00
Arngrimur Bjarnason
884eae269e Adding possiblity to get ssh keys 2019-09-17 14:39:46 +02:00
PauloMigAlmeida
59a973970e Remove duplicated wiremock dependency
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-09-15 10:57:22 +12:00
PauloMigAlmeida
225383464a Merge remote-tracking branch 'origin/master' 2019-09-15 10:52:53 +12:00
PauloMigAlmeida
3d82731325 Update tests using the new wiremock structure as per requested
Signed-off-by: PauloMigAlmeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-09-15 10:52:22 +12:00
PauloMigAlmeida
dacdf08309 Merge branch 'master' of https://github.com/kohsuke/github-api 2019-09-14 17:00:24 +12:00
Martin van Zijl
ad281adc97 Unit tests and fixes.
Fixed issue with getCodeFrequency() where it would occasionally throw
an exception when the statistics were still being generated.

Added comment about throwing an exception as a possibility when
202 is returned.
2019-09-14 10:39:59 +12:00
Liam Newman
80741c7773 Use CacheControl and only check for cache in constructor 2019-09-12 13:57:28 -07:00
Liam Newman
532f7a4b17 Merge branch 'master' into cache-fix 2019-09-11 22:48:26 -07:00
Liam Newman
5e87d582e4 Add tests showing cache performance 2019-09-11 22:05:02 -07:00
Liam Newman
b9bf47aaca Merge pull request #543 from jsoref/grammar
Grammar
2019-09-11 20:48:28 -07:00
Josh Soref
0dba882817 spelling: create a 2019-09-11 19:28:32 -04:00
Josh Soref
c419883814 spelling: single 2019-09-11 19:28:24 -04:00
Josh Soref
6f0ccbf2b5 grammar: agreement: returns...organizations 2019-09-11 19:28:14 -04:00
Josh Soref
54332c0bd1 this api is no longer a preview... 2019-09-11 19:27:40 -04:00
Josh Soref
5f80674e89 finish thought... 2019-09-11 19:27:04 -04:00
Josh Soref
c4d0d8ff06 grammar: operations-require 2019-09-11 19:26:47 -04:00
Josh Soref
8ac1b7082a brand: GitHub Enterprise 2019-09-11 19:26:14 -04:00
Josh Soref
f146ae8be4 spelling: user 2019-09-11 19:25:55 -04:00
Josh Soref
e7728fdc94 spelling: log-in 2019-09-11 19:25:44 -04:00
Josh Soref
052122e4d0 spelling: abuse 2019-09-11 19:25:29 -04:00
Josh Soref
38827d2b3d grammar: period at end of sentence (not inside parenthetical) 2019-09-11 19:25:19 -04:00
Liam Newman
9e1f16be27 Fix OkHttpConnector caching 2019-09-10 23:01:50 -07:00
Liam Newman
c845846317 Do not rerun tests
If they failed once, they will fail again.
2019-09-10 23:00:44 -07:00
Liam Newman
9276556f19 Mockito 3.0.0 2019-09-10 22:59:07 -07:00
Liam Newman
c796d18948 Merge pull request #541 from bitwiseman/wiremock-github-rule
Add GitHubApiWireMockRule
2019-09-10 22:54:27 -07:00
Liam Newman
8dee5520cf Add GitHubApiWireMockRule
Separates the WireMock and GitHub API info from project specific code.
2019-09-10 22:42:28 -07:00
Liam Newman
440e13714e Merge branch 'master' into issue_466_edit_gists 2019-09-09 22:04:11 -07:00
Liam Newman
44a70b372d Merge pull request #502 from CodeAndChoke/hashcode_equals
Added equals and hashcode
2019-09-09 22:02:22 -07:00
Liam Newman
504286e96e Merge pull request #540 from bitwiseman/test-run
Working CI Build
2019-09-09 22:01:33 -07:00
Liam Newman
ffdd54d2fa Merge branch 'master' into get-user-orgs 2019-09-09 19:40:00 -07:00
Liam Newman
32804b81c0 Merge pull request #527 from WouterG/patch-1
Remove unnessesairy "throws"
2019-09-09 19:38:09 -07:00
Liam Newman
403b22ade0 Working CI Build
This change automatically turns off tests where we haven't had a chance to implement wiremocking.
They can still be run locally by setting test.github.useProxy (even though most of them do actually use the proxy).
2019-09-09 19:34:09 -07:00
Liam Newman
a4e74abcca Merge branch 'master' into master 2019-09-09 17:19:58 -07:00
Liam Newman
8dcef5bac0 Merge branch 'master' into draft-pr 2019-09-09 16:57:14 -07:00
Liam Newman
49878bc4e3 Merge branch 'master' into patch-1 2019-09-09 16:56:34 -07:00
Liam Newman
3f1a71c8a4 Merge branch 'master' into request-log 2019-09-09 16:54:24 -07:00
Liam Newman
bf9b2c0da3 Merge branch 'master' into team-pr-review-requests 2019-09-09 16:40:00 -07:00
Liam Newman
909a274709 Merge pull request #538 from ewiegs4/pr-query-head
Namespace PR head queries with repo's owner by default
2019-09-09 16:31:21 -07:00
Liam Newman
fc529b8083 Merge remote-tracking branch 'kohsuke/master' into pr-query-head 2019-09-09 16:16:36 -07:00
Liam Newman
f1386f26fb maven-build.yml
Trying to get actions to trigger
2019-09-09 16:15:35 -07:00
Liam Newman
cccd09d329 Delete maven.yml 2019-09-09 16:13:51 -07:00
Liam Newman
0fccf7effe Update maven.yml 2019-09-09 16:06:21 -07:00
Liam Newman
4b91a47c8b Merge branch 'master' into issue_460_team_description_field 2019-09-09 16:01:27 -07:00
Liam Newman
bd40499bbe Improve behavior and documentation for WireMock testing 2019-09-09 15:55:03 -07:00
Liam Newman
c7c8cd76c6 Merge branch 'master' into label-description 2019-09-08 23:58:18 -07:00
Liam Newman
0bb9f0ce41 Merge branch 'master' into pr-query-head 2019-09-08 23:55:34 -07:00
Liam Newman
7136afce8e Update all WireMock data files 2019-09-08 23:33:44 -07:00
Liam Newman
ec17c1de6a Update PullRequestTest for WireMocking 2019-09-08 23:33:30 -07:00
Liam Newman
8d6daef354 Rewrite wiremock rule to snapshot on a per-method basis 2019-09-08 23:33:30 -07:00
Liam Newman
3a09d2de4a Rename README to README.md 2019-09-06 17:07:13 -07:00
Liam Newman
c78e10f92e Merge remote-tracking branch 'kohsuke/master' into pr-query-head 2019-09-06 16:18:49 -07:00
Liam Newman
b113ff35ac Merge pull request #537 from bitwiseman/wiremock
Add WireMock testing facility
2019-09-06 16:17:37 -07:00
Eddie Wiegers
6360024d20 Add test for qualified case. 2019-09-06 16:43:19 -05:00
Martin van Zijl
a7683f6bd7 Added setter and unit tests for GHTeam description field. 2019-09-05 16:23:38 +12:00
Liam Newman
e46a9f3f2a Java 8 required for testing, not for package 2019-09-03 13:16:28 -07:00
Eddie Wiegers
a8d711d4c8 Qualify PR head queries with repo's owner by default 2019-09-03 11:40:33 -05:00
Liam Newman
df74fc67bd Add WireMock tests to CI 2019-08-31 21:55:09 -07:00
Liam Newman
450261abbf Move scenario to json files 2019-08-31 19:52:50 -07:00
Liam Newman
12230edc54 Add UserTest to WireMock 2019-08-31 01:35:21 -07:00
Liam Newman
d1cfcf561b Converted GistTest to WireMock 2019-08-31 01:25:25 -07:00
Liam Newman
d143f5af8b Start of WireMock 2019-08-30 17:07:17 -07:00
Liam Newman
0f7ae3cda7 Merge pull request #534 from res0nance/https
Swap to HTTPs
2019-08-28 13:24:52 -07:00
Raihaan Shouhell
baf94e56c8 Swap to HTTPs 2019-08-27 10:45:02 +08:00
Paulo Miguel Almeida
905bd1a4c9 Fix typo
Signed-off-by: Paulo Almeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-08-26 12:37:28 +12:00
Paulo Almeida
96bcf24047 Merge branch 'master' of https://github.com/kohsuke/github-api
# Conflicts:
#	pom.xml
2019-08-26 12:31:23 +12:00
Liam Newman
dfe47235cf Update maven.yml 2019-08-23 19:11:16 -07:00
Liam Newman
b82ea8eaa8 Merge pull request #533 from sullis/jackson-2.9.9.3
jackson-databind 2.9.9.3
2019-08-23 19:06:25 -07:00
Liam Newman
b1b830c268 Switch to spotbugs 2019-08-23 19:02:14 -07:00
Liam Newman
e654d4a6df Fix pom warnings 2019-08-23 18:48:49 -07:00
Liam Newman
ac30b17ecb Do no run GMaven on this project 2019-08-23 18:45:03 -07:00
Liam Newman
95efdb3a51 Use newer dependency plugin 2019-08-23 18:35:38 -07:00
Liam Newman
49c165e203 Update maven.yml 2019-08-23 18:24:52 -07:00
Liam Newman
a4be351d9f Update maven.yml 2019-08-23 18:20:36 -07:00
Liam Newman
3d0401aecd Update maven.yml 2019-08-23 18:17:34 -07:00
Liam Newman
7c27572a53 Split out dependency downloading to new step
For visualization, it helps to not have to search through all the dependency downloads
2019-08-23 18:17:17 -07:00
Liam Newman
1e7760012e Merge pull request #476 from turbanoff/patch-1
Provide more exception details
2019-08-23 18:12:34 -07:00
Liam Newman
24d464b6e5 Add github build action
This ensures that PR's at least build
Currently runs no tests, since they all depend on having user level access to github
2019-08-23 18:10:38 -07:00
Sean Sullivan
499d91f9f8 jackson-databind 2.9.9.3 2019-08-15 15:23:42 -04:00
Matt Farmer
8e0ceaa06b Add a test for requesting reviewers 2019-08-10 20:52:55 -04:00
Matt Farmer
4e62641f7e Add ability to get requested teams 2019-08-10 20:46:34 -04:00
Matt Farmer
688644f5a4 Add support for requesting teams review prs 2019-08-10 20:31:15 -04:00
Paulo Miguel Almeida
4703f2d1f5 Add tests for GithubApp integration;
Add wiremock-standalone library;

Signed-off-by: Paulo Almeida <paulo.miguel.almeida.rodenas@gmail.com>
2019-08-10 19:01:12 +12:00
Artem V. Navrotskiy
14149ae949 Add GitHub API requests logging 2019-07-19 12:00:48 +03:00
Wouter Gerarts
a0fb0d170c Remove unnessesairy "throws"
All IOExceptions are already caught within the method itself.
2019-07-12 17:46:34 +02:00
Vincent Behar
e133afec86 Add support for draft pull requests
See https://developer.github.com/v3/pulls/#input
and https://help.github.com/en/articles/about-pull-requests#draft-pull-requests

Note that it requires the use of a github api preview: https://developer.github.com/v3/previews/#draft-pull-requests
2019-07-11 17:12:20 +02:00
Liam Newman
3ae8ee8ddb Merge pull request #498 from rmetzger/fix-450
Add GHPullRequestReview.submitted_at field
2019-07-01 10:32:01 -07:00
Liam Newman
012643a231 Merge pull request #413 from ThomasCookOnline/fix_version
fix issues
2019-06-19 17:11:59 -07:00
Liam Newman
dccb43f4dc Merge pull request #517 from jamesatha/repo-by-id
Adds the ability to get a repository by ID
2019-06-19 17:11:03 -07:00
Paulo Almeida
15b3bc6a63 Remove JWT dependencies used for testing purposes 2019-06-18 13:36:00 +12:00
Paulo Almeida
2d15bef76d Add missing CHECK_SUITE github event 2019-06-18 11:24:59 +12:00
Paulo Almeida
756d298f04 Add missing INTEGRATION_INSTALLATION_REPOSITORIES github event 2019-06-18 10:50:08 +12:00
Paulo Almeida
9f35eb1a85 Add @Preview and @Deprecated annotations to methods in which the API is still in preview 2019-06-12 11:32:03 +12:00
Paulo Almeida
c905bb4b6c Implement GitHub App API methods 2019-06-11 17:27:07 +12:00
Austin Witt
c78af01c8f Added two getUserPublicOrganizations(...) methods to get public Org memberships of any user, not just the currently-authenticated one. 2019-05-23 09:08:18 -05:00
Austin Witt
084855645a Due-diligence & hygiene updates to GitHub.java 2019-05-23 09:03:47 -05:00
Liam Newman
afce9ece89 Merge pull request #507 from ingwarsw/add_get_team_by_id
Add getTeam by id function
2019-05-22 15:22:25 -07:00
Liam Newman
154e50e36d Merge pull request #499 from anatolyD/feature/let-create-pr-to-org-fork
Create PR from original repo to private org fork
2019-05-22 14:55:52 -07:00
Liam Newman
80a129102b Merge pull request #492 from arykov/fix_add_team_member_role_capital
fixed membership role problem with case
2019-05-17 14:03:43 -07:00
Liam Newman
93672a074e Merge pull request #508 from blacelle/mindthecode-2019-03-24
Update maven dependency
2019-05-16 19:32:04 -07:00
Liam Newman
c7f6f6233c Merge pull request #485 from scotty-g/remove-console-logging
remove system.out from listOrgs
2019-05-16 18:56:45 -07:00
Liam Newman
68915a9daf Added tests for createLabel() method 2019-05-16 18:51:44 -07:00
Liam Newman
13eb91f8dd Preserve api compatibility for createLabel() 2019-05-16 18:44:39 -07:00
Liam Newman
1a8355e6fb Merge branch 'master' into fix_version 2019-05-16 18:23:59 -07:00
James Athappilly
aa2b7ae60a Adds the ability to get a repository by ID
Fixes: https://github.com/kohsuke/github-api/issues/515
2019-04-26 00:29:26 -07:00
Benoit Lacelle
acd36b7ea5 Update maven dependency versions 2019-03-24 12:55:40 +00:00
Karol Lassak
87245ab79f Add getTeam by id function 2019-03-18 14:15:29 +01:00
Long Nguyen
13b6a17827 Added equals and hashcode 2019-03-07 01:08:56 +01:00
Anatoly Danilov
615e4cf24e Create PR is possible without the owner of the repo to modify PR.
Use case: when fork is done into private organization then the original repo maintainer can't have any access there hence this field has to be set to `false` explicitly
2019-02-20 09:25:35 +03:00
Robert Metzger
0e6d08f027 Add GHPullRequestReview.submitted_at field 2019-02-19 10:13:21 +01:00
Alex Rykov
d593e584dd fixed membership role problem with case 2019-02-01 12:19:28 -05:00
sg012265
e046b97160 remove system.out from listOrgs 2018-12-22 21:31:33 -06:00
Martin van Zijl
567d3dac55 Add support for editing Gists.
Fixes issue #466

NOTE: I could not get the deleteFile() method to work.
2018-12-20 08:16:25 +13:00
Martin van Zijl
a67a0aa924 Add method to invite user to organization.
Fixes issue #467
2018-12-14 07:18:29 +13:00
Турбанов Андрей
1b1e3e88fe Provide more exception details
For now if invalid credentials used to search github-api throws following exception

    Exception in thread "main" org.kohsuke.github.GHException: Failed to retrieve https://api.github.com/search/repositories?q=vk+language%3Ajava+created%3A2015-11-26..2016-11-26
	at org.kohsuke.github.Requester$PagingIterator.fetch(Requester.java:529)
	at org.kohsuke.github.Requester$PagingIterator.hasNext(Requester.java:494)
	at org.kohsuke.github.PagedSearchIterable$1.hasNext(PagedSearchIterable.java:55)
	at org.kohsuke.github.PagedIterator.fetch(PagedIterator.java:44)
	at org.kohsuke.github.PagedIterator.hasNext(PagedIterator.java:32)

There is no mentions if credentials at all. Better to propagate exception to user to be able to deal with it.
2018-11-26 01:21:28 +03:00
Immanuel Washington
ec99636ef0 Adding Label description property
Label in the GitHub API has an optional field description which had not been implemented.
2018-11-25 02:10:06 -05:00
Martin van Zijl
9d955d252a Add statistics API.
Fixes issue #330
2018-11-16 18:24:30 +13:00
Martin van Zijl
f136f6837a Added description field to GHTeam class.
Fixes issue #460.
2018-11-13 07:37:07 +13:00
Martin van Zijl
6fc1fb0966 Added a method to list authorizations.
Fixes issue #459
2018-11-12 17:50:49 +13:00
Kohsuke Kawaguchi
fad203a66d [maven-release-plugin] prepare for next development iteration 2018-11-06 08:42:28 -08:00
Martin van Zijl
71304b114a Fix for issue #376. Added issue events API. 2018-08-13 11:44:21 +12:00
Edem Osmanov
2497ac68d1 fix issues 2018-02-14 12:16:01 +02:00
2017 changed files with 958208 additions and 1859 deletions

19
.github/release-drafter.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name-template: 'v$NEXT_PATCH_VERSION 🌈'
tag-template: 'v$NEXT_PATCH_VERSION'
categories:
- title: '🚀 Features'
labels:
- 'feature'
- 'enhancement'
- title: '🐛 Bug Fixes'
labels:
- 'fix'
- 'bugfix'
- 'bug'
- title: '🧰 Maintenance'
label: 'chore'
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
template: |
## Changes
$CHANGES

22
.github/workflows/maven-build.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: Java CI Build and Test
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
java: [ '1.8.0', '11.0.x', '13.0.x' ]
steps:
- uses: actions/checkout@v1
- 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
- name: Maven Build
run: mvn -B install site --file pom.xml

76
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at bitwiseman@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

62
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,62 @@
# Contributing
## Using WireMock and Snapshots
This project has started converting to using WireMock to stub out http responses instead of use live data.
This change will allow tests to run in a CI environment without needing to touch github.com.
The tests will instead serve previously recorded responses from local data files.
### Running WireMock tests
Example:
`mvn install -Dtest=WireMockStatusReporterTest`
This the default behavior.
### Setting up credential
1. Create an OAuth token on github.com
2. Set the GITHUB_OAUTH environment variable to the value of that token
3. Set the system property `test.github.useProxy` (usually like "-Dtest.github.useProxy" as a Java VM option)
`mvn install -Dtest.github.useProxy -Dtest=WireMockStatusReporterTest`
4. The above should report no test failures and include the following console output:
`WireMockStatusReporterTest: GitHub proxying and user auth correctly configured for user login: <your login>`
Whenever you run tests with `-Dtest.github.useProxy`, they will try to get data from local files but will fallback to proxying to github if not found.
### Writing a new test
Once you have credentials setup, you add new test classes and test methods as you would normally.
Keep `useProxy` enabled and iterate on your tests as needed. Remember, while proxying your tests are interacting with GitHub - you will need to clean up your state between runs.
When you are ready to create a snapshot of your test data,
run your test with `test.github.takeSnapshot` ("-Dtest.github.takeSnapshot" as a Java VM option). For example:
`mvn install -Dtest.github.takeSnapshot -Dtest=YourTestClassName`
The above command would create snapshot WireMock data files under the path `src/test/resources/org/kohsuhke/github/YourTestClassName/wiremock`.
Each method would get a separate director that would hold the data files for that test method.
Add all files including the generated data to your commit and submit a PR.
### Modifying existing tests
When modifying existing tests, you can change the stubbed WireMock data files by hand or you can try generating a new snapshot.
#### Manual editing of data (minor changes only)
If you know what data will change, it is sometimes simplest to make any required changes to the data files manually.
This can be easier if the changes are minor or when you development environment is not setup to to take updated snapshots.
#### Generating a new snapshot
For more most changes, it is recommended to take a new snapshot when updating tests.
Delete the wiremock data files for the test method you will be modifying.
For more significant changes, you can even delete the WireMock files for an entire test class.
Then follow the same as when writing a new test: run with proxy enabled to debug, take a new snapshot when done, commit everything, and submit the PR.

3
README
View File

@@ -1,3 +0,0 @@
Java API for GitHub
See http://github-api.kohsuke.org/ for more details

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
Java API for GitHub
See https://github-api.kohsuke.org/ for more details

400
pom.xml
View File

@@ -3,58 +3,148 @@
<parent>
<groupId>org.kohsuke</groupId>
<artifactId>pom</artifactId>
<version>20</version>
<version>21</version>
<relativePath />
</parent>
<artifactId>github-api</artifactId>
<version>1.95</version>
<version>1.99</version>
<name>GitHub API for Java</name>
<url>http://github-api.kohsuke.org/</url>
<url>https://github-api.kohsuke.org/</url>
<description>GitHub API for Java</description>
<scm>
<connection>scm:git:git@github.com/kohsuke/${project.artifactId}.git</connection>
<developerConnection>scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git</developerConnection>
<url>http://${project.artifactId}.kohsuke.org/</url>
<tag>github-api-1.95</tag>
<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.99</tag>
</scm>
<distributionManagement>
<site>
<id>github-pages</id>
<url>gitsite:git@github.com/kohsuke/${project.artifactId}.git</url>
<url>gitsite:git@github.com/github-api/${project.artifactId}.git</url>
</site>
</distributionManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<findbugs-maven-plugin.version>3.0.2</findbugs-maven-plugin.version>
<findbugs-maven-plugin.failOnError>true</findbugs-maven-plugin.failOnError>
<spotbugs-maven-plugin.version>3.1.12.2</spotbugs-maven-plugin.version>
<spotbugs.version>3.1.12</spotbugs.version>
<spotbugs-maven-plugin.failOnError>true</spotbugs-maven-plugin.failOnError>
<hamcrest.version>2.2</hamcrest.version>
<okhttp3.version>3.12.3</okhttp3.version>
<okio.version>2.4.1</okio.version>
<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>
<!-- For non-ci builds we'd like the build to still complete if jacoco metrics aren't met. -->
<jacoco.haltOnFailure>false</jacoco.haltOnFailure>
</properties>
<build>
<extensions>
<extension>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-provider-gitexe</artifactId>
<version>1.11.2</version>
</extension>
<extension>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-manager-plexus</artifactId>
<version>1.11.2</version>
</extension>
</extensions>
<testResources>
<testResource>
<directory>src/test/resources</directory>
<excludes>
<exclude>**/wiremock/**</exclude>
</excludes>
</testResource>
</testResources>
<pluginManagement>
<plugins>
<!-- adds jacoco coverage -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.5</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<source>8</source>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.8.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<rerunFailingTestsCount>2</rerunFailingTestsCount>
<autoVersionSubmodules>true</autoVersionSubmodules>
<useReleaseProfile>false</useReleaseProfile>
<releaseProfiles>release</releaseProfiles>
<goals>deploy</goals>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
<dependencies>
<dependency>
<groupId>org.apache.bcel</groupId>
<artifactId>bcel</artifactId>
<version>6.4.1</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>org.jenkins-ci</groupId>
<artifactId>annotation-indexer</artifactId>
<version>1.12</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>
<version>1.15</version>
<version>1.18</version>
<configuration>
<signature>
<groupId>org.codehaus.mojo.signature</groupId>
<artifactId>java15</artifactId>
<artifactId>java18</artifactId>
<version>1.0</version>
</signature>
</configuration>
<executions>
<execution>
<id>ensure-java-1.5-class-library</id>
<id>ensure-java-1.8-class-library</id>
<phase>test</phase>
<goals>
<goal>check</goal>
@@ -62,32 +152,51 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.infradna.tool</groupId>
<artifactId>bridge-method-injector</artifactId>
<version>1.18</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
</execution>
</executions>
<plugin>
<groupId>com.infradna.tool</groupId>
<artifactId>bridge-method-injector</artifactId>
<version>1.18</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>${findbugs-maven-plugin.version}</version>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>${spotbugs-maven-plugin.version}</version>
<configuration>
<xmlOutput>true</xmlOutput>
<failOnError>${findbugs-maven-plugin.failOnError}</failOnError>
<failOnError>${spotbugs-maven-plugin.failOnError}</failOnError>
</configuration>
<executions>
<execution>
<id>run-findbugs</id>
<phase>verify</phase>
<id>run-spotbugs</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<dependencies>
<!-- overwrite dependency on spotbugs if you want to specify the version of spotbugs -->
<dependency>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs</artifactId>
<version>${spotbugs.version}</version>
</dependency>
</dependencies>
</plugin>
<!-- Do not use gmaven plugin -->
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
@@ -99,12 +208,31 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
<version>3.9</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.7</version>
<version>1.13</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>
<!-- This is needed in order to force junit4 and JTH tests to use newer hamcrest version -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
@@ -112,26 +240,20 @@
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.2</version>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.4</version>
<version>2.6</version>
</dependency>
<dependency>
<groupId>com.infradna.tool</groupId>
<artifactId>bridge-method-annotation</artifactId>
<version>1.17</version>
<version>1.18</version>
<optional>true</optional>
</dependency>
<dependency>
@@ -143,19 +265,31 @@
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>4.9.0.201710071750-r</version>
<version>5.5.1.201910021850-r</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>okhttp-urlconnection</artifactId>
<version>2.7.5</version>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
<version>${okio.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp3.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp-urlconnection</artifactId>
<version>3.9.0</version>
<version>${okhttp3.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>okhttp-urlconnection</artifactId>
<version>2.7.5</version>
<optional>true</optional>
</dependency>
<dependency>
@@ -166,43 +300,189 @@
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<artifactId>mockito-core</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>annotations</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-annotations</artifactId>
<version>${spotbugs.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8-standalone</artifactId>
<version>2.25.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>repo.jenkins-ci.org</id>
<url>http://repo.jenkins-ci.org/public/</url>
<url>https://repo.jenkins-ci.org/public/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>repo.jenkins-ci.org</id>
<url>http://repo.jenkins-ci.org/public/</url>
<url>https://repo.jenkins-ci.org/public/</url>
</pluginRepository>
</pluginRepositories>
<profiles>
<profile>
<id>jacoco</id>
<activation>
<property>
<name>enable-jacoco</name>
</property>
</activation>
<build>
<plugins>
<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>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.0</version>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
</plugin>
</plugins>
</reporting>
<licenses>
<license>
<name>The MIT license</name>
<url>http://www.opensource.org/licenses/mit-license.php</url>
<url>https://www.opensource.org/licenses/mit-license.php</url>
<distribution>repo</distribution>
</license>
</licenses>

View File

@@ -24,9 +24,10 @@ public abstract class AbuseLimitHandler {
* @see <a href="https://developer.github.com/v3/#abuse-rate-limits">API documentation from GitHub</a>
* @param e
* Exception from Java I/O layer. If you decide to fail the processing, you can throw
* this exception (or wrap this exception into another exception and throw it.)
* this exception (or wrap this exception into another exception and throw it).
* @param uc
* Connection that resulted in an error. Useful for accessing other response headers.
* @throws IOException
*/
public abstract void onError(IOException e, HttpURLConnection uc) throws IOException;
@@ -38,7 +39,7 @@ public abstract class AbuseLimitHandler {
public void onError(IOException e, HttpURLConnection uc) throws IOException {
try {
Thread.sleep(parseWaitTime(uc));
} catch (InterruptedException _) {
} catch (InterruptedException ex) {
throw (InterruptedIOException)new InterruptedIOException().initCause(e);
}
}
@@ -57,7 +58,7 @@ public abstract class AbuseLimitHandler {
public static final AbuseLimitHandler FAIL = new AbuseLimitHandler() {
@Override
public void onError(IOException e, HttpURLConnection uc) throws IOException {
throw (IOException)new IOException("Abust limit reached").initCause(e);
throw (IOException)new IOException("Abuse limit reached").initCause(e);
}
};
}

View File

@@ -0,0 +1,172 @@
package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import static org.kohsuke.github.Previews.MACHINE_MAN;
/**
* A Github App.
*
* @author Paulo Miguel Almeida
*
* @see GitHub#getApp()
*/
public class GHApp extends GHObject {
private GitHub root;
private GHUser owner;
private String name;
private String description;
@JsonProperty("external_url")
private String externalUrl;
private Map<String,String> permissions;
private List<GHEvent> events;
@JsonProperty("installations_count")
private long installationsCount;
@JsonProperty("html_url")
private String htmlUrl;
public GHUser getOwner() {
return owner;
}
public void setOwner(GHUser owner) {
this.owner = owner;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getExternalUrl() {
return externalUrl;
}
public void setExternalUrl(String externalUrl) {
this.externalUrl = externalUrl;
}
public List<GHEvent> getEvents() {
return events;
}
public void setEvents(List<GHEvent> events) {
this.events = events;
}
public long getInstallationsCount() {
return installationsCount;
}
public void setInstallationsCount(long installationsCount) {
this.installationsCount = installationsCount;
}
public URL getHtmlUrl() {
return GitHub.parseURL(htmlUrl);
}
public Map<String, String> getPermissions() {
return permissions;
}
public void setPermissions(Map<String, String> permissions) {
this.permissions = permissions;
}
/*package*/ GHApp wrapUp(GitHub root) {
this.root = root;
return this;
}
/**
* Obtains all the installations associated with this app.
*
* You must use a JWT to access this endpoint.
*
* @see <a href="https://developer.github.com/v3/apps/#list-installations">List installations</a>
* @return a list of App installations
*/
@Preview @Deprecated
public PagedIterable<GHAppInstallation> listInstallations() {
return root.retrieve().withPreview(MACHINE_MAN)
.asPagedIterable(
"/app/installations",
GHAppInstallation[].class,
item -> item.wrapUp(root) );
}
/**
* Obtain an installation associated with this app
* @param id - Installation Id
*
* You must use a JWT to access this endpoint.
*
* @see <a href="https://developer.github.com/v3/apps/#get-an-installation">Get an installation</a>
*/
@Preview @Deprecated
public GHAppInstallation getInstallationById(long id) throws IOException {
return root.retrieve().withPreview(MACHINE_MAN).to(String.format("/app/installations/%d", id), GHAppInstallation.class).wrapUp(root);
}
/**
* Obtain an organization installation associated with this app
* @param name - Organization name
*
* You must use a JWT to access this endpoint.
*
* @see <a href="https://developer.github.com/v3/apps/#get-an-organization-installation">Get an organization installation</a>
*/
@Preview @Deprecated
public GHAppInstallation getInstallationByOrganization(String name) throws IOException {
return root.retrieve().withPreview(MACHINE_MAN).to(String.format("/orgs/%s/installation", name), GHAppInstallation.class).wrapUp(root);
}
/**
* Obtain an repository installation associated with this app
* @param ownerName - Organization or user name
* @param repositoryName - Repository name
*
* You must use a JWT to access this endpoint.
*
* @see <a href="https://developer.github.com/v3/apps/#get-a-repository-installation">Get a repository installation</a>
*/
@Preview @Deprecated
public GHAppInstallation getInstallationByRepository(String ownerName, String repositoryName) throws IOException {
return root.retrieve().withPreview(MACHINE_MAN).to(String.format("/repos/%s/%s/installation", ownerName, repositoryName), GHAppInstallation.class).wrapUp(root);
}
/**
* Obtain a user installation associated with this app
* @param name - user name
*
* You must use a JWT to access this endpoint.
*
* @see <a href="https://developer.github.com/v3/apps/#get-a-user-installation">Get a user installation</a>
*/
@Preview @Deprecated
public GHAppInstallation getInstallationByUser(String name) throws IOException {
return root.retrieve().withPreview(MACHINE_MAN).to(String.format("/users/%s/installation", name), GHAppInstallation.class).wrapUp(root);
}
}

View File

@@ -0,0 +1,53 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static org.kohsuke.github.Previews.MACHINE_MAN;
/**
* Creates a access token for a GitHub App Installation
*
* @author Paulo Miguel Almeida
*
* @see GHAppInstallation#createToken(Map)
*/
public class GHAppCreateTokenBuilder {
private final GitHub root;
protected final Requester builder;
private final String apiUrlTail;
@Preview @Deprecated
/*package*/ GHAppCreateTokenBuilder(GitHub root, String apiUrlTail, Map<String, GHPermissionType> permissions) {
this.root = root;
this.apiUrlTail = apiUrlTail;
this.builder = new Requester(root);
this.builder.withPermissions("permissions",permissions);
}
/**
* By default the installation token has access to all repositories that the installation can access. To restrict
* the access to specific repositories, you can provide the repository_ids when creating the token. When you omit
* repository_ids, the response does not contain neither the repositories nor the permissions key.
*
* @param repositoryIds - Array containing the repositories Ids
*
*/
@Preview @Deprecated
public GHAppCreateTokenBuilder repositoryIds(List<Long> repositoryIds) {
this.builder.with("repository_ids",repositoryIds);
return this;
}
/**
* Creates an app token with all the parameters.
*
* You must use a JWT to access this endpoint.
*/
@Preview @Deprecated
public GHAppInstallationToken create() throws IOException {
return builder.method("POST").withPreview(MACHINE_MAN).to(apiUrlTail, GHAppInstallationToken.class).wrapUp(root);
}
}

View File

@@ -0,0 +1,167 @@
package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import static org.kohsuke.github.Previews.GAMBIT;
/**
* A Github App Installation.
*
* @author Paulo Miguel Almeida
*
* @see GHApp#listInstallations()
* @see GHApp#getInstallationById(long)
* @see GHApp#getInstallationByOrganization(String)
* @see GHApp#getInstallationByRepository(String, String)
* @see GHApp#getInstallationByUser(String)
*/
public class GHAppInstallation extends GHObject {
private GitHub root;
private GHUser account;
@JsonProperty("access_tokens_url")
private String accessTokenUrl;
@JsonProperty("repositories_url")
private String repositoriesUrl;
@JsonProperty("app_id")
private long appId;
@JsonProperty("target_id")
private long targetId;
@JsonProperty("target_type")
private GHTargetType targetType;
private Map<String, GHPermissionType> permissions;
private List<GHEvent> events;
@JsonProperty("single_file_name")
private String singleFileName;
@JsonProperty("repository_selection")
private GHRepositorySelection repositorySelection;
private String htmlUrl;
public URL getHtmlUrl() {
return GitHub.parseURL(htmlUrl);
}
public GitHub getRoot() {
return root;
}
public void setRoot(GitHub root) {
this.root = root;
}
public GHUser getAccount() {
return account;
}
public void setAccount(GHUser account) {
this.account = account;
}
public String getAccessTokenUrl() {
return accessTokenUrl;
}
public void setAccessTokenUrl(String accessTokenUrl) {
this.accessTokenUrl = accessTokenUrl;
}
public String getRepositoriesUrl() {
return repositoriesUrl;
}
public void setRepositoriesUrl(String repositoriesUrl) {
this.repositoriesUrl = repositoriesUrl;
}
public long getAppId() {
return appId;
}
public void setAppId(long appId) {
this.appId = appId;
}
public long getTargetId() {
return targetId;
}
public void setTargetId(long targetId) {
this.targetId = targetId;
}
public GHTargetType getTargetType() {
return targetType;
}
public void setTargetType(GHTargetType targetType) {
this.targetType = targetType;
}
public Map<String, GHPermissionType> getPermissions() {
return permissions;
}
public void setPermissions(Map<String, GHPermissionType> permissions) {
this.permissions = permissions;
}
public List<GHEvent> getEvents() {
return events;
}
public void setEvents(List<GHEvent> events) {
this.events = events;
}
public String getSingleFileName() {
return singleFileName;
}
public void setSingleFileName(String singleFileName) {
this.singleFileName = singleFileName;
}
public GHRepositorySelection getRepositorySelection() {
return repositorySelection;
}
public void setRepositorySelection(GHRepositorySelection repositorySelection) {
this.repositorySelection = repositorySelection;
}
/*package*/ GHAppInstallation wrapUp(GitHub root) {
this.root = root;
return this;
}
/**
* Delete a Github App installation
*
* You must use a JWT to access this endpoint.
*
* @see <a href="https://developer.github.com/v3/apps/#delete-an-installation">Delete an installation</a>
*/
@Preview @Deprecated
public void deleteInstallation() throws IOException {
root.retrieve().method("DELETE").withPreview(GAMBIT).to(String.format("/app/installations/%d", id));
}
/**
* 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.
*/
@Preview @Deprecated
public GHAppCreateTokenBuilder createToken(Map<String,GHPermissionType> permissions){
return new GHAppCreateTokenBuilder(root,String.format("/app/installations/%d/access_tokens", id), permissions);
}
}

View File

@@ -0,0 +1,87 @@
package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* A Github App Installation Token.
*
* @author Paulo Miguel Almeida
*
* @see GHAppInstallation#createToken(Map)
*/
public class GHAppInstallationToken {
private GitHub root;
private String token;
protected String expires_at;
private Map<String, String> permissions;
private List<GHRepository> repositories;
@JsonProperty("repository_selection")
private GHRepositorySelection repositorySelection;
public GitHub getRoot() {
return root;
}
public void setRoot(GitHub root) {
this.root = root;
}
public Map<String, String> getPermissions() {
return permissions;
}
public void setPermissions(Map<String, String> permissions) {
this.permissions = permissions;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public List<GHRepository> getRepositories() {
return repositories;
}
public void setRepositories(List<GHRepository> repositories) {
this.repositories = repositories;
}
public GHRepositorySelection getRepositorySelection() {
return repositorySelection;
}
public void setRepositorySelection(GHRepositorySelection repositorySelection) {
this.repositorySelection = repositorySelection;
}
/**
* When was this tokens expires?
*/
@WithBridgeMethods(value=String.class, adapterMethod="expiresAtStr")
public Date getExpiresAt() throws IOException {
return GitHub.parseDate(expires_at);
}
@SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD", justification = "Bridge method of getExpiresAt")
private Object expiresAtStr(Date id, Class type) {
return expires_at;
}
/*package*/ GHAppInstallationToken wrapUp(GitHub root) {
this.root = root;
return this;
}
}

View File

@@ -327,17 +327,11 @@ public class GHCommit {
* Lists up all the commit comments in this repository.
*/
public PagedIterable<GHCommitComment> listComments() {
return new PagedIterable<GHCommitComment>() {
public PagedIterator<GHCommitComment> _iterator(int pageSize) {
return new PagedIterator<GHCommitComment>(owner.root.retrieve().asIterator(String.format("/repos/%s/%s/commits/%s/comments", owner.getOwnerName(), owner.getName(), sha), GHCommitComment[].class, pageSize)) {
@Override
protected void wrapUp(GHCommitComment[] page) {
for (GHCommitComment c : page)
c.wrap(owner);
}
};
}
};
return owner.root.retrieve()
.asPagedIterable(
String.format("/repos/%s/%s/commits/%s/comments", owner.getOwnerName(), owner.getName(), sha),
GHCommitComment[].class,
item -> item.wrap(owner) );
}
/**

View File

@@ -98,17 +98,11 @@ public class GHCommitComment extends GHObject implements Reactable {
@Preview @Deprecated
public PagedIterable<GHReaction> listReactions() {
return new PagedIterable<GHReaction>() {
public PagedIterator<GHReaction> _iterator(int pageSize) {
return new PagedIterator<GHReaction>(owner.root.retrieve().withPreview(SQUIRREL_GIRL).asIterator(getApiTail()+"/reactions", GHReaction[].class, pageSize)) {
@Override
protected void wrapUp(GHReaction[] page) {
for (GHReaction c : page)
c.wrap(owner.root);
}
};
}
};
return owner.root.retrieve().withPreview(SQUIRREL_GIRL)
.asPagedIterable(
getApiTail()+"/reactions",
GHReaction[].class,
item -> item.wrap(owner.root) );
}
/**

View File

@@ -91,15 +91,10 @@ public class GHCommitQueryBuilder {
* Lists up the commits with the criteria built so far.
*/
public PagedIterable<GHCommit> list() {
return new PagedIterable<GHCommit>() {
public PagedIterator<GHCommit> _iterator(int pageSize) {
return new PagedIterator<GHCommit>(req.asIterator(repo.getApiTailUrl("commits"), GHCommit[].class, pageSize)) {
protected void wrapUp(GHCommit[] page) {
for (GHCommit c : page)
c.wrapUp(repo);
}
};
}
};
return req
.asPagedIterable(
repo.getApiTailUrl("commits"),
GHCommit[].class,
item -> item.wrapUp(repo) );
}
}

View File

@@ -2,10 +2,12 @@ package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.codec.binary.Base64InputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
/**
* A Content of a repository.
@@ -14,7 +16,7 @@ import java.io.InputStream;
* @see GHRepository#getFileContent(String)
*/
@SuppressWarnings({"UnusedDeclaration"})
public class GHContent {
public class GHContent implements Refreshable {
/*
In normal use of this class, repository field is set via wrap(),
but in the code search API, there's a nested 'repository' field that gets populated from JSON.
@@ -91,10 +93,8 @@ public class GHContent {
* Use {@link #read()}
*/
public String getEncodedContent() throws IOException {
if (content!=null)
return content;
else
return Base64.encodeBase64String(IOUtils.toByteArray(read()));
refresh(content);
return content;
}
public String getUrl() {
@@ -112,16 +112,27 @@ public class GHContent {
/**
* Retrieves the actual content stored here.
*/
/**
* Retrieves the actual bytes of the blob.
*/
public InputStream read() throws IOException {
// if the download link is encoded with a token on the query string, the default behavior of POST will fail
return new Requester(root).method("GET").asStream(getDownloadUrl());
refresh(content);
if (encoding.equals("base64")) {
try {
return new Base64InputStream(new ByteArrayInputStream(content.getBytes("US-ASCII")), false);
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e); // US-ASCII is mandatory
}
}
throw new UnsupportedOperationException("Unrecognized encoding: "+encoding);
}
/**
* URL to retrieve the raw content of the file. Null if this is a directory.
*/
public String getDownloadUrl() throws IOException {
populate();
refresh(download_url);
return download_url;
}
@@ -139,7 +150,6 @@ public class GHContent {
* Depending on the original API call where this object is created, it may not contain everything.
*/
protected synchronized void populate() throws IOException {
if (download_url!=null) return; // already populated
root.retrieve().to(url, this);
}
@@ -150,16 +160,11 @@ public class GHContent {
if (!isDirectory())
throw new IllegalStateException(path+" is not a directory");
return new PagedIterable<GHContent>() {
public PagedIterator<GHContent> _iterator(int pageSize) {
return new PagedIterator<GHContent>(root.retrieve().asIterator(url, GHContent[].class, pageSize)) {
@Override
protected void wrapUp(GHContent[] page) {
GHContent.wrap(page, repository);
}
};
}
};
return root.retrieve()
.asPagedIterable(
url,
GHContent[].class,
item -> item.wrap(repository) );
}
@SuppressFBWarnings("DM_DEFAULT_ENCODING")
@@ -243,4 +248,14 @@ public class GHContent {
}
return contents;
}
/**
* Fully populate the data by retrieving missing data.
*
* Depending on the original API call where this object is created, it may not contain everything.
*/
@Override
public synchronized void refresh() throws IOException {
root.retrieve().to(url, this);
}
}

View File

@@ -7,7 +7,6 @@ package org.kohsuke.github;
* @see <a href="https://developer.github.com/v3/licenses/#get-a-repositorys-license">documentation</a>
* @see GHRepository#getLicense()
*/
@Preview @Deprecated
class GHContentWithLicense extends GHContent {
GHLicense license;

View File

@@ -8,10 +8,10 @@ public class GHDeployKey {
protected String url, key, title;
protected boolean verified;
protected int id;
protected long id;
private GHRepository owner;
public int getId() {
public long getId() {
return id;
}

View File

@@ -71,17 +71,11 @@ public class GHDeployment extends GHObject {
}
public PagedIterable<GHDeploymentStatus> listStatuses() {
return new PagedIterable<GHDeploymentStatus>() {
public PagedIterator<GHDeploymentStatus> _iterator(int pageSize) {
return new PagedIterator<GHDeploymentStatus>(root.retrieve().asIterator(statuses_url, GHDeploymentStatus[].class, pageSize)) {
@Override
protected void wrapUp(GHDeploymentStatus[] page) {
for (GHDeploymentStatus c : page)
c.wrap(owner);
}
};
}
};
return root.retrieve()
.asPagedIterable(
statuses_url,
GHDeploymentStatus[].class,
item -> item.wrap(owner) );
}
}

View File

@@ -23,6 +23,8 @@ public enum GHEvent {
GOLLUM,
INSTALLATION,
INSTALLATION_REPOSITORIES,
INTEGRATION_INSTALLATION_REPOSITORIES,
CHECK_SUITE,
ISSUE_COMMENT,
ISSUES,
LABEL,

View File

@@ -34,7 +34,7 @@ public class GHEventInfo {
"UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" }, justification = "JSON API")
public static class GHEventRepository {
@SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now")
private int id;
private long id;
@SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now")
private String url; // repository API URL
private String name; // owner/repo

View File

@@ -1,6 +1,7 @@
package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.net.URL;
@@ -115,8 +116,13 @@ public class GHGist extends GHObject {
e.getValue().fileName = e.getKey();
}
}
String getApiTailUrl(String tail) {
return "/gists/" + id + '/' + tail;
String result = "/gists/" + id;
if (!StringUtils.isBlank(tail)) {
result += StringUtils.prependIfMissing(tail, "/");
}
return result;
}
public void star() throws IOException {
@@ -139,17 +145,11 @@ public class GHGist extends GHObject {
}
public PagedIterable<GHGist> listForks() {
return new PagedIterable<GHGist>() {
public PagedIterator<GHGist> _iterator(int pageSize) {
return new PagedIterator<GHGist>(root.retrieve().asIterator(getApiTailUrl("forks"), GHGist[].class, pageSize)) {
@Override
protected void wrapUp(GHGist[] page) {
for (GHGist c : page)
c.wrapUp(root);
}
};
}
};
return root.retrieve()
.asPagedIterable(
getApiTailUrl("forks"),
GHGist[].class,
item -> item.wrapUp(root) );
}
/**
@@ -159,6 +159,13 @@ public class GHGist extends GHObject {
new Requester(root).method("DELETE").to("/gists/" + id);
}
/**
* Updates this gist via a builder.
*/
public GHGistUpdater update() throws IOException {
return new GHGistUpdater(this);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -172,4 +179,10 @@ public class GHGist extends GHObject {
public int hashCode() {
return id.hashCode();
}
GHGist wrap(GHUser owner) {
this.owner = owner;
this.root = owner.root;
return this;
}
}

View File

@@ -0,0 +1,60 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
/**
* Builder pattern for updating a Gist.
*
* @author Martin van Zijl
*/
public class GHGistUpdater {
private final GHGist base;
private final Requester builder;
LinkedHashMap<String,Object> files;
GHGistUpdater(GHGist base) {
this.base = base;
this.builder = new Requester(base.root);
files = new LinkedHashMap<>();
}
public GHGistUpdater addFile(String fileName, String content) throws IOException {
updateFile(fileName, content);
return this;
}
// // This method does not work.
// public GHGistUpdater deleteFile(String fileName) throws IOException {
// files.put(fileName, Collections.singletonMap("filename", null));
// return this;
// }
public GHGistUpdater renameFile(String fileName, String newFileName) throws IOException
{
files.put(fileName, Collections.singletonMap("filename", newFileName));
return this;
}
public GHGistUpdater updateFile(String fileName, String content) throws IOException {
files.put(fileName, Collections.singletonMap("content", content));
return this;
}
public GHGistUpdater description(String desc) {
builder.with("description",desc);
return this;
}
/**
* Updates the Gist based on the parameters specified thus far.
*/
public GHGist update() throws IOException {
builder._with("files", files);
return builder
.method("PATCH")
.to(base.getApiTailUrl(""), GHGist.class).wrap(base.owner);
}
}

View File

@@ -292,16 +292,11 @@ public class GHIssue extends GHObject implements Reactable{
* Obtains all the comments associated with this issue.
*/
public PagedIterable<GHIssueComment> listComments() throws IOException {
return new PagedIterable<GHIssueComment>() {
public PagedIterator<GHIssueComment> _iterator(int pageSize) {
return new PagedIterator<GHIssueComment>(root.retrieve().asIterator(getIssuesApiRoute() + "/comments", GHIssueComment[].class, pageSize)) {
protected void wrapUp(GHIssueComment[] page) {
for (GHIssueComment c : page)
c.wrapUp(GHIssue.this);
}
};
}
};
return root.retrieve()
.asPagedIterable(
getIssuesApiRoute() + "/comments",
GHIssueComment[].class,
item -> item.wrapUp(GHIssue.this) );
}
@Preview @Deprecated
@@ -314,17 +309,11 @@ public class GHIssue extends GHObject implements Reactable{
@Preview @Deprecated
public PagedIterable<GHReaction> listReactions() {
return new PagedIterable<GHReaction>() {
public PagedIterator<GHReaction> _iterator(int pageSize) {
return new PagedIterator<GHReaction>(owner.root.retrieve().withPreview(SQUIRREL_GIRL).asIterator(getApiRoute()+"/reactions", GHReaction[].class, pageSize)) {
@Override
protected void wrapUp(GHReaction[] page) {
for (GHReaction c : page)
c.wrap(owner.root);
}
};
}
};
return owner.root.retrieve().withPreview(SQUIRREL_GIRL)
.asPagedIterable(
getApiRoute()+"/reactions",
GHReaction[].class,
item -> item.wrap(owner.root) );
}
public void addAssignees(GHUser... assignees) throws IOException {
@@ -430,4 +419,15 @@ public class GHIssue extends GHObject implements Reactable{
return GitHub.parseURL(html_url);
}
}
/**
* Lists events for this issue.
* See https://developer.github.com/v3/issues/events/
*/
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) );
}
}

View File

@@ -109,17 +109,12 @@ public class GHIssueComment extends GHObject implements Reactable {
@Preview @Deprecated
public PagedIterable<GHReaction> listReactions() {
return new PagedIterable<GHReaction>() {
public PagedIterator<GHReaction> _iterator(int pageSize) {
return new PagedIterator<GHReaction>(owner.root.retrieve().withPreview(SQUIRREL_GIRL).asIterator(getApiRoute()+"/reactions", GHReaction[].class, pageSize)) {
@Override
protected void wrapUp(GHReaction[] page) {
for (GHReaction c : page)
c.wrap(owner.root);
}
};
}
};
return owner.root.retrieve()
.withPreview(SQUIRREL_GIRL)
.asPagedIterable(
getApiRoute()+"/reactions",
GHReaction[].class,
item -> item.wrap(owner.root) );
}
private String getApiRoute() {

View File

@@ -0,0 +1,81 @@
package org.kohsuke.github;
import java.util.Date;
/**
* @author Martin van Zijl
*/
public class GHIssueEvent {
private GitHub root;
private long id;
private String node_id;
private String url;
private GHUser actor;
private String event;
private String commit_id;
private String commit_url;
private String created_at;
private GHIssue issue;
public long getId() {
return id;
}
public String getNodeId() {
return node_id;
}
public String getUrl() {
return url;
}
public GHUser getActor() {
return actor;
}
public String getEvent() {
return event;
}
public String getCommitId() {
return commit_id;
}
public String getCommitUrl() {
return commit_url;
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public GitHub getRoot() {
return root;
}
public GHIssue getIssue() {
return issue;
}
GHIssueEvent wrapUp(GitHub root) {
this.root = root;
return this;
}
GHIssueEvent wrapUp(GHIssue parent) {
this.issue = parent;
this.root = parent.root;
return this;
}
@Override
public String toString() {
return String.format("Issue %d was %s by %s on %s",
getIssue().getNumber(),
getEvent(),
getActor().getLogin(),
getCreatedAt().toString());
}
}

View File

@@ -4,14 +4,16 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import static org.kohsuke.github.Previews.SYMMETRA;
/**
* @author Kohsuke Kawaguchi
* @see GHIssue#getLabels()
* @see GHRepository#listLabels()
*/
public class GHLabel {
private String url, name, color;
private String url, name, color, description;
private GHRepository repo;
public String getUrl() {
@@ -29,6 +31,14 @@ public class GHLabel {
return color;
}
/**
* Purpose of Label
*/
@Preview @Deprecated
public String getDescription() {
return description;
}
/*package*/ GHLabel wrapUp(GHRepository repo) {
this.repo = repo;
return this;
@@ -43,7 +53,26 @@ public class GHLabel {
* 6-letter hex color code, like "f29513"
*/
public void setColor(String newColor) throws IOException {
repo.root.retrieve().method("PATCH").with("name", name).with("color", newColor).to(url);
repo.root.retrieve().method("PATCH")
.withPreview(SYMMETRA)
.with("name", name)
.with("color", newColor)
.with("description", description)
.to(url);
}
/**
* @param newDescription
* Description of label
*/
@Preview @Deprecated
public void setDescription(String newDescription) throws IOException {
repo.root.retrieve().method("PATCH")
.withPreview(SYMMETRA)
.with("name", name)
.with("color", color)
.with("description", newDescription)
.to(url);
}
/*package*/ static Collection<String> toNames(Collection<GHLabel> labels) {
@@ -53,4 +82,20 @@ public class GHLabel {
}
return r;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final GHLabel ghLabel = (GHLabel) o;
return Objects.equals(url, ghLabel.url) &&
Objects.equals(name, ghLabel.name) &&
Objects.equals(color, ghLabel.color) &&
Objects.equals(repo, ghLabel.repo);
}
@Override
public int hashCode() {
return Objects.hash(url, name, color, repo);
}
}

View File

@@ -32,19 +32,15 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import static org.kohsuke.github.Previews.*;
/**
* The GitHub Preview API's license information
* <p>
* WARNING: This uses a PREVIEW API - subject to change.
*
* @author Duncan Dickinson
* @see GitHub#getLicense(String)
* @see GHRepository#getLicense()
* @see <a href="https://developer.github.com/v3/licenses/">https://developer.github.com/v3/licenses/</a>
*/
@Preview @Deprecated
@SuppressWarnings({"UnusedDeclaration"})
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
@@ -144,7 +140,7 @@ public class GHLicense extends GHObject {
protected synchronized void populate() throws IOException {
if (description!=null) return; // already populated
root.retrieve().withPreview(DRAX).to(url, this);
root.retrieve().to(url, this);
}
@Override

View File

@@ -85,10 +85,29 @@ public class GHMilestone extends GHObject {
edit("state", "open");
}
/**
* Deletes this milestone.
*/
public void delete() throws IOException {
root.retrieve().method("DELETE").to(getApiRoute());
}
private void edit(String key, Object value) throws IOException {
new Requester(root)._with(key, value).method("PATCH").to(getApiRoute());
}
public void setTitle(String title) throws IOException {
edit("title", title);
}
public void setDescription(String description) throws IOException {
edit("description", description);
}
public void setDueOn(Date dueOn) throws IOException {
edit("due_on", GitHub.printDate(dueOn));
}
protected String getApiRoute() {
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/milestones/"+number;
}

View File

@@ -156,17 +156,13 @@ public class GHMyself extends GHUser {
* @param repoType type of repository returned in the listing
*/
public PagedIterable<GHRepository> listRepositories(final int pageSize, final RepositoryListFilter repoType) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(root.retrieve().with("type",repoType).asIterator("/user/repos", GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
c.wrap(root);
}
};
}
}.withPageSize(pageSize);
return root.retrieve()
.with("type",repoType)
.asPagedIterable(
"/user/repos",
GHRepository[].class,
item -> item.wrap(root)
).withPageSize(pageSize);
}
/**
@@ -191,16 +187,12 @@ public class GHMyself extends GHUser {
* Filter by a specific state
*/
public PagedIterable<GHMembership> listOrgMemberships(final GHMembership.State state) {
return new PagedIterable<GHMembership>() {
public PagedIterator<GHMembership> _iterator(int pageSize) {
return new PagedIterator<GHMembership>(root.retrieve().with("state",state).asIterator("/user/memberships/orgs", GHMembership[].class, pageSize)) {
@Override
protected void wrapUp(GHMembership[] page) {
GHMembership.wrap(page,root);
}
};
}
};
return root.retrieve()
.with("state",state)
.asPagedIterable(
"/user/memberships/orgs",
GHMembership[].class,
item -> item.wrap(root) );
}
/**

View File

@@ -9,6 +9,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import static org.kohsuke.github.Previews.INERTIA;
/**
* @author Kohsuke Kawaguchi
@@ -69,17 +70,11 @@ public class GHOrganization extends GHPerson {
* List up all the teams.
*/
public PagedIterable<GHTeam> listTeams() throws IOException {
return new PagedIterable<GHTeam>() {
public PagedIterator<GHTeam> _iterator(int pageSize) {
return new PagedIterator<GHTeam>(root.retrieve().asIterator(String.format("/orgs/%s/teams", login), GHTeam[].class, pageSize)) {
@Override
protected void wrapUp(GHTeam[] page) {
for (GHTeam c : page)
c.wrapUp(GHOrganization.this);
}
};
}
};
return root.retrieve()
.asPagedIterable(
String.format("/orgs/%s/teams", login),
GHTeam[].class,
item -> item.wrapUp(GHOrganization.this) );
}
/**
@@ -104,6 +99,22 @@ public class GHOrganization extends GHPerson {
return null;
}
/** Member's role in an organization */
public enum Role {
ADMIN, /** The user is an owner of the organization. */
MEMBER /** The user is a non-owner member of the organization. */
}
/**
* Adds (invites) a user to the organization.
* @see <a href="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().method("PUT")
.with("role", role.name().toLowerCase())
.to("/orgs/" + login + "/memberships/" + user.getLogin());
}
/**
* Checks if this organization has the specified user as a member.
*/
@@ -173,17 +184,12 @@ public class GHOrganization extends GHPerson {
}
private PagedIterable<GHUser> listMembers(final String suffix, final String filter) throws IOException {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> _iterator(int pageSize) {
String filterParams = (filter == null) ? "" : ("?filter=" + filter);
return new PagedIterator<GHUser>(root.retrieve().asIterator(String.format("/orgs/%s/%s%s", login, suffix, filterParams), GHUser[].class, pageSize)) {
@Override
protected void wrapUp(GHUser[] users) {
GHUser.wrap(users, root);
}
};
}
};
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) );
}
/**
@@ -193,6 +199,37 @@ public class GHOrganization extends GHPerson {
root.retrieve().method("DELETE").to("/orgs/" + login + "/public_members/" + u.getLogin(), null);
}
/**
* Returns the projects for this organization.
* @param status The status filter (all, open or closed).
*/
public PagedIterable<GHProject> listProjects(final GHProject.ProjectStateFilter status) throws IOException {
return root.retrieve().withPreview(INERTIA)
.with("state", status)
.asPagedIterable(
String.format("/orgs/%s/projects", login),
GHProject[].class,
item -> item.wrap(root) );
}
/**
* Returns all open projects for the organization.
*/
public PagedIterable<GHProject> listProjects() throws IOException {
return listProjects(GHProject.ProjectStateFilter.OPEN);
}
/**
* Creates a project for the organization.
*/
public GHProject createProject(String name, String body) throws IOException {
return root.retrieve().method("POST")
.withPreview(INERTIA)
.with("name", name)
.with("body", body)
.to(String.format("/orgs/%s/projects", login), GHProject.class).wrap(root);
}
public enum Permission { ADMIN, PUSH, PULL }
/**
@@ -202,7 +239,7 @@ public class GHOrganization extends GHPerson {
Requester post = new Requester(root).with("name", name).with("permission", p);
List<String> repo_names = new ArrayList<String>();
for (GHRepository r : repositories) {
repo_names.add(r.getName());
repo_names.add(login + "/" + r.getName());
}
post.with("repo_names",repo_names);
return post.method("POST").to("/orgs/" + login + "/teams", GHTeam.class).wrapUp(this);
@@ -245,17 +282,11 @@ 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 new PagedIterable<GHEventInfo>() {
public PagedIterator<GHEventInfo> _iterator(int pageSize) {
return new PagedIterator<GHEventInfo>(root.retrieve().asIterator(String.format("/orgs/%s/events", login), GHEventInfo[].class, pageSize)) {
@Override
protected void wrapUp(GHEventInfo[] page) {
for (GHEventInfo c : page)
c.wrapUp(root);
}
};
}
};
return root.retrieve()
.asPagedIterable(
String.format("/orgs/%s/events", login),
GHEventInfo[].class,
item -> item.wrapUp(root) );
}
/**
@@ -267,17 +298,12 @@ public class GHOrganization extends GHPerson {
*/
@Override
public PagedIterable<GHRepository> listRepositories(final int pageSize) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(root.retrieve().asIterator("/orgs/" + login + "/repos", GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
c.wrap(root);
}
};
}
}.withPageSize(pageSize);
return root.retrieve()
.asPagedIterable(
"/orgs/" + login + "/repos",
GHRepository[].class,
item -> item.wrap(root)
).withPageSize(pageSize);
}
/**

View File

@@ -79,32 +79,28 @@ public abstract class GHPerson extends GHObject {
* Unlike {@link #getRepositories()}, this does not wait until all the repositories are returned.
*/
public PagedIterable<GHRepository> listRepositories(final int pageSize) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(root.retrieve().asIterator("/users/" + login + "/repos", GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
c.wrap(root);
}
};
}
}.withPageSize(pageSize);
return root.retrieve()
.asPagedIterable(
"/users/" + login + "/repos",
GHRepository[].class,
item -> item.wrap(root)
).withPageSize(pageSize);
}
/**
* Loads repository list in a paginated fashion.
*
*
* <p>
* For a person with a lot of repositories, GitHub returns the list of repositories in a paginated fashion.
* Unlike {@link #getRepositories()}, this method allows the caller to start processing data as it arrives.
*
*
* Every {@link Iterator#next()} call results in I/O. Exceptions that occur during the processing is wrapped
* into {@link Error}.
*
* @deprecated
* Use {@link #listRepositories()}
*/
@Deprecated
public synchronized Iterable<List<GHRepository>> iterateRepositories(final int pageSize) {
return new Iterable<List<GHRepository>>() {
public Iterator<List<GHRepository>> iterator() {

View File

@@ -0,0 +1,183 @@
/*
* The MIT License
*
* Copyright 2018 Martin van Zijl.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.kohsuke.github;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.Locale;
import static org.kohsuke.github.Previews.INERTIA;
/**
* A GitHub project.
* @see <a href="https://developer.github.com/v3/projects/">Projects</a>
* @author Martin van Zijl
*/
public class GHProject extends GHObject {
protected GitHub root;
protected GHObject owner;
private String owner_url;
private String html_url;
private String node_id;
private String name;
private String body;
private int number;
private String state;
private GHUser creator;
@Override
public URL getHtmlUrl() throws IOException {
return GitHub.parseURL(html_url);
}
public GitHub getRoot() {
return root;
}
public GHObject getOwner() throws IOException {
if(owner == null) {
try {
if(owner_url.contains("/orgs/")) {
owner = root.retrieve().to(getOwnerUrl().getPath(), GHOrganization.class).wrapUp(root);
} else if(owner_url.contains("/users/")) {
owner = root.retrieve().to(getOwnerUrl().getPath(), GHUser.class).wrapUp(root);
} else if(owner_url.contains("/repos/")) {
owner = root.retrieve().to(getOwnerUrl().getPath(), GHRepository.class).wrap(root);
}
} catch (FileNotFoundException e) {
return null;
}
}
return owner;
}
public URL getOwnerUrl() {
return GitHub.parseURL(owner_url);
}
public String getNode_id() {
return node_id;
}
public String getName() {
return name;
}
public String getBody() {
return body;
}
public int getNumber() {
return number;
}
public ProjectState getState() {
return Enum.valueOf(ProjectState.class, state.toUpperCase(Locale.ENGLISH));
}
public GHUser getCreator() {
return creator;
}
public GHProject wrap(GHRepository repo) {
this.owner = repo;
this.root = repo.root;
return this;
}
public GHProject wrap(GitHub root) {
this.root = root;
return this;
}
private void edit(String key, Object value) throws IOException {
new Requester(root).withPreview(INERTIA)._with(key, value).method("PATCH").to(getApiRoute());
}
protected String getApiRoute() {
return "/projects/" + id;
}
public void setName(String name) throws IOException {
edit("name", name);
}
public void setBody(String body) throws IOException {
edit("body", body);
}
public enum ProjectState {
OPEN,
CLOSED
}
public void setState(ProjectState state) throws IOException {
edit("state", state.toString().toLowerCase());
}
public static enum ProjectStateFilter {
ALL,
OPEN,
CLOSED
}
/**
* Set the permission level that all members of the project's organization will have on this project.
* Only applicable for organization-owned projects.
*/
public void setOrganizationPermission(GHPermissionType permission) throws IOException {
edit("organization_permission", permission.toString().toLowerCase());
}
/**
* Sets visibility of the project within the organization.
* Only applicable for organization-owned projects.
*/
public void setPublic(boolean isPublic) throws IOException {
edit("public", isPublic);
}
public void delete() throws IOException {
new Requester(root).withPreview(INERTIA).method("DELETE").to(getApiRoute());
}
public PagedIterable<GHProjectColumn> listColumns() throws IOException {
final GHProject project = this;
return root.retrieve()
.withPreview(INERTIA)
.asPagedIterable(
String.format("/projects/%d/columns", id),
GHProjectColumn[].class,
item -> item.wrap(project) );
}
public GHProjectColumn createColumn(String name) throws IOException {
return root.retrieve().method("POST")
.withPreview(INERTIA)
.with("name", name)
.to(String.format("/projects/%d/columns", id), GHProjectColumn.class).wrap(this);
}
}

View File

@@ -0,0 +1,123 @@
package org.kohsuke.github;
import org.apache.commons.lang3.StringUtils;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import static org.kohsuke.github.Previews.INERTIA;
/**
* @author Gunnar Skjold
*/
public class GHProjectCard extends GHObject {
private GitHub root;
private GHProject project;
private GHProjectColumn column;
private String note;
private GHUser creator;
private String content_url, project_url, column_url;
private boolean archived;
public URL getHtmlUrl() throws IOException {
return null;
}
public GHProjectCard wrap(GitHub root) {
this.root = root;
return this;
}
public GHProjectCard wrap(GHProjectColumn column) {
this.column = column;
this.project = column.project;
this.root = column.root;
return this;
}
public GitHub getRoot() {
return root;
}
public GHProject getProject() throws IOException {
if(project == null) {
try {
project = root.retrieve().to(getProjectUrl().getPath(), GHProject.class).wrap(root);
} catch (FileNotFoundException e) {
return null;
}
}
return project;
}
public GHProjectColumn getColumn() throws IOException {
if(column == null) {
try {
column = root.retrieve().to(getColumnUrl().getPath(), GHProjectColumn.class).wrap(root);
} catch (FileNotFoundException e) {
return null;
}
}
return column;
}
public GHIssue getContent() throws IOException {
if(StringUtils.isEmpty(content_url))
return null;
try {
if(content_url.contains("/pulls")) {
return root.retrieve().to(getContentUrl().getPath(), GHPullRequest.class).wrap(root);
} else {
return root.retrieve().to(getContentUrl().getPath(), GHIssue.class).wrap(root);
}
} catch (FileNotFoundException e) {
return null;
}
}
public String getNote() {
return note;
}
public GHUser getCreator() {
return creator;
}
public URL getContentUrl() {
return GitHub.parseURL(content_url);
}
public URL getProjectUrl() {
return GitHub.parseURL(project_url);
}
public URL getColumnUrl() {
return GitHub.parseURL(column_url);
}
public boolean isArchived() {
return archived;
}
public void setNote(String note) throws IOException {
edit("note", note);
}
public void setArchived(boolean archived) throws IOException {
edit("archived", archived);
}
private void edit(String key, Object value) throws IOException {
new Requester(root).withPreview(INERTIA)._with(key, value).method("PATCH").to(getApiRoute());
}
protected String getApiRoute() {
return String.format("/projects/columns/cards/%d", id);
}
public void delete() throws IOException {
new Requester(root).withPreview(INERTIA).method("DELETE").to(getApiRoute());
}
}

View File

@@ -0,0 +1,98 @@
package org.kohsuke.github;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import static org.kohsuke.github.Previews.INERTIA;
/**
* @author Gunnar Skjold
*/
public class GHProjectColumn extends GHObject {
protected GitHub root;
protected GHProject project;
private String name;
private String project_url;
@Override
public URL getHtmlUrl() throws IOException {
return null;
}
public GHProjectColumn wrap(GitHub root) {
this.root = root;
return this;
}
public GHProjectColumn wrap(GHProject project) {
this.project = project;
this.root = project.root;
return this;
}
public GitHub getRoot() {
return root;
}
public GHProject getProject() throws IOException {
if(project == null) {
try {
project = root.retrieve().to(getProjectUrl().getPath(), GHProject.class).wrap(root);
} catch (FileNotFoundException e) {
return null;
}
}
return project;
}
public String getName() {
return name;
}
public URL getProjectUrl() {
return GitHub.parseURL(project_url);
}
public void setName(String name) throws IOException {
edit("name", name);
}
private void edit(String key, Object value) throws IOException {
new Requester(root).withPreview(INERTIA)._with(key, value).method("PATCH").to(getApiRoute());
}
protected String getApiRoute() {
return String.format("/projects/columns/%d", id);
}
public void delete() throws IOException {
new Requester(root).withPreview(INERTIA).method("DELETE").to(getApiRoute());
}
public PagedIterable<GHProjectCard> listCards() throws IOException {
final GHProjectColumn column = this;
return root.retrieve()
.withPreview(INERTIA)
.asPagedIterable(
String.format("/projects/columns/%d/cards", id),
GHProjectCard[].class,
item -> item.wrap(column) );
}
public GHProjectCard createCard(String note) throws IOException {
return root.retrieve().method("POST")
.withPreview(INERTIA)
.with("note", note)
.to(String.format("/projects/columns/%d/cards", id), GHProjectCard.class).wrap(this);
}
public GHProjectCard createCard(GHIssue issue) throws IOException {
return root.retrieve().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).wrap(this);
}
}

View File

@@ -26,12 +26,15 @@ package org.kohsuke.github;
import javax.annotation.CheckForNull;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import static org.kohsuke.github.Previews.SHADOW_CAT;
/**
* A pull request.
*
@@ -39,7 +42,7 @@ import java.util.List;
* @see GHRepository#getPullRequest(int)
*/
@SuppressWarnings({"UnusedDeclaration"})
public class GHPullRequest extends GHIssue {
public class GHPullRequest extends GHIssue implements Refreshable {
private static final String COMMENTS_ACTION = "/comments";
private static final String REQUEST_REVIEWERS = "/requested_reviewers";
@@ -53,6 +56,8 @@ public class GHPullRequest extends GHIssue {
private GHUser merged_by;
private int review_comments, additions, commits;
private boolean merged, maintainer_can_modify;
// making these package private to all for testing
boolean draft;
private Boolean mergeable;
private int deletions;
private String mergeable_state;
@@ -61,6 +66,7 @@ public class GHPullRequest extends GHIssue {
// pull request reviewers
private GHUser[] requested_reviewers;
private GHTeam[] requested_teams;
/**
* GitHub doesn't return some properties of {@link GHIssue} when requesting the GET on the 'pulls' API
@@ -81,6 +87,7 @@ public class GHPullRequest extends GHIssue {
if (head != null) head.wrapUp(root);
if (merged_by != null) merged_by.wrapUp(root);
if (requested_reviewers != null) GHUser.wrap(requested_reviewers, root);
if (requested_teams != null) GHTeam.wrapUp(requested_teams, this);
return this;
}
@@ -187,6 +194,11 @@ public class GHPullRequest extends GHIssue {
return maintainer_can_modify;
}
public boolean isDraft() throws IOException {
populate();
return draft;
}
/**
* Is this PR mergeable?
*
@@ -196,11 +208,19 @@ public class GHPullRequest extends GHIssue {
* API call is made to retrieve the latest state.
*/
public Boolean getMergeable() throws IOException {
if (mergeable==null)
refresh();
refresh(mergeable);
return mergeable;
}
/**
* for test purposes only
*/
@Deprecated
Boolean getMergeableNoRefresh() throws IOException {
return mergeable;
}
public int getDeletions() throws IOException {
populate();
return deletions;
@@ -225,10 +245,15 @@ public class GHPullRequest extends GHIssue {
}
public List<GHUser> getRequestedReviewers() throws IOException {
populate();
refresh(requested_reviewers);
return Collections.unmodifiableList(Arrays.asList(requested_reviewers));
}
public List<GHTeam> getRequestedTeams() throws IOException {
refresh(requested_teams);
return Collections.unmodifiableList(Arrays.asList(requested_teams));
}
/**
* Fully populate the data by retrieving missing data.
*
@@ -246,79 +271,53 @@ public class GHPullRequest extends GHIssue {
if (root.isOffline()) {
return; // cannot populate, will have to live with what we have
}
root.retrieve().to(url, this).wrapUp(owner);
root.retrieve()
.withPreview(SHADOW_CAT)
.to(url, this).wrapUp(owner);
}
/**
* Retrieves all the files associated to this pull request.
*/
public PagedIterable<GHPullRequestFileDetail> listFiles() {
return new PagedIterable<GHPullRequestFileDetail>() {
public PagedIterator<GHPullRequestFileDetail> _iterator(int pageSize) {
return new PagedIterator<GHPullRequestFileDetail>(root.retrieve().asIterator(String.format("%s/files", getApiRoute()),
GHPullRequestFileDetail[].class, pageSize)) {
@Override
protected void wrapUp(GHPullRequestFileDetail[] page) {
}
};
}
};
return root.retrieve()
.asPagedIterable(
String.format("%s/files", getApiRoute()),
GHPullRequestFileDetail[].class,
null);
}
/**
* Retrieves all the reviews associated to this pull request.
*/
public PagedIterable<GHPullRequestReview> listReviews() {
return new PagedIterable<GHPullRequestReview>() {
public PagedIterator<GHPullRequestReview> _iterator(int pageSize) {
return new PagedIterator<GHPullRequestReview>(root.retrieve()
.asIterator(String.format("%s/reviews", getApiRoute()),
GHPullRequestReview[].class, pageSize)) {
@Override
protected void wrapUp(GHPullRequestReview[] page) {
for (GHPullRequestReview r: page) {
r.wrapUp(GHPullRequest.this);
}
}
};
}
};
return root.retrieve()
.asPagedIterable(
String.format("%s/reviews", getApiRoute()),
GHPullRequestReview[].class,
item -> item.wrapUp(GHPullRequest.this));
}
/**
* Obtains all the review comments associated with this pull request.
*/
public PagedIterable<GHPullRequestReviewComment> listReviewComments() throws IOException {
return new PagedIterable<GHPullRequestReviewComment>() {
public PagedIterator<GHPullRequestReviewComment> _iterator(int pageSize) {
return new PagedIterator<GHPullRequestReviewComment>(root.retrieve().asIterator(getApiRoute() + COMMENTS_ACTION,
GHPullRequestReviewComment[].class, pageSize)) {
protected void wrapUp(GHPullRequestReviewComment[] page) {
for (GHPullRequestReviewComment c : page)
c.wrapUp(GHPullRequest.this);
}
};
}
};
return root.retrieve()
.asPagedIterable(
getApiRoute() + COMMENTS_ACTION,
GHPullRequestReviewComment[].class,
item -> item.wrapUp(GHPullRequest.this) );
}
/**
* Retrieves all the commits associated to this pull request.
*/
public PagedIterable<GHPullRequestCommitDetail> listCommits() {
return new PagedIterable<GHPullRequestCommitDetail>() {
public PagedIterator<GHPullRequestCommitDetail> _iterator(int pageSize) {
return new PagedIterator<GHPullRequestCommitDetail>(root.retrieve().asIterator(
return root.retrieve()
.asPagedIterable(
String.format("%s/commits", getApiRoute()),
GHPullRequestCommitDetail[].class, pageSize)) {
@Override
protected void wrapUp(GHPullRequestCommitDetail[] page) {
for (GHPullRequestCommitDetail c : page)
c.wrapUp(GHPullRequest.this);
}
};
}
};
GHPullRequestCommitDetail[].class,
item -> item.wrapUp(GHPullRequest.this) );
}
/**
@@ -361,7 +360,17 @@ public class GHPullRequest extends GHIssue {
.withLogins("reviewers", reviewers)
.to(getApiRoute() + REQUEST_REVIEWERS);
}
public void requestTeamReviewers(List<GHTeam> teams) throws IOException {
List<String> teamReviewers = new ArrayList<String>(teams.size());
for (GHTeam team : teams) {
teamReviewers.add(team.getSlug());
}
new Requester(root).method("POST")
.with("team_reviewers", teamReviewers)
.to(getApiRoute() + REQUEST_REVIEWERS);
}
/**
* Merge this pull request.
*

View File

@@ -1,5 +1,7 @@
package org.kohsuke.github;
import static org.kohsuke.github.Previews.SHADOW_CAT;
/**
* Lists up pull requests with some filtering and sorting.
*
@@ -20,6 +22,9 @@ public class GHPullRequestQueryBuilder extends GHQueryBuilder<GHPullRequest> {
}
public GHPullRequestQueryBuilder head(String head) {
if (head != null && !head.contains(":")) {
head = repo.getOwnerName() + ":" + head;
}
req.with("head",head);
return this;
}
@@ -43,16 +48,11 @@ public class GHPullRequestQueryBuilder extends GHQueryBuilder<GHPullRequest> {
@Override
public PagedIterable<GHPullRequest> list() {
return new PagedIterable<GHPullRequest>() {
public PagedIterator<GHPullRequest> _iterator(int pageSize) {
return new PagedIterator<GHPullRequest>(req.asIterator(repo.getApiTailUrl("pulls"), GHPullRequest[].class, pageSize)) {
@Override
protected void wrapUp(GHPullRequest[] page) {
for (GHPullRequest pr : page)
pr.wrapUp(repo);
}
};
}
};
return req
.withPreview(SHADOW_CAT)
.asPagedIterable(
repo.getApiTailUrl("pulls"),
GHPullRequest[].class,
item -> item.wrapUp(repo) );
}
}

View File

@@ -25,6 +25,7 @@ package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Date;
import javax.annotation.CheckForNull;
import java.io.IOException;
import java.net.URL;
@@ -43,6 +44,7 @@ public class GHPullRequestReview extends GHObject {
private GHUser user;
private String commit_id;
private GHPullRequestReviewState state;
private String submitted_at;
/*package*/ GHPullRequestReview wrapUp(GHPullRequest owner) {
this.owner = owner;
@@ -88,6 +90,21 @@ public class GHPullRequestReview extends GHObject {
return owner.getApiRoute()+"/reviews/"+id;
}
/**
* When was this resource created?
*/
public Date getSubmittedAt() throws IOException {
return GitHub.parseDate(submitted_at);
}
/**
* Since this method does not exist, we forward this value.
*/
@Override
public Date getCreatedAt() throws IOException {
return getSubmittedAt();
}
/**
* @deprecated
* Former preview method that changed when it got public. Left here for backward compatibility.
@@ -131,18 +148,10 @@ public class GHPullRequestReview extends GHObject {
* Obtains all the review comments associated with this pull request review.
*/
public PagedIterable<GHPullRequestReviewComment> listReviewComments() throws IOException {
return new PagedIterable<GHPullRequestReviewComment>() {
public PagedIterator<GHPullRequestReviewComment> _iterator(int pageSize) {
return new PagedIterator<GHPullRequestReviewComment>(
owner.root.retrieve()
.asIterator(getApiRoute() + "/comments",
GHPullRequestReviewComment[].class, pageSize)) {
protected void wrapUp(GHPullRequestReviewComment[] page) {
for (GHPullRequestReviewComment c : page)
c.wrapUp(owner);
}
};
}
};
return owner.root.retrieve()
.asPagedIterable(
getApiRoute() + "/comments",
GHPullRequestReviewComment[].class,
item -> item.wrapUp(owner) );
}
}

View File

@@ -148,16 +148,11 @@ public class GHPullRequestReviewComment extends GHObject implements Reactable {
@Preview @Deprecated
public PagedIterable<GHReaction> listReactions() {
return new PagedIterable<GHReaction>() {
public PagedIterator<GHReaction> _iterator(int pageSize) {
return new PagedIterator<GHReaction>(owner.root.retrieve().withPreview(SQUIRREL_GIRL).asIterator(getApiRoute() + "/reactions", GHReaction[].class, pageSize)) {
@Override
protected void wrapUp(GHReaction[] page) {
for (GHReaction c : page)
c.wrap(owner.root);
}
};
}
};
return owner.root.retrieve()
.withPreview(SQUIRREL_GIRL)
.asPagedIterable(
getApiRoute() + "/reactions",
GHReaction[].class,
item -> item.wrap(owner.root) );
}
}

View File

@@ -24,6 +24,9 @@
package org.kohsuke.github;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.lang3.StringUtils;
@@ -34,7 +37,9 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Arrays;
@@ -49,6 +54,9 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.WeakHashMap;
import java.util.NoSuchElementException;
import java.util.logging.Level;
import java.util.logging.Logger;
import static java.util.Arrays.*;
import static org.kohsuke.github.Previews.*;
@@ -76,6 +84,11 @@ public class GHRepository extends GHObject {
private String git_url, ssh_url, clone_url, svn_url, mirror_url;
private GHUser owner; // not fully populated. beware.
private boolean has_issues, has_wiki, fork, has_downloads, has_pages, archived;
private boolean allow_squash_merge;
private boolean allow_merge_commit;
private boolean allow_rebase_merge;
@JsonProperty("private")
private boolean _private;
private int forks_count, stargazers_count, watchers_count, size, open_issues_count, subscribers_count;
@@ -105,24 +118,18 @@ public class GHRepository extends GHObject {
public PagedIterable<GHDeployment> listDeployments(String sha,String ref,String task,String environment){
List<String> params = Arrays.asList(getParam("sha", sha), getParam("ref", ref), getParam("task", task), getParam("environment", environment));
final String deploymentsUrl = getApiTailUrl("deployments") + "?"+ join(params,"&");
return new PagedIterable<GHDeployment>() {
public PagedIterator<GHDeployment> _iterator(int pageSize) {
return new PagedIterator<GHDeployment>(root.retrieve().asIterator(deploymentsUrl, GHDeployment[].class, pageSize)) {
@Override
protected void wrapUp(GHDeployment[] page) {
for (GHDeployment c : page)
c.wrap(GHRepository.this);
}
};
}
};
return root.retrieve()
.asPagedIterable(
deploymentsUrl,
GHDeployment[].class,
item -> item.wrap(GHRepository.this) );
}
/**
* Obtains a single {@link GHDeployment} by its ID.
*/
public GHDeployment getDeployment(long id) throws IOException {
return root.retrieve().to("deployments/" + id, GHDeployment.class).wrap(this);
return root.retrieve().to(getApiTailUrl("deployments/" + id), GHDeployment.class).wrap(this);
}
private String join(List<String> params, String joinStr) {
@@ -271,17 +278,11 @@ public class GHRepository extends GHObject {
* Lists up all the issues in this repository.
*/
public PagedIterable<GHIssue> listIssues(final GHIssueState state) {
return new PagedIterable<GHIssue>() {
public PagedIterator<GHIssue> _iterator(int pageSize) {
return new PagedIterator<GHIssue>(root.retrieve().with("state",state).asIterator(getApiTailUrl("issues"), GHIssue[].class, pageSize)) {
@Override
protected void wrapUp(GHIssue[] page) {
for (GHIssue c : page)
c.wrap(GHRepository.this);
}
};
}
};
return root.retrieve().with("state",state)
.asPagedIterable(
getApiTailUrl("issues"),
GHIssue[].class,
item -> item.wrap(GHRepository.this) );
}
public GHReleaseBuilder createRelease(String tag) {
@@ -335,31 +336,19 @@ public class GHRepository extends GHObject {
}
public PagedIterable<GHRelease> listReleases() throws IOException {
return new PagedIterable<GHRelease>() {
public PagedIterator<GHRelease> _iterator(int pageSize) {
return new PagedIterator<GHRelease>(root.retrieve().asIterator(getApiTailUrl("releases"), GHRelease[].class, pageSize)) {
@Override
protected void wrapUp(GHRelease[] page) {
for (GHRelease c : page)
c.wrap(GHRepository.this);
}
};
}
};
return root.retrieve()
.asPagedIterable(
getApiTailUrl("releases"),
GHRelease[].class,
item -> item.wrap(GHRepository.this) );
}
public PagedIterable<GHTag> listTags() throws IOException {
return new PagedIterable<GHTag>() {
public PagedIterator<GHTag> _iterator(int pageSize) {
return new PagedIterator<GHTag>(root.retrieve().asIterator(getApiTailUrl("tags"), GHTag[].class, pageSize)) {
@Override
protected void wrapUp(GHTag[] page) {
for (GHTag c : page)
c.wrap(GHRepository.this);
}
};
}
};
return root.retrieve()
.asPagedIterable(
getApiTailUrl("tags"),
GHTag[].class,
item -> item.wrap(GHRepository.this) );
}
/**
@@ -397,6 +386,18 @@ public class GHRepository extends GHObject {
public boolean isArchived() {
return archived;
}
public boolean isAllowSquashMerge() {
return allow_squash_merge;
}
public boolean isAllowMergeCommit() {
return allow_merge_commit;
}
public boolean isAllowRebaseMerge() {
return allow_rebase_merge;
}
/**
* Returns the number of all forks of this repository.
@@ -620,6 +621,22 @@ public class GHRepository extends GHObject {
edit("default_branch", value);
}
public void setPrivate(boolean value) throws IOException {
edit("private", Boolean.toString(value));
}
public void allowSquashMerge(boolean value) throws IOException {
edit("allow_squash_merge", Boolean.toString(value));
}
public void allowMergeCommit(boolean value) throws IOException {
edit("allow_merge_commit", Boolean.toString(value));
}
public void allowRebaseMerge(boolean value) throws IOException {
edit("allow_rebase_merge", Boolean.toString(value));
}
/**
* Deletes this repository.
*/
@@ -631,6 +648,29 @@ public class GHRepository extends GHObject {
}
}
/**
* Will archive and this repository as read-only. When a repository is archived, any operation
* that can change its state is forbidden. This applies symmetrically if trying to unarchive it.
*
* <p>When you try to do any operation that modifies a read-only repository, it returns the
* response:
*
* <pre>
* org.kohsuke.github.HttpException: {
* "message":"Repository was archived so is read-only.",
* "documentation_url":"https://developer.github.com/v3/repos/#edit"
* }
* </pre>
*
* @throws IOException In case of any networking error or error from the server.
*/
public void archive() throws IOException {
edit("archived", "true");
// Generall would not update this record,
// but do so here since this will result in any other update actions failing
archived = true;
}
/**
* Sort orders for listing forks
*/
@@ -650,18 +690,11 @@ public class GHRepository extends GHObject {
* currently {@link ForkSort#NEWEST ForkSort.NEWEST}.
*/
public PagedIterable<GHRepository> listForks(final ForkSort sort) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(root.retrieve().with("sort",sort).asIterator(getApiTailUrl("forks"), GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page) {
c.wrap(root);
}
}
};
}
};
return root.retrieve().with("sort",sort)
.asPagedIterable(
getApiTailUrl("forks"),
GHRepository[].class,
item -> item.wrap(root) );
}
/**
@@ -712,7 +745,9 @@ public class GHRepository extends GHObject {
* Retrieves a specified pull request.
*/
public GHPullRequest getPullRequest(int i) throws IOException {
return root.retrieve().to(getApiTailUrl("pulls/" + i), GHPullRequest.class).wrapUp(this);
return root.retrieve()
.withPreview(SHADOW_CAT)
.to(getApiTailUrl("pulls/" + i), GHPullRequest.class).wrapUp(this);
}
/**
@@ -758,10 +793,64 @@ public class GHRepository extends GHObject {
* of a pull request.
*/
public GHPullRequest createPullRequest(String title, String head, String base, String body) throws IOException {
return new Requester(root).with("title",title)
return createPullRequest(title, head, base, body, true);
}
/**
* Creates a new pull request. Maintainer's permissions aware.
*
* @param title
* Required. The title of the pull request.
* @param head
* Required. The name of the branch where your changes are implemented.
* For cross-repository pull requests in the same network,
* namespace head with a user like this: username:branch.
* @param base
* Required. The name of the branch you want your changes pulled into.
* This should be an existing branch on the current repository.
* @param body
* The contents of the pull request. This is the markdown description
* of a pull request.
* @param maintainerCanModify
* Indicates whether maintainers can modify the pull request.
*/
public GHPullRequest createPullRequest(String title, String head, String base, String body,
boolean maintainerCanModify) throws IOException {
return createPullRequest(title, head, base, body, maintainerCanModify, false);
}
/**
* Creates a new pull request. Maintainer's permissions and draft aware.
*
* @param title
* Required. The title of the pull request.
* @param head
* Required. The name of the branch where your changes are implemented.
* For cross-repository pull requests in the same network,
* namespace head with a user like this: username:branch.
* @param base
* Required. The name of the branch you want your changes pulled into.
* This should be an existing branch on the current repository.
* @param body
* The contents of the pull request. This is the markdown description
* of a pull request.
* @param maintainerCanModify
* Indicates whether maintainers can modify the pull request.
* @param draft
* Indicates whether to create a draft pull request or not.
*/
public GHPullRequest createPullRequest(String title, String head, String base, String body,
boolean maintainerCanModify, boolean draft) throws IOException {
return new Requester(root)
.withPreview(SHADOW_CAT)
.with("title",title)
.with("head",head)
.with("base",base)
.with("body",body).to(getApiTailUrl("pulls"),GHPullRequest.class).wrapUp(this);
.with("body",body)
.with("maintainer_can_modify", maintainerCanModify)
.with("draft", draft)
.to(getApiTailUrl("pulls"),GHPullRequest.class)
.wrapUp(this);
}
/**
@@ -777,7 +866,7 @@ public class GHRepository extends GHObject {
/**
* Gets a comparison between 2 points in the repository. This would be similar
* to calling <tt>git log id1...id2</tt> against a local repository.
* to calling <code>git log id1...id2</code> against a local repository.
* @param id1 an identifier for the first point to compare from, this can be a sha1 ID (for a commit, tag etc) or a direct tag name
* @param id2 an identifier for the second point to compare to. Can be the same as the first point.
* @return the comparison output
@@ -830,22 +919,16 @@ public class GHRepository extends GHObject {
*/
public PagedIterable<GHRef> listRefs() throws IOException {
final String url = String.format("/repos/%s/%s/git/refs", getOwnerName(), name);
return new PagedIterable<GHRef>() {
public PagedIterator<GHRef> _iterator(int pageSize) {
return new PagedIterator<GHRef>(root.retrieve().asIterator(url, GHRef[].class, pageSize)) {
protected void wrapUp(GHRef[] page) {
for(GHRef p: page) {
p.wrap(root);
}
}
};
}
};
return root.retrieve()
.asPagedIterable(
url,
GHRef[].class,
item -> item.wrap(root) );
}
/**
* Retrieves all refs of the given type for the current GitHub repository.
* @param refType the type of reg to search for e.g. <tt>tags</tt> or <tt>commits</tt>
* @param refType the type of reg to search for e.g. <code>tags</code> or <code>commits</code>
* @return an array of all refs matching the request type
* @throws IOException on failure communicating with GitHub, potentially due to an invalid ref type being requested
*/
@@ -856,21 +939,17 @@ public class GHRepository extends GHObject {
/**
* Retrieves all refs of the given type for the current GitHub repository.
*
* @param refType the type of reg to search for e.g. <tt>tags</tt> or <tt>commits</tt>
* @param refType the type of reg to search for e.g. <code>tags</code> or <code>commits</code>
* @return paged iterable of all refs of the specified type
* @throws IOException on failure communicating with GitHub, potentially due to an invalid ref type being requested
*/
public PagedIterable<GHRef> listRefs(String refType) throws IOException {
final String url = String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType);
return new PagedIterable<GHRef>() {
public PagedIterator<GHRef> _iterator(int pageSize) {
return new PagedIterator<GHRef>(root.retrieve().asIterator(url, GHRef[].class, pageSize)) {
protected void wrapUp(GHRef[] page) {
// no-op
}
};
}
};
return root.retrieve()
.asPagedIterable(
url,
GHRef[].class,
item -> item.wrap(root));
}
/**
@@ -901,7 +980,7 @@ public class GHRepository extends GHObject {
public GHTagObject getTagObject(String sha) throws IOException {
return root.retrieve().to(getApiTailUrl("git/tags/" + sha), GHTagObject.class).wrap(this);
}
/**
* Retrive a tree of the given type for the current GitHub repository.
*
@@ -984,16 +1063,11 @@ public class GHRepository extends GHObject {
* Lists all the commits.
*/
public PagedIterable<GHCommit> listCommits() {
return new PagedIterable<GHCommit>() {
public PagedIterator<GHCommit> _iterator(int pageSize) {
return new PagedIterator<GHCommit>(root.retrieve().asIterator(String.format("/repos/%s/%s/commits", getOwnerName(), name), GHCommit[].class, pageSize)) {
protected void wrapUp(GHCommit[] page) {
for (GHCommit c : page)
c.wrapUp(GHRepository.this);
}
};
}
};
return root.retrieve()
.asPagedIterable(
String.format("/repos/%s/%s/commits", getOwnerName(), name),
GHCommit[].class,
item -> item.wrapUp(GHRepository.this) );
}
/**
@@ -1007,28 +1081,20 @@ public class GHRepository extends GHObject {
* Lists up all the commit comments in this repository.
*/
public PagedIterable<GHCommitComment> listCommitComments() {
return new PagedIterable<GHCommitComment>() {
public PagedIterator<GHCommitComment> _iterator(int pageSize) {
return new PagedIterator<GHCommitComment>(root.retrieve().asIterator(String.format("/repos/%s/%s/comments", getOwnerName(), name), GHCommitComment[].class, pageSize)) {
@Override
protected void wrapUp(GHCommitComment[] page) {
for (GHCommitComment c : page)
c.wrap(GHRepository.this);
}
};
}
};
return root.retrieve()
.asPagedIterable(
String.format("/repos/%s/%s/comments", getOwnerName(), name),
GHCommitComment[].class,
item -> item.wrap(GHRepository.this) );
}
/**
* Gets the basic license details for the repository.
* <p>
* This is a preview item and subject to change.
*
* @throws IOException as usual but also if you don't use the preview connector
* @return null if there's no license.
*/
@Preview @Deprecated
public GHLicense getLicense() throws IOException{
GHContentWithLicense lic = getLicenseContent_();
return lic!=null ? lic.license : null;
@@ -1037,21 +1103,17 @@ public class GHRepository extends GHObject {
/**
* Retrieves the contents of the repository's license file - makes an additional API call
* <p>
* This is a preview item and subject to change.
*
* @return details regarding the license contents, or null if there's no license.
* @throws IOException as usual but also if you don't use the preview connector
*/
@Preview @Deprecated
public GHContent getLicenseContent() throws IOException {
return getLicenseContent_();
}
@Preview @Deprecated
private GHContentWithLicense getLicenseContent_() throws IOException {
try {
return root.retrieve()
.withPreview(DRAX)
.to(getApiTailUrl("license"), GHContentWithLicense.class).wrap(this);
} catch (FileNotFoundException e) {
return null;
@@ -1064,17 +1126,11 @@ public class GHRepository extends GHObject {
* Lists all the commit statues attached to the given commit, newer ones first.
*/
public PagedIterable<GHCommitStatus> listCommitStatuses(final String sha1) throws IOException {
return new PagedIterable<GHCommitStatus>() {
public PagedIterator<GHCommitStatus> _iterator(int pageSize) {
return new PagedIterator<GHCommitStatus>(root.retrieve().asIterator(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), name, sha1), GHCommitStatus[].class, pageSize)) {
@Override
protected void wrapUp(GHCommitStatus[] page) {
for (GHCommitStatus c : page)
c.wrapUp(root);
}
};
}
};
return root.retrieve()
.asPagedIterable(
String.format("/repos/%s/%s/statuses/%s", getOwnerName(), name, sha1),
GHCommitStatus[].class,
item -> item.wrapUp(root) );
}
/**
@@ -1115,17 +1171,11 @@ public class GHRepository extends GHObject {
* Lists repository events.
*/
public PagedIterable<GHEventInfo> listEvents() throws IOException {
return new PagedIterable<GHEventInfo>() {
public PagedIterator<GHEventInfo> _iterator(int pageSize) {
return new PagedIterator<GHEventInfo>(root.retrieve().asIterator(String.format("/repos/%s/%s/events", getOwnerName(), name), GHEventInfo[].class, pageSize)) {
@Override
protected void wrapUp(GHEventInfo[] page) {
for (GHEventInfo c : page)
c.wrapUp(root);
}
};
}
};
return root.retrieve()
.asPagedIterable(
String.format("/repos/%s/%s/events", getOwnerName(), name),
GHEventInfo[].class,
item -> item.wrapUp(root) );
}
/**
@@ -1134,27 +1184,40 @@ public class GHRepository extends GHObject {
* https://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository
*/
public PagedIterable<GHLabel> listLabels() throws IOException {
return new PagedIterable<GHLabel>() {
public PagedIterator<GHLabel> _iterator(int pageSize) {
return new PagedIterator<GHLabel>(root.retrieve().asIterator(getApiTailUrl("labels"), GHLabel[].class, pageSize)) {
@Override
protected void wrapUp(GHLabel[] page) {
for (GHLabel c : page)
c.wrapUp(GHRepository.this);
}
};
}
};
return root.retrieve()
.withPreview(SYMMETRA)
.asPagedIterable(
getApiTailUrl("labels"),
GHLabel[].class,
item -> item.wrapUp(GHRepository.this) );
}
public GHLabel getLabel(String name) throws IOException {
return root.retrieve().to(getApiTailUrl("labels/"+name), GHLabel.class).wrapUp(this);
return root.retrieve()
.withPreview(SYMMETRA)
.to(getApiTailUrl("labels/"+name), GHLabel.class)
.wrapUp(this);
}
public GHLabel createLabel(String name, String color) throws IOException {
return createLabel(name, color, "");
}
/**
* Description is still in preview.
* @param name
* @param color
* @param description
* @return
* @throws IOException
*/
@Preview @Deprecated
public GHLabel createLabel(String name, String color, String description) throws IOException {
return root.retrieve().method("POST")
.withPreview(SYMMETRA)
.with("name",name)
.with("color", color)
.with("description", description)
.to(getApiTailUrl("labels"), GHLabel.class).wrapUp(this);
}
@@ -1162,16 +1225,11 @@ public class GHRepository extends GHObject {
* Lists all the invitations.
*/
public PagedIterable<GHInvitation> listInvitations() {
return new PagedIterable<GHInvitation>() {
public PagedIterator<GHInvitation> _iterator(int pageSize) {
return new PagedIterator<GHInvitation>(root.retrieve().asIterator(String.format("/repos/%s/%s/invitations", getOwnerName(), name), GHInvitation[].class, pageSize)) {
protected void wrapUp(GHInvitation[] page) {
for (GHInvitation c : page)
c.wrapUp(root);
}
};
}
};
return root.retrieve()
.asPagedIterable(
String.format("/repos/%s/%s/invitations", getOwnerName(), name),
GHInvitation[].class,
item -> item.wrapUp(root) );
}
/**
@@ -1197,34 +1255,20 @@ public class GHRepository extends GHObject {
* see {@link #listStargazers()}
*/
public PagedIterable<GHStargazer> listStargazers2() {
return new PagedIterable<GHStargazer>() {
@Override
public PagedIterator<GHStargazer> _iterator(int pageSize) {
Requester requester = root.retrieve();
requester.setHeader("Accept", "application/vnd.github.v3.star+json");
return new PagedIterator<GHStargazer>(requester.asIterator(getApiTailUrl("stargazers"), GHStargazer[].class, pageSize)) {
@Override
protected void wrapUp(GHStargazer[] page) {
for (GHStargazer c : page) {
c.wrapUp(GHRepository.this);
}
}
};
}
};
return root.retrieve()
.withPreview("application/vnd.github.v3.star+json")
.asPagedIterable(
getApiTailUrl("stargazers"),
GHStargazer[].class,
item -> item.wrapUp(GHRepository.this) );
}
private PagedIterable<GHUser> listUsers(final String suffix) {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> _iterator(int pageSize) {
return new PagedIterator<GHUser>(root.retrieve().asIterator(getApiTailUrl(suffix), GHUser[].class, pageSize)) {
protected void wrapUp(GHUser[] page) {
for (GHUser c : page)
c.wrapUp(root);
}
};
}
};
return root.retrieve()
.asPagedIterable(
getApiTailUrl(suffix),
GHUser[].class,
item -> item.wrapUp(root) );
}
/**
@@ -1350,8 +1394,25 @@ public class GHRepository extends GHObject {
return r;
}
/**
* Replace special characters (e.g. #) with standard values (e.g. %23) so
* GitHub understands what is being requested.
* @param value string to be encoded.
* @return The encoded string.
*/
private String UrlEncode(String value) {
try {
return URLEncoder.encode(value, org.apache.commons.codec.CharEncoding.UTF_8);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(GHRepository.class.getName()).log(Level.SEVERE, null, ex);
}
// Something went wrong - just return original value as is.
return value;
}
public GHBranch getBranch(String name) throws IOException {
return root.retrieve().to(getApiTailUrl("branches/"+name),GHBranch.class).wrap(this);
return root.retrieve().to(getApiTailUrl("branches/"+UrlEncode(name)),GHBranch.class).wrap(this);
}
/**
@@ -1370,17 +1431,11 @@ public class GHRepository extends GHObject {
* Lists up all the milestones in this repository.
*/
public PagedIterable<GHMilestone> listMilestones(final GHIssueState state) {
return new PagedIterable<GHMilestone>() {
public PagedIterator<GHMilestone> _iterator(int pageSize) {
return new PagedIterator<GHMilestone>(root.retrieve().with("state",state).asIterator(getApiTailUrl("milestones"), GHMilestone[].class, pageSize)) {
@Override
protected void wrapUp(GHMilestone[] page) {
for (GHMilestone c : page)
c.wrap(GHRepository.this);
}
};
}
};
return root.retrieve().with("state",state)
.asPagedIterable(
getApiTailUrl("milestones"),
GHMilestone[].class,
item -> item.wrap(GHRepository.this) );
}
public GHMilestone getMilestone(int number) throws IOException {
@@ -1545,17 +1600,11 @@ public class GHRepository extends GHObject {
}
public PagedIterable<Contributor> listContributors() throws IOException {
return new PagedIterable<Contributor>() {
public PagedIterator<Contributor> _iterator(int pageSize) {
return new PagedIterator<Contributor>(root.retrieve().asIterator(getApiTailUrl("contributors"), Contributor[].class, pageSize)) {
@Override
protected void wrapUp(Contributor[] page) {
for (Contributor c : page)
c.wrapUp(root);
}
};
}
};
return root.retrieve()
.asPagedIterable(
getApiTailUrl("contributors"),
Contributor[].class,
item -> item.wrapUp(root) );
}
public static class Contributor extends GHUser {
@@ -1578,6 +1627,46 @@ public class GHRepository extends GHObject {
}
}
/**
* Returns the statistics for this repository.
*/
public GHRepositoryStatistics getStatistics() {
// TODO: Use static object and introduce refresh() method,
// instead of returning new object each time.
return new GHRepositoryStatistics(this);
}
/**
* Create a project for this repository.
*/
public GHProject createProject(String name, String body) throws IOException {
return root.retrieve().method("POST")
.withPreview(INERTIA)
.with("name", name)
.with("body", body)
.to(getApiTailUrl("projects"), GHProject.class).wrap(this);
}
/**
* Returns the projects for this repository.
* @param status The status filter (all, open or closed).
*/
public PagedIterable<GHProject> listProjects(final GHProject.ProjectStateFilter status) throws IOException {
return root.retrieve().withPreview(INERTIA)
.with("state", status)
.asPagedIterable(
getApiTailUrl("projects"),
GHProject[].class,
item -> item.wrap(GHRepository.this) );
}
/**
* Returns open projects for this repository.
*/
public PagedIterable<GHProject> listProjects() throws IOException {
return listProjects(GHProject.ProjectStateFilter.OPEN);
}
/**
* Render a Markdown document.
*
@@ -1636,4 +1725,48 @@ public class GHRepository extends GHObject {
if (tail.length()>0 && !tail.startsWith("/")) tail='/'+tail;
return "/repos/" + getOwnerName() + "/" + name +tail;
}
/**
* Get all issue events for this repository.
* See https://developer.github.com/v3/issues/events/#list-events-for-a-repository
*/
public PagedIterable<GHIssueEvent> listIssueEvents() throws IOException {
return root.retrieve().asPagedIterable(
getApiTailUrl("issues/events"),
GHIssueEvent[].class,
item -> item.wrapUp(root) );
}
/**
* Get a single issue event.
* See https://developer.github.com/v3/issues/events/#get-a-single-event
*/
public GHIssueEvent getIssueEvent(long id) throws IOException {
return root.retrieve().to(getApiTailUrl("issues/events/" + id), GHIssueEvent.class).wrapUp(root);
}
// Only used within listTopics().
private static class Topics {
public List<String> names;
}
/**
* Return the topics for this repository.
* See https://developer.github.com/v3/repos/#list-all-topics-for-a-repository
*/
public List<String> listTopics() throws IOException {
Topics topics = root.retrieve().withPreview(MERCY).to(getApiTailUrl("topics"), Topics.class);
return topics.names;
}
/**
* Set the topics for this repository.
* See https://developer.github.com/v3/repos/#replace-all-topics-for-a-repository
*/
// This currently returns a "404" error (as of 30 Oct 2019).
// 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"));
// }
}

View File

@@ -0,0 +1,22 @@
package org.kohsuke.github;
import java.util.Locale;
/**
* App installation repository selection.
*
* @author Paulo Miguel Almeida
*
* @see GHAppInstallation
*/
public enum GHRepositorySelection {
SELECTED,
ALL;
/**
* Returns GitHub's internal representation of this event.
*/
String symbol() {
return name().toLowerCase(Locale.ENGLISH);
}
}

View File

@@ -0,0 +1,433 @@
package org.kohsuke.github;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
/**
* Statistics for a GitHub repository.
*
* @author Martin van Zijl
*/
public class GHRepositoryStatistics {
private final GHRepository repo;
private final GitHub root;
private static final int MAX_WAIT_ITERATIONS = 3;
private static final int WAIT_SLEEP_INTERVAL = 5000;
public GHRepositoryStatistics(GHRepository repo) {
this.repo = repo;
this.root = repo.root;
}
/**
* Get contributors list with additions, deletions, and commit count. See
* https://developer.github.com/v3/repos/statistics/#get-contributors-list-with-additions-deletions-and-commit-counts
*/
public PagedIterable<ContributorStats> getContributorStats() throws IOException, InterruptedException {
return getContributorStats(true);
}
/**
* @param waitTillReady Whether to sleep the thread if necessary until the
* statistics are ready. This is true by default.
*/
@Preview
@Deprecated
@SuppressWarnings("SleepWhileInLoop")
@SuppressFBWarnings(value = {"RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"}, justification = "JSON API")
public PagedIterable<ContributorStats> getContributorStats(boolean waitTillReady) throws IOException, InterruptedException {
PagedIterable<GHRepositoryStatistics.ContributorStats> stats =
getContributorStatsImpl();
if (stats == null && waitTillReady) {
for (int i = 0; i < MAX_WAIT_ITERATIONS; i += 1) {
// Wait a few seconds and try again.
Thread.sleep(WAIT_SLEEP_INTERVAL);
stats = getContributorStatsImpl();
if (stats != null) {
break;
}
}
}
return stats;
}
/**
* 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) );
}
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD", "URF_UNREAD_FIELD"}, justification = "JSON API")
public static class ContributorStats extends GHObject {
/*package almost final*/ private GitHub root;
private GHUser author;
private int total;
private List<Week> weeks;
@Override
public URL getHtmlUrl() throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
public GitHub getRoot() {
return root;
}
/**
* @return The author described by these statistics.
*/
public GHUser getAuthor() {
return author;
}
/**
* @return The total number of commits authored by the contributor.
*/
public int getTotal() {
return total;
}
/**
* Convenience method to look up week with particular timestamp.
*
* @param timestamp The timestamp to look for.
* @return The week starting with the given timestamp. Throws an
* exception if it is not found.
* @throws NoSuchElementException
*/
public Week getWeek(long timestamp) throws NoSuchElementException {
// maybe store the weeks in a map to make this more efficient?
for (Week week : weeks) {
if (week.getWeekTimestamp() == timestamp) {
return week;
}
}
// this is safer than returning null
throw new NoSuchElementException();
}
/**
* @return The total number of commits authored by the contributor.
*/
public List<Week> getWeeks() {
return weeks;
}
@Override
public String toString() {
return author.getLogin() + " made " + String.valueOf(total)
+ " contributions over " + String.valueOf(weeks.size())
+ " weeks";
}
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD", "URF_UNREAD_FIELD"}, justification = "JSON API")
public static class Week {
private long w;
private int a;
private int d;
private int c;
/**
* @return Start of the week, as a UNIX timestamp.
*/
public long getWeekTimestamp() {
return w;
}
/**
* @return The number of additions for the week.
*/
public int getNumberOfAdditions() {
return a;
}
/**
* @return The number of deletions for the week.
*/
public int getNumberOfDeletions() {
return d;
}
/**
* @return The number of commits for the week.
*/
public int getNumberOfCommits() {
return c;
}
@Override
public String toString() {
return String.format("Week starting %d - Additions: %d, Deletions: %d, Commits: %d", w, a, d, c);
}
}
/*package*/ ContributorStats wrapUp(GitHub root) {
this.root = root;
return this;
}
}
/**
* Get the last year of commit activity data. See
* https://developer.github.com/v3/repos/statistics/#get-the-last-year-of-commit-activity-data
*/
public PagedIterable<CommitActivity> getCommitActivity() throws IOException {
return root.retrieve()
.asPagedIterable(
getApiTailUrl("commit_activity"),
CommitActivity[].class,
item -> item.wrapUp(root) );
}
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public static class CommitActivity extends GHObject {
/*package almost final*/ private GitHub root;
private List<Integer> days;
private int total;
private long week;
/**
* @return The number of commits for each day of the week. 0 = Sunday, 1
* = Monday, etc.
*/
public List<Integer> getDays() {
return days;
}
/**
* @return The total number of commits for the week.
*/
public int getTotal() {
return total;
}
/**
* @return The start of the week as a UNIX timestamp.
*/
public long getWeek() {
return week;
}
/*package*/ CommitActivity wrapUp(GitHub root) {
this.root = root;
return this;
}
public GitHub getRoot() {
return root;
}
@Override
public URL getHtmlUrl() throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
}
/**
* Get the number of additions and deletions per week.
* See https://developer.github.com/v3/repos/statistics/#get-the-number-of-additions-and-deletions-per-week
*/
public List<CodeFrequency> getCodeFrequency() throws IOException {
// Map to ArrayLists first, since there are no field names in the
// returned JSON.
try {
InputStream stream = root.retrieve().asStream(getApiTailUrl("code_frequency"));
ObjectMapper mapper = new ObjectMapper();
TypeReference<ArrayList<ArrayList<Integer> > > typeRef =
new TypeReference<ArrayList< ArrayList<Integer> > >() {};
ArrayList<ArrayList <Integer> > list = mapper.readValue(stream, typeRef);
// Convert to proper objects.
ArrayList<CodeFrequency> returnList = new ArrayList<CodeFrequency>();
for(ArrayList<Integer> item: list)
{
CodeFrequency cf = new CodeFrequency(item);
returnList.add(cf);
}
return returnList;
} catch (MismatchedInputException e) {
// This sometimes happens when retrieving code frequency statistics
// for a repository for the first time. It is probably still being
// generated, so return null.
return null;
}
}
public static class CodeFrequency {
private int week;
private int additions;
private int deletions;
private CodeFrequency(ArrayList<Integer> item) {
week = item.get(0);
additions = item.get(1);
deletions = item.get(2);
}
/**
* @return The start of the week as a UNIX timestamp.
*/
public int getWeekTimestamp() {
return week;
}
/**
* @return The number of additions for the week.
*/
public long getAdditions() {
return additions;
}
/**
* @return The number of deletions for the week.
* NOTE: This will be a NEGATIVE number.
*/
public long getDeletions() {
// TODO: Perhaps return Math.abs(deletions),
// since most developers may not expect a negative number.
return deletions;
}
@Override
public String toString() {
return "Week starting " + getWeekTimestamp() + " has " + getAdditions() +
" additions and " + Math.abs(getDeletions()) + " deletions";
}
}
/**
* Get the weekly commit count for the repository owner and everyone else.
* See https://developer.github.com/v3/repos/statistics/#get-the-weekly-commit-count-for-the-repository-owner-and-everyone-else
*/
public Participation getParticipation() throws IOException {
return root.retrieve().to(getApiTailUrl("participation"), Participation.class);
}
public static class Participation extends GHObject {
/*package almost final*/ private GitHub root;
private List<Integer> all;
private List<Integer> owner;
@Override
public URL getHtmlUrl() throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
public GitHub getRoot() {
return root;
}
/**
* @return The list of commit counts for everyone combined, for the
* last 52 weeks.
*/
public List<Integer> getAllCommits() {
return all;
}
/**
* @return The list of commit counts for the owner, for the
* last 52 weeks.
*/
public List<Integer> getOwnerCommits() {
return owner;
}
/*package*/ Participation wrapUp(GitHub root) {
this.root = root;
return this;
}
}
/**
* Get the number of commits per hour in each day.
* See https://developer.github.com/v3/repos/statistics/#get-the-number-of-commits-per-hour-in-each-day
*/
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"));
ObjectMapper mapper = new ObjectMapper();
TypeReference<ArrayList<ArrayList<Integer> > > typeRef =
new TypeReference<ArrayList< ArrayList<Integer> > >() {};
ArrayList<ArrayList <Integer> > list = mapper.readValue(stream, typeRef);
// Convert to proper objects.
ArrayList<PunchCardItem> returnList = new ArrayList<PunchCardItem>();
for(ArrayList<Integer> item: list) {
PunchCardItem pci = new PunchCardItem(item);
returnList.add(pci);
}
return returnList;
}
public static class PunchCardItem {
private int dayOfWeek;
private int hourOfDay;
private int numberOfCommits;
private PunchCardItem(ArrayList<Integer> item) {
dayOfWeek = item.get(0);
hourOfDay = item.get(1);
numberOfCommits = item.get(2);
}
/**
* @return The day of the week.
* 0 = Sunday, 1 = Monday, etc.
*/
public int getDayOfWeek() {
return dayOfWeek;
}
/**
* @return The hour of the day from 0 to 23.
*/
public long getHourOfDay() {
return hourOfDay;
}
/**
* @return The number of commits for the day and hour.
*/
public long getNumberOfCommits() {
return numberOfCommits;
}
public String toString() {
return "Day " + getDayOfWeek() + " Hour " + getHourOfDay() + ": " +
getNumberOfCommits() + " commits";
}
}
String getApiTailUrl(String tail) {
return repo.getApiTailUrl("stats/" + tail);
}
}

View File

@@ -49,7 +49,7 @@ public class GHSubscription {
* Removes this subscription.
*/
public void delete() throws IOException {
new Requester(root).method("DELETE").to(url);
new Requester(root).method("DELETE").to(repo.getApiTailUrl("subscription"));
}
GHSubscription wrapUp(GHRepository repo) {

View File

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

View File

@@ -11,12 +11,12 @@ import java.util.TreeMap;
*
* @author Kohsuke Kawaguchi
*/
public class GHTeam {
private String name,permission,slug;
public class GHTeam implements Refreshable {
private String name,permission,slug,description;
private int id;
private GHOrganization organization; // populated by GET /user/teams where Teams+Orgs are returned together
protected /*final*/ GHOrganization org;
protected /*final*/ GitHub root;
/** Member's role in a team */
public enum Role {
@@ -31,7 +31,8 @@ public class GHTeam {
}
/*package*/ GHTeam wrapUp(GHOrganization owner) {
this.org = owner;
this.organization = owner;
this.root = owner.root;
return this;
}
@@ -47,6 +48,13 @@ public class GHTeam {
return teams;
}
/*package*/ static GHTeam[] wrapUp(GHTeam[] teams, GHPullRequest owner) {
for (GHTeam t : teams) {
t.root = owner.root;
}
return teams;
}
public String getName() {
return name;
}
@@ -59,6 +67,16 @@ public class GHTeam {
return slug;
}
public String getDescription() {
return description;
}
public void setDescription(String description) throws IOException {
root.retrieve().method("PATCH")
.with("description", description)
.to(api(""));
}
public int getId() {
return id;
}
@@ -67,16 +85,11 @@ public class GHTeam {
* Retrieves the current members.
*/
public PagedIterable<GHUser> listMembers() throws IOException {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> _iterator(int pageSize) {
return new PagedIterator<GHUser>(org.root.retrieve().asIterator(api("/members"), GHUser[].class, pageSize)) {
@Override
protected void wrapUp(GHUser[] page) {
GHUser.wrap(page, org.root);
}
};
}
};
return root.retrieve()
.asPagedIterable(
api("/members"),
GHUser[].class,
item -> item.wrapUp(root) );
}
public Set<GHUser> getMembers() throws IOException {
@@ -88,7 +101,7 @@ public class GHTeam {
*/
public boolean hasMember(GHUser user) {
try {
org.root.retrieve().to("/teams/" + id + "/members/" + user.getLogin());
root.retrieve().to("/teams/" + id + "/members/" + user.getLogin());
return true;
} catch (IOException ignore) {
return false;
@@ -104,17 +117,11 @@ public class GHTeam {
}
public PagedIterable<GHRepository> listRepositories() {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(org.root.retrieve().asIterator(api("/repos"), GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository r : page)
r.wrap(org.root);
}
};
}
};
return root.retrieve()
.asPagedIterable(
api("/repos"),
GHRepository[].class,
item -> item.wrap(root) );
}
/**
@@ -125,7 +132,7 @@ public class GHTeam {
* @since 1.59
*/
public void add(GHUser u) throws IOException {
org.root.retrieve().method("PUT").to(api("/memberships/" + u.getLogin()), null);
root.retrieve().method("PUT").to(api("/memberships/" + u.getLogin()), null);
}
/**
@@ -139,8 +146,8 @@ public class GHTeam {
* @throws IOException
*/
public void add(GHUser user, Role role) throws IOException {
org.root.retrieve().method("PUT")
.with("role", role.name())
root.retrieve().method("PUT")
.with("role", role)
.to(api("/memberships/" + user.getLogin()), null);
}
@@ -148,7 +155,7 @@ public class GHTeam {
* Removes a member to the team.
*/
public void remove(GHUser u) throws IOException {
org.root.retrieve().method("DELETE").to(api("/members/" + u.getLogin()), null);
root.retrieve().method("DELETE").to(api("/members/" + u.getLogin()), null);
}
public void add(GHRepository r) throws IOException {
@@ -156,27 +163,33 @@ public class GHTeam {
}
public void add(GHRepository r, GHOrganization.Permission permission) throws IOException {
org.root.retrieve().method("PUT")
root.retrieve().method("PUT")
.with("permission", permission)
.to(api("/repos/" + r.getOwnerName() + '/' + r.getName()), null);
}
public void remove(GHRepository r) throws IOException {
org.root.retrieve().method("DELETE").to(api("/repos/" + r.getOwnerName() + '/' + r.getName()), null);
root.retrieve().method("DELETE").to(api("/repos/" + r.getOwnerName() + '/' + r.getName()), null);
}
/**
* Deletes this team.
*/
public void delete() throws IOException {
org.root.retrieve().method("DELETE").to(api(""));
root.retrieve().method("DELETE").to(api(""));
}
private String api(String tail) {
return "/teams/" + id + tail;
}
public GHOrganization getOrganization() {
return org;
public GHOrganization getOrganization() throws IOException {
refresh(organization);
return organization;
}
@Override
public void refresh() throws IOException {
root.retrieve().to(api(""), this).wrapUp(root);
}
}

View File

@@ -26,8 +26,7 @@ package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.*;
/**
* Represents an user of GitHub.
@@ -36,6 +35,10 @@ import java.util.Set;
*/
public class GHUser extends GHPerson {
public List<GHKey> getKeys() throws IOException {
return Collections.unmodifiableList(Arrays.asList(root.retrieve().to(getApiTailUrl("keys"), GHKey[].class)));
}
/**
* Follow this user.
*/
@@ -81,15 +84,11 @@ public class GHUser extends GHPerson {
}
private PagedIterable<GHUser> listUser(final String suffix) {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> _iterator(int pageSize) {
return new PagedIterator<GHUser>(root.retrieve().asIterator(getApiTailUrl(suffix), GHUser[].class, pageSize)) {
protected void wrapUp(GHUser[] page) {
GHUser.wrap(page,root);
}
};
}
};
return root.retrieve()
.asPagedIterable(
getApiTailUrl(suffix),
GHUser[].class,
item -> item.wrapUp(root) );
}
/**
@@ -109,16 +108,11 @@ public class GHUser extends GHPerson {
}
private PagedIterable<GHRepository> listRepositories(final String suffix) {
return new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(root.retrieve().asIterator(getApiTailUrl(suffix), GHRepository[].class, pageSize)) {
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
c.wrap(root);
}
};
}
};
return root.retrieve()
.asPagedIterable(
getApiTailUrl(suffix),
GHRepository[].class,
item -> item.wrap(root) );
}
/**
@@ -166,34 +160,22 @@ 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 new PagedIterable<GHEventInfo>() {
public PagedIterator<GHEventInfo> _iterator(int pageSize) {
return new PagedIterator<GHEventInfo>(root.retrieve().asIterator(String.format("/users/%s/events", login), GHEventInfo[].class, pageSize)) {
@Override
protected void wrapUp(GHEventInfo[] page) {
for (GHEventInfo c : page)
c.wrapUp(root);
}
};
}
};
return root.retrieve()
.asPagedIterable(
String.format("/users/%s/events", login),
GHEventInfo[].class,
item -> item.wrapUp(root) );
}
/**
* Lists Gists created by this user.
*/
public PagedIterable<GHGist> listGists() throws IOException {
return new PagedIterable<GHGist>() {
public PagedIterator<GHGist> _iterator(int pageSize) {
return new PagedIterator<GHGist>(root.retrieve().asIterator(String.format("/users/%s/gists", login), GHGist[].class, pageSize)) {
@Override
protected void wrapUp(GHGist[] page) {
for (GHGist c : page)
c.wrapUp(GHUser.this);
}
};
}
};
return root.retrieve()
.asPagedIterable(
String.format("/users/%s/gists", login),
GHGist[].class,
item -> item.wrapUp(GHUser.this) );
}
@Override

View File

@@ -34,33 +34,23 @@ import org.apache.commons.io.IOUtils;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Logger;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.*;
import static java.net.HttpURLConnection.*;
import static java.util.logging.Level.*;
import static org.kohsuke.github.Previews.*;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
import static java.util.logging.Level.FINE;
import static org.kohsuke.github.Previews.INERTIA;
import static org.kohsuke.github.Previews.MACHINE_MAN;
/**
* Root of the GitHub API.
@@ -104,7 +94,7 @@ public class GitHub {
* to represent different ways of authentication.
*
* <dl>
* <dt>Loging anonymously
* <dt>Log in anonymously
* <dd>Leave all three parameters null and you will be making HTTP requests without any authentication.
*
* <dt>Log in with password
@@ -115,15 +105,21 @@ public class GitHub {
* <dd>Specify oauthAccessToken, and optionally specify the login. Leave password null.
* This will send OAuth token to the GitHub API. If the login parameter is null,
* The constructor makes an API call to figure out the user name that owns the token.
*
* <dt>Log in with JWT token
* <dd>Specify jwtToken. Leave password null.
* This will send JWT token to the GitHub API via the Authorization HTTP header.
* Please note that only operations in which permissions have been previously configured and accepted during
* the GitHub App will be executed successfully.
* </dl>
*
* @param apiUrl
* The URL of GitHub (or GitHub enterprise) API endpoint, such as "https://api.github.com" or
* "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has <tt>/api/v3</tt> in the URL.
* "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has <code>/api/v3</code> in the URL.
* For historical reasons, this parameter still accepts the bare domain name, but that's considered deprecated.
* Password is also considered deprecated as it is no longer required for api usage.
* @param login
* The use ID on GitHub that you are logging in as. Can be omitted if the OAuth token is
* The user ID on GitHub that you are logging in as. Can be omitted if the OAuth token is
* provided or if logging in anonymously. Specifying this would save one API call.
* @param oauthAccessToken
* Secret OAuth token.
@@ -132,7 +128,7 @@ public class GitHub {
* @param connector
* HttpConnector to use. Pass null to use default connector.
*/
/* package */ GitHub(String apiUrl, String login, String oauthAccessToken, String password, HttpConnector connector, RateLimitHandler rateLimitHandler, AbuseLimitHandler abuseLimitHandler) throws IOException {
/* package */ GitHub(String apiUrl, String login, String oauthAccessToken, String jwtToken, String password, HttpConnector connector, RateLimitHandler rateLimitHandler, AbuseLimitHandler abuseLimitHandler) throws IOException {
if (apiUrl.endsWith("/")) apiUrl = apiUrl.substring(0, apiUrl.length()-1); // normalize
this.apiUrl = apiUrl;
if (null != connector) this.connector = connector;
@@ -140,7 +136,9 @@ public class GitHub {
if (oauthAccessToken!=null) {
encodedAuthorization = "token "+oauthAccessToken;
} else {
if (password!=null) {
if(jwtToken!=null){
encodedAuthorization = "Bearer "+jwtToken;
}else if (password!=null) {
String authorization = (login + ':' + password);
String charsetName = Charsets.UTF_8.name();
encodedAuthorization = "Basic "+new String(Base64.encodeBase64(authorization.getBytes(charsetName)), charsetName);
@@ -154,7 +152,7 @@ public class GitHub {
this.rateLimitHandler = rateLimitHandler;
this.abuseLimitHandler = abuseLimitHandler;
if (login==null && encodedAuthorization!=null)
if (login==null && encodedAuthorization!=null && jwtToken == null)
login = getMyself().getLogin();
this.login = login;
}
@@ -172,6 +170,7 @@ public class GitHub {
* @deprecated
* Use {@link #connectToEnterpriseWithOAuth(String, String, String)}
*/
@Deprecated
public static GitHub connectToEnterprise(String apiUrl, String oauthAccessToken) throws IOException {
return connectToEnterpriseWithOAuth(apiUrl,null,oauthAccessToken);
}
@@ -180,8 +179,8 @@ public class GitHub {
* Version that connects to GitHub Enterprise.
*
* @param apiUrl
* The URL of GitHub (or GitHub enterprise) API endpoint, such as "https://api.github.com" or
* "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has <tt>/api/v3</tt> in the URL.
* The URL of GitHub (or GitHub Enterprise) API endpoint, such as "https://api.github.com" or
* "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has <code>/api/v3</code> in the URL.
* For historical reasons, this parameter still accepts the bare domain name, but that's considered deprecated.
*/
public static GitHub connectToEnterpriseWithOAuth(String apiUrl, String login, String oauthAccessToken) throws IOException {
@@ -194,6 +193,7 @@ public class GitHub {
* @deprecated
* Use with caution. Login with password is not a preferred method.
*/
@Deprecated
public static GitHub connectToEnterprise(String apiUrl, String login, String password) throws IOException {
return new GitHubBuilder().withEndpoint(apiUrl).withPassword(login, password).build();
}
@@ -207,6 +207,7 @@ public class GitHub {
* Either OAuth token or password is sufficient, so there's no point in passing both.
* Use {@link #connectUsingPassword(String, String)} or {@link #connectUsingOAuth(String)}.
*/
@Deprecated
public static GitHub connect(String login, String oauthAccessToken, String password) throws IOException {
return new GitHubBuilder().withOAuthToken(oauthAccessToken, login).withPassword(login, password).build();
}
@@ -225,7 +226,7 @@ public class GitHub {
/**
* Connects to GitHub anonymously.
*
* All operations that requires authentication will fail.
* All operations that require authentication will fail.
*/
public static GitHub connectAnonymously() throws IOException {
return new GitHubBuilder().build();
@@ -234,7 +235,7 @@ public class GitHub {
/**
* Connects to GitHub Enterprise anonymously.
*
* All operations that requires authentication will fail.
* All operations that require authentication will fail.
*/
public static GitHub connectToEnterpriseAnonymously(String apiUrl) throws IOException {
return new GitHubBuilder().withEndpoint(apiUrl).build();
@@ -380,7 +381,7 @@ public class GitHub {
requireCredential();
synchronized (this) {
if (this.myself != null) return myself;
GHMyself u = retrieve().to("/user", GHMyself.class);
u.root = this;
@@ -402,9 +403,9 @@ public class GitHub {
return u;
}
/**
* clears all cached data in order for external changes (modifications and del
* clears all cached data in order for external changes (modifications and del) to be reflected
*/
public void refreshCache() {
users.clear();
@@ -449,20 +450,12 @@ 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 new PagedIterable<GHOrganization>() {
@Override
public PagedIterator<GHOrganization> _iterator(int pageSize) {
System.out.println("page size: " + pageSize);
return new PagedIterator<GHOrganization>(retrieve().with("since",since)
.asIterator("/organizations", GHOrganization[].class, pageSize)) {
@Override
protected void wrapUp(GHOrganization[] page) {
for (GHOrganization c : page)
c.wrapUp(GitHub.this);
}
};
}
};
return retrieve()
.with("since",since)
.asPagedIterable(
"/organizations",
GHOrganization[].class,
item -> item.wrapUp(GitHub.this) );
}
/**
@@ -474,59 +467,49 @@ public class GitHub {
String[] tokens = name.split("/");
return retrieve().to("/repos/" + tokens[0] + '/' + tokens[1], GHRepository.class).wrap(this);
}
/**
* Gets the repository object from its ID
*/
public GHRepository getRepositoryById(String id) throws IOException {
return retrieve().to("/repositories/" + id, GHRepository.class).wrap(this);
}
/**
* Returns a list of popular open source licenses
*
* WARNING: This uses a PREVIEW API.
*
* @see <a href="https://developer.github.com/v3/licenses/">GitHub API - Licenses</a>
*
* @return a list of popular open source licenses
*/
@Preview @Deprecated
public PagedIterable<GHLicense> listLicenses() throws IOException {
return new PagedIterable<GHLicense>() {
public PagedIterator<GHLicense> _iterator(int pageSize) {
return new PagedIterator<GHLicense>(retrieve().withPreview(DRAX).asIterator("/licenses", GHLicense[].class, pageSize)) {
@Override
protected void wrapUp(GHLicense[] page) {
for (GHLicense c : page)
c.wrap(GitHub.this);
}
};
}
};
return retrieve()
.asPagedIterable(
"/licenses",
GHLicense[].class,
item -> item.wrap(GitHub.this) );
}
/**
* Returns a list of all users.
*/
public PagedIterable<GHUser> listUsers() throws IOException {
return new PagedIterable<GHUser>() {
public PagedIterator<GHUser> _iterator(int pageSize) {
return new PagedIterator<GHUser>(retrieve().asIterator("/users", GHUser[].class, pageSize)) {
@Override
protected void wrapUp(GHUser[] page) {
for (GHUser u : page)
u.wrapUp(GitHub.this);
}
};
}
};
return retrieve()
.asPagedIterable(
"/users",
GHUser[].class,
item -> item.wrapUp(GitHub.this) );
}
/**
* Returns the full details for a license
*
* WARNING: This uses a PREVIEW API.
*
* @param key The license key provided from the API
* @return The license details
* @see GHLicense#getKey()
*/
@Preview @Deprecated
public GHLicense getLicense(String key) throws IOException {
return retrieve().withPreview(DRAX).to("/licenses/" + key, GHLicense.class);
return retrieve().to("/licenses/" + key, GHLicense.class);
}
/**
@@ -541,7 +524,7 @@ public class GitHub {
}
/**
* This method returns a shallowly populated organizations.
* This method returns shallowly populated organizations.
*
* To retrieve full organization details, you need to call {@link #getOrganization(String)}
* TODO: make this automatic.
@@ -555,6 +538,32 @@ public class GitHub {
}
return r;
}
/**
* Alias for {@link #getUserPublicOrganizations(String)}.
*/
public Map<String, GHOrganization> getUserPublicOrganizations(GHUser user) throws IOException {
return getUserPublicOrganizations( user.getLogin() );
}
/**
* This method returns a shallowly populated organizations.
*
* To retrieve full organization details, you need to call {@link #getOrganization(String)}
*
* @param login the user to retrieve public Organization membership information for
*
* @return the public Organization memberships for the user
*/
public Map<String, GHOrganization> getUserPublicOrganizations(String login) throws IOException {
GHOrganization[] orgs = retrieve().to("/users/" + login + "/orgs", GHOrganization[].class);
Map<String, GHOrganization> r = new HashMap<String, GHOrganization>();
for (GHOrganization o : orgs) {
// don't put 'o' into orgs because they are shallow
r.put(o.getLogin(),o.wrapUp(this));
}
return r;
}
/**
* Gets complete map of organizations/teams that current user belongs to.
@@ -578,6 +587,13 @@ public class GitHub {
return allMyTeams;
}
/**
* Gets a sigle team by ID.
*/
public GHTeam getTeam(int id) throws IOException {
return retrieve().to("/teams/" + id, GHTeam.class).wrapUp(this);
}
/**
* Public events visible to you. Equivalent of what's displayed on https://github.com/
*/
@@ -589,7 +605,7 @@ public class GitHub {
}
/**
* Gets a sigle gist by ID.
* Gets a single gist by ID.
*/
public GHGist getGist(String id) throws IOException {
return retrieve().to("/gists/"+id,GHGist.class).wrapUp(this);
@@ -620,6 +636,7 @@ public class GitHub {
* @deprecated
* Use {@link #createRepository(String)} that uses a builder pattern to let you control every aspect.
*/
@Deprecated
public GHRepository createRepository(String name, String description, String homepage, boolean isPublic) throws IOException {
return createRepository(name).description(description).homepage(homepage).private_(!isPublic).create();
}
@@ -629,7 +646,7 @@ public class GitHub {
*
* <p>
* You use the returned builder to set various properties, then call {@link GHCreateRepositoryBuilder#create()}
* to finally createa repository.
* to finally create a repository.
*
* <p>
* To create a repository in an organization, see
@@ -691,10 +708,34 @@ public class GitHub {
return retrieve().method("POST").to("/applications/" + clientId + "/tokens/" + accessToken, GHAuthorization.class);
}
/**
* Returns a list of all authorizations.
* @see <a href="https://developer.github.com/v3/oauth_authorizations/#list-your-authorizations">List your authorizations</a>
*/
public PagedIterable<GHAuthorization> listMyAuthorizations() throws IOException {
return retrieve()
.asPagedIterable(
"/authorizations",
GHAuthorization[].class,
item -> item.wrap(GitHub.this) );
}
/**
* Returns the GitHub App associated with the authentication credentials used.
*
* You must use a JWT to access this endpoint.
*
* @see <a href="https://developer.github.com/v3/apps/#get-the-authenticated-github-app">Get the authenticated GitHub App</a>
*/
@Preview @Deprecated
public GHApp getApp() throws IOException {
return retrieve().withPreview(MACHINE_MAN).to("/app", GHApp.class).wrapUp(this);
}
/**
* Ensures that the credential is valid.
*/
public boolean isCredentialValid() throws IOException {
public boolean isCredentialValid() {
try {
retrieve().to("/user", GHUser.class);
return true;
@@ -717,6 +758,18 @@ public class GitHub {
return user;
}
public GHProject getProject(long id) throws IOException {
return retrieve().withPreview(INERTIA).to("/projects/"+id, GHProject.class).wrap(this);
}
public GHProjectColumn getProjectColumn(long id) throws IOException {
return retrieve().withPreview(INERTIA).to("/projects/columns/"+id, GHProjectColumn.class).wrap(this);
}
public GHProjectCard getProjectCard(long id) throws IOException {
return retrieve().withPreview(INERTIA).to("/projects/columns/cards/"+id, GHProjectCard.class).wrap(this);
}
private static class GHApiInfo {
private String rate_limit_url;
@@ -854,17 +907,11 @@ 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 new PagedIterable<GHRepository>() {
public PagedIterator<GHRepository> _iterator(int pageSize) {
return new PagedIterator<GHRepository>(retrieve().with("since",since).asIterator("/repositories", GHRepository[].class, pageSize)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
c.wrap(GitHub.this);
}
};
}
};
return retrieve().with("since",since)
.asPagedIterable(
"/repositories",
GHRepository[].class,
item -> item.wrap(GitHub.this) );
}
/**
@@ -909,12 +956,18 @@ public class GitHub {
}
/*package*/ static String printDate(Date dt) {
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(dt);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
df.setTimeZone(TimeZone.getTimeZone("GMT"));
return df.format(dt);
}
/*package*/ static final ObjectMapper MAPPER = new ObjectMapper();
private static final String[] TIME_FORMATS = {"yyyy/MM/dd HH:mm:ss ZZZZ","yyyy-MM-dd'T'HH:mm:ss'Z'"};
private static final String[] TIME_FORMATS = {
"yyyy/MM/dd HH:mm:ss ZZZZ",
"yyyy-MM-dd'T'HH:mm:ss'Z'",
"yyyy-MM-dd'T'HH:mm:ss.S'Z'" // GitHub App endpoints return a different date format
};
static {
MAPPER.setVisibilityChecker(new Std(NONE, NONE, NONE, NONE, ANY));

View File

@@ -19,14 +19,15 @@ import java.util.Properties;
*
* @since 1.59
*/
public class GitHubBuilder {
public class GitHubBuilder implements Cloneable {
// default scoped so unit tests can read them.
/* private */ String endpoint = GitHub.GITHUB_URL;
/* private */ String user;
/* private */ String password;
/* private */ String oauthToken;
/* private */ String jwtToken;
private HttpConnector connector;
private RateLimitHandler rateLimitHandler = RateLimitHandler.WAIT;
@@ -36,36 +37,36 @@ public class GitHubBuilder {
}
/**
* First check if the credentials are configured using the ~/.github properties file.
*
* If no user is specified it means there is no configuration present so check the environment instead.
* First check if the credentials are configured in the environment.
* We use environment first because users are not likely to give required (full) permissions to their default key.
*
* If no user is specified it means there is no configuration present, so try using the ~/.github properties file.
**
* If there is still no user it means there are no credentials defined and throw an IOException.
*
* @return the configured Builder from credentials defined on the system or in the environment.
* @return the configured Builder from credentials defined on the system or in the environment. Otherwise returns null.
*
* @throws IOException If there are no credentials defined in the ~/.github properties file or the process environment.
*/
public static GitHubBuilder fromCredentials() throws IOException {
static GitHubBuilder fromCredentials() throws IOException {
Exception cause = null;
GitHubBuilder builder;
GitHubBuilder builder = null;
builder = fromEnvironment();
if (builder.oauthToken != null || builder.user != null || builder.jwtToken != null)
return builder;
try {
builder = fromPropertyFile();
if (builder.oauthToken != null || builder.user != null)
if (builder.oauthToken != null || builder.user != null || builder.jwtToken != null)
return builder;
} catch (FileNotFoundException e) {
// fall through
cause = e;
}
builder = fromEnvironment();
if (builder.oauthToken != null || builder.user != null)
return builder;
else
throw (IOException)new IOException("Failed to resolve credentials from ~/.github or the environment.").initCause(cause);
throw (IOException)new IOException("Failed to resolve credentials from ~/.github or the environment.").initCause(cause);
}
/**
@@ -108,6 +109,7 @@ public class GitHubBuilder {
* <li>GITHUB_PASSWORD: raw password
* <li>GITHUB_OAUTH: OAuth token to login
* <li>GITHUB_ENDPOINT: URL of the API endpoint
* <li>GITHUB_JWT: JWT token to login
* </ul>
*
* <p>
@@ -126,7 +128,7 @@ public class GitHubBuilder {
}
return fromProperties(props);
}
public static GitHubBuilder fromPropertyFile() throws IOException {
File homeDir = new File(System.getProperty("user.home"));
File propertyFile = new File(homeDir, ".github");
@@ -149,6 +151,7 @@ public class GitHubBuilder {
public static GitHubBuilder fromProperties(Properties props) {
GitHubBuilder self = new GitHubBuilder();
self.withOAuthToken(props.getProperty("oauth"), props.getProperty("login"));
self.withJwtToken(props.getProperty("jwt"));
self.withPassword(props.getProperty("login"), props.getProperty("password"));
self.withEndpoint(props.getProperty("endpoint", GitHub.GITHUB_URL));
return self;
@@ -157,7 +160,7 @@ public class GitHubBuilder {
/**
* @param endpoint
* The URL of GitHub (or GitHub enterprise) API endpoint, such as "https://api.github.com" or
* "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has <tt>/api/v3</tt> in the URL.
* "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has <code>/api/v3</code> in the URL.
* For historical reasons, this parameter still accepts the bare domain name, but that's considered deprecated.
*/
public GitHubBuilder withEndpoint(String endpoint) {
@@ -177,6 +180,22 @@ public class GitHubBuilder {
this.user = user;
return this;
}
/**
* Configures {@link GitHubBuilder} with Installation Token generated by the GitHub Application
*
* @param appInstallationToken A string containing the GitHub App installation token
* @return the configured Builder from given GitHub App installation token.
* @see GHAppInstallation#createToken(java.util.Map)
*/
public GitHubBuilder withAppInstallationToken(String appInstallationToken){
return withOAuthToken(appInstallationToken, "");
}
public GitHubBuilder withJwtToken(String jwtToken){
this.jwtToken = jwtToken;
return this;
}
public GitHubBuilder withConnector(HttpConnector connector) {
this.connector = connector;
return this;
@@ -204,6 +223,15 @@ public class GitHubBuilder {
}
public GitHub build() throws IOException {
return new GitHub(endpoint, user, oauthToken, password, connector, rateLimitHandler, abuseLimitHandler);
return new GitHub(endpoint, user, oauthToken, jwtToken, password, connector, rateLimitHandler, abuseLimitHandler);
}
@Override
public GitHubBuilder clone() {
try {
return (GitHubBuilder) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException("Clone should be supported", e);
}
}
}

View File

@@ -1,12 +1,81 @@
package org.kohsuke.github;
/**
* Provides the media type strings for GitHub API previews
*
* https://developer.github.com/v3/previews/
*
* @author Kohsuke Kawaguchi
*/
/*package*/ class Previews {
/**
* Commit Search
*
* @see <a href="https://developer.github.com/v3/previews/#commit-search">GitHub API Previews</a>
*/
static final String CLOAK = "application/vnd.github.cloak-preview+json";
/**
* Owners of GitHub Apps can now uninstall an app using the Apps API
*
* @see <a href="https://developer.github.com/v3/previews/#uninstall-a-github-app">GitHub API Previews</a>
*/
static final String GAMBIT = "application/vnd.github.gambit-preview+json";
/**
* Manage projects
*
* @see <a href="https://developer.github.com/v3/previews/#projects">GitHub API Previews</a>
*/
static final String INERTIA = "application/vnd.github.inertia-preview+json";
/**
* Require multiple approving reviews
*
* @see <a href="https://developer.github.com/v3/previews/#require-multiple-approving-reviews">GitHub API Previews</a>
*/
static final String LUKE_CAGE = "application/vnd.github.luke-cage-preview+json";
static final String DRAX = "application/vnd.github.drax-preview+json";
/**
* Manage integrations through the API
*
* @see <a href="https://developer.github.com/v3/previews/#integrations">GitHub API Previews</a>
*/
static final String MACHINE_MAN = "application/vnd.github.machine-man-preview+json";
/**
* View a list of repository topics in calls that return repository results
*
* @see <a href="https://developer.github.com/v3/previews/#repository-topics">GitHub API Previews</a>
*/
static final String MERCY = "application/vnd.github.mercy-preview+json";
/**
* Draft pull requests
*
* @see <a href="https://developer.github.com/v3/previews/#draft-pull-requests">GitHub API Previews</a>
*/
static final String SHADOW_CAT = "application/vnd.github.shadow-cat-preview+json";
/**
* Reactions
*
* @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";
static final String CLOAK = "application/vnd.github.cloak-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";
/**
* Require signed commits
*
* @see <a href="https://developer.github.com/v3/previews/#require-signed-commits">GitHub API Previews</a>
*/
static final String ZZZAX = "application/vnd.github.zzzax-preview+json";
}

View File

@@ -0,0 +1,30 @@
package org.kohsuke.github;
import org.kohsuke.github.extras.ImpatientHttpConnector;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
/**
*
*
*
* @author Liam Newman
*/
public interface Refreshable {
/**
* Opens a connection to the given URL.
*/
void refresh() throws IOException;
/**
* Calls refresh if the provided value is null
*/
default void refresh(Object value) throws IOException {
if (value == null) {
this.refresh();
}
}
}

View File

@@ -54,6 +54,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.function.Consumer;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -154,18 +155,14 @@ class Requester {
public Requester with(String key, Enum e) {
if (e==null) return _with(key, null);
// by convention Java constant names are upper cases, but github uses
// lower-case constants. GitHub also uses '-', which in Java we always
// replace by '_'
return with(key, e.toString().toLowerCase(Locale.ENGLISH).replace('_', '-'));
return with(key, transformEnum(e));
}
public Requester with(String key, String value) {
return _with(key, value);
}
public Requester with(String key, Collection<String> value) {
public Requester with(String key, Collection<?> value) {
return _with(key, value);
}
@@ -181,6 +178,14 @@ class Requester {
return _with(key, value);
}
public Requester withPermissions(String key, Map<String, GHPermissionType> value) {
Map<String,String> retMap = new HashMap<String, String>();
for (Map.Entry<String, GHPermissionType> entry : value.entrySet()) {
retMap.put(entry.getKey(), transformEnum(entry.getValue()));
}
return _with(key, retMap);
}
public Requester with(@WillClose/*later*/ InputStream body) {
this.body = body;
return this;
@@ -435,6 +440,40 @@ class Requester {
return forceBody || !METHODS_WITHOUT_BODY.contains(method);
}
/*package*/ <T> PagedIterable<T> asPagedIterable(String tailApiUrl, Class<T[]> type, Consumer<T> consumer) {
return new PagedIterableWithConsumer(type, this, tailApiUrl, consumer);
}
private static class PagedIterableWithConsumer<S> extends PagedIterable<S> {
private final Class<S[]> clazz;
private final Requester requester;
private final String tailApiUrl;
private final Consumer<S> consumer;
public PagedIterableWithConsumer(Class<S[]> clazz, Requester requester, String tailApiUrl, Consumer<S> 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) {
@Override
protected void wrapUp(S[] page) {
if (consumer != null) {
for (S item : page) {
consumer.accept(item);
}
}
}
};
}
}
/**
* Loads paginated resources.
*
@@ -526,7 +565,7 @@ class Requester {
}
}
} catch (IOException e) {
throw new GHException("Failed to retrieve "+url);
throw new GHException("Failed to retrieve " + url, e);
}
}
@@ -554,6 +593,9 @@ class Requester {
private void 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);
// if the authentication is needed but no credential is given, try it anyway (so that some calls
@@ -622,6 +664,14 @@ class Requester {
return type.cast(Array.newInstance(type.getComponentType(),0));
}
// Response code 202 means the statistics are still being cached.
// See https://developer.github.com/v3/repos/statistics/#a-word-about-caching
if (responseCode == 202) {
LOGGER.log(INFO, "The statistics are still being generated. Please try again in 5 seconds.");
// Maybe throw an exception instead?
return null;
}
r = new InputStreamReader(wrapStream(uc.getInputStream()), "UTF-8");
String data = IOUtils.toString(r);
if (type!=null)
@@ -726,6 +776,18 @@ class Requester {
throw e;
}
/**
* Transform Java Enum into Github constants given its conventions
* @param en - Enum to be transformed
* @return a String containing the value of a Github constant
*/
private String transformEnum(Enum en){
// by convention Java constant names are upper cases, but github uses
// lower-case constants. GitHub also uses '-', which in Java we always
// replace by '_'
return en.toString().toLowerCase(Locale.ENGLISH).replace('_', '-');
}
private static final List<String> METHODS_WITHOUT_BODY = asList("GET", "DELETE");
private static final Logger LOGGER = Logger.getLogger(Requester.class.getName());
}

View File

@@ -16,12 +16,18 @@ import java.net.URL;
* response does not count against the rate limit.
* See http://developer.github.com/v3/#conditional-requests
*
* @see org.kohsuke.github.extras.okhttp3.OkHttpConnector
* @author Roberto Tyley
* @author Kohsuke Kawaguchi
*/
@Deprecated
public class OkHttp3Connector implements HttpConnector {
private final OkUrlFactory urlFactory;
/*
* @see org.kohsuke.github.extras.okhttp3.OkHttpConnector
*/
@Deprecated
public OkHttp3Connector(OkUrlFactory urlFactory) {
this.urlFactory = urlFactory;
}

View File

@@ -1,5 +1,6 @@
package org.kohsuke.github.extras;
import com.squareup.okhttp.CacheControl;
import com.squareup.okhttp.ConnectionSpec;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.OkUrlFactory;
@@ -16,6 +17,7 @@ import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
@@ -32,16 +34,49 @@ import javax.net.ssl.SSLSocketFactory;
* @author Kohsuke Kawaguchi
*/
public class OkHttpConnector implements HttpConnector {
private static final String HEADER_NAME = "Cache-Control";
private final OkUrlFactory urlFactory;
private final String maxAgeHeaderValue;
public OkHttpConnector(OkUrlFactory urlFactory) {
this(urlFactory, 0);
}
/**
* package private for tests to be able to change max-age for cache.
* @param urlFactory
* @param cacheMaxAge
*/
OkHttpConnector(OkUrlFactory urlFactory, int cacheMaxAge) {
urlFactory.client().setSslSocketFactory(TlsSocketFactory());
urlFactory.client().setConnectionSpecs(TlsConnectionSpecs());
this.urlFactory = urlFactory;
if (cacheMaxAge >= 0 && urlFactory.client() != null && urlFactory.client().getCache() != null) {
maxAgeHeaderValue = new CacheControl.Builder()
.maxAge(cacheMaxAge, TimeUnit.SECONDS)
.build()
.toString();
} else {
maxAgeHeaderValue = null;
}
}
public HttpURLConnection connect(URL url) throws IOException {
return urlFactory.open(url);
HttpURLConnection urlConnection = urlFactory.open(url);
if (maxAgeHeaderValue != null) {
// By default OkHttp honors max-age, meaning it will use local cache
// without checking the network within that time frame.
// However, that can result in stale data being returned during that time so
// we force network-based checking no matter how often the query is made.
// OkHttp still automatically does ETag checking and returns cached data when
// GitHub reports 304, but those do not count against rate limit.
urlConnection.setRequestProperty(HEADER_NAME, maxAgeHeaderValue);
}
return urlConnection;
}
/** Returns TLSv1.2 only SSL Socket Factory. */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,77 @@
package org.kohsuke.github.extras.okhttp3;
import com.squareup.okhttp.CacheControl;
import okhttp3.ConnectionSpec;
import okhttp3.OkHttpClient;
import org.kohsuke.github.HttpConnector;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* {@link HttpConnector} for {@link OkHttpClient}.
*
* Unlike {@link #DEFAULT}, OkHttp does response caching.
* Making a conditional request against GitHubAPI and receiving a 304
* response does not count against the rate limit.
* See http://developer.github.com/v3/#conditional-requests
*
* @author Liam Newman
* @author Kohsuke Kawaguchi
*/
public class OkHttpConnector implements HttpConnector {
private static final String HEADER_NAME = "Cache-Control";
private final String maxAgeHeaderValue;
private final OkHttpClient client;
private final ObsoleteUrlFactory urlFactory;
public OkHttpConnector(OkHttpClient client) {
this(client, 0);
}
public OkHttpConnector(OkHttpClient client, int cacheMaxAge) {
OkHttpClient.Builder builder = client.newBuilder();
builder.connectionSpecs(TlsConnectionSpecs());
this.client = builder.build();
if (cacheMaxAge >= 0 && this.client != null && this.client.cache() != null) {
maxAgeHeaderValue = new CacheControl.Builder()
.maxAge(cacheMaxAge, TimeUnit.SECONDS)
.build()
.toString();
} else {
maxAgeHeaderValue = null;
}
this.urlFactory = new ObsoleteUrlFactory(this.client);
}
public HttpURLConnection connect(URL url) throws IOException {
HttpURLConnection urlConnection = urlFactory.open(url);
if (maxAgeHeaderValue != null) {
// By default OkHttp honors max-age, meaning it will use local cache
// without checking the network within that timeframe.
// However, that can result in stale data being returned during that time so
// we force network-based checking no matter how often the query is made.
// OkHttp still automatically does ETag checking and returns cached data when
// GitHub reports 304, but those do not count against rate limit.
urlConnection.setRequestProperty(HEADER_NAME, maxAgeHeaderValue);
}
return urlConnection;
}
/** Returns connection spec with TLS v1.2 in it */
private List<ConnectionSpec> TlsConnectionSpecs() {
return Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT);
}
}

View File

@@ -0,0 +1,28 @@
Authenticating as an installation
In order to authenticate to GitHub as an installation of your GitHub App, you must use the App Installation Token
authentication mechanism. This can be achieved with by creating a <<<GitHub>>> instance like this:
+-----+
GitHub githubAuthAsInst = new GitHubBuilder()
.withAppInstallationToken(appInstallationToken.getToken())
.build();
+-----+
How do I create an App Installation Token?
Assuming that you followed the {{{/githubappjwtauth.html} GitHub App Authentication via JWT token guide}} then you
can create the App Installation Token like this:
+-----+
String jwtToken = createJWT("44435", 600000); //sdk-github-api-app-test
GitHub gitHubApp = new GitHubBuilder().withJwtToken(jwtToken).build();
GHAppInstallation appInstallation = gitHubApp.getApp().getInstallationById(111111); // Installation Id
Map<String, GHPermissionType> permissions = new HashMap<>();
permissions.put("pull_requests", GHPermissionType.WRITE);
GHAppInstallationToken appInstallationToken = appInstallation
.createToken(permissions)
.create();
+-----+

View File

@@ -0,0 +1,41 @@
GitHub App Auth Flow
GitHub Apps are commonly mistaken for OAuth Apps due to their similarities but understanding the differences between
them will help you decide which kind of app you want to create.
In a nutshell, an OAuth App acts as a GitHub user, whereas a GitHub App uses its own identity when installed on an
organization or on repositories within an organization. For a comprehensive comparision please refer to the official
GitHub {{{https://developer.github.com/apps/differences-between-apps/}documentation}}.
For this guide, we are going assume that you are using a GitHub App.
Overview
Assuming that your GitHub app has already been installed on either a user or an organization, the programmatic flow
the developer must follow in order to be able to authenticate on their behalf is:
[images/GitHub_App_Auth_Flow.jpg] GitHub_App_Auth_Flow
Multiple <<<GitHub>>> instances will have to be created and each of them will be using a different authentication
mechanism. Some actions are only accessible if you are authenticated as a GitHub App while others will only be
possible if you are authenticated on behalf of a user or org.
Prerequisites
In order to follow this guide, you must have:
* A GitHub App created as described {{{https://developer.github.com/apps/building-github-apps/creating-a-github-app/}here}}
* A Private Key must be configured in your GitHub App as described {{{https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/#generating-a-private-key}here}}
* A User or an organisation that has already installed your GitHub App as described {{{https://developer.github.com/apps/installing-github-apps/}here}}
[]
What next?
* Authenticating as a GitHub App via the {{{/githubappjwtauth.html}JWT Authentication}}
* Authenticating as an installation via the {{{/githubappappinsttokenauth.html}App Installation Token}}
[]

View File

@@ -0,0 +1,135 @@
GitHub App Authentication via JWT token
In order to authenticate to GitHub as a GitHub App, you must use the JWT token authentication mechanism. This can be
easily achieved with this library by obtaining a <<<GitHub>>> instance like this:
+-----+
GitHub github = new GitHubBuilder().withJwtToken("my_jwt_token").build();
+-----+
Authenticating as a GitHub App lets you do a couple of things:
* You can retrieve high-level management information about your GitHub App.
* You can request access tokens for an installation of the app.
[]
Where do I get the JWT token from?
To generate the JWT token required to authenticate as a GitHub app you have to:
* Sign the JWT token using the private key you configured on your GitHub app as described {{{https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/#generating-a-private-key}here}}
* Encode it using the <<<RS256>>> algorithm.
[]
GitHub checks that the request is authenticated by verifying the token with the app's stored public key.
Converting the private key into a Java friendly format
<<Note:>> GitHub let's you download the GitHub App private key in the <<<PEM>>> format which isn't natively supported
by the JVM unless you leverage a third-party library such as {{{https://www.bouncycastle.org/}BouncyCastle}}. In this
guide we will convert it to <<<DER>>> using the <<<openssl>>> utility.
+-----+
openssl pkcs8 -topk8 -inform PEM -outform DER -in ~/github-api-app.private-key.pem -out ~/github-api-app.private-key.der -nocrypt
+-----+
How can I generate the JWT token?
Once you have the private key converted to the <<<DER>>> format, you will need 2 more things before you are able to
generate JWT tokens:
<<GitHub App Id:>>
You can obtain the GitHub App Id from your app settings webpage as shown below:
[images/Github_App_Id.png] Github_App_Id
<<JWT library:>>
In order to generate the JWT, you will have to likely use a JWT library.
In this guide we will use {{{https://github.com/jwtk/jjwt}jjwt}} to that matter.
Having said that, add on your <<<pom.xml>>> the following dependencies:
+-----+
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.10.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.10.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.10.5</version>
<scope>runtime</scope>
</dependency>
+-----+
Now we have everything we need so let's generate the JWT token:
+-----+
static PrivateKey get(String filename) throws Exception {
byte[] keyBytes = Files.toByteArray(new File(filename));
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}
static String createJWT(String githubAppId, long ttlMillis) throws Exception {
//The JWT signature algorithm we will be using to sign the token
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
//We will sign our JWT with our private key
Key signingKey = get("github-api-app.private-key.der");
//Let's set the JWT Claims
JwtBuilder builder = Jwts.builder()
.setIssuedAt(now)
.setIssuer(githubAppId)
.signWith(signingKey, signatureAlgorithm);
//if it has been specified, let's add the expiration
if (ttlMillis > 0) {
long expMillis = nowMillis + ttlMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp);
}
//Builds the JWT and serializes it to a compact, URL-safe string
return builder.compact();
}
public static void main(String[] args) throws Exception {
String jwtToken = createJWT("44435", 600000); //sdk-github-api-app-test
GitHub gitHubApp = new GitHubBuilder().withJwtToken(jwtToken).build();
}
+-----+
How do I get a specific app installation?
+-----+
String jwtToken = createJWT("44435", 600000); //sdk-github-api-app-test
GitHub gitHubApp = new GitHubBuilder().withJwtToken(jwtToken).build();
GHAppInstallation appInstallation = gitHubApp.getApp().getInstallationById(111111); // Installation Id
+-----+
What next?
* Authenticating as an installation via the {{{/githubappappinsttokenauth.html}App Installation Token}}
[]

154
src/site/apt/index.apt Normal file
View File

@@ -0,0 +1,154 @@
What is this?
This library defines an object oriented representation of the GitHub API. By "object oriented" we mean
there are classes that correspond to the domain model of GitHub (such as <<<GHUser>>> and <<<GHRepository>>>),
operations that act on them as defined as methods (such as <<<GHUser.follow()>>>), and those object references
are used in favor of using string handle (such as <<<GHUser.isMemberOf(GHOrganization)>>> instead of
<<<GHUser.isMemberOf(String)>>>)
The library supports both github.com and GitHub Enterprise.
Most of the GitHub APIs are covered, although there are some corners that are still not yet implemented.
Sample Usage
+-----+
GitHub github = GitHub.connect();
GHRepository repo = github.createRepository(
"new-repository","this is my new repository",
"http://www.kohsuke.org/",true/*public*/);
repo.addCollaborators(github.getUser("abayer"),github.getUser("rtyler"));
repo.delete();
+-----+
Authentication
The library allows connecting to GitHub via several different authentication mechanisms.
* Programmatically
To connect via Username and Password (not recommended):
+-----+
GitHub github = new GitHubBuilder().withPassword("my_user", "my_passwd").build();
+-----+
To connect via Personal access token:
+-----+
// If you don't specify the GitHub user id then the sdk will retrieve it via /user endpoint
GitHub github = new GitHubBuilder().withOAuthToken("my_personal_token").build();
// If the token has access to an organization, you can specify it here.
GitHub github = new GitHubBuilder().withOAuthToken("my_personal_token","user_id_OR_org_name").build();
+-----+
To connect via JWT token as a GitHub App:
+-----+
GitHub github = new GitHubBuilder().withJwtToken("my_jwt_token").build();
+-----+
To connect via GitHub App installation token on behalf of a user or organization:
+-----+
GitHub github = new GitHubBuilder().withAppInstallationToken("my_installation_token").build();
+-----+
* Property file
This library defines a common convention so that applications using this library will look at a consistent location.
In this convention, the library looks at <<<~/.github>>> property file. The content of the files depends on the way
you want this library to authenticate as shown below:
To connect via Username and Password (not recommended):
+-----+
login=kohsuke
password=012345678
+-----+
To connect via Personal access token:
+-----+
oauth=4d98173f7c075527cb64878561d1fe70
+-----+
To connect via Personal access token as a user or organization:
+-----+
login=my_org
oauth=4d98173f7c075527cb64878561d1fe70
+-----+
To connect via JWT token as a GitHub App:
+-----+
jwt=my_jwt_token
+-----+
Once your <<<~/.github>>> property file is properly configured, you can obtain a <<<GitHub>>> instance using:
+-----+
// if you are using the default configuration file
GitHub github = GitHubBuilder.fromPropertyFile().build();
// if you need to use a separate configuration file
GitHub github = GitHubBuilder.fromPropertyFile("location/my_custom_github.properties").build();
+-----+
* Environmental variables
This library also allows developers to authenticate GitHub with environmental variables.
To connect via Username and Password (not recommended):
+-----+
export GITHUB_LOGIN=kohsuke
export GITHUB_PASSWORD=012345678
+-----+
To connect via Personal access token:
+-----+
export GITHUB_OAUTH=4d98173f7c075527cb64878561d1fe70
+-----+
To connect via Personal access token as a user or organization:
+-----+
export GITHUB_LOGIN=my_org
export GITHUB_OAUTH=4d98173f7c075527cb64878561d1fe70
+-----+
To connect via JWT token as a GitHub App:
+-----+
export GITHUB_JWT=my_jwt_token
+-----+
Once exported, you can obtain a <<<GitHub>>> instance using:
+-----+
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}},
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}}.
The following code shows an example of how to set up persistent cache on the disk:
+-----+
Cache cache = new Cache(cacheDirectory, 10 * 1024 * 1024); // 10MB cache
GitHub gitHub = GitHubBuilder.fromEnvironment()
.withConnector(new OkHttpConnector(new OkUrlFactory(new OkHttpClient().setCache(cache))))
.build();
+-----+

View File

@@ -1,51 +0,0 @@
What is this?
=====
This library defines an object oriented representation of the GitHub API. By "object oriented" we mean
there are classes that correspond to the domain model of GitHub (such as `GHUser` and `GHRepository`),
operations that act on them as defined as methods (such as `GHUser.follow()`), and those object references
are used in favor of using string handle (such as `GHUser.isMemberOf(GHOrganization)` instead of
`GHUser.isMemberOf(String)`)
The library supports both github.com and GitHub Enterprise.
Most of the GitHub APIs are covered, although there are some corners that are still not yet implemented.
Sample Usage
-----
GitHub github = GitHub.connect();
GHRepository repo = github.createRepository(
"new-repository","this is my new repository",
"http://www.kohsuke.org/",true/*public*/);
repo.addCollaborators(github.getUser("abayer"),github.getUser("rtyler"));
repo.delete();
Credential
----
This library allows the caller to supply the credential as parameters, but it also defines a common convention
so that applications using this library will look at the consistent location. In this convention, the library
looks at `~/.github` property file, which should have the following two values:
login=kohsuke
password=012345678
Alternatively, you can have just the OAuth token in this file:
oauth=4d98173f7c075527cb64878561d1fe70
OkHttp
----
This library comes with a pluggable connector to use different HTTP client implementations
through `HttpConnector`. In particular, this means you can use [OkHttp](http://square.github.io/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
[does not count against the rate limit](http://developer.github.com/v3/#conditional-requests).
The following code shows an example of how to set up persistent cache on the disk:
Cache cache = new Cache(cacheDirectory, 10 * 1024 * 1024); // 10MB cache
GitHub gitHub = GitHubBuilder.fromCredentials()
.withConnector(new OkHttpConnector(new OkUrlFactory(new OkHttpClient().setCache(cache))))
.build();

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

@@ -9,15 +9,22 @@
<artifactId>maven-skin</artifactId>
<version>1.2</version>
</skin>
<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="Source code" href="https://github.com/kohsuke/${project.artifactId}"/>
<item name="Introduction" href="/index.html"/>
<item name="Download" href="http://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>
<menu name="Guides">
<item name="GitHub App Auth Flow" href="/githubappflow.html">
<item name="JWT Authentication" href="/githubappjwtauth.html"/>
<item name="App Installation Token " href="/githubappappinsttokenauth.html"/>
</item>
</menu>
<menu name="References">
<item name="Javadoc" href="apidocs/index.html"/>
</menu>

View File

@@ -1,22 +0,0 @@
import org.kohsuke.github.GHRepository.Contributor;
import org.kohsuke.github.GHUser;
import org.kohsuke.github.GitHub;
/**
* @author Kohsuke Kawaguchi
*/
public class Foo {
public static void main(String[] args) throws Exception {
GitHub gh = GitHub.connect();
for (Contributor c : gh.getRepository("kohsuke/yo").listContributors()) {
System.out.println(c);
}
}
private static void testRateLimit() throws Exception {
GitHub g = GitHub.connectAnonymously();
for (GHUser u : g.getOrganization("jenkinsci").listMembers()) {
u.getFollowersCount();
}
}
}

View File

@@ -25,8 +25,8 @@ public class HookApp {
public void doIndex(StaplerRequest req) throws IOException {
String str = req.getParameter("payload");
System.out.println(str);
GHEventPayload.PullRequest o = GitHub.connect().parseEventPayload(new StringReader(str),GHEventPayload.PullRequest.class);
System.out.println(o);
// System.out.println(str);
GHEventPayload.PullRequest o = GitHub.connect().parseEventPayload(new StringReader(str), GHEventPayload.PullRequest.class);
// System.out.println(o);
}
}

View File

@@ -2,6 +2,7 @@ package org.kohsuke.github;
import java.io.FileInputStream;
import java.util.Properties;
import org.apache.commons.io.IOUtils;
import org.junit.Assert;
import org.junit.Assume;
@@ -11,44 +12,21 @@ import org.kohsuke.randname.RandomNameGenerator;
import java.io.File;
import java.io.IOException;
import static org.junit.Assume.assumeTrue;
/**
* @author Kohsuke Kawaguchi
*/
public abstract class AbstractGitHubApiTestBase extends Assert {
protected GitHub gitHub;
public abstract class AbstractGitHubApiTestBase extends AbstractGitHubWireMockTest {
@Before
public void setUp() throws Exception {
File f = new File(System.getProperty("user.home"), ".github.kohsuke2");
if (f.exists()) {
Properties props = new Properties();
FileInputStream in = null;
try {
in = new FileInputStream(f);
props.load(in);
} finally {
IOUtils.closeQuietly(in);
}
// use the non-standard credential preferentially, so that developers of this library do not have
// to clutter their event stream.
gitHub = GitHubBuilder.fromProperties(props).withRateLimitHandler(RateLimitHandler.FAIL).build();
} else {
gitHub = GitHubBuilder.fromCredentials().withRateLimitHandler(RateLimitHandler.FAIL).build();
}
}
protected GHUser getUser() {
try {
return gitHub.getMyself();
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
assumeTrue("All tests inheriting from this class are not guaranteed to work without proxy", mockGitHub.isUseProxy());
}
protected void kohsuke() {
String login = getUser().getLogin();
Assume.assumeTrue(login.equals("kohsuke") || login.equals("kohsuke2"));
assumeTrue(login.equals("kohsuke") || login.equals("kohsuke2"));
}
protected static final RandomNameGenerator rnd = new RandomNameGenerator();

View File

@@ -0,0 +1,222 @@
package org.kohsuke.github;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.kohsuke.github.junit.GitHubWireMockRule;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
/**
* @author Liam Newman
*/
public abstract class AbstractGitHubWireMockTest extends Assert {
private final GitHubBuilder githubBuilder = createGitHubBuilder();
final static String GITHUB_API_TEST_ORG = "github-api-test-org";
final static String STUBBED_USER_LOGIN = "placeholder-user";
final static String STUBBED_USER_PASSWORD = "placeholder-password";
protected boolean useDefaultGitHub = true;
protected final Set<String> tempGitHubRepositories = new HashSet<>();
/**
* {@link GitHub} instance for use during test.
* Traffic will be part of snapshot when taken.
*/
protected GitHub gitHub;
/**
* {@link GitHub} instance for use before/after test.
* Traffic will not be part of snapshot when taken.
* Should only be used when isUseProxy() or isTakeSnapShot().
*/
protected GitHub gitHubBeforeAfter;
protected final String baseFilesClassPath = this.getClass().getName().replace('.', '/');
protected final String baseRecordPath = "src/test/resources/" + baseFilesClassPath + "/wiremock";
@Rule
public final GitHubWireMockRule mockGitHub;
public AbstractGitHubWireMockTest() {
mockGitHub = new GitHubWireMockRule(
this.getWireMockOptions()
);
}
protected WireMockConfiguration getWireMockOptions() {
return WireMockConfiguration.options()
.dynamicPort()
.usingFilesUnderDirectory(baseRecordPath);
}
private static GitHubBuilder createGitHubBuilder() {
GitHubBuilder builder = new GitHubBuilder();
try {
File f = new File(System.getProperty("user.home"), ".github.kohsuke2");
if (f.exists()) {
Properties props = new Properties();
FileInputStream in = null;
try {
in = new FileInputStream(f);
props.load(in);
} finally {
IOUtils.closeQuietly(in);
}
// use the non-standard credential preferentially, so that developers of this library do not have
// to clutter their event stream.
builder = GitHubBuilder.fromProperties(props);
} else {
builder = GitHubBuilder.fromEnvironment();
builder = GitHubBuilder.fromCredentials();
}
} catch (IOException e) {
}
return builder.withRateLimitHandler(RateLimitHandler.FAIL);
}
protected GitHubBuilder getGitHubBuilder() {
GitHubBuilder builder = githubBuilder.clone();
if (!mockGitHub.isUseProxy()) {
// This sets the user and password to a placeholder for wiremock testing
// This makes the tests believe they are running with permissions
// The recorded stubs will behave like they running with permissions
builder.oauthToken = null;
builder.withPassword(STUBBED_USER_LOGIN, STUBBED_USER_PASSWORD);
}
return builder;
}
@Before
public void wireMockSetup() throws Exception {
GitHubBuilder builder = getGitHubBuilder()
.withEndpoint(mockGitHub.apiServer().baseUrl());
if (useDefaultGitHub) {
gitHub = builder
.build();
}
if (mockGitHub.isUseProxy()) {
gitHubBeforeAfter = getGitHubBuilder()
.withEndpoint("https://api.github.com/")
.build();
} else {
gitHubBeforeAfter = null;
}
}
protected void snapshotNotAllowed() {
assumeFalse("Test contains hand written mappings. Only valid when not taking a snapshot.", mockGitHub.isTakeSnapshot());
}
protected void requireProxy(String reason) {
assumeTrue("Test only valid when proxying (-Dtest.github.useProxy to enable): " + reason, mockGitHub.isUseProxy());
}
protected GHUser getUser() {
return getUser(gitHub);
}
protected static GHUser getUser(GitHub gitHub) {
try {
return gitHub.getMyself();
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
/**
*
*/
protected GHRepository getTempRepository() throws IOException{
return getTempRepository("temp-" + this.mockGitHub.getMethodName());
}
/**
* Creates
*/
protected GHRepository getTempRepository(String name) throws IOException {
String fullName = GITHUB_API_TEST_ORG +'/' + name;
if (mockGitHub.isUseProxy()) {
cleanupRepository(fullName);
GHRepository repository = gitHubBeforeAfter.getOrganization(GITHUB_API_TEST_ORG)
.createRepository(name)
.description("A test repository for testing the github-api project: " + name)
.homepage("http://github-api.kohsuke.org/")
.autoInit(true)
.create();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e.getMessage(), e);
}
configureTempRepository(repository);
}
return gitHub.getRepository(fullName);
}
protected void configureTempRepository(GHRepository repository) throws IOException {
repository.enableIssueTracker(true);
repository.enableDownloads(true);
repository.enableWiki(true);
}
@Before
@After
public void cleanupTempRepositories() throws IOException {
if (mockGitHub.isUseProxy()) {
for(String fullName : tempGitHubRepositories) {
cleanupRepository(fullName);
}
}
}
protected void cleanupRepository(String fullName) throws IOException {
if (mockGitHub.isUseProxy()) {
tempGitHubRepositories.add(fullName);
try {
GHRepository repository = gitHubBeforeAfter.getRepository(fullName);
if (repository != null) {
repository.delete();
}
} catch (GHFileNotFoundException e) {
// Repo already deleted
}
}
}
protected void kohsuke() {
// No-op for now
// Generally this means the test is doing something that requires additional access rights
// Not always clear which ones.
// TODO: Add helpers that assert the expected rights using gitHubBeforeAfter and only when proxy is enabled
// String login = getUserTest().getLogin();
// assumeTrue(login.equals("kohsuke") || login.equals("kohsuke2"));
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,43 @@
package org.kohsuke.github;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.equalTo;
/**
* @author Kohsuke Kawaguchi
*/
public class BridgeMethodTest extends Assert {
@Test
public void lastStatus() throws IOException {
GHObject obj = new GHIssue();
List<Method> createdAtMethods = new ArrayList<>();
for (Method method : obj.getClass().getMethods()) {
if (method.getName().equalsIgnoreCase("getCreatedAt")) {
if(method.getReturnType() == Date.class) {
createdAtMethods.add(0, method);
} else {
createdAtMethods.add(method);
}
}
}
assertThat(createdAtMethods.size(), equalTo(2));
assertThat(createdAtMethods.get(0).getParameterCount(), equalTo(0));
assertThat(createdAtMethods.get(1).getParameterCount(), equalTo(0));
assertThat(createdAtMethods.get(0).getReturnType(), is(Date.class));
assertThat(createdAtMethods.get(1).getReturnType(), is(String.class));
}
}

View File

@@ -8,11 +8,11 @@ import java.io.IOException;
/**
* @author Kohsuke Kawaguchi
*/
public class CommitTest extends AbstractGitHubApiTestBase {
public class CommitTest extends AbstractGitHubWireMockTest {
@Test // issue 152
public void lastStatus() throws IOException {
GHTag t = gitHub.getRepository("stapler/stapler").listTags().iterator().next();
t.getCommit().getLastStatus();
assertNotNull(t.getCommit().getLastStatus());
}
@Test // issue 230
@@ -20,7 +20,7 @@ public class CommitTest extends AbstractGitHubApiTestBase {
GHRepository repo = gitHub.getRepository("stapler/stapler");
PagedIterable<GHCommit> commits = repo.queryCommits().path("pom.xml").list();
for (GHCommit commit : Iterables.limit(commits, 10)) {
GHCommit expected = repo.getCommit( commit.getSHA1() );
GHCommit expected = repo.getCommit(commit.getSHA1());
assertEquals(expected.getFiles().size(), commit.getFiles().size());
}
}

View File

@@ -0,0 +1,148 @@
package org.kohsuke.github;
import org.junit.Test;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.hamcrest.Matchers.*;
/**
* Tests for the GitHub App API methods
*
* @author Paulo Miguel Almeida
*/
public class GHAppTest 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 getGitHubApp() throws IOException {
GHApp app = gitHub.getApp();
assertThat(app.id, is((long) 11111));
assertThat(app.getOwner().id, is((long) 111111111));
assertThat(app.getOwner().login, is("bogus"));
assertThat(app.getName(), is("Bogus-Development"));
assertThat(app.getDescription(), is(""));
assertThat(app.getExternalUrl(), is("https://bogus.domain.com"));
assertThat(app.getHtmlUrl().toString(), is("https://github.com/apps/bogus-development"));
assertThat(app.getCreatedAt(), is(GitHub.parseDate("2019-06-10T04:21:41Z")));
assertThat(app.getUpdatedAt(), is(GitHub.parseDate("2019-06-10T04:21:41Z")));
assertThat(app.getPermissions().size(), is(4));
assertThat(app.getEvents().size(), is(2));
assertThat(app.getInstallationsCount(), is((long) 1));
}
@Test
public void listInstallations() throws IOException {
GHApp app = gitHub.getApp();
List<GHAppInstallation> installations = app.listInstallations().asList();
assertThat(installations.size(), is(1));
GHAppInstallation appInstallation = installations.get(0);
testAppInstallation(appInstallation);
}
@Test
public void getInstallationById() throws IOException {
GHApp app = gitHub.getApp();
GHAppInstallation installation = app.getInstallationById(1111111);
testAppInstallation(installation);
}
@Test
public void getInstallationByOrganization() throws IOException {
GHApp app = gitHub.getApp();
GHAppInstallation installation = app.getInstallationByOrganization("bogus");
testAppInstallation(installation);
}
@Test
public void getInstallationByRepository() throws IOException {
GHApp app = gitHub.getApp();
GHAppInstallation installation = app.getInstallationByRepository("bogus", "bogus");
testAppInstallation(installation);
}
@Test
public void getInstallationByUser() throws IOException {
GHApp app = gitHub.getApp();
GHAppInstallation installation = app.getInstallationByUser("bogus");
testAppInstallation(installation);
}
@Test
public void deleteInstallation() throws IOException {
GHApp app = gitHub.getApp();
GHAppInstallation installation = app.getInstallationByUser("bogus");
try {
installation.deleteInstallation();
} catch (IOException e) {
fail("deleteInstallation wasn't suppose to fail in this test");
}
}
@Test
public void createToken() throws IOException {
GHApp app = gitHub.getApp();
GHAppInstallation installation = app.getInstallationByUser("bogus");
Map<String, GHPermissionType> permissions = new HashMap<String, GHPermissionType>();
permissions.put("checks", GHPermissionType.WRITE);
permissions.put("pull_requests", GHPermissionType.WRITE);
permissions.put("contents", GHPermissionType.READ);
permissions.put("metadata", GHPermissionType.READ);
GHAppInstallationToken installationToken = installation.createToken(permissions)
.repositoryIds(Arrays.asList((long)111111111))
.create();
assertThat(installationToken.getToken(), is("bogus"));
assertThat(installation.getPermissions(), is(permissions));
assertThat(installationToken.getRepositorySelection(),is(GHRepositorySelection.SELECTED));
assertThat(installationToken.getExpiresAt(), is(GitHub.parseDate("2019-08-10T05:54:58Z")));
GHRepository repository = installationToken.getRepositories().get(0);
assertThat(installationToken.getRepositories().size(), is(1));
assertThat(repository.getId(), is((long) 111111111));
assertThat(repository.getName(), is("bogus"));
}
private void testAppInstallation(GHAppInstallation appInstallation) throws IOException {
Map<String, GHPermissionType> appPermissions = appInstallation.getPermissions();
GHUser appAccount = appInstallation.getAccount();
assertThat(appInstallation.id, is((long) 11111111));
assertThat(appAccount.id, is((long) 111111111));
assertThat(appAccount.login, is("bogus"));
assertThat(appInstallation.getRepositorySelection(), is(GHRepositorySelection.SELECTED));
assertThat(appInstallation.getAccessTokenUrl(), endsWith("/app/installations/11111111/access_tokens"));
assertThat(appInstallation.getRepositoriesUrl(), endsWith("/installation/repositories"));
assertThat(appInstallation.getAppId(), is((long) 11111));
assertThat(appInstallation.getTargetId(), is((long) 111111111));
assertThat(appInstallation.getTargetType(), is(GHTargetType.ORGANIZATION));
Map<String, GHPermissionType> permissionsMap = new HashMap<String, GHPermissionType>();
permissionsMap.put("checks", GHPermissionType.WRITE);
permissionsMap.put("pull_requests", GHPermissionType.WRITE);
permissionsMap.put("contents", GHPermissionType.READ);
permissionsMap.put("metadata", GHPermissionType.READ);
assertThat(appPermissions, is(permissionsMap));
List<GHEvent> events = Arrays.asList(GHEvent.PULL_REQUEST, GHEvent.PUSH);
assertThat(appInstallation.getEvents(), containsInAnyOrder(events.toArray(new GHEvent[0])));
assertThat(appInstallation.getCreatedAt(), is(GitHub.parseDate("2019-07-04T01:19:36.000Z")));
assertThat(appInstallation.getUpdatedAt(), is(GitHub.parseDate("2019-07-30T22:48:09.000Z")));
assertNull(appInstallation.getSingleFileName());
}
}

View File

@@ -49,25 +49,25 @@ public class GHBranchProtectionTest extends AbstractGitHubApiTestBase {
public void testEnableBranchProtections() throws Exception {
// team/user restrictions require an organization repo to test against
GHBranchProtection protection = branch.enableProtection()
.addRequiredChecks("test-status-check")
.requireBranchIsUpToDate()
.requireCodeOwnReviews()
.dismissStaleReviews()
.requiredReviewers(2)
.includeAdmins()
.enable();
.addRequiredChecks("test-status-check")
.requireBranchIsUpToDate()
.requireCodeOwnReviews()
.dismissStaleReviews()
.requiredReviewers(2)
.includeAdmins()
.enable();
RequiredStatusChecks statusChecks = protection.getRequiredStatusChecks();
assertNotNull(statusChecks);
assertTrue(statusChecks.isRequiresBranchUpToDate());
assertTrue(statusChecks.getContexts().contains("test-status-check"));
RequiredReviews requiredReviews = protection.getRequiredReviews();
assertNotNull(requiredReviews);
assertTrue(requiredReviews.isDismissStaleReviews());
assertTrue(requiredReviews.isRequireCodeOwnerReviews());
assertEquals(2, requiredReviews.getRequiredReviewers());
EnforceAdmins enforceAdmins = protection.getEnforceAdmins();
assertNotNull(enforceAdmins);
assertTrue(enforceAdmins.isEnabled());
@@ -82,10 +82,10 @@ public class GHBranchProtectionTest extends AbstractGitHubApiTestBase {
@Test
public void testEnableRequireReviewsOnly() throws Exception {
GHBranchProtection protection = branch.enableProtection()
.requireReviews()
.enable();
assertNotNull(protection.getRequiredReviews());
.requireReviews()
.enable();
assertNotNull(protection.getRequiredReviews());
}
@Test

View File

@@ -1,27 +1,46 @@
package org.kohsuke.github;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
/**
* Integration test for {@link GHContent}.
*/
public class GHContentIntegrationTest extends AbstractGitHubApiTestBase {
public class GHContentIntegrationTest extends AbstractGitHubWireMockTest {
private GHRepository repo;
private String createdFilename = rnd.next();
private String createdFilename = "test-file-to-create.txt";
@Before
@Override
public void setUp() throws Exception {
super.setUp();
repo = gitHub.getRepository("github-api-test-org/GHContentIntegrationTest").fork();
@After
public void cleanup() throws Exception {
if(mockGitHub.isUseProxy()) {
repo = gitHubBeforeAfter.getRepository("github-api-test-org/GHContentIntegrationTest");
try {
GHContent content = repo.getFileContent(createdFilename);
if (content != null) {
content.delete("Cleanup");
}
} catch (IOException e) {}
}
}
@Before
public void setUp() throws Exception {
repo = gitHub.getRepository("github-api-test-org/GHContentIntegrationTest");
}
@Test
public void testGetFileContent() throws Exception {
repo = gitHub.getRepository("github-api-test-org/GHContentIntegrationTest");
GHContent content = repo.getFileContent("ghcontent-ro/a-file-with-content");
assertTrue(content.isFile());
@@ -54,7 +73,7 @@ public class GHContentIntegrationTest extends AbstractGitHubApiTestBase {
@Test
public void testCRUDContent() throws Exception {
GHContentUpdateResponse created =
repo.createContent("this is an awesome file I created\n", "Creating a file for integration tests.", createdFilename);
repo.createContent("this is an awesome file I created\n", "Creating a file for integration tests.", createdFilename);
GHContent createdContent = created.getContent();
assertNotNull(created.getCommit());
@@ -68,7 +87,8 @@ public class GHContentIntegrationTest extends AbstractGitHubApiTestBase {
assertNotNull(updatedContentResponse.getCommit());
assertNotNull(updatedContentResponse.getContent());
// due to what appears to be a cache propagation delay, this test is too flaky
// assertEquals("this is some new content\n", updatedContent.getContent());
assertEquals("this is some new content", new BufferedReader(new InputStreamReader(updatedContent.read())).readLine());
assertEquals("this is some new content\n", updatedContent.getContent());
GHContentUpdateResponse deleteResponse = updatedContent.delete("Enough of this foolishness!");

View File

@@ -0,0 +1,27 @@
package org.kohsuke.github;
import org.junit.Test;
import java.io.IOException;
import static org.junit.Assert.assertNotNull;
/**
* @author Martin van Zijl
*/
public class GHDeploymentTest extends AbstractGitHubWireMockTest {
@Test
public void testGetDeploymentById() throws IOException {
GHRepository repo = getRepository();
GHDeployment deployment = repo.getDeployment(178653229);
assertNotNull(deployment);
}
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

@@ -15,7 +15,7 @@ public class GHEventPayloadTest {
@Test
public void commit_comment() throws Exception {
GHEventPayload.CommitComment event =
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.CommitComment.class);
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.CommitComment.class);
assertThat(event.getAction(), is("created"));
assertThat(event.getComment().getSHA1(), is("9049f1265b7d61be4a8904a9a27120d2064dab3b"));
assertThat(event.getComment().getUser().getLogin(), is("baxterthehacker"));
@@ -27,7 +27,7 @@ public class GHEventPayloadTest {
@Test
public void create() throws Exception {
GHEventPayload.Create event =
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.Create.class);
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.Create.class);
assertThat(event.getRef(), is("0.0.1"));
assertThat(event.getRefType(), is("tag"));
assertThat(event.getMasterBranch(), is("master"));
@@ -40,7 +40,7 @@ public class GHEventPayloadTest {
@Test
public void delete() throws Exception {
GHEventPayload.Delete event =
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.Delete.class);
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.Delete.class);
assertThat(event.getRef(), is("simple-tag"));
assertThat(event.getRefType(), is("tag"));
assertThat(event.getRepository().getName(), is("public-repo"));
@@ -51,7 +51,7 @@ public class GHEventPayloadTest {
@Test
public void deployment() throws Exception {
GHEventPayload.Deployment event =
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.Deployment.class);
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.Deployment.class);
assertThat(event.getDeployment().getSha(), is("9049f1265b7d61be4a8904a9a27120d2064dab3b"));
assertThat(event.getDeployment().getEnvironment(), is("production"));
assertThat(event.getDeployment().getCreator().getLogin(), is("baxterthehacker"));
@@ -63,7 +63,7 @@ public class GHEventPayloadTest {
@Test
public void deployment_status() throws Exception {
GHEventPayload.DeploymentStatus event =
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.DeploymentStatus.class);
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.DeploymentStatus.class);
assertThat(event.getDeploymentStatus().getState(), is(GHDeploymentState.SUCCESS));
assertThat(event.getDeploymentStatus().getTargetUrl(), nullValue());
assertThat(event.getDeployment().getSha(), is("9049f1265b7d61be4a8904a9a27120d2064dab3b"));
@@ -77,7 +77,7 @@ public class GHEventPayloadTest {
@Test
public void fork() throws Exception {
GHEventPayload.Fork event =
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.Fork.class);
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.Fork.class);
assertThat(event.getForkee().getName(), is("public-repo"));
assertThat(event.getForkee().getOwner().getLogin(), is("baxterandthehackers"));
assertThat(event.getRepository().getName(), is("public-repo"));
@@ -106,7 +106,7 @@ public class GHEventPayloadTest {
@Test
public void issue_comment() throws Exception {
GHEventPayload.IssueComment event =
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.IssueComment.class);
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.IssueComment.class);
assertThat(event.getAction(), is("created"));
assertThat(event.getIssue().getNumber(), is(2));
assertThat(event.getIssue().getTitle(), is("Spelling error in the README file"));
@@ -122,8 +122,8 @@ public class GHEventPayloadTest {
@Test
public void issues() throws Exception {
GHEventPayload.Issue event = GitHub.offline().parseEventPayload(payload.asReader(),GHEventPayload.Issue.class);
assertThat(event.getAction(),is("opened"));
GHEventPayload.Issue event = GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.Issue.class);
assertThat(event.getAction(), is("opened"));
assertThat(event.getIssue().getNumber(), is(2));
assertThat(event.getIssue().getTitle(), is("Spelling error in the README file"));
assertThat(event.getIssue().getState(), is(GHIssueState.OPEN));
@@ -158,7 +158,7 @@ public class GHEventPayloadTest {
@Payload("public")
public void public_() throws Exception {
GHEventPayload.Public event =
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.Public.class);
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.Public.class);
assertThat(event.getRepository().getName(), is("public-repo"));
assertThat(event.getRepository().getOwner().getLogin(), is("baxterthehacker"));
assertThat(event.getSender().getLogin(), is("baxterthehacker"));
@@ -167,13 +167,13 @@ public class GHEventPayloadTest {
@Test
public void pull_request() throws Exception {
GHEventPayload.PullRequest event =
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.PullRequest.class);
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.PullRequest.class);
assertThat(event.getAction(), is("opened"));
assertThat(event.getNumber(), is(1));
assertThat(event.getPullRequest().getNumber(), is(1));
assertThat(event.getPullRequest().getTitle(), is("Update the README with new information"));
assertThat(event.getPullRequest().getBody(), is("This is a pretty simple change that we need to pull into "
+ "master."));
+ "master."));
assertThat(event.getPullRequest().getUser().getLogin(), is("baxterthehacker"));
assertThat(event.getPullRequest().getHead().getUser().getLogin(), is("baxterthehacker"));
assertThat(event.getPullRequest().getHead().getRef(), is("changes"));
@@ -200,13 +200,13 @@ public class GHEventPayloadTest {
@Test
public void pull_request_review() throws Exception {
GHEventPayload.PullRequestReview event =
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.PullRequestReview.class);
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.PullRequestReview.class);
assertThat(event.getAction(), is("submitted"));
assertThat(event.getReview().getId(), is(2626884L));
assertThat(event.getReview().getBody(), is("Looks great!\n"));
assertThat(event.getReview().getState(), is(GHPullRequestReviewState.APPROVED));
assertThat(event.getPullRequest().getNumber(), is(8));
assertThat(event.getPullRequest().getTitle(), is("Add a README description"));
assertThat(event.getPullRequest().getBody(), is("Just a few more details"));
@@ -219,21 +219,21 @@ public class GHEventPayloadTest {
assertThat(event.getPullRequest().getBase().getRef(), is("master"));
assertThat(event.getPullRequest().getBase().getLabel(), is("baxterthehacker:master"));
assertThat(event.getPullRequest().getBase().getSha(), is("9049f1265b7d61be4a8904a9a27120d2064dab3b"));
assertThat(event.getRepository().getName(), is("public-repo"));
assertThat(event.getRepository().getOwner().getLogin(), is("baxterthehacker"));
assertThat(event.getSender().getLogin(), is("baxterthehacker"));
}
@Test
public void pull_request_review_comment() throws Exception {
GHEventPayload.PullRequestReviewComment event =
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.PullRequestReviewComment.class);
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.PullRequestReviewComment.class);
assertThat(event.getAction(), is("created"));
assertThat(event.getComment().getBody(), is("Maybe you should use more emojji on this line."));
assertThat(event.getPullRequest().getNumber(), is(1));
assertThat(event.getPullRequest().getTitle(), is("Update the README with new information"));
assertThat(event.getPullRequest().getBody(), is("This is a pretty simple change that we need to pull into master."));
@@ -246,17 +246,17 @@ public class GHEventPayloadTest {
assertThat(event.getPullRequest().getBase().getRef(), is("master"));
assertThat(event.getPullRequest().getBase().getLabel(), is("baxterthehacker:master"));
assertThat(event.getPullRequest().getBase().getSha(), is("9049f1265b7d61be4a8904a9a27120d2064dab3b"));
assertThat(event.getRepository().getName(), is("public-repo"));
assertThat(event.getRepository().getOwner().getLogin(), is("baxterthehacker"));
assertThat(event.getSender().getLogin(), is("baxterthehacker"));
}
@Test
public void push() throws Exception {
GHEventPayload.Push event =
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.Push.class);
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.Push.class);
assertThat(event.getRef(), is("refs/heads/changes"));
assertThat(event.getBefore(), is("9049f1265b7d61be4a8904a9a27120d2064dab3b"));
assertThat(event.getHead(), is("0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c"));
@@ -286,7 +286,7 @@ public class GHEventPayloadTest {
@Test
public void repository() throws Exception {
GHEventPayload.Repository event =
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.Repository.class);
GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.Repository.class);
assertThat(event.getAction(), is("created"));
assertThat(event.getRepository().getName(), is("new-repository"));
assertThat(event.getRepository().getOwner().getLogin(), is("baxterandthehackers"));

View File

@@ -0,0 +1,73 @@
package org.kohsuke.github;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* @author Martin van Zijl
*/
public class GHGistUpdaterTest extends AbstractGitHubWireMockTest {
private GHGist gist;
@Before
public void setUp() throws IOException {
GHGistBuilder builder = new GHGistBuilder(gitHub);
gist = builder.description("Test for the API")
.file("unmodified.txt", "Should be unmodified")
//.file("delete-me.txt", "To be deleted")
.file("rename-me.py", "print 'hello'")
.file("update-me.txt", "To be updated")
.public_(true)
.create();
}
@After
public void cleanUp() throws Exception {
// Cleanup is only needed when proxying
if (!mockGitHub.isUseProxy()) {
return;
}
gist.delete();
}
@Test
public void testGitUpdater() throws Exception {
GHGistUpdater updater = gist.update();
GHGist updatedGist = updater.description("Description updated by API")
.addFile("new-file.txt", "Added by updater")
//.deleteFile("delete-me.txt")
.renameFile("rename-me.py", "renamed.py")
.updateFile("update-me.txt", "Content updated by API")
.update();
assertEquals("Description updated by API", updatedGist.getDescription());
Map<String,GHGistFile> files = updatedGist.getFiles();
// Check that the unmodified file stays intact.
assertTrue(files.containsKey("unmodified.txt"));
assertEquals("Should be unmodified", files.get("unmodified.txt").getContent());
// Check that the files are updated as expected.
//assertFalse("File was not deleted.", files.containsKey("delete-me.txt"));
assertTrue(files.containsKey("new-file.txt"));
assertEquals("Added by updater", files.get("new-file.txt").getContent());
assertFalse(files.containsKey("rename-me.py"));
assertTrue(files.containsKey("renamed.py"));
assertEquals("print 'hello'", files.get("renamed.py").getContent());
assertEquals("Content updated by API", files.get("update-me.txt").getContent());
}
}

View File

@@ -0,0 +1,59 @@
package org.kohsuke.github;
import java.io.IOException;
import java.util.List;
import org.junit.Test;
/**
* @author Martin van Zijl
*/
public class GHIssueEventTest extends AbstractGitHubApiTestBase {
@Test
public void testEventsForSingleIssue() throws Exception {
// Create the issue.
GHRepository repo = getRepository();
GHIssueBuilder builder = repo.createIssue("Test from the API");
GHIssue issue = builder.create();
// Generate some events.
issue.addLabels("test-label");
// Test that the events are present.
List<GHIssueEvent> list = issue.listEvents().asList();
assertEquals(1, list.size());
GHIssueEvent event = list.get(0);
assertEquals(issue.getNumber(), event.getIssue().getNumber());
assertEquals("labeled", event.getEvent());
// Test that we can get a single event directly.
GHIssueEvent eventFromRepo = repo.getIssueEvent(event.getId());
assertEquals(event.getId(), eventFromRepo.getId());
assertEquals(event.getCreatedAt(), eventFromRepo.getCreatedAt());
// Close the issue.
issue.close();
}
@Test
public void testRepositoryEvents() throws Exception {
GHRepository repo = getRepository();
List<GHIssueEvent> list = repo.listIssueEvents().asList();
assertTrue(list.size() > 0);
int i = 0;
for (GHIssueEvent event : list) {
assertNotNull(event.getIssue());
if (i++ > 10) break;
}
}
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

@@ -25,8 +25,6 @@
package org.kohsuke.github;
import org.apache.commons.io.IOUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
@@ -35,15 +33,7 @@ import java.net.URL;
/**
* @author Duncan Dickinson
*/
public class GHLicenseTest extends Assert {
private GitHub gitHub;
@Before
public void setUp() throws Exception {
gitHub = new GitHubBuilder()
.fromCredentials()
.build();
}
public class GHLicenseTest extends AbstractGitHubWireMockTest {
/**
* Basic test to ensure that the list of licenses from {@link GitHub#listLicenses()} is returned
@@ -67,7 +57,7 @@ public class GHLicenseTest extends Assert {
PagedIterable<GHLicense> licenses = gitHub.listLicenses();
for (GHLicense lic : licenses) {
if (lic.getKey().equals("mit")) {
assertTrue(lic.getUrl().equals(new URL("https://api.github.com/licenses/mit")));
assertTrue(lic.getUrl().equals(new URL(mockGitHub.apiServer().baseUrl() + "/licenses/mit")));
return;
}
}
@@ -97,12 +87,12 @@ public class GHLicenseTest extends Assert {
*/
@Test
public void checkRepositoryLicense() throws IOException {
GHRepository repo = gitHub.getRepository("kohsuke/github-api");
GHRepository repo = gitHub.getRepository("github-api/github-api");
GHLicense license = repo.getLicense();
assertNotNull("The license is populated", license);
assertTrue("The key is correct", license.getKey().equals("mit"));
assertTrue("The name is correct", license.getName().equals("MIT License"));
assertTrue("The URL is correct", license.getUrl().equals(new URL("https://api.github.com/licenses/mit")));
assertTrue("The URL is correct", license.getUrl().equals(new URL(mockGitHub.apiServer().baseUrl() + "/licenses/mit")));
}
/**
@@ -118,7 +108,7 @@ public class GHLicenseTest extends Assert {
assertNotNull("The license is populated", license);
assertTrue("The key is correct", license.getKey().equals("mit"));
assertTrue("The name is correct", license.getName().equals("MIT License"));
assertTrue("The URL is correct", license.getUrl().equals(new URL("https://api.github.com/licenses/mit")));
assertTrue("The URL is correct", license.getUrl().equals(new URL(mockGitHub.apiServer().baseUrl() + "/licenses/mit")));
}
/**
@@ -134,7 +124,7 @@ public class GHLicenseTest extends Assert {
assertNotNull("The license is populated", license);
assertTrue("The key is correct", license.getKey().equals("apache-2.0"));
assertTrue("The name is correct", license.getName().equals("Apache License 2.0"));
assertTrue("The URL is correct", license.getUrl().equals(new URL("https://api.github.com/licenses/apache-2.0")));
assertTrue("The URL is correct", license.getUrl().equals(new URL(mockGitHub.apiServer().baseUrl() + "/licenses/apache-2.0")));
}
/**
@@ -145,7 +135,7 @@ public class GHLicenseTest extends Assert {
*/
@Test
public void checkRepositoryWithoutLicense() throws IOException {
GHRepository repo = gitHub.getRepository("dedickinson/test-repo");
GHRepository repo = gitHub.getRepository(GITHUB_API_TEST_ORG + "/empty");
GHLicense license = repo.getLicense();
assertNull("There is no license", license);
}
@@ -159,12 +149,12 @@ public class GHLicenseTest extends Assert {
*/
@Test
public void checkRepositoryFullLicense() throws IOException {
GHRepository repo = gitHub.getRepository("kohsuke/github-api");
GHRepository repo = gitHub.getRepository("github-api/github-api");
GHLicense license = repo.getLicense();
assertNotNull("The license is populated", license);
assertTrue("The key is correct", license.getKey().equals("mit"));
assertTrue("The name is correct", license.getName().equals("MIT License"));
assertTrue("The URL is correct", license.getUrl().equals(new URL("https://api.github.com/licenses/mit")));
assertTrue("The URL is correct", license.getUrl().equals(new URL(mockGitHub.apiServer().baseUrl() + "/licenses/mit")));
assertTrue("The HTML URL is correct", license.getHtmlUrl().equals(new URL("http://choosealicense.com/licenses/mit/")));
}

View File

@@ -0,0 +1,64 @@
package org.kohsuke.github;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.Date;
/**
* @author Martin van Zijl
*/
public class GHMilestoneTest extends AbstractGitHubWireMockTest {
@Before
@After
public void cleanUp() throws Exception {
// Cleanup is only needed when proxying
if (!mockGitHub.isUseProxy()) {
return;
}
for (GHMilestone milestone : getRepository(gitHubBeforeAfter).listMilestones(GHIssueState.ALL)) {
if ("Original Title".equals(milestone.getTitle()) ||
"Updated Title".equals(milestone.getTitle())) {
milestone.delete();
}
}
}
@Test
public void testUpdateMilestone() throws Exception {
GHRepository repo = getRepository();
GHMilestone milestone = repo.createMilestone("Original Title",
"To test the update methods");
String NEW_TITLE = "Updated Title";
String NEW_DESCRIPTION = "Updated Description";
Date NEW_DUE_DATE = GitHub.parseDate("2020-10-05T13:00:00Z");
Date OUTPUT_DUE_DATE = GitHub.parseDate("2020-10-05T07:00:00Z");
milestone.setTitle(NEW_TITLE);
milestone.setDescription(NEW_DESCRIPTION);
milestone.setDueOn(NEW_DUE_DATE);
// Force reload.
milestone = repo.getMilestone(milestone.getNumber());
assertEquals(NEW_TITLE, milestone.getTitle());
assertEquals(NEW_DESCRIPTION, milestone.getDescription());
// The time is truncated when sent to the server, but still part of the returned value
// 07:00 midnight PDT
assertEquals(OUTPUT_DUE_DATE, milestone.getDueOn());
}
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,24 +1,39 @@
package org.kohsuke.github;
import com.jcraft.jsch.IO;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
public class GHOrganizationTest extends AbstractGitHubApiTestBase {
public class GHOrganizationTest extends AbstractGitHubWireMockTest {
public static final String GITHUB_API_TEST = "github-api-test";
private GHOrganization org;
public static final String TEAM_NAME_CREATE = "create-team-test";
@Override
public void setUp() throws Exception {
super.setUp();
org = gitHub.getOrganization("github-api-test-org");
@Before
@After
public void cleanUpTeam() throws IOException {
// Cleanup is only needed when proxying
if (!mockGitHub.isUseProxy()) {
return;
}
GHTeam team = gitHubBeforeAfter.getOrganization(GITHUB_API_TEST_ORG).
getTeamByName(TEAM_NAME_CREATE);
if (team != null) {
team.delete();
}
}
@Test
public void testCreateRepository() throws IOException {
cleanupRepository(GITHUB_API_TEST_ORG + '/' + GITHUB_API_TEST);
GHOrganization org = gitHub.getOrganization(GITHUB_API_TEST_ORG);
GHRepository repository = org.createRepository(GITHUB_API_TEST,
"a test repository used to test kohsuke's github-api", "http://github-api.kohsuke.org/", "Core Developers", true);
Assert.assertNotNull(repository);
@@ -26,18 +41,49 @@ public class GHOrganizationTest extends AbstractGitHubApiTestBase {
@Test
public void testCreateRepositoryWithAutoInitialization() throws IOException {
cleanupRepository(GITHUB_API_TEST_ORG + '/' + GITHUB_API_TEST);
GHOrganization org = gitHub.getOrganization(GITHUB_API_TEST_ORG);
GHRepository repository = org.createRepository(GITHUB_API_TEST)
.description("a test repository used to test kohsuke's github-api")
.homepage("http://github-api.kohsuke.org/")
.team(org.getTeamByName("Core Developers"))
.autoInit(true).create();
.description("a test repository used to test kohsuke's github-api")
.homepage("http://github-api.kohsuke.org/")
.team(org.getTeamByName("Core Developers"))
.autoInit(true).create();
Assert.assertNotNull(repository);
Assert.assertNotNull(repository.getReadme());
}
@After
public void cleanUp() throws Exception {
GHRepository repository = org.getRepository(GITHUB_API_TEST);
repository.delete();
@Test
public void testInviteUser() throws IOException {
GHOrganization org = gitHub.getOrganization(GITHUB_API_TEST_ORG);
GHUser user = gitHub.getUser("martinvanzijl2");
// First remove the user
if (org.hasMember(user)) {
org.remove(user);
}
// Then invite the user again
org.add(user, GHOrganization.Role.MEMBER);
// Now the user has to accept the invitation
// Can this be automated?
// user.acceptInvitationTo(org); // ?
// Check the invitation has worked.
// assertTrue(org.hasMember(user));
}
@Test
public void testCreateTeamWithRepoAccess() throws IOException {
String REPO_NAME = "github-api";
GHOrganization org = gitHub.getOrganization(GITHUB_API_TEST_ORG);
GHRepository repo = org.getRepository(REPO_NAME);
// Create team with access to repository. Check access was granted.
GHTeam team = org.createTeam(TEAM_NAME_CREATE, GHOrganization.Permission.PUSH, repo);
Assert.assertTrue(team.getRepositories().containsKey(REPO_NAME));
}
}

View File

@@ -0,0 +1,107 @@
package org.kohsuke.github;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* @author Gunnar Skjold
*/
public class GHProjectCardTest extends AbstractGitHubWireMockTest {
private GHOrganization org;
private GHProject project;
private GHProjectColumn column;
private GHProjectCard card;
@Before
public void setUp() throws Exception {
org = gitHub.getOrganization(GITHUB_API_TEST_ORG);
project = org.createProject("test-project", "This is a test project");
column = project.createColumn("column-one");
card = column.createCard("This is a card");
}
@Test
public void testCreatedCard() {
Assert.assertEquals("This is a card", card.getNote());
Assert.assertFalse(card.isArchived());
}
@Test
public void testEditCardNote() throws IOException {
card.setNote("New note");
card = gitHub.getProjectCard(card.getId());
Assert.assertEquals("New note", card.getNote());
Assert.assertFalse(card.isArchived());
}
@Test
public void testArchiveCard() throws IOException {
card.setArchived(true);
card = gitHub.getProjectCard(card.getId());
Assert.assertEquals("This is a card", card.getNote());
Assert.assertTrue(card.isArchived());
}
@Test
public void testCreateCardFromIssue() throws IOException {
GHRepository repo = org.createRepository("repo-for-project-card").create();
try {
GHIssue issue = repo.createIssue("new-issue").body("With body").create();
GHProjectCard card = column.createCard(issue);
Assert.assertEquals(issue.getUrl(), card.getContentUrl());
} finally {
repo.delete();
}
}
@Test
public void testDeleteCard() throws IOException {
card.delete();
try {
card = gitHub.getProjectCard(card.getId());
Assert.assertNull(card);
} catch (FileNotFoundException e) {
card = null;
}
}
@After
public void after() throws IOException {
if(mockGitHub.isUseProxy()) {
if (card != null) {
card = gitHubBeforeAfter.getProjectCard(card.getId());
try {
card.delete();
card = null;
} catch (FileNotFoundException e) {
card = null;
}
}
if (column != null) {
column = gitHubBeforeAfter
.getProjectColumn(column.getId());
try {
column.delete();
column = null;
} catch (FileNotFoundException e) {
column = null;
}
}
if (project != null) {
project = gitHubBeforeAfter
.getProject(project.getId());
try {
project.delete();
project = null;
} catch (FileNotFoundException e) {
project = null;
}
}
}
}
}

View File

@@ -0,0 +1,74 @@
package org.kohsuke.github;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* @author Gunnar Skjold
*/
public class GHProjectColumnTest extends AbstractGitHubWireMockTest {
private GHProject project;
private GHProjectColumn column;
@Before
public void setUp() throws Exception {
project = gitHub
.getOrganization(GITHUB_API_TEST_ORG)
.createProject("test-project", "This is a test project");
column = project.createColumn("column-one");
}
@Test
public void testCreatedColumn() {
Assert.assertEquals("column-one", column.getName());
}
@Test
public void testEditColumnName() throws IOException {
column.setName("new-name");
column = gitHub.getProjectColumn(column.getId());
Assert.assertEquals("new-name", column.getName());
}
@Test
public void testDeleteColumn() throws IOException {
column.delete();
try {
column = gitHub.getProjectColumn(column.getId());
Assert.assertNull(column);
} catch (FileNotFoundException e) {
column = null;
}
}
@After
public void after() throws IOException {
if(mockGitHub.isUseProxy()) {
if (column != null) {
column = gitHubBeforeAfter
.getProjectColumn(column.getId());
try {
column.delete();
column = null;
} catch (FileNotFoundException e) {
column = null;
}
}
if (project != null) {
project = gitHubBeforeAfter
.getProject(project.getId());
try {
project.delete();
project = null;
} catch (FileNotFoundException e) {
project = null;
}
}
}
}
}

View File

@@ -0,0 +1,85 @@
package org.kohsuke.github;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* @author Gunnar Skjold
*/
public class GHProjectTest extends AbstractGitHubWireMockTest {
private GHProject project;
@Before
public void setUp() throws Exception {
project = gitHub
.getOrganization(GITHUB_API_TEST_ORG)
.createProject("test-project", "This is a test project");
}
@Test
public void testCreatedProject() {
Assert.assertNotNull(project);
Assert.assertEquals("test-project", project.getName());
Assert.assertEquals("This is a test project", project.getBody());
Assert.assertEquals(GHProject.ProjectState.OPEN, project.getState());
}
@Test
public void testEditProjectName() throws IOException {
project.setName("new-name");
project = gitHub.getProject(project.getId());
Assert.assertEquals("new-name", project.getName());
Assert.assertEquals("This is a test project", project.getBody());
Assert.assertEquals(GHProject.ProjectState.OPEN, project.getState());
}
@Test
public void testEditProjectBody() throws IOException {
project.setBody("New body");
project = gitHub.getProject(project.getId());
Assert.assertEquals("test-project", project.getName());
Assert.assertEquals("New body", project.getBody());
Assert.assertEquals(GHProject.ProjectState.OPEN, project.getState());
}
@Test
public void testEditProjectState() throws IOException {
project.setState(GHProject.ProjectState.CLOSED);
project = gitHub.getProject(project.getId());
Assert.assertEquals("test-project", project.getName());
Assert.assertEquals("This is a test project", project.getBody());
Assert.assertEquals(GHProject.ProjectState.CLOSED, project.getState());
}
@Test
public void testDeleteProject() throws IOException {
project.delete();
try {
project = gitHub.getProject(project.getId());
Assert.assertNull(project);
} catch (FileNotFoundException e) {
project = null;
}
}
@After
public void after() throws IOException {
if (mockGitHub.isUseProxy()) {
if (project != null) {
project = gitHubBeforeAfter
.getProject(project.getId());
try {
project.delete();
project = null;
} catch (FileNotFoundException e) {
project = null;
}
}
}
}
}

View File

@@ -0,0 +1,329 @@
package org.kohsuke.github;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.hamcrest.CoreMatchers.*;
/**
* @author Kohsuke Kawaguchi
*/
public class GHPullRequestTest extends AbstractGitHubWireMockTest {
@Before
@After
public void cleanUp() throws Exception {
// Cleanup is only needed when proxying
if (!mockGitHub.isUseProxy()) {
return;
}
for (GHPullRequest pr : getRepository(this.gitHubBeforeAfter).getPullRequests(GHIssueState.OPEN)) {
pr.close();
}
}
@Test
public void createPullRequest() throws Exception {
String name = "createPullRequest";
GHRepository repo = getRepository();
GHPullRequest p = repo.createPullRequest(name, "test/stable", "master", "## test");
assertEquals(name, p.getTitle());
assertThat(p.canMaintainerModify(), is(false));
assertThat(p.isDraft(), is(false));
}
@Test
public void createDraftPullRequest() throws Exception {
String name = "createDraftPullRequest";
GHRepository repo = getRepository();
GHPullRequest p = repo.createPullRequest(name, "test/stable", "master", "## test", false, true);
assertEquals(name, p.getTitle());
assertThat(p.canMaintainerModify(), is(false));
assertThat(p.isDraft(), is(true));
// There are multiple paths to get PRs and each needs to read draft correctly
p.draft = false;
p.refresh();
assertThat(p.isDraft(), is(true));
GHPullRequest p2 = repo.getPullRequest(p.getNumber());
assertThat(p2.getNumber(), is(p.getNumber()));
assertThat(p2.isDraft(), is(true));
p = repo.queryPullRequests()
.state(GHIssueState.OPEN)
.head("test/stable")
.list().asList().get(0);
assertThat(p2.getNumber(), is(p.getNumber()));
assertThat(p.isDraft(), is(true));
}
@Test
public void createPullRequestComment() throws Exception {
String name = "createPullRequestComment";
GHPullRequest p = getRepository().createPullRequest(name, "test/stable", "master", "## test");
p.comment("Some comment");
}
@Test
public void closePullRequest() throws Exception {
String name = "closePullRequest";
GHPullRequest p = getRepository().createPullRequest(name, "test/stable", "master", "## test");
// System.out.println(p.getUrl());
assertEquals(name, p.getTitle());
assertEquals(GHIssueState.OPEN, getRepository().getPullRequest(p.getNumber()).getState());
p.close();
assertEquals(GHIssueState.CLOSED, getRepository().getPullRequest(p.getNumber()).getState());
}
@Test
public void pullRequestReviews() throws Exception {
String name = "testPullRequestReviews";
GHPullRequest p = getRepository().createPullRequest(name, "test/stable", "master", "## test");
GHPullRequestReview draftReview = p.createReview()
.body("Some draft review")
.comment("Some niggle", "README.md", 1)
.create();
assertThat(draftReview.getState(), is(GHPullRequestReviewState.PENDING));
assertThat(draftReview.getBody(), is("Some draft review"));
assertThat(draftReview.getCommitId(), notNullValue());
List<GHPullRequestReview> reviews = p.listReviews().asList();
assertThat(reviews.size(), is(1));
GHPullRequestReview review = reviews.get(0);
assertThat(review.getState(), is(GHPullRequestReviewState.PENDING));
assertThat(review.getBody(), is("Some draft review"));
assertThat(review.getCommitId(), notNullValue());
draftReview.submit("Some review comment", GHPullRequestReviewEvent.COMMENT);
List<GHPullRequestReviewComment> comments = review.listReviewComments().asList();
assertEquals(1, comments.size());
GHPullRequestReviewComment comment = comments.get(0);
assertEquals("Some niggle", comment.getBody());
draftReview = p.createReview()
.body("Some new review")
.comment("Some niggle", "README.md", 1)
.create();
draftReview.delete();
}
@Test
public void pullRequestReviewComments() throws Exception {
String name = "pullRequestReviewComments";
GHPullRequest p = getRepository().createPullRequest(name, "test/stable", "master", "## test");
// System.out.println(p.getUrl());
assertTrue(p.listReviewComments().asList().isEmpty());
p.createReviewComment("Sample review comment", p.getHead().getSha(), "README.md", 1);
List<GHPullRequestReviewComment> comments = p.listReviewComments().asList();
assertEquals(1, comments.size());
GHPullRequestReviewComment comment = comments.get(0);
assertEquals("Sample review comment", comment.getBody());
comment.update("Updated review comment");
comments = p.listReviewComments().asList();
assertEquals(1, comments.size());
comment = comments.get(0);
assertEquals("Updated review comment", comment.getBody());
comment.delete();
comments = p.listReviewComments().asList();
assertTrue(comments.isEmpty());
}
@Test
public void testPullRequestReviewRequests() throws Exception {
String name = "testPullRequestReviewRequests";
GHPullRequest p = getRepository().createPullRequest(name, "test/stable", "master", "## test");
// System.out.println(p.getUrl());
assertTrue(p.getRequestedReviewers().isEmpty());
GHUser kohsuke2 = gitHub.getUser("kohsuke2");
p.requestReviewers(Collections.singletonList(kohsuke2));
p.refresh();
assertFalse(p.getRequestedReviewers().isEmpty());
}
@Test
public void testPullRequestTeamReviewRequests() throws Exception {
String name = "testPullRequestTeamReviewRequests";
GHPullRequest p = getRepository().createPullRequest(name, "test/stable", "master", "## test");
// System.out.println(p.getUrl());
assertTrue(p.getRequestedReviewers().isEmpty());
GHOrganization testOrg = gitHub.getOrganization("github-api-test-org");
GHTeam testTeam = testOrg.getTeamBySlug("dummy-team");
p.requestTeamReviewers(Collections.singletonList(testTeam));
int baseRequestCount = mockGitHub.getRequestCount();
p.refresh();
assertThat("We should not eagerly load organizations for teams",
mockGitHub.getRequestCount() - baseRequestCount , equalTo(1));
assertThat(p.getRequestedTeams().size(), equalTo(1));
assertThat("We should not eagerly load organizations for teams",
mockGitHub.getRequestCount() - baseRequestCount , equalTo(1));
assertThat("Org should be queried for automatically if asked for",
p.getRequestedTeams().get(0).getOrganization(), notNullValue());
assertThat("Request count should show lazy load occurred",
mockGitHub.getRequestCount() - baseRequestCount , equalTo(2));
}
@Test
public void mergeCommitSHA() throws Exception {
String name = "mergeCommitSHA";
GHRepository repo = getRepository();
GHPullRequest p = repo.createPullRequest(name, "test/mergeable_branch", "master", "## test");
int baseRequestCount = mockGitHub.getRequestCount();
assertThat(p.getMergeableNoRefresh(), nullValue());
assertThat("Used existing value",
mockGitHub.getRequestCount() - baseRequestCount , equalTo(0));
// mergeability computation takes time, this should still be null immediately after creation
assertThat(p.getMergeable(), nullValue());
assertThat("Asked for PR information",
mockGitHub.getRequestCount() - baseRequestCount , equalTo(1));
for (int i = 2; i <= 10; i++) {
if (Boolean.TRUE.equals(p.getMergeable()) && p.getMergeCommitSha() != null) {
assertThat("Asked for PR information",
mockGitHub.getRequestCount() - baseRequestCount , equalTo(i));
// make sure commit exists
GHCommit commit = repo.getCommit(p.getMergeCommitSha());
assertNotNull(commit);
assertThat("Asked for PR information",
mockGitHub.getRequestCount() - baseRequestCount , equalTo(i + 1));
return;
}
// mergeability computation takes time. give it more chance
Thread.sleep(1000);
}
// hmm?
fail();
}
@Test
public void squashMerge() throws Exception {
String name = "squashMerge";
String branchName = "test/" + name;
GHRef masterRef = getRepository().getRef("heads/master");
GHRef branchRef = getRepository().createRef("refs/heads/" + branchName, masterRef.getObject().getSha());
getRepository().createContent(name, name, name, branchName);
Thread.sleep(1000);
GHPullRequest p = getRepository().createPullRequest(name, branchName, "master", "## test squash");
Thread.sleep(1000);
p.merge("squash merge", null, GHPullRequest.MergeMethod.SQUASH);
}
@Test
public void updateContentSquashMerge() throws Exception {
String name = "updateContentSquashMerge";
String branchName = "test/" + name;
GHRef masterRef = getRepository().getRef("heads/master");
GHRef branchRef = getRepository().createRef("refs/heads/" + branchName, masterRef.getObject().getSha());
GHContentUpdateResponse response = getRepository().createContent(name, name, name, branchName);
Thread.sleep(1000);
getRepository().createContent()
.content(name + name)
.path(name)
.branch(branchName)
.message(name)
.sha(response.getContent().getSha())
.commit();
GHPullRequest p = getRepository().createPullRequest(name, branchName, "master", "## test squash");
Thread.sleep(1000);
p.merge("squash merge", null, GHPullRequest.MergeMethod.SQUASH);
}
@Test
public void queryPullRequestsQualifiedHead() throws Exception {
GHRepository repo = getRepository();
// Create PRs from two different branches to master
repo.createPullRequest("queryPullRequestsQualifiedHead_stable", "test/stable", "master", null);
repo.createPullRequest("queryPullRequestsQualifiedHead_rc", "test/rc", "master", null);
// Query by one of the heads and make sure we only get that branch's PR back.
List<GHPullRequest> prs = repo.queryPullRequests().state(GHIssueState.OPEN).head("github-api-test-org:test/stable").base("master").list().asList();
assertNotNull(prs);
assertEquals(1, prs.size());
assertEquals("test/stable", prs.get(0).getHead().getRef());
}
@Test
public void queryPullRequestsUnqualifiedHead() throws Exception {
GHRepository repo = getRepository();
// Create PRs from two different branches to master
repo.createPullRequest("queryPullRequestsUnqualifiedHead_stable", "test/stable", "master", null);
repo.createPullRequest("queryPullRequestsUnqualifiedHead_rc", "test/rc", "master", null);
// Query by one of the heads and make sure we only get that branch's PR back.
List<GHPullRequest> prs = repo.queryPullRequests().state(GHIssueState.OPEN).head("test/stable").base("master").list().asList();
assertNotNull(prs);
assertEquals(1, prs.size());
assertEquals("test/stable", prs.get(0).getHead().getRef());
}
@Test
// Requires push access to the test repo to pass
public void setLabels() throws Exception {
GHPullRequest p = getRepository().createPullRequest("setLabels", "test/stable", "master", "## test");
String label = "setLabels_label_name";
p.setLabels(label);
Collection<GHLabel> labels = getRepository().getPullRequest(p.getNumber()).getLabels();
assertEquals(1, labels.size());
assertEquals(label, labels.iterator().next().getName());
}
@Test
// Requires push access to the test repo to pass
public void setAssignee() throws Exception {
GHPullRequest p = getRepository().createPullRequest("setAssignee", "test/stable", "master", "## test");
GHMyself user = gitHub.getMyself();
p.assignTo(user);
assertEquals(user, getRepository().getPullRequest(p.getNumber()).getAssignee());
}
@Test
public void getUserTest() throws IOException {
GHPullRequest p = getRepository().createPullRequest("getUserTest", "test/stable", "master", "## test");
GHPullRequest prSingle = getRepository().getPullRequest(p.getNumber());
assertNotNull(prSingle.getUser().root);
prSingle.getMergeable();
assertNotNull(prSingle.getUser().root);
PagedIterable<GHPullRequest> ghPullRequests = getRepository().listPullRequests(GHIssueState.OPEN);
for (GHPullRequest pr : ghPullRequests) {
assertNotNull(pr.getUser().root);
pr.getMergeable();
assertNotNull(pr.getUser().root);
}
}
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

@@ -0,0 +1,220 @@
package org.kohsuke.github;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
import java.util.NoSuchElementException;
public class GHRepositoryStatisticsTest extends AbstractGitHubWireMockTest {
public static int MAX_ITERATIONS = 3;
public static int SLEEP_INTERVAL = 5000;
@Test
public void testContributorStats() throws IOException, InterruptedException {
// get the statistics
PagedIterable<GHRepositoryStatistics.ContributorStats> stats =
getRepository().getStatistics().getContributorStats();
// check that the statistics were eventually retrieved
if (stats == null) {
fail("Statistics took too long to retrieve.");
return;
}
// check the statistics are accurate
List<GHRepositoryStatistics.ContributorStats> list = stats.asList();
assertEquals(99, list.size());
// find a particular developer
// TODO: Add an accessor method for this instead of having use a loop.
boolean developerFound = false;
final String authorLogin = "kohsuke";
for (GHRepositoryStatistics.ContributorStats statsForAuthor: list) {
if (authorLogin.equals(statsForAuthor.getAuthor().getLogin())) {
assertEquals(715, statsForAuthor.getTotal());
List<GHRepositoryStatistics.ContributorStats.Week> weeks =
statsForAuthor.getWeeks();
assertEquals(494, weeks.size());
try {
// check a particular week
// TODO: Maybe add a convenience method to get the week
// containing a certain date (Java.Util.Date).
GHRepositoryStatistics.ContributorStats.Week week =
statsForAuthor.getWeek(1541289600);
assertEquals(63, week.getNumberOfAdditions());
assertEquals(56, week.getNumberOfDeletions());
assertEquals(5, week.getNumberOfCommits());
}
catch(NoSuchElementException e) {
fail("Did not find week 1546128000");
}
developerFound = true;
break;
}
}
assertTrue("Did not find author " + authorLogin, developerFound);
}
@Test
@SuppressWarnings("SleepWhileInLoop")
public void testCommitActivity() throws IOException, InterruptedException {
// get the statistics
PagedIterable<GHRepositoryStatistics.CommitActivity> stats = null;
for (int i = 0; i < MAX_ITERATIONS; i += 1) {
stats = getRepository().getStatistics().getCommitActivity();
if(stats == null) {
Thread.sleep(SLEEP_INTERVAL);
}
else {
break;
}
}
// check that the statistics were eventually retrieved
if (stats == null) {
fail("Statistics took too long to retrieve.");
return;
}
// check the statistics are accurate
List<GHRepositoryStatistics.CommitActivity> list = stats.asList();
// TODO: Return this as a map with the timestamp as the key.
// Either that or wrap in an object an accessor method.
Boolean foundWeek = false;
for (GHRepositoryStatistics.CommitActivity item: list) {
if (item.getWeek() == 1566691200) {
assertEquals(6, item.getTotal());
List<Integer> days = item.getDays();
assertEquals(0, (long)days.get(0));
assertEquals(0, (long)days.get(1));
assertEquals(1, (long)days.get(2));
assertEquals(0, (long)days.get(3));
assertEquals(0, (long)days.get(4));
assertEquals(1, (long)days.get(5));
assertEquals(4, (long)days.get(6));
foundWeek = true;
break;
}
}
assertTrue("Could not find week starting 1546128000", foundWeek);
}
@Test
@SuppressWarnings("SleepWhileInLoop")
public void testCodeFrequency() throws IOException, InterruptedException {
// get the statistics
List<GHRepositoryStatistics.CodeFrequency> stats = null;
for (int i = 0; i < MAX_ITERATIONS; i += 1) {
stats = getRepository().getStatistics().getCodeFrequency();
if(stats == null) {
Thread.sleep(SLEEP_INTERVAL);
}
else {
break;
}
}
// check that the statistics were eventually retrieved
if (stats == null) {
fail("Statistics took too long to retrieve.");
return;
}
// check the statistics are accurate
// TODO: Perhaps return this as a map with the timestamp as the key?
// Either that or wrap in an object with accessor methods.
Boolean foundWeek = false;
for (GHRepositoryStatistics.CodeFrequency item: stats) {
if (item.getWeekTimestamp() == 1535241600) {
assertEquals(185, item.getAdditions());
assertEquals(-243, item.getDeletions());
foundWeek = true;
break;
}
}
assertTrue("Could not find week starting 1535241600", foundWeek);
}
@Test
public void testParticipation() throws IOException, InterruptedException {
// get the statistics
GHRepositoryStatistics.Participation stats = null;
for (int i = 0; i < MAX_ITERATIONS; i += 1) {
stats = getRepository().getStatistics().getParticipation();
if(stats == null) {
Thread.sleep(SLEEP_INTERVAL);
}
else {
break;
}
}
// check that the statistics were eventually retrieved
if (stats == null) {
fail("Statistics took too long to retrieve.");
return;
}
// check the statistics are accurate
List<Integer> allCommits = stats.getAllCommits();
assertEquals(52, allCommits.size());
assertEquals(2, (int)allCommits.get(2));
List<Integer> ownerCommits = stats.getOwnerCommits();
assertEquals(52, ownerCommits.size());
// The values depend on who is running the test.
}
@Test
@SuppressWarnings("SleepWhileInLoop")
public void testPunchCard() throws IOException, InterruptedException {
// get the statistics
List<GHRepositoryStatistics.PunchCardItem> stats = null;
for (int i = 0; i < MAX_ITERATIONS; i += 1) {
stats = getRepository().getStatistics().getPunchCard();
if(stats == null) {
Thread.sleep(SLEEP_INTERVAL);
}
else {
break;
}
}
// check that the statistics were eventually retrieved
if (stats == null) {
fail("Statistics took too long to retrieve.");
return;
}
// check the statistics are accurate
Boolean hourFound = false;
for (GHRepositoryStatistics.PunchCardItem item: stats) {
if(item.getDayOfWeek() == 2 && item.getHourOfDay() == 10) {
// TODO: Make an easier access method. Perhaps wrap in an
// object and have a method such as GetCommits(1, 16).
assertEquals(16, item.getNumberOfCommits());
hourFound = true;
break;
}
}
assertTrue("Hour 10 for Day 2 not found.", hourFound);
}
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

@@ -0,0 +1,277 @@
package org.kohsuke.github;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.*;
import static org.junit.Assume.assumeFalse;
/**
* @author Liam Newman
*/
public class GHRepositoryTest extends AbstractGitHubWireMockTest {
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");
}
@Test
public void archive() throws Exception {
snapshotNotAllowed();
// Archive is a one-way action in the API.
// We do thi this one
GHRepository repo = getRepository();
assertThat(repo.isArchived(), is(false));
repo.archive();
assertThat(repo.isArchived(), is(true));
assertThat(getRepository().isArchived(), is(true));
}
@Test
public void getBranch_URLEncoded() throws Exception {
GHRepository repo = getRepository();
GHBranch branch = repo.getBranch("test/#UrlEncode");
assertThat(branch.getName(), is("test/#UrlEncode"));
}
@Test
public void subscription() throws Exception {
GHRepository r = getRepository();
assertNull(r.getSubscription());
GHSubscription s = r.subscribe(true, false);
assertEquals(s.getRepository(), r);
s.delete();
assertNull(r.getSubscription());
}
@Test
public void testSetPublic() throws Exception {
kohsuke();
GHUser myself = gitHub.getMyself();
String repoName = "test-repo-public";
GHRepository repo = gitHub.createRepository(repoName).private_(false).create();
try {
assertFalse(repo.isPrivate());
repo.setPrivate(true);
assertTrue(myself.getRepository(repoName).isPrivate());
repo.setPrivate(false);
assertFalse(myself.getRepository(repoName).isPrivate());
} finally {
repo.delete();
}
}
@Test
public void listContributors() throws IOException {
GHRepository r = gitHub.getOrganization("github-api").getRepository("github-api");
int i = 0;
boolean kohsuke = false;
for (GHRepository.Contributor c : r.listContributors()) {
if (c.getLogin().equals("kohsuke")) {
assertTrue(c.getContributions() > 0);
kohsuke = true;
}
if (i++ > 5) {
break;
}
}
assertTrue(kohsuke);
}
@Test
public void getPermission() throws Exception {
kohsuke();
GHRepository r = gitHub.getRepository("github-api-test-org/test-permission");
assertEquals(GHPermissionType.ADMIN, r.getPermission("kohsuke"));
assertEquals(GHPermissionType.READ, r.getPermission("dude"));
r = gitHub.getOrganization("apache").getRepository("groovy");
try {
r.getPermission("jglick");
fail();
} catch (HttpException x) {
//x.printStackTrace(); // good
assertEquals(403, x.getResponseCode());
}
if (false) {
// can't easily test this; there's no private repository visible to the test user
r = gitHub.getOrganization("cloudbees").getRepository("private-repo-not-writable-by-me");
try {
r.getPermission("jglick");
fail();
} catch (FileNotFoundException x) {
x.printStackTrace(); // good
}
}
}
@Test
public void LatestRepositoryExist() {
try {
// add the repository that have latest release
GHRelease release = gitHub.getRepository("kamontat/CheckIDNumber").getLatestRelease();
assertEquals("v3.0", release.getTagName());
} catch (IOException e) {
e.printStackTrace();
fail();
}
}
@Test
public void LatestRepositoryNotExist() {
try {
// add the repository that `NOT` have latest release
GHRelease release = gitHub.getRepository("kamontat/Java8Example").getLatestRelease();
assertNull(release);
} catch (IOException e) {
e.printStackTrace();
fail();
}
}
@Test
public void listReleases() throws IOException {
PagedIterable<GHRelease> releases = gitHub.getOrganization("github").getRepository("hub").listReleases();
assertTrue(releases.iterator().hasNext());
}
@Test
public void getReleaseExists() throws IOException {
GHRelease release = gitHub.getOrganization("github").getRepository("hub").getRelease(6839710);
assertEquals("v2.3.0-pre10", release.getTagName());
}
@Test
public void getReleaseDoesNotExist() throws IOException {
GHRelease release = gitHub.getOrganization("github").getRepository("hub").getRelease(Long.MAX_VALUE);
assertNull(release);
}
@Test
public void getReleaseByTagNameExists() throws IOException {
GHRelease release = gitHub.getOrganization("github").getRepository("hub").getReleaseByTagName("v2.3.0-pre10");
assertNotNull(release);
assertEquals("v2.3.0-pre10", release.getTagName());
}
@Test
public void getReleaseByTagNameDoesNotExist() throws IOException {
GHRelease release = getRepository().getReleaseByTagName("foo-bar-baz");
assertNull(release);
}
@Test
public void listLanguages() throws IOException {
GHRepository r = gitHub.getRepository("github-api/github-api");
String mainLanguage = r.getLanguage();
assertTrue(r.listLanguages().containsKey(mainLanguage));
}
@Test // Issue #261
public void listEmptyContributors() throws IOException {
for (GHRepository.Contributor c : gitHub.getRepository(GITHUB_API_TEST_ORG + "/empty").listContributors()) {
// System.out.println(c);
fail("This list should be empty, but should return a valid empty iterable.");
}
}
@Test
public void searchRepositories() throws Exception {
PagedSearchIterable<GHRepository> r = gitHub.searchRepositories().q("tetris").language("assembly").sort(GHRepositorySearchBuilder.Sort.STARS).list();
GHRepository u = r.iterator().next();
// System.out.println(u.getName());
assertNotNull(u.getId());
assertEquals("Assembly", u.getLanguage());
assertTrue(r.getTotalCount() > 0);
}
@Test // issue #162
public void testIssue162() throws Exception {
GHRepository r = gitHub.getRepository("github-api/github-api");
List<GHContent> contents = r.getDirectoryContent("", "gh-pages");
for (GHContent content : contents) {
if (content.isFile()) {
String content1 = content.getContent();
String content2 = r.getFileContent(content.getPath(), "gh-pages").getContent();
// System.out.println(content.getPath());
assertEquals(content1, content2);
}
}
}
@Test
public void markDown() throws Exception {
assertEquals("<p><strong>Test日本語</strong></p>", IOUtils.toString(gitHub.renderMarkdown("**Test日本語**")).trim());
String actual = IOUtils.toString(gitHub.getRepository("github-api/github-api").renderMarkdown("@kohsuke to fix issue #1", MarkdownMode.GFM));
// System.out.println(actual);
assertTrue(actual.contains("href=\"https://github.com/kohsuke\""));
assertTrue(actual.contains("href=\"https://github.com/github-api/github-api/pull/1\""));
assertTrue(actual.contains("class=\"user-mention\""));
assertTrue(actual.contains("class=\"issue-link "));
assertTrue(actual.contains("to fix issue"));
}
@Test
public void getMergeOptions() throws IOException {
GHRepository r = getTempRepository();
assertNotNull(r.isAllowMergeCommit());
assertNotNull(r.isAllowRebaseMerge());
assertNotNull(r.isAllowSquashMerge());
}
@Test
public void setMergeOptions() throws IOException {
// String repoName = "github-api-test-org/test-mergeoptions";
GHRepository r = getTempRepository();
// at least one merge option must be selected
// flip all the values at least once
r.allowSquashMerge(true);
r.allowMergeCommit(false);
r.allowRebaseMerge(false);
r = gitHub.getRepository(r.getFullName());
assertFalse(r.isAllowMergeCommit());
assertFalse(r.isAllowRebaseMerge());
assertTrue(r.isAllowSquashMerge());
// flip the last value
r.allowMergeCommit(true);
r.allowRebaseMerge(true);
r.allowSquashMerge(false);
r = gitHub.getRepository(r.getFullName());
assertTrue(r.isAllowMergeCommit());
assertTrue(r.isAllowRebaseMerge());
assertFalse(r.isAllowSquashMerge());
}
@Test
public void testListTopics() throws Exception {
List<String> topics = getRepository(gitHub).listTopics();
assertTrue(topics.contains("api-test-dummy"));
}
}

View File

@@ -0,0 +1,35 @@
package org.kohsuke.github;
import org.junit.Test;
import java.io.IOException;
import java.util.Random;
public class GHTeamTest extends AbstractGitHubWireMockTest {
@Test
public void testSetDescription() throws IOException {
String description = "Updated by API Test";
String teamSlug = "dummy-team";
// Set the description.
GHTeam team = gitHub.getOrganization(GITHUB_API_TEST_ORG).getTeamBySlug(teamSlug);
team.setDescription(description);
// Check that it was set correctly.
team = gitHub.getOrganization(GITHUB_API_TEST_ORG).getTeamBySlug(teamSlug);
assertEquals(description, team.getDescription());
description += "Modified";
// Set the description.
team.setDescription(description);
// Check that it was set correctly.
team = gitHub.getOrganization(GITHUB_API_TEST_ORG).getTeamBySlug(teamSlug);
assertEquals(description, team.getDescription());
}
}

View File

@@ -0,0 +1,85 @@
package org.kohsuke.github;
import org.junit.Test;
import java.io.IOException;
import java.util.*;
import static org.hamcrest.CoreMatchers.*;
public class GHUserTest extends AbstractGitHubWireMockTest {
@Test
public void listFollowsAndFollowers() throws IOException {
GHUser u = gitHub.getUser("rtyler");
assertNotEquals(
count30(u.listFollowers()),
count30(u.listFollows()));
}
private Set<GHUser> count30(PagedIterable<GHUser> l) {
Set<GHUser> users = new HashSet<GHUser>();
PagedIterator<GHUser> itr = l.iterator();
for (int i = 0; i < 30 && itr.hasNext(); i++) {
users.add(itr.next());
}
assertEquals(30, users.size());
return users;
}
@Test
public void getKeys() throws IOException {
GHUser u = gitHub.getUser("rtyler");
List<GHKey> ghKeys = new ArrayList<>(u.getKeys());
assertEquals(3, ghKeys.size());
Collections.sort(ghKeys, new Comparator<GHKey>() {
@Override
public int compare(GHKey ghKey, GHKey t1) {
return ghKey.getId() - t1.getId();
}
});
assertEquals(1066173, ghKeys.get(0).getId());
assertEquals("ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAueiy12T5bvFhsc9YjfLc3aVIxgySd3gDxQWy/bletIoZL8omKmzocBYJ7F58U1asoyfWsy2ToTOY8jJp1eToXmbD6L5+xvHba0A7djYh9aQRrFam7doKQ0zp0ZSUF6+R1v0OM4nnWqK4n2ECIYd+Bdzrp+xA5+XlW3ZSNzlnW2BeWznzmgRMcp6wI+zQ9GMHWviR1cxpml5Z6wrxTZ0aX91btvnNPqoOGva976B6e6403FOEkkIFTk6CC1TFKwc/VjbqxYBg4kU0JhiTP+iEZibcQrYjWdYUgAotYbFVe5/DneHMLNsMPdeihba4PUwt62rXyNegenuCRmCntLcaFQ==",
ghKeys.get(0).getKey());
assertEquals(28136459, ghKeys.get(1).getId());
assertEquals("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDTU0s5OKCC6VpKZGL9NJD4mNLY0AtujkVB1JkkuQ4OkMi2YGUHJtGhTbTwEVhNxpm0x2dM5KSzse6MLDYuGBW0qkE/VVuD9+9I73hbq461KqP0+WlupNh+Qc86kbiLBDv64+vWc+50mp1dbINpoM5xvaPYxgjnemydPv7vu5bhCHBugW7aN8VcLgfFgcp8vZCEanMtd3hIRjRU8v8Skk233ZGu1bXkG8iIOBQPabvEtZ0VDMg9pT3Q1R6lnnKqfCwHXd6zP6uAtejFSxvKRGKpu3OLGQMHwk7NlImVuhkVdaEFBq7pQtpOaGuP2eLKcN1wy5jsTYE+ZB6pvHCi2ecb",
ghKeys.get(1).getKey());
assertEquals(31452581, ghKeys.get(2).getId());
assertEquals("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC3JhH2FZBDmHLjXTcBoV6tdcYKmsQ7sgu8k1RsUhwxGsXm65+Cuas6GcMVoA1DncKfJGQkulHDFiTxIROIBmedh9/otHWBlZ4HqYZ4MQ1A8W5quULkXwX/kF+UdRBUxFvjigibEbuHB+LARVxRRzFlPnTSE9rAfAv8OOEsb3lNUGT/IGhN8w1vwe8GclB90tgqN1RBDgrVqwLFwn5AfrW9kUIa2f2oT4RjYu1OrhKhVIIzfHADo85aD+s8wEhqwI96BCJG3qTWrypoHwBUoj1O6Ak5CGc1iKz9o8XyTMjudRt2ddCjfOtxsuwSlTbVtQXJGIpgKviX1sgh4pPvGh7BVAFP+mdAK4F+mEugDnuj47GO/K5KGGDRCL56kh9+h28l4q/+fZvp7DhtmSN2EzrVAdQFskF8yY/6Xit/aAvjeKm03DcjbylSXbG26EJefaLHlwYFq2mUFRMak25wuuCZS71GF3RC3Sl/bMoxBKRYkyfYtGafeaYTFNGn8Dbd+hfVUCz31ebI8cvmlQR5b5AbCre3T7HTVgw8FKbAxWRf1Fio56PnqHsj+sT1KVj255Zo1F8iD9GrgERSVAlkh5bY/CKszQ8ZSd01c9Qp2a47/gR7XAAbxhzGHP+cSOlrqDlJ24fbPtcpVsM0llqKUcxpmoOBFNboRmE1QqnSmAf9ww==",
ghKeys.get(2).getKey());
}
@Test
public void listPublicRepositories() throws IOException {
GHUser user = gitHub.getUser("kohsuke");
Iterator<GHRepository> itr = user.listRepositories().iterator();
int i = 0;
for (; i < 115; i++) {
assertTrue(itr.hasNext());
GHRepository r = itr.next();
// System.out.println(r.getFullName());
assertNotNull(r.getUrl());
assertNotEquals(0L, r.getId());
}
assertThat(i, equalTo(115));
}
@Test
public void listPublicRepositoriesPageSize62() throws IOException {
GHUser user = gitHub.getUser("kohsuke");
Iterator<GHRepository> itr = user.listRepositories().withPageSize(62).iterator();
int i = 0;
for (; i < 115; i++) {
assertTrue(itr.hasNext());
GHRepository r = itr.next();
// System.out.println(r.getFullName());
assertNotNull(r.getUrl());
assertNotEquals(0L, r.getId());
}
assertThat(i, equalTo(115));
}
}

View File

@@ -1,26 +1,32 @@
package org.kohsuke.github;
import com.github.tomakehurst.wiremock.stubbing.Scenario;
import org.junit.Test;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.core.Is.is;
/**
* @author Kohsuke Kawaguchi
*/
public class GistTest extends AbstractGitHubApiTestBase {
public class GistTest extends AbstractGitHubWireMockTest {
/**
* CRUD operation.
*/
@Test
public void lifecycleTest() throws Exception {
GHGist gist = gitHub.createGist()
.public_(false)
.description("Test Gist")
.file("abc.txt","abc")
.file("def.txt","def")
.create();
.public_(false)
.description("Test Gist")
.file("abc.txt", "abc")
.file("def.txt", "def")
.create();
assertThat(gist.getCreatedAt(), is(notNullValue()));
assertNotNull(gist.getCreatedAt());
assertNotNull(gist.getUpdatedAt());
assertNotNull(gist.getCommentsUrl());
assertNotNull(gist.getCommitsUrl());
assertNotNull(gist.getGitPullUrl());
@@ -33,10 +39,12 @@ public class GistTest extends AbstractGitHubApiTestBase {
@Test
public void starTest() throws Exception {
GHGist gist = gitHub.getGist("9903708");
assertEquals("rtyler",gist.getOwner().getLogin());
assertEquals("rtyler", gist.getOwner().getLogin());
gist.star();
assertTrue(gist.isStarred());
gist.unstar();
assertFalse(gist.isStarred());
@@ -62,10 +70,10 @@ public class GistTest extends AbstractGitHubApiTestBase {
assertTrue(gist.isPublic());
assertEquals(1,gist.getFiles().size());
assertEquals(1, gist.getFiles().size());
GHGistFile f = gist.getFile("keybase.md");
assertEquals("text/plain", f.getType());
assertEquals("text/markdown", f.getType());
assertEquals("Markdown", f.getLanguage());
assertTrue(f.getContent().contains("### Keybase proof"));
assertNotNull(f.getContent());

View File

@@ -0,0 +1,377 @@
package org.kohsuke.github;
import org.junit.Test;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;
import static org.hamcrest.CoreMatchers.*;
/**
* Unit test for {@link GitHub}.
*/
public class GitHubConnectionTest extends AbstractGitHubWireMockTest {
public GitHubConnectionTest() {
useDefaultGitHub = false;
}
@Test
public void testOffline() throws Exception {
GitHub hub = GitHub.offline();
assertEquals("https://api.github.invalid/test", hub.getApiURL("/test").toString());
assertTrue(hub.isAnonymous());
try {
hub.getRateLimit();
fail("Offline instance should always fail");
} catch (IOException e) {
assertEquals("Offline", e.getMessage());
}
}
@Test
public void testGitHubServerWithHttp() throws Exception {
GitHub hub = GitHub.connectToEnterprise("http://enterprise.kohsuke.org/api/v3", "bogus", "bogus");
assertEquals("http://enterprise.kohsuke.org/api/v3/test", hub.getApiURL("/test").toString());
}
@Test
public void testGitHubServerWithHttps() throws Exception {
GitHub hub = GitHub.connectToEnterprise("https://enterprise.kohsuke.org/api/v3", "bogus", "bogus");
assertEquals("https://enterprise.kohsuke.org/api/v3/test", hub.getApiURL("/test").toString());
}
@Test
public void testGitHubServerWithoutServer() throws Exception {
GitHub hub = GitHub.connectUsingPassword("kohsuke", "bogus");
assertEquals("https://api.github.com/test", hub.getApiURL("/test").toString());
}
@Test
public void testGitHubBuilderFromEnvironment() throws IOException {
Map<String, String> props = new HashMap<String, String>();
props.put("login", "bogus");
props.put("oauth", "bogus");
props.put("password", "bogus");
props.put("jwt", "bogus");
setupEnvironment(props);
GitHubBuilder builder = GitHubBuilder.fromEnvironment();
assertEquals("bogus", builder.user);
assertEquals("bogus", builder.oauthToken);
assertEquals("bogus", builder.password);
assertEquals("bogus", builder.jwtToken);
}
@Test
public void testGitHubBuilderFromCustomEnvironment() throws IOException {
Map<String, String> props = new HashMap<String, String>();
props.put("customLogin", "bogusLogin");
props.put("customOauth", "bogusOauth");
props.put("customPassword", "bogusPassword");
props.put("customEndpoint", "bogusEndpoint");
setupEnvironment(props);
GitHubBuilder builder = GitHubBuilder.fromEnvironment("customLogin", "customPassword", "customOauth", "customEndpoint");
assertEquals("bogusLogin", builder.user);
assertEquals("bogusOauth", builder.oauthToken);
assertEquals("bogusPassword", builder.password);
assertEquals("bogusEndpoint", builder.endpoint);
}
@Test
public void testGithubBuilderWithAppInstallationToken() throws Exception{
GitHubBuilder builder = new GitHubBuilder().withAppInstallationToken("bogus");
assertEquals("bogus", builder.oauthToken);
assertEquals("", builder.user);
// test authorization header is set as in the RFC6749
GitHub github = builder.build();
assertEquals("token bogus",github.encodedAuthorization);
assertEquals("",github.login);
}
@Test
public void testGitHubRateLimit() throws Exception {
assertThat(mockGitHub.getRequestCount(), equalTo(0));
GHRateLimit rateLimit = null;
GitHub hub = null;
Date lastReset = new Date(System.currentTimeMillis() / 1000L);
int lastRemaining = 5000;
// Give this a moment
Thread.sleep(1000);
// -------------------------------------------------------------
// /user gets response with rate limit information
hub = getGitHubBuilder()
.withEndpoint(mockGitHub.apiServer().baseUrl()).build();
hub.getMyself();
assertThat(mockGitHub.getRequestCount(), equalTo(1));
// Since we already had rate limit info these don't request again
rateLimit = hub.lastRateLimit();
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.limit, equalTo(5000));
lastRemaining = rateLimit.remaining;
// Because we're gettting this from old mocked info, it will be an older date
//assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(-1));
lastReset = rateLimit.getResetDate();
GHRateLimit headerRateLimit = rateLimit;
// Give this a moment
Thread.sleep(1000);
// ratelimit() uses headerRateLimit if available
assertThat(hub.rateLimit(), equalTo(headerRateLimit));
assertThat(mockGitHub.getRequestCount(), equalTo(1));
// Give this a moment
Thread.sleep(1000);
// Always requests new info
rateLimit = hub.getRateLimit();
assertThat(mockGitHub.getRequestCount(), equalTo(2));
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.limit, equalTo(5000));
// rate limit request is free
assertThat(rateLimit.remaining, equalTo(lastRemaining));
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(0));
// Give this a moment
Thread.sleep(1000);
// Always requests new info
rateLimit = hub.getRateLimit();
assertThat(mockGitHub.getRequestCount(), equalTo(3));
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.limit, equalTo(5000));
// rate limit request is free
assertThat(rateLimit.remaining, equalTo(lastRemaining));
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(0));
hub.getOrganization(GITHUB_API_TEST_ORG);
assertThat(mockGitHub.getRequestCount(), equalTo(4));
assertThat(hub.lastRateLimit(), not(equalTo(headerRateLimit)));
rateLimit = hub.lastRateLimit();
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.limit, equalTo(5000));
// Org costs limit to query
assertThat(rateLimit.remaining, equalTo(lastRemaining - 1));
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(0));
lastReset = rateLimit.getResetDate();
headerRateLimit = rateLimit;
// ratelimit() should prefer headerRateLimit when it is most recent
assertThat(hub.rateLimit(), equalTo(headerRateLimit));
assertThat(mockGitHub.getRequestCount(), equalTo(4));
// Always requests new info
rateLimit = hub.getRateLimit();
assertThat(mockGitHub.getRequestCount(), equalTo(5));
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.limit, equalTo(5000));
// Org costs limit to query
assertThat(rateLimit.remaining, equalTo(lastRemaining - 1));
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(0));
// ratelimit() should prefer headerRateLimit when getRateLimit() fails
// BUG: When getRateLimit() succeeds, it should reset the ratelimit() to the new value
// assertThat(hub.rateLimit(), equalTo(rateLimit));
// assertThat(hub.rateLimit(), not(equalTo(headerRateLimit)));
assertThat(hub.rateLimit(), equalTo(headerRateLimit));
assertThat(mockGitHub.getRequestCount(), equalTo(5));
}
@Test
public void testGitHubEnterpriseDoesNotHaveRateLimit() throws Exception {
// Customized response that results in file not found the same as GitHub Enterprise
snapshotNotAllowed();
assertThat(mockGitHub.getRequestCount(), equalTo(0));
GHRateLimit rateLimit = null;
GitHub hub = null;
Date lastReset = new Date(System.currentTimeMillis() / 1000L);
// Give this a moment
Thread.sleep(1000);
// -------------------------------------------------------------
// Before any queries, rate limit starts as null but may be requested
hub = GitHub.connectToEnterprise(mockGitHub.apiServer().baseUrl(), "bogus", "bogus");
assertThat(mockGitHub.getRequestCount(), equalTo(0));
assertThat(hub.lastRateLimit(), nullValue());
rateLimit = hub.rateLimit();
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.limit, equalTo(1000000));
assertThat(rateLimit.remaining, equalTo(1000000));
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(1));
lastReset = rateLimit.getResetDate();
assertThat(mockGitHub.getRequestCount(), equalTo(1));
// last is still null, because it actually means lastHeaderRateLimit
assertThat(hub.lastRateLimit(), nullValue());
assertThat(mockGitHub.getRequestCount(), equalTo(1));
// Give this a moment
Thread.sleep(1000);
// -------------------------------------------------------------
// First call to /user gets response without rate limit information
hub = GitHub.connectToEnterprise(mockGitHub.apiServer().baseUrl(), "bogus", "bogus");
hub.getMyself();
assertThat(mockGitHub.getRequestCount(), equalTo(2));
assertThat(hub.lastRateLimit(), nullValue());
rateLimit = hub.rateLimit();
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.limit, equalTo(1000000));
assertThat(rateLimit.remaining, equalTo(1000000));
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(1));
lastReset = rateLimit.getResetDate();
assertThat(mockGitHub.getRequestCount(), equalTo(3));
// Give this a moment
Thread.sleep(1000);
// Always requests new info
rateLimit = hub.getRateLimit();
assertThat(mockGitHub.getRequestCount(), equalTo(4));
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.limit, equalTo(1000000));
assertThat(rateLimit.remaining, equalTo(1000000));
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(1));
// Give this a moment
Thread.sleep(1000);
// last is still null, because it actually means lastHeaderRateLimit
assertThat(hub.lastRateLimit(), nullValue());
// ratelimit() tries not to make additional requests, uses queried rate limit since header not available
Thread.sleep(1000);
assertThat(hub.rateLimit(), equalTo(rateLimit));
// -------------------------------------------------------------
// Second call to /user gets response with rate limit information
hub = GitHub.connectToEnterprise(mockGitHub.apiServer().baseUrl(), "bogus", "bogus");
hub.getMyself();
assertThat(mockGitHub.getRequestCount(), equalTo(5));
// Since we already had rate limit info these don't request again
rateLimit = hub.lastRateLimit();
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.limit, equalTo(5000));
assertThat(rateLimit.remaining, equalTo(4978));
// Because we're gettting this from old mocked info, it will be an older date
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(-1));
lastReset = rateLimit.getResetDate();
GHRateLimit headerRateLimit = rateLimit;
// Give this a moment
Thread.sleep(1000);
// ratelimit() uses headerRateLimit if available
assertThat(hub.rateLimit(), equalTo(headerRateLimit));
assertThat(mockGitHub.getRequestCount(), equalTo(5));
// Give this a moment
Thread.sleep(1000);
// Always requests new info
rateLimit = hub.getRateLimit();
assertThat(mockGitHub.getRequestCount(), equalTo(6));
assertThat(rateLimit, notNullValue());
assertThat(rateLimit.limit, equalTo(1000000));
assertThat(rateLimit.remaining, equalTo(1000000));
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(1));
// Give this a moment
Thread.sleep(1000);
// ratelimit() should prefer headerRateLimit when getRateLimit fails
assertThat(hub.rateLimit(), equalTo(headerRateLimit));
assertThat(mockGitHub.getRequestCount(), equalTo(6));
}
@Test
public void testGitHubIsApiUrlValid() throws IOException {
GitHub hub = GitHub.connectAnonymously();
//GitHub github = GitHub.connectToEnterpriseAnonymously("https://github.mycompany.com/api/v3/");
try {
hub.checkApiUrlValidity();
} catch (IOException ioe) {
assertTrue(ioe.getMessage().contains("private mode enabled"));
}
}
/*
* Copied from StackOverflow: http://stackoverflow.com/a/7201825/2336755
*
* This allows changing the in memory process environment.
*
* Its used to wire in values for the github credentials to test that the GitHubBuilder works properly to resolve them.
*/
private void setupEnvironment(Map<String, String> newenv) {
try {
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
theEnvironmentField.setAccessible(true);
Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
env.putAll(newenv);
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
theCaseInsensitiveEnvironmentField.setAccessible(true);
Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
cienv.putAll(newenv);
} catch (NoSuchFieldException e) {
try {
Class[] classes = Collections.class.getDeclaredClasses();
Map<String, String> env = System.getenv();
for (Class cl : classes) {
if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Object obj = field.get(env);
Map<String, String> map = (Map<String, String>) obj;
map.clear();
map.putAll(newenv);
}
}
} catch (Exception e2) {
e2.printStackTrace();
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
}

View File

@@ -0,0 +1,79 @@
package org.kohsuke.github;
import org.junit.Assert;
import org.junit.Test;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.TimeZone;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
/**
* Unit test for {@link GitHub} static helpers.
*
* @author Liam Newman
*/
public class GitHubStaticTest extends Assert {
@Test
public void timeRoundTrip() throws Exception {
Instant instantNow = Instant.now();
Date instantSeconds = Date.from(instantNow.truncatedTo(ChronoUnit.SECONDS));
Date instantMillis = Date.from(instantNow.truncatedTo(ChronoUnit.MILLIS));
// if we happen to land exactly on zero milliseconds, add 1 milli
if (instantSeconds.equals(instantMillis)) {
instantMillis = Date.from(instantNow.plusMillis(1).truncatedTo(ChronoUnit.MILLIS));
}
// TODO: other formats
String instantFormatSlash = formatDate(instantMillis, "yyyy/MM/dd HH:mm:ss ZZZZ");
String instantFormatDash = formatDate(instantMillis, "yyyy-MM-dd'T'HH:mm:ss'Z'");
String instantFormatMillis = formatDate(instantMillis, "yyyy-MM-dd'T'HH:mm:ss.S'Z'");
String instantSecondsFormatMillis = formatDate(instantSeconds, "yyyy-MM-dd'T'HH:mm:ss.S'Z'");
String instantBadFormat = formatDate(instantMillis, "yy-MM-dd'T'HH:mm'Z'");
assertThat(GitHub.parseDate(GitHub.printDate(instantSeconds)),
equalTo(GitHub.parseDate(GitHub.printDate(instantMillis))));
assertThat(instantSeconds,
equalTo(GitHub.parseDate(GitHub.printDate(instantSeconds))));
// printDate will truncate to the nearest second, so it should not be equal
assertThat(instantMillis,
not(equalTo(GitHub.parseDate(GitHub.printDate(instantMillis)))));
assertThat(instantSeconds,
equalTo(GitHub.parseDate(instantFormatSlash)));
assertThat(instantSeconds,
equalTo(GitHub.parseDate(instantFormatDash)));
// This parser does not truncate to the nearest second, so it will be equal
assertThat(instantMillis,
equalTo(GitHub.parseDate(instantFormatMillis)));
assertThat(instantSeconds,
equalTo(GitHub.parseDate(instantSecondsFormatMillis)));
try {
GitHub.parseDate(instantBadFormat);
fail("Bad time format should throw.");
} catch (IllegalStateException e) {
assertThat(e.getMessage(), equalTo("Unable to parse the timestamp: " + instantBadFormat));
}
}
static String formatDate(Date dt, String format) {
SimpleDateFormat df = new SimpleDateFormat(format);
df.setTimeZone(TimeZone.getTimeZone("GMT"));
return df.format(dt);
}
}

View File

@@ -3,171 +3,80 @@ package org.kohsuke.github;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
import com.google.common.collect.Iterables;
import org.apache.commons.io.IOUtils;
import org.junit.Ignore;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.hamcrest.CoreMatchers.*;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
/**
* Unit test for {@link GitHub}.
*/
public class GitHubTest {
@Test
public void testOffline() throws Exception {
GitHub hub = GitHub.offline();
assertEquals("https://api.github.invalid/test", hub.getApiURL("/test").toString());
assertTrue(hub.isAnonymous());
try {
hub.getRateLimit();
fail("Offline instance should always fail");
} catch (IOException e) {
assertEquals("Offline", e.getMessage());
}
}
@Test
public void testGitHubServerWithHttp() throws Exception {
GitHub hub = GitHub.connectToEnterprise("http://enterprise.kohsuke.org/api/v3", "bogus","bogus");
assertEquals("http://enterprise.kohsuke.org/api/v3/test", hub.getApiURL("/test").toString());
}
@Test
public void testGitHubServerWithHttps() throws Exception {
GitHub hub = GitHub.connectToEnterprise("https://enterprise.kohsuke.org/api/v3", "bogus","bogus");
assertEquals("https://enterprise.kohsuke.org/api/v3/test", hub.getApiURL("/test").toString());
}
@Test
public void testGitHubServerWithoutServer() throws Exception {
GitHub hub = GitHub.connectUsingPassword("kohsuke", "bogus");
assertEquals("https://api.github.com/test", hub.getApiURL("/test").toString());
}
@Test
public void testGitHubBuilderFromEnvironment() throws IOException {
Map<String, String>props = new HashMap<String, String>();
props.put("login", "bogus");
props.put("oauth", "bogus");
props.put("password", "bogus");
setupEnvironment(props);
GitHubBuilder builder = GitHubBuilder.fromEnvironment();
assertEquals("bogus", builder.user);
assertEquals("bogus", builder.oauthToken);
assertEquals("bogus", builder.password);
}
/*
* Copied from StackOverflow: http://stackoverflow.com/a/7201825/2336755
*
* This allows changing the in memory process environment.
*
* Its used to wire in values for the github credentials to test that the GitHubBuilder works properly to resolve them.
*/
private void setupEnvironment(Map<String, String> newenv) {
try {
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
theEnvironmentField.setAccessible(true);
Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
env.putAll(newenv);
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
theCaseInsensitiveEnvironmentField.setAccessible(true);
Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
cienv.putAll(newenv);
} catch (NoSuchFieldException e) {
try {
Class[] classes = Collections.class.getDeclaredClasses();
Map<String, String> env = System.getenv();
for (Class cl : classes) {
if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Object obj = field.get(env);
Map<String, String> map = (Map<String, String>) obj;
map.clear();
map.putAll(newenv);
}
}
} catch (Exception e2) {
e2.printStackTrace();
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
@Test
public void testGitHubBuilderFromCustomEnvironment() throws IOException {
Map<String, String> props = new HashMap<String, String>();
props.put("customLogin", "bogusLogin");
props.put("customOauth", "bogusOauth");
props.put("customPassword", "bogusPassword");
props.put("customEndpoint", "bogusEndpoint");
setupEnvironment(props);
GitHubBuilder builder = GitHubBuilder.fromEnvironment("customLogin", "customPassword", "customOauth", "customEndpoint");
assertEquals("bogusLogin", builder.user);
assertEquals("bogusOauth", builder.oauthToken);
assertEquals("bogusPassword", builder.password);
assertEquals("bogusEndpoint", builder.endpoint);
}
@Test
public void testGitHubEnterpriseDoesNotHaveRateLimit() throws IOException {
GitHub github = spy(new GitHubBuilder().build());
when(github.retrieve()).thenThrow(FileNotFoundException.class);
GHRateLimit rateLimit = github.getRateLimit();
assertThat(rateLimit.getResetDate(), notNullValue());
}
@Test
public void testGitHubIsApiUrlValid() throws IOException {
GitHub github = GitHub.connectAnonymously();
//GitHub github = GitHub.connectToEnterpriseAnonymously("https://github.mycompany.com/api/v3/");
try {
github.checkApiUrlValidity();
} catch (IOException ioe) {
assertTrue(ioe.getMessage().contains("private mode enabled"));
}
}
public class GitHubTest extends AbstractGitHubWireMockTest {
@Test
public void listUsers() throws IOException {
GitHub hub = GitHub.connect();
for (GHUser u : Iterables.limit(hub.listUsers(),10)) {
assert u.getName()!=null;
System.out.println(u.getName());
for (GHUser u : Iterables.limit(gitHub.listUsers(), 10)) {
assert u.getName() != null;
// System.out.println(u.getName());
}
}
@Test
public void getOrgs() throws IOException {
GitHub hub = GitHub.connect();
int iterations = 10;
Set<Long> orgIds = new HashSet<Long>();
for (GHOrganization org : Iterables.limit(hub.listOrganizations().withPageSize(2), iterations)) {
for (GHOrganization org : Iterables.limit(gitHub.listOrganizations().withPageSize(2), iterations)) {
orgIds.add(org.getId());
System.out.println(org.getName());
// System.out.println(org.getName());
}
assertThat(orgIds.size(), equalTo(iterations));
}
@Test
public void searchUsers() throws Exception {
PagedSearchIterable<GHUser> r = gitHub.searchUsers().q("tom").repos(">42").followers(">1000").list();
GHUser u = r.iterator().next();
// System.out.println(u.getName());
assertNotNull(u.getId());
assertTrue(r.getTotalCount() > 0);
}
@Test
public void testListAllRepositories() throws Exception {
Iterator<GHRepository> itr = gitHub.listAllPublicRepositories().iterator();
for (int i = 0; i < 115; i++) {
assertTrue(itr.hasNext());
GHRepository r = itr.next();
// System.out.println(r.getFullName());
assertNotNull(r.getUrl());
assertNotEquals(0L, r.getId());
}
}
@Test
public void searchContent() throws Exception {
PagedSearchIterable<GHContent> r = gitHub.searchContent().q("addClass").in("file").language("js").repo("jquery/jquery").list();
GHContent c = r.iterator().next();
// System.out.println(c.getName());
assertNotNull(c.getDownloadUrl());
assertNotNull(c.getOwner());
assertEquals("jquery/jquery", c.getOwner().getFullName());
assertTrue(r.getTotalCount() > 0);
}
@Test
public void testListMyAuthorizations() throws IOException
{
PagedIterable<GHAuthorization> list = gitHub.listMyAuthorizations();
for (GHAuthorization auth: list) {
assertNotNull(auth.getAppName());
}
}
}

View File

@@ -26,26 +26,26 @@ public class LifecycleTest extends AbstractGitHubApiTestBase {
Thread.sleep(1000);
}
repository = org.createRepository("github-api-test",
"a test repository used to test kohsuke's github-api", "http://github-api.kohsuke.org/", "Core Developers", true);
"a test repository used to test kohsuke's github-api", "http://github-api.kohsuke.org/", "Core Developers", true);
Thread.sleep(1000); // wait for the repository to become ready
assertTrue(repository.getReleases().isEmpty());
try {
GHMilestone milestone = repository.createMilestone("Initial Release", "first one");
GHIssue issue = repository.createIssue("Test Issue")
.body("issue body just for grins")
.milestone(milestone)
.assignee(myself)
.label("bug")
.create();
.body("issue body just for grins")
.milestone(milestone)
.assignee(myself)
.label("bug")
.create();
File repoDir = new File(System.getProperty("java.io.tmpdir"), "github-api-test");
delete(repoDir);
Git origin = Git.cloneRepository()
.setBare(false)
.setURI(repository.getSshUrl())
.setDirectory(repoDir)
.setCredentialsProvider(getCredentialsProvider(myself))
.call();
.setBare(false)
.setURI(repository.getSshUrl())
.setDirectory(repoDir)
.setCredentialsProvider(getCredentialsProvider(myself))
.call();
commitTestFile(myself, repoDir, origin);
@@ -84,9 +84,9 @@ public class LifecycleTest extends AbstractGitHubApiTestBase {
private GHRelease createRelease(GHRepository repository) throws IOException {
GHRelease builder = repository.createRelease("release_tag")
.name("Test Release")
.body("How exciting! To be able to programmatically create releases is a dream come true!")
.create();
.name("Test Release")
.body("How exciting! To be able to programmatically create releases is a dream come true!")
.create();
List<GHRelease> releases = repository.getReleases();
assertEquals(1, releases.size());
GHRelease release = releases.get(0);

View File

@@ -6,6 +6,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import org.apache.commons.io.IOUtils;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
@@ -44,8 +45,8 @@ public class PayloadRule implements TestRule {
public InputStream asInputStream() throws FileNotFoundException {
String name = resourceName.startsWith("/")
? resourceName + type
: testClass.getSimpleName() + "/" + resourceName + type;
? resourceName + type
: testClass.getSimpleName() + "/" + resourceName + type;
InputStream stream = testClass.getResourceAsStream(name);
if (stream == null) {
throw new FileNotFoundException(String.format("Resource %s from class %s", name, testClass));
@@ -81,6 +82,7 @@ public class PayloadRule implements TestRule {
public Reader asReader(String encoding) throws IOException {
return new InputStreamReader(asInputStream(), encoding);
}
public Reader asReader(Charset encoding) throws FileNotFoundException {
return new InputStreamReader(asInputStream(), encoding);
}

View File

@@ -1,186 +0,0 @@
package org.kohsuke.github;
import org.junit.After;
import org.junit.Test;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import static org.hamcrest.CoreMatchers.*;
/**
* @author Kohsuke Kawaguchi
*/
public class PullRequestTest extends AbstractGitHubApiTestBase {
@Test
public void createPullRequest() throws Exception {
String name = rnd.next();
GHPullRequest p = getRepository().createPullRequest(name, "stable", "master", "## test");
System.out.println(p.getUrl());
assertEquals(name, p.getTitle());
}
@Test
public void createPullRequestComment() throws Exception {
String name = rnd.next();
GHPullRequest p = getRepository().createPullRequest(name, "stable", "master", "## test");
p.comment("Some comment");
}
@Test
public void testPullRequestReviews() throws Exception {
String name = rnd.next();
GHPullRequest p = getRepository().createPullRequest(name, "stable", "master", "## test");
GHPullRequestReview draftReview = p.createReview()
.body("Some draft review")
.comment("Some niggle", "changelog.html", 1)
.create();
assertThat(draftReview.getState(), is(GHPullRequestReviewState.PENDING));
assertThat(draftReview.getBody(), is("Some draft review"));
assertThat(draftReview.getCommitId(), notNullValue());
List<GHPullRequestReview> reviews = p.listReviews().asList();
assertThat(reviews.size(), is(1));
GHPullRequestReview review = reviews.get(0);
assertThat(review.getState(), is(GHPullRequestReviewState.PENDING));
assertThat(review.getBody(), is("Some draft review"));
assertThat(review.getCommitId(), notNullValue());
draftReview.submit("Some review comment", GHPullRequestReviewEvent.COMMENT);
List<GHPullRequestReviewComment> comments = review.listReviewComments().asList();
assertEquals(1, comments.size());
GHPullRequestReviewComment comment = comments.get(0);
assertEquals("Some niggle", comment.getBody());
draftReview = p.createReview()
.body("Some new review")
.comment("Some niggle", "changelog.html", 1)
.create();
draftReview.delete();
}
@Test
public void testPullRequestReviewComments() throws Exception {
String name = rnd.next();
GHPullRequest p = getRepository().createPullRequest(name, "stable", "master", "## test");
System.out.println(p.getUrl());
assertTrue(p.listReviewComments().asList().isEmpty());
p.createReviewComment("Sample review comment", p.getHead().getSha(), "cli/pom.xml", 5);
List<GHPullRequestReviewComment> comments = p.listReviewComments().asList();
assertEquals(1, comments.size());
GHPullRequestReviewComment comment = comments.get(0);
assertEquals("Sample review comment", comment.getBody());
comment.update("Updated review comment");
comments = p.listReviewComments().asList();
assertEquals(1, comments.size());
comment = comments.get(0);
assertEquals("Updated review comment", comment.getBody());
comment.delete();
comments = p.listReviewComments().asList();
assertTrue(comments.isEmpty());
}
@Test
public void testMergeCommitSHA() throws Exception {
String name = rnd.next();
GHPullRequest p = getRepository().createPullRequest(name, "mergeable-branch", "master", "## test");
for (int i=0; i<100; i++) {
GHPullRequest updated = getRepository().getPullRequest(p.getNumber());
if (updated.getMergeCommitSha()!=null) {
// make sure commit exists
GHCommit commit = getRepository().getCommit(updated.getMergeCommitSha());
assertNotNull(commit);
return;
}
// mergeability computation takes time. give it more chance
Thread.sleep(100);
}
// hmm?
fail();
}
@Test
public void testSquashMerge() throws Exception {
String name = rnd.next();
GHRef masterRef = getRepository().getRef("heads/master");
GHRef branchRef = getRepository().createRef("refs/heads/" + name, masterRef.getObject().getSha());
getRepository().createContent(name, name, name, name);
Thread.sleep(1000);
GHPullRequest p = getRepository().createPullRequest(name, name, "master", "## test squash");
Thread.sleep(1000);
p.merge("squash merge", null, GHPullRequest.MergeMethod.SQUASH);
branchRef.delete();
}
@Test
public void testUpdateContentSquashMerge() throws Exception {
String name = rnd.next();
GHRef masterRef = getRepository().getRef("heads/master");
GHRef branchRef = getRepository().createRef("refs/heads/" + name, masterRef.getObject().getSha());
GHContentUpdateResponse response = getRepository().createContent(name, name, name, name);
Thread.sleep(1000);
getRepository().createContent()
.content(name + name)
.path(name)
.branch(name)
.message(name)
.sha(response.getContent().getSha())
.commit();
GHPullRequest p = getRepository().createPullRequest(name, name, "master", "## test squash");
Thread.sleep(1000);
p.merge("squash merge", null, GHPullRequest.MergeMethod.SQUASH);
branchRef.delete();
}
@Test
// Requires push access to the test repo to pass
public void setLabels() throws Exception {
GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test");
String label = rnd.next();
p.setLabels(label);
Collection<GHLabel> labels = getRepository().getPullRequest(p.getNumber()).getLabels();
assertEquals(1, labels.size());
assertEquals(label, labels.iterator().next().getName());
}
@Test
// Requires push access to the test repo to pass
public void setAssignee() throws Exception {
GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test");
GHMyself user = gitHub.getMyself();
p.assignTo(user);
assertEquals(user, getRepository().getPullRequest(p.getNumber()).getAssignee());
}
@Test
public void testGetUser() throws IOException {
GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test");
GHPullRequest prSingle = getRepository().getPullRequest(p.getNumber());
assertNotNull(prSingle.getUser().root);
prSingle.getMergeable();
assertNotNull(prSingle.getUser().root);
PagedIterable<GHPullRequest> ghPullRequests = getRepository().listPullRequests(GHIssueState.OPEN);
for (GHPullRequest pr : ghPullRequests) {
assertNotNull(pr.getUser().root);
pr.getMergeable();
assertNotNull(pr.getUser().root);
}
}
@After
public void cleanUp() throws Exception {
for (GHPullRequest pr : getRepository().getPullRequests(GHIssueState.OPEN)) {
pr.close();
}
}
private GHRepository getRepository() throws IOException {
return gitHub.getOrganization("github-api-test-org").getRepository("jenkins");
}
}

View File

@@ -41,14 +41,14 @@ public class RepositoryMockTest {
when(iterator.hasNext()).thenReturn(true, false, true);
when(iterator.next()).thenReturn(new GHUser[]{user1}, new GHUser[]{user2});
when(iterator.next()).thenReturn(new GHUser[] {user1}, new GHUser[] {user2});
Requester requester = Mockito.mock(Requester.class);
when(mockGitHub.retrieve()).thenReturn(requester);
when(requester.asIterator("/repos/*/*/collaborators",
GHUser[].class, 0)).thenReturn(iterator, iterator);
GHUser[].class, 0)).thenReturn(iterator, iterator);
PagedIterable<GHUser> pagedIterable = Mockito.mock(PagedIterable.class);

View File

@@ -1,145 +0,0 @@
package org.kohsuke.github;
import org.junit.Test;
import org.kohsuke.github.GHRepository.Contributor;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* @author Kohsuke Kawaguchi
*/
public class RepositoryTest extends AbstractGitHubApiTestBase {
@Test
public void subscription() throws Exception {
GHRepository r = getRepository();
assertNull(r.getSubscription());
GHSubscription s = r.subscribe(true, false);
assertEquals(s.getRepository(), r);
s.delete();
assertNull(r.getSubscription());
}
@Test
public void listContributors() throws IOException {
GHRepository r = gitHub.getOrganization("stapler").getRepository("stapler");
int i=0;
boolean kohsuke = false;
for (Contributor c : r.listContributors()) {
System.out.println(c.getName());
assertTrue(c.getContributions()>0);
if (c.getLogin().equals("kohsuke"))
kohsuke = true;
if (i++ > 5)
break;
}
assertTrue(kohsuke);
}
@Test
public void getPermission() throws Exception {
kohsuke();
GHRepository r = gitHub.getRepository("github-api-test-org/test-permission");
assertEquals(GHPermissionType.ADMIN, r.getPermission("kohsuke"));
assertEquals(GHPermissionType.READ, r.getPermission("dude"));
r = gitHub.getOrganization("apache").getRepository("groovy");
try {
r.getPermission("jglick");
fail();
} catch (HttpException x) {
x.printStackTrace(); // good
assertEquals(403, x.getResponseCode());
}
if (false) {
// can't easily test this; there's no private repository visible to the test user
r = gitHub.getOrganization("cloudbees").getRepository("private-repo-not-writable-by-me");
try {
r.getPermission("jglick");
fail();
} catch (FileNotFoundException x) {
x.printStackTrace(); // good
}
}
}
@Test
public void LatestRepositoryExist() {
try {
// add the repository that have latest release
GHRelease release = gitHub.getRepository("kamontat/CheckIDNumber").getLatestRelease();
assertEquals("v3.0", release.getTagName());
} catch (IOException e) {
e.printStackTrace();
fail();
}
}
@Test
public void LatestRepositoryNotExist() {
try {
// add the repository that `NOT` have latest release
GHRelease release = gitHub.getRepository("kamontat/Java8Example").getLatestRelease();
assertNull(release);
} catch (IOException e) {
e.printStackTrace();
fail();
}
}
@Test public void listReleases() throws IOException {
PagedIterable<GHRelease> releases = gitHub.getOrganization("github").getRepository("hub").listReleases();
assertTrue(releases.iterator().hasNext());
}
@Test
public void getReleaseExists() throws IOException {
GHRelease release = gitHub.getOrganization("github").getRepository("hub").getRelease(6839710);
assertEquals("v2.3.0-pre10", release.getTagName());
}
@Test
public void getReleaseDoesNotExist() throws IOException {
GHRelease release = gitHub.getOrganization("github").getRepository("hub").getRelease(Long.MAX_VALUE);
assertNull(release);
}
@Test
public void getReleaseByTagNameExists() throws IOException {
GHRelease release = gitHub.getOrganization("github").getRepository("hub").getReleaseByTagName("v2.3.0-pre10");
assertNotNull(release);
assertEquals("v2.3.0-pre10", release.getTagName());
}
@Test
public void getReleaseByTagNameDoesNotExist() throws IOException {
GHRelease release = getRepository().getReleaseByTagName("foo-bar-baz");
assertNull(release);
}
private GHRepository getRepository() throws IOException {
return gitHub.getOrganization("github-api-test-org").getRepository("jenkins");
}
@Test
public void listLanguages() throws IOException {
GHRepository r = gitHub.getRepository("kohsuke/github-api");
String mainLanguage = r.getLanguage();
assertTrue(r.listLanguages().containsKey(mainLanguage));
}
@Test // Issue #261
public void listEmptyContributors() throws IOException {
GitHub gh = GitHub.connect();
for (Contributor c : gh.getRepository("github-api-test-org/empty").listContributors()) {
System.out.println(c);
}
}
}

View File

@@ -17,11 +17,17 @@ import java.util.Iterator;
import java.util.List;
import java.util.TimeZone;
public class RepositoryTrafficTest {
public class RepositoryTrafficTest extends AbstractGitHubApiTestBase {
final private String login = "kohsuke", repositoryName = "github-api";
@Override
protected GitHubBuilder getGitHubBuilder() {
return new GitHubBuilder()
.withPassword(login, null);
}
@SuppressWarnings("unchecked")
private <T extends GHRepositoryTraffic> void checkResponse(T expected, T actual){
private <T extends GHRepositoryTraffic> void checkResponse(T expected, T actual) {
Assert.assertEquals(expected.getCount(), actual.getCount());
Assert.assertEquals(expected.getUniques(), actual.getUniques());
@@ -34,7 +40,7 @@ public class RepositoryTrafficTest {
expectedIt = expectedList.iterator();
actualIt = actualList.iterator();
while(expectedIt.hasNext() && actualIt.hasNext()) {
while (expectedIt.hasNext() && actualIt.hasNext()) {
DailyInfo expectedDailyInfo = expectedIt.next();
DailyInfo actualDailyInfo = actualIt.next();
Assert.assertEquals(expectedDailyInfo.getCount(), actualDailyInfo.getCount());
@@ -43,14 +49,12 @@ public class RepositoryTrafficTest {
}
}
private <T extends GHRepositoryTraffic> void testTraffic(T expectedResult) throws IOException{
SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
private <T extends GHRepositoryTraffic> void testTraffic(T expectedResult) throws IOException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
ObjectMapper mapper = new ObjectMapper().setDateFormat(dateFormat);
String mockedResponse = mapper.writeValueAsString(expectedResult);
GitHub gitHub = GitHub.connect(login, null);
GitHub gitHubSpy = Mockito.spy(gitHub);
GHRepository repo = gitHubSpy.getUser(login).getRepository(repositoryName);
@@ -71,8 +75,8 @@ public class RepositoryTrafficTest {
// this covers calls on "uc" in Requester.setupConnection and Requester.buildRequest
URL trafficURL = new URL(
"https://api.github.com/repos/"+login+"/"+repositoryName+"/traffic/" +
URL trafficURL = gitHub.getApiURL(
"/repos/" + login + "/" + repositoryName + "/traffic/" +
((expectedResult instanceof GHRepositoryViewTraffic) ? "views" : "clones")
);
Mockito.doReturn(mockHttpURLConnection).when(connectorSpy).connect(Mockito.eq(trafficURL));
@@ -84,64 +88,63 @@ public class RepositoryTrafficTest {
InputStream stubInputStream = IOUtils.toInputStream(mockedResponse, "UTF-8");
Mockito.doReturn(stubInputStream).when(mockHttpURLConnection).getInputStream();
if(expectedResult instanceof GHRepositoryViewTraffic){
if (expectedResult instanceof GHRepositoryViewTraffic) {
GHRepositoryViewTraffic views = repo.getViewTraffic();
checkResponse(expectedResult, views);
}
else if(expectedResult instanceof GHRepositoryCloneTraffic) {
} else if (expectedResult instanceof GHRepositoryCloneTraffic) {
GHRepositoryCloneTraffic clones = repo.getCloneTraffic();
checkResponse(expectedResult, clones);
}
}
@Test
public void testGetViews() throws IOException{
public void testGetViews() throws IOException {
GHRepositoryViewTraffic expectedResult = new GHRepositoryViewTraffic(
21523359,
65534,
Arrays.asList(
new GHRepositoryViewTraffic.DailyInfo("2016-10-10T00:00:00Z", 3, 2),
new GHRepositoryViewTraffic.DailyInfo("2016-10-11T00:00:00Z", 9, 4),
new GHRepositoryViewTraffic.DailyInfo("2016-10-12T00:00:00Z", 27, 8),
new GHRepositoryViewTraffic.DailyInfo("2016-10-13T00:00:00Z", 81, 16),
new GHRepositoryViewTraffic.DailyInfo("2016-10-14T00:00:00Z", 243, 32),
new GHRepositoryViewTraffic.DailyInfo("2016-10-15T00:00:00Z", 729, 64),
new GHRepositoryViewTraffic.DailyInfo("2016-10-16T00:00:00Z", 2187, 128),
new GHRepositoryViewTraffic.DailyInfo("2016-10-17T00:00:00Z", 6561, 256),
new GHRepositoryViewTraffic.DailyInfo("2016-10-18T00:00:00Z", 19683, 512),
new GHRepositoryViewTraffic.DailyInfo("2016-10-19T00:00:00Z", 59049, 1024),
new GHRepositoryViewTraffic.DailyInfo("2016-10-20T00:00:00Z", 177147, 2048),
new GHRepositoryViewTraffic.DailyInfo("2016-10-21T00:00:00Z", 531441, 4096),
new GHRepositoryViewTraffic.DailyInfo("2016-10-22T00:00:00Z", 1594323, 8192),
new GHRepositoryViewTraffic.DailyInfo("2016-10-23T00:00:00Z", 4782969, 16384),
new GHRepositoryViewTraffic.DailyInfo("2016-10-24T00:00:00Z", 14348907, 32768)
)
21523359,
65534,
Arrays.asList(
new GHRepositoryViewTraffic.DailyInfo("2016-10-10T00:00:00Z", 3, 2),
new GHRepositoryViewTraffic.DailyInfo("2016-10-11T00:00:00Z", 9, 4),
new GHRepositoryViewTraffic.DailyInfo("2016-10-12T00:00:00Z", 27, 8),
new GHRepositoryViewTraffic.DailyInfo("2016-10-13T00:00:00Z", 81, 16),
new GHRepositoryViewTraffic.DailyInfo("2016-10-14T00:00:00Z", 243, 32),
new GHRepositoryViewTraffic.DailyInfo("2016-10-15T00:00:00Z", 729, 64),
new GHRepositoryViewTraffic.DailyInfo("2016-10-16T00:00:00Z", 2187, 128),
new GHRepositoryViewTraffic.DailyInfo("2016-10-17T00:00:00Z", 6561, 256),
new GHRepositoryViewTraffic.DailyInfo("2016-10-18T00:00:00Z", 19683, 512),
new GHRepositoryViewTraffic.DailyInfo("2016-10-19T00:00:00Z", 59049, 1024),
new GHRepositoryViewTraffic.DailyInfo("2016-10-20T00:00:00Z", 177147, 2048),
new GHRepositoryViewTraffic.DailyInfo("2016-10-21T00:00:00Z", 531441, 4096),
new GHRepositoryViewTraffic.DailyInfo("2016-10-22T00:00:00Z", 1594323, 8192),
new GHRepositoryViewTraffic.DailyInfo("2016-10-23T00:00:00Z", 4782969, 16384),
new GHRepositoryViewTraffic.DailyInfo("2016-10-24T00:00:00Z", 14348907, 32768)
)
);
testTraffic(expectedResult);
}
@Test
public void testGetClones() throws IOException{
public void testGetClones() throws IOException {
GHRepositoryCloneTraffic expectedResult = new GHRepositoryCloneTraffic(
1500,
455,
Arrays.asList(
new GHRepositoryCloneTraffic.DailyInfo("2016-10-10T00:00:00Z", 10,3),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-11T00:00:00Z", 20,6),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-12T00:00:00Z", 30,5),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-13T00:00:00Z", 40,7),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-14T00:00:00Z", 50,11),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-15T00:00:00Z", 60,12),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-16T00:00:00Z", 70,19),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-17T00:00:00Z", 170,111),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-18T00:00:00Z", 180,70),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-19T00:00:00Z", 190,10),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-20T00:00:00Z", 200,18),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-21T00:00:00Z", 210,8),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-22T00:00:00Z", 220,168),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-23T00:00:00Z", 5,2),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-24T00:00:00Z", 45,5)
)
1500,
455,
Arrays.asList(
new GHRepositoryCloneTraffic.DailyInfo("2016-10-10T00:00:00Z", 10, 3),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-11T00:00:00Z", 20, 6),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-12T00:00:00Z", 30, 5),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-13T00:00:00Z", 40, 7),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-14T00:00:00Z", 50, 11),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-15T00:00:00Z", 60, 12),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-16T00:00:00Z", 70, 19),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-17T00:00:00Z", 170, 111),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-18T00:00:00Z", 180, 70),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-19T00:00:00Z", 190, 10),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-20T00:00:00Z", 200, 18),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-21T00:00:00Z", 210, 8),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-22T00:00:00Z", 220, 168),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-23T00:00:00Z", 5, 2),
new GHRepositoryCloneTraffic.DailyInfo("2016-10-24T00:00:00Z", 45, 5)
)
);
testTraffic(expectedResult);
}
@@ -149,19 +152,17 @@ public class RepositoryTrafficTest {
@Test
public void testGetTrafficStatsAccessFailureDueToInsufficientPermissions() throws IOException {
String errorMsg = "Exception should be thrown, since we don't have permission to access repo traffic info.";
GitHub gitHub = GitHub.connect(login, null);
GHRepository repo = gitHub.getUser(login).getRepository(repositoryName);
try {
repo.getViewTraffic();
Assert.fail(errorMsg);
}
catch (HttpException ex){
} catch (HttpException ex) {
}
try {
repo.getCloneTraffic();
Assert.fail(errorMsg);
}
catch (HttpException ex){
} catch (HttpException ex) {
}
}
}

View File

@@ -1,30 +0,0 @@
package org.kohsuke.github;
import org.junit.Test;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
/**
* @author Kohsuke Kawaguchi
*/
public class UserTest extends AbstractGitHubApiTestBase {
@Test
public void listFollowsAndFollowers() throws IOException {
GHUser u = gitHub.getUser("rtyler");
assertNotEquals(
count30(u.listFollowers()),
count30(u.listFollows()));
}
private Set<GHUser> count30(PagedIterable<GHUser> l) {
Set<GHUser> users = new HashSet<GHUser>();
PagedIterator<GHUser> itr = l.iterator();
for (int i=0; i<30 && itr.hasNext(); i++) {
users.add(itr.next());
}
assertEquals(30, users.size());
return users;
}
}

View File

@@ -0,0 +1,140 @@
package org.kohsuke.github;
import org.kohsuke.github.junit.WireMockRule;
import org.hamcrest.Matchers;
import org.junit.Ignore;
import org.junit.Test;
import static org.hamcrest.Matchers.*;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
/**
* Tests in this class are meant to show the behavior of {@link AbstractGitHubWireMockTest} with proxying on or off.
* <p>
* The wiremock data for these tests should only be modified by hand - thus most are skipped when snapshotting.
*
* @author Liam Newman
*/
public class WireMockStatusReporterTest extends AbstractGitHubWireMockTest {
@Test
public void user_whenProxying_AuthCorrectlyConfigured() throws Exception {
snapshotNotAllowed();
requireProxy("Tests proper configuration when proxying.");
assertThat(
"GitHub connection believes it is anonymous. Make sure you set GITHUB_OAUTH or both GITHUB_USER and GITHUB_PASSWORD environment variables",
gitHub.isAnonymous(), is(false));
assertThat(gitHub.login, not(equalTo(STUBBED_USER_LOGIN)));
// If this user query fails, either the proxying config has broken (unlikely)
// or your auth settings are not being retrieved from the environemnt.
// Check your settings.
GHUser user = gitHub.getMyself();
assertThat(user.getLogin(), notNullValue());
// System.out.println();
// System.out.println("WireMockStatusReporterTest: GitHub proxying and user auth correctly configured for user login: " + user.getLogin());
// System.out.println();
}
@Test
public void user_whenNotProxying_Stubbed() throws Exception {
snapshotNotAllowed();
assumeFalse("Test only valid when not proxying", mockGitHub.isUseProxy());
assertThat(gitHub.isAnonymous(), is(false));
assertThat(gitHub.login, equalTo(STUBBED_USER_LOGIN));
GHUser user = gitHub.getMyself();
// NOTE: the stubbed user does not have to match the login provided from the github object
// github.login is literally just a placeholder when mocking
assertThat(user.getLogin(), not(equalTo(STUBBED_USER_LOGIN)));
assertThat(user.getLogin(), equalTo("stubbed-user-login"));
// System.out.println("GitHub proxying and user auth correctly configured for user login: " + user.getLogin());
}
@Ignore("Can't run this as WireMock will report failure after the test method completes.")
@Test
public void BasicBehaviors_whenNotProxying() throws Exception {
snapshotNotAllowed();
assumeFalse("Test only valid when not proxying", mockGitHub.isUseProxy());
Exception e = null;
GHRepository repo = null;
// Valid repository, stubbed
repo = gitHub.getRepository("github-api/github-api");
assertThat(repo.getDescription(), equalTo("this is a stubbed description"));
// Invalid repository, without stub - fails 404 when not proxying
try {
gitHub.getRepository("jenkinsci/jenkins");
fail();
} catch (Exception ex) {
e = ex;
}
assertThat(e, Matchers.<Exception>instanceOf(GHFileNotFoundException.class));
assertThat(e.getMessage(), containsString("Request was not matched"));
// Invalid repository, without stub - fails 404 when not proxying
e = null;
try {
gitHub.getRepository("github-api/non-existant-repository");
fail();
} catch (Exception ex) {
e = ex;
}
assertThat(e, Matchers.<Exception>instanceOf(GHFileNotFoundException.class));
assertThat(e.getMessage(), containsString("Request was not matched"));
}
@Test
public void BasicBehaviors_whenProxying() throws Exception {
snapshotNotAllowed();
requireProxy("Tests basic behaviors when proxying.");
Exception e = null;
GHRepository repo = null;
// Valid repository, stubbed
repo = gitHub.getRepository("github-api/github-api");
assertThat(repo.getDescription(), equalTo("this is a stubbed description"));
// Valid repository, without stub - succeeds when proxying
repo = gitHub.getRepository("jenkinsci/jenkins");
assertThat(repo.getDescription(), notNullValue());
// Invalid repository, without stub - fails 404 when proxying
e = null;
try {
gitHub.getRepository("github-api/non-existant-repository");
} catch (Exception ex) {
e = ex;
}
assertThat(e, Matchers.<Exception>instanceOf(GHFileNotFoundException.class));
assertThat(e.getMessage(), equalTo("{\"message\":\"Not Found\",\"documentation_url\":\"https://developer.github.com/v3/repos/#get\"}"));
}
@Test
public void whenSnapshot_EnsureProxy() throws Exception {
assumeTrue("Test only valid when Snapshotting (-Dtest.github.takeSnapshot to enable)", mockGitHub.isTakeSnapshot());
assertTrue("When taking a snapshot, proxy should automatically be enabled", mockGitHub.isUseProxy());
}
@Ignore("Not implemented yet")
@Test
public void whenSnapshot_EnsureRecordToExpectedLocation() throws Exception {
assumeTrue("Test only valid when Snapshotting (-Dtest.github.takeSnapshot to enable)", mockGitHub.isTakeSnapshot());
}
}

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