mirror of
https://github.com/jlengrand/github-api.git
synced 2026-03-11 15:50:17 +00:00
Compare commits
345 Commits
github-api
...
github-api
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eff48dfe67 | ||
|
|
0c38bdc068 | ||
|
|
b8e1736696 | ||
|
|
c2f36444d0 | ||
|
|
5dc74f5b4d | ||
|
|
9694dfe4cc | ||
|
|
734125ea14 | ||
|
|
438f5d1b87 | ||
|
|
fadd6d7978 | ||
|
|
5026262273 | ||
|
|
5b53fba020 | ||
|
|
3892e6e16f | ||
|
|
33467de763 | ||
|
|
f3528d97c2 | ||
|
|
6fb3b01bf0 | ||
|
|
e3c9cec440 | ||
|
|
0e011425fb | ||
|
|
ba658f7fea | ||
|
|
0e6087143b | ||
|
|
5f967e6307 | ||
|
|
2eb8ce632c | ||
|
|
f25dbd15d9 | ||
|
|
cc5ea77170 | ||
|
|
e323644af2 | ||
|
|
61f3a3219f | ||
|
|
4dcf5dbc13 | ||
|
|
8faecba0a2 | ||
|
|
739551cbe3 | ||
|
|
24a2e42881 | ||
|
|
6921754c99 | ||
|
|
d8827a0b44 | ||
|
|
a48091988f | ||
|
|
9bd9c9cf1f | ||
|
|
695692285b | ||
|
|
03edacf7b6 | ||
|
|
4802c97e89 | ||
|
|
9fc24d1981 | ||
|
|
d4ddf453b0 | ||
|
|
c0117f07cf | ||
|
|
8a88c14b13 | ||
|
|
a5b6302a69 | ||
|
|
9f29d4619d | ||
|
|
f4b9dd7d7b | ||
|
|
c0a4152b00 | ||
|
|
efb87c5a9e | ||
|
|
061e8bb662 | ||
|
|
a4f42b2948 | ||
|
|
cb2fcd3a9e | ||
|
|
1d004a35a0 | ||
|
|
c763c02018 | ||
|
|
eb36cb4436 | ||
|
|
72d4b9bf62 | ||
|
|
81ea138f41 | ||
|
|
1bbc66ad62 | ||
|
|
e7348df372 | ||
|
|
550e060647 | ||
|
|
2970a58e95 | ||
|
|
e0efa04fd4 | ||
|
|
4d24088982 | ||
|
|
baba9f5de6 | ||
|
|
c35cd63d0e | ||
|
|
80fa389ce3 | ||
|
|
8ec861c9fe | ||
|
|
837400fb5e | ||
|
|
ec4525b8ff | ||
|
|
281c927971 | ||
|
|
9dd44c13e4 | ||
|
|
f28edbcf8f | ||
|
|
29e147f992 | ||
|
|
830f4231e1 | ||
|
|
7d65e31055 | ||
|
|
dec7a91b5b | ||
|
|
1ba630c221 | ||
|
|
7d3387fb96 | ||
|
|
a0c0de28d7 | ||
|
|
dc31d52f83 | ||
|
|
620c822dac | ||
|
|
5990f5ae22 | ||
|
|
37329a50d4 | ||
|
|
550597f72e | ||
|
|
2aa4022e2c | ||
|
|
b40741b14d | ||
|
|
3c739d889e | ||
|
|
24a92a133e | ||
|
|
ce97eb5b40 | ||
|
|
7a4e3c480e | ||
|
|
eefa710839 | ||
|
|
4c3e1afcca | ||
|
|
c1a77ada5d | ||
|
|
5671e5ed67 | ||
|
|
2fdc5a8541 | ||
|
|
297dbae247 | ||
|
|
0910cdf3a4 | ||
|
|
6877fb5c74 | ||
|
|
2d65daa8c9 | ||
|
|
dab4cb6186 | ||
|
|
40773a2b49 | ||
|
|
7e0d61a6fc | ||
|
|
7f9620d75f | ||
|
|
3559aef1a1 | ||
|
|
94ceb5eaaf | ||
|
|
778ca76d22 | ||
|
|
b1c0e41c5c | ||
|
|
f826edd097 | ||
|
|
edc7c4a4b8 | ||
|
|
dafdc66d25 | ||
|
|
0d135f14bb | ||
|
|
568c08d0e9 | ||
|
|
87410e295e | ||
|
|
b163e68950 | ||
|
|
88b006e957 | ||
|
|
477f2f2814 | ||
|
|
933d99c23b | ||
|
|
d3a0c5ded1 | ||
|
|
1e173ddc24 | ||
|
|
ca404cb33b | ||
|
|
f0dc7d5b02 | ||
|
|
933702376f | ||
|
|
e08896775b | ||
|
|
d610e46f8e | ||
|
|
7d1989f5a2 | ||
|
|
5c1e371427 | ||
|
|
dbd9d51747 | ||
|
|
fdf5d3f72d | ||
|
|
2719867a86 | ||
|
|
0240412ad2 | ||
|
|
7c065c1205 | ||
|
|
f9aa1ad1f2 | ||
|
|
5feffdf544 | ||
|
|
4e56b8bb78 | ||
|
|
845017313c | ||
|
|
dc2830d94f | ||
|
|
552edf8698 | ||
|
|
41c51646fe | ||
|
|
a42024bdbc | ||
|
|
20cfb26a7f | ||
|
|
3972d11827 | ||
|
|
5cc88a0075 | ||
|
|
fc08711111 | ||
|
|
b20c2babec | ||
|
|
cb0facc6ef | ||
|
|
78abb2edcb | ||
|
|
7d350d9def | ||
|
|
48d7daf2c4 | ||
|
|
2782059d88 | ||
|
|
0ca10bc2ac | ||
|
|
880abe2305 | ||
|
|
22f61d6225 | ||
|
|
4fbaa425fb | ||
|
|
e81e228f03 | ||
|
|
1076f89954 | ||
|
|
9c6f977202 | ||
|
|
bd23ba6077 | ||
|
|
c7af56d0ed | ||
|
|
8da6db9fcc | ||
|
|
2fe7342fd7 | ||
|
|
f6221144a8 | ||
|
|
872d713e50 | ||
|
|
d5b04f572b | ||
|
|
0f7a5f1c08 | ||
|
|
a163c565a8 | ||
|
|
413a316b15 | ||
|
|
65a92a49b5 | ||
|
|
563507ca21 | ||
|
|
21b2d02f0a | ||
|
|
19e1a00fd7 | ||
|
|
a02a6a22d0 | ||
|
|
3488421f67 | ||
|
|
34a961088c | ||
|
|
b35509150a | ||
|
|
d096aa2065 | ||
|
|
efd5bef102 | ||
|
|
b8c6e44ab6 | ||
|
|
9a91cc43e2 | ||
|
|
f4cbab52a7 | ||
|
|
57b58cf203 | ||
|
|
9ba8ae08a1 | ||
|
|
dfe81f510e | ||
|
|
f3a0b35442 | ||
|
|
64e3be3bc7 | ||
|
|
4c82d1c56e | ||
|
|
d8451fc2f5 | ||
|
|
8078423252 | ||
|
|
68176b5695 | ||
|
|
1bf7833959 | ||
|
|
89770b922d | ||
|
|
716947bbb1 | ||
|
|
47e0d7786b | ||
|
|
55f9c40bba | ||
|
|
51afa30732 | ||
|
|
23c07316ee | ||
|
|
e740f52e5e | ||
|
|
a731109747 | ||
|
|
a50a011eb3 | ||
|
|
e22c6d3a94 | ||
|
|
50fb9c1795 | ||
|
|
22575c9a01 | ||
|
|
2934922cb5 | ||
|
|
9042ff46c7 | ||
|
|
a1a91539c2 | ||
|
|
468f4f94a3 | ||
|
|
3ebd35437e | ||
|
|
a166bbadad | ||
|
|
7ff07a132a | ||
|
|
6f297bcbb8 | ||
|
|
1c023e15af | ||
|
|
37f96848a7 | ||
|
|
3d04765f51 | ||
|
|
e1152fa549 | ||
|
|
ab47896f17 | ||
|
|
4f13565e51 | ||
|
|
7ab93a59e2 | ||
|
|
943c0d022b | ||
|
|
bea8922c39 | ||
|
|
97c96a7ee1 | ||
|
|
3d831ba7e8 | ||
|
|
df749a98cb | ||
|
|
22bbc9c621 | ||
|
|
30def4e515 | ||
|
|
cf8be37310 | ||
|
|
12409df446 | ||
|
|
3452a08de3 | ||
|
|
425ea0579e | ||
|
|
22afb769af | ||
|
|
884eae269e | ||
|
|
59a973970e | ||
|
|
225383464a | ||
|
|
3d82731325 | ||
|
|
dacdf08309 | ||
|
|
ad281adc97 | ||
|
|
80741c7773 | ||
|
|
532f7a4b17 | ||
|
|
5e87d582e4 | ||
|
|
b9bf47aaca | ||
|
|
0dba882817 | ||
|
|
c419883814 | ||
|
|
6f0ccbf2b5 | ||
|
|
54332c0bd1 | ||
|
|
5f80674e89 | ||
|
|
c4d0d8ff06 | ||
|
|
8ac1b7082a | ||
|
|
f146ae8be4 | ||
|
|
e7728fdc94 | ||
|
|
052122e4d0 | ||
|
|
38827d2b3d | ||
|
|
9e1f16be27 | ||
|
|
c845846317 | ||
|
|
9276556f19 | ||
|
|
c796d18948 | ||
|
|
8dee5520cf | ||
|
|
440e13714e | ||
|
|
44a70b372d | ||
|
|
504286e96e | ||
|
|
ffdd54d2fa | ||
|
|
32804b81c0 | ||
|
|
403b22ade0 | ||
|
|
a4e74abcca | ||
|
|
8dcef5bac0 | ||
|
|
49878bc4e3 | ||
|
|
3f1a71c8a4 | ||
|
|
bf9b2c0da3 | ||
|
|
909a274709 | ||
|
|
fc529b8083 | ||
|
|
f1386f26fb | ||
|
|
cccd09d329 | ||
|
|
0fccf7effe | ||
|
|
4b91a47c8b | ||
|
|
bd40499bbe | ||
|
|
c7c8cd76c6 | ||
|
|
0bb9f0ce41 | ||
|
|
7136afce8e | ||
|
|
ec17c1de6a | ||
|
|
8d6daef354 | ||
|
|
3a09d2de4a | ||
|
|
c78e10f92e | ||
|
|
b113ff35ac | ||
|
|
6360024d20 | ||
|
|
a7683f6bd7 | ||
|
|
e46a9f3f2a | ||
|
|
a8d711d4c8 | ||
|
|
df74fc67bd | ||
|
|
450261abbf | ||
|
|
12230edc54 | ||
|
|
d1cfcf561b | ||
|
|
d143f5af8b | ||
|
|
0f7ae3cda7 | ||
|
|
baf94e56c8 | ||
|
|
905bd1a4c9 | ||
|
|
96bcf24047 | ||
|
|
dfe47235cf | ||
|
|
b82ea8eaa8 | ||
|
|
b1b830c268 | ||
|
|
e654d4a6df | ||
|
|
ac30b17ecb | ||
|
|
95efdb3a51 | ||
|
|
49c165e203 | ||
|
|
a4be351d9f | ||
|
|
3d0401aecd | ||
|
|
7c27572a53 | ||
|
|
1e7760012e | ||
|
|
24d464b6e5 | ||
|
|
499d91f9f8 | ||
|
|
8e0ceaa06b | ||
|
|
4e62641f7e | ||
|
|
688644f5a4 | ||
|
|
4703f2d1f5 | ||
|
|
14149ae949 | ||
|
|
a0fb0d170c | ||
|
|
e133afec86 | ||
|
|
3ae8ee8ddb | ||
|
|
012643a231 | ||
|
|
dccb43f4dc | ||
|
|
15b3bc6a63 | ||
|
|
2d15bef76d | ||
|
|
756d298f04 | ||
|
|
9f35eb1a85 | ||
|
|
c905bb4b6c | ||
|
|
c78af01c8f | ||
|
|
084855645a | ||
|
|
afce9ece89 | ||
|
|
154e50e36d | ||
|
|
80a129102b | ||
|
|
93672a074e | ||
|
|
c7f6f6233c | ||
|
|
68915a9daf | ||
|
|
13eb91f8dd | ||
|
|
1a8355e6fb | ||
|
|
aa2b7ae60a | ||
|
|
acd36b7ea5 | ||
|
|
87245ab79f | ||
|
|
13b6a17827 | ||
|
|
615e4cf24e | ||
|
|
0e6d08f027 | ||
|
|
d593e584dd | ||
|
|
e046b97160 | ||
|
|
567d3dac55 | ||
|
|
a67a0aa924 | ||
|
|
1b1e3e88fe | ||
|
|
ec99636ef0 | ||
|
|
9d955d252a | ||
|
|
f136f6837a | ||
|
|
6fc1fb0966 | ||
|
|
fad203a66d | ||
|
|
71304b114a | ||
|
|
2497ac68d1 |
19
.github/release-drafter.yml
vendored
Normal file
19
.github/release-drafter.yml
vendored
Normal 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
22
.github/workflows/maven-build.yml
vendored
Normal 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
76
CODE_OF_CONDUCT.md
Normal 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
62
CONTRIBUTING.md
Normal 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
3
README
@@ -1,3 +0,0 @@
|
||||
Java API for GitHub
|
||||
|
||||
See http://github-api.kohsuke.org/ for more details
|
||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Java API for GitHub
|
||||
|
||||
See https://github-api.kohsuke.org/ for more details
|
||||
400
pom.xml
400
pom.xml
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
172
src/main/java/org/kohsuke/github/GHApp.java
Normal file
172
src/main/java/org/kohsuke/github/GHApp.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
167
src/main/java/org/kohsuke/github/GHAppInstallation.java
Normal file
167
src/main/java/org/kohsuke/github/GHAppInstallation.java
Normal 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);
|
||||
}
|
||||
}
|
||||
87
src/main/java/org/kohsuke/github/GHAppInstallationToken.java
Normal file
87
src/main/java/org/kohsuke/github/GHAppInstallationToken.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ public enum GHEvent {
|
||||
GOLLUM,
|
||||
INSTALLATION,
|
||||
INSTALLATION_REPOSITORIES,
|
||||
INTEGRATION_INSTALLATION_REPOSITORIES,
|
||||
CHECK_SUITE,
|
||||
ISSUE_COMMENT,
|
||||
ISSUES,
|
||||
LABEL,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
60
src/main/java/org/kohsuke/github/GHGistUpdater.java
Normal file
60
src/main/java/org/kohsuke/github/GHGistUpdater.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
81
src/main/java/org/kohsuke/github/GHIssueEvent.java
Normal file
81
src/main/java/org/kohsuke/github/GHIssueEvent.java
Normal 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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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() {
|
||||
|
||||
183
src/main/java/org/kohsuke/github/GHProject.java
Normal file
183
src/main/java/org/kohsuke/github/GHProject.java
Normal 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);
|
||||
}
|
||||
}
|
||||
123
src/main/java/org/kohsuke/github/GHProjectCard.java
Normal file
123
src/main/java/org/kohsuke/github/GHProjectCard.java
Normal 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());
|
||||
}
|
||||
}
|
||||
98
src/main/java/org/kohsuke/github/GHProjectColumn.java
Normal file
98
src/main/java/org/kohsuke/github/GHProjectColumn.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
// }
|
||||
}
|
||||
|
||||
22
src/main/java/org/kohsuke/github/GHRepositorySelection.java
Normal file
22
src/main/java/org/kohsuke/github/GHRepositorySelection.java
Normal 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);
|
||||
}
|
||||
}
|
||||
433
src/main/java/org/kohsuke/github/GHRepositoryStatistics.java
Normal file
433
src/main/java/org/kohsuke/github/GHRepositoryStatistics.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
24
src/main/java/org/kohsuke/github/GHTargetType.java
Normal file
24
src/main/java/org/kohsuke/github/GHTargetType.java
Normal 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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
30
src/main/java/org/kohsuke/github/Refreshable.java
Normal file
30
src/main/java/org/kohsuke/github/Refreshable.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
28
src/site/apt/githubappappinsttokenauth.apt
Normal file
28
src/site/apt/githubappappinsttokenauth.apt
Normal 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();
|
||||
+-----+
|
||||
41
src/site/apt/githubappflow.apt
Normal file
41
src/site/apt/githubappflow.apt
Normal 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}}
|
||||
|
||||
[]
|
||||
135
src/site/apt/githubappjwtauth.apt
Normal file
135
src/site/apt/githubappjwtauth.apt
Normal 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
154
src/site/apt/index.apt
Normal 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();
|
||||
+-----+
|
||||
@@ -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();
|
||||
BIN
src/site/resources/images/GitHub_App_Auth_Flow.jpg
Normal file
BIN
src/site/resources/images/GitHub_App_Auth_Flow.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
BIN
src/site/resources/images/Github_App_Id.png
Normal file
BIN
src/site/resources/images/Github_App_Id.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
222
src/test/java/org/kohsuke/github/AbstractGitHubWireMockTest.java
Normal file
222
src/test/java/org/kohsuke/github/AbstractGitHubWireMockTest.java
Normal 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
43
src/test/java/org/kohsuke/github/BridgeMethodTest.java
Normal file
43
src/test/java/org/kohsuke/github/BridgeMethodTest.java
Normal 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));
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
148
src/test/java/org/kohsuke/github/GHAppTest.java
Normal file
148
src/test/java/org/kohsuke/github/GHAppTest.java
Normal 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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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!");
|
||||
|
||||
|
||||
27
src/test/java/org/kohsuke/github/GHDeploymentTest.java
Normal file
27
src/test/java/org/kohsuke/github/GHDeploymentTest.java
Normal 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");
|
||||
}
|
||||
}
|
||||
@@ -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"));
|
||||
|
||||
73
src/test/java/org/kohsuke/github/GHGistUpdaterTest.java
Normal file
73
src/test/java/org/kohsuke/github/GHGistUpdaterTest.java
Normal 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());
|
||||
}
|
||||
}
|
||||
59
src/test/java/org/kohsuke/github/GHIssueEventTest.java
Normal file
59
src/test/java/org/kohsuke/github/GHIssueEventTest.java
Normal 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");
|
||||
}
|
||||
}
|
||||
@@ -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/")));
|
||||
}
|
||||
|
||||
|
||||
64
src/test/java/org/kohsuke/github/GHMilestoneTest.java
Normal file
64
src/test/java/org/kohsuke/github/GHMilestoneTest.java
Normal 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");
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
107
src/test/java/org/kohsuke/github/GHProjectCardTest.java
Normal file
107
src/test/java/org/kohsuke/github/GHProjectCardTest.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
74
src/test/java/org/kohsuke/github/GHProjectColumnTest.java
Normal file
74
src/test/java/org/kohsuke/github/GHProjectColumnTest.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
85
src/test/java/org/kohsuke/github/GHProjectTest.java
Normal file
85
src/test/java/org/kohsuke/github/GHProjectTest.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
329
src/test/java/org/kohsuke/github/GHPullRequestTest.java
Normal file
329
src/test/java/org/kohsuke/github/GHPullRequestTest.java
Normal 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");
|
||||
}
|
||||
}
|
||||
220
src/test/java/org/kohsuke/github/GHRepositoryStatisticsTest.java
Normal file
220
src/test/java/org/kohsuke/github/GHRepositoryStatisticsTest.java
Normal 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");
|
||||
}
|
||||
}
|
||||
277
src/test/java/org/kohsuke/github/GHRepositoryTest.java
Normal file
277
src/test/java/org/kohsuke/github/GHRepositoryTest.java
Normal 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"));
|
||||
}
|
||||
}
|
||||
35
src/test/java/org/kohsuke/github/GHTeamTest.java
Normal file
35
src/test/java/org/kohsuke/github/GHTeamTest.java
Normal 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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
85
src/test/java/org/kohsuke/github/GHUserTest.java
Normal file
85
src/test/java/org/kohsuke/github/GHUserTest.java
Normal 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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
377
src/test/java/org/kohsuke/github/GitHubConnectionTest.java
Normal file
377
src/test/java/org/kohsuke/github/GitHubConnectionTest.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
79
src/test/java/org/kohsuke/github/GitHubStaticTest.java
Normal file
79
src/test/java/org/kohsuke/github/GitHubStaticTest.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
140
src/test/java/org/kohsuke/github/WireMockStatusReporterTest.java
Normal file
140
src/test/java/org/kohsuke/github/WireMockStatusReporterTest.java
Normal 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
Reference in New Issue
Block a user