diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000000..ed1247ac692 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.yml] +indent_style = space +indent_size = 2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..c459022a96c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +* text=auto + +/doc export-ignore +/test export-ignore +/.* export-ignore +/phpunit.xml.dist export-ignore diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000000..823ad09b27d --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [acrobat] diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..6d2d16a545f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/backwards-compatibility.yml b/.github/workflows/backwards-compatibility.yml new file mode 100644 index 00000000000..8d13b2d512e --- /dev/null +++ b/.github/workflows/backwards-compatibility.yml @@ -0,0 +1,24 @@ +name: "BC check" + +on: + pull_request: + +jobs: + roave_bc_check: + name: "Roave BC check" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + + - name: Install roave/backward-compatibility-check + run: composer require --dev roave/backward-compatibility-check + + - name: Run roave/backward-compatibility-check + run: vendor/bin/roave-backward-compatibility-check --from=${{ github.event.pull_request.base.sha }} --format=github-actions diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000000..26fa98818e2 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,49 @@ +name: CI + +on: + [push, pull_request] + +jobs: + test: + name: Test on PHP ${{ matrix.php-versions }} + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] + + steps: + - uses: actions/checkout@v6 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + coverage: none + + - name: Install Composer Dependencies + uses: ramsey/composer-install@v3 + + - name: Run phpunit + run: vendor/bin/phpunit --verbose + env: + SYMFONY_DEPRECATIONS_HELPER: 'max[self]=0' + + phpstan: + name: PHPStan + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + + - uses: shivammathur/setup-php@v2 + with: + php-version: 7.2 + coverage: none + + - name: Install Composer Dependencies + uses: ramsey/composer-install@v3 + + - name: Run phpstan + run: vendor/bin/phpstan analyse --no-progress diff --git a/.gitignore b/.gitignore index fbeabd9bcd2..ebe7b7ea7a3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ +.php_cs.cache phpunit.xml +.phpunit.result.cache composer.lock composer.phar vendor/* diff --git a/.styleci.yml b/.styleci.yml new file mode 100644 index 00000000000..4187da89396 --- /dev/null +++ b/.styleci.yml @@ -0,0 +1,8 @@ +preset: recommended + +enabled: + - return_assignment + +disabled: + - align_double_arrow + - no_multiline_whitespace_before_semicolons diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 776d6a9b15b..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: php - -php: - - 5.3.3 - - 5.3 - - 5.4 - - 5.5 - -before_script: - - composer install --dev --prefer-source - -script: - - phpunit --coverage-text diff --git a/CHANGELOG-3.X.md b/CHANGELOG-3.X.md new file mode 100644 index 00000000000..f26bcc96430 --- /dev/null +++ b/CHANGELOG-3.X.md @@ -0,0 +1,231 @@ +# Changelog + +## 3.16.0 + +### Added +- Add API to rerequest a check run ([Spea](https://github.com/Spea)) [#1141](https://github.com/KnpLabs/php-github-api/issues/1141) +- List pull requests associated with a commit ([lmjhs](https://github.com/lmjhs)) [#1146](https://github.com/KnpLabs/php-github-api/issues/1146) + +## 3.15.0 + +### Added +- Fix implicit nullable types to avoid PHP 8.4 warnings ([eiriksm](https://github.com/eiriksm), [acrobat](https://github.com/acrobat)) [#1144](https://github.com/KnpLabs/php-github-api/issues/1144) +- Add API endpoints to interact with organization roles ([glaubinix](https://github.com/glaubinix)) [#1143](https://github.com/KnpLabs/php-github-api/issues/1143) +- Copilot Usage Endpoints ([anthony-webart](https://github.com/anthony-webart)) [#1142](https://github.com/KnpLabs/php-github-api/issues/1142) +- Fix type error in ResultPager::fetch ([nunoplopes](https://github.com/nunoplopes)) [#1132](https://github.com/KnpLabs/php-github-api/issues/1132) + +## 3.14.1 + +### Fixed +- Handle case of GitHub returning 204 No Content in some scenarios ([tomcorbett](https://github.com/tomcorbett)) [#1135](https://github.com/KnpLabs/php-github-api/issues/1135) + +## 3.14.0 + +### Added +- Allow php-http/cache-plugin v2 ([GrahamCampbell](https://github.com/GrahamCampbell)) [#1134](https://github.com/KnpLabs/php-github-api/issues/1134) + +## 3.13.0 + +### Added +- Test against php 8.3 ([sergiy-petrov](https://github.com/sergiy-petrov)) [#1124](https://github.com/KnpLabs/php-github-api/issues/1124) +- feat: Secret Scanning Alerts ([haridarshan](https://github.com/haridarshan)) [#1114](https://github.com/KnpLabs/php-github-api/issues/1114) +- feat: User Migration ([haridarshan](https://github.com/haridarshan)) [#1115](https://github.com/KnpLabs/php-github-api/issues/1115) + +### Changed +- General chores ([acrobat](https://github.com/acrobat)) [#1125](https://github.com/KnpLabs/php-github-api/issues/1125) + +### Fixed +- Fix detection of secondary rate limit ([mathieudz](https://github.com/mathieudz)) [#1126](https://github.com/KnpLabs/php-github-api/issues/1126) + +## 3.12.0 + +### Added +- feat: Support for Organization Runners ([haridarshan](https://github.com/haridarshan), [renovate](https://github.com/renovate)[[bot](https://github.com/bot)]) [#1101](https://github.com/KnpLabs/php-github-api/issues/1101) +- allow psr/http-message v2 ([LordSimal](https://github.com/LordSimal)) [#1122](https://github.com/KnpLabs/php-github-api/issues/1122) + +### Changed +- Fixed branch alias ([GrahamCampbell](https://github.com/GrahamCampbell)) [#1109](https://github.com/KnpLabs/php-github-api/issues/1109) + +## 3.11.0 + +### Added +- Added environment variables & secrets ([Froxz](https://github.com/Froxz)) [#1104](https://github.com/KnpLabs/php-github-api/issues/1104) +- Added Org & Repository variables ([Froxz](https://github.com/Froxz)) [#1106](https://github.com/KnpLabs/php-github-api/issues/1106) +- Deployment branch policies ([Froxz](https://github.com/Froxz)) [#1108](https://github.com/KnpLabs/php-github-api/issues/1108) + +### Changed +- Test on PHP 8.2 ([GrahamCampbell](https://github.com/GrahamCampbell)) [#1105](https://github.com/KnpLabs/php-github-api/issues/1105) + +### Fixed +- Bugfix creating env ([Froxz](https://github.com/Froxz)) [#1107](https://github.com/KnpLabs/php-github-api/issues/1107) + +## 3.10.0 + +### Added +- Add vulnerability alerts endpoints ([andreia](https://github.com/andreia)) [#1096](https://github.com/KnpLabs/php-github-api/issues/1096) +- Added environments ([Froxz](https://github.com/Froxz)) [#1103](https://github.com/KnpLabs/php-github-api/issues/1103) + +### Changed +- Create authorization removed from docs ([rafasashi](https://github.com/rafasashi)) [#1090](https://github.com/KnpLabs/php-github-api/issues/1090) +- Setup dependabot for github action workflows ([acrobat](https://github.com/acrobat)) [#1098](https://github.com/KnpLabs/php-github-api/issues/1098) +- Bump actions/checkout from 2 to 3 ([dependabot](https://github.com/dependabot)[[bot](https://github.com/bot)]) [#1099](https://github.com/KnpLabs/php-github-api/issues/1099) +- Bump ramsey/composer-install from 1 to 2 ([dependabot](https://github.com/dependabot)[[bot](https://github.com/bot)]) [#1100](https://github.com/KnpLabs/php-github-api/issues/1100) + +## 3.9.0 + +### Added +- Add the ability to download raw file, needed when size > 1MB ([genintho](https://github.com/genintho)) [#1075](https://github.com/KnpLabs/php-github-api/issues/1075) +- Feat: Support new Team Repositories Endpoint ([iBotPeaches](https://github.com/iBotPeaches)) [#1082](https://github.com/KnpLabs/php-github-api/issues/1082) +- App: add hook endpoints ([glaubinix](https://github.com/glaubinix)) [#1086](https://github.com/KnpLabs/php-github-api/issues/1086) +- Add sync a fork branch with the upstream repository ([DAGpro](https://github.com/DAGpro)) [#1084](https://github.com/KnpLabs/php-github-api/issues/1084) + +### Changed +- Fix return types in phpdoc for `Assignees` and `ReviewRequest` ([rob006](https://github.com/rob006)) [#1078](https://github.com/KnpLabs/php-github-api/issues/1078) +- Fixed several typos and grammar errors ([AndrewDawes](https://github.com/AndrewDawes)) [#1088](https://github.com/KnpLabs/php-github-api/issues/1088) + +## 3.8.0 + +### Added +- API rate limit error status can be 403 ([matthewnessworthy](https://github.com/matthewnessworthy)) [#1072](https://github.com/KnpLabs/php-github-api/issues/1072) +- Add method to use generate release notes endpoint ([GuySartorelli](https://github.com/GuySartorelli)) [#1074](https://github.com/KnpLabs/php-github-api/issues/1074) +- Fix typehint for repository dispatch method ([cweagans](https://github.com/cweagans)) [#1066](https://github.com/KnpLabs/php-github-api/issues/1066) + +### Changed +- Update security.md ([secalith-code](https://github.com/secalith-code)) [#1076](https://github.com/KnpLabs/php-github-api/issues/1076) + +### Fixed +- dont require encoding ([gemal](https://github.com/gemal)) [#1071](https://github.com/KnpLabs/php-github-api/issues/1071) + +## 3.7.0 + +### Added +- added phpdocs ([staabm](https://github.com/staabm)) [#1068](https://github.com/KnpLabs/php-github-api/issues/1068) +- added missing magic method phpdocs for deployments ([staabm](https://github.com/staabm)) [#1069](https://github.com/KnpLabs/php-github-api/issues/1069) +- Fix issue https://github.com/KnpLabs/php-github-api/issues/1061 ([mruell](https://github.com/mruell)) [#1062](https://github.com/KnpLabs/php-github-api/issues/1062) + +### Changed +- Updates ReviewRequest Create method to return type Array ([ejntaylor](https://github.com/ejntaylor)) [#1060](https://github.com/KnpLabs/php-github-api/issues/1060) + +## 3.6.0 + +### Added +- Include optional params parameter for Commits compare method ([mountiny](https://github.com/mountiny)) [#1053](https://github.com/KnpLabs/php-github-api/issues/1053) + +### Changed +- Update incorrect documentation ([pheeque1](https://github.com/pheeque1)) [#1058](https://github.com/KnpLabs/php-github-api/issues/1058) + +### Fixed +- fix(Apps): use /orgs/ORG/installation ([ellisio](https://github.com/ellisio)) [#1056](https://github.com/KnpLabs/php-github-api/issues/1056) + +## 3.5.1 + +### Fixed +- Boolean private needed to create private repo! ([mruell](https://github.com/mruell)) [#1051](https://github.com/KnpLabs/php-github-api/issues/1051) + +## 3.5.0 + +### Added +- added support for psr\cache 3.0 ([rconfig](https://github.com/rconfig)) [#1046](https://github.com/KnpLabs/php-github-api/issues/1046) +- Symfony: allow deprecation-contracts version 3 ([glaubinix](https://github.com/glaubinix)) [#1049](https://github.com/KnpLabs/php-github-api/issues/1049) + +### Changed +- Fix internal doc link ([staudenmeir](https://github.com/staudenmeir)) [#1044](https://github.com/KnpLabs/php-github-api/issues/1044) + +### Fixed +- Fix Client URL Prepending For GraphQL Endpoint on Enterprise ([asher-goldberg](https://github.com/asher-goldberg), [acrobat](https://github.com/acrobat)) [#1048](https://github.com/KnpLabs/php-github-api/issues/1048) + +## 3.4.0 + +### Added +- Add create a repository using a template endpoint ([martinbean](https://github.com/martinbean)) [#994](https://github.com/KnpLabs/php-github-api/issues/994) +- Allow fetching repo readme for a specific ref ([bery](https://github.com/bery)) [#1019](https://github.com/KnpLabs/php-github-api/issues/1019) +- allow assigning role to organisation members ([luceos](https://github.com/luceos)) [#1018](https://github.com/KnpLabs/php-github-api/issues/1018) +- Branch lists . ( ? query per_page) ([pitonic](https://github.com/pitonic)) [#1020](https://github.com/KnpLabs/php-github-api/issues/1020) +- Php8.1 support ([acrobat](https://github.com/acrobat)) [#1025](https://github.com/KnpLabs/php-github-api/issues/1025) +- Allow psr/cache 2.0 as well as 1.0 ([johnnoel](https://github.com/johnnoel)) [#1029](https://github.com/KnpLabs/php-github-api/issues/1029) +- adding code_with_match (#1024) ([QuentinRa](https://github.com/QuentinRa)) [#1031](https://github.com/KnpLabs/php-github-api/issues/1031) +- Added dir parameter for Repo readme ([AlexandrePavy](https://github.com/AlexandrePavy)) [#1032](https://github.com/KnpLabs/php-github-api/issues/1032) +- refs #955: deprecate Client::AUTH_* constants and replace them with AuthMethod::AUTH_* const ([ipalo](https://github.com/ipalo)) [#1036](https://github.com/KnpLabs/php-github-api/issues/1036) +- feat: Add `visibility` option to repo create ([gerdemann](https://github.com/gerdemann)) [#1038](https://github.com/KnpLabs/php-github-api/issues/1038) +- Feature get authenticated app ([kdaniel95](https://github.com/kdaniel95)) [#1041](https://github.com/KnpLabs/php-github-api/issues/1041) + +### Changed +- Fix up typos ([dereuromark](https://github.com/dereuromark)) [#1011](https://github.com/KnpLabs/php-github-api/issues/1011) +- Update integration authentication documentation for usage with lcobucci/jwt ^4 ([glaubinix](https://github.com/glaubinix)) [#1017](https://github.com/KnpLabs/php-github-api/issues/1017) +- Update result_pager.md ([tomsowerby](https://github.com/tomsowerby)) [#1023](https://github.com/KnpLabs/php-github-api/issues/1023) +- fix(doc): links to doc in CurrentUser class ([Nek-](https://github.com/Nek-)) [#1026](https://github.com/KnpLabs/php-github-api/issues/1026) +- Fix incorrect phpdoc ([gemal](https://github.com/gemal)) [#1034](https://github.com/KnpLabs/php-github-api/issues/1034) + +### Fixed +- Add accept header for creating repo from template ([davidpeach](https://github.com/davidpeach)) [#1030](https://github.com/KnpLabs/php-github-api/issues/1030) + +## 3.3.0 + +### Added +- Allow costume accept headers for GraphQL Endpoint. ([Necmttn](https://github.com/Necmttn)) [#1001](https://github.com/KnpLabs/php-github-api/issues/1001) +- Add endpoint for approve workflow run ([Nyholm](https://github.com/Nyholm)) [#1006](https://github.com/KnpLabs/php-github-api/issues/1006) + +### Changed +- Update readme and add example for different http client usage ([acrobat](https://github.com/acrobat)) [#1002](https://github.com/KnpLabs/php-github-api/issues/1002) +- Bumped branch alias after new feature merged ([GrahamCampbell](https://github.com/GrahamCampbell)) [#1004](https://github.com/KnpLabs/php-github-api/issues/1004) +- Add comment on AbstractApi::$perPage() ([Nyholm](https://github.com/Nyholm)) [#1007](https://github.com/KnpLabs/php-github-api/issues/1007) + +### Fixed +- Fix publicKey ([Yurunsoft](https://github.com/Yurunsoft)) [#1005](https://github.com/KnpLabs/php-github-api/issues/1005) + +## 3.2.0 + +### Added +- Deprecate ResultPager::postFetch method ([acrobat](https://github.com/acrobat)) [#986](https://github.com/KnpLabs/php-github-api/issues/986) +- Add deprecations to the PR review methods to allow cleanup ([acrobat](https://github.com/acrobat)) [#984](https://github.com/KnpLabs/php-github-api/issues/984) +- Allow binary content downloads of assets ([acrobat](https://github.com/acrobat)) [#990](https://github.com/KnpLabs/php-github-api/issues/990) +- Deployments: added missing 'delete deployment' endpoint ([clxmstaab](https://github.com/clxmstaab)) [#991](https://github.com/KnpLabs/php-github-api/issues/991) +- Events list per authenticated user for all repos ([richard015ar](https://github.com/richard015ar)) [#1000](https://github.com/KnpLabs/php-github-api/issues/1000) + +### Changed +- Fixed branch alias ([GrahamCampbell](https://github.com/GrahamCampbell)) [#975](https://github.com/KnpLabs/php-github-api/issues/975) +- fix typo ([staabm](https://github.com/staabm)) [#977](https://github.com/KnpLabs/php-github-api/issues/977) +- Improved bc check ([acrobat](https://github.com/acrobat)) [#982](https://github.com/KnpLabs/php-github-api/issues/982) +- Correctly link to github actions docs and fix backlinks ([acrobat](https://github.com/acrobat)) [#983](https://github.com/KnpLabs/php-github-api/issues/983) +- Add missing repo hooks documentation ([acrobat](https://github.com/acrobat)) [#987](https://github.com/KnpLabs/php-github-api/issues/987) +- Fix incorrect public key documentation ([acrobat](https://github.com/acrobat)) [#988](https://github.com/KnpLabs/php-github-api/issues/988) +- Fixed incorrect parameters in apps docs ([acrobat](https://github.com/acrobat)) [#989](https://github.com/KnpLabs/php-github-api/issues/989) +- phpdoc: fix typo ([clxmstaab](https://github.com/clxmstaab)) [#993](https://github.com/KnpLabs/php-github-api/issues/993) +- Fix upmerged usage of deprecated phpunit assert ([acrobat](https://github.com/acrobat)) [#995](https://github.com/KnpLabs/php-github-api/issues/995) +- Fix typo ([romainneutron](https://github.com/romainneutron)) [#997](https://github.com/KnpLabs/php-github-api/issues/997) + +### Fixed +- Deployments: use proper media-type for in_progress/queued, inactive state ([staabm](https://github.com/staabm)) [#979](https://github.com/KnpLabs/php-github-api/issues/979) +- [952] doc - Specify lcobucci/jwt version, fix deprecation ([amacrobert-meq](https://github.com/amacrobert-meq), [acrobat](https://github.com/acrobat)) [#953](https://github.com/KnpLabs/php-github-api/issues/953) +- Replace deprecated organization team repository add/remove urls ([acrobat](https://github.com/acrobat)) [#985](https://github.com/KnpLabs/php-github-api/issues/985) +- fixed php warning in GithubExceptionThrower ([clxmstaab](https://github.com/clxmstaab), [acrobat](https://github.com/acrobat)) [#992](https://github.com/KnpLabs/php-github-api/issues/992) + +## 3.1.0 + +### Added +- Add workflow dispatch and allow workflow names. ([fodinabor](https://github.com/fodinabor)) [#969](https://github.com/KnpLabs/php-github-api/issues/969) + +### Changed +- Re-enable roave bc check for 3.x ([acrobat](https://github.com/acrobat)) [#958](https://github.com/KnpLabs/php-github-api/issues/958) +- Cleanup 3.0.0 changelog ([acrobat](https://github.com/acrobat)) [#957](https://github.com/KnpLabs/php-github-api/issues/957) +- Update new GitHub doc links in repo. ([fodinabor](https://github.com/fodinabor)) [#974](https://github.com/KnpLabs/php-github-api/issues/974) + +### Fixed +- Add accept header for the checks API ([Agares](https://github.com/Agares)) [#968](https://github.com/KnpLabs/php-github-api/issues/968) +- ExceptionThrower: adjust rate limit detection ([glaubinix](https://github.com/glaubinix)) [#959](https://github.com/KnpLabs/php-github-api/issues/959) + +## 3.0.0 + +### Added +- Switch to PSR18 client implementation and bump httplug minimum version to ^2.0 ([GrahamCampbell](https://github.com/GrahamCampbell)) [#885](https://github.com/KnpLabs/php-github-api/issues/885) +- Switch to PSR-17 and remove deprecated code ([GrahamCampbell](https://github.com/GrahamCampbell)) [#888](https://github.com/KnpLabs/php-github-api/issues/888) +- Allow PHP8 ([acrobat](https://github.com/acrobat)) [#934](https://github.com/KnpLabs/php-github-api/issues/934) +- [3.x] Make PHP 7.2.5 the minimum version ([GrahamCampbell](https://github.com/GrahamCampbell)) [#942](https://github.com/KnpLabs/php-github-api/issues/942) +- [3.x] Re-worked pagination to not mutate the api classes ([GrahamCampbell](https://github.com/GrahamCampbell)) [#907](https://github.com/KnpLabs/php-github-api/issues/907) & ([acrobat](https://github.com/acrobat)) [#956](https://github.com/KnpLabs/php-github-api/issues/956) +- Prepare 3.0 release and remove remaining deprecated code ([acrobat](https://github.com/acrobat)) [#948](https://github.com/KnpLabs/php-github-api/issues/948) + +### Changed +- Remove BC check on 3.x ([GrahamCampbell](https://github.com/GrahamCampbell)) [#900](https://github.com/KnpLabs/php-github-api/issues/900) +- [3.x] Fix the HTTP methods client ([GrahamCampbell](https://github.com/GrahamCampbell)) [#910](https://github.com/KnpLabs/php-github-api/issues/910) +- fix typo ([michielkempen](https://github.com/michielkempen)) [#920](https://github.com/KnpLabs/php-github-api/issues/920) +- [3.x] Added some additional scalar types and return types ([GrahamCampbell](https://github.com/GrahamCampbell)) [#949](https://github.com/KnpLabs/php-github-api/issues/949) diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000000..47980eff62f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,438 @@ +# Changelog + +## 2.20.0 + +### Added +- Deployments: added missing 'delete deployment' endpoint ([clxmstaab](https://github.com/clxmstaab)) [#991](https://github.com/KnpLabs/php-github-api/issues/991) + +### Changed +- phpdoc: fix typo ([clxmstaab](https://github.com/clxmstaab)) [#993](https://github.com/KnpLabs/php-github-api/issues/993) + +### Fixed +- fixed php warning in GithubExceptionThrower ([clxmstaab](https://github.com/clxmstaab), [acrobat](https://github.com/acrobat)) [#992](https://github.com/KnpLabs/php-github-api/issues/992) + +## 2.19.2 + +### Changed +- Improved bc check ([acrobat](https://github.com/acrobat)) [#982](https://github.com/KnpLabs/php-github-api/issues/982) +- Correctly link to github actions docs and fix backlinks ([acrobat](https://github.com/acrobat)) [#983](https://github.com/KnpLabs/php-github-api/issues/983) +- Add missing repo hooks documentation ([acrobat](https://github.com/acrobat)) [#987](https://github.com/KnpLabs/php-github-api/issues/987) +- Fix incorrect public key documentation ([acrobat](https://github.com/acrobat)) [#988](https://github.com/KnpLabs/php-github-api/issues/988) +- Fixed incorrect parameters in apps docs ([acrobat](https://github.com/acrobat)) [#989](https://github.com/KnpLabs/php-github-api/issues/989) + +### Fixed +- Deployments: use proper media-type for in_progress/queued, inactive state ([staabm](https://github.com/staabm)) [#979](https://github.com/KnpLabs/php-github-api/issues/979) +- backported #979 into 2.x ([staabm](https://github.com/staabm)) [#981](https://github.com/KnpLabs/php-github-api/issues/981) +- [952] doc - Specify lcobucci/jwt version, fix deprecation ([amacrobert-meq](https://github.com/amacrobert-meq), [acrobat](https://github.com/acrobat)) [#953](https://github.com/KnpLabs/php-github-api/issues/953) +- Replace deprecated organization team repository add/remove urls ([acrobat](https://github.com/acrobat)) [#985](https://github.com/KnpLabs/php-github-api/issues/985) + +## 2.19.1 + +### Fixed +- ExceptionThrower: adjust rate limit detection ([glaubinix](https://github.com/glaubinix)) [#959](https://github.com/KnpLabs/php-github-api/issues/959) + +## 2.19.0 + +### Added +- Mark some classes as final ([acrobat](https://github.com/acrobat)) [#954](https://github.com/KnpLabs/php-github-api/issues/954) + +## 2.18.0 + +### Added +- Add parameters to PullRequest commits method ([seanmtaylor](https://github.com/seanmtaylor)) [#938](https://github.com/KnpLabs/php-github-api/issues/938) +- Actions (#872) ([lexor](https://github.com/lexor)) [#939](https://github.com/KnpLabs/php-github-api/issues/939) +- automated security endpoints (#868) ([lexor](https://github.com/lexor)) [#944](https://github.com/KnpLabs/php-github-api/issues/944) + +### Changed +- Update apps.md ([clarkeash](https://github.com/clarkeash)) [#936](https://github.com/KnpLabs/php-github-api/issues/936) + +### Fixed +- Throw exception for graphql errors ([acrobat](https://github.com/acrobat)) [#941](https://github.com/KnpLabs/php-github-api/issues/941) + +## 2.17.0 + +### Added + +- Improve checks api implementation ([acrobat](https://github.com/acrobat)) [#932](https://github.com/KnpLabs/php-github-api/issues/932) + +### Changed +- Missing auth method in list of omitted passwords. ([tobyS](https://github.com/tobyS)) [#933](https://github.com/KnpLabs/php-github-api/issues/933) +- Improve github actions setup ([acrobat](https://github.com/acrobat)) [#935](https://github.com/KnpLabs/php-github-api/issues/935) + +## 2.16.0 + +### Added +- Add support for SSO errors coming from the API ([eiriksm](https://github.com/eiriksm)) [#913](https://github.com/KnpLabs/php-github-api/issues/913) +- Add OutsideCollaborators api ([Matth--](https://github.com/Matth--)) [#925](https://github.com/KnpLabs/php-github-api/issues/925) +- Add support for creating a repo dispatch event ([Nyholm](https://github.com/Nyholm)) [#931](https://github.com/KnpLabs/php-github-api/issues/931) + +### Changed +- Fix: Wrong PHPDoc description ([OskarStark](https://github.com/OskarStark)) [#922](https://github.com/KnpLabs/php-github-api/issues/922) +- Adding GitHub authentication to GraphQL documentation ([legionth](https://github.com/legionth)) [#927](https://github.com/KnpLabs/php-github-api/issues/927) + +### Fixed +- Use RFC3986 for building URI query strings ([GrahamCampbell](https://github.com/GrahamCampbell)) [#908](https://github.com/KnpLabs/php-github-api/issues/908) +- Fix call to test a webhook method ([morrislaptop](https://github.com/morrislaptop)) [#915](https://github.com/KnpLabs/php-github-api/issues/915) + +## 2.15.0 + +### Added +- Prepare deprecation of authentication methods ([acrobat](https://github.com/acrobat)) [#870](https://github.com/KnpLabs/php-github-api/issues/870) +- Add Support For GitData Reference Matching Methods ([nickpoulos](https://github.com/nickpoulos)) [#875](https://github.com/KnpLabs/php-github-api/issues/875) +- Make invalid request error more clear ([acrobat](https://github.com/acrobat)) [#880](https://github.com/KnpLabs/php-github-api/issues/880) +- Show user by ID ([genintho](https://github.com/genintho)) [#894](https://github.com/KnpLabs/php-github-api/issues/894) +- add additional check run methods ([bobeagan](https://github.com/bobeagan), [acrobat](https://github.com/acrobat)) [#865](https://github.com/KnpLabs/php-github-api/issues/865) + +### Changed +- Added phpstan ([clxkoders](https://github.com/clxkoders)) [#871](https://github.com/KnpLabs/php-github-api/issues/871) +- Increase phpstan to level 4 ([acrobat](https://github.com/acrobat)) [#874](https://github.com/KnpLabs/php-github-api/issues/874) +- [Documentation] Add Missing Children to Pull Request Index ([jimlind](https://github.com/jimlind)) [#877](https://github.com/KnpLabs/php-github-api/issues/877) +- [Documentation] Include links to Pull Request Children on Pull Request Doc. ([jimlind](https://github.com/jimlind)) [#878](https://github.com/KnpLabs/php-github-api/issues/878) +- Fix typo in /lib/Github/Api/RateLimit.php ([yoonper](https://github.com/yoonper)) [#886](https://github.com/KnpLabs/php-github-api/issues/886) +- Don't use deprecated auth in examples ([GrahamCampbell](https://github.com/GrahamCampbell)) [#892](https://github.com/KnpLabs/php-github-api/issues/892) +- Removed shadow-cat ([GrahamCampbell](https://github.com/GrahamCampbell)) [#893](https://github.com/KnpLabs/php-github-api/issues/893) +- Don't urlencode integer values ([acrobat](https://github.com/acrobat)) [#895](https://github.com/KnpLabs/php-github-api/issues/895) +- phpstan level 6 fixes ([acrobat](https://github.com/acrobat), [GrahamCampbell](https://github.com/GrahamCampbell)) [#897](https://github.com/KnpLabs/php-github-api/issues/897) + +### Fixed +- fix: use new media type for branch protections ([iBotPeaches](https://github.com/iBotPeaches)) [#881](https://github.com/KnpLabs/php-github-api/issues/881) +- Added missing 'machine-man-preview' accept headers ([vovayatsyuk](https://github.com/vovayatsyuk)) [#883](https://github.com/KnpLabs/php-github-api/issues/883) +- Fix broken roave/bc-check test ([acrobat](https://github.com/acrobat)) [#890](https://github.com/KnpLabs/php-github-api/issues/890) +- Fixed incorrect MissingArgumentException parent constructor values ([acrobat](https://github.com/acrobat)) [#896](https://github.com/KnpLabs/php-github-api/issues/896) +- Added AUTH_ACCESS_TOKEN to allowed methods ([GrahamCampbell](https://github.com/GrahamCampbell)) [#899](https://github.com/KnpLabs/php-github-api/issues/899) + +## 2.14.0 + +### Added +- Replace deprecated Organization\Teams api calls ([lolos](https://github.com/lolos)) [#860](https://github.com/KnpLabs/php-github-api/issues/860) +- Add sort and direction for fetching organizations repos ([pgrimaud](https://github.com/pgrimaud)) [#863](https://github.com/KnpLabs/php-github-api/issues/863) +- Added parameters to Repo/milestones() method ([dereuromark](https://github.com/dereuromark)) [#856](https://github.com/KnpLabs/php-github-api/issues/856) + +### Fixed + +- Remove incorrect MissingArgumentException in Labels api ([bobeagan](https://github.com/bobeagan)) [#861](https://github.com/KnpLabs/php-github-api/issues/861) + +### Changed +- Fix typos in test/Github/Tests/Api/RepoTest.php ([pgrimaud](https://github.com/pgrimaud)) [#862](https://github.com/KnpLabs/php-github-api/issues/862) +- further detail on ResultPager parameters ([sepiariver](https://github.com/sepiariver)) [#843](https://github.com/KnpLabs/php-github-api/issues/843) +- fix phpdoc in labels api ([staabm](https://github.com/staabm)) [#854](https://github.com/KnpLabs/php-github-api/issues/854) +- fix api link in Issue\Labels::add() phpdoc ([staabm](https://github.com/staabm)) [#853](https://github.com/KnpLabs/php-github-api/issues/853) + +## 2.13.0 + +### Added + +- Support the new authorizations API +- Repo community profile API endpoint +- Support for draft PRs +- Missing Apps endpoints +- Test against php 7.4 + +### Changed + +- Allow create & remove to set and remove requests for teams + +## 2.12.1 + +### Fixed + +- Fixed bug in handling of validation errors +- Updated docs to not use deprected string parameter in issue assignee call + +## 2.12.0 + +### Added + +- Support for HTTPlug 2.0 and PSR-18 +- Add support for GitHub Checks +- Add support for GitHub Pages +- Add support to update a Pull Request Review +- Add support to get specific revision of a gist +- Added a 4th argument `$parameters` to `PullRequest::files()` +- Added `Accept` headers to Github Apps + +### Removed + +- Active support for HHVM +- Support for PHP <7.1 + +### Changed + +- Allow tags to be created without the `Tagger` object +- When updating DeployKeys we will first remove existing then add a new DeployKey + +### Fixed + +- In `Trees` we should check if `array_key_exists('sha', $tree)` instead of `isset` to avoid issues with `null`. (#822) + +### Deprecated + +- Passing an integer (`$page`) as 4th arugment in `Comments::all()` is deprecated. It should be an array. + +## 2.11.0 + +### Added + +- Support for Miscellaneous Licenses (#744) +- Structured Limit objects for rate limiting API (#733) +- Support for getting star creation timestamps in activity/starring endpoint (#729) + +### Fixed + +- Added missing has_projects parameter to repo create (#752) +- Proper type hinting for magic methods (#758) +- Allow symlink to files to be downloaded (#751) + +### Changed + +- Fix of PHP version in readme (#747) +- Fix documentation to get release for a tag (#755) +- Declare all used properties in RateLimitResource class (#762) +- Set correct property and return types (#764) +- Fixed install docs broken after 2.0 release of httplug lib (#767) + +## 2.10.1 + +### Fixed + +- Convert the assignee parameter to array to avoid getting a 422 error on github (#738) +- Fix GraphQL test warnings when they do not assert anything (#735) + +### Changed + +- Check for BC breaks during the travis build (#734) + +## 2.10.0 + +### Added + +- Support for "before" parameter on Notification API (#724) + +### Changed + +- Allow unspecified `event` when creating review (#723) + +### Fixed + +- Adjust: installationn access token endpoint (#731) +- Fixed "get single label" example and add correct example for getting issue's labels (#732) +- Add comment about `Key` constructor argument (#722) + +## 2.9.0 + +### Added + +- API endpoint `Github\Api\Repo::transfer()` +- API endpoint `Github\Api\Notification::markThreadRead()` +- API endpoint `Github\Api\Search::topics()` + +### Fixed + +- Make sure to always reset the "per page" in `Github\ResultPager::fetchAll()`. + +## 2.8.0 + +### Added + +- Allow our HTTP plugins to show up in the Symfony web profiler page. (#687) +- Repository documentation to current user (#671) +- Add collaborator permission call (#678) +- Add missing parameters for User/CurrentUser Repositories (#684) +- Pimp the readme with badge poser (#686) + +### Fixed + +- Typo in assignee documentation +- Missing use statement in security example +- Fixed phpdoc typo (#695) +- Replace use of deprecated api to the correct one in the security docs (#697) + +### Changed + +- Updated requirements in readme (#689) + +## 2.7.0 + +### Added + +- Phpunit 6 compatibility +- `Github\Api\AbstractApi::setPage()` to allow you to set the page on all endpoints. +- Support for query parameters and request headers on `Github\Api\User::following` and `Github\Api\User::followers` +- API endpoint `Github\Api\CurrentUser\Emails::allPublic()` +- API endpoint `Github\Api\Search::commits()` +- API endpoint `Github\Api\Miscellaneous\CodeOfConduct` +- API endpoint `Github\Api\Repo::topics()` +- API endpoint `Github\Api\Repo::replaceTopics()` + +### Fixed + +- Fixed bug in `PathPrepend` plugin where "api/vX" could be duplicated. + +### Changed + +- Improved documentation and doc blocks + +### Removed + +- Dropped support for php 5.5 + +### Deprecated + +The following endpoints were deprecated by Github and are also deprecated in the client: + +- `Github\Api\Repo::find()` +- `Github\Api\User::find()` +- `Github\Api\Issue::find()` + +## 2.6.0 + +### Added + +- Support for graphql api [variables](https://developer.github.com/v4/guides/forming-calls/#working-with-variables) (#612) +- Added missing branch protection methods (#616) +- Helper function `fromFile ` to get GraphQL queries from a file (#628) +- Extra parameter `params` to collaborators api calls (#623) +- Documentation for GitData API (#613) + +### Fixed +- Remove `body` as a required parameter when creating an issue (#624) +- Minor fixes in example code (#617) + +## 2.5.0 + +### Added + +- Stable support for graphql api (V4) (#593) +- Stable support for apps (previously integrations) (#592) +- `Repo::events()` + +### Fixed + +- Incorrect link in repository search docs (#594) +- Added the required parameter `$message` on `Review::dismiss`. + +## 2.4.0 + +### Added + +- `Integrations::configure` to allow accessing early access program endpoints. +- Add support for pagination and parameters in the pull request comments +- Add the ability to fetch user installations (`CurrentUser::installations`) +- Allow getting repo info by id (`Repo::showById`) +- Allow fetching repositories for a specific installation and user (`CurrentUser::repositoriesByInstallation`) + +### Changed + +- `PullRequest\Review` and `PullRequest\ReviewRequest` is now part of the official API. No need to call `configure`. + +## 2.3.0 + +### Fixed + +- Issue where we serve the wrong cached response. We vary on authorization header now. + +### Added + +- `PullRequest::status` +- Throw InvalidArgumentException on `PullRequest::merge` when wrong merge method is used. +- Added `Protection::configure` + +### Changed + +- First argument to `Integrations::listRepositories()` is now optional. +- Moved tests from "functional" to "integration" + +## 2.2.0 + +### Added + +- API support for Pull Request Review Requests. +- API support for Traffic. +- API support for issue Assignees. +- API support for Miscellaneous Gitignore and Emojis. +- Added endpoints for issue lock, unlock and issue label show. +- Added more parameters to `User::starred`. +- Fluid interface by allowing `configure()` to return `$this`. +- `configure()` support for issues API. + +### Fixed + +- Cache issue where some requests are not cached +- Issue with `User::all()` creates a query with double question marks. + +## 2.1.0 + +### Added + +- Add support for retrieving a single notification info using his ID +- Add a function to get user organizations +- Added GraphQL support +- Add page variable to organization repo list (Organization::repositories()) +- Add support for pull request review. +- Add support for adding branch protection. + +### Fixed + +- Bug with double slashes when using enterprise URL. +- Bug when headers not being passed to request (#529) + +## 2.0.0 + +### Added + +- Support for JWT authentication +- API for Organization\Members +- API for Integrations +- API for Repo\Cards +- API for Repo\Columns +- API for Repo\Projects +- API for User\MyRepositories +- Methods in Repo API for frequency and participation + +### Changed + +- `ApiLimitExceedException::__construct` has a new second parameter for the remaining API calls. +- First parameter of `Github\Client` has changed type from `\Http\Client\HttpClient` to +`Github\HttpClient\Builder`. A factory class was also added. To upgrade you need to change: + +```php +// Old way does not work: +$github = new Github\Client($httpClient); + +// New way will work: +$github = new Github\Client(new Github\HttpClient\Builder($httpClient)); +$github = Github\Client::createWithHttpClient($httpClient); +``` +- Renamed the currentuser `DeployKeys` api class to `PublicKeys` to reflect to github api name. + +## 2.0.0-rc4 + +### Added + +- HTTPlug to decouple from Guzzle +- `Github\Client::getLastResponse` was added +- Support for PSR-6 cache +- `Github\Client::addPlugin` and `Github\Client::removePlugin` +- `Github\Client::getApiVersion` +- `Github\Client::removeCache` + +### Changed + +- Uses of `Github\HttpClient\HttpClientInterface` is replaced by `Http\Client\HttpClient` ie the constructor of `Github\Client`. +- We use PSR-7's representation of HTTP message instead of `Guzzle\Http\Message\Response` and `Guzzle\Http\Message\Request`. +- `Github\Client::addHeaders` was added instead of `Github\Client::setHeaders` +- Signature of `Github\Client::useCache` has changed. First argument must be a `CacheItemPoolInterface` +- We use PSR-4 instead of PSR-0 + +### Removed + +- Support for PHP 5.3 and 5.4 +- `Github/HttpClient/HttpClientInterface` was removed +- `Github/HttpClient/HttpClient` was removed +- All classes in `Github/HttpClient/HttpClient/Listener/*` were removed +- `Github/HttpClient/CachedHttpClient` was removed +- All classes in `Github/HttpClient/Cache/*` were removed + +## 1.7.1 + +No change log before this version diff --git a/LICENSE b/LICENSE old mode 100755 new mode 100644 diff --git a/README.markdown b/README.markdown deleted file mode 100755 index ff29b648a9f..00000000000 --- a/README.markdown +++ /dev/null @@ -1,112 +0,0 @@ -# PHP GitHub API - -[![Build Status](https://secure.travis-ci.org/KnpLabs/php-github-api.png)](http://travis-ci.org/KnpLabs/php-github-api) - -A simple Object Oriented wrapper for GitHub API, written with PHP5. - -Uses [GitHub API v3](http://developer.github.com/v3/). The object API is very similar to the RESTful API. - -## Features - -* Follows PSR-0 conventions and coding standard: autoload friendly -* Light and fast thanks to lazy loading of API classes -* Extensively tested and documented - -## Requirements - -* PHP >= 5.3.2 with [cURL](http://php.net/manual/en/book.curl.php) extension, -* [Guzzle](https://github.com/guzzle/guzzle) library, -* (optional) PHPUnit to run tests. - -## Autoload - -The new version of `php-github-api` using [Composer](http://getcomposer.org). -The first step to use `php-github-api` is to download composer: - -```bash -$ curl -s http://getcomposer.org/installer | php -``` - -Then we have to install our dependencies using: -```bash -$ php composer.phar install -``` -Now we can use autoloader from Composer by: - -```yaml -{ - "require": { - "knplabs/github-api": "*" - }, - "minimum-stability": "dev" -} -``` - -> `php-github-api` follows the PSR-0 convention names for its classes, which means you can easily integrate `php-github-api` classes loading in your own autoloader. - -## Basic usage of `php-github-api` client - -```php -api('user')->repositories('ornicar'); -``` - -From `$client` object, you can access to all GitHub. - -## Cache usage - -```php - '/tmp/github-api-cache')) -); - -// Or select directly which cache you want to use -$client = new \Github\HttpClient\CachedHttpClient(); -$client->setCache( - // Built in one, or any cache implementing this interface: - // Github\HttpClient\Cache\CacheInterface - new \Github\HttpClient\Cache\FilesystemCache('/tmp/github-api-cache') -); - -$client = new \Github\Client($client); -``` - -Using cache, the client will get cached responses if resources haven't changed since last time, -**without** reaching the `X-Rate-Limit` [imposed by github](http://developer.github.com/v3/#rate-limiting). - - -## Documentation - -See the `doc` directory for more detailed documentation. - -## License - -`php-github-api` is licensed under the MIT License - see the LICENSE file for details - -## Credits - -### Sponsored by - -[![KnpLabs Team](http://knplabs.pl/bundles/knpcorporate/images/logo.png)](http://knplabs.com) - -### Contributors - -- Thanks to [Thibault Duplessis aka. ornicar](http://github.com/ornicar) for his first version of this library. -- Thanks to [Joseph Bielawski aka. stloyd](http://github.com/stloyd) for his contributions and support. -- Thanks to [noloh](http://github.com/noloh) for his contribution on the Object API. -- Thanks to [bshaffer](http://github.com/bshaffer) for his contribution on the Repo API. -- Thanks to [Rolf van de Krol](http://github.com/rolfvandekrol) for his countless contributions. -- Thanks to [Nicolas Pastorino](http://github.com/jeanvoye) for his contribution on the Pull Request API. -- Thanks to [Edoardo Rivello](http://github.com/erivello) for his contribution on the Gists API. - -Thanks to GitHub for the high quality API and documentation. diff --git a/README.md b/README.md new file mode 100644 index 00000000000..de79112b4f8 --- /dev/null +++ b/README.md @@ -0,0 +1,134 @@ +# PHP GitHub API + +![Build Status](https://github.com/KnpLabs/php-github-api/actions/workflows/ci.yml/badge.svg) +[![StyleCI](https://styleci.io/repos/3948501/shield?style=flat)](https://styleci.io/repos/3948501) +[![Latest Stable Version](https://poser.pugx.org/knplabs/github-api/v/stable)](https://packagist.org/packages/knplabs/github-api) +[![Total Downloads](https://poser.pugx.org/knplabs/github-api/downloads)](https://packagist.org/packages/knplabs/github-api) +[![Monthly Downloads](https://poser.pugx.org/knplabs/github-api/d/monthly)](https://packagist.org/packages/knplabs/github-api) +[![Daily Downloads](https://poser.pugx.org/knplabs/github-api/d/daily)](https://packagist.org/packages/knplabs/github-api) + +A simple Object Oriented wrapper for GitHub API, written with PHP. + +Uses [GitHub API v3](http://developer.github.com/v3/) & supports [GitHub API v4](http://developer.github.com/v4). The object API (v3) is very similar to the RESTful API. + +## Features + +* Light and fast thanks to lazy loading of API classes +* Extensively tested and documented + +## Requirements + +* PHP >= 7.2 +* A [PSR-17 implementation](https://packagist.org/providers/psr/http-factory-implementation) +* A [PSR-18 implementation](https://packagist.org/providers/psr/http-client-implementation) + +## Quick install + +Via [Composer](https://getcomposer.org). + +This command will get you up and running quickly with a Guzzle HTTP client. + +```bash +composer require knplabs/github-api:^3.0 guzzlehttp/guzzle:^7.0.1 http-interop/http-factory-guzzle:^1.0 +``` + +## Advanced install + +We are decoupled from any HTTP messaging client with help by [HTTPlug](https://httplug.io). + +### Using a different http client + +```bash +composer require knplabs/github-api:^3.0 symfony/http-client nyholm/psr7 +``` + +To set up the Github client with this HTTP client + +```php +use Github\Client; +use Symfony\Component\HttpClient\HttplugClient; + +$client = Client::createWithHttpClient(new HttplugClient()); +``` + +Read more about [using different clients in our docs](doc/customize.md). + +## Framework integrations + +### Laravel + +To integrate this library in laravel [Graham Campbell](https://github.com/GrahamCampbell) created [graham-campbell/github](https://github.com/GrahamCampbell/Laravel-GitHub). See the [installation instructions](https://github.com/GrahamCampbell/Laravel-GitHub#installation) to get started in laravel. + +## Basic usage of `php-github-api` client + +```php +api('user')->repositories('ornicar'); +``` + +From `$client` object, you have access to all available GitHub api endpoints. + +## Cache usage + +This example uses the PSR6 cache pool [redis-adapter](https://github.com/php-cache/redis-adapter). See http://www.php-cache.com/ for alternatives. + +```php +connect('127.0.0.1', 6379); +// Create a PSR6 cache pool +$pool = new RedisCachePool($client); + +$client = new \Github\Client(); +$client->addCache($pool); + +// Do some request + +// Stop using cache +$client->removeCache(); +``` + +Using cache, the client will get cached responses if resources haven't changed since last time, +**without** reaching the `X-Rate-Limit` [imposed by github](http://developer.github.com/v3/#rate-limiting). + + +## Documentation + +See the [`doc` directory](doc/) for more detailed documentation. + +## License + +`php-github-api` is licensed under the MIT License - see the LICENSE file for details + +## Maintainers + +Please read [this post](https://knplabs.com/en/blog/news-for-our-foss-projects-maintenance) first. + +This library is maintained by the following people (alphabetically sorted) : +- [@acrobat](https://github.com/acrobat) +- [@Nyholm](https://github.com/Nyholm) + +## Contributors + +- Thanks to [Thibault Duplessis aka. ornicar](https://github.com/ornicar) for his first version of this library. +- Thanks to [Joseph Bielawski aka. stloyd](https://github.com/stloyd) for his contributions and support. +- Thanks to [noloh](https://github.com/noloh) for his contribution on the Object API. +- Thanks to [bshaffer](https://github.com/bshaffer) for his contribution on the Repo API. +- Thanks to [Rolf van de Krol](https://github.com/rolfvandekrol) for his countless contributions. +- Thanks to [Nicolas Pastorino](https://github.com/jeanvoye) for his contribution on the Pull Request API. +- Thanks to [Edoardo Rivello](https://github.com/erivello) for his contribution on the Gists API. +- Thanks to [Miguel Piedrafita](https://github.com/m1guelpf) for his contribution to the v4 & Apps API. +- Thanks to [Emre DEGER](https://github.com/lexor) for his contribution to the Actions API. + +Thanks to GitHub for the high quality API and documentation. diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md new file mode 100644 index 00000000000..738343d6c37 --- /dev/null +++ b/UPGRADE-3.0.md @@ -0,0 +1,21 @@ +## UPGRADE from 2.x to 3.0 + +### General + +* The `php-http/httplug` dependency requires is bumped to minimum ^2.1. +* A client implementing `psr/http-client-implementation` is required. + To upgrade your application (default install) switch from guzzle 6 to guzzle 7 (or replace `php-http/guzzle6-adapter` with any `psr/http-client-implementation`), see the install instructions in the [README file](README.md) +* All previous deprecated code in version 2 is removed. +* The following classes are now final + * `Github\HttpClient\Message\ResponseMediator` + * `Github\HttpClient\Plugin\Authentication` + * `Github\HttpClient\Plugin\GithubExceptionThrower` + * `Github\HttpClient\Plugin\History` + * `Github\HttpClient\Plugin\PathPrepend` + +### Authentication methods + +* `Github\Client::AUTH_URL_TOKEN` use `Github\Client::AUTH_ACCESS_TOKEN` instead. +* `Github\Client::AUTH_URL_CLIENT_ID` use `Github\Client::AUTH_CLIENT_ID` instead. +* `Github\Client::AUTH_HTTP_TOKEN` use `Github\Client::AUTH_ACCESS_TOKEN` instead. +* `Github\Client::AUTH_HTTP_PASSWORD` use `Github\Client::AUTH_ACCESS_TOKEN` instead. diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md new file mode 100644 index 00000000000..6ede78deb51 --- /dev/null +++ b/UPGRADE-4.0.md @@ -0,0 +1,11 @@ +## UPGRADE from 3.x to 4.0 + +### ResultPager + +* `\Github\ResultPagerInterface::postFetch` is deprecated, and the method will be removed from the ResultPager interface/class. + +### Authentication methods + +* `Github\Client::AUTH_CLIENT_ID` is deprecated, use `Github\AuthMethod::CLIENT_ID` instead. +* `Github\Client::AUTH_ACCESS_TOKEN` is deprecated, use `Github\AuthMethod::ACCESS_TOKEN` instead. +* `Github\Client::AUTH_JWT` is deprecated, use `Github\AuthMethod::JWT` instead. diff --git a/composer.json b/composer.json index 2ef7ee247d3..da450bc019d 100644 --- a/composer.json +++ b/composer.json @@ -17,25 +17,49 @@ } ], "require": { - "php": ">=5.3.2", - "ext-curl": "*", - "guzzle/guzzle": ">=3.7" + "php": "^7.2.5 || ^8.0", + "ext-json": "*", + "php-http/cache-plugin": "^1.7.1|^2.0", + "php-http/client-common": "^2.3", + "php-http/discovery": "^1.12", + "php-http/httplug": "^2.2", + "php-http/multipart-stream-builder": "^1.1.2", + "psr/cache": "^1.0|^2.0|^3.0", + "psr/http-client-implementation": "^1.0", + "psr/http-factory-implementation": "^1.0", + "psr/http-message": "^1.0|^2.0", + "symfony/polyfill-php80": "^1.17", + "symfony/deprecation-contracts": "^2.2|^3.0" }, "require-dev": { - "phpunit/phpunit": ">=3.7" - }, - "require-dev": { - "phpunit/phpunit": ">=3.6.0" - }, - "suggest": { - "knplabs/gaufrette": "Needed for optional Gaufrette cache" + "symfony/cache": "^5.1.8", + "guzzlehttp/psr7": "^2.7", + "http-interop/http-factory-guzzle": "^1.0", + "guzzlehttp/guzzle": "^7.2", + "php-http/mock-client": "^1.4.1", + "phpstan/phpstan": "^0.12.57", + "phpstan/extension-installer": "^1.0.5", + "phpstan/phpstan-deprecation-rules": "^0.12.5", + "phpunit/phpunit": "^8.5 || ^9.4", + "symfony/phpunit-bridge": "^5.2" }, "autoload": { - "psr-0": { "Github\\": "lib/" } + "psr-4": { "Github\\": "lib/Github/" } + }, + "autoload-dev": { + "psr-4": { "Github\\Tests\\": "test/Github/Tests/"} }, "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-2.x": "2.20.x-dev", + "dev-master": "3.16-dev" + } + }, + "config": { + "allow-plugins": { + "phpstan/extension-installer": true, + "composer/package-versions-deprecated": true, + "php-http/discovery": true } } } diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 00000000000..17c3604dc35 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,93 @@ +Navigation +========== + +v4 API: +* [GraphQL](graphql.md) + +v3 APIs: +* [Activity](activity.md) +* [Applications](apps.md) +* [Authorizations](authorizations.md) +* [Commits](commits.md) +* Current User + * [Emails](currentuser/emails.md) + * [Public keys](currentuser/publickeys.md) + * [Memberships](currentuser/memberships.md) +* [Enterprise](enterprise.md) + * [Secret Scanning Alert](enterprise/secret-scanning.md) +* [Gists](gists.md) + * [Comments](gists/comments.md) +* GitData + * [Blobs](gitdata/blobs.md) + * [Commits](gitdata/commits.md) + * [References](gitdata/references.md) + * [Tags](gitdata/tags.md) + * [Trees](gitdata/trees.md) +* [GraphQL](graphql.md) +* [Issues](issues.md) + * [Assignees](issue/assignees.md) + * [Comments](issue/comments.md) + * [Labels](issue/labels.md) + * [Milestones](issue/milestones.md) + * [Timeline](issue/timeline.md) +* [Meta](meta.md) +* Miscellaneous + * [Code of conduct](miscellaneous/codeofconduct.md) + * [Emojis](miscellaneous/emojis.md) + * [Gitignore](miscellaneous/gitignore.md) + * [Licenses](miscellaneous/licenses.md) + * [Markdown](miscellaneous/markdown.md) +* [Organization](organization.md) + * [Members](organization/members.md) + * [Teams](organization/teams.md) + * [Self hosted runners](organization/actions/self_hosted_runners.md) + * [Secrets](organization/actions/secrets.md) + * [Variables](organization/actions/variables.md) + * [Secret Scanning Alert](organization/secret-scanning.md) + * [Organization Roles](organization/organization-roles.md) +* [Projects](project/projects.md) + * [Columns](project/columns.md) + * [Cards](project/cards.md) +* [Pull Requests](pull_requests.md) + * [Comments](pull_request/comments.md) + * [Review Request](pull_request/review_request.md) + * [Reviews](pull_request/reviews.md) +* [Rate Limits](rate_limits.md) +* [Repositories](repos.md) + * Actions + * [Artifacts](repo/actions/artifacts.md) + * [Secrets](repo/actions/secrets.md) + * [Variables](repo/actions/variables.md) + * [Self hosted runners](repo/actions/self_hosted_runners.md) + * [Workflow jobs](repo/actions/workflow_jobs.md) + * [Workflow runs](repo/actions/workflow_runs.md) + * [Workflows](repo/actions/workflows.md) + * [Check Runs](repo/check_runs.md) + * [Check Suites](repo/check_suites.md) + * [Contents](repo/contents.md) + * [Deployments](repo/deployments.md) + * [Policies](repo/deployments/policies.md) + * [Environments](repo/deployments/environments.md) + * [Secrets](repo/deployments/environment/secrets.md) + * [Variables](repo/deployments/environment/variables.md) + * [Labels](repo/labels.md) + * [Protection](repo/protection.md) + * [Releases](repo/releases.md) + * [Assets](repo/assets.md) + * [Stargazers](repo/stargazers.md) + * [Statuses](repo/statuses.md) + * [Tags](repo/tags.md) + * [Secret Scanning Alert](repo/secret-scanning.md) +* [Search](search.md) +* [Users](users.md) + * [Migrations](user/migration.md) + +Additional features: + +* [Authentication & Security](security.md) +* [Customize `php-github-api`](customize.md) +* [Running and writing tests](testing.md) +* [Response caching](caching.md) +* [Request / Response info](request_response_info.md) +* [Pagination support](result_pager.md) +* [Request any Route](request_any_route.md) diff --git a/doc/activity.md b/doc/activity.md new file mode 100644 index 00000000000..48d7cfb423d --- /dev/null +++ b/doc/activity.md @@ -0,0 +1,110 @@ +## Activity API (incomplete) +[Back to the navigation](README.md) + +Access to Starring and Watching a Repository for [non] authenticated users. +Wrap [GitHub Activity API](https://developer.github.com/v3/activity/). + +> *** No authentication required. *** + +### Get repos that a specific user has starred + +```php +$users = $client->api('user')->starred('ornicar'); +``` + +Returns an array of starred repos. + +### Get repos that a specific user is watching + +```php +$users = $client->api('user')->watched('ornicar'); +``` + +Returns an array of watched repos. + +> *** Requires [authentication](security.md). *** + +### Get repos that an authenticated user has starred + +```php +$activity = $client->api('current_user')->starring()->all(); +``` +Returns an array of starred repos. + +### Get list of private and public events for an authenticated user for all repos + +```php +$activity = $client->api('user')->events('ornicar'); +``` +Returns an array of private and public events created for all repos related to the user. + +### Get repos that an authenticated user has starred with creation date + +Support for getting the star creation timestamp in the response, using the custom `Accept: application/vnd.github.v3.star+json` header. + +```php +$activity = $client->api('current_user')->starring()->configure('star')->all(); +``` +Returns an array of starred repos, including the `created_at` attribute for every star. + +### Check if authenticated user has starred a specific repo + +```php +$owner = "KnpLabs"; +$repo = "php-github-api"; +$activity = $client->api('current_user')->starring()->check($owner, $repo); +``` +Throws an Exception with code 404 in case that the repo is not starred by the authenticated user or NULL in case that it is starred by the authenticated user. + +### Star a specific repo for authenticated user + +```php +$owner = "KnpLabs"; +$repo = "php-github-api"; +$activity = $client->api('current_user')->starring()->star($owner, $repo); +``` +Throws an Exception in case of failure or NULL in case of success. + +### Unstar a specific repo for authenticated user + +```php +$owner = "KnpLabs"; +$repo = "php-github-api"; +$activity = $client->api('current_user')->starring()->unstar($owner, $repo); +``` +Throws an Exception in case of failure or NULL in case of success. + + +### Get repos that an authenticated user is watching + +```php +$activity = $client->api('current_user')->watchers()->all(); +``` +Returns an array of watched repos. + +### Check if authenticated user is watching a specific repo + +```php +$owner = "KnpLabs"; +$repo = "php-github-api"; +$activity = $client->api('current_user')->watchers()->check($owner, $repo); +``` +Throws an Exception with code 404 in case that the repo is not being watched by the authenticated user or NULL in case that it is being watched by the authenticated user. + +### Watch a specific repo for authenticated user + +```php +$owner = "KnpLabs"; +$repo = "php-github-api"; +$activity = $client->api('current_user')->watchers()->watch($owner, $repo); +``` +Throws an Exception in case of failure or NULL in case of success. + +### Stop watching a specific repo for authenticated user + +```php +$owner = "KnpLabs"; +$repo = "php-github-api"; +$activity = $client->api('current_user')->watchers()->unwatch($owner, $repo); +``` +Throws an Exception in case of failure or NULL in case of success. diff --git a/doc/api_version.md b/doc/api_version.md new file mode 100644 index 00000000000..c8cbfdde2ae --- /dev/null +++ b/doc/api_version.md @@ -0,0 +1,13 @@ +## Api version +[Back to the navigation](README.md) + +If you want to change the API version from its default ("v3") you may do that with a constructor argument. +For example: + +```php +$client = new Github\Client(); +echo $client->getApiVersion(); // prints "v3" + +$client = new Github\Client(new Github\HttpClient\Builder($httpClient), 'v2'); +echo $client->getApiVersion(); // prints "v2" +``` diff --git a/doc/apps.md b/doc/apps.md new file mode 100644 index 00000000000..14de9e4434d --- /dev/null +++ b/doc/apps.md @@ -0,0 +1,57 @@ +## Applications API +[Back to the navigation](README.md) + +Wraps [GitHub Applications API](http://developer.github.com/v3/apps/). + +### Create a new installation token +For the installation id 123 use the following: +```php +$token = $client->api('apps')->createInstallationToken(123); +``` + +To create an access token on behalf of a user with id 456 use: +```php +$token = $client->api('apps')->createInstallationToken(123, 456); +``` + +### Find all installations + +Find all installations for the authenticated application. +```php +$installations = $client->api('apps')->findInstallations(); +``` + +### Find installations for a user + +```php +$installations = $client->api('current_user')->installations(); +``` + +### List repositories + +List repositories that are accessible to the authenticated installation. +```php +$repositories = $client->api('apps')->listRepositories($userId); +``` + +### List repositories for a given installation and user + +```php +$repositories = $client->api('current_user')->repositoriesByInstallation($installationId, $parameters); +``` + +### Add repository to installation +```php +$client->api('apps')->addRepository($installationId, $repositoryId); +``` + +### Remove repository from installation +```php +$client->api('apps')->removeRepository($installationId, $repositoryId); +``` + +### Get authenticated app + +```php +$authenticatedApp = $client->api('apps')->getAuthenticatedApp(); +``` diff --git a/doc/authorizations.md b/doc/authorizations.md index 5386c6acab5..b037e402c27 100644 --- a/doc/authorizations.md +++ b/doc/authorizations.md @@ -1,7 +1,7 @@ ## Authorizations API -[Back to the navigation](index.md) +[Back to the navigation](README.md) -Creating, deleting and listing authorizations. Wraps [GitHub Authorizations API](http://developer.github.com/v3/oauth/). +Creating, deleting and listing authorizations. Wraps [GitHub Authorizations API](http://developer.github.com/v3/oauth_authorizations/). #### List all authorizations. @@ -15,18 +15,6 @@ $authorizations = $github->api('authorizations')->all(); $authorization = $github->api('authorizations')->show(1); ``` -#### Create an authorization - -```php -$data = array( - 'note' => 'This is an optional description' -); - -$authorization = $github->api('authorizations')->create($data); -``` - -Creates and returns an authorization. - #### Update an authorization You can update ``note``. @@ -50,3 +38,21 @@ $authorization = $github->api('authorizations')->remove(1234); ```php $authorization = $github->api('authorizations')->check(1234, 'token'); ``` + +#### Reset an authorization + +```php +$authorization = $github->api('authorizations')->reset(1234, 'token'); +``` + +#### Revoke an authorization + +```php +$github->api('authorizations')->revoke(1234, 'token'); +``` + +#### Revoke all authorizations + +```php +$github->api('authorizations')->revokeAll(1234); +``` diff --git a/doc/caching.md b/doc/caching.md new file mode 100644 index 00000000000..1a004cc8781 --- /dev/null +++ b/doc/caching.md @@ -0,0 +1,30 @@ +## Response caching +[Back to the navigation](README.md) + +This example uses the PSR6 cache pool [redis-adapter](https://github.com/php-cache/redis-adapter). See http://www.php-cache.com/ for alternatives. + +```php +connect('127.0.0.1', 6379); +// Create a PSR6 cache pool +$pool = new RedisCachePool($client); + +$client = new \Github\Client(); +$client->addCache($pool); + +// Do some request + +// Stop using cache +$client->removeCache(); +``` + +Using cache, the client will get cached responses if resources haven't changed since last time, +**without** reaching the `X-Rate-Limit` [imposed by GitHub](http://developer.github.com/v3/#rate-limiting). + diff --git a/doc/commits.md b/doc/commits.md index c48ce3126f8..165d71ecae2 100644 --- a/doc/commits.md +++ b/doc/commits.md @@ -1,5 +1,5 @@ ## Commits API -[Back to the navigation](index.md) +[Back to the navigation](README.md) Getting information on specific commits, the diffs they introduce, the files they've changed. Wrap [GitHub Commit API](http://developer.github.com/v3/git/commits/). @@ -35,3 +35,11 @@ $commit = $client->api('repo')->commits()->compare('KnpLabs', 'php-github-api', ``` Returns an array of commits. + +### List pull requests associated with a commit + +```php +$commit = $client->api('repo')->commits()->pulls('KnpLabs', 'php-github-api', '839e5185da9434753db47959bee16642bb4f2ce4'); +``` + +Returns an array of pull requests. \ No newline at end of file diff --git a/doc/copilot/usage.md b/doc/copilot/usage.md new file mode 100644 index 00000000000..6005adc1600 --- /dev/null +++ b/doc/copilot/usage.md @@ -0,0 +1,80 @@ +# Copilot Usage API Documentation +[Back to the navigation](../README.md) + +## Overview + +The Copilot Usage API provides endpoints to retrieve usage summaries for organizations and enterprises. + +**Note**: This endpoint is in beta and is subject to change. + +## Endpoints + +### Organization Usage Summary + +Retrieve the usage summary for a specific organization. + +**Method:** `GET` + +**Endpoint:** `/orgs/{organization}/copilot/usage` + +**Parameters:** +- `organization` (string): The name of the organization. +- `params` (array, optional): Additional query parameters. + +**Example:** +```php +$usage = $client->api('copilotUsage')->orgUsageSummary('KnpLabs'); +``` + +### Organization Team Usage Summary + +Retrieve the usage summary for a specific team within an organization. + +**Method:** `GET` + +**Endpoint:** `/orgs/{organization}/team/{team}/copilot/usage` + +**Parameters:** +- `organization` (string): The name of the organization. +- `team` (string): The name of the team. +- `params` (array, optional): Additional query parameters. + +**Example:** +```php +$usage = $client->api('copilotUsage')->orgTeamUsageSummary('KnpLabs', 'developers'); +``` + +### Enterprise Usage Summary + +Retrieve the usage summary for a specific enterprise. + +**Method:** `GET` + +**Endpoint:** `/enterprises/{enterprise}/copilot/usage` + +**Parameters:** +- `enterprise` (string): The name of the enterprise. +- `params` (array, optional): Additional query parameters. + +**Example:** +```php +$usage = $client->api('copilotUsage')->enterpriseUsageSummary('KnpLabs'); +``` + +### Enterprise Team Usage Summary + +Retrieve the usage summary for a specific team within an enterprise. + +**Method:** `GET` + +**Endpoint:** `/enterprises/{enterprise}/team/{team}/copilot/usage` + +**Parameters:** +- `enterprise` (string): The name of the enterprise. +- `team` (string): The name of the team. +- `params` (array, optional): Additional query parameters. + +**Example:** +```php +$usage = $client->api('copilotUsage')->enterpriseTeamUsageSummary('KnpLabs', 'developers'); +``` diff --git a/doc/currentuser/emails.md b/doc/currentuser/emails.md new file mode 100644 index 00000000000..ef099f468d5 --- /dev/null +++ b/doc/currentuser/emails.md @@ -0,0 +1,35 @@ +## Current user / Emails API +[Back to the navigation](../README.md) + +Wraps [GitHub User Emails API](https://developer.github.com/v3/users/emails/#emails). + +> Requires [authentication](../security.md). + +### List email addresses for a user + +```php +$emails = $client->currentUser()->emails()->all(); +``` + +### List public email addresses for a user + +```php +$emails = $client->currentUser()->emails()->allPublic(); +``` + +### Add email address(es) + +```php +$emails = $client->currentUser()->emails()->add(['email1', 'email2']); +``` +### Delete email address(es) + +```php +$client->currentUser()->emails()->remove(['email1', 'email2']); +``` + +### Toggle primary email visibility + +```php +$primaryEmail = $client->currentUser()->emails()->toggleVisibility(); +``` diff --git a/doc/currentuser/memberships.md b/doc/currentuser/memberships.md new file mode 100644 index 00000000000..53ee81eb96e --- /dev/null +++ b/doc/currentuser/memberships.md @@ -0,0 +1,36 @@ +## Current user / Memberships API +[Back to the navigation](../README.md) + +Wraps [GitHub Issue Comments API](https://developer.github.com/v3/orgs/members/#get-your-organization-membership). + +### List your memberships + +> Requires [authentication](../security.md). + +```php +$memberships = $client->currentUser()->memberships()->all(); +``` + +Returns an array of your memberships in all organizations you are part of. + +### Show an organization membership + +> Requires [authentication](../security.md). + +```php +$membership = $client->currentUser()->memberships()->organization('KnpLabs'); +``` +* `KnpLabs` : the organization + +Returns an array of one membership in a specific organization. + +### Update an organization membership + +> Requires [authentication](../security.md). + +```php +$membership = $client->currentUser()->memberships()->edit('KnpLabs'); +``` +* `KnpLabs` : the organization + +Update your membership to an organization. The only possible action is to activate your membership. diff --git a/doc/currentuser/publickeys.md b/doc/currentuser/publickeys.md new file mode 100644 index 00000000000..444dd58fa0c --- /dev/null +++ b/doc/currentuser/publickeys.md @@ -0,0 +1,36 @@ +## Current user / Public Keys API +[Back to the navigation](../README.md) + +Wraps [GitHub User Public Keys API](https://developer.github.com/v3/users/keys/#public-keys). + +### List your public keys + +```php +$keys = $client->me()->keys()->all(); +``` + +Returns a list of public keys for the authenticated user. + +### Shows a public key for the authenticated user. + +```php +$key = $client->me()->keys()->show(1234); +``` + +### Add a public key to the authenticated user. + +> Requires [authentication](../security.md). + +```php +$key = $client->me()->keys()->create(array('title' => 'key title', 'key' => 12345)); +``` + +Adds a key with title 'key title' to the authenticated user and returns the created key for the user. + +### Remove a public key from the authenticated user. + +> Requires [authentication](../security.md). + +```php +$client->me()->keys()->remove(12345); +``` diff --git a/doc/currentuser/repositories.md b/doc/currentuser/repositories.md new file mode 100644 index 00000000000..9b5e1d85e94 --- /dev/null +++ b/doc/currentuser/repositories.md @@ -0,0 +1,30 @@ +## Current user / Repo API +[Back to the navigation](../README.md) + +> Requires [authentication](../security.md). + +### List repositories that are accessible to the authenticated user. + +```php +$repositories = $client->currentUser()->repositories(); +``` + +This includes repositories owned by the authenticated user, repositories where the authenticated user is a collaborator, and repositories that the authenticated user has access to through an organization membership. + +There are three values that can be passed into the `repositories` method: `type`, `sort` and `direction` + +| Parameters | Default | Possible Values | +| ------------- |-------------| -------------------------------------------- | +| type | `owner` | `all`, `owner`, `public`, `private`, `member` +| sort | `full_name` | `created`, `updated`, `pushed`, `full_name` +| direction | `asc` | `asc`, `desc` + +> See https://developer.github.com/v3/repos/#list-your-repositories for possible values and additional information + +#### Code Example: + +```php +$client = new \Github\Client(); +$client->authenticate($github_token, null, \Github\AuthMethod::ACCESS_TOKEN); +$client->currentUser()->repositories(); +``` diff --git a/doc/customize.md b/doc/customize.md index 0b58ee69bd5..b475ee57322 100644 --- a/doc/customize.md +++ b/doc/customize.md @@ -1,47 +1,60 @@ -## Customize `php-github-api` and testing -[Back to the navigation](index.md) +## Customize `php-github-api` +[Back to the navigation](README.md) -### Configure the http client -Wanna change, let's say, the http client User Agent? +### Inject a new HTTP client instance + +`php-github-api` relies on `php-http/discovery` to find an installed HTTP client. You may specify an HTTP client +yourself by calling `\Github\Client::setHttpClient`. An HTTP client must implement `Http\Client\HttpClient`. A list of +community provided clients is found here: https://packagist.org/providers/php-http/client-implementation + +You can inject an HTTP client through the `Github\Client` constructor: ```php -$client->getHttpClient()->setOption('user_agent', 'My new User Agent'); +$client = Github\Client::createWithHttpClient(new Http\Adapter\Guzzle6\Client()); ``` -See all available options in `Github/HttpClient/HttpClient.php` +#### Example -### Inject a new http client instance +To use the symfony http client + +```bash +composer require symfony/http-client nyholm/psr7 +``` -`php-github-api` provides a curl-based implementation of a http client. -If you want to use your own http client implementation, inject it to the `Github\Client` instance: +To set up the GitHub client with this http client ```php -use Github\HttpClient\HttpClient; +use Github\Client; +use Symfony\Component\HttpClient\HttplugClient; -// create a custom http client -class MyHttpClient extends HttpClient -{ - public function request($url, array $parameters = array(), $httpMethod = 'GET', array $headers = array()) - { - // send the request and return the raw response - } -} +$client = Client::createWithHttpClient(new HttplugClient()); ``` -> Your http client implementation may not extend `Github\HttpClient\HttpClient`, but only implement `Github\HttpClient\HttpClientInterface`. +### Configure the HTTP client -You can now inject your http client through `Github\Client#setHttpClient()` method: +Wanna change, let's say, the HTTP client User Agent? You need to create a Plugin that modifies the +request. Read more about [HTTPlug plugins here](http://docs.php-http.org/en/latest/plugins/introduction.html#how-it-works). ```php -$client = new Github\Client(); -$client->setHttpClient(new MyHttpClient()); -``` +use Http\Client\Common\Plugin; +use Psr\Http\Message\RequestInterface; + +class CustomUserAgentPlugin implements Plugin +{ + /** + * {@inheritdoc} + */ + public function handleRequest(RequestInterface $request, callable $next, callable $first) + { + $request->withHeader('user-agent', 'Foobar'); -### Run Test Suite + return $next($request); + } +} -The code is unit tested, there are also some functional tests. To run tests on your machine, from a CLI, run +$httpBuilder = new Github\HttpClient\Builder(new Http\Adapter\Guzzle6\Client()); +$httpBuilder->addPlugin(new CustomUserAgentPlugin()); -```bash -$ phpunit +$client = new Github\Client($httpBuilder); ``` diff --git a/doc/enterprise.md b/doc/enterprise.md new file mode 100644 index 00000000000..5245fe7c3d8 --- /dev/null +++ b/doc/enterprise.md @@ -0,0 +1,41 @@ +## Enterprise API +[Back to the navigation](README.md) + +Provides information about a GitHub Enterprise installation. Wraps [GitHub Enterprise API](http://developer.github.com/v3/enterprise/). + +### Configuration +In order to configure the client to point to a GitHub Enterprise installation, do the following: + +```php +api('user')->repositories('ornicar'); +``` + +### Authentication +The Admin Stats, License, and User Administration API endpoints are only accessible to GitHub Enterprise site administrators. The Management Console API endpoints are only accessible via the Management Console password. + +### User Administration + +#### Suspend a user (Enterprise only) + +> Requires [authentication](security.md). + +```php +$client->api('enterprise')->userAdmin()->suspend('ornicar'); +``` + +#### Unsuspend a user (Enterprise only) + +> Requires [authentication](security.md). + +```php +$client->api('enterprise')->userAdmin()->unsuspend('ornicar'); +``` diff --git a/doc/enterprise/secret-scanning.md b/doc/enterprise/secret-scanning.md new file mode 100644 index 00000000000..ad7626c4709 --- /dev/null +++ b/doc/enterprise/secret-scanning.md @@ -0,0 +1,10 @@ +## Enterprise / Secret Scanning API +[Back to the "Enterprise API"](../../enterprise.md) | [Back to the navigation](../../README.md) + +# List secret-scanning alerts for an Enterprise + +https://docs.github.com/en/enterprise-server@3.5/rest/secret-scanning#list-secret-scanning-alerts-for-an-enterprise + +```php +$alerts = $client->api('enterprise')->secretScanning()->alerts('KnpLabs'); +``` diff --git a/doc/gists.md b/doc/gists.md index 696fda9d1a6..7db9f2c6cd5 100644 --- a/doc/gists.md +++ b/doc/gists.md @@ -1,7 +1,11 @@ ## Gists API -[Back to the navigation](index.md) +[Back to the navigation](README.md) -Creating, editing, deleting and listing gists. Wraps [GitHub Gists API](http://developer.github.com/v3/gists/). +Creating, editing, deleting and listing gists. +Wraps [GitHub Gists API](http://developer.github.com/v3/gists/). + +Additional APIs: +* [Comments](gists/comments.md) #### List all public gists. @@ -33,6 +37,18 @@ $gists = $github->api('gists')->all(); $gist = $github->api('gists')->show(1); ``` +#### Get a specific revision of a gist + +```php +$gist = $github->api('gists')->show(1, 'd189dbd4c5d96442db74ebcb62bb38e661a0c8ce'); +``` + +#### Get commits for a single gist + +```php +$commits = $github->api('gists')->commits(1); +``` + #### Create a gist ```php @@ -60,7 +76,7 @@ $data = array( 'description' => 'This is new description' ); -$gist = $github->api('gists')->update($data); +$gist = $github->api('gists')->update(1234, $data); ``` You can update ``content`` of a previous file's version. diff --git a/doc/gists/comments.md b/doc/gists/comments.md new file mode 100644 index 00000000000..2df9966537a --- /dev/null +++ b/doc/gists/comments.md @@ -0,0 +1,51 @@ +## Gists / Comments API + +[Back to the "Gists API"](../gists.md) | [Back to the navigation](../README.md) + +Wraps [GitHub Issue Comments API](http://developer.github.com/v3/gists/comments/). + +### List a gist comments + +```php +// for gist https://gist.github.com/danvbe/4476697 +$comments = $client->api('gist')->comments()->all('4476697'); +``` + +* `4476697` : the id of the gist + +### Show a gist comment + +```php +$comment = $client->api('gist')->comments()->show('4476697', '779656'); +``` + +* `4476697` : the id of the gist +* `779656` : the id of the comment + +### Create a gist comment + +```php +$client->api('gist')->comments()->create('4476697', 'Hello World'); +``` + +* `4476697` : the id of the gist +* `Hello World` : the body of the comment + +### Update a gist comment + +```php +$client->api('gist')->comments()->create('4476697', '123456', 'Hello Dolly'); +``` + +* `4476697` : the id of the gist +* `123456` : the id of the comment +* `Hello Dolly` : the body of the updated comment + +### Remove a gist comment + +```php +$client->api('gist')->comments()->remove('4476697', '123456'); +``` + +* `4476697` : the id of the gist +* `123456` : the id of the comment diff --git a/doc/gitdata/blobs.md b/doc/gitdata/blobs.md new file mode 100644 index 00000000000..78a79ac0810 --- /dev/null +++ b/doc/gitdata/blobs.md @@ -0,0 +1,14 @@ +## Blobs API +[Back to the navigation](../README.md) + +### Show a blob + +```php +$blob = $client->api('gitData')->blobs()->show('KnpLabs', 'php-github-api', '839e5185da9434753db47959bee16642bb4f2ce4'); +``` + +### Create a blob + +```php +$blob = $client->api('gitData')->blobs()->create('KnpLabs', 'php-github-api', ['content' => 'Test content', 'encoding' => 'utf-8']); +``` \ No newline at end of file diff --git a/doc/gitdata/commits.md b/doc/gitdata/commits.md new file mode 100644 index 00000000000..07584e49929 --- /dev/null +++ b/doc/gitdata/commits.md @@ -0,0 +1,15 @@ +## Commits API +[Back to the navigation](../README.md) + +### Show a commit + +```php +$commit = $client->api('gitData')->commits()->show('KnpLabs', 'php-github-api', '839e5185da9434753db47959bee16642bb4f2ce4'); +``` + +### Create a commit + +```php +$commitData = ['message' => 'Upgrading documentation', 'tree' => $treeSHA, 'parents' => [$parentCommitSHA]]; +$commit = $client->api('gitData')->commits()->create('KnpLabs', 'php-github-api', $commitData); +``` \ No newline at end of file diff --git a/doc/gitdata/references.md b/doc/gitdata/references.md new file mode 100644 index 00000000000..8cc2b971e7e --- /dev/null +++ b/doc/gitdata/references.md @@ -0,0 +1,49 @@ +## References API +[Back to the navigation](../README.md) + + +### List all references +```php +$references = $client->api('gitData')->references()->all('KnpLabs', 'php-github-api'); +``` + +### List Matching references +```php +$references = $client->api('gitData')->references()->matching('KnpLabs', 'php-github-api', 'heads/branchName'); // use 'tags/tagName' for third argument if ref is tag +``` + +### Show a reference + +```php +$reference = $client->api('gitData')->references()->show('KnpLabs', 'php-github-api', 'heads/featureA'); +``` + +### Create a reference + +```php +$referenceData = ['ref' => 'refs/heads/featureA', 'sha' => '839e5185da9434753db47959bee16642bb4f2ce4']; +$reference = $client->api('gitData')->references()->create('KnpLabs', 'php-github-api', $referenceData); +``` + +### Update a reference + +```php +$referenceData = ['sha' => '839e5185da9434753db47959bee16642bb4f2ce4', 'force' => false ]; //Force is default false +$reference = $client->api('gitData')->references()->update('KnpLabs', 'php-github-api', 'heads/featureA', $referenceData); +``` + +### Delete a reference + +```php +$client->api('gitData')->references()->remove('KnpLabs', 'php-github-api', 'heads/featureA'); +``` + +### List all branches +```php +$references = $client->api('gitData')->references()->branches('KnpLabs', 'php-github-api'); +``` + +### List all tags +```php +$references = $client->api('gitData')->references()->tags('KnpLabs', 'php-github-api'); +``` diff --git a/doc/gitdata/tags.md b/doc/gitdata/tags.md new file mode 100644 index 00000000000..36b323e5c74 --- /dev/null +++ b/doc/gitdata/tags.md @@ -0,0 +1,32 @@ +## Tags API +[Back to the navigation](../README.md) + +### Show all tags + +```php +$tags = $client->api('gitData')->tags()->all('KnpLabs', 'php-github-api'); +``` + +### Show a tag + +```php +$tag = $client->api('gitData')->tags()->show('KnpLabs', 'php-github-api', '839e5185da9434753db47959bee16642bb4f2ce4'); +``` + +### Create a tag + +```php +$tagData = [ + 'tag' => 'v0.0.1', + 'message' => 'initial version', + 'object' => 'c3d0be41ecbe669545ee3e94d31ed9a4bc91ee3c', + 'type' => 'commit', + 'tagger' => [ + 'name' => 'KnpLabs', + 'email' => 'hello@knplabs.com', + 'date' => '2017-06-17T14:53:35-07:00' + ] +]; + +$tag = $client->api('gitData')->tags()->create('KnpLabs', 'php-github-api', $tagData); +``` \ No newline at end of file diff --git a/doc/gitdata/trees.md b/doc/gitdata/trees.md new file mode 100644 index 00000000000..dcdd0b49c08 --- /dev/null +++ b/doc/gitdata/trees.md @@ -0,0 +1,25 @@ +## Trees API +[Back to the navigation](../README.md) + +### Show a tree + +```php +$tree = $client->api('gitData')->trees()->show('KnpLabs', 'php-github-api', '839e5185da9434753db47959bee16642bb4f2ce4'); +``` + +### Create a tree + +```php +$treeData = [ + 'base_tree' => '839e5185da9434753db47959bee16642bb4f2ce4', + 'tree' => [ + [ + 'path' => 'README.md', + 'mode' => '100644', + 'type' => 'blob', + 'content' => 'Updated Readme file' + ] + ] +]; +$tree = $client->api('gitData')->trees()->create('KnpLabs', 'php-github-api', $treeData); +``` \ No newline at end of file diff --git a/doc/graphql.md b/doc/graphql.md new file mode 100644 index 00000000000..dfe83639085 --- /dev/null +++ b/doc/graphql.md @@ -0,0 +1,57 @@ +## GraphQL API +[Back to the navigation](README.md) + +Wraps [GitHub v4 API (GraphQL API)](http://developer.github.com/v4/). + +#### Execute a query + +```php +$rateLimits = $client->api('graphql')->execute($query); +``` + +#### Authentication + +To use [GitHub v4 API (GraphQL API)](http://developer.github.com/v4/) requests must [authenticate](security.md). + +```php +$client->authenticate($token, null, Github\AuthMethod::ACCESS_TOKEN); + +$result = $client->api('graphql')->execute($query); +``` + +#### Use different `Accept` Headers +You can preview upcoming features and changes to the GitHub GraphQL schema before they are added to the GitHub GraphQL API. +To access a schema preview, you'll need to provide a custom media type in the Accept header for your requests. Feature documentation for each preview specifies which custom media type to provide. More info about [Schema Previews](https://docs.github.com/en/graphql/overview/schema-previews). + +To use [GitHub v4 API (GraphQL API)](http://developer.github.com/v4/) with different `Accept` header you can pass third argument to execute method. + +```php +$result = $client->api('graphql')->execute($query, [], 'application/vnd.github.starfox-preview+json') +``` +> default accept header is `application/vnd.github.v4+json` + + + +#### Use variables + +[Variables](https://developer.github.com/v4/guides/forming-calls/#working-with-variables) allow specifying of requested data without dynamical change of a query on a client side. + +```php +$query = <<<'QUERY' +query showOrganizationInfo ( + $organizationLogin: String! +) { + organization(login: $organizationLogin) { + name + url + } +} +QUERY; +$variables = [ + 'organizationLogin' => 'KnpLabs' +]; + +$client->authenticate('', null, Github\AuthMethod::ACCESS_TOKEN); + +$orgInfo = $client->api('graphql')->execute($query, $variables); +``` diff --git a/doc/index.md b/doc/index.md deleted file mode 100644 index 1f447d6e457..00000000000 --- a/doc/index.md +++ /dev/null @@ -1,26 +0,0 @@ -Navigation -========== - -APIs: -* [Authorizations](authorizations.md) -* [Commits](commits.md) -* [Gists](gists.md) -* [Issues](issues.md) - * [Comments](issue/comments.md) - * [Labels](issue/labels.md) -* [Organization](organization.md) - * [Members](organization/members.md) - * [Teams](organization/teams.md) -* [Pull Requests](pull_requests.md) - * [Comments](pull_request/comments.md) -* [Repositories](repos.md) - * [Releases](repo/releases.md) - * [Assets](repo/assets.md) -* [Users](users.md) - -Additional features: - -* [Pagination support](result_pager.md) -* [Authentication & Security](security.md) -* [Request any Route](request_any_route.md) -* [Customize `php-github-api` and testing](customize.md) diff --git a/doc/issue/assignees.md b/doc/issue/assignees.md new file mode 100644 index 00000000000..58071d74f97 --- /dev/null +++ b/doc/issue/assignees.md @@ -0,0 +1,28 @@ +## Issues / Assignees API +[Back to the "Issues API"](../issues.md) | [Back to the navigation](../README.md) + +Wraps [GitHub Issue Assignees API](https://developer.github.com/v3/issues/assignees/). + +### List all available assignees + +```php +$assignees = $client->api('issue')->assignees()->listAvailable('KnpLabs', 'php-github-api'); +``` + +### Check if a user is an available assignee + +```php +$info = $client->api('issue')->assignees()->check('KnpLabs', 'php-github-api', 'test-user'); +``` + +### Add assignee + +```php +$client->api('issue')->assignees()->add('KnpLabs', 'php-github-api', 4, ['assignees' => ['test-user']]); +``` + +### Remove assignee + +```php +$client->api('issue')->assignees()->remove('KnpLabs', 'php-github-api', 4, ['assignees' => ['test-user']]); +``` diff --git a/doc/issue/comments.md b/doc/issue/comments.md index f976047b885..ac0f8a619ea 100644 --- a/doc/issue/comments.md +++ b/doc/issue/comments.md @@ -1,5 +1,5 @@ ## Issues / Comments API -[Back to the "Issues API"](../issues.md) | [Back to the navigation](../index.md) +[Back to the "Issues API"](../issues.md) | [Back to the navigation](../README.md) Wraps [GitHub Issue Comments API](http://developer.github.com/v3/issues/comments/). @@ -9,8 +9,24 @@ Wraps [GitHub Issue Comments API](http://developer.github.com/v3/issues/comments $comments = $client->api('issue')->comments()->all('KnpLabs', 'php-github-api', 4); ``` -List an issue comments by username, repo and issue number. -Returns an array of issues. +* `KnpLabs` : the owner of the repository +* `php-github-api` : the name of the repository +* `4` : the issue number +* You can select another page of comments using one more parameter (default: 1) + +Returns an array of comments. + + +### Show an issue comment + +```php +$comment = $client->api('issue')->comments()->show('KnpLabs', 'php-github-api', 33793831); +``` + +* `KnpLabs` : the owner of the repository +* `php-github-api` : the name of the repository +* `33793831` : the id of the comment + ### Add a comment on an issue @@ -23,5 +39,36 @@ Returns an array of issues. $client->api('issue')->comments()->create('KnpLabs', 'php-github-api', 4, array('body' => 'My new comment')); ``` -Add a comment to the issue by username, repo and issue number and array with comment data: `body` -and optionally `title`. +* `KnpLabs` : the owner of the repository +* `php-github-api` : the name of the repository +* `4` : the issue number +* You can set a `body` and optionally a `title` + + +### Update a comment on an issue + +> **Note:** + +> Requires [authentication](../security.md). + +```php +$client->api('issue')->comments()->update('KnpLabs', 'php-github-api', 33793831, array('body' => 'My updated comment')); +``` + +* `KnpLabs` : the owner of the repository +* `php-github-api` : the name of the repository +* `33793831` : the id of the comment + +### Remove a comment on an issue + +> **Note:** + +> Requires [authentication](../security.md). + +```php +$client->api('issue')->comments()->remove('KnpLabs', 'php-github-api', 33793831); +``` + +* `KnpLabs` : the owner of the repository +* `php-github-api` : the name of the repository +* `33793831` : the id of the comment diff --git a/doc/issue/labels.md b/doc/issue/labels.md index 797d9a50427..4a9964f4402 100644 --- a/doc/issue/labels.md +++ b/doc/issue/labels.md @@ -1,5 +1,5 @@ ## Issues / Labels API -[Back to the "Issues API"](../issues.md) | [Back to the navigation](../index.md) +[Back to the "Issues API"](../issues.md) | [Back to the navigation](../README.md) Wraps [GitHub Issue Labels API](http://developer.github.com/v3/issues/labels/). @@ -12,6 +12,39 @@ $labels = $client->api('issue')->labels()->all('KnpLabs', 'php-github-api'); List all project labels by username and repo. Returns an array of project labels. +### Get a single label + +```php +$label = $client->api('issue')->labels()->show('KnpLabs', 'php-github-api', 'label1'); +``` + +### Create a label + +```php +$labels = $client->api('issue')->labels()->create('KnpLabs', 'php-github-api', array( + 'name' => 'Bug', + 'color' => 'FFFFFF', +)); +``` + +Create a new label in the repository. + +### Update a label + +```php +$labels = $client->api('issue')->labels()->update('KnpLabs', 'php-github-api', 'Enhancement', 'Feature', 'FFFFFF'); +``` + +Update the label name and color. + +### Delete a label + +```php +$labels = $client->api('issue')->labels()->deleteLabel('KnpLabs', 'php-github-api', 'Bug'); +``` + +Delete a new label from the repository. + ### Add a label on an issue > Requires [authentication](../security.md). @@ -24,6 +57,12 @@ Add a label to the issue by username, repo, issue number label name and. If the the system, it will be created. Returns an array of the issue labels. +### Get all labels for an issue + +```php +$label = $client->api('issue')->labels()->all('KnpLabs', 'php-github-api', 4); +``` + ### Replace all labels for an issue > Requires [authentication](../security.md). @@ -34,7 +73,7 @@ $client->api('issue')->labels()->replace('KnpLabs', 'php-github-api', 4, array(' Replace a label for an issue: by username, repo, issue number and array of labels. -### Remove all labels fom an issue +### Remove all labels from an issue > Requires [authentication](../security.md). diff --git a/doc/issue/milestones.md b/doc/issue/milestones.md new file mode 100644 index 00000000000..e376d221fa6 --- /dev/null +++ b/doc/issue/milestones.md @@ -0,0 +1,40 @@ +## Issues / Milestones API +[Back to the "Issues API"](../issues.md) | [Back to the navigation](../README.md) + +Wraps [GitHub Issue Milestones API](http://developer.github.com/v3/issues/milestones/). + +### List milestones for a repository + +```php +$milestones = $client->api('issue')->milestones()->all('KnpLabs', 'php-github-api'); +``` + +### Get information about milestone + +```php +$milestone = $client->api('issue')->milestones()->show('KnpLabs', 'php-github-api', 123); +``` + +### Create a new milestone + +```php +$milestone = $client->api('issue')->milestones()->create('KnpLabs', 'php-github-api', array('title' => '3.0')); +``` + +### Update a milestone + +```php +$milestone = $client->api('issue')->milestones()->update('KnpLabs', 'php-github-api', 123, array('title' => '3.0')); +``` + +### Remove a milestone + +```php +$client->api('issue')->milestones()->remove('KnpLabs', 'php-github-api', 123); +``` + +### List milestone labels + +```php +$labels = $client->api('issue')->milestones()->labels('KnpLabs', 'php-github-api', 123); +``` diff --git a/doc/issue/timeline.md b/doc/issue/timeline.md new file mode 100644 index 00000000000..5b0760f92ee --- /dev/null +++ b/doc/issue/timeline.md @@ -0,0 +1,17 @@ +## Issues / Timeline API +[Back to the "Issues API"](../issues.md) | [Back to the navigation](../README.md) + +Wraps [GitHub Issue Timeline API](http://developer.github.com/v3/issues/timeline/). + +This api is currently only available to developers in Early Access. To access the API during the Early Access period, +you must provide a custom media type in the Accept header. + +```php +$client->api('ìssue')->timeline()->configure(); +``` + +### List events for an issue + +```php +$events = $client->api('issue')->timeline()->all('KnpLabs', 'php-github-api', 123); +``` diff --git a/doc/issues.md b/doc/issues.md index a92ade373ec..317f4babebe 100644 --- a/doc/issues.md +++ b/doc/issues.md @@ -1,5 +1,5 @@ ## Issues API -[Back to the navigation](index.md) +[Back to the navigation](README.md) Listing issues, searching, editing and closing your projects issues. Wraps [GitHub Issue API](http://developer.github.com/v3/issues/). @@ -7,6 +7,7 @@ Wraps [GitHub Issue API](http://developer.github.com/v3/issues/). Additional APIs: * [Comments](issue/comments.md) * [Labels](issue/labels.md) +* [Milestones](issue/milestones.md) ### List issues in a project @@ -22,7 +23,7 @@ Returns an array of issues. $issues = $client->api('issue')->find('KnpLabs', 'php-github-api', 'closed', 'bug'); ``` -Returns an array of closed issues matching the "bug" term. +Returns an array of closed issues matching the "bug" term. For more complex searches, use the [search api](search.md) which supports the advanced GitHub search syntax. ### Get information about an issue @@ -37,10 +38,10 @@ Returns an array of information about the issue. > Requires [authentication](security.md). ```php -$client->api('issue')->create('KnpLabs', 'php-github-api', array('title' => 'The issue title', 'body' => 'The issue body'); +$client->api('issue')->create('KnpLabs', 'php-github-api-example', array('title' => 'The issue title', 'body' => 'The issue body')); ``` -Creates a new issue in the repo "php-github-api" of the user "KnpLabs". The issue is assigned to the authenticated user. +Creates a new issue in the repo "php-github-api-example" (the repository in this example does not exist) of the user "KnpLabs". The issue is assigned to the authenticated user. Returns an array of information about the issue. ### Close an issue @@ -83,3 +84,15 @@ $client->api('issue')->all('KnpLabs', 'php-github-api', array('labels' => 'label ``` Returns an array of issues matching the given label. + +### Lock an issue discussion + +```php +$client->api('issue')->lock('KnpLabs', 'php-github-api', 4); +``` + +### Unlock an issue discussion + +```php +$client->api('issue')->unlock('KnpLabs', 'php-github-api', 4); +``` diff --git a/doc/meta.md b/doc/meta.md new file mode 100644 index 00000000000..fb3d579f1d9 --- /dev/null +++ b/doc/meta.md @@ -0,0 +1,29 @@ +## Meta API +[Back to the navigation](README.md) + + +Wrap [GitHub Meta API](http://developer.github.com/v3/meta/). + +### Get information about GitHub services + +```php +$service = $client->api('meta')->service(); +``` + +return + +``` +array(3) { + 'verifiable_password_authentication' => bool + 'hooks' => + array(1) { + [0] => + string(15) "127.0.0.1/22" + } + 'git' => + array(1) { + [0] => + string(15) "127.0.0.1/22" + } +} +``` diff --git a/doc/miscellaneous/codeofconduct.md b/doc/miscellaneous/codeofconduct.md new file mode 100644 index 00000000000..c47b3c49774 --- /dev/null +++ b/doc/miscellaneous/codeofconduct.md @@ -0,0 +1,14 @@ +## CodeOfConduct API +[Back to the navigation](../README.md) + +### Lists all code of conducts. + +```php +$codeOfConducts = $client->api('codeOfConduct')->all(); +``` + +### Get a code of conduct. + +```php +$codeOfConducts = $client->api('codeOfConduct')->show('contributor_covenant'); +``` diff --git a/doc/miscellaneous/emojis.md b/doc/miscellaneous/emojis.md new file mode 100644 index 00000000000..0ba2045596e --- /dev/null +++ b/doc/miscellaneous/emojis.md @@ -0,0 +1,8 @@ +## Emojis API +[Back to the navigation](../README.md) + +### Lists all available emojis on GitHub. + +```php +$emojis = $client->api('emojis')->all(); +``` diff --git a/doc/miscellaneous/gitignore.md b/doc/miscellaneous/gitignore.md new file mode 100644 index 00000000000..181424f34ad --- /dev/null +++ b/doc/miscellaneous/gitignore.md @@ -0,0 +1,14 @@ +## Gitignore API +[Back to the navigation](../README.md) + +### Lists all available gitignore templates + +```php +$gitignoreTemplates = $client->api('gitignore')->all(); +``` + +### Get a single template + +```php +$gitignore = $client->api('gitignore')->show('C'); +``` diff --git a/doc/miscellaneous/licenses.md b/doc/miscellaneous/licenses.md new file mode 100644 index 00000000000..c533f7ffda0 --- /dev/null +++ b/doc/miscellaneous/licenses.md @@ -0,0 +1,14 @@ +## Licenses API +[Back to the navigation](../README.md) + +### Lists all licenses. + +```php +$licenses = $client->api('licenses')->all(); +``` + +### Get a license. + +```php +$license = $client->api('licenses')->show('gpl-2.0'); +``` diff --git a/doc/miscellaneous/markdown.md b/doc/miscellaneous/markdown.md new file mode 100644 index 00000000000..4f9ffecc179 --- /dev/null +++ b/doc/miscellaneous/markdown.md @@ -0,0 +1,14 @@ +## Markdown API +[Back to the navigation](../README.md) + +### Render an arbitrary Markdown document + +```php +$gitignoreTemplates = $client->api('markdown')->render('Hello world github/linguist#1 **cool**, and #1!', 'markdown'); +``` + +### Render a Markdown document in raw mode + +```php +$gitignore = $client->api('markdown')->renderRaw('path/to/file'); +``` diff --git a/doc/notification.md b/doc/notification.md new file mode 100644 index 00000000000..ad022cad835 --- /dev/null +++ b/doc/notification.md @@ -0,0 +1,54 @@ +## Notification API +[Back to the navigation](README.md) + +Listing notifications and marking them as read. +Wraps [GitHub Notification API](https://developer.github.com/v3/activity/notifications/). + +### List notifications + +```php +$issues = $client->api('notification')->all(); +``` + +Returns an array of unread notifications. + +### Include already read notifications, including participating, or since a certain date + +```php +$includingRead = true; +$participating = true; +$since = new DateTime('1970/01/01'); +$issues = $client->api('notification')->all($includingRead, $participating, $since); +``` + +Returns an array of all notifications + +### Mark notifications as read + +```php +$client->api('notification')->markRead(); +``` + +or up until a certain date + +```php +$client->api('notification')->markRead(new DateTime('2015/01/01')); +``` + +Marks all notifications as read up until the current date, unless a date is given + +### Mark a thread as read using its ID + +```php +$client->api('notification')->markThreadRead($id); +``` + +Marks a single thread as read using its ID. + +### Get a single thread using its ID + +```php +$client->api('notification')->id($id); +``` + +Retrieves single thread's data using its ID. diff --git a/doc/organization.md b/doc/organization.md index 6763a8f845b..e44c436dff3 100644 --- a/doc/organization.md +++ b/doc/organization.md @@ -1,10 +1,26 @@ ## Organization API -[Back to the navigation](index.md) +[Back to the navigation](README.md) -Wraps [GitHub Organization API](http://developer.github.com/v3/organization/). +Wraps [GitHub Organization API](http://developer.github.com/v3/orgs/). Additional APIs: * [Members API](organization/members.md) * [Teams API](organization/teams.md) +### List issues in an organization +[GitHub Issues API](https://developer.github.com/v3/issues/). + +```php +$issues = $client->api('organizations')->issues('KnpLabs', 'php-github-api', array('state' => 'open')); +``` +You can specify the page number: + +```php +$issues = $client->api('organizations')->issues('KnpLabs', 'php-github-api', array('state' => 'open'), 2); +``` + +Returns an array of issues. + + + To be written... diff --git a/doc/organization/actions/secrets.md b/doc/organization/actions/secrets.md new file mode 100644 index 00000000000..04b10877fa2 --- /dev/null +++ b/doc/organization/actions/secrets.md @@ -0,0 +1,85 @@ +## Organization / Secrets API +[Back to the "Organization API"](../organization.md) | [Back to the navigation](../README.md) + +### List organization secrets + +https://docs.github.com/en/rest/reference/actions#list-organization-secrets + +```php +$secrets = $client->organization()->secrets()->all('KnpLabs'); +``` + +### Get an organization secret + +https://docs.github.com/en/rest/reference/actions#get-an-organization-secret + +```php +$secret = $client->organization()->secrets()->show('KnpLabs', $secretName); +``` + +### Create an organization secret + +https://docs.github.com/en/rest/reference/actions#create-or-update-an-organization-secret + +```php +$client->organization()->secrets()->create('KnpLabs', $secretName, [ + 'encrypted_value' => $encryptedValue, + 'visibility' => $visibility, + 'selected_repository_ids' => $selectedRepositoryIds, +]); +``` + +### Update an organization secret + +https://docs.github.com/en/rest/reference/actions#create-or-update-an-organization-secret + +```php +$client->organization()->secrets()->update('KnpLabs', $secretName, [ + 'key_id' => 'keyId', + 'encrypted_value' => 'encryptedValue', + 'visibility' => 'private', +]); +``` + +### Delete an organization secret + +https://docs.github.com/en/rest/reference/actions#delete-an-organization-secret + +```php +$client->organization()->secrets()->remove('KnpLabs', $secretName); +``` + +### List selected repositories for organization secret + +https://docs.github.com/en/rest/reference/actions#list-selected-repositories-for-an-organization-secret + +```php +$client->organization()->secrets()->selectedRepositories('KnpLabs', $secretName); +``` + +### Set selected repositories for an organization secret + +https://docs.github.com/en/rest/reference/actions#set-selected-repositories-for-an-organization-secret + +```php +$client->organization()->secrets()->setSelectedRepositories('KnpLabs', 'secretName', [ + 'selected_repository_ids' => [1, 2, 3], +]); +``` + +### Remove selected repository from an organization secret + +https://docs.github.com/en/rest/reference/actions#remove-selected-repository-from-an-organization-secret + +```php +$client->organization()->secrets()->addSecret('KnpLabs', $repositoryId, $secretName); +``` + +### Get an organization public key + +https://docs.github.com/en/rest/reference/actions#get-an-organization-public-key + +```php +$client->organization()->secrets()->publicKey('KnpLabs'); +``` + diff --git a/doc/organization/actions/self_hosted_runners.md b/doc/organization/actions/self_hosted_runners.md new file mode 100644 index 00000000000..f6e915cdce5 --- /dev/null +++ b/doc/organization/actions/self_hosted_runners.md @@ -0,0 +1,51 @@ +## Organization / Actions / Self Hosted Runners API +[Back to the "Organization API"](../../organization.md) | [Back to the navigation](../../README.md) + +# List self-hosted runners for an Organization + +https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#list-self-hosted-runners-for-an-organization + +```php +$runners = $client->api('organization')->runners()->all('KnpLabs'); +``` + +# Get a self-hosted runner for an Organization + + https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#get-a-self-hosted-runner-for-an-organization + +```php +$runner = $client->api('organization')->runners()->show('KnpLabs', $runnerId); +``` + +# Delete a self-hosted runner from an Organization + +https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#delete-a-self-hosted-runner-from-an-organization + +```php +$client->api('organization')->runners()->remove('KnpLabs', $runnerId); +``` + +# List runner applications for an Organization + +https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#list-runner-applications-for-an-organization + +```php +$applications = $client->api('organization')->selfHostedRunners()->applications('KnpLabs'); +``` + +# List of all runners with Pagination + +```php +$api = $github->api('organization')->runners(); +$paginator = new Github\ResultPager($github); +$parameters = array('KnpLabs'); +$runners = $paginator->fetchAll($api, 'all', $parameters); + +do { + foreach ($runners['runners'] as $runner) { + // code + } + $runners = $paginator->fetchNext(); +} +while($paginator->hasNext()); +``` diff --git a/doc/organization/actions/variables.md b/doc/organization/actions/variables.md new file mode 100644 index 00000000000..89c641007f3 --- /dev/null +++ b/doc/organization/actions/variables.md @@ -0,0 +1,87 @@ +## Organization / Variables API +[Back to the "Organization API"](../organization.md) | [Back to the navigation](../README.md) + +### List organization variables + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#list-organization-variables + +```php +$variables = $client->organization()->variables()->all('KnpLabs'); +``` + +### Get an organization variable + +https://docs.github.com/en/rest/reference/actions#get-an-organization-secret + +```php +$variable = $client->organization()->variables()->show('KnpLabs', $variableName); +``` + +### Create an organization variable + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#create-an-organization-variable + +```php +$client->organization()->variables()->create('KnpLabs', [ + 'name' => $name, + 'value' => $value, + 'visibility' => $visibility, + 'selected_repository_ids' => $selectedRepositoryIds, +]); +``` + +### Update an organization variable + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#update-an-organization-variable + +```php +$client->organization()->variables()->update('KnpLabs', $variableName, [ + 'name' => $name, + 'value' => $value, + 'visibility' => $visibility, + 'selected_repository_ids' => $selectedRepositoryIds +]); +``` + +### Delete an organization variable + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#delete-an-organization-variable + +```php +$client->organization()->variables()->remove('KnpLabs', $variableName); +``` + +### List selected repositories for organization variable + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#list-selected-repositories-for-an-organization-variable + +```php +$client->organization()->variables()->selectedRepositories('KnpLabs', $variableName); +``` + +### Set selected repositories for an organization variable + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#set-selected-repositories-for-an-organization-variable + +```php +$client->organization()->variables()->setSelectedRepositories('KnpLabs', 'variableName', [ + 'selected_repository_ids' => [1, 2, 3], +]); +``` + +### Add selected repository to an organization variable + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#add-selected-repository-to-an-organization-variable + +```php +$client->organization()->variables()->addRepository('KnpLabs', $repositoryId, $variableName); +``` + +### Remove selected repository from an organization variable + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#remove-selected-repository-from-an-organization-variable + +```php +$client->organization()->variables()->removeRepository('KnpLabs', $repositoryId, $variableName); +``` + diff --git a/doc/organization/members.md b/doc/organization/members.md index 730836da497..b22b79c6008 100644 --- a/doc/organization/members.md +++ b/doc/organization/members.md @@ -1,5 +1,5 @@ ## Organization / Members API -[Back to the "Organization API"](../organization.md) | [Back to the navigation](../index.md) +[Back to the "Organization API"](../organization.md) | [Back to the navigation](../README.md) Wraps [GitHub Organization Members API](http://developer.github.com/v3/organization/members/). diff --git a/doc/organization/organization-roles.md b/doc/organization/organization-roles.md new file mode 100644 index 00000000000..a320b6eb047 --- /dev/null +++ b/doc/organization/organization-roles.md @@ -0,0 +1,108 @@ +## Organization / Webhooks API +[Back to the navigation](../README.md) + +Listing, showing, assigning, and removing orgniazationroles. +Wraps [GitHub Organization Roles API](https://docs.github.com/en/rest/orgs/organization-roles). + +Additional APIs: +* [Organization](../doc/organization) + +### List all organizaton roles in an organization + +> Requires [authentication](../security.md). + +```php +$roles = $client->organization()->organizationRoles()->all('acme'); +``` + +Returns a counter and a list of organization roles in the organization. + +### Get an organization role in an organization + +> Requires [authentication](../security.md). + +```php +$role = $client->organization()->organizationRoles()->show('acme', 123); +``` + +Returns a single organization role in the organization. + +### List all teams with role assigned in an organization + +> Requires [authentication](../security.md). + +```php +$users = $client->organization()->organizationRoles()->listTeamsWithRole('acme', 1); +``` + +Returns a list of teams with the role assigned to them. + +### Assign a single role to a team in an organization + +> Requires [authentication](../security.md). + +```php +$client->organization()->organizationRoles()->assignRoleToTeam('acme', 1, 'admin-user'); +``` + +No content is returned. + +### Remove a single role from a team in an organization + +> Requires [authentication](../security.md). + +```php +$client->organization()->organizationRoles()->removeRoleFromTeam('acme', 1, 'admin-team'); +``` + +No content is returned. + +### Remove all roles from a team in an organization + +> Requires [authentication](../security.md). + +```php +$client->organization()->organizationRoles()->removeAllRolesFromTeam('acme', 'admin-team'); +``` + +No content is returned. + +### List all users with role assigned in an organization + +> Requires [authentication](../security.md). + +```php +$users = $client->organization()->organizationRoles()->listUsersWithRole('acme', 1); +``` + +Returns a list of users with the role assigned to them. + +### Assign a single role to a user in an organization + +> Requires [authentication](../security.md). + +```php +$client->organization()->organizationRoles()->assignRoleToUser('acme', 1, 'admin-user'); +``` + +No content is returned. + +### Remove a single role from a user in an organization + +> Requires [authentication](../security.md). + +```php +$client->organization()->organizationRoles()->removeRoleFromUser('acme', 1, 'admin-user'); +``` + +No content is returned. + +### Remove all roles from a user in an organization + +> Requires [authentication](../security.md). + +```php +$client->organization()->organizationRoles()->removeAllRolesFromUser('acme', 'admin-user'); +``` + +No content is returned. diff --git a/doc/organization/secret-scanning.md b/doc/organization/secret-scanning.md new file mode 100644 index 00000000000..9ee5d4d972d --- /dev/null +++ b/doc/organization/secret-scanning.md @@ -0,0 +1,10 @@ +## Organization / Secret Scanning API +[Back to the "Organization API"](../../organization.md) | [Back to the navigation](../../README.md) + +# List secret-scanning alerts for an Organization + +https://docs.github.com/en/enterprise-server@3.5/rest/secret-scanning#list-secret-scanning-alerts-for-an-organization + +```php +$alerts = $client->api('organization')->secretScanning()->alerts('KnpLabs'); +``` diff --git a/doc/organization/teams.md b/doc/organization/teams.md index 1f932139493..7fc1c8b1075 100644 --- a/doc/organization/teams.md +++ b/doc/organization/teams.md @@ -1,5 +1,5 @@ ## Organization / Teams API -[Back to the "Organization API"](../organization.md) | [Back to the navigation](../index.md) +[Back to the "Organization API"](../organization.md) | [Back to the navigation](../README.md) Wraps [GitHub Organization Teams API](http://developer.github.com/v3/organization/teams/). diff --git a/doc/organization/webhooks.md b/doc/organization/webhooks.md new file mode 100644 index 00000000000..669e3446125 --- /dev/null +++ b/doc/organization/webhooks.md @@ -0,0 +1,95 @@ +## Organization / Webhooks API +[Back to the navigation](../README.md) + +Listing, showing, creating, updating, testing and removing organizations webhooks. +Wraps [GitHub Organization Webhooks API](https://developer.github.com/v3/orgs/hooks/). + +Additional APIs: +* [Organization](../doc/organization) + +### List webhooks for an organization + +> Requires [authentication](../security.md). + +```php +$webhooks = $client->organization()->all('KnpLabs'); +``` + +Returns an array of webhooks for the organization. + +### Get a webhook for an organization + +> Requires [authentication](../security.md). + +```php +$webhook = $client->organization()->show('KnpLabs', 123); +``` + +Returns the webhook with the ID 123 as an array for the organization. + +### Create a new webhook for an organization + +> Requires [authentication](../security.md). + +```php +$webhook = $client->organization()->create('KnpLabs', array( + 'name' => 'web', + 'active' => true, + 'events' => array( + 'push', + 'pull_request' + ), + 'config' => array( + 'url' => 'http=>//example.com/webhook', + 'content_type' => 'json' + ) +)); +``` + +Creates a new webhook for the organization. +*name* and *url* parameters are required. + +The create webhook will be returned as an array. + +### Update an existing webhook for an organization + +> Requires [authentication](../security.md). + +```php +$success = $client->organization()->update('KnpLabs', 123, array( + 'active' => true, + 'events' => array( + 'push', + 'pull_request' + ), + 'config' => array( + 'url' => 'http=>//example.com/webhook', + 'content_type' => 'json' + ) +)); +``` + +Update an existing webhook with ID 123 for the organization. +*url* parameter is required. + +In case of success, an array of information about the webhook will be returned. + +### Ping a webhook for an organization + +> Requires [authentication](../security.md). + +```php +$client->organization()->pings('KnpLabs', 123); +``` + +No content is returned. + +### Delete a webhook for an organization + +> Requires [authentication](../security.md). + +```php +$client->organization()->delete('KnpLabs', 123); +``` + +No content is returned. diff --git a/doc/project/cards.md b/doc/project/cards.md new file mode 100644 index 00000000000..b66707e6779 --- /dev/null +++ b/doc/project/cards.md @@ -0,0 +1,57 @@ +## Repo / Cards API +[Back to the "Repos API"](../repos.md) | [Back to the navigation](../README.md) + +This api is currently only available to developers in Early Access. To access the API during the Early Access period, +you must provide a custom media type in the Accept header. + +Both repositories and organisations have projects. The api is only different for getting all project or retrieving a single project. +All the example use the repository projects column card api but this also works form the organization api (`$client->api('org_projects')->columns()->cards()`) + + +```php +$client->api('repo')->projects()->columns()->cards()->configure(); +``` + +### List all cards of a column + +```php +$cards = $client->api('repo')->projects()->columns()->cards()->all($columnId); +``` + +### List one card + +```php +$card = $client->api('repo')->projects()->columns()->cards()->show($cardId); +``` + +### Create a card + +> Requires [authentication](../security.md). + +```php +$card = $client->api('repo')->projects()->columns()->cards()->create($columnId, array('content_type' => 'Issue', 'content_id' => '452')); +``` + +### Edit a card + +> Requires [authentication](../security.md). + +```php +$card = $client->api('repo')->project()->columns()->cards()->update($cardId, array('note' => 'card note')); +``` + +### Remove a card + +> Requires [authentication](../security.md). + +```php +$card = $client->api('repo')->projects()->columns()->cards()->deleteCard($cardId); +``` + +### Move a card + +> Requires [authentication](../security.md). + +```php +$card = $client->api('repo')->projects()->columns()->cards()->move($cardId, array('position' => 'top)); +``` diff --git a/doc/project/columns.md b/doc/project/columns.md new file mode 100644 index 00000000000..2f4a990942d --- /dev/null +++ b/doc/project/columns.md @@ -0,0 +1,57 @@ +## Repo / Columns API +[Back to the "Repos API"](../repos.md) | [Back to the navigation](../README.md) + +This api is currently only available to developers in Early Access. To access the API during the Early Access period, +you must provide a custom media type in the Accept header. + +Both repositories and organisations have projects. The api is only different for getting all project or retrieving a single project. +All the example use the repository projects column api but this also works form the organization api (`$client->api('org_projects')->columns()`) + + +```php +$client->api('repo')->projects()->columns()->configure(); +``` + +### List all columns of a project + +```php +$columns = $client->api('repo')->projects()->columns()->all($projectId); +``` + +### List one column + +```php +$column = $client->api('repo')->projects()->columns()->show($columnId); +``` + +### Create a column + +> Requires [authentication](../security.md). + +```php +$column = $client->api('repo')->projects()->columns()->create($projectId, array('name' => 'Column name')); +``` + +### Edit a column + +> Requires [authentication](../security.md). + +```php +$column = $client->api('repo')->project()->columns()->update($columnId, array('name' => 'New name')); +``` + +### Remove a column + +> Requires [authentication](../security.md). + +```php +$column = $client->api('repo')->projects()->columns()->deleteColumn($columnId); +``` + +### Move a column + +> Requires [authentication](../security.md). + +```php +$column = $client->api('repo')->projects()->columns()->move($columnId, array('position' => 'first)); +``` diff --git a/doc/project/projects.md b/doc/project/projects.md new file mode 100644 index 00000000000..103bbe10c86 --- /dev/null +++ b/doc/project/projects.md @@ -0,0 +1,52 @@ +## Repo / Projects API +[Back to the "Repos API"](../) | [Back to the navigation](../README.md) + +This api is currently only available to developers in Early Access. To access the API during the Early Access period, +you must provide a custom media type in the Accept header. + +Both repositories and organisations have projects. The api is only different for getting all or a single project. +All the example use the repository projects api but this also works form the organization api (`$client->api('org_projects')`) + +```php +$client->api('repo')->projects()->configure(); +``` + +### List all projects + +```php +$projects = $client->api('repo')->projects()->all('twbs', 'bootstrap'); + +//or + +$projects = $client->api('org_projects')->all('twbs'); +``` + +### List one project + +```php +$project = $client->api('repo')->projects()->show($projectId); +``` + +### Create a project + +> Requires [authentication](../security.md). + +```php +$project = $client->api('repo')->projects()->create('twbs', 'bootstrap', array('name' => 'Project name')); +``` + +### Edit a project + +> Requires [authentication](../security.md). + +```php +$project = $client->api('repo')->project()->update($projectId, array('name' => 'New name')); +``` + +### Remove a project + +> Requires [authentication](../security.md). + +```php +$project = $client->api('repo')->projects()->deleteProject($projectId); +``` diff --git a/doc/pull_request/comments.md b/doc/pull_request/comments.md index dfeb5be3333..e996f804989 100644 --- a/doc/pull_request/comments.md +++ b/doc/pull_request/comments.md @@ -1,5 +1,5 @@ ## Pull Requests / Review Comments API -[Back to the "Pull Requests API"](../pull_requests.md) | [Back to the navigation](../index.md) +[Back to the "Pull Requests API"](../pull_requests.md) | [Back to the navigation](../README.md) Review Comments are comments on a portion of the unified diff. These are separate from Commit Comments (which are applied directly to a commit, outside of the Pull Request view), and Issue Comments (which do not reference @@ -37,7 +37,7 @@ $comment = $client->api('pull_request')->comments()->create('KnpLabs', 'php-gith 'path' => 'README.markdown', 'position' => 37, 'line' => 31 -); +)); ``` This returns the details of the comment. @@ -50,7 +50,7 @@ This returns the details of the comment. $comment = $client->api('pull_request')->comments()->create('KnpLabs', 'php-github-api', 8, array( 'body' => 'Yeah! Really nice change', 'in_reply_to' => 2 -); +)); ``` This returns the details of the comment. @@ -62,12 +62,12 @@ This returns the details of the comment. ```php $comment = $client->api('pull_request')->comments()->update('KnpLabs', 'php-github-api', 2, array( 'body' => 'Hell Yeah! Awesome change!' -); +)); ``` This returns the details of the updated comment. -### Remove a review comment from an pull request +### Remove a review comment from a pull request > Requires [authentication](../security.md). diff --git a/doc/pull_request/review_request.md b/doc/pull_request/review_request.md new file mode 100644 index 00000000000..bed33a426c2 --- /dev/null +++ b/doc/pull_request/review_request.md @@ -0,0 +1,20 @@ +## Pull Requests / Review Requests API +[Back to the "Pull Requests API"](../pull_requests.md) | [Back to the navigation](../README.md) + +### List all review requests + +```php +$reviewRequests = $client->api('pull_request')->reviewRequests()->all('twbs', 'bootstrap', 12); +``` + +### Create a review request + +```php +$client->api('pull_request')->reviewRequests()->create('twbs', 'bootstrap', 12, array('user1', 'user2')); +``` + +### Remove a review request + +```php +$client->api('pull_request')->reviewRequests()->remove('twbs', 'bootstrap', 12, array('user1', 'user2')); +``` diff --git a/doc/pull_request/reviews.md b/doc/pull_request/reviews.md new file mode 100644 index 00000000000..fdc5f09442e --- /dev/null +++ b/doc/pull_request/reviews.md @@ -0,0 +1,51 @@ +## Pull Requests / Reviews API +[Back to the "Pull Requests API"](../pull_requests.md) | [Back to the navigation](../README.md) + +### List all reviews + +```php +$reviewRequests = $client->api('pull_request')->reviews()->all('twbs', 'bootstrap', 12); +``` + +### Create a review + +```php +$client->api('pull_request')->reviews()->create('twbs', 'bootstrap', 12, array( + 'event' => 'APPROVE', // Accepted values: APPROVE, REQUEST_CHANGES, COMMENT, see https://developer.github.com/v3/pulls/reviews/#input-1 + 'body' => 'OK, looks good :)',// Optional, the review body text + 'commit_id' => $commitSha, // Optional, default value is HEAD sha +)); +``` + +### Get a review + +```php +$client->api('pull_request')->reviews()->show('twbs', 'bootstrap', 12, $reviewId); +``` + +### Get comment from a review + +```php +$client->api('pull_request')->reviews()->comments('twbs', 'bootstrap', 12, $reviewId); +``` + +### Dismiss a review +**This does not remove the review but dismisses the (dis)approval status of this one** + +Note: To dismiss a pull request review on a protected branch, you must be a +repository administrator or be included in the list of people or teams who can dismiss pull request reviews. + +```php +$client->api('pull_request')->reviews()->remove('twbs', 'bootstrap', 12, $reviewId, 'Dismiss reason (mandatory)'); +``` + +### Remove a review + +```php +$client->api('pull_request')->reviews()->remove('twbs', 'bootstrap', 12, $reviewId); +``` + +### Update a review +```php +$client->api('pull_request')->reviews()->update('twbs', 'bootstrap', 12, $reviewId, 'Review body (mandatory)') +``` diff --git a/doc/pull_requests.md b/doc/pull_requests.md index 8f8ad29b7d3..d87e6180043 100644 --- a/doc/pull_requests.md +++ b/doc/pull_requests.md @@ -1,8 +1,10 @@ ## Pull Requests API -[Back to the navigation](index.md) +[Back to the navigation](README.md) Additional APIs: * [Review Comments](pull_request/comments.md) +* [Review Request](pull_request/review_request.md) +* [Reviews](pull_request/reviews.md) Lets you list pull requests for a given repository, list one pull request in particular along with its discussion, and create a pull-request. @@ -15,10 +17,10 @@ Wraps [GitHub Pull Request API](http://developer.github.com/v3/pulls/). ```php api('pull_request')->all('ezsystems', 'ezpublish', 'open'); +$openPullRequests = $client->api('pull_request')->all('ezsystems', 'ezpublish', array('state' => 'open')); ``` -The last parameter of the listPullRequests method default to 'open'. The call above is equivalent to: +The state parameter of the listPullRequests method default to 'open'. The call above is equivalent to: ```php api('pull_request')->all('ezsystems', 'ezpublish'); ```php api('pull_request')->all('ezsystems', 'ezpublish', 'closed'); +$closedPullRequests = $client->api('pull_request')->all('ezsystems', 'ezpublish', array('state' => 'closed')); ``` ``$closedPullRequests`` contains an array of closed pull-requests for this repository. @@ -54,6 +56,7 @@ The ``$pullRequest`` array contains the same elements as every entry in the resu A pull request can either be created by supplying both the Title & Body, OR an Issue ID. Details regarding the content of parameters 3 and 4 of the ``create``. +You can create a draft pull request by adding a parameter with key `draft` and value `true`. #### Populated with Title and Body @@ -67,7 +70,7 @@ $pullRequest = $client->api('pull_request')->create('ezsystems', 'ezpublish', ar 'head' => 'testbranch', 'title' => 'My nifty pull request', 'body' => 'This pull request contains a bunch of enhancements and bug-fixes, happily shared with you' -); +)); ``` This returns the details of the pull request. @@ -83,7 +86,7 @@ $pullRequest = $client->api('pull_request')->create('ezsystems', 'ezpublish', ar 'base' => 'master', 'head' => 'testbranch', 'issue' => 15 -); +)); ``` This returns the details of the pull request. diff --git a/doc/rate_limits.md b/doc/rate_limits.md new file mode 100644 index 00000000000..454981d0b4f --- /dev/null +++ b/doc/rate_limits.md @@ -0,0 +1,81 @@ +## Rate Limit API +[Back to the navigation](README.md) + +Get rate limit wrappers from [GitHub Rate Limit API](http://developer.github.com/v3/rate_limit/). + +#### Get All Rate Limits + +```php +/** @var \Github\Api\RateLimit\RateLimitResource[] $rateLimits */ +$rateLimits = $client->api('rate_limit')->getResources(); +``` + +var_dump() output: +``` +array(4) { + ["core"]=> + object(Github\Api\RateLimit\RateLimitResource)#30 (4) { + ["name":"Github\Api\RateLimit\RateLimitResource":private]=> + string(4) "core" + ["limit":"Github\Api\RateLimit\RateLimitResource":private]=> + int(5000) + ["reset":"Github\Api\RateLimit\RateLimitResource":private]=> + int(1566137712) + ["remaining":"Github\Api\RateLimit\RateLimitResource":private]=> + int(5000) + } + ["search"]=> + object(Github\Api\RateLimit\RateLimitResource)#32 (4) { + ["name":"Github\Api\RateLimit\RateLimitResource":private]=> + string(6) "search" + ["limit":"Github\Api\RateLimit\RateLimitResource":private]=> + int(30) + ["reset":"Github\Api\RateLimit\RateLimitResource":private]=> + int(1566134172) + ["remaining":"Github\Api\RateLimit\RateLimitResource":private]=> + int(30) + } + ["graphql"]=> + object(Github\Api\RateLimit\RateLimitResource)#43 (4) { + ["name":"Github\Api\RateLimit\RateLimitResource":private]=> + string(7) "graphql" + ["limit":"Github\Api\RateLimit\RateLimitResource":private]=> + int(5000) + ["reset":"Github\Api\RateLimit\RateLimitResource":private]=> + int(1566137712) + ["remaining":"Github\Api\RateLimit\RateLimitResource":private]=> + int(5000) + } + ["integration_manifest"]=> + object(Github\Api\RateLimit\RateLimitResource)#44 (4) { + ["name":"Github\Api\RateLimit\RateLimitResource":private]=> + string(20) "integration_manifest" + ["limit":"Github\Api\RateLimit\RateLimitResource":private]=> + int(5000) + ["reset":"Github\Api\RateLimit\RateLimitResource":private]=> + int(1566137712) + ["remaining":"Github\Api\RateLimit\RateLimitResource":private]=> + int(5000) + } +} +``` + +#### Get Core Rate Limit + +```php +$coreLimit = $client->api('rate_limit')->getResource('core')->getLimit(); +$remaining = $client->api('rate_limit')->getResource('core')->getRemaining(); +$reset = $client->api('rate_limit')->getResource('core')->getReset(); +``` + +#### Get Search Rate Limit + +```php +$searchLimit = $client->api('rate_limit')->getResource('search')->getLimit(); +``` + +#### Get GraphQL Rate Limit + +```php +$searchLimit = $client->api('rate_limit')->getResource('graphql')->getLimit(); +``` diff --git a/doc/repo/actions/artifacts.md b/doc/repo/actions/artifacts.md new file mode 100644 index 00000000000..58d68ff66e8 --- /dev/null +++ b/doc/repo/actions/artifacts.md @@ -0,0 +1,44 @@ +## Repo / Actions / Artifacts API +[Back to the "Repos API"](../../repos.md) | [Back to the navigation](../../README.md) + +### List artifacts for a repository + +https://docs.github.com/en/rest/reference/actions#list-artifacts-for-a-repository + +```php +$artifacts = $client->api('repo')->artifacts()->all('KnpLabs'); +``` + +### List workflow run artifacts + +https://docs.github.com/en/rest/reference/actions#list-workflow-run-artifacts + +```php +$runArtifacts = $client->api('repo')->artifacts()->runArtifacts('KnpLabs', 'php-github-api', $runId); +``` + +### Get an artifact + +https://docs.github.com/en/rest/reference/actions#get-an-artifact + +```php +$artifact = $client->api('repo')->artifacts()->show('KnpLabs', 'php-github-api', $artifactId); +``` + +### Delete an artifact + +https://docs.github.com/en/rest/reference/actions#delete-an-artifact + +```php +$client->api('repo')->artifacts()->delete('KnpLabs', 'php-github-api', $artifactId); +``` + + +### Download an artifact + +https://docs.github.com/en/rest/reference/actions#download-an-artifact + +```php +$artifactFile = $client->api('repo')->artifacts()->download('KnpLabs', 'php-github-api', $artifactId, $format = 'zip'); +file_put_contents($artifactId.'.'.$format, $artifactFile); +``` diff --git a/doc/repo/actions/secrets.md b/doc/repo/actions/secrets.md new file mode 100644 index 00000000000..d4769639d37 --- /dev/null +++ b/doc/repo/actions/secrets.md @@ -0,0 +1,54 @@ +## Repo / Actions / Secrets API +[Back to the "Repos API"](../../repos.md) | [Back to the navigation](../../README.md) + +### List repository secrets + +https://docs.github.com/en/rest/reference/actions#list-repository-secrets + +```php +$secrets = $client->api('repo')->secrets()->all('KnpLabs', 'php-github-api'); +``` + +### Get a repository secret + +https://docs.github.com/en/rest/reference/actions#get-a-repository-secret + +```php +$secret = $client->api('repo')->secrets()->show('KnpLabs', 'php-github-api', $secretName); +``` + +### Create a repository secret + +https://docs.github.com/en/rest/reference/actions#create-or-update-a-repository-secret + +```php +$client->api('repo')->secrets()->create('KnpLabs', 'php-github-api', $secretName, [ + 'encrypted_value' => $encryptedValue, +]); $client->api('repo')->secrets()->all(); +``` + +### Update a repository secret + +https://docs.github.com/en/rest/reference/actions#create-or-update-a-repository-secret + +```php +$client->api('repo')->secrets()->update('KnpLabs', 'php-github-api', $secretName, [ + 'key_id' => $keyId, 'encrypted_value' => $encryptedValue, +]); +``` + +### Delete a repository secret + +https://docs.github.com/en/rest/reference/actions#delete-a-repository-secret + +```php +$client->api('repo')->secrets()->remove('KnpLabs', 'php-github-api', $secretName); +``` + +### Get a repository public key + +https://docs.github.com/en/rest/reference/actions#get-a-repository-public-key + +```php +$publicKey = $client->api('repo')->secrets()->publicKey('KnpLabs', 'php-github-api'); +``` diff --git a/doc/repo/actions/self_hosted_runners.md b/doc/repo/actions/self_hosted_runners.md new file mode 100644 index 00000000000..55a1ed0e420 --- /dev/null +++ b/doc/repo/actions/self_hosted_runners.md @@ -0,0 +1,35 @@ +## Repo / Actions / Self Hosted Runners API +[Back to the "Repos API"](../../repos.md) | [Back to the navigation](../../README.md) + +# List self-hosted runners for a repository + +https://docs.github.com/en/rest/reference/actions#list-self-hosted-runners-for-a-repository + +```php +$runners = $client->api('repo')->selfHostedRunners()->all('KnpLabs', 'php-github-api'); +``` + +# Get a self-hosted runner for a repository + +https://docs.github.com/en/rest/reference/actions#get-a-self-hosted-runner-for-a-repository + +```php +$runner = $client->api('repo')->selfHostedRunners()->show('KnpLabs', 'php-github-api', $runnerId); +``` + +# Delete a self-hosted runner from a repository + +https://docs.github.com/en/rest/reference/actions#delete-a-self-hosted-runner-from-a-repository + +```php +$client->api('repo')->selfHostedRunners()->remove('KnpLabs', 'php-github-api', $runnerId); +``` + +# List runner applications for a repository + +https://docs.github.com/en/rest/reference/actions#list-runner-applications-for-a-repository + +```php +$applications = $client->api('repo')->selfHostedRunners()->applications('KnpLabs', 'php-github-api'); +``` + diff --git a/doc/repo/actions/variables.md b/doc/repo/actions/variables.md new file mode 100644 index 00000000000..c6cc26ac1df --- /dev/null +++ b/doc/repo/actions/variables.md @@ -0,0 +1,48 @@ +## Repo / Actions / Variables API +[Back to the "Repos API"](../../repos.md) | [Back to the navigation](../../README.md) + +### List repository variables + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#list-repository-variables + +```php +$variables = $client->api('repo')->variables()->all('KnpLabs', 'php-github-api'); +``` + +### Get a repository variable + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#get-a-repository-variable + +```php +$variable = $client->api('repo')->variables()->show('KnpLabs', 'php-github-api', $variableName); +``` + +### Create a repository variable + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#create-a-repository-variable + +```php +$client->api('repo')->variables()->create('KnpLabs', 'php-github-api', [ + 'name' => $name, + 'value' => $value, +]); +``` + +### Update a repository variable + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#update-a-repository-variable + +```php +$client->api('repo')->variables()->update('KnpLabs', 'php-github-api', $variableName, [ + 'name' => $name, + 'value' => $value, +]); +``` + +### Delete a repository variable + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#delete-a-repository-variable + +```php +$client->api('repo')->variables()->remove('KnpLabs', 'php-github-api', $variableName); +``` diff --git a/doc/repo/actions/workflow_jobs.md b/doc/repo/actions/workflow_jobs.md new file mode 100644 index 00000000000..62467353c53 --- /dev/null +++ b/doc/repo/actions/workflow_jobs.md @@ -0,0 +1,27 @@ +## Repo / Actions / Workflow Jobs API +[Back to the "Repos API"](../../repos.md) | [Back to the navigation](../../README.md) + +### List jobs for a workflow run + +https://docs.github.com/en/rest/reference/actions#list-jobs-for-a-workflow-run + +```php +$client->api('repo')->workflowJobs()->all('KnpLabs', 'php-github-api', $runId); +``` + +### Get a job for a workflow run + +https://docs.github.com/en/rest/reference/actions#get-a-job-for-a-workflow-run + +```php +$job = $client->api('repo')->workflowJobs()->all('KnpLabs', 'php-github-api', $jobId); +``` + +### Download job logs for a workflow run + +https://docs.github.com/en/rest/reference/actions#download-job-logs-for-a-workflow-run + +```php +$jobLogs = $client->api('repo')->workflowJobs()->downloadLogs('KnpLabs', 'php-github-api', $jobId); +file_put_contents('jobLogs.zip', $jobLogs); +``` diff --git a/doc/repo/actions/workflow_runs.md b/doc/repo/actions/workflow_runs.md new file mode 100644 index 00000000000..4b879ca5b98 --- /dev/null +++ b/doc/repo/actions/workflow_runs.md @@ -0,0 +1,84 @@ +## Repo / Actions / Workflow Runs API +[Back to the "Repos API"](../../repos.md) | [Back to the navigation](../../README.md) + +### List workflow runs for a repository + +https://docs.github.com/en/rest/reference/actions#list-workflow-runs-for-a-repository + +```php +$workflowRuns = $client->api('repo')->workflowRuns()->all('KnpLabs', 'php-github-api'); +``` + +### List workflow runs + +https://docs.github.com/en/rest/reference/actions#list-workflow-runs + +```php +$runs = $client->api('repo')->workflowRuns()->listRuns('KnpLabs', 'php-github-api', $workflow); +``` + +### Get a workflow run + +https://docs.github.com/en/rest/reference/actions#get-a-workflow-run + +```php +$workflowRun = $client->api('repo')->workflowRuns()->show('KnpLabs', 'php-github-api', $runId); +``` + +### Delete a workflow run + +https://docs.github.com/en/rest/reference/actions#delete-a-workflow-run + +```php +$client->api('repo')->workflowRuns()->remove('KnpLabs', 'php-github-api', $runId); +``` + +### Re-run a workflow + +https://docs.github.com/en/rest/reference/actions#re-run-a-workflow + +```php +$client->api('repo')->workflowRuns()->rerun('KnpLabs', 'php-github-api', $runId); +``` + +### Cancel a workflow run + +https://docs.github.com/en/rest/reference/actions#cancel-a-workflow-run + +```php +$client->api('repo')->workflowRuns()->cancel('KnpLabs', 'php-github-api', $runId); +``` + +### Get workflow run usage + +https://docs.github.com/en/rest/reference/actions#get-workflow-run-usage + +```php +$workflowUsage = $client->api('repo')->workflowRuns()->usage('KnpLabs', 'php-github-api', $runId); +``` + +### Download workflow run logs + +https://docs.github.com/en/rest/reference/actions#download-workflow-run-logs + +```php +$logs = $client->api('repo')->workflowRuns()->downloadLogs('KnpLabs', 'php-github-api', $runId); + +file_put_contents('logs.zip', $logs); +``` + +### Delete workflow run logs + +https://docs.github.com/en/rest/reference/actions#delete-workflow-run-logs + +```php +$client->api('repo')->workflowRuns()->deleteLogs('KnpLabs', 'php-github-api', $runId); +``` + +### Approve workflow run + +https://docs.github.com/en/rest/reference/actions#approve-a-workflow-run-for-a-fork-pull-request + +```php +$client->api('repo')->workflowRuns()->approve('KnpLabs', 'php-github-api', $runId); +``` diff --git a/doc/repo/actions/workflows.md b/doc/repo/actions/workflows.md new file mode 100644 index 00000000000..91839cf0ecf --- /dev/null +++ b/doc/repo/actions/workflows.md @@ -0,0 +1,34 @@ +## Repo / Actions / Workflows API +[Back to the "Repos API"](../../repos.md) | [Back to the navigation](../../README.md) + +### List repository workflows + +https://docs.github.com/en/rest/reference/actions#list-repository-workflows + +```php +$workflows = $client->api('repo')->workflows()->all('KnpLabs', 'php-github-api'); +``` + +### Get a workflow + +https://docs.github.com/en/rest/reference/actions#get-a-workflow + +```php +$workflow = $client->api('repo')->workflows()->show('KnpLabs', 'php-github-api', $workflow); +``` + +### Get workflow usage + +https://docs.github.com/en/rest/reference/actions#get-workflow-usage + +```php +$usage = $client->api('repo')->workflows()->usage('KnpLabs', 'php-github-api', $workflow); +``` + +### Dispatch a workflow + +https://docs.github.com/en/rest/reference/actions#create-a-workflow-dispatch-event + +```php +$client->api('repo')->workflows()->dispatches('KnpLabs', 'php-github-api', $workflow, 'main'); +``` diff --git a/doc/repo/assets.md b/doc/repo/assets.md index be59c6b1b8d..93234929074 100644 --- a/doc/repo/assets.md +++ b/doc/repo/assets.md @@ -1,5 +1,5 @@ ## Repo / Releases API -[Back to the "Repos API"](../repos.md) | [Back to the navigation](../index.md) +[Back to the "Repos API"](../repos.md) | [Back to the navigation](../README.md) ### List all assets by release @@ -13,10 +13,16 @@ $assets = $client->api('repo')->releases()->assets()->all('twbs', 'bootstrap', $ $asset = $client->api('repo')->releases()->assets()->show('twbs', 'bootstrap', $assetId); ``` +### Download binary content of asset + +```php +$asset = $client->api('repo')->releases()->assets()->show('twbs', 'bootstrap', $assetId, true); +``` + ### Create an asset ```php -$asset = $client->api('repo')->releases()->assets()->show('twbs', 'bootstrap', $releaseId, $name, $contentType, $content); +$asset = $client->api('repo')->releases()->assets()->create('twbs', 'bootstrap', $releaseId, $name, $contentType, $content); ``` ### Edit an asset diff --git a/doc/repo/check_runs.md b/doc/repo/check_runs.md new file mode 100644 index 00000000000..3b7b69b8f86 --- /dev/null +++ b/doc/repo/check_runs.md @@ -0,0 +1,71 @@ +## Repo / Checks runs API +[Back to the "Repos API"](../repos.md) | [Back to the navigation](../README.md) + +### Create a check run + +[Visit GitHub for a full of list of parameters and their descriptions.](https://docs.github.com/en/rest/reference/checks#create-a-check-run) + +```php +$params = [ + 'name' => 'my check', # required + 'head_sha' => $commitSha, # required + 'status' => 'queued', + 'output' => [/*...*/] +]; +$check = $client->api('repo')->checkRuns()->create('KnpLabs', 'php-github-api', $params); +``` + +### Get a check run + +https://docs.github.com/en/rest/reference/checks#get-a-check-run + +```php +$check = $client->api('repo')->checkRuns()->show('KnpLabs', 'php-github-api', $checkRunId); +``` + +### Update an existing check run + +https://docs.github.com/en/rest/reference/checks#update-a-check-run + +```php +$params = [ + 'name' => 'my check', + 'status' => 'in_progress', + 'output' => [/*...*/] +]; +$check = $client->api('repo')->checkRuns()->update('KnpLabs', 'php-github-api', $checkRunId, $params); +``` + +### List check run annotations + +https://docs.github.com/en/rest/reference/checks#list-check-run-annotations + +```php +$annotations = $client->api('repo')->checkRuns()->annotations('KnpLabs', 'php-github-api', $checkRunId); +``` + +### List check runs for a check suite + +https://docs.github.com/en/rest/reference/checks#list-check-runs-in-a-check-suite + +```php +$params = [/*...*/]; +$checks = $client->api('repo')->checkRuns()->allForCheckSuite('KnpLabs', 'php-github-api', $checkSuiteId, $params); +``` + +### List check runs for a Git reference + +https://docs.github.com/en/rest/reference/checks#list-check-runs-for-a-git-reference + +```php +$params = [/*...*/]; +$checks = $client->api('repo')->checkRuns()->allForReference('KnpLabs', 'php-github-api', $reference, $params); +``` + +### Rerequest a check run + +https://docs.github.com/en/rest/reference/checks#rerequest-a-check-run + +```php +$checks = $client->api('repo')->checkRuns()->rerequest('KnpLabs', 'php-github-api', $checkRunId); +``` diff --git a/doc/repo/check_suites.md b/doc/repo/check_suites.md new file mode 100644 index 00000000000..b91c8199813 --- /dev/null +++ b/doc/repo/check_suites.md @@ -0,0 +1,48 @@ +## Repo / Check suites API +[Back to the "Repos API"](../repos.md) | [Back to the navigation](../README.md) + +### Create a check suite + +https://docs.github.com/en/rest/reference/checks#create-a-check-suite + +```php +$params = [ + 'head_sha' => $commitSha, # required +]; +$check = $client->api('repo')->checkSuites()->create('KnpLabs', 'php-github-api', $params); +``` + +### Update check suite preferences + +https://docs.github.com/en/rest/reference/checks#update-repository-preferences-for-check-suites + +```php +$params = [/*...*/]; +$check = $client->api('repo')->checkSuites()->updatePreferences('KnpLabs', 'php-github-api', $params); +``` + +### Get a check suite + +https://docs.github.com/en/rest/reference/checks#get-a-check-suite + +```php +$check = $client->api('repo')->checkSuites()->getCheckSuite('KnpLabs', 'php-github-api', $checkSuiteId); +``` + +### Rerequest a check suite + +https://docs.github.com/en/rest/reference/checks#rerequest-a-check-suite + +```php +$annotations = $client->api('repo')->checkSuites()->rerequest('KnpLabs', 'php-github-api', $checkSuiteId); +``` + + +### List check suites for a Git reference + +https://docs.github.com/en/rest/reference/checks#list-check-suites-for-a-git-reference + +```php +$params = [/*...*/]; +$checks = $client->api('repo')->checkSuites()->allForReference('KnpLabs', 'php-github-api', $reference, $params); +``` diff --git a/doc/repo/checks.md b/doc/repo/checks.md new file mode 100644 index 00000000000..f81f1f6f8f3 --- /dev/null +++ b/doc/repo/checks.md @@ -0,0 +1,62 @@ +## Repo / Checks API +[Back to the "Repos API"](../repos.md) | [Back to the navigation](../README.md) + +**This API class is deprecated use the [Check runs](check_runs.md) and the [Check suites](check_suites.md) api classes.** + +### Create a check for a commit + +[Visit GitHub for a full of list of parameters and their descriptions.](https://developer.github.com/v3/checks/runs/#create-a-check-run) + +```php +$params = [ + 'name' => 'my check', # required + 'head_sha' => $commitSha, # required + 'status' => 'pending', + 'details_url' => 'https://nimbleci.com/...', + 'output' => {...} +]; +$check = $client->api('repo')->checks()->create('NimbleCI', 'docker-web-tester-behat', $params); +``` + +### Update an existing check on a commit + +https://developer.github.com/v3/checks/runs/#update-a-check-run + +```php +$params = [ + 'name' => 'my check', + 'status' => 'pending', + 'details_url' => 'https://nimbleci.com/...', + 'output' => {...} +]; +$check = $client->api('repo')->checks()->create('NimbleCI', 'docker-web-tester-behat', $checkRunId, $params); +``` + +### List check runs for a Git reference + +https://developer.github.com/v3/checks/runs/#list-check-runs-for-a-git-reference + +```php +$params = [ + 'check_name' => 'my check', + 'status' => 'completed', + 'filter' => 'latest', +]; +$checks = $client->api('repo')->checks()->all('NimbleCI', 'docker-web-tester-behat', $ref, $params); +``` + +### Get a check run + +https://developer.github.com/v3/checks/runs/#get-a-check-run + +```php +$check = $client->api('repo')->checks()->show('NimbleCI', 'docker-web-tester-behat', $checkRunId); +``` + +### List check run annotations + +https://developer.github.com/v3/checks/runs/#list-check-run-annotations + +```php +$annotations = $client->api('repo')->checks()->annotations('NimbleCI', 'docker-web-tester-behat', $checkRunId); +``` diff --git a/doc/repo/contents.md b/doc/repo/contents.md new file mode 100644 index 00000000000..756a5785316 --- /dev/null +++ b/doc/repo/contents.md @@ -0,0 +1,61 @@ +## Repo / Contents API +[Back to the "Repos API"](../repos.md) | [Back to the navigation](../README.md) + +--- + +You can read about references [here](https://developer.github.com/v3/git/refs/). + + +### Get a repository's README + +```php +$readme = $client->api('repo')->contents()->readme('KnpLabs', 'php-github-api', $reference); +``` + +### Get information about a repository file or directory + +```php +$fileInfo = $client->api('repo')->contents()->show('KnpLabs', 'php-github-api', $path, $reference); +``` + +### Check that a file or directory exists in the repository +```php +$fileExists = $client->api('repo')->contents()->exists('KnpLabs', 'php-github-api', $path, $reference); +``` + +### Create a file +```php +$committer = array('name' => 'KnpLabs', 'email' => 'info@knplabs.com'); + +$fileInfo = $client->api('repo')->contents()->create('KnpLabs', 'php-github-api', $path, $content, $commitMessage, $branch, $committer); +``` + +### Update a file + +```php +$committer = array('name' => 'KnpLabs', 'email' => 'info@knplabs.com'); +$oldFile = $client->api('repo')->contents()->show('KnpLabs', 'php-github-api', $path, $branch); + +$fileInfo = $client->api('repo')->contents()->update('KnpLabs', 'php-github-api', $path, $content, $commitMessage, $oldFile['sha'], $branch, $committer); +``` + +### Remove a file + +```php +$committer = array('name' => 'KnpLabs', 'email' => 'info@knplabs.com'); +$oldFile = $client->api('repo')->contents()->show('KnpLabs', 'php-github-api', $path, $branch); + +$fileInfo = $client->api('repo')->contents()->rm('KnpLabs', 'php-github-api', $path, $commitMessage, $oldFile['sha'], $branch, $committer); +``` + +### Get repository archive + +```php +$archive = $client->api('repo')->contents()->archive('KnpLabs', 'php-github-api', $format, $reference); +``` + +### Download a file + +```php +$fileContent = $client->api('repo')->contents()->download('KnpLabs', 'php-github-api', $path, $reference); +``` diff --git a/doc/repo/deployments.md b/doc/repo/deployments.md new file mode 100644 index 00000000000..8c2ae1a8675 --- /dev/null +++ b/doc/repo/deployments.md @@ -0,0 +1,56 @@ +## Repo / Deployments API +[Back to the "Repos API"](../repos.md) | [Back to the navigation](../index.md) + +Provides information about deployments for a repository. Wraps [GitHub Deployments API](https://developer.github.com/v3/repos/deployments/). + +#### List all deployments. + +```php +$deployments = $client->api('deployment')->all('KnpLabs', 'php-github-api'); +``` + +You can also filter the returned results (see [the documentation](https://developer.github.com/v3/repos/deployments/#list-deployments) for more information): + +```php +$deployments = $client->api('deployment')->all('KnpLabs', 'php-github-api', array('environment' => 'production')); +``` + +### List one deployment. + +```php +$deployment = $client->api('deployment')->show('KnpLabs', 'php-github-api', $id); +``` + +#### Create a new deployment. + +The `ref` parameter is required. + +```php +$data = $client->api('deployment')->create('KnpLabs', 'php-github-api', array('ref' => 'fd6a5f9e5a430dddae8d6a8ea378f913d3a766f9')); +``` + +Please note that once a deployment is created it cannot be edited. Only status updates can be created. + +#### Delete a existing deployment. + +```php +$deployment = $client->api('deployment')->show('KnpLabs', 'php-github-api', $id); +``` + +Please note that a deployment can only be deleted when in inactive state. +Consider transitioning the status to `inactive` beforehand using `updateStatus`. + + +#### Create a new status update. + +The `state` parameter is required. At the time of writing, this must be pending, queued, in_progress, success, inactive, error, or failure. + +```php +$data = $client->api('deployment')->updateStatus('KnpLabs', 'php-github-api', 1, array('state' => 'error', 'description' => 'syntax error')); +``` + +#### Get all status updates for a deployment. + +```php +$statusUpdates = $client->api('deployment')->getStatuses('KnpLabs', 'php-github-api', 1); +``` diff --git a/doc/repo/deployments/environment/secrets.md b/doc/repo/deployments/environment/secrets.md new file mode 100644 index 00000000000..5c0c86b85d7 --- /dev/null +++ b/doc/repo/deployments/environment/secrets.md @@ -0,0 +1,46 @@ +## Environment / Secrets API +[Back to the "Environments API"](../environments.md) | [Back to the navigation](../README.md) + +### List environment secrets + +https://docs.github.com/en/rest/actions/secrets?apiVersion=2022-11-28 + +```php +$secrets = $client->environment()->secrets()->all($repoId, $envName); +``` + +### Get an environment secret + +https://docs.github.com/en/rest/actions/secrets?apiVersion=2022-11-28#get-an-environment-secret + +```php +$secret = $client->environment()->secrets()->show($repoId, $envName, $secretName); +``` + +### Create or Update an environment secret + +https://docs.github.com/en/rest/actions/secrets?apiVersion=2022-11-28#create-or-update-an-environment-secret + +```php +$client->environment()->secrets()->createOrUpdate($repoId, $envName, $secretName, [ + 'encrypted_value' => $encryptedValue, + 'key_id' => $key_id +]); +``` + +### Delete an environment secret + +https://docs.github.com/en/rest/reference/actions#delete-an-organization-secret + +```php +$client->environment()->secrets()->remove($repoId, $envName, $secretName); +``` + +### Get an environment public key + +https://docs.github.com/en/rest/reference/actions#get-an-organization-public-key + +```php +$client->environment()->secrets()->publicKey($repoId, $envName); +``` + diff --git a/doc/repo/deployments/environment/variables.md b/doc/repo/deployments/environment/variables.md new file mode 100644 index 00000000000..d645349a204 --- /dev/null +++ b/doc/repo/deployments/environment/variables.md @@ -0,0 +1,49 @@ +## Environment / Variables API +[Back to the "Environments API"](../environments.md) | [Back to the navigation](../README.md) + +### List environment variables + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#list-environment-variables + +```php +$variables = $client->environment()->variables()->all($repoId, $envName); +``` + +### Get an environment variable + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#get-an-environment-variable + +```php +$variable = $client->environment()->variables()->show($repoId, $envName, $variableName); +``` + +### Create environment variable + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#create-an-environment-variable + +```php +$client->environment()->variables()->create($repoId, $envName, [ + 'name' => $name, + 'value' => $value +]); +``` + +### Update environment variable + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#update-an-environment-variable + +```php +$client->environment()->variables()->update($repoId, $envName, $variableName, [ + 'name' => $name, + 'value' => $value +]); +``` + +### Delete an environment variable + +https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#delete-an-environment-variable + +```php +$client->environment()->variables()->remove($repoId, $envName, $variableName); +``` + diff --git a/doc/repo/deployments/environments.md b/doc/repo/deployments/environments.md new file mode 100644 index 00000000000..6cb409ae3b3 --- /dev/null +++ b/doc/repo/deployments/environments.md @@ -0,0 +1,32 @@ +## Deployment / Environments API +[Back to the "Deployment API"](../deployments.md) | [Back to the navigation](../index.md) + +Provides information about environments for a repository. Wraps [GitHub Environments API](https://docs.github.com/en/rest/deployments/environments?apiVersion=2022-11-28). + +Additional APIs: +* [Secrets API](environment/secrets.md) +* [Variables API](environment/variables.md) + +#### List all environments. + +```php +$environments = $client->deployment()->environment()->all('KnpLabs', 'php-github-api'); +``` + +### Get one environment. + +```php +$environment = $client->deployment()->environment()->show('KnpLabs', 'php-github-api', $name); +``` + +#### Create or update environment. + +```php +$data = $client->deployment()->environment()->createOrUpdate('KnpLabs', 'php-github-api', $name); +``` + +#### Delete a existing environment. + +```php +$environment = $client->deployment()->environment()->remove('KnpLabs', 'php-github-api', $name); +``` diff --git a/doc/repo/deployments/policies.md b/doc/repo/deployments/policies.md new file mode 100644 index 00000000000..442fc0c4acb --- /dev/null +++ b/doc/repo/deployments/policies.md @@ -0,0 +1,38 @@ +## Deployment / Branch policies API +[Back to the "Deployment API"](../deployments.md) | [Back to the navigation](../index.md) + +Provides information about deployment branch policies. Wraps [GitHub Deployment branch policies API](https://docs.github.com/en/rest/deployments/branch-policies?apiVersion=2022-11-28#about-deployment-branch-policies). + +#### List deployment branch policies. + +```php +$policies = $client->deployment()->policies()->all('KnpLabs', 'php-github-api', 'production'); +``` + +### Get one environment. + +```php +$policy = $client->deployment()->policies()->show('KnpLabs', 'php-github-api', 'production', $branchPolicyId); +``` + +#### Create policy. + +```php +$data = $client->deployment()->policies()->create('KnpLabs', 'php-github-api', 'production', [ + 'name' => 'name' +]); +``` + +#### Update policy. + +```php +$data = $client->deployment()->policies()->update('KnpLabs', 'php-github-api', 'production', $branchPolicyId, [ + 'name' => 'name' +]); +``` + +#### Delete a existing policy. + +```php +$policy = $client->deployment()->policies()->remove('KnpLabs', 'php-github-api', 'production', $branchPolicyId); +``` diff --git a/doc/repo/hooks.md b/doc/repo/hooks.md new file mode 100644 index 00000000000..a4f9d9af655 --- /dev/null +++ b/doc/repo/hooks.md @@ -0,0 +1,46 @@ +## Repo / Hooks API +[Back to the "Repos API"](../repos.md) | [Back to the navigation](../README.md) + +For extended info see the [GitHub documentation](https://docs.github.com/en/rest/reference/repos#webhooks) + +### List repository webhooks + +```php +$hooks = $client->api('repo')->hooks()->all('twbs', 'bootstrap'); +``` + +### Get a repository webhook + +```php +$hook = $client->api('repo')->hooks()->show('twbs', 'bootstrap', $hookId); +``` + +### Create a repository webhook + +```php +$client->api('repo')->hooks()->create('twbs', 'bootstrap', $parameters); +``` + +### Update a repository webhook + +```php +$client->api('repo')->hooks()->update('twbs', 'bootstrap', $hookId, $parameters); +``` + +### Delete a repository webhook + +```php +$client->api('repo')->hooks()->remove('twbs', 'bootstrap', $hookId); +``` + +### Ping a repository webhook + +```php +$client->api('repo')->hooks()->ping('twbs', 'bootstrap', $hookId); +``` + +### Test the push repository webhook + +```php +$client->api('repo')->hooks()->test('twbs', 'bootstrap', $hookId); +``` diff --git a/doc/repo/labels.md b/doc/repo/labels.md new file mode 100644 index 00000000000..5e924058f77 --- /dev/null +++ b/doc/repo/labels.md @@ -0,0 +1,48 @@ +## Repo / Labels API +[Back to the "Repos API"](../repos.md) | [Back to the navigation](../README.md) + +### List all labels for this repository + +```php +$labels = $client->api('repo')->labels()->all('twbs', 'bootstrap'); +``` + +### Get a single label + +```php +$label = $client->api('repo')->labels()->show('twbs', 'bootstrap', 'feature'); +``` + +### Create a label + +> Requires [authentication](../security.md). + +```php +$params = [ + 'name' => 'bug', + 'color' => 'f29513', + 'description' => 'Something isn\'t working', +]; +$label = $client->api('repo')->labels()->create('twbs', 'bootstrap', $params); +``` + +### Update a label + +> Requires [authentication](../security.md). + +```php +$params = [ + 'new_name' => 'bug :bug:', + 'color' => 'b01f26', + 'description' => 'Small bug fix required', +]; +$label = $client->api('repo')->labels()->update('twbs', 'bootstrap', 'bug', $params); +``` + +### Delete a label + +> Requires [authentication](../security.md). + +```php +$label = $client->api('repo')->labels()->remove('twbs', 'bootstrap', 'bug'); +``` diff --git a/doc/repo/protection.md b/doc/repo/protection.md new file mode 100644 index 00000000000..9ba596dca1a --- /dev/null +++ b/doc/repo/protection.md @@ -0,0 +1,273 @@ +## Repo / Protection API +[Back to the "Repos API"](../repos.md) | [Back to the navigation](../README.md) + +The Protection API is currently available for developers to preview. +To access the API during the preview period, you must provide a custom media type in the Accept header: + +```php +$client->api('repo')->protection()->configure(); +``` + +### List all branch protection + +> Requires [authentication](../security.md). + +```php +$protection = $client->api('repo')->protection()->show('twbs', 'bootstrap', 'master'); +``` + +### Update branch protection + +> Requires [authentication](../security.md). + +For the full list of parameters see https://developer.github.com/v3/repos/branches/#parameters-1 + +```php +$params = [ + 'required_status_checks' => null, + 'required_pull_request_reviews' => [ + 'include_admins' => true, + ], + 'enforce_admins' => true, + 'restrictions' => null, +]; +$protection = $client->api('repo')->protection()->update('twbs', 'bootstrap', 'master', $params); +``` + +### Remove branch protection + +> Requires [authentication](../security.md). + +```php +$protection = $client->api('repo')->protection()->remove('twbs', 'bootstrap', 'master'); +``` + +### Get required status checks of protected branch + +> Requires [authentication](../security.md). + +```php +$protection = $client->api('repo')->protection()->showStatusChecks('twbs', 'bootstrap', 'master'); +``` + +### Update required status checks of protected branch + +> Requires [authentication](../security.md). + +```php +$params = [ + 'strict' => true, + 'contexts' => [ + 'continuous-integration/travis-ci', + ], +]; +$protection = $client->api('repo')->protection()->updateStatusChecks('twbs', 'bootstrap', 'master', $params); +``` + +### Remove required status checks of protected branch + +> Requires [authentication](../security.md). + +```php +$protection = $client->api('repo')->protection()->removeStatusChecks('twbs', 'bootstrap', 'master'); +``` + +### List required status checks contexts of protected branch + +> Requires [authentication](../security.md). + +```php +$protection = $client->api('repo')->protection()->showStatusChecksContexts('twbs', 'bootstrap', 'master'); +``` + +### Replace required status checks contexts of protected branch + +> Requires [authentication](../security.md). + +```php +$params = [ + 'continuous-integration/travis-ci', +]; +$protection = $client->api('repo')->protection()->replaceStatusChecksContexts('twbs', 'bootstrap', 'master', $params); +``` + +### Add required status checks contexts of protected branch + +> Requires [authentication](../security.md). + +```php +$params = [ + 'continuous-integration/jenkins', +]; +$protection = $client->api('repo')->protection()->addStatusChecksContexts('twbs', 'bootstrap', 'master', $params); +``` + +### Remove required status checks contexts of protected branch + +> Requires [authentication](../security.md). + +```php +$params = [ + 'continuous-integration/jenkins', +]; +$protection = $client->api('repo')->protection()->removeStatusChecksContexts('twbs', 'bootstrap', 'master', $params); +``` + +### Get pull request review enforcement of protected branch + +> Requires [authentication](../security.md). + +```php +$protection = $client->api('repo')->protection()->showPullRequestReviewEnforcement('twbs', 'bootstrap', 'master'); +``` + +### Update pull request review enforcement of protected branch + +> Requires [authentication](../security.md) with admin access and branch protection to be enabled. + +```php +$params = [ + 'dismissal_restrictions' => [ + 'users' => [ + 'octocat', + ], + 'teams' => [ + 'justice-league', + ], + ], + 'dismiss_stale_reviews' => true, + 'require_code_owner_reviews' => true, +]; +$protection = $client->api('repo')->protection()->updatePullRequestReviewEnforcement('twbs', 'bootstrap', 'master', $params); +``` + +### Remove pull request review enforcement of protected branch + +> Requires [authentication](../security.md). + +```php +$protection = $client->api('repo')->protection()->removePullRequestReviewEnforcement('twbs', 'bootstrap', 'master'); +``` + +### Get admin enforcement of protected branch + + +> Requires [authentication](../security.md). + +```php +$protection = $client->api('repo')->protection()->showAdminEnforcement('twbs', 'bootstrap', 'master'); +``` + +### Add admin enforcement of protected branch + +> Requires [authentication](../security.md) with admin access and branch protection to be enabled. + +```php +$protection = $client->api('repo')->protection()->addAdminEnforcement('twbs', 'bootstrap', 'master'); +``` + +### Remove admin enforcement of protected branch + +> Requires [authentication](../security.md) with admin access and branch protection to be enabled. + +```php +$protection = $client->api('repo')->protection()->removeAdminEnforcement('twbs', 'bootstrap', 'master'); +``` + +### Get restrictions of protected branch + +> Requires [authentication](../security.md) and is only available for organization-owned repositories. + +```php +$protection = $client->api('repo')->protection()->showRestrictions('twbs', 'bootstrap', 'master'); +``` + +### Remove restrictions of protected branch + +> Requires [authentication](../security.md) and is only available for organization-owned repositories. + +```php +$protection = $client->api('repo')->protection()->removeRestrictions('twbs', 'bootstrap', 'master'); +``` + +### List team restrictions of protected branch + +> Requires [authentication](../security.md) and is only available for organization-owned repositories. + +```php +$protection = $client->api('repo')->protection()->showTeamRestrictions('twbs', 'bootstrap', 'master'); +``` + +### Replace team restrictions of protected branch + +> Requires [authentication](../security.md) and is only available for organization-owned repositories. + +```php +$params = [ + 'justice-league', +]; +$protection = $client->api('repo')->protection()->replaceTeamRestrictions('twbs', 'bootstrap', 'master', $params); +``` + +### Add team restrictions of protected branch + +> Requires [authentication](../security.md) and is only available for organization-owned repositories. + +```php +$params = [ + 'justice-league', +]; +$protection = $client->api('repo')->protection()->addTeamRestrictions('twbs', 'bootstrap', 'master', $params); +``` + +### Remove team restrictions of protected branch + +> Requires [authentication](../security.md) and is only available for organization-owned repositories. + +```php +$params = [ + 'octocats', +]; +$protection = $client->api('repo')->protection()->removeTeamRestrictions('twbs', 'bootstrap', 'master', $params); +``` + +### List user restrictions of protected branch + +> Requires [authentication](../security.md) and is only available for organization-owned repositories. + +```php +$protection = $client->api('repo')->protection()->showUserRestrictions('twbs', 'bootstrap', 'master'); +``` + +### Replace user restrictions of protected branch + +> Requires [authentication](../security.md) and is only available for organization-owned repositories. + +```php +$params = [ + 'octocat', +]; +$protection = $client->api('repo')->protection()->replaceUserRestrictions('twbs', 'bootstrap', 'master', $params); +``` + +### Add user restrictions of protected branch + +> Requires [authentication](../security.md) and is only available for organization-owned repositories. + +```php +$params = [ + 'octocat', +]; +$protection = $client->api('repo')->protection()->addUserRestrictions('twbs', 'bootstrap', 'master', $params); +``` + +### Remove user restrictions of protected branch + +> Requires [authentication](../security.md) and is only available for organization-owned repositories. + +```php +$params = [ + 'defunkt', +]; +$protection = $client->api('repo')->protection()->removeUserRestrictions('twbs', 'bootstrap', 'master', $params); +``` diff --git a/doc/repo/releases.md b/doc/repo/releases.md index cfbf5721338..1b433a5f6ab 100644 --- a/doc/repo/releases.md +++ b/doc/repo/releases.md @@ -1,8 +1,28 @@ ## Repo / Releases API -[Back to the "Repos API"](../repos.md) | [Back to the navigation](../index.md) +[Back to the "Repos API"](../repos.md) | [Back to the navigation](../README.md) -This Github API Endpoint is currently undocumented because it's new, but works just fine. +Provides information about releases for a repository. Wraps [GitHub Releases API](https://developer.github.com/v3/repos/releases/). +### Get latest actual release + +```php +$release = $client->api('repo')->releases()->latest('twbs', 'bootstrap'); +``` + +The `latest()` method fetches only releases which are not marked "prerelease" or "draft". + +To obtain the latest release *including* prereleases and drafts, select the first element in the "all releases" function: +```php +$release = $client->api('repo')->releases()->all('username', 'repo')[0]; +``` + +Note: Draft releases are only visible to authenticated users who have push access to the repository. + +### List releases for a tag + +```php +$release = $client->api('repo')->releases()->tag('twbs', 'bootstrap', 'd890eec'); +``` ### List all releases diff --git a/doc/repo/secret-scanning.md b/doc/repo/secret-scanning.md new file mode 100644 index 00000000000..18f3ef20b28 --- /dev/null +++ b/doc/repo/secret-scanning.md @@ -0,0 +1,37 @@ +## Repository / Secret Scanning API +[Back to the "Repos API"](../../repos.md) | [Back to the navigation](../../README.md) + +# List secret-scanning alerts for a repository + +https://docs.github.com/en/enterprise-server@3.5/rest/secret-scanning#list-secret-scanning-alerts-for-a-repository + +```php +$alerts = $client->api('repos')->secretScanning()->alerts('KnpLabs', 'php-github-api'); +``` + +# Get a secret-scanning alert + +https://docs.github.com/en/enterprise-server@3.5/rest/secret-scanning#get-a-secret-scanning-alert + +```php +$alert = $client->api('repos')->secretScanning()->getAlert('KnpLabs', 'php-github-api', $alertNumber); +``` + +# Update a secret-scanning alert + +https://docs.github.com/en/enterprise-server@3.5/rest/secret-scanning#update-a-secret-scanning-alert + +```php +$client->api('repos')->secretScanning()->updateAlert('KnpLabs', 'php-github-api', $alertNumber, [ + 'state' => 'resolved', + 'resolution' => 'wont-fix' +]); +``` + +# List Locations for a secret-scanning alert + +https://docs.github.com/en/enterprise-server@3.5/rest/secret-scanning#list-locations-for-a-secret-scanning-alert + +```php +$locations = $client->api('repos')->secretScanning()->locations('KnpLabs', 'php-github-api', $alertNumber); +``` diff --git a/doc/repo/stargazers.md b/doc/repo/stargazers.md new file mode 100644 index 00000000000..003f2ad8d71 --- /dev/null +++ b/doc/repo/stargazers.md @@ -0,0 +1,10 @@ +## Repo / Stargazers API +[Back to the "Repos API"](../repos.md) | [Back to the navigation](../README.md) + +### List all stargazers + +```php +$stargazers = $client->api('repo')->stargazers(); + +$stargazers->all('twbs', 'bootstrap'); +``` diff --git a/doc/repo/statuses.md b/doc/repo/statuses.md new file mode 100644 index 00000000000..4f4378c2b54 --- /dev/null +++ b/doc/repo/statuses.md @@ -0,0 +1,28 @@ +## Repo / Statuses API +[Back to the "Repos API"](../repos.md) | [Back to the navigation](../README.md) + +### List all statuses for a commit + +```php +$statuses = $client->api('repo')->statuses()->show('NimbleCI', 'docker-web-tester-behat', $commitSha); +``` + +### Get the combined statuses for a commit + +```php +$statuses = $client->api('repo')->statuses()->combined('NimbleCI', 'docker-web-tester-behat', $commitSha); +``` + +### Create a status for a commit + +For the full list of parameters see https://developer.github.com/v3/repos/statuses/#parameters + +```php +$params = [ + 'state' => 'pending', # The 'state' element is required + 'target_url' => 'https://nimbleci.com/...', + 'description' => 'A great description...', + 'context' => 'my-context', +]; +$statuses = $client->api('repo')->statuses()->create('NimbleCI', 'docker-web-tester-behat', $commitSha, $params); +``` diff --git a/doc/repo/tags.md b/doc/repo/tags.md new file mode 100644 index 00000000000..95e35bb0665 --- /dev/null +++ b/doc/repo/tags.md @@ -0,0 +1,8 @@ +## Repo / Tags API +[Back to the "Repos API"](../repos.md) | [Back to the navigation](../README.md) + +### List all tags + +```php +$tags = $client->api('repo')->tags('twbs', 'bootstrap'); +``` diff --git a/doc/repos.md b/doc/repos.md index fd8601a3b9e..d7c30d490f4 100644 --- a/doc/repos.md +++ b/doc/repos.md @@ -1,9 +1,23 @@ ## Repositories API -[Back to the navigation](index.md) +[Back to the navigation](README.md) Searching repositories, getting repository information and managing repository information for authenticated users. Wrap [GitHub Repo API](http://developer.github.com/v3/repos/). All methods are described on that page. +### List all repositories + +#### Simple call + +```php +$repos = $client->api('repo')->all(); +``` + +#### Start from a specific repository id + +```php +$repos = $client->api('repo')->all(1337); +``` + ### Search repos by keyword #### Simple search @@ -13,10 +27,9 @@ $repos = $client->api('repo')->find('symfony'); ``` Returns a list of repositories. - #### Advanced search -You can filter the results by language. It takes the same values as the language drop down on [http://github.com/search](http://github). +You can filter the results by language. It takes the same values as the language drop down on [http://github.com/search](http://github.com/search). ```php $repos = $client->api('repo')->find('chess', array('language' => 'php')); @@ -30,10 +43,18 @@ $repos = $client->api('repo')->find('chess', array('language' => 'php', 'start_p ### Get extended information about a repository +Using the username of the repository owner and the repository name: + ```php $repo = $client->api('repo')->show('KnpLabs', 'php-github-api') ``` +Or by using the repository id (note that this is at time of writing an undocumented feature, see [here](https://github.com/piotrmurach/github/issues/283) and [here](https://github.com/piotrmurach/github/issues/282)): + +```php +$repo = $client->api('repo')->showById(123456) +``` + Returns an array of information about the specified repository. ### Get the repositories of a specific user @@ -76,7 +97,7 @@ Updates and returns the repository named 'my-new-repo' that is owned by 'usernam > Requires [authentication](security.md). ```php -$client->api('repo')->delete('username', 'my-new-repo'); // Get the deletion token +$client->api('repo')->remove('username', 'my-new-repo'); // Get the deletion token ``` Deletes the my-new-repo repository. @@ -122,6 +143,30 @@ $client->api('repo')->keys()->remove('username', 'reponame', 12345); Removes the key with id 12345 from the 'reponame' repository and returns a list of the deploy keys for the repository. +### Add a hook to a repository + +> Requires [authentication](security.md). + +```php +$client->api('repo')->hooks()->create('username', 'reponame', $params); +``` + +### Remove a hook from a repository + +> Requires [authentication](security.md). + +```php +$client->api('repo')->hooks()->remove('username', 'reponame', $id); +``` + +### Return a list of all hooks for the 'reponame' repository + +> Requires [authentication](security.md). + +```php +$client->api('repo')->hooks()->all('username', 'reponame'); +``` + ### Get the collaborators for a repository ```php @@ -133,20 +178,29 @@ Returns a list of the collaborators for the 'reponame' repository. ### Add a collaborator to a repository ```php -$client->api('repo')->collaborators()->add('username', 'reponame', 'KnpLabs'); +$client->api('repo')->collaborators()->add('username', 'reponame', 'collaborator'); ``` -Adds the 'username' user as collaborator to the 'reponame' repository. +Adds the 'collaborator' user as collaborator to the 'reponame' repository. ### Remove a collaborator from a repository > Requires [authentication](security.md). ```php -$client->api('repo')->collaborators()->remove('username', 'reponame', 'KnpLabs'); +$client->api('repo')->collaborators()->remove('username', 'reponame', 'collaborator'); +``` + +Remove the 'collaborator' collaborator from the 'reponame' repository. + +### Get the permissions of a collaborator for a repository + +```php +$permissions = $client->api('repo')->collaborators()->permission('username', 'reponame', 'collaborator'); ``` -Remove the 'username' collaborator from the 'reponame' repository. +Returns the permissions of 'collaborator' collaborator for the 'reponame' repository. + ### Watch and unwatch a repository @@ -169,6 +223,15 @@ $repository = $client->api('repo')->forks()->create('ornicar', 'php-github-api') Creates a fork of the 'php-github-api' owned by 'ornicar' and returns the newly created repository. +### Merge upstream repository + +> Requires [authentication](security.md). + +```php +$repository = $client->api('repo')->mergeUpstream('ornicar', 'php-github-api', 'branchName'); +``` +Merge upstream a branch of a forked repository to keep it up-to-date with the upstream repository. + ### Get the tags of a repository ```php @@ -212,11 +275,27 @@ Returns list of the forks of the 'php-github-api' owned by 'ornicar', including ### Get the languages for a repository ```php -$contributors = $client->api('repo')->languages('ornicar', 'php-github-api'); +$languages = $client->api('repo')->languages('ornicar', 'php-github-api'); ``` Returns a list of languages. +### Enable automated security fixes + +https://docs.github.com/en/rest/reference/repos#enable-automated-security-fixes + +```php +$client->api('repo')->enableAutomatedSecurityFixes('KnpLabs', 'php-github-api'); +``` + +### Disable automated security fixes + +https://docs.github.com/en/rest/reference/repos#disable-automated-security-fixes + +```php +$client->api('repo')->disableAutomatedSecurityFixes('KnpLabs', 'php-github-api'); +``` + ### Get the contributors of a repository ```php @@ -230,3 +309,108 @@ To include non GitHub users, add a third parameter to true: ```php $contributors = $client->api('repo')->contributors('ornicar', 'php-github-api', true); ``` + +### Get the commit activity of a repository + +```php +$activity = $client->api('repo')->activity('ornicar', 'php-github-api'); +``` + +Returns an array of commit activity group by week. + +### `Moved` repositories +GitHub repositories can be moved to another org/user, but it remains the `id`. +In case you can't find the repo anymore, you can retrieve it by `id`: + +```php +use Github\HttpClient\Message\ResponseMediator; + +$data = $client->getHttpClient()->get('/repositories/24560307'); +$repo = ResponseMediator::getContent($data); +``` + +### Get the milestones of a repository + +```php +$milestones = $client->api('repo')->milestones('ornicar', 'php-github-api'); +``` + +Returns a list of milestones. + +### Get the community profile metrics for a repository + +```php +$communityProfile = $client->api('repo')->communityProfile('ornicar', 'php-github-api'); +``` + +### Get the contents of a repository's code of conduct + +```php +$codeOfConduct = $client->api('repo')->codeOfConduct('ornicar', 'php-github-api'); +``` + +### List all topics for a repository + +```php +$topics = $client->api('repo')->topics('ornicar', 'php-github-api'); +``` + +### Replace all topics for a repository + +```php +$currentTopics = $client->api('repo')->replaceTopics('ornicar', 'php-github-api', ['new', 'topics']); +``` + +### Transfer a repo to another user + +```php +$repo = $client->api('repo')->transfer('KnpLabs', 'php-github-api', 'github'); +``` +You can optionally assign some teams by passing an array with their ID's if you're transferring the repo to an organization: + +```php +$repo = $client->api('repo')->transfer('KnpLabs', 'php-github-api', 'github', [1234]); +``` + +### Create a repository dispatch event + +Example when you want to configure custom GitHub action workflows. + +```php +$client->api('repo')->dispatch('KnpLabs', 'php-github-api', 'acme-event', ['foo'=>'bar']); +``` + +### Create a repository using a template + +Create a new repository using a repository template. + +```php +$client->api('repo')->createFromTemplate('template-owner', 'template-repo', [ + 'name' => 'name-of-new-repo', + 'owner' => 'name-of-new-repo-owner', // can be user or org +]); +``` + +### Check if vulnerability alerts (dependabot alerts) are enabled for a repository + +https://developer.github.com/v3/repos/#check-if-vulnerability-alerts-are-enabled-for-a-repository + +```php +$client->api('repo')->isVulnerabilityAlertsEnabled('KnpLabs', 'php-github-api'); +``` + +### Enable vulnerability alerts (dependabot alerts) + +https://developer.github.com/v3/repos/#enable-vulnerability-alerts + +```php +$client->api('repo')->enableVulnerabilityAlerts('KnpLabs', 'php-github-api'); +``` + +### Disable vulnerability alerts (dependabot alerts) + +https://developer.github.com/v3/repos/#disable-vulnerability-alerts + +```php +$client->api('repo')->disableVulnerabilityAlerts('KnpLabs', 'php-github-api'); +``` diff --git a/doc/request_any_route.md b/doc/request_any_route.md index 1465ff7934d..76680fe857f 100644 --- a/doc/request_any_route.md +++ b/doc/request_any_route.md @@ -1,5 +1,5 @@ ## Request any Route -[Back to the navigation](index.md) +[Back to the navigation](README.md) The method you need does not exist yet? You can access any GitHub route by using the "get" and "post" methods. For example: diff --git a/doc/request_response_info.md b/doc/request_response_info.md new file mode 100644 index 00000000000..32e30981ea4 --- /dev/null +++ b/doc/request_response_info.md @@ -0,0 +1,14 @@ +## Request / Response information +[Back to the navigation](README.md) + +### Get response headers + +Get the response header for the latest request + +``` +$headers = $githubClient->getLastResponse()->getHeaders(); +//Example headers +$headers['X-RateLimit-Remaining']; +$headers['X-OAuth-Scopes']; +$headers['X-Accepted-OAuth-Scopes']; +``` diff --git a/doc/result_pager.md b/doc/result_pager.md index 52ac2993696..f074f1cc4a1 100644 --- a/doc/result_pager.md +++ b/doc/result_pager.md @@ -1,9 +1,9 @@ ## Result Pager -[Back to the navigation](index.md) +[Back to the navigation](README.md) ### Usage examples -Get all repositories of a organization +#### Get all repositories of an organization ```php $client = new Github\Client(); @@ -15,7 +15,20 @@ $parameters = array('github'); $result = $paginator->fetchAll($organizationApi, 'repositories', $parameters); ``` -Get the first page +Parameters of the `fetchAll` method: + +* The API object you're working with +* The method of the API object you're using +* The parameters of the method + +Parameters are passed to the API method via [call_user_func_array](https://www.php.net/manual/en/function.call-user-func-array.php). + +```php +$parameters = array('github', 'all', 1); // $organization, $type, $page +``` + +#### Get the first page + ```php $client = new Github\Client(); @@ -26,27 +39,27 @@ $parameters = array('github'); $result = $paginator->fetch($organizationApi, 'repositories', $parameters); ``` -Check for a next page: +#### Check for a next page: + ```php $paginator->hasNext(); ``` -Get next page: +#### Get next page: + ```php $paginator->fetchNext(); ``` -Check for previous page: +#### Check for previous page: + ```php $paginator->hasPrevious(); ``` -Get previous page: +#### Get previous page: + ```php $paginator->fetchPrevious(); ``` -If you want to retrieve the pagination links (available after the call to fetch): -```php -$paginator->getPagination(); -``` diff --git a/doc/search.md b/doc/search.md new file mode 100644 index 00000000000..24dbbef2302 --- /dev/null +++ b/doc/search.md @@ -0,0 +1,61 @@ +## Search API +[Back to the navigation](README.md) + +Searching repositories, code, issues and users. +Wrap [GitHub Search API](http://developer.github.com/v3/search/). All methods are described on that page. + +### Search repositories + +```php +$repos = $client->api('search')->repositories('github language:php'); +``` + +Returns a list of repositories found by such criteria. + +### Search code + +```php +$files = $client->api('search')->code('@todo language:php'); +``` + +Returns a list of files found by such criteria (containing "@todo" and language==php). + +```php +$files = $client->api('search')->codeWithMatch('@todo language:php'); +``` + +Same as code, with additional data to highlight the matching fragments (see [Text match metadata](https://docs.github.com/en/rest/reference/search#text-match-metadata)). + +### Search issues + +```php +$issues = $client->api('search')->issues('bug language:php'); +``` + +Returns a list of issues found by such criteria. + +### Search users + +```php +$users = $client->api('search')->users('location:Amsterdam language:php'); +``` + +### Search commits + +```php +$commits = $client->api('search')->commits('repo:octocat/Spoon-Knife+css'); +``` + +Returns a list of users found by such criteria. + +### Sorting results + +You can sort results using 2-3 arguments. + +```php +$repos = $client->api('search')->repositories('...', 'created', 'asc'); +$files = $client->api('search')->code('...........', 'indexed', 'desc'); +$issues = $client->api('search')->issues('.........', 'comments', 'asc'); +$users = $client->api('search')->users('..........', 'followers', 'asc'); +$commits = $client->api('search')->commits('..........', 'author-date', 'desc'); +``` diff --git a/doc/security.md b/doc/security.md index 4d74fcb9aa2..a8596de20b1 100644 --- a/doc/security.md +++ b/doc/security.md @@ -1,12 +1,13 @@ ## Authentication & Security -[Back to the navigation](index.md) +[Back to the navigation](README.md) Most GitHub services do not require authentication, but some do. For example the methods that allow you to change properties on Repositories and some others. Therefore this step is facultative. ### Authenticate -GitHub provides some different ways of authentication. This API implementation implements three of them which are handled by one function: +GitHub provides some different ways of authentication. This API implementation implements three of them which are +handled by one function: ```php $client->authenticate($usernameOrToken, $password, $method); @@ -15,27 +16,56 @@ $client->authenticate($usernameOrToken, $password, $method); `$usernameOrToken` is, of course, the username (or in some cases token/client ID, more details you can find below), and guess what should contain `$password`. The `$method` can contain one of the three allowed values: -* `Github\Client::AUTH_URL_TOKEN` -* `Github\Client::AUTH_URL_CLIENT_ID` -* `Github\Client::AUTH_HTTP_TOKEN` -* `Github\Client::AUTH_HTTP_PASSWORD` +#### Supported methods +* `Github\AuthMethod::CLIENT_ID` - https://developer.github.com/v3/#oauth2-keysecret +* `Github\AuthMethod::ACCESS_TOKEN` - https://developer.github.com/v3/#oauth2-token-sent-in-a-header +* `Github\AuthMethod::JWT` - https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/#authenticating-as-a-github-app -The required value of `$password` depends on the chosen `$method`. For the `Github\Client::AUTH_*_TOKEN` methods, -you should provide the API token in `$username` variable (`$password` is omitted in this particular case). For the -`Github\Client::AUTH_HTTP_PASSWORD`, you should provide the password of the account. When using `Github\Client::AUTH_URL_CLIENT_ID` -`$usernameOrToken` should contain your client ID, and `$password` should contain client secret. +The required value of `$password` depends on the chosen `$method`. For `Github\AuthMethod::CLIENT_ID`, `Github\AuthMethod::ACCESS_TOKEN` and +`Github\AuthMethod::JWT` methods you should provide the API token in `$usernameOrToken` variable (`$password` is omitted in +this particular case). -After executing the `$client->authenticate($usernameOrToken, $secret, $method);` method using correct credentials, -all further requests are done as the given user. +The `Github\AuthMethod::JWT` authentication method sends the specified JSON Web Token in an Authorization header. -### About authentication methods +After executing the `$client->authenticate($usernameOrToken, $secret, $method);` method using correct credentials, all +further requests are done as the given user. -The `Github\Client::AUTH_URL_TOKEN` authentication method sends the API token in URL parameters. -The `Github\Client::AUTH_URL_CLIENT_ID` authentication method sends the client ID and secret in URL parameters. -The `Github_Client::AUTH_HTTP_*` authentication methods send their values to GitHub using HTTP Basic Authentication. +### Authenticating as an Integration -`Github\Client::AUTH_URL_TOKEN` used to be the only available authentication method. To prevent existing applications -from changing their behavior in case of an API upgrade, this method is chosen as the default for this API implementation. +To authenticate as an integration you need to supply a JSON Web Token with `Github\AuthMethod::JWT` to request +and installation access token which is then usable with `Github\AuthMethod::ACCESS_TOKEN`. [GitHub´s integration +authentication docs](https://developer.github.com/apps/building-github-apps/authentication-options-for-github-apps/#authenticating-as-a-github-app) describe the flow in detail. +It´s important for integration requests to use the custom Accept header `application/vnd.github.machine-man-preview`. -Note however that GitHub describes this method as deprecated. In most case you should use the -`Github\Client::AUTH_HTTP_TOKEN` instead. +The following sample code authenticates as an installation using [lcobucci/jwt 4.1](https://github.com/lcobucci/jwt/tree/4.1.x) +to generate a JSON Web Token (JWT). + +```php +use Github\HttpClient\Builder; +use Lcobucci\JWT\Configuration; +use Lcobucci\JWT\Encoding\ChainedFormatter; +use Lcobucci\JWT\Signer\Key\LocalFileReference; +use Lcobucci\JWT\Signer\Rsa\Sha256; + +$builder = new Builder(); + +$github = new Github\Client($builder, 'machine-man-preview'); + +$config = Configuration::forSymmetricSigner( + new Sha256(), + LocalFileReference::file('path/to/integration.private-key.pem') +); + +$now = new \DateTimeImmutable(); +$jwt = $config->builder(ChainedFormatter::withUnixTimestampDates()) + ->issuedBy($integrationId) + ->issuedAt($now) + ->expiresAt($now->modify('+1 minute')) + ->getToken($config->signer(), $config->signingKey()) +; + +$github->authenticate($jwt->toString(), null, Github\AuthMethod::JWT); +``` + +The `$integrationId` you can find in the about section of your GitHub app. +The `$installationId` you can find by installing the app and using the id in the url. diff --git a/doc/testing.md b/doc/testing.md new file mode 100644 index 00000000000..36df32097eb --- /dev/null +++ b/doc/testing.md @@ -0,0 +1,73 @@ +## Running and writing tests +[Back to the navigation](README.md) + + +### Run Test Suite + +The code is unit tested, there are also some functional tests. To run tests on +your machine, from a CLI, run + +```bash +$ composer update +$ phpunit +``` + +### Write tests + +It is always great if someone wants to contribute and extend the functionality of +the API client. But all new features must be properly tested. To test a new API +function, one should test its communication with the HTTP client. The code should +never make an actual call to GitHub. Testing could easily be done with mocking. + +If you want to write test for the function that shows you comments to a gist. + +```php +class Comments extends AbstractApi +{ + // ... + public function show($gist, $comment) + { + return $this->get('/gists/'.rawurlencode($gist).'/comments/'.rawurlencode($comment)); + } +} +``` + +The test will look like this: + +```php +use Github\Tests\Api\TestCase; + +class CommentsTest extends TestCase +{ + // ... + + /** + * @test + */ + public function shouldShowGistComment() + { + // Create a variable with the "Server response". + $expectedValue = array('comment1'); + + // Get the API mock (see "getApiClass" below). + $api = $this->getApiMock(); + + $api->expects($this->once()) // Expect one call + ->method('get') // A GET request + ->with('/gists/123/comments/456') // URI should be "/gists/123/comments/456" + ->will($this->returnValue($expectedValue)); // Should return the "Server response" + + // Call Comments::show + $result = $api->show(123, 456); + + // Verify that the result is the "Server response" as we expect. + $this->assertEquals($expectedValue, $result); + } + + protected function getApiClass() + { + // Tell the "getAPIMock" what class to mock. + return \Github\Api\Gist\Comments::class; + } +} +``` diff --git a/doc/user/migration.md b/doc/user/migration.md new file mode 100644 index 00000000000..a2c3eb14c5e --- /dev/null +++ b/doc/user/migration.md @@ -0,0 +1,79 @@ +## User / Migrations API +[Back to the "Users API"](../../users.md) | [Back to the navigation](../../README.md) + +# List user migrations + +https://docs.github.com/en/rest/migrations/users?apiVersion=2022-11-28#list-user-migrations + +```php +$api = $github->api('user')->migration(); +$paginator = new Github\ResultPager($github); +$parameters = []; +$migrations = $paginator->fetchAll($api, 'list', $parameters); + +do { + foreach ($migrations as $migration) { + // do something + } + $migrations = $paginator->fetchNext(); +} +while($paginator->hasNext()); +``` + +# Start a User Migration + +https://docs.github.com/en/rest/migrations/users?apiVersion=2022-11-28#start-a-user-migration + +```php +$client->users()->migration()->start([ + 'repositories' => [ + 'KnpLabs/php-github-api' + ], + 'lock_repositories' => true, + 'exclude_metadata' => false, + 'exclude_git_data' => false, + 'exclude_attachments' => true, + 'exclude_releases' => false, + 'exclude_owner_projects' => true, + 'org_metadata_only' => false, + 'exclude' => [ + 'Exclude attributes from the API response to improve performance' + ] +]); +``` + +# Get a User Migration Status + +https://docs.github.com/en/rest/migrations/users?apiVersion=2022-11-28#get-a-user-migration-status + +```php +$status = $client->user()->migration()->status(12, [ + 'exclude' => [ + 'exclude attributes' + ] +]); +``` + +# Delete a User Migration Archive + +https://docs.github.com/en/rest/migrations/users?apiVersion=2022-11-28#delete-a-user-migration-archive + +```php +$client->user()->migration()->deleteArchive(12); +``` + +# Unlock a User Repository + +https://docs.github.com/en/rest/migrations/users?apiVersion=2022-11-28#unlock-a-user-repository + +```php +$client->user()->migration()->unlockRepo(12, 'php-github-api'); +``` + +# List repositories for a User Migration + +https://docs.github.com/en/rest/migrations/users?apiVersion=2022-11-28#list-repositories-for-a-user-migration + +```php +$repos = $client->user()->migration()->repos(2); +``` diff --git a/doc/users.md b/doc/users.md index b0cc072bbbf..48bb0d7dc15 100644 --- a/doc/users.md +++ b/doc/users.md @@ -1,16 +1,28 @@ ## Users API -[Back to the navigation](index.md) +[Back to the navigation](README.md) Searching users, getting user information and managing authenticated user account information. Wrap [GitHub User API](http://developer.github.com/v3/users/). ### Search for users by keyword +Use the [Search API](https://github.com/KnpLabs/php-github-api/blob/master/doc/search.md#search-users) to find users by keyword. + +### Lists all users, in the order they signed up, since the last user you've seen + +```php +$users = $client->api('user')->all(135); +``` + +Returns an array of all users that registered after the user whose ID is 135. + +### Lists all users, in the order they signed up + ```php -$users = $client->api('user')->find('KnpLabs'); +$users = $client->api('user')->all(); ``` -Returns an array of found users. +Returns an array of all users. ### Get information about a user @@ -20,7 +32,14 @@ $user = $client->api('user')->show('KnpLabs'); Returns an array of information about the user. -### Update user informations + +You can also use the User ID, but it will use an undocumented GitHub API + +```php +$user = $client->api('user')->showById(202732); +``` + +### Update user information > Requires [authentication](security.md). @@ -79,7 +98,7 @@ $client->api('current_user')->follow()->follow('symfony'); Returns an array of followed users. -### Unfollow a +### Unfollow a user > Requires [authentication](security.md). @@ -92,6 +111,7 @@ $client->api('current_user')->follow()->unfollow('symfony'); Returns an array of followed users. ### Get repos that a specific user is watching +> See [more](activity.md). ```php $users = $client->api('user')->watched('ornicar'); @@ -102,11 +122,39 @@ For authenticated user use. > Requires [authentication](security.md). ```php -$users = $client->api('current_user')->watched(); +$users = $client->api('current_user')->watchers()->all(); ``` Returns an array of watched repos. +### Get repos that a specific user has starred +> See [more](activity.md). + +```php +$users = $client->api('user')->starred('ornicar'); +``` + +For authenticated user use. + +> Requires [authentication](security.md). + +```php +$users = $client->api('current_user')->starring()->all(); +``` + +Returns an array of starred repos. + +### Get the authenticated user activity + +> Requires [authentication](security.md). + +```php +$activity = $client->api('user')->events('ornicar'); +``` + +Returns an array of private and public events created for all repos related to the user. +> See [more](activity.md). + ### Get the authenticated user emails > Requires [authentication](security.md). diff --git a/lib/Github/Api/AbstractApi.php b/lib/Github/Api/AbstractApi.php index 7ef6e6cf353..71f71cce5d6 100644 --- a/lib/Github/Api/AbstractApi.php +++ b/lib/Github/Api/AbstractApi.php @@ -4,87 +4,124 @@ use Github\Client; use Github\HttpClient\Message\ResponseMediator; +use Psr\Http\Message\ResponseInterface; /** - * Abstract class for Api classes - * * @author Joseph Bielawski + * @author Graham Campbell */ -abstract class AbstractApi implements ApiInterface +abstract class AbstractApi { /** - * The client + * The client instance. * * @var Client */ - protected $client; + private $client; /** - * number of items per page (GitHub pagination) + * The per page parameter. It is used by the ResultPager. * - * @var null|int + * @var int|null */ - protected $perPage; + private $perPage; /** + * Create a new API instance. + * * @param Client $client + * + * @return void */ public function __construct(Client $client) { $this->client = $client; } - public function configure() + /** + * Get the client instance. + * + * @return Client + */ + protected function getClient(): Client { + return $this->client; } /** - * @return null|int + * Get the API version. + * + * @return string */ - public function getPerPage() + protected function getApiVersion(): string { - return $this->perPage; + return $this->client->getApiVersion(); } /** - * @param null|int $perPage + * @return $this */ - public function setPerPage($perPage) + public function configure() { - $this->perPage = (null === $perPage ? $perPage : (int) $perPage); - return $this; } /** * Send a GET request with query parameters. * - * @param string $path Request path. - * @param array $parameters GET parameters. - * @param array $requestHeaders Request Headers. - * @return \Guzzle\Http\EntityBodyInterface|mixed|string + * @param string $path Request path. + * @param array $parameters GET parameters. + * @param array $requestHeaders Request Headers. + * + * @return array|string */ - protected function get($path, array $parameters = array(), $requestHeaders = array()) + protected function get(string $path, array $parameters = [], array $requestHeaders = []) { if (null !== $this->perPage && !isset($parameters['per_page'])) { $parameters['per_page'] = $this->perPage; } - if (array_key_exists('ref', $parameters) && is_null($parameters['ref'])) { + + if (array_key_exists('ref', $parameters) && null === $parameters['ref']) { unset($parameters['ref']); } - $response = $this->client->getHttpClient()->get($path, $parameters, $requestHeaders); + + if (count($parameters) > 0) { + $path .= '?'.http_build_query($parameters, '', '&', PHP_QUERY_RFC3986); + } + + $response = $this->client->getHttpClient()->get($path, $requestHeaders); return ResponseMediator::getContent($response); } + /** + * Send a HEAD request with query parameters. + * + * @param string $path Request path. + * @param array $parameters HEAD parameters. + * @param array $requestHeaders Request headers. + * + * @return ResponseInterface + */ + protected function head(string $path, array $parameters = [], array $requestHeaders = []): ResponseInterface + { + if (array_key_exists('ref', $parameters) && null === $parameters['ref']) { + unset($parameters['ref']); + } + + return $this->client->getHttpClient()->head($path.'?'.http_build_query($parameters, '', '&', PHP_QUERY_RFC3986), $requestHeaders); + } + /** * Send a POST request with JSON-encoded parameters. * - * @param string $path Request path. - * @param array $parameters POST parameters to be JSON encoded. - * @param array $requestHeaders Request headers. + * @param string $path Request path. + * @param array $parameters POST parameters to be JSON encoded. + * @param array $requestHeaders Request headers. + * + * @return array|string */ - protected function post($path, array $parameters = array(), $requestHeaders = array()) + protected function post(string $path, array $parameters = [], array $requestHeaders = []) { return $this->postRaw( $path, @@ -96,74 +133,78 @@ protected function post($path, array $parameters = array(), $requestHeaders = ar /** * Send a POST request with raw data. * - * @param string $path Request path. - * @param $body Request body. - * @param array $requestHeaders Request headers. - * @return \Guzzle\Http\EntityBodyInterface|mixed|string + * @param string $path Request path. + * @param string $body Request body. + * @param array $requestHeaders Request headers. + * + * @return array|string */ - protected function postRaw($path, $body, $requestHeaders = array()) + protected function postRaw(string $path, $body, array $requestHeaders = []) { $response = $this->client->getHttpClient()->post( $path, - $body, - $requestHeaders + $requestHeaders, + $body ); return ResponseMediator::getContent($response); } - /** * Send a PATCH request with JSON-encoded parameters. * - * @param string $path Request path. - * @param array $parameters POST parameters to be JSON encoded. - * @param array $requestHeaders Request headers. + * @param string $path Request path. + * @param array $parameters POST parameters to be JSON encoded. + * @param array $requestHeaders Request headers. + * + * @return array|string */ - protected function patch($path, array $parameters = array(), $requestHeaders = array()) + protected function patch(string $path, array $parameters = [], array $requestHeaders = []) { $response = $this->client->getHttpClient()->patch( $path, - $this->createJsonBody($parameters), - $requestHeaders + $requestHeaders, + $this->createJsonBody($parameters) ); return ResponseMediator::getContent($response); } - /** * Send a PUT request with JSON-encoded parameters. * - * @param string $path Request path. - * @param array $parameters POST parameters to be JSON encoded. - * @param array $requestHeaders Request headers. + * @param string $path Request path. + * @param array $parameters POST parameters to be JSON encoded. + * @param array $requestHeaders Request headers. + * + * @return array|string */ - protected function put($path, array $parameters = array(), $requestHeaders = array()) + protected function put(string $path, array $parameters = [], array $requestHeaders = []) { $response = $this->client->getHttpClient()->put( $path, - $this->createJsonBody($parameters), - $requestHeaders + $requestHeaders, + $this->createJsonBody($parameters) ); return ResponseMediator::getContent($response); } - /** * Send a DELETE request with JSON-encoded parameters. * - * @param string $path Request path. - * @param array $parameters POST parameters to be JSON encoded. - * @param array $requestHeaders Request headers. + * @param string $path Request path. + * @param array $parameters POST parameters to be JSON encoded. + * @param array $requestHeaders Request headers. + * + * @return array|string */ - protected function delete($path, array $parameters = array(), $requestHeaders = array()) + protected function delete(string $path, array $parameters = [], array $requestHeaders = []) { $response = $this->client->getHttpClient()->delete( $path, - $this->createJsonBody($parameters), - $requestHeaders + $requestHeaders, + $this->createJsonBody($parameters) ); return ResponseMediator::getContent($response); @@ -172,10 +213,11 @@ protected function delete($path, array $parameters = array(), $requestHeaders = /** * Create a JSON encoded version of an array of parameters. * - * @param array $parameters Request parameters - * @return null|string + * @param array $parameters Request parameters + * + * @return string|null */ - protected function createJsonBody(array $parameters) + protected function createJsonBody(array $parameters): ?string { return (count($parameters) === 0) ? null : json_encode($parameters, empty($parameters) ? JSON_FORCE_OBJECT : 0); } diff --git a/lib/Github/Api/AcceptHeaderTrait.php b/lib/Github/Api/AcceptHeaderTrait.php new file mode 100644 index 00000000000..6a990a56144 --- /dev/null +++ b/lib/Github/Api/AcceptHeaderTrait.php @@ -0,0 +1,66 @@ + + */ +trait AcceptHeaderTrait +{ + /** @var string */ + protected $acceptHeaderValue; + + protected function get(string $path, array $parameters = [], array $requestHeaders = []) + { + return parent::get($path, $parameters, $this->mergeHeaders($requestHeaders)); + } + + protected function head(string $path, array $parameters = [], array $requestHeaders = []): ResponseInterface + { + return parent::head($path, $parameters, $this->mergeHeaders($requestHeaders)); + } + + protected function post(string $path, array $parameters = [], array $requestHeaders = []) + { + return parent::post($path, $parameters, $this->mergeHeaders($requestHeaders)); + } + + protected function postRaw(string $path, $body, array $requestHeaders = []) + { + return parent::postRaw($path, $body, $this->mergeHeaders($requestHeaders)); + } + + protected function patch(string $path, array $parameters = [], array $requestHeaders = []) + { + return parent::patch($path, $parameters, $this->mergeHeaders($requestHeaders)); + } + + protected function put(string $path, array $parameters = [], array $requestHeaders = []) + { + return parent::put($path, $parameters, $this->mergeHeaders($requestHeaders)); + } + + protected function delete(string $path, array $parameters = [], array $requestHeaders = []) + { + return parent::delete($path, $parameters, $this->mergeHeaders($requestHeaders)); + } + + /** + * Append a new accept header on all requests. + * + * @return array + */ + private function mergeHeaders(array $headers = []): array + { + $default = []; + if ($this->acceptHeaderValue) { + $default = ['Accept' => $this->acceptHeaderValue]; + } + + return array_merge($default, $headers); + } +} diff --git a/lib/Github/Api/ApiInterface.php b/lib/Github/Api/ApiInterface.php deleted file mode 100644 index c5928637ac7..00000000000 --- a/lib/Github/Api/ApiInterface.php +++ /dev/null @@ -1,19 +0,0 @@ - - */ -interface ApiInterface -{ - public function __construct(Client $client); - - public function getPerPage(); - - public function setPerPage($perPage); -} diff --git a/lib/Github/Api/App/Hook.php b/lib/Github/Api/App/Hook.php new file mode 100644 index 00000000000..e7475dce740 --- /dev/null +++ b/lib/Github/Api/App/Hook.php @@ -0,0 +1,76 @@ +get('/app/hook/config'); + } + + /** + * Update the hook configuration of an app. + * + * @link https://docs.github.com/en/rest/apps/webhooks#update-a-webhook-configuration-for-an-app + * + * @param array $params + * + * @return array + */ + public function updateConfig(array $params) + { + return $this->patch('/app/hook/config', $params); + } + + /** + * List deliveries for an app webhook. + * + * @link https://docs.github.com/en/rest/apps/webhooks#list-deliveries-for-an-app-webhook + * + * @return array + */ + public function deliveries() + { + return $this->get('/app/hook/deliveries'); + } + + /** + * Get a delivery for an app webhook. + * + * @link https://docs.github.com/en/rest/apps/webhooks#get-a-delivery-for-an-app-webhook + * + * @param int $delivery + * + * @return array + */ + public function delivery($delivery) + { + return $this->get('/app/hook/deliveries/'.$delivery); + } + + /** + * Redeliver a delivery for an app webhook. + * + * @link https://docs.github.com/en/rest/apps/webhooks#redeliver-a-delivery-for-an-app-webhook + * + * @param int $delivery + * + * @return array + */ + public function redeliver($delivery) + { + return $this->post('/app/hook/deliveries/'.$delivery.'/attempts'); + } +} diff --git a/lib/Github/Api/Apps.php b/lib/Github/Api/Apps.php new file mode 100644 index 00000000000..15e1dfdcd4a --- /dev/null +++ b/lib/Github/Api/Apps.php @@ -0,0 +1,215 @@ + + */ +class Apps extends AbstractApi +{ + use AcceptHeaderTrait; + + private function configurePreviewHeader() + { + $this->acceptHeaderValue = 'application/vnd.github.machine-man-preview+json'; + } + + /** + * Create an access token for an installation. + * + * @param int $installationId An integration installation id + * @param int $userId An optional user id on behalf of whom the + * token will be requested + * + * @link https://developer.github.com/v3/apps/#create-a-new-installation-token + * + * @return array token and token metadata + */ + public function createInstallationToken($installationId, $userId = null) + { + $parameters = []; + if ($userId) { + $parameters['user_id'] = $userId; + } + + $this->configurePreviewHeader(); + + return $this->post('/app/installations/'.$installationId.'/access_tokens', $parameters); + } + + /** + * Find all installations for the authenticated application. + * + * @link https://developer.github.com/v3/apps/#find-installations + * + * @return array + */ + public function findInstallations() + { + $this->configurePreviewHeader(); + + return $this->get('/app/installations'); + } + + /** + * Get an installation of the application. + * + * @link https://developer.github.com/v3/apps/#get-an-installation + * + * @param int $installationId An integration installation id + * + * @return array + */ + public function getInstallation($installationId) + { + $this->configurePreviewHeader(); + + return $this->get('/app/installations/'.$installationId); + } + + /** + * Get an installation of the application for an organization. + * + * @link https://developer.github.com/v3/apps/#get-an-organization-installation + * + * @param string $org An organization + * + * @return array + */ + public function getInstallationForOrganization($org) + { + $this->configurePreviewHeader(); + + return $this->get('/orgs/'.rawurldecode($org).'/installation'); + } + + /** + * Get an installation of the application for a repository. + * + * @link https://developer.github.com/v3/apps/#get-a-repository-installation + * + * @param string $owner the owner of a repository + * @param string $repo the name of the repository + * + * @return array + */ + public function getInstallationForRepo($owner, $repo) + { + $this->configurePreviewHeader(); + + return $this->get('/repos/'.rawurldecode($owner).'/'.rawurldecode($repo).'/installation'); + } + + /** + * Get an installation of the application for a user. + * + * @link https://developer.github.com/v3/apps/#get-a-user-installation + * + * @param string $username + * + * @return array + */ + public function getInstallationForUser($username) + { + $this->configurePreviewHeader(); + + return $this->get('/users/'.rawurldecode($username).'/installation'); + } + + /** + * Delete an installation of the application. + * + * @link https://developer.github.com/v3/apps/#delete-an-installation + * + * @param int $installationId An integration installation id + */ + public function removeInstallation($installationId) + { + $this->configurePreviewHeader(); + + $this->delete('/app/installations/'.$installationId); + } + + /** + * List repositories that are accessible to the authenticated installation. + * + * @link https://developer.github.com/v3/apps/installations/#list-repositories + * + * @param int $userId + * + * @return array + */ + public function listRepositories($userId = null) + { + $parameters = []; + if ($userId) { + $parameters['user_id'] = $userId; + } + + $this->configurePreviewHeader(); + + return $this->get('/installation/repositories', $parameters); + } + + /** + * Add a single repository to an installation. + * + * @link https://developer.github.com/v3/apps/installations/#add-repository-to-installation + * + * @param int $installationId + * @param int $repositoryId + * + * @return array + */ + public function addRepository($installationId, $repositoryId) + { + $this->configurePreviewHeader(); + + return $this->put('/installations/'.$installationId.'/repositories/'.$repositoryId); + } + + /** + * Remove a single repository from an installation. + * + * @link https://developer.github.com/v3/apps/installations/#remove-repository-from-installation + * + * @param int $installationId + * @param int $repositoryId + * + * @return array + */ + public function removeRepository($installationId, $repositoryId) + { + $this->configurePreviewHeader(); + + return $this->delete('/installations/'.$installationId.'/repositories/'.$repositoryId); + } + + /** + * Get the currently authenticated app. + * + * @link https://docs.github.com/en/rest/reference/apps#get-the-authenticated-app + * + * @return array + */ + public function getAuthenticatedApp() + { + return $this->get('/app'); + } + + /** + * Manage the hook of an app. + * + * @link https://docs.github.com/en/rest/apps/webhooks + * + * @return Hook + */ + public function hook() + { + return new Hook($this->getClient()); + } +} diff --git a/lib/Github/Api/Authorizations.php b/lib/Github/Api/Authorizations.php index 0066a1f0f3f..6032c7fadb2 100644 --- a/lib/Github/Api/Authorizations.php +++ b/lib/Github/Api/Authorizations.php @@ -2,42 +2,64 @@ namespace Github\Api; -use Github\Api\AbstractApi; - /** - * Creating, deleting and listing authorizations + * Creating, deleting and listing authorizations. + * + * @link http://developer.github.com/v3/oauth_authorizations/ * - * @link http://developer.github.com/v3/oauth/ + * @author Evgeniy Guseletov */ class Authorizations extends AbstractApi { - public function all() - { - return $this->get('authorizations'); - } - - public function show($number) - { - return $this->get('authorizations/'.rawurlencode($number)); - } - - public function create(array $params) + /** + * Check an application token. + * + * @param string $clientId + * @param string|null $token + * + * @return array + */ + public function checkToken($clientId, $token = null) { - return $this->post('authorizations', $params); + return $this->post('/applications/'.rawurlencode($clientId).'/token', $token ? ['access_token' => $token] : []); } - public function update($id, array $params) + /** + * Reset an application token. + * + * @param string $clientId + * @param string|null $token + * + * @return array + */ + public function resetToken($clientId, $token = null) { - return $this->patch('authorizations/'.rawurlencode($id), $params); + return $this->patch('/applications/'.rawurlencode($clientId).'/token', $token ? ['access_token' => $token] : []); } - public function remove($id) + /** + * Revoke an application token. + * + * @param string $clientId + * @param string|null $token + * + * @return void + */ + public function deleteToken($clientId, $token = null) { - return $this->delete('authorizations/'.rawurlencode($id)); + $this->delete('/applications/'.rawurlencode($clientId).'/token', $token ? ['access_token' => $token] : []); } - public function check($id, $token) + /** + * Revoke an application authorization. + * + * @param string $clientId + * @param string|null $token + * + * @return void + */ + public function deleteGrant($clientId, $token = null) { - return $this->get('authorizations/'.rawurlencode($id).'/tokens/'.rawurlencode($token)); + $this->delete('/applications/'.rawurlencode($clientId).'/grant', $token ? ['access_token' => $token] : []); } } diff --git a/lib/Github/Api/Copilot/Usage.php b/lib/Github/Api/Copilot/Usage.php new file mode 100644 index 00000000000..0110a58bb40 --- /dev/null +++ b/lib/Github/Api/Copilot/Usage.php @@ -0,0 +1,34 @@ +get('/orgs/'.rawurlencode($organization).'/copilot/usage', $params); + } + + public function orgTeamUsageSummary(string $organization, string $teamSlug, array $params = []): array + { + return $this->get( + '/orgs/'.rawurlencode($organization).'/team/'.rawurlencode($teamSlug).'/copilot/usage', + $params + ); + } + + public function enterpriseUsageSummary(string $enterprise, array $params = []): array + { + return $this->get('/enterprises/'.rawurlencode($enterprise).'/copilot/usage', $params); + } + + public function enterpriseTeamUsageSummary(string $enterprise, string $teamSlug, array $params = []): array + { + return $this->get( + '/enterprises/'.rawurlencode($enterprise).'/team/'.rawurlencode($teamSlug).'/copilot/usage', + $params + ); + } +} diff --git a/lib/Github/Api/CurrentUser.php b/lib/Github/Api/CurrentUser.php index 7b1af4381c8..b5cbc89a376 100644 --- a/lib/Github/Api/CurrentUser.php +++ b/lib/Github/Api/CurrentUser.php @@ -2,26 +2,32 @@ namespace Github\Api; -use Github\Api\CurrentUser\DeployKeys; use Github\Api\CurrentUser\Emails; use Github\Api\CurrentUser\Followers; +use Github\Api\CurrentUser\Memberships; use Github\Api\CurrentUser\Notifications; +use Github\Api\CurrentUser\PublicKeys; +use Github\Api\CurrentUser\Starring; use Github\Api\CurrentUser\Watchers; /** * @link http://developer.github.com/v3/users/ + * * @author Joseph Bielawski + * @author Felipe Valtl de Mello */ class CurrentUser extends AbstractApi { + use AcceptHeaderTrait; + public function show() { - return $this->get('user'); + return $this->get('/user'); } public function update(array $params) { - return $this->patch('user', $params); + return $this->patch('/user', $params); } /** @@ -29,7 +35,7 @@ public function update(array $params) */ public function emails() { - return new Emails($this->client); + return new Emails($this->getClient()); } /** @@ -37,35 +43,35 @@ public function emails() */ public function follow() { - return new Followers($this->client); + return new Followers($this->getClient()); } public function followers($page = 1) { - return $this->get('user/followers', array( - 'page' => $page - )); + return $this->get('/user/followers', [ + 'page' => $page, + ]); } /** - * @link http://developer.github.com/v3/issues/#list-issues + * @link https://docs.github.com/en/rest/reference/issues#list-user-account-issues-assigned-to-the-authenticated-user * - * @param array $params - * @param boolean $includeOrgIssues + * @param array $params + * @param bool $includeOrgIssues * * @return array */ - public function issues(array $params = array(), $includeOrgIssues = true) + public function issues(array $params = [], $includeOrgIssues = true) { - return $this->get($includeOrgIssues ? 'issues' : 'user/issues', array_merge(array('page' => 1), $params)); + return $this->get($includeOrgIssues ? '/issues' : '/user/issues', array_merge(['page' => 1], $params)); } /** - * @return DeployKeys + * @return PublicKeys */ public function keys() { - return new DeployKeys($this->client); + return new PublicKeys($this->getClient()); } /** @@ -73,27 +79,67 @@ public function keys() */ public function notifications() { - return new Notifications($this->client); + return new Notifications($this->getClient()); } /** - * @link http://developer.github.com/v3/orgs/#list-user-organizations + * @return Memberships + */ + public function memberships() + { + return new Memberships($this->getClient()); + } + + /** + * @link https://docs.github.com/en/rest/reference/orgs#list-organizations-for-the-authenticated-user * * @return array */ public function organizations() { - return $this->get('user/orgs'); + return $this->get('/user/orgs'); } /** - * @link http://developer.github.com/v3/repos/#list-your-repositories + * @link https://developer.github.com/v3/orgs/teams/#list-user-teams * * @return array */ - public function repositories() + public function teams() { - return $this->get('user/repos'); + return $this->get('/user/teams'); + } + + /** + * @link https://docs.github.com/en/rest/reference/repos#list-repositories-for-the-authenticated-user + * + * @param string $type role in the repository + * @param string $sort sort by + * @param string $direction direction of sort, asc or desc + * @param string $visibility visibility of repository + * @param string $affiliation relationship to repository + * + * @return array + */ + public function repositories($type = 'owner', $sort = 'full_name', $direction = 'asc', $visibility = null, $affiliation = null) + { + $params = [ + 'type' => $type, + 'sort' => $sort, + 'direction' => $direction, + ]; + + if (null !== $visibility) { + unset($params['type']); + $params['visibility'] = $visibility; + } + + if (null !== $affiliation) { + unset($params['type']); + $params['affiliation'] = $affiliation; + } + + return $this->get('/user/repos', $params); } /** @@ -101,23 +147,47 @@ public function repositories() */ public function watchers() { - return new Watchers($this->client); + return new Watchers($this->getClient()); } - public function watched($page = 1) + /** + * @return Starring + */ + public function starring() + { + return new Starring($this->getClient()); + } + + /** + * @link https://docs.github.com/en/rest/reference/activity#list-repositories-watched-by-the-authenticated-user + */ + public function subscriptions() + { + return $this->get('/user/subscriptions'); + } + + /** + * @link https://docs.github.com/en/rest/reference/apps#list-app-installations-accessible-to-the-user-access-token + * + * @param array $params + */ + public function installations(array $params = []) { - return $this->get('user/watched', array( - 'page' => $page - )); + $this->acceptHeaderValue = 'application/vnd.github.machine-man-preview+json'; + + return $this->get('/user/installations', array_merge(['page' => 1], $params)); } /** - * @link http://developer.github.com/changes/2012-9-5-watcher-api/ + * @link https://developer.github.com/v3/apps/installations/#list-repositories-accessible-to-the-user-access-token + * + * @param string $installationId the ID of the Installation + * @param array $params */ - public function starred($page = 1) + public function repositoriesByInstallation($installationId, array $params = []) { - return $this->get('user/starred', array( - 'page' => $page - )); + $this->acceptHeaderValue = 'application/vnd.github.machine-man-preview+json'; + + return $this->get(sprintf('/user/installations/%s/repositories', $installationId), array_merge(['page' => 1], $params)); } } diff --git a/lib/Github/Api/CurrentUser/DeployKeys.php b/lib/Github/Api/CurrentUser/DeployKeys.php deleted file mode 100644 index 87a0eaed843..00000000000 --- a/lib/Github/Api/CurrentUser/DeployKeys.php +++ /dev/null @@ -1,85 +0,0 @@ - - */ -class DeployKeys extends AbstractApi -{ - /** - * List deploy keys for the authenticated user - * @link http://developer.github.com/v3/repos/keys/ - * - * @return array - */ - public function all() - { - return $this->get('user/keys'); - } - - /** - * Shows deploy key for the authenticated user - * @link http://developer.github.com/v3/repos/keys/ - * - * @param string $id - * @return array - */ - public function show($id) - { - return $this->get('user/keys/'.rawurlencode($id)); - } - - /** - * Adds deploy key for the authenticated user - * @link http://developer.github.com/v3/repos/keys/ - * - * @param array $params - * @return array - * - * @throws MissingArgumentException - */ - public function create(array $params) - { - if (!isset($params['title'], $params['key'])) { - throw new MissingArgumentException(array('title', 'key')); - } - - return $this->post('user/keys', $params); - } - - /** - * Updates deploy key for the authenticated user - * @link http://developer.github.com/v3/repos/keys/ - * - * @param string $id - * @param array $params - * @return array - * - * @throws MissingArgumentException - */ - public function update($id, array $params) - { - if (!isset($params['title'], $params['key'])) { - throw new MissingArgumentException(array('title', 'key')); - } - - return $this->patch('user/keys/'.rawurlencode($id), $params); - } - - /** - * Removes deploy key for the authenticated user - * @link http://developer.github.com/v3/repos/keys/ - * - * @param string $id - * @return array - */ - public function remove($id) - { - return $this->delete('user/keys/'.rawurlencode($id)); - } -} diff --git a/lib/Github/Api/CurrentUser/Emails.php b/lib/Github/Api/CurrentUser/Emails.php index ec8c78d5986..23f2ab2402d 100644 --- a/lib/Github/Api/CurrentUser/Emails.php +++ b/lib/Github/Api/CurrentUser/Emails.php @@ -7,58 +7,88 @@ /** * @link http://developer.github.com/v3/users/emails/ + * * @author Joseph Bielawski */ class Emails extends AbstractApi { /** - * List emails for the authenticated user + * List emails for the authenticated user. + * * @link http://developer.github.com/v3/users/emails/ * * @return array */ public function all() { - return $this->get('user/emails'); + return $this->get('/user/emails'); } /** - * Adds one or more email for the authenticated user - * @link http://developer.github.com/v3/users/emails/ + * List public email addresses for a user. + * + * @link https://developer.github.com/v3/users/emails/#list-public-email-addresses-for-a-user * - * @param string|array $emails * @return array + */ + public function allPublic() + { + return $this->get('/user/public_emails'); + } + + /** + * Adds one or more email for the authenticated user. + * + * @link http://developer.github.com/v3/users/emails/ * - * @throws InvalidArgumentException + * @param string|array $emails + * + * @throws \Github\Exception\InvalidArgumentException + * + * @return array */ public function add($emails) { if (is_string($emails)) { - $emails = array($emails); + $emails = [$emails]; } elseif (0 === count($emails)) { - throw new InvalidArgumentException(); + throw new InvalidArgumentException('The user emails parameter should be a single email or an array of emails'); } - return $this->post('user/emails', $emails); + return $this->post('/user/emails', $emails); } /** - * Removes one or more email for the authenticated user + * Removes one or more email for the authenticated user. + * * @link http://developer.github.com/v3/users/emails/ * - * @param string|array $emails - * @return array + * @param string|array $emails + * + * @throws \Github\Exception\InvalidArgumentException * - * @throws InvalidArgumentException + * @return array */ public function remove($emails) { if (is_string($emails)) { - $emails = array($emails); + $emails = [$emails]; } elseif (0 === count($emails)) { - throw new InvalidArgumentException(); + throw new InvalidArgumentException('The user emails parameter should be a single email or an array of emails'); } - return $this->delete('user/emails', $emails); + return $this->delete('/user/emails', $emails); + } + + /** + * Toggle primary email visibility. + * + * @link https://developer.github.com/v3/users/emails/#toggle-primary-email-visibility + * + * @return array + */ + public function toggleVisibility() + { + return $this->patch('/user/email/visibility'); } } diff --git a/lib/Github/Api/CurrentUser/Followers.php b/lib/Github/Api/CurrentUser/Followers.php index ea356d85e32..52a712ca99e 100644 --- a/lib/Github/Api/CurrentUser/Followers.php +++ b/lib/Github/Api/CurrentUser/Followers.php @@ -6,57 +6,66 @@ /** * @link http://developer.github.com/v3/users/followers/ + * * @author Joseph Bielawski */ class Followers extends AbstractApi { /** - * List followed users by the authenticated user + * List followed users by the authenticated user. + * * @link http://developer.github.com/v3/repos/followers/ * - * @param integer $page + * @param int $page + * * @return array */ public function all($page = 1) { - return $this->get('user/following', array( - 'page' => $page - )); + return $this->get('/user/following', [ + 'page' => $page, + ]); } /** - * Check that the authenticated user follows a user + * Check that the authenticated user follows a user. + * * @link http://developer.github.com/v3/repos/followers/ * - * @param string $username the username to follow + * @param string $username the username to follow + * * @return array */ public function check($username) { - return $this->get('user/following/'.rawurlencode($username)); + return $this->get('/user/following/'.rawurlencode($username)); } /** - * Make the authenticated user follow a user + * Make the authenticated user follow a user. + * * @link http://developer.github.com/v3/repos/followers/ * - * @param string $username the username to follow + * @param string $username the username to follow + * * @return array */ public function follow($username) { - return $this->put('user/following/'.rawurlencode($username)); + return $this->put('/user/following/'.rawurlencode($username)); } /** - * Make the authenticated user un-follow a user + * Make the authenticated user un-follow a user. + * * @link http://developer.github.com/v3/repos/followers/ * - * @param string $username the username to un-follow + * @param string $username the username to un-follow + * * @return array */ public function unfollow($username) { - return $this->delete('user/following/'.rawurlencode($username)); + return $this->delete('/user/following/'.rawurlencode($username)); } } diff --git a/lib/Github/Api/CurrentUser/Memberships.php b/lib/Github/Api/CurrentUser/Memberships.php new file mode 100644 index 00000000000..da727397407 --- /dev/null +++ b/lib/Github/Api/CurrentUser/Memberships.php @@ -0,0 +1,48 @@ +get('/user/memberships/orgs'); + } + + /** + * Get your organization membership. + * + * @link https://developer.github.com/v3/orgs/members/#get-your-organization-membership + * + * @param string $organization + * + * @return array + */ + public function organization($organization) + { + return $this->get('/user/memberships/orgs/'.rawurlencode($organization)); + } + + /** + * Edit your organization membership. + * + * @link https://developer.github.com/v3/orgs/members/#edit-your-organization-membership + * + * @param string $organization + * + * @return array + */ + public function edit($organization) + { + return $this->patch('/user/memberships/orgs/'.rawurlencode($organization), ['state' => 'active']); + } +} diff --git a/lib/Github/Api/CurrentUser/Notifications.php b/lib/Github/Api/CurrentUser/Notifications.php index a35519df783..9f3f2ce7bac 100644 --- a/lib/Github/Api/CurrentUser/Notifications.php +++ b/lib/Github/Api/CurrentUser/Notifications.php @@ -6,114 +6,140 @@ /** * @link http://developer.github.com/v3/activity/notifications/ + * * @author Joseph Bielawski */ class Notifications extends AbstractApi { /** - * List all notifications for the authenticated user + * List all notifications for the authenticated user. + * * @link http://developer.github.com/v3/activity/notifications/#list-your-notifications * - * @param array $params + * @param array $params + * * @return array */ - public function all(array $params = array()) + public function all(array $params = []) { - return $this->get('notifications', $params); + return $this->get('/notifications', $params); } /** - * List all notifications for the authenticated user in selected repository + * List all notifications for the authenticated user in selected repository. + * * @link http://developer.github.com/v3/activity/notifications/#list-your-notifications-in-a-repository * - * @param string $username the user who owns the repo - * @param string $repository the name of the repo - * @param array $params + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * @param array $params + * * @return array */ - public function allInRepository($username, $repository, array $params = array()) + public function allInRepository($username, $repository, array $params = []) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/notifications', $params); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/notifications', $params); } /** + * Mark all notifications as read. + * * @link http://developer.github.com/v3/activity/notifications/#mark-as-read * - * @param array $params + * @param array $params + * * @return array */ - public function markAsReadAll(array $params = array()) + public function markAsReadAll(array $params = []) { - return $this->put('notifications', $params); + return $this->put('/notifications', $params); } /** + * Mark all notifications for a repository as read. + * * @link http://developer.github.com/v3/activity/notifications/#mark-notifications-as-read-in-a-repository * - * @param string $username the user who owns the repo - * @param string $repository the name of the repo - * @param array $params + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * @param array $params + * * @return array */ - public function markAsReadInRepository($username, $repository, array $params = array()) + public function markAsReadInRepository($username, $repository, array $params = []) { - return $this->put('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/notifications', $params); + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/notifications', $params); } /** + * Mark a notification as read. + * * @link http://developer.github.com/v3/activity/notifications/#mark-a-thread-as-read * - * @param string $id the notification number - * @param array $params + * @param int $id the notification number + * @param array $params + * * @return array */ public function markAsRead($id, array $params) { - return $this->patch('notifications/threads/'.rawurlencode($id), $params); + return $this->patch('/notifications/threads/'.$id, $params); } /** + * Show a notification. + * * @link http://developer.github.com/v3/activity/notifications/#view-a-single-thread * - * @param string $id the notification number + * @param int $id the notification number + * * @return array */ public function show($id) { - return $this->get('notifications/threads/'.rawurlencode($id)); + return $this->get('/notifications/threads/'.$id); } /** + * Show a subscription. + * * @link http://developer.github.com/v3/activity/notifications/#get-a-thread-subscription * - * @param string $id the notification number + * @param int $id the notification number + * * @return array */ public function showSubscription($id) { - return $this->get('notifications/threads/'.rawurlencode($id).'/subscription'); + return $this->get('/notifications/threads/'.$id.'/subscription'); } /** + * Create a subscription. + * * @link http://developer.github.com/v3/activity/notifications/#set-a-thread-subscription * - * @param string $id the notification number - * @param array $params + * @param int $id the notification number + * @param array $params + * * @return array */ public function createSubscription($id, array $params) { - return $this->put('notifications/threads/'.rawurlencode($id).'/subscription', $params); + return $this->put('/notifications/threads/'.$id.'/subscription', $params); } /** + * Delete a subscription. + * * @link http://developer.github.com/v3/activity/notifications/#delete-a-thread-subscription * - * @param string $id the notification number + * @param int $id the notification number + * * @return array */ public function removeSubscription($id) { - return $this->delete('notifications/threads/'.rawurlencode($id).'/subscription'); + return $this->delete('/notifications/threads/'.$id.'/subscription'); } } diff --git a/lib/Github/Api/CurrentUser/PublicKeys.php b/lib/Github/Api/CurrentUser/PublicKeys.php new file mode 100644 index 00000000000..cb24dec9ace --- /dev/null +++ b/lib/Github/Api/CurrentUser/PublicKeys.php @@ -0,0 +1,74 @@ + + */ +class PublicKeys extends AbstractApi +{ + /** + * List deploy keys for the authenticated user. + * + * @link https://developer.github.com/v3/users/keys/ + * + * @return array + */ + public function all() + { + return $this->get('/user/keys'); + } + + /** + * Shows deploy key for the authenticated user. + * + * @link https://developer.github.com/v3/users/keys/ + * + * @param int $id + * + * @return array + */ + public function show($id) + { + return $this->get('/user/keys/'.$id); + } + + /** + * Adds deploy key for the authenticated user. + * + * @link https://developer.github.com/v3/users/keys/ + * + * @param array $params + * + * @throws \Github\Exception\MissingArgumentException + * + * @return array + */ + public function create(array $params) + { + if (!isset($params['title'], $params['key'])) { + throw new MissingArgumentException(['title', 'key']); + } + + return $this->post('/user/keys', $params); + } + + /** + * Removes deploy key for the authenticated user. + * + * @link https://developer.github.com/v3/users/keys/ + * + * @param int $id + * + * @return array + */ + public function remove($id) + { + return $this->delete('/user/keys/'.$id); + } +} diff --git a/lib/Github/Api/CurrentUser/Starring.php b/lib/Github/Api/CurrentUser/Starring.php new file mode 100644 index 00000000000..ee2c50233e3 --- /dev/null +++ b/lib/Github/Api/CurrentUser/Starring.php @@ -0,0 +1,97 @@ + + */ +class Starring extends AbstractApi +{ + use AcceptHeaderTrait; + + /** + * Configure the body type. + * + * @see https://developer.github.com/v3/activity/starring/#list-stargazers + * + * @param string $bodyType + * + * @return $this + */ + public function configure($bodyType = null) + { + if ('star' === $bodyType) { + $this->acceptHeaderValue = sprintf('application/vnd.github.%s.star+json', $this->getApiVersion()); + } + + return $this; + } + + /** + * List repositories starred by the authenticated user. + * + * @link https://developer.github.com/v3/activity/starring/ + * + * @param int $page + * @param int $perPage + * + * @return array + */ + public function all($page = 1, $perPage = 30) + { + return $this->get('/user/starred', [ + 'page' => $page, + 'per_page' => $perPage, + ]); + } + + /** + * Check that the authenticated user starres a repository. + * + * @link https://developer.github.com/v3/activity/starring/ + * + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * + * @return array + */ + public function check($username, $repository) + { + return $this->get('/user/starred/'.rawurlencode($username).'/'.rawurlencode($repository)); + } + + /** + * Make the authenticated user star a repository. + * + * @link https://developer.github.com/v3/activity/starring/ + * + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * + * @return array + */ + public function star($username, $repository) + { + return $this->put('/user/starred/'.rawurlencode($username).'/'.rawurlencode($repository)); + } + + /** + * Make the authenticated user unstar a repository. + * + * @link https://developer.github.com/v3/activity/starring + * + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * + * @return array + */ + public function unstar($username, $repository) + { + return $this->delete('/user/starred/'.rawurlencode($username).'/'.rawurlencode($repository)); + } +} diff --git a/lib/Github/Api/CurrentUser/Watchers.php b/lib/Github/Api/CurrentUser/Watchers.php index 398ac58536a..79c04b5df36 100644 --- a/lib/Github/Api/CurrentUser/Watchers.php +++ b/lib/Github/Api/CurrentUser/Watchers.php @@ -5,61 +5,72 @@ use Github\Api\AbstractApi; /** - * @link http://developer.github.com/v3/repos/watching/ + * @link https://developer.github.com/v3/activity/watching/ + * * @author Joseph Bielawski + * + * @revised Felipe Valtl de Mello */ class Watchers extends AbstractApi { /** - * List repositories watched by the authenticated user - * @link http://developer.github.com/v3/repos/watching/ + * List repositories watched by the authenticated user. + * + * @link https://developer.github.com/v3/activity/watching/ + * + * @param int $page * - * @param integer $page * @return array */ public function all($page = 1) { - return $this->get('user/watched', array( - 'page' => $page - )); + return $this->get('/user/subscriptions', [ + 'page' => $page, + ]); } /** - * Check that the authenticated user watches a repository - * @link http://developer.github.com/v3/repos/watching/ + * Check that the authenticated user watches a repository. + * + * @link https://developer.github.com/v3/activity/watching/ + * + * @param string $username the user who owns the repo + * @param string $repository the name of the repo * - * @param string $username the user who owns the repo - * @param string $repository the name of the repo * @return array */ public function check($username, $repository) { - return $this->get('user/watched/'.rawurlencode($username).'/'.rawurlencode($repository)); + return $this->get('/user/subscriptions/'.rawurlencode($username).'/'.rawurlencode($repository)); } /** - * Make the authenticated user watch a repository - * @link http://developer.github.com/v3/repos/watching/ + * Make the authenticated user watch a repository. + * + * @link https://developer.github.com/v3/activity/watching/ + * + * @param string $username the user who owns the repo + * @param string $repository the name of the repo * - * @param string $username the user who owns the repo - * @param string $repository the name of the repo * @return array */ public function watch($username, $repository) { - return $this->put('user/watched/'.rawurlencode($username).'/'.rawurlencode($repository)); + return $this->put('/user/subscriptions/'.rawurlencode($username).'/'.rawurlencode($repository)); } /** - * Make the authenticated user unwatch a repository - * @link http://developer.github.com/v3/repos/watching/ + * Make the authenticated user unwatch a repository. + * + * @link https://developer.github.com/v3/activity/watching/ + * + * @param string $username the user who owns the repo + * @param string $repository the name of the repo * - * @param string $username the user who owns the repo - * @param string $repository the name of the repo * @return array */ public function unwatch($username, $repository) { - return $this->delete('user/watched/'.rawurlencode($username).'/'.rawurlencode($repository)); + return $this->delete('/user/subscriptions/'.rawurlencode($username).'/'.rawurlencode($repository)); } } diff --git a/lib/Github/Api/Deployment.php b/lib/Github/Api/Deployment.php new file mode 100644 index 00000000000..de5b0cb0eb9 --- /dev/null +++ b/lib/Github/Api/Deployment.php @@ -0,0 +1,151 @@ +get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/deployments', $params); + } + + /** + * Get a deployment in selected repository. + * + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * @param int $id the id of the deployment + * + * @return array + */ + public function show($username, $repository, $id) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/deployments/'.$id); + } + + /** + * Create a new deployment for the given username and repo. + * + * @link https://developer.github.com/v3/repos/deployments/#create-a-deployment + * + * Important: Once a deployment is created, it cannot be updated. Changes are indicated by creating new statuses. + * @see updateStatus + * + * @param string $username the username + * @param string $repository the repository + * @param array $params the new deployment data + * + * @throws MissingArgumentException + * + * @return array information about the deployment + */ + public function create($username, $repository, array $params) + { + if (!isset($params['ref'])) { + throw new MissingArgumentException(['ref']); + } + + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/deployments', $params); + } + + /** + * Delete a deployment for the given username and repo. + * + * @link https://docs.github.com/en/rest/reference/repos#delete-a-deployment + * + * Important: Deployments can only be deleted when in inactive state + * @see updateStatus + * + * @return mixed null on success, array on error with 'message' + */ + public function remove(string $username, string $repository, int $id) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/deployments/'.$id); + } + + /** + * Updates a deployment by creating a new status update. + * + * @link https://developer.github.com/v3/repos/deployments/#create-a-deployment-status + * + * @param string $username the username + * @param string $repository the repository + * @param int $id the deployment number + * @param array $params The information about the deployment update. + * Must include a "state" field of pending, success, error, or failure. + * May also be given a target_url and description, see link for more details. + * + * @throws MissingArgumentException + * + * @return array information about the deployment + */ + public function updateStatus($username, $repository, $id, array $params) + { + if (!isset($params['state'])) { + throw new MissingArgumentException(['state']); + } + + // adjust media-type per github docs + // https://docs.github.com/en/rest/reference/repos#create-a-deployment-status + if ($params['state'] === 'inactive') { + $this->acceptHeaderValue = 'application/vnd.github.ant-man-preview+json'; + } + if ($params['state'] === 'in_progress' || $params['state'] === 'queued') { + $this->acceptHeaderValue = 'application/vnd.github.flash-preview+json'; + } + + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/deployments/'.$id.'/statuses', $params); + } + + /** + * Gets all of the status updates tied to a given deployment. + * + * @param string $username the username + * @param string $repository the repository + * @param int $id the deployment identifier + * + * @return array the deployment statuses + */ + public function getStatuses($username, $repository, $id) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/deployments/'.$id.'/statuses'); + } + + /** + * @return Environments + */ + public function environments() + { + return new Environments($this->getClient()); + } + + /** + * @return Policies + */ + public function policies() + { + return new Policies($this->getClient()); + } +} diff --git a/lib/Github/Api/Deployment/Environments.php b/lib/Github/Api/Deployment/Environments.php new file mode 100644 index 00000000000..191ec498eab --- /dev/null +++ b/lib/Github/Api/Deployment/Environments.php @@ -0,0 +1,90 @@ +get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/environments', $params); + } + + /** + * Get a environment in selected repository. + * + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * @param string $name the name of the environment + * + * @return array + */ + public function show($username, $repository, $name) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/environments/'.rawurlencode($name)); + } + + /** + * Create or update a environment for the given username and repo. + * + * @link https://docs.github.com/en/rest/deployments/environments?apiVersion=2022-11-28#create-or-update-an-environment + * + * @param string $username the username + * @param string $repository the repository + * @param string $name the name of the environment + * @param array $params the new environment data + * + * @return array information about the environment + */ + public function createOrUpdate($username, $repository, $name, array $params = []) + { + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/environments/'.rawurlencode($name), $params); + } + + /** + * Delete a environment for the given username and repo. + * + * @link https://docs.github.com/en/rest/deployments/environments?apiVersion=2022-11-28#delete-an-environment + * + * @return mixed null on success, array on error with 'message' + */ + public function remove(string $username, string $repository, string $name) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/environments/'.rawurlencode($name)); + } + + /** + * @link https://docs.github.com/en/rest/actions/secrets?apiVersion=2022-11-28#about-secrets-in-github-actions + */ + public function secrets(): Secrets + { + return new Secrets($this->getClient()); + } + + /** + * @link https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#about-variables-in-github-actions + */ + public function variables(): Variables + { + return new Variables($this->getClient()); + } +} diff --git a/lib/Github/Api/Deployment/Policies.php b/lib/Github/Api/Deployment/Policies.php new file mode 100644 index 00000000000..e2d8fb59680 --- /dev/null +++ b/lib/Github/Api/Deployment/Policies.php @@ -0,0 +1,97 @@ +get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/environments/'.rawurlencode($environment).'/deployment-branch-policies', $params); + } + + /** + * Get a deployment branch policy. + * + * @link https://docs.github.com/en/rest/deployments/branch-policies?apiVersion=2022-11-28#get-a-deployment-branch-policy + * + * @param string $username the username of the user who owns the repository + * @param string $repository the name of the repository + * @param string $environment the name of the environment. + * @param int $id the unique identifier of the branch policy. + * + * @return array + */ + public function show(string $username, string $repository, string $environment, int $id) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/environments/'.rawurlencode($environment).'/deployment-branch-policies/'.$id); + } + + /** + * Creates a deployment branch policy for an environment. + * + * @link https://docs.github.com/en/rest/deployments/branch-policies?apiVersion=2022-11-28#create-a-deployment-branch-policy + * + * @param string $username the username of the user who owns the repository + * @param string $repository the name of the repository + * @param string $environment the name of the environment. + * + * @return array information about the deployment branch policy + */ + public function create(string $username, string $repository, string $environment, array $params) + { + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/environments/'.rawurlencode($environment).'/deployment-branch-policies', $params); + } + + /** + * Updates a deployment branch policy for an environment. + * + * @link https://docs.github.com/en/rest/deployments/branch-policies?apiVersion=2022-11-28#update-a-deployment-branch-policy + * + * @param string $username the username of the user who owns the repository + * @param string $repository the name of the repository + * @param string $environment the name of the environment. + * @param int $id the unique identifier of the branch policy. + * + * @return array information about the deployment branch policy + */ + public function update(string $username, string $repository, string $environment, int $id, array $params) + { + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/environments/'.rawurlencode($environment).'/deployment-branch-policies/'.$id, $params); + } + + /** + * Delete a deployment branch policy. + * + * @link https://docs.github.com/en/rest/deployments/branch-policies?apiVersion=2022-11-28#delete-a-deployment-branch-policy + * + * @param string $username the username of the user who owns the repository + * @param string $repository the name of the repository + * @param string $environment the name of the environment. + * @param int $id the unique identifier of the branch policy. + * + * @return mixed null on success, array on error with 'message' + */ + public function remove(string $username, string $repository, string $environment, int $id) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/environments/'.rawurlencode($environment).'/deployment-branch-policies/'.$id); + } +} diff --git a/lib/Github/Api/Enterprise.php b/lib/Github/Api/Enterprise.php new file mode 100644 index 00000000000..62abaff577e --- /dev/null +++ b/lib/Github/Api/Enterprise.php @@ -0,0 +1,60 @@ + + * @author Guillermo A. Fisher + */ +class Enterprise extends AbstractApi +{ + /** + * @return Stats + */ + public function stats() + { + return new Stats($this->getClient()); + } + + /** + * @return License + */ + public function license() + { + return new License($this->getClient()); + } + + /** + * @return ManagementConsole + */ + public function console() + { + return new ManagementConsole($this->getClient()); + } + + /** + * @return UserAdmin + */ + public function userAdmin() + { + return new UserAdmin($this->getClient()); + } + + /** + * @return SecretScanning + */ + public function secretScanning(): SecretScanning + { + return new SecretScanning($this->getClient()); + } +} diff --git a/lib/Github/Api/Enterprise/License.php b/lib/Github/Api/Enterprise/License.php new file mode 100644 index 00000000000..67e1c2a96ea --- /dev/null +++ b/lib/Github/Api/Enterprise/License.php @@ -0,0 +1,20 @@ +get('/enterprise/settings/license'); + } +} diff --git a/lib/Github/Api/Enterprise/ManagementConsole.php b/lib/Github/Api/Enterprise/ManagementConsole.php new file mode 100644 index 00000000000..f11c47643eb --- /dev/null +++ b/lib/Github/Api/Enterprise/ManagementConsole.php @@ -0,0 +1,77 @@ +getWithLicenseHash('/setup/api/configcheck', $hash); + } + + /** + * Retrieves your installation’s settings. + * + * @link https://developer.github.com/v3/enterprise/management_console/#retrieve-settings + * + * @param string $hash md5 hash of your license + * + * @return array array of settings + */ + public function settings($hash) + { + return $this->getWithLicenseHash('/setup/api/settings', $hash); + } + + /** + * Checks your installation’s maintenance status. + * + * @link https://developer.github.com/v3/enterprise/management_console/#check-maintenance-status + * + * @param string $hash md5 hash of your license + * + * @return array array of maintenance status information + */ + public function maintenance($hash) + { + return $this->getWithLicenseHash('/setup/api/maintenance', $hash); + } + + /** + * Retrieves your installation’s authorized SSH keys. + * + * @link https://developer.github.com/v3/enterprise/management_console/#retrieve-authorized-ssh-keys + * + * @param string $hash md5 hash of your license + * + * @return array array of authorized keys + */ + public function keys($hash) + { + return $this->getWithLicenseHash('/setup/api/settings/authorized-keys', $hash); + } + + /** + * Sends an authenticated GET request. + * + * @param string $uri the request URI + * @param string $hash md5 hash of your license + * + * @return array|string + */ + protected function getWithLicenseHash($uri, $hash) + { + return $this->get($uri, ['license_md5' => rawurlencode($hash)]); + } +} diff --git a/lib/Github/Api/Enterprise/SecretScanning.php b/lib/Github/Api/Enterprise/SecretScanning.php new file mode 100644 index 00000000000..5d92c1d8a47 --- /dev/null +++ b/lib/Github/Api/Enterprise/SecretScanning.php @@ -0,0 +1,21 @@ +get('/enterprises/'.rawurlencode($enterprise).'/secret-scanning/alerts', $params); + } +} diff --git a/lib/Github/Api/Enterprise/Stats.php b/lib/Github/Api/Enterprise/Stats.php new file mode 100644 index 00000000000..78ba42565e9 --- /dev/null +++ b/lib/Github/Api/Enterprise/Stats.php @@ -0,0 +1,128 @@ +show('issues'); + } + + /** + * Returns the number of active and inactive hooks. + * + * @return array array with totals of active and inactive hooks + */ + public function hooks() + { + return $this->show('hooks'); + } + + /** + * Returns the number of open and closed milestones. + * + * @return array array with totals of open and closed milestones + */ + public function milestones() + { + return $this->show('milestones'); + } + + /** + * Returns the number of organizations, teams, team members, and disabled organizations. + * + * @return array array with totals of organizations, teams, team members, and disabled organizations + */ + public function orgs() + { + return $this->show('orgs'); + } + + /** + * Returns the number of comments on issues, pull requests, commits, and gists. + * + * @return array array with totals of comments on issues, pull requests, commits, and gists + */ + public function comments() + { + return $this->show('comments'); + } + + /** + * Returns the number of GitHub Pages sites. + * + * @return array array with totals of GitHub Pages sites + */ + public function pages() + { + return $this->show('pages'); + } + + /** + * Returns the number of suspended and admin users. + * + * @return array array with totals of suspended and admin users + */ + public function users() + { + return $this->show('users'); + } + + /** + * Returns the number of private and public gists. + * + * @return array array with totals of private and public gists + */ + public function gists() + { + return $this->show('gists'); + } + + /** + * Returns the number of merged, mergeable, and unmergeable pull requests. + * + * @return array array with totals of merged, mergeable, and unmergeable pull requests + */ + public function pulls() + { + return $this->show('pulls'); + } + + /** + * Returns the number of organization-owned repositories, root repositories, forks, pushed commits, and wikis. + * + * @return array array with totals of organization-owned repositories, root repositories, forks, pushed commits, and wikis + */ + public function repos() + { + return $this->show('repos'); + } + + /** + * Returns all of the statistics. + * + * @return array array with all of the statistics + */ + public function all() + { + return $this->show('all'); + } + + /** + * @param string $type The type of statistics to show + * + * @return array + */ + public function show($type) + { + return $this->get('/enterprise/stats/'.rawurlencode($type)); + } +} diff --git a/lib/Github/Api/Enterprise/UserAdmin.php b/lib/Github/Api/Enterprise/UserAdmin.php new file mode 100644 index 00000000000..0cd55a38c53 --- /dev/null +++ b/lib/Github/Api/Enterprise/UserAdmin.php @@ -0,0 +1,36 @@ +put('/users/'.rawurldecode($username).'/suspended', ['Content-Length' => 0]); + } + + /** + * Unsuspend a user. + * + * @link https://developer.github.com/v3/users/administration/#unsuspend-a-user + * + * @param string $username + * + * @return array + */ + public function unsuspend($username) + { + return $this->delete('/users/'.rawurldecode($username).'/suspended'); + } +} diff --git a/lib/Github/Api/Environment/Secrets.php b/lib/Github/Api/Environment/Secrets.php new file mode 100644 index 00000000000..cef84c34958 --- /dev/null +++ b/lib/Github/Api/Environment/Secrets.php @@ -0,0 +1,80 @@ +get('/repositories/'.$id.'/environments/'.rawurlencode($name).'/secrets'); + } + + /** + * @link https://docs.github.com/en/rest/actions/secrets?apiVersion=2022-11-28#get-an-environment-secret + * + * @param int $id + * @param string $name + * @param string $secretName + * + * @return array|string + */ + public function show(int $id, string $name, string $secretName) + { + return $this->get('/repositories/'.$id.'/environments/'.rawurlencode($name).'/secrets/'.rawurlencode($secretName)); + } + + /** + * @link https://docs.github.com/en/rest/actions/secrets?apiVersion=2022-11-28#create-or-update-an-environment-secret + * + * @param int $id + * @param string $name + * @param string $secretName + * @param array $parameters + * + * @return array|string + */ + public function createOrUpdate(int $id, string $name, string $secretName, array $parameters = []) + { + return $this->put('/repositories/'.$id.'/environments/'.rawurlencode($name).'/secrets/'.rawurlencode($secretName), $parameters); + } + + /** + * @link https://docs.github.com/en/rest/actions/secrets?apiVersion=2022-11-28#delete-an-environment-secret + * + * @param int $id + * @param string $name + * @param string $secretName + * + * @return array|string + */ + public function remove(int $id, string $name, string $secretName) + { + return $this->delete('/repositories/'.$id.'/environments/'.rawurlencode($name).'/secrets/'.rawurlencode($secretName)); + } + + /** + * @link https://docs.github.com/en/rest/actions/secrets?apiVersion=2022-11-28#get-an-environment-public-key + * + * @param int $id + * @param string $name + * + * @return array|string + */ + public function publicKey(int $id, string $name) + { + return $this->get('/repositories/'.$id.'/environments/'.rawurlencode($name).'/secrets/public-key'); + } +} diff --git a/lib/Github/Api/Environment/Variables.php b/lib/Github/Api/Environment/Variables.php new file mode 100644 index 00000000000..035a8f605a3 --- /dev/null +++ b/lib/Github/Api/Environment/Variables.php @@ -0,0 +1,81 @@ +get('/repositories/'.$id.'/environments/'.rawurlencode($name).'/variables'); + } + + /** + * @link https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#get-an-environment-variable + * + * @param int $id + * @param string $name + * @param string $variableName + * + * @return array|string + */ + public function show(int $id, string $name, string $variableName) + { + return $this->get('/repositories/'.$id.'/environments/'.rawurlencode($name).'/variables/'.rawurlencode($variableName)); + } + + /** + * @link https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#create-an-environment-variable + * + * @param int $id + * @param string $name + * @param array $parameters + * + * @return array|string + */ + public function create(int $id, string $name, array $parameters) + { + return $this->post('/repositories/'.$id.'/environments/'.rawurlencode($name).'/variables', $parameters); + } + + /** + * @link https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#update-an-environment-variable + * + * @param int $id + * @param string $name + * @param string $variableName + * @param array $parameters + * + * @return array|string + */ + public function update(int $id, string $name, string $variableName, array $parameters) + { + return $this->patch('/repositories/'.$id.'/environments/'.rawurlencode($name).'/variables/'.rawurlencode($variableName), $parameters); + } + + /** + * @link https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#delete-an-environment-variable + * + * @param int $id + * @param string $name + * @param string $variableName + * + * @return array|string + */ + public function remove(int $id, string $name, string $variableName) + { + return $this->delete('/repositories/'.$id.'/environments/'.rawurlencode($name).'/variables/'.rawurlencode($variableName)); + } +} diff --git a/lib/Github/Api/Gist/Comments.php b/lib/Github/Api/Gist/Comments.php new file mode 100644 index 00000000000..31587d94016 --- /dev/null +++ b/lib/Github/Api/Gist/Comments.php @@ -0,0 +1,101 @@ + + */ +class Comments extends AbstractApi +{ + use AcceptHeaderTrait; + + /** + * Configure the body type. + * + * @link https://developer.github.com/v3/gists/comments/#custom-media-types + * + * @param string|null $bodyType + * + * @return $this + */ + public function configure($bodyType = null) + { + if (!in_array($bodyType, ['text', 'html', 'full'])) { + $bodyType = 'raw'; + } + + $this->acceptHeaderValue = sprintf('application/vnd.github.%s.%s+json', $this->getApiVersion(), $bodyType); + + return $this; + } + + /** + * Get all comments for a gist. + * + * @param string $gist + * + * @return array + */ + public function all($gist) + { + return $this->get('/gists/'.rawurlencode($gist).'/comments'); + } + + /** + * Get a comment of a gist. + * + * @param string $gist + * @param int $comment + * + * @return array + */ + public function show($gist, $comment) + { + return $this->get('/gists/'.rawurlencode($gist).'/comments/'.$comment); + } + + /** + * Create a comment for gist. + * + * @param string $gist + * @param string $body + * + * @return array + */ + public function create($gist, $body) + { + return $this->post('/gists/'.rawurlencode($gist).'/comments', ['body' => $body]); + } + + /** + * Create a comment for a gist. + * + * @param string $gist + * @param int $comment_id + * @param string $body + * + * @return array + */ + public function update($gist, $comment_id, $body) + { + return $this->patch('/gists/'.rawurlencode($gist).'/comments/'.$comment_id, ['body' => $body]); + } + + /** + * Delete a comment for a gist. + * + * @param string $gist + * @param int $comment + * + * @return array + */ + public function remove($gist, $comment) + { + return $this->delete('/gists/'.rawurlencode($gist).'/comments/'.$comment); + } +} diff --git a/lib/Github/Api/Gists.php b/lib/Github/Api/Gists.php index 7514d99e6ff..42bbdb9c97b 100644 --- a/lib/Github/Api/Gists.php +++ b/lib/Github/Api/Gists.php @@ -2,30 +2,78 @@ namespace Github\Api; -use Github\Api\AbstractApi; +use Github\Api\Gist\Comments; use Github\Exception\MissingArgumentException; /** - * Creating, editing, deleting and listing gists + * Creating, editing, deleting and listing gists. * * @link http://developer.github.com/v3/gists/ + * * @author Joseph Bielawski * @author Edoardo Rivello */ class Gists extends AbstractApi { + use AcceptHeaderTrait; + + /** + * Configure the body type. + * + * @link https://developer.github.com/v3/gists/#custom-media-types + * + * @param string|null $bodyType + * + * @return $this + */ + public function configure($bodyType = null) + { + if ('base64' !== $bodyType) { + $bodyType = 'raw'; + } + + $this->acceptHeaderValue = sprintf('application/vnd.github.%s.%s', $this->getApiVersion(), $bodyType); + + return $this; + } + + /** + * @param string|null $type + * + * @return array|string + */ public function all($type = null) { - if (!in_array($type, array('public', 'starred'))) { - return $this->get('gists'); + if (!in_array($type, ['public', 'starred'])) { + return $this->get('/gists'); } - return $this->get('gists/'.rawurlencode($type)); + return $this->get('/gists/'.rawurlencode($type)); } + /** + * @param string $number + * + * @return array + */ public function show($number) { - return $this->get('gists/'.rawurlencode($number)); + return $this->get('/gists/'.rawurlencode($number)); + } + + /** + * Get a specific revision of a gist. + * + * @param string $number + * @param string $sha + * + * @link https://developer.github.com/v3/gists/#get-a-specific-revision-of-a-gist + * + * @return array + */ + public function revision($number, $sha) + { + return $this->get('/gists/'.rawurlencode($number).'/'.rawurlencode($sha)); } public function create(array $params) @@ -34,38 +82,101 @@ public function create(array $params) throw new MissingArgumentException('files'); } - $params['public'] = (boolean) $params['public']; + $params['public'] = (bool) $params['public']; - return $this->post('gists', $params); + return $this->post('/gists', $params); } + /** + * @param string $id + * @param array $params + * + * @return array + */ public function update($id, array $params) { - return $this->patch('gists/'.rawurlencode($id), $params); + return $this->patch('/gists/'.rawurlencode($id), $params); } + /** + * @param string $id + * + * @return array + */ + public function commits($id) + { + return $this->get('/gists/'.rawurlencode($id).'/commits'); + } + + /** + * @param string $id + * + * @return array + */ public function fork($id) { - return $this->post('gists/'.rawurlencode($id).'/fork'); + return $this->post('/gists/'.rawurlencode($id).'/fork'); + } + + /** + * @param string $id + * + * @return array + */ + public function forks($id) + { + return $this->get('/gists/'.rawurlencode($id).'/forks'); } + /** + * @param string $id + * + * @return array + */ public function remove($id) { - return $this->delete('gists/'.rawurlencode($id)); + return $this->delete('/gists/'.rawurlencode($id)); } + /** + * @param string $id + * + * @return array + */ public function check($id) { - return $this->get('gists/'.rawurlencode($id).'/star'); + return $this->get('/gists/'.rawurlencode($id).'/star'); } + /** + * @param string $id + * + * @return array + */ public function star($id) { - return $this->put('gists/'.rawurlencode($id).'/star'); + return $this->put('/gists/'.rawurlencode($id).'/star'); } + /** + * @param string $id + * + * @return array + */ public function unstar($id) { - return $this->delete('gists/'.rawurlencode($id).'/star'); + return $this->delete('/gists/'.rawurlencode($id).'/star'); + } + + /** + * Get a gist's comments. + * + * @link http://developer.github.com/v3/gists/comments/ + * + * @return Comments + */ + public function comments() + { + return new Comments($this->getClient()); } } diff --git a/lib/Github/Api/GitData.php b/lib/Github/Api/GitData.php index 21395a8ba7a..b7a9f48c344 100644 --- a/lib/Github/Api/GitData.php +++ b/lib/Github/Api/GitData.php @@ -12,6 +12,7 @@ * Getting full versions of specific files and trees in your Git repositories. * * @link http://developer.github.com/v3/git/ + * * @author Joseph Bielawski */ class GitData extends AbstractApi @@ -21,7 +22,7 @@ class GitData extends AbstractApi */ public function blobs() { - return new Blobs($this->client); + return new Blobs($this->getClient()); } /** @@ -29,7 +30,7 @@ public function blobs() */ public function commits() { - return new Commits($this->client); + return new Commits($this->getClient()); } /** @@ -37,7 +38,7 @@ public function commits() */ public function references() { - return new References($this->client); + return new References($this->getClient()); } /** @@ -45,7 +46,7 @@ public function references() */ public function tags() { - return new Tags($this->client); + return new Tags($this->getClient()); } /** @@ -53,6 +54,6 @@ public function tags() */ public function trees() { - return new Trees($this->client); + return new Trees($this->getClient()); } } diff --git a/lib/Github/Api/GitData/Blobs.php b/lib/Github/Api/GitData/Blobs.php index 2ff844db24a..31aacda5674 100644 --- a/lib/Github/Api/GitData/Blobs.php +++ b/lib/Github/Api/GitData/Blobs.php @@ -3,36 +3,66 @@ namespace Github\Api\GitData; use Github\Api\AbstractApi; +use Github\Api\AcceptHeaderTrait; use Github\Exception\MissingArgumentException; /** * @link http://developer.github.com/v3/git/blobs/ + * * @author Joseph Bielawski + * @author Tobias Nyholm */ class Blobs extends AbstractApi { + use AcceptHeaderTrait; + + /** + * Configure the Accept header depending on the blob type. + * + * @param string|null $bodyType + * + * @return $this + */ public function configure($bodyType = null) { - if ('raw' == $bodyType) { - $this->client->setHeaders(array( - 'Accept' => sprintf('application/vnd.github.%s.raw', $this->client->getOption('api_version')) - )); + if ('raw' === $bodyType) { + $this->acceptHeaderValue = sprintf('application/vnd.github.%s.raw', $this->getApiVersion()); } + + return $this; } + /** + * Show a blob of a sha for a repository. + * + * @param string $username + * @param string $repository + * @param string $sha + * + * @return array + */ public function show($username, $repository, $sha) { - $response = $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/blobs/'.rawurlencode($sha)); - - return $response; + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/blobs/'.rawurlencode($sha)); } + /** + * Create a blob of a sha for a repository. + * + * @param string $username + * @param string $repository + * @param array $params + * + * @throws \Github\Exception\MissingArgumentException + * + * @return array + */ public function create($username, $repository, array $params) { - if (!isset($params['content'], $params['encoding'])) { - throw new MissingArgumentException(array('content', 'encoding')); + if (!isset($params['content'])) { + throw new MissingArgumentException('content'); } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/blobs', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/blobs', $params); } } diff --git a/lib/Github/Api/GitData/Commits.php b/lib/Github/Api/GitData/Commits.php index 1c161e1d790..4205931f408 100644 --- a/lib/Github/Api/GitData/Commits.php +++ b/lib/Github/Api/GitData/Commits.php @@ -7,21 +7,42 @@ /** * @link http://developer.github.com/v3/git/commits/ + * * @author Joseph Bielawski */ class Commits extends AbstractApi { + /** + * Show a commit for a repository. + * + * @param string $username + * @param string $repository + * @param string $sha + * + * @return array + */ public function show($username, $repository, $sha) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/commits/'.rawurlencode($sha)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/commits/'.rawurlencode($sha)); } + /** + * Create a commit for a repository. + * + * @param string $username + * @param string $repository + * @param array $params + * + * @throws \Github\Exception\MissingArgumentException + * + * @return array + */ public function create($username, $repository, array $params) { if (!isset($params['message'], $params['tree'], $params['parents'])) { - throw new MissingArgumentException(array('message', 'tree', 'parents')); + throw new MissingArgumentException(['message', 'tree', 'parents']); } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/commits', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/commits', $params); } } diff --git a/lib/Github/Api/GitData/References.php b/lib/Github/Api/GitData/References.php index 70d8fa37afa..d67cbe512b9 100644 --- a/lib/Github/Api/GitData/References.php +++ b/lib/Github/Api/GitData/References.php @@ -7,50 +7,150 @@ /** * @link http://developer.github.com/v3/git/references/ + * * @author Joseph Bielawski */ class References extends AbstractApi { + /** + * Get all references of a repository. + * + * @param string $username + * @param string $repository + * + * @return array + */ public function all($username, $repository) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/refs'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/refs'); } + /** + * Get all matching references for the supplied reference name. + * + * @param string $username + * @param string $repository + * @param string $reference + * + * @return array + */ + public function matching(string $username, string $repository, string $reference): array + { + $reference = $this->encodeReference($reference); + + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/matching-refs/'.$reference); + } + + /** + * Get all branches of a repository. + * + * @param string $username + * @param string $repository + * + * @return array + */ public function branches($username, $repository) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/refs/heads'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/refs/heads'); } + /** + * Get all tags of a repository. + * + * @param string $username + * @param string $repository + * + * @return array + */ public function tags($username, $repository) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/refs/tags'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/refs/tags'); } + /** + * Show the reference of a repository. + * + * @param string $username + * @param string $repository + * @param string $reference + * + * @return array + */ public function show($username, $repository, $reference) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/refs/'.rawurlencode($reference)); + $reference = $this->encodeReference($reference); + + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/refs/'.$reference); } + /** + * Create a reference for a repository. + * + * @param string $username + * @param string $repository + * @param array $params + * + * @throws \Github\Exception\MissingArgumentException + * + * @return array + */ public function create($username, $repository, array $params) { if (!isset($params['ref'], $params['sha'])) { - throw new MissingArgumentException(array('ref', 'sha')); + throw new MissingArgumentException(['ref', 'sha']); } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/refs', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/refs', $params); } + /** + * Update a reference for a repository. + * + * @param string $username + * @param string $repository + * @param string $reference + * @param array $params + * + * @throws \Github\Exception\MissingArgumentException + * + * @return array + */ public function update($username, $repository, $reference, array $params) { if (!isset($params['sha'])) { throw new MissingArgumentException('sha'); } - return $this->patch('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/refs/'.rawurlencode($reference), $params); + $reference = $this->encodeReference($reference); + + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/refs/'.$reference, $params); } + /** + * Delete a reference of a repository. + * + * @param string $username + * @param string $repository + * @param string $reference + * + * @return array + */ public function remove($username, $repository, $reference) { - return $this->delete('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/refs/'.rawurlencode($reference)); + $reference = $this->encodeReference($reference); + + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/refs/'.$reference); + } + + /** + * Encode the raw reference. + * + * @param string $rawReference + * + * @return string + */ + private function encodeReference($rawReference) + { + return implode('/', array_map('rawurlencode', explode('/', $rawReference))); } } diff --git a/lib/Github/Api/GitData/Tags.php b/lib/Github/Api/GitData/Tags.php index b27dddd12f4..11bf200a31f 100644 --- a/lib/Github/Api/GitData/Tags.php +++ b/lib/Github/Api/GitData/Tags.php @@ -7,34 +7,59 @@ /** * @link http://developer.github.com/v3/git/tags/ + * * @author Joseph Bielawski */ class Tags extends AbstractApi { + /** + * Get all tags for a repository. + * + * @param string $username + * @param string $repository + * + * @return array + */ public function all($username, $repository) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/refs/tags'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/refs/tags'); } + /** + * Get a tag for a repository. + * + * @param string $username + * @param string $repository + * @param string $sha + * + * @return array + */ public function show($username, $repository, $sha) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/tags/'.rawurlencode($sha)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/tags/'.rawurlencode($sha)); } + /** + * Create a tag for a repository. + * + * @param string $username + * @param string $repository + * @param array $params + * + * @throws \Github\Exception\MissingArgumentException + * + * @return array + */ public function create($username, $repository, array $params) { if (!isset($params['tag'], $params['message'], $params['object'], $params['type'])) { - throw new MissingArgumentException(array('tag', 'message', 'object', 'type')); + throw new MissingArgumentException(['tag', 'message', 'object', 'type']); } - if (!isset($params['tagger'])) { - throw new MissingArgumentException('tagger'); + if (isset($params['tagger']) && !isset($params['tagger']['name'], $params['tagger']['email'], $params['tagger']['date'])) { + throw new MissingArgumentException(['tagger.name', 'tagger.email', 'tagger.date']); } - if (!isset($params['tagger']['name'], $params['tagger']['email'], $params['tagger']['date'])) { - throw new MissingArgumentException(array('tagger.name', 'tagger.email', 'tagger.date')); - } - - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/tags', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/tags', $params); } } diff --git a/lib/Github/Api/GitData/Trees.php b/lib/Github/Api/GitData/Trees.php index 92bd21ac433..939e8619b73 100644 --- a/lib/Github/Api/GitData/Trees.php +++ b/lib/Github/Api/GitData/Trees.php @@ -7,15 +7,37 @@ /** * @link http://developer.github.com/v3/git/trees/ + * * @author Joseph Bielawski */ class Trees extends AbstractApi { + /** + * Get the tree for a repository. + * + * @param string $username + * @param string $repository + * @param string $sha + * @param bool $recursive + * + * @return array + */ public function show($username, $repository, $sha, $recursive = false) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/trees/'.rawurlencode($sha), array('recursive' => $recursive ? 1 : null)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/trees/'.rawurlencode($sha), $recursive ? ['recursive' => 1] : []); } + /** + * Create tree for a repository. + * + * @param string $username + * @param string $repository + * @param array $params + * + * @throws \Github\Exception\MissingArgumentException + * + * @return array + */ public function create($username, $repository, array $params) { if (!isset($params['tree']) || !is_array($params['tree'])) { @@ -23,20 +45,20 @@ public function create($username, $repository, array $params) } if (!isset($params['tree'][0])) { - $params['tree'] = array($params['tree']); + $params['tree'] = [$params['tree']]; } foreach ($params['tree'] as $key => $tree) { if (!isset($tree['path'], $tree['mode'], $tree['type'])) { - throw new MissingArgumentException(array("tree.$key.path", "tree.$key.mode", "tree.$key.type")); + throw new MissingArgumentException(["tree.$key.path", "tree.$key.mode", "tree.$key.type"]); } // If `sha` is not set, `content` is required - if (!isset($tree['sha']) && !isset($tree['content'])) { + if (!array_key_exists('sha', $tree) && !isset($tree['content'])) { throw new MissingArgumentException("tree.$key.content"); } } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/trees', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/git/trees', $params); } } diff --git a/lib/Github/Api/GraphQL.php b/lib/Github/Api/GraphQL.php new file mode 100644 index 00000000000..02499ad8ef7 --- /dev/null +++ b/lib/Github/Api/GraphQL.php @@ -0,0 +1,48 @@ + + */ +class GraphQL extends AbstractApi +{ + use AcceptHeaderTrait; + + /** + * @param string $query + * @param array $variables + * @param string $acceptHeaderValue + * + * @return array + */ + public function execute($query, array $variables = [], string $acceptHeaderValue = 'application/vnd.github.v4+json') + { + $this->acceptHeaderValue = $acceptHeaderValue; + $params = [ + 'query' => $query, + ]; + if (!empty($variables)) { + $params['variables'] = json_encode($variables); + } + + return $this->post('/graphql', $params); + } + + /** + * @param string $file + * @param array $variables + * + * @return array + */ + public function fromFile($file, array $variables = []) + { + return $this->execute(file_get_contents($file), $variables); + } +} diff --git a/lib/Github/Api/Issue.php b/lib/Github/Api/Issue.php index c4aae96e994..764f5e442a9 100644 --- a/lib/Github/Api/Issue.php +++ b/lib/Github/Api/Issue.php @@ -2,165 +2,240 @@ namespace Github\Api; +use Github\Api\Issue\Assignees; use Github\Api\Issue\Comments; use Github\Api\Issue\Events; use Github\Api\Issue\Labels; use Github\Api\Issue\Milestones; +use Github\Api\Issue\Timeline; use Github\Exception\MissingArgumentException; /** * Listing issues, searching, editing and closing your projects issues. * * @link http://develop.github.com/p/issues.html + * * @author Thibault Duplessis * @author Joseph Bielawski */ class Issue extends AbstractApi { + use AcceptHeaderTrait; + /** - * List issues by username, repo and state - * @link http://developer.github.com/v3/issues/ + * Configure the body type. + * + * @link https://developer.github.com/v3/issues/#custom-media-types * - * @param string $username the username - * @param string $repository the repository - * @param array $params the additional parameters like milestone, assignees, labels, sort, direction - * @return array list of issues found + * @param string|null $bodyType + * + * @return $this */ - public function all($username, $repository, array $params = array()) + public function configure($bodyType = null) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues', array_merge(array('page' => 1), $params)); + if (!in_array($bodyType, ['text', 'html', 'full'])) { + $bodyType = 'raw'; + } + + $this->acceptHeaderValue = sprintf('application/vnd.github.%s.%s+json', $this->getApiVersion(), $bodyType); + + return $this; } /** - * Search issues by username, repo, state and keyword - * @link http://developer.github.com/v3/search/#search-issues + * List issues by username, repo and state. + * + * @link http://developer.github.com/v3/issues/ * * @param string $username the username * @param string $repository the repository - * @param string $state the issue state, can be open or closed - * @param string $keyword the keyword to filter issues by + * @param array $params the additional parameters like milestone, assignees, labels, sort, direction * * @return array list of issues found */ - public function find($username, $repository, $state, $keyword) + public function all($username, $repository, array $params = []) { - if (!in_array($state, array('open', 'closed'))) { - $state = 'open'; - } - - return $this->get('legacy/issues/search/'.rawurlencode($username).'/'.rawurlencode($repository).'/'.rawurlencode($state).'/'.rawurlencode($keyword)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues', array_merge(['page' => 1], $params)); } /** - * List issues by organization + * List issues by organization. + * * @link http://developer.github.com/v3/issues/ * - * @param string $organization the organization - * @param string $state the issue state, can be open or closed - * @param array $params the additional parameters like milestone, assignees, labels, sort, direction - * @return array list of issues found + * @param string $organization the organization + * @param string $state the issue state, can be open or closed + * @param array $params the additional parameters like milestone, assignees, labels, sort, direction + * + * @return array list of issues found */ - public function org($organization, $state, array $params = array()) + public function org($organization, $state, array $params = []) { - if (!in_array($state, array('open', 'closed'))) { + if (!in_array($state, ['open', 'closed'])) { $state = 'open'; } - return $this->get('orgs/'.rawurlencode($organization).'/issues', array_merge(array('page' => 1, 'state' => $state), $params)); + return $this->get('/orgs/'.rawurlencode($organization).'/issues', array_merge(['page' => 1, 'state' => $state], $params)); } /** - * Get extended information about an issue by its username, repo and number + * Get extended information about an issue by its username, repo and number. + * * @link http://developer.github.com/v3/issues/ * - * @param string $username the username - * @param string $repository the repository - * @param string $id the issue number - * @return array information about the issue + * @param string $username the username + * @param string $repository the repository + * @param int $id the issue number + * + * @return array information about the issue */ public function show($username, $repository, $id) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.rawurlencode($id)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.$id); } /** * Create a new issue for the given username and repo. * The issue is assigned to the authenticated user. Requires authentication. + * * @link http://developer.github.com/v3/issues/ * - * @param string $username the username - * @param string $repository the repository - * @param array $params the new issue data - * @return array information about the issue + * @param string $username the username + * @param string $repository the repository + * @param array $params the new issue data * * @throws MissingArgumentException + * + * @return array information about the issue */ public function create($username, $repository, array $params) { - if (!isset($params['title'], $params['body'])) { - throw new MissingArgumentException(array('title', 'body')); + if (!isset($params['title'])) { + throw new MissingArgumentException(['title']); } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues', $params); } /** * Update issue information's by username, repo and issue number. Requires authentication. + * * @link http://developer.github.com/v3/issues/ * * @param string $username the username * @param string $repository the repository - * @param string $id the issue number + * @param int $id the issue number * @param array $params key=>value user attributes to update. * key can be title or body + * * @return array information about the issue */ public function update($username, $repository, $id, array $params) { - return $this->patch('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.rawurlencode($id), $params); + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.$id, $params); + } + + /** + * Lock an issue. Users with push access can lock an issue's conversation. + * + * @link https://developer.github.com/v3/issues/#lock-an-issue + * + * @param string $username + * @param string $repository + * @param int $id + * + * @return string + */ + public function lock($username, $repository, $id) + { + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.$id.'/lock'); + } + + /** + * Unlock an issue. Users with push access can unlock an issue's conversation. + * + * @link https://developer.github.com/v3/issues/#lock-an-issue + * + * @param string $username + * @param string $repository + * @param int $id + * + * @return string + */ + public function unlock($username, $repository, $id) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.$id.'/lock'); } /** - * List an issue comments + * List an issue comments. + * * @link http://developer.github.com/v3/issues/comments/ * * @return Comments */ public function comments() { - return new Comments($this->client); + return new Comments($this->getClient()); } /** - * List all project events + * List all project events. + * * @link http://developer.github.com/v3/issues/events/ * * @return Events */ public function events() { - return new Events($this->client); + return new Events($this->getClient()); } /** - * List all project labels + * List all project labels. + * * @link http://developer.github.com/v3/issues/labels/ * * @return Labels */ public function labels() { - return new Labels($this->client); + return new Labels($this->getClient()); } /** - * List all project milestones + * List all project milestones. + * * @link http://developer.github.com/v3/issues/milestones/ * * @return Milestones */ public function milestones() { - return new Milestones($this->client); + return new Milestones($this->getClient()); + } + + /** + * List all assignees. + * + * @link https://developer.github.com/v3/issues/assignees/ + * + * @return Assignees + */ + public function assignees() + { + return new Assignees($this->getClient()); + } + + /** + * List all events. + * + * @link https://developer.github.com/v3/issues/timeline/ + * + * @return Timeline + */ + public function timeline() + { + return new Timeline($this->getClient()); } } diff --git a/lib/Github/Api/Issue/Assignees.php b/lib/Github/Api/Issue/Assignees.php new file mode 100644 index 00000000000..46435650823 --- /dev/null +++ b/lib/Github/Api/Issue/Assignees.php @@ -0,0 +1,91 @@ +get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/assignees', $parameters); + } + + /** + * Check to see if a particular user is an assignee for a repository. + * + * @link https://developer.github.com/v3/issues/assignees/#check-assignee + * + * @param string $username + * @param string $repository + * @param string $assignee + * + * @return array + */ + public function check($username, $repository, $assignee) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/assignees/'.rawurlencode($assignee)); + } + + /** + * Add assignees to an Issue. + * + * @link https://developer.github.com/v3/issues/assignees/#add-assignees-to-an-issue + * + * @param string $username + * @param string $repository + * @param string $issue + * @param array $parameters + * + * @throws InvalidArgumentException + * @throws MissingArgumentException + * + * @return array + */ + public function add($username, $repository, $issue, array $parameters) + { + if (!isset($parameters['assignees'])) { + throw new MissingArgumentException('assignees'); + } + + if (!is_array($parameters['assignees'])) { + throw new InvalidArgumentException('The assignees parameter should be an array of assignees'); + } + + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.rawurlencode($issue).'/assignees', $parameters); + } + + /** + * Remove assignees from an Issue. + * + * @link https://developer.github.com/v3/issues/assignees/#remove-assignees-from-an-issue + * + * @param string $username + * @param string $repository + * @param string $issue + * @param array $parameters + * + * @throws MissingArgumentException + * + * @return array + */ + public function remove($username, $repository, $issue, array $parameters) + { + if (!isset($parameters['assignees'])) { + throw new MissingArgumentException('assignees'); + } + + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.rawurlencode($issue).'/assignees', $parameters); + } +} diff --git a/lib/Github/Api/Issue/Comments.php b/lib/Github/Api/Issue/Comments.php index ae6370fc660..b0fe878797f 100644 --- a/lib/Github/Api/Issue/Comments.php +++ b/lib/Github/Api/Issue/Comments.php @@ -3,68 +3,131 @@ namespace Github\Api\Issue; use Github\Api\AbstractApi; +use Github\Api\AcceptHeaderTrait; use Github\Exception\MissingArgumentException; /** * @link http://developer.github.com/v3/issues/comments/ + * * @author Joseph Bielawski + * @author Tobias Nyholm */ class Comments extends AbstractApi { + use AcceptHeaderTrait; + + /** + * Configure the body type. + * + * @link https://developer.github.com/v3/issues/comments/#custom-media-types + * + * @param string|null $bodyType + * + * @return $this + */ public function configure($bodyType = null) { - switch ($bodyType) { - case 'raw': - $header = sprintf('Accept: application/vnd.github.%s.raw+json', $this->client->getOption('api_version')); - break; - - case 'text': - $header = sprintf('Accept: application/vnd.github.%s.text+json', $this->client->getOption('api_version')); - break; - - case 'html': - $header = sprintf('Accept: application/vnd.github.%s.html+json', $this->client->getOption('api_version')); - break; - - default: - $header = sprintf('Accept: application/vnd.github.%s.full+json', $this->client->getOption('api_version')); + if (!in_array($bodyType, ['raw', 'text', 'html'])) { + $bodyType = 'full'; } - $this->client->setHeaders(array($header)); + $this->acceptHeaderValue = sprintf('application/vnd.github.%s.%s+json', $this->getApiVersion(), $bodyType); + + return $this; } - public function all($username, $repository, $issue, $page = 1) + /** + * Get all comments for an issue. + * + * @link https://developer.github.com/v3/issues/comments/#list-comments-on-an-issue + * + * @param string $username + * @param string $repository + * @param int $issue + * @param array $params + * + * @return array + */ + public function all($username, $repository, $issue, array $params = []) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.rawurlencode($issue).'/comments', array( - 'page' => $page - )); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.$issue.'/comments', $params); } + /** + * Get a comment for an issue. + * + * @link https://developer.github.com/v3/issues/comments/#get-a-single-comment + * + * @param string $username + * @param string $repository + * @param int $comment + * + * @return array + */ public function show($username, $repository, $comment) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/comments/'.rawurlencode($comment)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/comments/'.$comment); } + /** + * Create a comment for an issue. + * + * @link https://developer.github.com/v3/issues/comments/#create-a-comment + * + * @param string $username + * @param string $repository + * @param int $issue + * @param array $params + * + * @throws \Github\Exception\MissingArgumentException + * + * @return array + */ public function create($username, $repository, $issue, array $params) { if (!isset($params['body'])) { throw new MissingArgumentException('body'); } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.rawurlencode($issue).'/comments', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.$issue.'/comments', $params); } + /** + * Update a comment for an issue. + * + * @link https://developer.github.com/v3/issues/comments/#edit-a-comment + * + * @param string $username + * @param string $repository + * @param int $comment + * @param array $params + * + * @throws \Github\Exception\MissingArgumentException + * + * @return array + */ public function update($username, $repository, $comment, array $params) { if (!isset($params['body'])) { throw new MissingArgumentException('body'); } - return $this->patch('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/comments/'.rawurlencode($comment), $params); + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/comments/'.$comment, $params); } + /** + * Delete a comment for an issue. + * + * @link https://developer.github.com/v3/issues/comments/#delete-a-comment + * + * @param string $username + * @param string $repository + * @param int $comment + * + * @return array + */ public function remove($username, $repository, $comment) { - return $this->delete('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/comments/'.rawurlencode($comment)); + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/comments/'.$comment); } } diff --git a/lib/Github/Api/Issue/Events.php b/lib/Github/Api/Issue/Events.php index 17bcef83921..a628b2c60bf 100644 --- a/lib/Github/Api/Issue/Events.php +++ b/lib/Github/Api/Issue/Events.php @@ -6,25 +6,49 @@ /** * @link http://developer.github.com/v3/issues/events/ + * * @author Joseph Bielawski */ class Events extends AbstractApi { + /** + * Get all events for an issue. + * + * @link https://developer.github.com/v3/issues/events/#list-events-for-an-issue + * + * @param string $username + * @param string $repository + * @param int|null $issue + * @param int $page + * + * @return array + */ public function all($username, $repository, $issue = null, $page = 1) { if (null !== $issue) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.rawurlencode($issue).'/events', array( - 'page' => $page - )); + $path = '/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.$issue.'/events'; + } else { + $path = '/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/events'; } - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/events', array( - 'page' => $page - )); + return $this->get($path, [ + 'page' => $page, + ]); } + /** + * Display an event for an issue. + * + * @link https://developer.github.com/v3/issues/events/#get-a-single-event + * + * @param string $username + * @param string $repository + * @param string $event + * + * @return array + */ public function show($username, $repository, $event) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/events/'.rawurlencode($event)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/events/'.rawurlencode($event)); } } diff --git a/lib/Github/Api/Issue/Labels.php b/lib/Github/Api/Issue/Labels.php index 5628201f50c..3cfad23d5b0 100644 --- a/lib/Github/Api/Issue/Labels.php +++ b/lib/Github/Api/Issue/Labels.php @@ -4,22 +4,66 @@ use Github\Api\AbstractApi; use Github\Exception\InvalidArgumentException; +use Github\Exception\MissingArgumentException; /** * @link http://developer.github.com/v3/issues/labels/ + * * @author Joseph Bielawski */ class Labels extends AbstractApi { + /** + * Get all labels for a repository or the labels for a specific issue. + * + * @link https://developer.github.com/v3/issues/labels/#list-labels-on-an-issue + * + * @param string $username + * @param string $repository + * @param int|null $issue + * + * @return array + */ public function all($username, $repository, $issue = null) { if ($issue === null) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels'); + $path = '/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels'; + } else { + $path = '/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.$issue.'/labels'; } - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.rawurlencode($issue).'/labels'); + return $this->get($path); } + /** + * Get a single label. + * + * @link https://developer.github.com/v3/issues/labels/#get-a-single-label + * + * @param string $username + * @param string $repository + * @param string $label + * + * @return array + */ + public function show($username, $repository, $label) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels/'.rawurlencode($label)); + } + + /** + * Create a label for a repository. + * + * @link https://developer.github.com/v3/issues/labels/#create-a-label + * + * @param string $username + * @param string $repository + * @param array $params + * + * @throws \Github\Exception\MissingArgumentException + * + * @return array + */ public function create($username, $repository, array $params) { if (!isset($params['name'])) { @@ -29,32 +73,120 @@ public function create($username, $repository, array $params) $params['color'] = 'FFFFFF'; } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels', $params); + } + + /** + * Delete a label for a repository. + * + * @link https://developer.github.com/v3/issues/labels/#remove-a-label-from-an-issue + * + * @param string $username + * @param string $repository + * @param string $label + * + * @return array + */ + public function deleteLabel($username, $repository, $label) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels/'.rawurlencode($label)); + } + + /** + * Edit a label for a repository. + * + * @link https://developer.github.com/v3/issues/labels/#update-a-label + * + * @param string $username + * @param string $repository + * @param string $label + * @param string $newName + * @param string $color + * + * @return array + */ + public function update($username, $repository, $label, $newName, $color) + { + $params = [ + 'name' => $newName, + 'color' => $color, + ]; + + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels/'.rawurlencode($label), $params); } + /** + * Add a label to an issue. + * + * @link https://developer.github.com/v3/issues/labels/#add-labels-to-an-issue + * + * @param string $username + * @param string $repository + * @param int $issue + * @param string|array $labels + * + * @return array + * + * @thorws \Github\Exception\InvalidArgumentException + */ public function add($username, $repository, $issue, $labels) { if (is_string($labels)) { - $labels = array($labels); + $labels = [$labels]; } elseif (0 === count($labels)) { - throw new InvalidArgumentException(); + throw new InvalidArgumentException('The labels parameter should be a single label or an array of labels'); } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.rawurlencode($issue).'/labels', $labels); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.$issue.'/labels', $labels); } + /** + * Replace labels for an issue. + * + * @link https://developer.github.com/v3/issues/labels/#replace-all-labels-for-an-issue + * + * @param string $username + * @param string $repository + * @param int $issue + * @param array $params + * + * @return array + */ public function replace($username, $repository, $issue, array $params) { - return $this->put('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.rawurlencode($issue).'/labels', $params); + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.$issue.'/labels', $params); } + /** + * Remove a label for an issue. + * + * @link https://developer.github.com/v3/issues/labels/#remove-a-label-from-an-issue + * + * @param string $username + * @param string $repository + * @param int $issue + * @param string $label + * + * @return array|string + */ public function remove($username, $repository, $issue, $label) { - return $this->delete('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.rawurlencode($issue).'/labels/'.rawurlencode($label)); + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.$issue.'/labels/'.rawurlencode($label)); } + /** + * Remove all labels from an issue. + * + * @link https://developer.github.com/v3/issues/labels/#replace-all-labels-for-an-issue + * + * @param string $username + * @param string $repository + * @param int $issue + * + * @return array|string + */ public function clear($username, $repository, $issue) { - return $this->delete('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.rawurlencode($issue).'/labels'); + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.$issue.'/labels'); } } diff --git a/lib/Github/Api/Issue/Milestones.php b/lib/Github/Api/Issue/Milestones.php index c13c4aebb2b..fe9f2296dd6 100644 --- a/lib/Github/Api/Issue/Milestones.php +++ b/lib/Github/Api/Issue/Milestones.php @@ -7,58 +7,133 @@ /** * @link http://developer.github.com/v3/issues/milestones/ + * * @author Joseph Bielawski */ class Milestones extends AbstractApi { - public function all($username, $repository, array $params = array()) + /** + * Get all milestones for a repository. + * + * @link https://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository + * + * @param string $username + * @param string $repository + * @param array $params + * + * @return array + */ + public function all($username, $repository, array $params = []) { - if (isset($params['state']) && !in_array($params['state'], array('open', 'closed'))) { + if (isset($params['state']) && !in_array($params['state'], ['open', 'closed', 'all'])) { $params['state'] = 'open'; } - if (isset($params['sort']) && !in_array($params['sort'], array('due_date', 'completeness'))) { + if (isset($params['sort']) && !in_array($params['sort'], ['due_date', 'completeness'])) { $params['sort'] = 'due_date'; } - if (isset($params['direction']) && !in_array($params['direction'], array('asc', 'desc'))) { - $params['direction'] = 'desc'; + if (isset($params['direction']) && !in_array($params['direction'], ['asc', 'desc'])) { + $params['direction'] = 'asc'; } - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/milestones', array_merge(array('page' => 1, 'state' => 'open', 'sort' => 'due_date', 'direction' => 'desc'), $params)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/milestones', array_merge([ + 'page' => 1, + 'state' => 'open', + 'sort' => 'due_date', + 'direction' => 'asc', + ], $params)); } + /** + * Get a milestone for a repository. + * + * @link https://developer.github.com/v3/issues/milestones/#get-a-single-milestone + * + * @param string $username + * @param string $repository + * @param int $id + * + * @return array + */ public function show($username, $repository, $id) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/milestones/'.rawurlencode($id)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/milestones/'.$id); } + /** + * Create a milestone for a repository. + * + * @link https://developer.github.com/v3/issues/milestones/#create-a-milestone + * + * @param string $username + * @param string $repository + * @param array $params + * + * @throws \Github\Exception\MissingArgumentException + * + * @return array + */ public function create($username, $repository, array $params) { if (!isset($params['title'])) { throw new MissingArgumentException('title'); } - if (isset($params['state']) && !in_array($params['state'], array('open', 'closed'))) { + if (isset($params['state']) && !in_array($params['state'], ['open', 'closed'])) { $params['state'] = 'open'; } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/milestones', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/milestones', $params); } - public function update($username, $repository, $milestone, array $params) + /** + * Update a milestone for a repository. + * + * @link https://developer.github.com/v3/issues/milestones/#update-a-milestone + * + * @param string $username + * @param string $repository + * @param int $id + * @param array $params + * + * @return array + */ + public function update($username, $repository, $id, array $params) { - if (isset($params['state']) && !in_array($params['state'], array('open', 'closed'))) { + if (isset($params['state']) && !in_array($params['state'], ['open', 'closed'])) { $params['state'] = 'open'; } - return $this->patch('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/milestones/'.rawurlencode($milestone), $params); + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/milestones/'.$id, $params); } - public function remove($username, $repository, $milestone) + /** + * Delete a milestone for a repository. + * + * @link https://developer.github.com/v3/issues/milestones/#delete-a-milestone + * + * @param string $username + * @param string $repository + * @param int $id + * + * @return array|string + */ + public function remove($username, $repository, $id) { - return $this->delete('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/milestones/'.rawurlencode($milestone)); + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/milestones/'.$id); } - public function labels($username, $repository, $milestone) + /** + * Get the labels of a milestone. + * + * @link https://developer.github.com/v3/issues/labels/#get-labels-for-every-issue-in-a-milestone + * + * @param string $username + * @param string $repository + * @param int $id + * + * @return array + */ + public function labels($username, $repository, $id) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/milestones/'.rawurlencode($milestone).'/labels'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/milestones/'.$id.'/labels'); } } diff --git a/lib/Github/Api/Issue/Timeline.php b/lib/Github/Api/Issue/Timeline.php new file mode 100644 index 00000000000..16ec4b069b2 --- /dev/null +++ b/lib/Github/Api/Issue/Timeline.php @@ -0,0 +1,34 @@ +acceptHeaderValue = 'application/vnd.github.mockingbird-preview'; + + return $this; + } + + /** + * Get all events for a specific issue. + * + * @link https://developer.github.com/v3/issues/timeline/#list-events-for-an-issue + * + * @param string $username + * @param string $repository + * @param int $issue + * + * @return array + */ + public function all($username, $repository, $issue) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/issues/'.$issue.'/timeline'); + } +} diff --git a/lib/Github/Api/Markdown.php b/lib/Github/Api/Markdown.php index 8620ee86757..977b1d048e0 100644 --- a/lib/Github/Api/Markdown.php +++ b/lib/Github/Api/Markdown.php @@ -3,9 +3,10 @@ namespace Github\Api; /** - * Markdown Rendering API + * Markdown Rendering API. * * @link http://developer.github.com/v3/markdown/ + * * @author Joseph Bielawski */ class Markdown extends AbstractApi @@ -19,19 +20,19 @@ class Markdown extends AbstractApi */ public function render($text, $mode = 'markdown', $context = null) { - if (!in_array($mode, array('gfm', 'markdown'))) { + if (!in_array($mode, ['gfm', 'markdown'])) { $mode = 'markdown'; } - $params = array( + $params = [ 'text' => $text, - 'mode' => $mode - ); + 'mode' => $mode, + ]; if (null !== $context && 'gfm' === $mode) { $params['context'] = $context; } - return $this->post('markdown', $params); + return $this->post('/markdown', $params); } /** @@ -41,8 +42,8 @@ public function render($text, $mode = 'markdown', $context = null) */ public function renderRaw($file) { - return $this->post('markdown/raw', array( - 'file' => $file - )); + return $this->post('/markdown/raw', [ + 'file' => $file, + ]); } } diff --git a/lib/Github/Api/Meta.php b/lib/Github/Api/Meta.php new file mode 100644 index 00000000000..0ec81f65ef9 --- /dev/null +++ b/lib/Github/Api/Meta.php @@ -0,0 +1,23 @@ + + */ +class Meta extends AbstractApi +{ + /** + * Get the ip address of the hook and git servers for the GitHub.com service. + * + * @return array Information about the service of GitHub.com + */ + public function service() + { + return $this->get('/meta'); + } +} diff --git a/lib/Github/Api/Miscellaneous/CodeOfConduct.php b/lib/Github/Api/Miscellaneous/CodeOfConduct.php new file mode 100644 index 00000000000..64bfaa8b420 --- /dev/null +++ b/lib/Github/Api/Miscellaneous/CodeOfConduct.php @@ -0,0 +1,44 @@ +acceptHeaderValue = 'application/vnd.github.scarlet-witch-preview+json'; + + return $this; + } + + /** + * List all codes of conduct. + * + * @link https://developer.github.com/v3/codes_of_conduct/#list-all-codes-of-conduct + * + * @return array + */ + public function all() + { + return $this->get('/codes_of_conduct'); + } + + /** + * Get an individual code of conduct. + * + * @link https://developer.github.com/v3/codes_of_conduct/#get-an-individual-code-of-conduct + * + * @param string $key + * + * @return array + */ + public function show($key) + { + return $this->get('/codes_of_conduct/'.rawurlencode($key)); + } +} diff --git a/lib/Github/Api/Miscellaneous/Emojis.php b/lib/Github/Api/Miscellaneous/Emojis.php new file mode 100644 index 00000000000..2a940f6dfb7 --- /dev/null +++ b/lib/Github/Api/Miscellaneous/Emojis.php @@ -0,0 +1,20 @@ +get('/emojis'); + } +} diff --git a/lib/Github/Api/Miscellaneous/Gitignore.php b/lib/Github/Api/Miscellaneous/Gitignore.php new file mode 100644 index 00000000000..c5f03e7e0e0 --- /dev/null +++ b/lib/Github/Api/Miscellaneous/Gitignore.php @@ -0,0 +1,34 @@ +get('/gitignore/templates'); + } + + /** + * Get a single template. + * + * @link https://developer.github.com/v3/gitignore/#get-a-single-template + * + * @param string $template + * + * @return array + */ + public function show($template) + { + return $this->get('/gitignore/templates/'.rawurlencode($template)); + } +} diff --git a/lib/Github/Api/Miscellaneous/Licenses.php b/lib/Github/Api/Miscellaneous/Licenses.php new file mode 100644 index 00000000000..f8e55782a89 --- /dev/null +++ b/lib/Github/Api/Miscellaneous/Licenses.php @@ -0,0 +1,34 @@ +get('/licenses'); + } + + /** + * Get an individual license by its license key. + * + * @link https://developer.github.com/v3/licenses/#get-an-individual-license + * + * @param string $license + * + * @return array + */ + public function show($license) + { + return $this->get('/licenses/'.rawurlencode($license)); + } +} diff --git a/lib/Github/Api/Notification.php b/lib/Github/Api/Notification.php new file mode 100644 index 00000000000..f720ad0c88c --- /dev/null +++ b/lib/Github/Api/Notification.php @@ -0,0 +1,91 @@ + + */ +class Notification extends AbstractApi +{ + /** + * Get a listing of notifications. + * + * @link https://developer.github.com/v3/activity/notifications/ + * + * @param bool $includingRead + * @param bool $participating + * @param DateTime|null $since + * @param DateTime|null $before + * + * @return array array of notifications + */ + public function all($includingRead = false, $participating = false, ?DateTime $since = null, ?DateTime $before = null) + { + $parameters = [ + 'all' => $includingRead, + 'participating' => $participating, + ]; + + if ($since !== null) { + $parameters['since'] = $since->format(DateTime::ISO8601); + } + + if ($before !== null) { + $parameters['before'] = $before->format(DateTime::ISO8601); + } + + return $this->get('/notifications', $parameters); + } + + /** + * Marks all notifications as read from the current date. + * + * Optionally give DateTime to mark as read before that date. + * + * @link https://developer.github.com/v3/activity/notifications/#mark-as-read + * + * @param DateTime|null $since + */ + public function markRead(?DateTime $since = null) + { + $parameters = []; + + if ($since !== null) { + $parameters['last_read_at'] = $since->format(DateTime::ISO8601); + } + + $this->put('/notifications', $parameters); + } + + /** + * Mark a single thread as read using its ID. + * + * @link https://developer.github.com/v3/activity/notifications/#mark-a-thread-as-read + * + * @param int $id + */ + public function markThreadRead($id) + { + $this->patch('/notifications/threads/'.$id); + } + + /** + * Gets a single thread using its ID. + * + * @link https://developer.github.com/v3/activity/notifications/#view-a-single-thread + * + * @param int $id + */ + public function id($id) + { + return $this->get('/notifications/threads/'.$id); + } +} diff --git a/lib/Github/Api/Organization.php b/lib/Github/Api/Organization.php index da46badcfcd..0e1210c95b6 100644 --- a/lib/Github/Api/Organization.php +++ b/lib/Github/Api/Organization.php @@ -2,50 +2,84 @@ namespace Github\Api; +use Github\Api\Organization\Actions\Secrets; +use Github\Api\Organization\Actions\SelfHostedRunners; +use Github\Api\Organization\Actions\Variables; +use Github\Api\Organization\Hooks; use Github\Api\Organization\Members; +use Github\Api\Organization\OrganizationRoles; +use Github\Api\Organization\OutsideCollaborators; +use Github\Api\Organization\SecretScanning; use Github\Api\Organization\Teams; /** * Getting organization information and managing authenticated organization account information. * * @link http://developer.github.com/v3/orgs/ + * * @author Antoine Berranger * @author Joseph Bielawski */ class Organization extends AbstractApi { /** - * Get extended information about an organization by its name + * @link https://developer.github.com/v3/orgs/#list-all-organizations + * + * @return array the organizations + */ + public function all($since = '') + { + return $this->get('/organizations?since='.rawurlencode($since)); + } + + /** + * Get extended information about an organization by its name. + * * @link http://developer.github.com/v3/orgs/#get * * @param string $organization the organization to show * - * @return array informations about the organization + * @return array information about the organization */ public function show($organization) { - return $this->get('orgs/'.rawurlencode($organization)); + return $this->get('/orgs/'.rawurlencode($organization)); } public function update($organization, array $params) { - return $this->patch('orgs/'.rawurlencode($organization), $params); + return $this->patch('/orgs/'.rawurlencode($organization), $params); } /** - * List all repositories across all the organizations that you can access + * List all repositories across all the organizations that you can access. + * * @link http://developer.github.com/v3/repos/#list-organization-repositories * * @param string $organization the user name * @param string $type the type of repositories + * @param int $page the page + * @param string $sort sort by + * @param string $direction direction of sort, asc or desc * * @return array the repositories */ - public function repositories($organization, $type = 'all') + public function repositories($organization, $type = 'all', $page = 1, $sort = null, $direction = null) { - return $this->get('orgs/'.rawurlencode($organization).'/repos', array( - 'type' => $type - )); + $parameters = [ + 'type' => $type, + 'page' => $page, + ]; + + if ($sort !== null) { + $parameters['sort'] = $sort; + } + + if ($direction !== null) { + $parameters['direction'] = $direction; + } + + return $this->get('/orgs/'.rawurlencode($organization).'/repos', $parameters); } /** @@ -53,7 +87,15 @@ public function repositories($organization, $type = 'all') */ public function members() { - return new Members($this->client); + return new Members($this->getClient()); + } + + /** + * @return Hooks + */ + public function hooks() + { + return new Hooks($this->getClient()); } /** @@ -61,6 +103,65 @@ public function members() */ public function teams() { - return new Teams($this->client); + return new Teams($this->getClient()); + } + + /** + * @return Secrets + */ + public function secrets(): Secrets + { + return new Secrets($this->getClient()); + } + + /** + * @return Variables + */ + public function variables(): Variables + { + return new Variables($this->getClient()); + } + + /** + * @return OutsideCollaborators + */ + public function outsideCollaborators() + { + return new OutsideCollaborators($this->getClient()); + } + + /** + * @link http://developer.github.com/v3/issues/#list-issues + * + * @param string $organization + * @param array $params + * @param int $page + * + * @return array + */ + public function issues($organization, array $params = [], $page = 1) + { + return $this->get('/orgs/'.rawurlencode($organization).'/issues', array_merge(['page' => $page], $params)); + } + + /** + * @return SelfHostedRunners + */ + public function runners(): SelfHostedRunners + { + return new SelfHostedRunners($this->getClient()); + } + + /** + * @return SecretScanning + */ + public function secretScanning(): SecretScanning + { + return new SecretScanning($this->getClient()); + } + + public function organizationRoles(): OrganizationRoles + { + return new OrganizationRoles($this->getClient()); } } diff --git a/lib/Github/Api/Organization/Actions/Secrets.php b/lib/Github/Api/Organization/Actions/Secrets.php new file mode 100644 index 00000000000..819e2c46738 --- /dev/null +++ b/lib/Github/Api/Organization/Actions/Secrets.php @@ -0,0 +1,144 @@ +get('/orgs/'.rawurlencode($organization).'/actions/secrets'); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#get-an-organization-secret + * + * @param string $organization + * @param string $secretName + * + * @return array|string + */ + public function show(string $organization, string $secretName) + { + return $this->get('/orgs/'.rawurlencode($organization).'/actions/secrets/'.rawurlencode($secretName)); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#create-or-update-an-organization-secret + * + * @param string $organization + * @param string $secretName + * @param array $parameters + * + * @return array|string + */ + public function create(string $organization, string $secretName, array $parameters = []) + { + return $this->put('/orgs/'.rawurlencode($organization).'/actions/secrets/'.rawurlencode($secretName), $parameters); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#create-or-update-an-organization-secret + * + * @param string $organization + * @param string $secretName + * @param array $parameters + * + * @return array|string + */ + public function update(string $organization, string $secretName, array $parameters = []) + { + return $this->put('/orgs/'.rawurlencode($organization).'/actions/secrets/'.rawurlencode($secretName), $parameters); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#delete-an-organization-secret + * + * @param string $organization + * @param string $secretName + * + * @return array|string + */ + public function remove(string $organization, string $secretName) + { + return $this->delete('/orgs/'.rawurlencode($organization).'/actions/secrets/'.rawurlencode($secretName)); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#list-selected-repositories-for-an-organization-secret + * + * @param string $organization + * @param string $secretName + * + * @return array|string + */ + public function selectedRepositories(string $organization, string $secretName) + { + return $this->get('/orgs/'.rawurlencode($organization).'/actions/secrets/'.rawurlencode($secretName).'/repositories'); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#set-selected-repositories-for-an-organization-secret + * + * @param string $organization + * @param string $secretName + * @param array $parameters + * + * @return array|string + */ + public function setSelectedRepositories(string $organization, string $secretName, array $parameters = []) + { + return $this->put('/orgs/'.rawurlencode($organization).'/actions/secrets/'.rawurlencode($secretName).'/repositories', $parameters); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#add-selected-repository-to-an-organization-secret + * + * @param string $organization + * @param string $repositoryId + * @param string $secretName + * + * @return array|string + */ + public function addSecret(string $organization, string $repositoryId, string $secretName) + { + return $this->put('/orgs/'.rawurlencode($organization).'/actions/secrets/'.rawurlencode($secretName).'/repositories/'.$repositoryId); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#remove-selected-repository-from-an-organization-secret + * + * @param string $organization + * @param string $repositoryId + * @param string $secretName + * + * @return array|string + */ + public function removeSecret(string $organization, string $repositoryId, string $secretName) + { + return $this->delete('/orgs/'.rawurlencode($organization).'/actions/secrets/'.rawurlencode($secretName).'/repositories/'.$repositoryId); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#get-an-organization-public-key + * + * @param string $organization + * + * @return array|string + */ + public function publicKey(string $organization) + { + return $this->get('/orgs/'.rawurlencode($organization).'/actions/secrets/public-key'); + } +} diff --git a/lib/Github/Api/Organization/Actions/SelfHostedRunners.php b/lib/Github/Api/Organization/Actions/SelfHostedRunners.php new file mode 100644 index 00000000000..f0b989f5751 --- /dev/null +++ b/lib/Github/Api/Organization/Actions/SelfHostedRunners.php @@ -0,0 +1,59 @@ +get('/orgs/'.rawurlencode($organization).'/actions/runners', $parameters); + } + + /** + * @link https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#get-a-self-hosted-runner-for-an-organization + * + * @param string $organization + * @param int $runnerId + * + * @return array|string + */ + public function show(string $organization, int $runnerId) + { + return $this->get('/orgs/'.rawurlencode($organization).'/actions/runners/'.$runnerId); + } + + /** + * @link https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#delete-a-self-hosted-runner-from-an-organization + * + * @param string $organization + * @param int $runnerId + * + * @return array|string + */ + public function remove(string $organization, int $runnerId) + { + return $this->delete('/orgs/'.rawurlencode($organization).'/actions/runners/'.$runnerId); + } + + /** + * @link https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#list-runner-applications-for-an-organization + * + * @param string $organization + * + * @return array|string + */ + public function applications(string $organization) + { + return $this->get('/orgs/'.rawurlencode($organization).'/actions/runners/downloads'); + } +} diff --git a/lib/Github/Api/Organization/Actions/Variables.php b/lib/Github/Api/Organization/Actions/Variables.php new file mode 100644 index 00000000000..88c037238d3 --- /dev/null +++ b/lib/Github/Api/Organization/Actions/Variables.php @@ -0,0 +1,131 @@ +get('/orgs/'.rawurlencode($organization).'/actions/variables'); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#get-an-organization-secret + * + * @param string $organization + * @param string $variableName + * + * @return array|string + */ + public function show(string $organization, string $variableName) + { + return $this->get('/orgs/'.rawurlencode($organization).'/actions/variables/'.rawurlencode($variableName)); + } + + /** + * @link https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#create-an-organization-variable + * + * @param string $organization + * @param array $parameters + * + * @return array|string + */ + public function create(string $organization, array $parameters) + { + return $this->post('/orgs/'.rawurlencode($organization).'/actions/variables', $parameters); + } + + /** + * @link https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#update-an-organization-variable + * + * @param string $organization + * @param string $variableName + * @param array $parameters + * + * @return array|string + */ + public function update(string $organization, string $variableName, array $parameters = []) + { + return $this->patch('/orgs/'.rawurlencode($organization).'/actions/variables/'.rawurlencode($variableName), $parameters); + } + + /** + * @link https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#delete-an-organization-variable + * + * @param string $organization + * @param string $variableName + * + * @return array|string + */ + public function remove(string $organization, string $variableName) + { + return $this->delete('/orgs/'.rawurlencode($organization).'/actions/variables/'.rawurlencode($variableName)); + } + + /** + * @link https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#list-selected-repositories-for-an-organization-variable + * + * @param string $organization + * @param string $variableName + * + * @return array|string + */ + public function selectedRepositories(string $organization, string $variableName) + { + return $this->get('/orgs/'.rawurlencode($organization).'/actions/variables/'.rawurlencode($variableName).'/repositories'); + } + + /** + * @link https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#set-selected-repositories-for-an-organization-variable + * + * @param string $organization + * @param string $variableName + * @param array $parameters + * + * @return array|string + */ + public function setSelectedRepositories(string $organization, string $variableName, array $parameters = []) + { + return $this->put('/orgs/'.rawurlencode($organization).'/actions/variables/'.rawurlencode($variableName).'/repositories', $parameters); + } + + /** + * @link https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#add-selected-repository-to-an-organization-variable + * + * @param string $organization + * @param int $repositoryId + * @param string $variableName + * + * @return array|string + */ + public function addRepository(string $organization, int $repositoryId, string $variableName) + { + return $this->put('/orgs/'.rawurlencode($organization).'/actions/variables/'.rawurlencode($variableName).'/repositories/'.$repositoryId); + } + + /** + * @link https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#remove-selected-repository-from-an-organization-variable + * + * @param string $organization + * @param int $repositoryId + * @param string $variableName + * + * @return array|string + */ + public function removeRepository(string $organization, int $repositoryId, string $variableName) + { + return $this->delete('/orgs/'.rawurlencode($organization).'/actions/variables/'.rawurlencode($variableName).'/repositories/'.$repositoryId); + } +} diff --git a/lib/Github/Api/Organization/Hooks.php b/lib/Github/Api/Organization/Hooks.php new file mode 100644 index 00000000000..945cabc8667 --- /dev/null +++ b/lib/Github/Api/Organization/Hooks.php @@ -0,0 +1,111 @@ +get('/orgs/'.rawurlencode($organization).'/hooks'); + } + + /** + * Get a single hook. + * + * @link https://developer.github.com/v3/orgs/hooks/#get-single-hook + * + * @param string $organization + * @param int $id + * + * @return array + */ + public function show($organization, $id) + { + return $this->get('/orgs/'.rawurlencode($organization).'/hooks/'.$id); + } + + /** + * Create a hook. + * + * @link https://developer.github.com/v3/orgs/hooks/#create-a-hook + * + * @param string $organization + * @param array $params + * + * @throws \Github\Exception\MissingArgumentException + * + * @return array + */ + public function create($organization, array $params) + { + if (!isset($params['name'], $params['config'])) { + throw new MissingArgumentException(['name', 'config']); + } + + return $this->post('/orgs/'.rawurlencode($organization).'/hooks', $params); + } + + /** + * Edit a hook. + * + * @link https://developer.github.com/v3/orgs/hooks/#edit-a-hook + * + * @param string $organization + * @param int $id + * @param array $params + * + * @throws \Github\Exception\MissingArgumentException + * + * @return array + */ + public function update($organization, $id, array $params) + { + if (!isset($params['config'])) { + throw new MissingArgumentException(['config']); + } + + return $this->patch('/orgs/'.rawurlencode($organization).'/hooks/'.$id, $params); + } + + /** + * Ping a hook. + * + * @link https://developer.github.com/v3/orgs/hooks/#ping-a-hook + * + * @param string $organization + * @param int $id + * + * @return array|string + */ + public function ping($organization, $id) + { + return $this->post('/orgs/'.rawurlencode($organization).'/hooks/'.$id.'/pings'); + } + + /** + * Delete a hook. + * + * @link https://developer.github.com/v3/orgs/hooks/#delete-a-hook + * + * @param string $organization + * @param int $id + * + * @return array|string + */ + public function remove($organization, $id) + { + return $this->delete('/orgs/'.rawurlencode($organization).'/hooks/'.$id); + } +} diff --git a/lib/Github/Api/Organization/Members.php b/lib/Github/Api/Organization/Members.php index 691f11c335c..023e3f8d545 100644 --- a/lib/Github/Api/Organization/Members.php +++ b/lib/Github/Api/Organization/Members.php @@ -6,41 +6,70 @@ /** * @link http://developer.github.com/v3/orgs/members/ + * * @author Joseph Bielawski */ class Members extends AbstractApi { - public function all($organization, $type = null) + public function all($organization, $type = null, $filter = 'all', $role = null) { + $parameters = []; + $path = '/orgs/'.rawurlencode($organization).'/'; if (null === $type) { - return $this->get('orgs/'.rawurlencode($organization).'/members'); + $path .= 'members'; + if (null !== $filter) { + $parameters['filter'] = $filter; + } + if (null !== $role) { + $parameters['role'] = $role; + } + } else { + $path .= 'public_members'; } - return $this->get('orgs/'.rawurlencode($organization).'/public_members'); + return $this->get($path, $parameters); } public function show($organization, $username) { - return $this->get('orgs/'.rawurlencode($organization).'/members/'.rawurlencode($username)); + return $this->get('/orgs/'.rawurlencode($organization).'/members/'.rawurlencode($username)); + } + + public function member($organization, $username) + { + return $this->get('/orgs/'.rawurlencode($organization).'/memberships/'.rawurlencode($username)); } public function check($organization, $username) { - return $this->get('orgs/'.rawurlencode($organization).'/public_members/'.rawurlencode($username)); + return $this->get('/orgs/'.rawurlencode($organization).'/public_members/'.rawurlencode($username)); } public function publicize($organization, $username) { - return $this->put('orgs/'.rawurlencode($organization).'/public_members/'.rawurlencode($username)); + return $this->put('/orgs/'.rawurlencode($organization).'/public_members/'.rawurlencode($username)); } public function conceal($organization, $username) { - return $this->delete('orgs/'.rawurlencode($organization).'/public_members/'.rawurlencode($username)); + return $this->delete('/orgs/'.rawurlencode($organization).'/public_members/'.rawurlencode($username)); + } + + /* + * Add user to organization + */ + public function add($organization, $username, array $params = []) + { + return $this->put('/orgs/'.rawurlencode($organization).'/memberships/'.rawurlencode($username), $params); + } + + public function addMember($organization, $username) + { + return $this->add($organization, $username); } public function remove($organization, $username) { - return $this->delete('orgs/'.rawurlencode($organization).'/members/'.rawurlencode($username)); + return $this->delete('/orgs/'.rawurlencode($organization).'/members/'.rawurlencode($username)); } } diff --git a/lib/Github/Api/Organization/OrganizationRoles.php b/lib/Github/Api/Organization/OrganizationRoles.php new file mode 100644 index 00000000000..dd44fceceaf --- /dev/null +++ b/lib/Github/Api/Organization/OrganizationRoles.php @@ -0,0 +1,61 @@ +get('/orgs/'.rawurlencode($organization).'/organization-roles'); + } + + public function show(string $organization, int $roleId) + { + return $this->get('/orgs/'.rawurlencode($organization).'/organization-roles/'.$roleId); + } + + public function listTeamsWithRole(string $organization, int $roleId) + { + return $this->get('/orgs/'.rawurlencode($organization).'/organization-roles/'.$roleId.'/teams'); + } + + public function assignRoleToTeam(string $organization, int $roleId, string $teamSlug): void + { + $this->put('/orgs/'.rawurlencode($organization).'/organization-roles/teams/'.rawurlencode($teamSlug).'/'.$roleId); + } + + public function removeRoleFromTeam(string $organization, int $roleId, string $teamSlug): void + { + $this->delete('/orgs/'.rawurlencode($organization).'/organization-roles/teams/'.rawurlencode($teamSlug).'/'.$roleId); + } + + public function removeAllRolesFromTeam(string $organization, string $teamSlug): void + { + $this->delete('/orgs/'.rawurlencode($organization).'/organization-roles/teams/'.rawurlencode($teamSlug)); + } + + public function listUsersWithRole(string $organization, int $roleId): array + { + return $this->get('/orgs/'.rawurlencode($organization).'/organization-roles/'.$roleId.'/users'); + } + + public function assignRoleToUser(string $organization, int $roleId, string $username): void + { + $this->put('/orgs/'.rawurlencode($organization).'/organization-roles/users/'.rawurlencode($username).'/'.$roleId); + } + + public function removeRoleFromUser(string $organization, int $roleId, string $username): void + { + $this->delete('/orgs/'.rawurlencode($organization).'/organization-roles/users/'.rawurlencode($username).'/'.$roleId); + } + + public function removeAllRolesFromUser(string $organization, string $username): void + { + $this->delete('/orgs/'.rawurlencode($organization).'/organization-roles/users/'.rawurlencode($username)); + } +} diff --git a/lib/Github/Api/Organization/OutsideCollaborators.php b/lib/Github/Api/Organization/OutsideCollaborators.php new file mode 100644 index 00000000000..958100a56ee --- /dev/null +++ b/lib/Github/Api/Organization/OutsideCollaborators.php @@ -0,0 +1,52 @@ + + */ +class OutsideCollaborators extends AbstractApi +{ + /** + * @link https://developer.github.com/v3/orgs/outside_collaborators/#list-outside-collaborators-for-an-organization + * + * @param string $organization the organization + * @param array $params + * + * @return array the organizations + */ + public function all($organization, array $params = []) + { + return $this->get('/orgs/'.rawurlencode($organization).'/outside_collaborators', $params); + } + + /** + * @link https://developer.github.com/v3/orgs/outside_collaborators/#convert-an-organization-member-to-outside-collaborator + * + * @param string $organization the organization + * @param string $username the github username + * + * @return array + */ + public function convert($organization, $username) + { + return $this->put('/orgs/'.rawurlencode($organization).'/outside_collaborators/'.rawurldecode($username)); + } + + /** + * @link https://developer.github.com/v3/orgs/outside_collaborators/#remove-outside-collaborator-from-an-organization + * + * @param string $organization the organization + * @param string $username the username + * + * @return array + */ + public function remove($organization, $username) + { + return $this->delete('/orgs/'.rawurlencode($organization).'/outside_collaborators/'.rawurldecode($username)); + } +} diff --git a/lib/Github/Api/Organization/Projects.php b/lib/Github/Api/Organization/Projects.php new file mode 100644 index 00000000000..2bb7196e95a --- /dev/null +++ b/lib/Github/Api/Organization/Projects.php @@ -0,0 +1,23 @@ +get('/orgs/'.rawurlencode($organization).'/projects', array_merge(['page' => 1], $params)); + } + + public function create($organization, array $params) + { + if (!isset($params['name'])) { + throw new MissingArgumentException(['name']); + } + + return $this->post('/orgs/'.rawurlencode($organization).'/projects', $params); + } +} diff --git a/lib/Github/Api/Organization/SecretScanning.php b/lib/Github/Api/Organization/SecretScanning.php new file mode 100644 index 00000000000..a323fd06fcc --- /dev/null +++ b/lib/Github/Api/Organization/SecretScanning.php @@ -0,0 +1,19 @@ +get('/orgs/'.rawurlencode($organization).'/secret-scanning/alerts', $params); + } +} diff --git a/lib/Github/Api/Organization/Teams.php b/lib/Github/Api/Organization/Teams.php index 5cdf876db74..20bb2791a7a 100644 --- a/lib/Github/Api/Organization/Teams.php +++ b/lib/Github/Api/Organization/Teams.php @@ -7,13 +7,14 @@ /** * @link http://developer.github.com/v3/orgs/teams/ + * * @author Joseph Bielawski */ class Teams extends AbstractApi { public function all($organization) { - return $this->get('orgs/'.rawurlencode($organization).'/teams'); + return $this->get('/orgs/'.rawurlencode($organization).'/teams'); } public function create($organization, array $params) @@ -22,74 +23,106 @@ public function create($organization, array $params) throw new MissingArgumentException('name'); } if (isset($params['repo_names']) && !is_array($params['repo_names'])) { - $params['repo_names'] = array($params['repo_names']); + $params['repo_names'] = [$params['repo_names']]; } - if (isset($params['permission']) && !in_array($params['permission'], array('pull', 'push', 'admin'))) { + if (isset($params['permission']) && !in_array($params['permission'], ['pull', 'push', 'admin'])) { $params['permission'] = 'pull'; } - return $this->post('orgs/'.rawurlencode($organization).'/teams', $params); + return $this->post('/orgs/'.rawurlencode($organization).'/teams', $params); } - public function show($team) + /** + * @link https://developer.github.com/v3/teams/#list-teams + */ + public function show($team, $organization) { - return $this->get('teams/'.rawurlencode($team)); + return $this->get('/orgs/'.rawurlencode($organization).'/teams/'.rawurlencode($team)); } - public function update($team, array $params) + /** + * @link https://developer.github.com/v3/teams/#edit-team + */ + public function update($team, array $params, $organization) { if (!isset($params['name'])) { throw new MissingArgumentException('name'); } - if (isset($params['permission']) && !in_array($params['permission'], array('pull', 'push', 'admin'))) { + if (isset($params['permission']) && !in_array($params['permission'], ['pull', 'push', 'admin'])) { $params['permission'] = 'pull'; } - return $this->patch('teams/'.rawurlencode($team), $params); + return $this->patch('/orgs/'.rawurlencode($organization).'/teams/'.rawurlencode($team), $params); } - public function remove($team) + /** + * @link https://developer.github.com/v3/teams/#delete-team + */ + public function remove($team, $organization) { - return $this->delete('teams/'.rawurlencode($team)); + return $this->delete('/orgs/'.rawurlencode($organization).'/teams/'.rawurlencode($team)); } - public function members($team) + /** + * @link https://developer.github.com/v3/teams/members/#list-team-members + */ + public function members($team, $organization) { - return $this->get('teams/'.rawurlencode($team).'/members'); + return $this->get('/orgs/'.rawurlencode($organization).'/teams/'.rawurlencode($team).'/members'); } - public function check($team, $username) + /** + * @link https://developer.github.com/v3/teams/members/#get-team-membership + */ + public function check($team, $username, $organization) { - return $this->get('teams/'.rawurlencode($team).'/members/'.rawurlencode($username)); + return $this->get('/orgs/'.rawurlencode($organization).'/teams/'.rawurlencode($team).'/memberships/'.rawurlencode($username)); } - public function addMember($team, $username) + /** + * @link https://developer.github.com/v3/teams/members/#add-or-update-team-membership + */ + public function addMember($team, $username, $organization) { - return $this->put('teams/'.rawurlencode($team).'/members/'.rawurlencode($username)); + return $this->put('/orgs/'.rawurlencode($organization).'/teams/'.rawurlencode($team).'/memberships/'.rawurlencode($username)); } - public function removeMember($team, $username) + /** + * @link https://developer.github.com/v3/teams/members/#remove-team-membership + */ + public function removeMember($team, $username, $organization) { - return $this->delete('teams/'.rawurlencode($team).'/members/'.rawurlencode($username)); + return $this->delete('/orgs/'.rawurlencode($organization).'/teams/'.rawurlencode($team).'/memberships/'.rawurlencode($username)); } - public function repositories($team) + /** + * @link https://docs.github.com/en/rest/teams/teams#list-team-repositories + */ + public function repositories($team, $organization = '') { - return $this->get('teams/'.rawurlencode($team).'/repos'); + if (empty($organization)) { + return $this->get('/teams/'.rawurlencode($team).'/repos'); + } + + return $this->get('/orgs/'.rawurlencode($organization).'/teams/'.rawurlencode($team).'/repos'); } - public function repository($team, $username, $repository) + public function repository($team, $organization, $repository) { - return $this->get('teams/'.rawurlencode($team).'/repos/'.rawurlencode($username).'/'.rawurlencode($repository)); + return $this->get('/teams/'.rawurlencode($team).'/repos/'.rawurlencode($organization).'/'.rawurlencode($repository)); } - public function addRepository($team, $username, $repository) + public function addRepository($team, $organization, $repository, $params = []) { - return $this->put('teams/'.rawurlencode($team).'/repos/'.rawurlencode($username).'/'.rawurlencode($repository)); + if (isset($params['permission']) && !in_array($params['permission'], ['pull', 'push', 'admin', 'maintain', 'triage'])) { + $params['permission'] = 'pull'; + } + + return $this->put('/orgs/'.rawurlencode($organization).'/teams/'.rawurlencode($team).'/repos/'.rawurlencode($organization).'/'.rawurlencode($repository), $params); } - public function removeRepository($team, $username, $repository) + public function removeRepository($team, $organization, $repository) { - return $this->delete('teams/'.rawurlencode($team).'/repos/'.rawurlencode($username).'/'.rawurlencode($repository)); + return $this->delete('/orgs/'.rawurlencode($organization).'/teams/'.rawurlencode($team).'/repos/'.rawurlencode($organization).'/'.rawurlencode($repository)); } } diff --git a/lib/Github/Api/Project/AbstractProjectApi.php b/lib/Github/Api/Project/AbstractProjectApi.php new file mode 100644 index 00000000000..049d67562c0 --- /dev/null +++ b/lib/Github/Api/Project/AbstractProjectApi.php @@ -0,0 +1,45 @@ +acceptHeaderValue = 'application/vnd.github.inertia-preview+json'; + + return $this; + } + + public function show($id, array $params = []) + { + return $this->get('/projects/'.rawurlencode($id), array_merge(['page' => 1], $params)); + } + + public function update($id, array $params) + { + return $this->patch('/projects/'.rawurlencode($id), $params); + } + + public function deleteProject($id) + { + return $this->delete('/projects/'.rawurlencode($id)); + } + + public function columns() + { + return new Columns($this->getClient()); + } +} diff --git a/lib/Github/Api/Project/Cards.php b/lib/Github/Api/Project/Cards.php new file mode 100644 index 00000000000..0d670f93863 --- /dev/null +++ b/lib/Github/Api/Project/Cards.php @@ -0,0 +1,60 @@ +acceptHeaderValue = 'application/vnd.github.inertia-preview+json'; + + return $this; + } + + public function all($columnId, array $params = []) + { + return $this->get('/projects/columns/'.rawurlencode($columnId).'/cards', array_merge(['page' => 1], $params)); + } + + public function show($id) + { + return $this->get('/projects/columns/cards/'.rawurlencode($id)); + } + + public function create($columnId, array $params) + { + return $this->post('/projects/columns/'.rawurlencode($columnId).'/cards', $params); + } + + public function update($id, array $params) + { + return $this->patch('/projects/columns/cards/'.rawurlencode($id), $params); + } + + public function deleteCard($id) + { + return $this->delete('/projects/columns/cards/'.rawurlencode($id)); + } + + public function move($id, array $params) + { + if (!isset($params['position'])) { + throw new MissingArgumentException(['position']); + } + + return $this->post('/projects/columns/cards/'.rawurlencode($id).'/moves', $params); + } +} diff --git a/lib/Github/Api/Project/Columns.php b/lib/Github/Api/Project/Columns.php new file mode 100644 index 00000000000..5146ac223af --- /dev/null +++ b/lib/Github/Api/Project/Columns.php @@ -0,0 +1,73 @@ +acceptHeaderValue = 'application/vnd.github.inertia-preview+json'; + + return $this; + } + + public function all($projectId, array $params = []) + { + return $this->get('/projects/'.rawurlencode($projectId).'/columns', array_merge(['page' => 1], $params)); + } + + public function show($id) + { + return $this->get('/projects/columns/'.rawurlencode($id)); + } + + public function create($projectId, array $params) + { + if (!isset($params['name'])) { + throw new MissingArgumentException(['name']); + } + + return $this->post('/projects/'.rawurlencode($projectId).'/columns', $params); + } + + public function update($id, array $params) + { + if (!isset($params['name'])) { + throw new MissingArgumentException(['name']); + } + + return $this->patch('/projects/columns/'.rawurlencode($id), $params); + } + + public function deleteColumn($id) + { + return $this->delete('/projects/columns/'.rawurlencode($id)); + } + + public function move($id, array $params) + { + if (!isset($params['position'])) { + throw new MissingArgumentException(['position']); + } + + return $this->post('/projects/columns/'.rawurlencode($id).'/moves', $params); + } + + public function cards() + { + return new Cards($this->getClient()); + } +} diff --git a/lib/Github/Api/PullRequest.php b/lib/Github/Api/PullRequest.php index e52815cf01a..22922c1ee92 100644 --- a/lib/Github/Api/PullRequest.php +++ b/lib/Github/Api/PullRequest.php @@ -3,72 +3,138 @@ namespace Github\Api; use Github\Api\PullRequest\Comments; +use Github\Api\PullRequest\Review; +use Github\Api\PullRequest\ReviewRequest; +use Github\Exception\InvalidArgumentException; use Github\Exception\MissingArgumentException; /** * API for accessing Pull Requests from your Git/Github repositories. * - * @link http://developer.github.com/v3/pulls/ + * @see http://developer.github.com/v3/pulls/ + * * @author Joseph Bielawski */ class PullRequest extends AbstractApi { + use AcceptHeaderTrait; + + /** + * Configure the body type. + * + * @link https://developer.github.com/v3/pulls/#custom-media-types + * + * @param string|null $bodyType + * @param string|null $apiVersion + * + * @return $this + */ + public function configure($bodyType = null, $apiVersion = null) + { + if (null === $apiVersion) { + $apiVersion = $this->getApiVersion(); + } + + if (!in_array($bodyType, ['text', 'html', 'full', 'diff', 'patch'])) { + $bodyType = 'raw'; + } + + if (!in_array($bodyType, ['diff', 'patch'])) { + $bodyType .= '+json'; + } + + $this->acceptHeaderValue = sprintf('application/vnd.github.%s.%s', $apiVersion, $bodyType); + + return $this; + } + /** * Get a listing of a project's pull requests by the username, repository and (optionally) state. + * * @link http://developer.github.com/v3/pulls/ * - * @param string $username the username - * @param string $repository the repository - * @param string $state the state of the fetched pull requests. - * The API seems to automatically default to 'open' - * @param integer $page the page - * @param integer $perPage the per page + * @param string $username the username + * @param string $repository the repository + * @param array $parameters a list of extra parameters. * * @return array array of pull requests for the project */ - public function all($username, $repository, $state = null, $page = 1, $perPage = 30) + public function all($username, $repository, array $parameters = []) { - $parameters = array( - 'page' => $page, - 'per_page' => $perPage, - 'state' => $state, - ); - - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls', $parameters); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls', $parameters); } /** * Show all details of a pull request, including the discussions. + * * @link http://developer.github.com/v3/pulls/ * * @param string $username the username * @param string $repository the repository - * @param string $id the ID of the pull request for which details are retrieved + * @param int $id the ID of the pull request for which details are retrieved * - * @return array array of pull requests for the project + * @return array|string pull request details */ public function show($username, $repository, $id) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.rawurlencode($id)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.$id); + } + + public function commits($username, $repository, $id, array $parameters = []) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.rawurlencode($id).'/commits', $parameters); } - public function commits($username, $repository, $id) + public function files($username, $repository, $id, array $parameters = []) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.rawurlencode($id).'/commits'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.rawurlencode($id).'/files', $parameters); } - public function files($username, $repository, $id) + /** + * All statuses which are the statuses of its head branch. + * + * @see http://developer.github.com/v3/pulls/ + * + * @param string $username the username + * @param string $repository the repository + * @param int $id the ID of the pull request for which statuses are retrieved + * + * @return array array of statuses for the project + */ + public function status($username, $repository, $id) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.rawurlencode($id).'/files'); + $link = $this->show($username, $repository, $id)['_links']['statuses']['href']; + + return $this->get($link); } + /** + * @return Comments + */ public function comments() { - return new Comments($this->client); + return new Comments($this->getClient()); } /** - * Create a pull request + * @return Review + */ + public function reviews() + { + return new Review($this->getClient()); + } + + /** + * @return ReviewRequest + */ + public function reviewRequests() + { + return new ReviewRequest($this->getClient()); + } + + /** + * Create a pull request. + * * @link http://developer.github.com/v3/pulls/ * * @param string $username the username @@ -79,47 +145,63 @@ public function comments() * "my-user:some-branch". The String title of the Pull Request. The String body of * the Pull Request. The issue number. Used when title and body is not set. * - * @return array - * * @throws MissingArgumentException + * + * @return array */ public function create($username, $repository, array $params) { // Two ways to create PR, using issue or title if (!isset($params['issue']) && !isset($params['title'])) { - throw new MissingArgumentException(array('issue', 'title')); + throw new MissingArgumentException(['issue', 'title']); } if (!isset($params['base'], $params['head'])) { - throw new MissingArgumentException(array('base', 'head')); + throw new MissingArgumentException(['base', 'head']); } // If `issue` is not sent, then `body` must be sent if (!isset($params['issue']) && !isset($params['body'])) { - throw new MissingArgumentException(array('issue', 'body')); + throw new MissingArgumentException(['issue', 'body']); } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls', $params); } public function update($username, $repository, $id, array $params) { - if (isset($params['state']) && !in_array($params['state'], array('open', 'closed'))) { + if (isset($params['state']) && !in_array($params['state'], ['open', 'closed'])) { $params['state'] = 'open'; } - return $this->patch('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.rawurlencode($id), $params); + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.rawurlencode($id), $params); } public function merged($username, $repository, $id) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.rawurlencode($id).'/merge'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.rawurlencode($id).'/merge'); } - public function merge($username, $repository, $id, $message = null) + public function merge($username, $repository, $id, $message, $sha, $mergeMethod = 'merge', $title = null) { - return $this->put('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.rawurlencode($id).'/merge', array( - 'commit_message' => $message - )); + if (is_bool($mergeMethod)) { + $mergeMethod = $mergeMethod ? 'squash' : 'merge'; + } + + if (!in_array($mergeMethod, ['merge', 'squash', 'rebase'], true)) { + throw new InvalidArgumentException(sprintf('"$mergeMethod" must be one of ["merge", "squash", "rebase"] ("%s" given).', $mergeMethod)); + } + + $params = [ + 'commit_message' => $message, + 'sha' => $sha, + 'merge_method' => $mergeMethod, + ]; + + if (is_string($title)) { + $params['commit_title'] = $title; + } + + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.rawurlencode($id).'/merge', $params); } } diff --git a/lib/Github/Api/PullRequest/Comments.php b/lib/Github/Api/PullRequest/Comments.php index dec30fb0566..3ded9456cf3 100644 --- a/lib/Github/Api/PullRequest/Comments.php +++ b/lib/Github/Api/PullRequest/Comments.php @@ -3,24 +3,101 @@ namespace Github\Api\PullRequest; use Github\Api\AbstractApi; +use Github\Api\AcceptHeaderTrait; use Github\Exception\MissingArgumentException; /** * @link http://developer.github.com/v3/pulls/comments/ + * * @author Joseph Bielawski */ class Comments extends AbstractApi { - public function all($username, $repository, $pullRequest) + use AcceptHeaderTrait; + + /** + * Configure the body type. + * + * @link https://developer.github.com/v3/pulls/comments/#custom-media-types + * + * @param string|null $bodyType + * @param string|null $apiVersion + * + * @return $this + */ + public function configure($bodyType = null, $apiVersion = null) + { + if ($apiVersion !== 'squirrel-girl-preview') { + $apiVersion = $this->getApiVersion(); + } + + if (!in_array($bodyType, ['text', 'html', 'full'])) { + $bodyType = 'raw'; + } + + $this->acceptHeaderValue = sprintf('application/vnd.github.%s.%s+json', $apiVersion, $bodyType); + + return $this; + } + + /** + * Get a listing of a pull request's comments by the username, repository and pull request number + * or all repository comments by the username and repository. + * + * @link https://developer.github.com/v3/pulls/comments/#list-comments-on-a-pull-request + * @link https://developer.github.com/v3/pulls/comments/#list-comments-in-a-repository + * + * @param string $username the username + * @param string $repository the repository + * @param int|null $pullRequest the pull request number + * @param array $params a list of extra parameters. + * + * @return array + */ + public function all($username, $repository, $pullRequest = null, array $params = []) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.rawurlencode($pullRequest).'/comments'); + if (null !== $pullRequest) { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.$pullRequest.'/comments'); + } + + $parameters = array_merge([ + 'page' => 1, + 'per_page' => 30, + ], $params); + + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/comments', $parameters); } + /** + * Get a single pull request comment by the username, repository and comment id. + * + * @link https://developer.github.com/v3/pulls/comments/#get-a-single-comment + * + * @param string $username the username + * @param string $repository the repository + * @param int $comment the comment id + * + * @return array + */ public function show($username, $repository, $comment) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/comments/'.rawurlencode($comment)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/comments/'.$comment); } + /** + * Create a pull request comment by the username, repository and pull request number. + * + * @link https://developer.github.com/v3/pulls/comments/#create-a-comment + * + * @param string $username the username + * @param string $repository the repository + * @param int $pullRequest the pull request number + * @param array $params a list of extra parameters. + * + * @throws MissingArgumentException + * + * @return array + */ public function create($username, $repository, $pullRequest, array $params) { if (!isset($params['body'])) { @@ -29,23 +106,48 @@ public function create($username, $repository, $pullRequest, array $params) // If `in_reply_to` is set, other options are not necessary anymore if (!isset($params['in_reply_to']) && !isset($params['commit_id'], $params['path'], $params['position'])) { - throw new MissingArgumentException(array('commit_id', 'path', 'position')); + throw new MissingArgumentException(['commit_id', 'path', 'position']); } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.rawurlencode($pullRequest).'/comments', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.$pullRequest.'/comments', $params); } + /** + * Update a pull request comment by the username, repository and comment id. + * + * @link https://developer.github.com/v3/pulls/comments/#edit-a-comment + * + * @param string $username the username + * @param string $repository the repository + * @param int $comment the comment id + * @param array $params a list of extra parameters. + * + * @throws MissingArgumentException + * + * @return array + */ public function update($username, $repository, $comment, array $params) { if (!isset($params['body'])) { throw new MissingArgumentException('body'); } - return $this->patch('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/comments/'.rawurlencode($comment), $params); + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/comments/'.$comment, $params); } + /** + * Delete a pull request comment by the username, repository and comment id. + * + * @link https://developer.github.com/v3/pulls/comments/#delete-a-comment + * + * @param string $username the username + * @param string $repository the repository + * @param int $comment the comment id + * + * @return string + */ public function remove($username, $repository, $comment) { - return $this->delete('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/comments/'.rawurlencode($comment)); + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/comments/'.$comment); } } diff --git a/lib/Github/Api/PullRequest/Review.php b/lib/Github/Api/PullRequest/Review.php new file mode 100644 index 00000000000..ed586ddf6fc --- /dev/null +++ b/lib/Github/Api/PullRequest/Review.php @@ -0,0 +1,211 @@ + + */ +class Review extends AbstractApi +{ + use AcceptHeaderTrait; + + public function configure() + { + trigger_deprecation('KnpLabs/php-github-api', '3.2', 'The "%s" is deprecated and will be removed.', __METHOD__); + + return $this; + } + + /** + * Get a listing of a pull request's reviews by the username, repository and pull request number. + * + * @link https://developer.github.com/v3/pulls/reviews/#list-reviews-on-a-pull-request + * + * @param string $username the username + * @param string $repository the repository + * @param int $pullRequest the pull request number + * @param array $params a list of extra parameters. + * + * @return array array of pull request reviews for the pull request + */ + public function all($username, $repository, $pullRequest, array $params = []) + { + if (!empty($params)) { + trigger_deprecation('KnpLabs/php-github-api', '3.2', 'The "$params" parameter is deprecated, to paginate the results use the "ResultPager" instead.'); + } + + $parameters = array_merge([ + 'page' => 1, + 'per_page' => 30, + ], $params); + + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.$pullRequest.'/reviews', $parameters); + } + + /** + * Get a single pull request review by the username, repository, pull request number and the review id. + * + * @link https://developer.github.com/v3/pulls/reviews/#get-a-single-review + * + * @param string $username the username + * @param string $repository the repository + * @param int $pullRequest the pull request number + * @param int $id the review id + * + * @return array the pull request review + */ + public function show($username, $repository, $pullRequest, $id) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.$pullRequest.'/reviews/'.$id); + } + + /** + * Delete a single pull request review by the username, repository, pull request number and the review id. + * + * @link https://developer.github.com/v3/pulls/reviews/#delete-a-pending-review + * + * @param string $username the username + * @param string $repository the repository + * @param int $pullRequest the pull request number + * @param int $id the review id + * + * @return array|string + */ + public function remove($username, $repository, $pullRequest, $id) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.$pullRequest.'/reviews/'.$id); + } + + /** + * Get comments for a single pull request review. + * + * @link https://developer.github.com/v3/pulls/reviews/#get-comments-for-a-single-review + * + * @param string $username the username + * @param string $repository the repository + * @param int $pullRequest the pull request number + * @param int $id the review id + * + * @return array|string + */ + public function comments($username, $repository, $pullRequest, $id) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.$pullRequest.'/reviews/'.$id.'/comments'); + } + + /** + * Create a pull request review by the username, repository and pull request number. + * + * @link https://developer.github.com/v3/pulls/reviews/#create-a-pull-request-review + * + * @param string $username the username + * @param string $repository the repository + * @param int $pullRequest the pull request number + * @param array $params a list of extra parameters. + * + * @throws MissingArgumentException + * + * @return array the pull request review + */ + public function create($username, $repository, $pullRequest, array $params = []) + { + if (array_key_exists('event', $params) && !in_array($params['event'], ['APPROVE', 'REQUEST_CHANGES', 'COMMENT'], true)) { + throw new InvalidArgumentException(sprintf('"event" must be one of ["APPROVE", "REQUEST_CHANGES", "COMMENT"] ("%s" given).', $params['event'])); + } + + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.$pullRequest.'/reviews', $params); + } + + /** + * Submit a pull request review by the username, repository, pull request number and the review id. + * + * @link https://developer.github.com/v3/pulls/reviews/#submit-a-pull-request-review + * + * @param string $username the username + * @param string $repository the repository + * @param int $pullRequest the pull request number + * @param int $id the review id + * @param array $params a list of extra parameters. + * + * @throws MissingArgumentException + * + * @return array the pull request review + */ + public function submit($username, $repository, $pullRequest, $id, array $params = []) + { + if (!isset($params['event'])) { + throw new MissingArgumentException('event'); + } + + if (!in_array($params['event'], ['APPROVE', 'REQUEST_CHANGES', 'COMMENT'], true)) { + throw new InvalidArgumentException(sprintf('"event" must be one of ["APPROVE", "REQUEST_CHANGES", "COMMENT"] ("%s" given).', $params['event'])); + } + + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.$pullRequest.'/reviews/'.$id.'/events', $params); + } + + /** + * Dismiss a pull request review by the username, repository, pull request number and the review id. + * + * @link https://developer.github.com/v3/pulls/reviews/#dismiss-a-pull-request-review + * + * @param string $username the username + * @param string $repository the repository + * @param int $pullRequest the pull request number + * @param int $id the review id + * @param string $message a mandatory dismissal message + * + * @return array|string + */ + public function dismiss($username, $repository, $pullRequest, $id, $message) + { + if (!is_string($message)) { + throw new InvalidArgumentException(sprintf('"message" must be a valid string ("%s" given).', gettype($message))); + } + + if (empty($message)) { + throw new InvalidArgumentException('"message" is mandatory and cannot be empty'); + } + + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.$pullRequest.'/reviews/'.$id.'/dismissals', [ + 'message' => $message, + ]); + } + + /** + * Update a pull request review by the username, repository, pull request number and the review id. + * + * @link https://developer.github.com/v3/pulls/reviews/#update-a-pull-request-review + * + * @param string $username the username + * @param string $repository the repository + * @param int $pullRequest the pull request number + * @param int $id the review id + * @param string $body a mandatory dismissal message + * + * @return array|string + */ + public function update($username, $repository, $pullRequest, $id, $body) + { + if (!is_string($body)) { + throw new InvalidArgumentException(sprintf('"body" must be a valid string ("%s" given).', gettype($body))); + } + + if (empty($body)) { + throw new InvalidArgumentException('"body" is mandatory and cannot be empty'); + } + + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.$pullRequest.'/reviews/'.$id, [ + 'body' => $body, + ]); + } +} diff --git a/lib/Github/Api/PullRequest/ReviewRequest.php b/lib/Github/Api/PullRequest/ReviewRequest.php new file mode 100644 index 00000000000..e9b9280a119 --- /dev/null +++ b/lib/Github/Api/PullRequest/ReviewRequest.php @@ -0,0 +1,72 @@ +get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.$pullRequest.'/requested_reviewers', $params); + } + + /** + * @link https://docs.github.com/en/rest/reference/pulls#request-reviewers-for-a-pull-request + * + * @param string $username + * @param string $repository + * @param int $pullRequest + * @param array $reviewers + * @param array $teamReviewers + * + * @return array + */ + public function create($username, $repository, $pullRequest, array $reviewers = [], array $teamReviewers = []) + { + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.$pullRequest.'/requested_reviewers', ['reviewers' => $reviewers, 'team_reviewers' => $teamReviewers]); + } + + /** + * @link https://developer.github.com/v3/pulls/review_requests/#delete-a-review-request + * + * @param string $username + * @param string $repository + * @param int $pullRequest + * @param array $reviewers + * @param array $teamReviewers + * + * @return array + */ + public function remove($username, $repository, $pullRequest, array $reviewers = [], array $teamReviewers = []) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pulls/'.$pullRequest.'/requested_reviewers', ['reviewers' => $reviewers, 'team_reviewers' => $teamReviewers]); + } +} diff --git a/lib/Github/Api/RateLimit.php b/lib/Github/Api/RateLimit.php new file mode 100644 index 00000000000..10b8b5b3288 --- /dev/null +++ b/lib/Github/Api/RateLimit.php @@ -0,0 +1,70 @@ + + */ +class RateLimit extends AbstractApi +{ + /** + * @var RateLimitResource[] + */ + protected $resources = []; + + /** + * Gets the rate limit resource objects. + * + * @return RateLimitResource[] + */ + public function getResources() + { + $this->fetchLimits(); + + return $this->resources; + } + + /** + * Returns a rate limit resource object by the given name. + * + * @param string $name + * + * @return RateLimitResource|false + */ + public function getResource($name) + { + // Fetch once per instance + if (empty($this->resources)) { + $this->fetchLimits(); + } + + if (!isset($this->resources[$name])) { + return false; + } + + return $this->resources[$name]; + } + + /** + * Returns the data directly from the GitHub API endpoint. + * + * @return array + */ + protected function fetchLimits() + { + $result = $this->get('/rate_limit') ?: []; + + // Assemble Limit instances + foreach ($result['resources'] as $resourceName => $resource) { + $this->resources[$resourceName] = new RateLimitResource($resourceName, $resource); + } + + return $result; + } +} diff --git a/lib/Github/Api/RateLimit/RateLimitResource.php b/lib/Github/Api/RateLimit/RateLimitResource.php new file mode 100644 index 00000000000..661a4e5287c --- /dev/null +++ b/lib/Github/Api/RateLimit/RateLimitResource.php @@ -0,0 +1,73 @@ +name = $name; + $this->limit = $data['limit']; + $this->remaining = $data['remaining']; + $this->reset = $data['reset']; + } + + /** + * The name of the Limit, e.g. "core", "graphql", "search". + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * The rate limit amount. + * + * @return int + */ + public function getLimit() + { + return $this->limit; + } + + /** + * Number of requests remaining in time period before hitting the rate limit. + * + * @return int + */ + public function getRemaining() + { + return $this->remaining; + } + + /** + * Timestamp for when the rate limit will be reset. + * + * @return int + */ + public function getReset() + { + return $this->reset; + } +} diff --git a/lib/Github/Api/Repo.php b/lib/Github/Api/Repo.php index e0b891841f0..5653ae4c152 100644 --- a/lib/Github/Api/Repo.php +++ b/lib/Github/Api/Repo.php @@ -2,44 +2,127 @@ namespace Github\Api; +use Github\Api\Repository\Actions\Artifacts; +use Github\Api\Repository\Actions\Secrets; +use Github\Api\Repository\Actions\SelfHostedRunners; +use Github\Api\Repository\Actions\Variables; +use Github\Api\Repository\Actions\WorkflowJobs; +use Github\Api\Repository\Actions\WorkflowRuns; +use Github\Api\Repository\Actions\Workflows; +use Github\Api\Repository\Checks\CheckRuns; +use Github\Api\Repository\Checks\CheckSuites; use Github\Api\Repository\Collaborators; use Github\Api\Repository\Comments; use Github\Api\Repository\Commits; use Github\Api\Repository\Contents; use Github\Api\Repository\DeployKeys; use Github\Api\Repository\Downloads; -use Github\Api\Repository\Releases; use Github\Api\Repository\Forks; use Github\Api\Repository\Hooks; use Github\Api\Repository\Labels; +use Github\Api\Repository\Pages; +use Github\Api\Repository\Projects; +use Github\Api\Repository\Protection; +use Github\Api\Repository\Releases; +use Github\Api\Repository\SecretScanning; +use Github\Api\Repository\Stargazers; use Github\Api\Repository\Statuses; +use Github\Api\Repository\Traffic; /** * Searching repositories, getting repository information * and managing repository information for authenticated users. * * @link http://developer.github.com/v3/repos/ + * * @author Joseph Bielawski * @author Thibault Duplessis */ class Repo extends AbstractApi { + use AcceptHeaderTrait; + /** - * Search repositories by keyword: - * @link http://developer.github.com/v3/search/#search-repositories + * List all public repositories. * - * @param string $keyword the search query - * @param array $params + * @link https://developer.github.com/v3/repos/#list-all-public-repositories + * + * @param int|null $id The integer ID of the last Repository that you’ve seen. + * + * @return array list of users found + */ + public function all($id = null) + { + if (!is_int($id)) { + return $this->get('/repositories'); + } + + return $this->get('/repositories', ['since' => $id]); + } + + /** + * Get the last year of commit activity for a repository grouped by week. + * + * @link http://developer.github.com/v3/repos/statistics/#commit-activity + * + * @param string $username the user who owns the repository + * @param string $repository the name of the repository + * + * @return array commit activity grouped by week + */ + public function activity($username, $repository) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/stats/commit_activity'); + } + + /** + * Get contributor commit statistics for a repository. + * + * @link http://developer.github.com/v3/repos/statistics/#contributors + * + * @param string $username the user who owns the repository + * @param string $repository the name of the repository + * + * @return array list of contributors and their commit statistics + */ + public function statistics($username, $repository) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/stats/contributors'); + } + + /** + * Get a weekly aggregate of the number of additions and deletions pushed to a repository. + * + * @link http://developer.github.com/v3/repos/statistics/#code-frequency + * + * @param string $username the user who owns the repository + * @param string $repository the name of the repository + * + * @return array list of weeks and their commit statistics + */ + public function frequency($username, $repository) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/stats/code_frequency'); + } + + /** + * Get the weekly commit count for the repository owner and everyone else. + * + * @link http://developer.github.com/v3/repos/statistics/#participation * - * @return array list of founded repositories + * @param string $username the user who owns the repository + * @param string $repository the name of the repository + * + * @return array list of weekly commit count grouped by 'all' and 'owner' */ - public function find($keyword, array $params) + public function participation($username, $repository) { - return $this->get('legacy/repos/search/'.rawurlencode($keyword), array_merge(array('start_page' => 1), $params)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/stats/participation'); } /** - * List all repositories for an organization + * List all repositories for an organization. + * * @link http://developer.github.com/v3/repos/#list-organization-repositories * * @param string $organization the name of the organization @@ -47,39 +130,60 @@ public function find($keyword, array $params) * * @return array list of organization repositories */ - public function org($organization, array $params = array()) + public function org($organization, array $params = []) { - return $this->get('orgs/'.$organization.'/repos', array_merge(array('start_page' => 1), $params)); + return $this->get('/orgs/'.$organization.'/repos', array_merge(['start_page' => 1], $params)); } /** - * Get extended information about a repository by its username and repository name + * Get extended information about a repository by its username and repository name. + * * @link http://developer.github.com/v3/repos/ * * @param string $username the user who owns the repository * @param string $repository the name of the repository * - * @return array informations about the repository + * @return array information about the repository */ public function show($username, $repository) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository)); } /** - * Create repository + * Get extended information about a repository by its id. + * Note: at time of writing this is an undocumented feature but GitHub support have advised that it can be relied on. + * + * @link http://developer.github.com/v3/repos/ + * @link https://github.com/piotrmurach/github/issues/283 + * @link https://github.com/piotrmurach/github/issues/282 + * + * @param int $id the id of the repository + * + * @return array information about the repository + */ + public function showById($id) + { + return $this->get('/repositories/'.$id); + } + + /** + * Create repository. + * * @link http://developer.github.com/v3/repos/ * * @param string $name name of the repository * @param string $description repository description * @param string $homepage homepage url - * @param boolean $public `true` for public, `false` for private - * @param null|string $organization username of organization if applicable - * @param boolean $hasIssues `true` to enable issues for this repository, `false` to disable them - * @param boolean $hasWiki `true` to enable the wiki for this repository, `false` to disable it - * @param boolean $hadDownloads `true` to enable downloads for this repository, `false` to disable them - * @param integer $teamId The id of the team that will be granted access to this repository. This is only valid when creating a repo in an organization. - * @param boolean $autoInit `true` to create an initial commit with empty README, `false` for no initial commit + * @param bool $public `true` for public, `false` for private + * @param string|null $organization username of organization if applicable + * @param bool $hasIssues `true` to enable issues for this repository, `false` to disable them + * @param bool $hasWiki `true` to enable the wiki for this repository, `false` to disable it + * @param bool $hasDownloads `true` to enable downloads for this repository, `false` to disable them + * @param int $teamId The id of the team that will be granted access to this repository. This is only valid when creating a repo in an organization. + * @param bool $autoInit `true` to create an initial commit with empty README, `false` for no initial commit + * @param bool $hasProjects `true` to enable projects for this repository or false to disable them. + * @param string|null $visibility * * @return array returns repository data */ @@ -93,20 +197,27 @@ public function create( $hasWiki = false, $hasDownloads = false, $teamId = null, - $autoInit = false + $autoInit = false, + $hasProjects = true, + $visibility = null ) { - $path = null !== $organization ? 'orgs/'.$organization.'/repos' : 'user/repos'; - - $parameters = array( - 'name' => $name, - 'description' => $description, - 'homepage' => $homepage, - 'private' => !$public, - 'has_issues' => $hasIssues, - 'has_wiki' => $hasWiki, + $path = null !== $organization ? '/orgs/'.$organization.'/repos' : '/user/repos'; + + $parameters = [ + 'name' => $name, + 'description' => $description, + 'homepage' => $homepage, + 'private' => ($visibility ?? ($public ? 'public' : 'private')) === 'private', + 'has_issues' => $hasIssues, + 'has_wiki' => $hasWiki, 'has_downloads' => $hasDownloads, - 'auto_init' => $autoInit - ); + 'auto_init' => $autoInit, + 'has_projects' => $hasProjects, + ]; + + if ($visibility) { + $parameters['visibility'] = $visibility; + } if ($organization && $teamId) { $parameters['team_id'] = $teamId; @@ -116,22 +227,24 @@ public function create( } /** - * Set information of a repository + * Set information of a repository. + * * @link http://developer.github.com/v3/repos/ * * @param string $username the user who owns the repository * @param string $repository the name of the repository * @param array $values the key => value pairs to post * - * @return array informations about the repository + * @return array information about the repository */ public function update($username, $repository, array $values) { - return $this->patch('repos/'.rawurlencode($username).'/'.rawurlencode($repository), $values); + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository), $values); } /** - * Delete a repository + * Delete a repository. + * * @link http://developer.github.com/v3/repos/ * * @param string $username the user who owns the repository @@ -141,183 +254,346 @@ public function update($username, $repository, array $values) */ public function remove($username, $repository) { - return $this->delete('repos/'.rawurlencode($username).'/'.rawurlencode($repository)); + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository)); } - + /** - * Get the readme content for a repository by its username and repository name + * Get the readme content for a repository by its username and repository name. + * * @link http://developer.github.com/v3/repos/contents/#get-the-readme * * @param string $username the user who owns the repository * @param string $repository the name of the repository + * @param string $format one of formats: "raw", "html", or "v3+json" + * @param string $dir The alternate path to look for a README file + * @param array $params additional query params like "ref" to fetch readme for branch/tag + * + * @return string|array the readme content + */ + public function readme($username, $repository, $format = 'raw', $dir = null, $params = []) + { + $path = '/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/readme'; + + if (null !== $dir) { + $path .= '/'.rawurlencode($dir); + } + + return $this->get($path, $params, [ + 'Accept' => "application/vnd.github.$format", + ]); + } + + /** + * Create a repository dispatch event. + * + * @link https://developer.github.com/v3/repos/#create-a-repository-dispatch-event * - * @return array the readme content + * @param string $username the user who owns the repository + * @param string $repository the name of the repository + * @param string $eventType A custom webhook event name + * @param array|object $clientPayload The payload to pass to Github. + * + * @return mixed null on success, array on error with 'message' */ - public function readme($username, $repository) + public function dispatch($username, $repository, $eventType, $clientPayload) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/readme'); + if (is_array($clientPayload)) { + $clientPayload = (object) $clientPayload; + } + + return $this->post(\sprintf('/repos/%s/%s/dispatches', rawurlencode($username), rawurlencode($repository)), [ + 'event_type' => $eventType, + 'client_payload' => $clientPayload, + ]); } /** - * Manage the collaborators of a repository + * Manage the collaborators of a repository. + * * @link http://developer.github.com/v3/repos/collaborators/ * * @return Collaborators */ public function collaborators() { - return new Collaborators($this->client); + return new Collaborators($this->getClient()); } /** - * Manage the comments of a repository + * Manage the comments of a repository. + * * @link http://developer.github.com/v3/repos/comments/ * * @return Comments */ public function comments() { - return new Comments($this->client); + return new Comments($this->getClient()); } /** - * Manage the commits of a repository + * Manage the commits of a repository. + * * @link http://developer.github.com/v3/repos/commits/ * * @return Commits */ public function commits() { - return new Commits($this->client); + return new Commits($this->getClient()); + } + + /** + * @link https://docs.github.com/en/rest/reference/checks#check-runs + */ + public function checkRuns(): CheckRuns + { + return new CheckRuns($this->getClient()); + } + + /** + * @link https://docs.github.com/en/rest/reference/checks#check-suites + */ + public function checkSuites(): CheckSuites + { + return new CheckSuites($this->getClient()); + } + + /** + * @link https://developer.github.com/v3/actions/artifacts/#artifacts + */ + public function artifacts(): Artifacts + { + return new Artifacts($this->getClient()); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#workflows + */ + public function workflows(): Workflows + { + return new Workflows($this->getClient()); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#workflow-runs + */ + public function workflowRuns(): WorkflowRuns + { + return new WorkflowRuns($this->getClient()); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#workflow-jobs + */ + public function workflowJobs(): WorkflowJobs + { + return new WorkflowJobs($this->getClient()); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#self-hosted-runners + */ + public function selfHostedRunners(): SelfHostedRunners + { + return new SelfHostedRunners($this->getClient()); } /** - * Manage the content of a repository + * @link https://docs.github.com/en/rest/reference/actions#secrets + */ + public function secrets(): Secrets + { + return new Secrets($this->getClient()); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#secrets + */ + public function variables(): Variables + { + return new Variables($this->getClient()); + } + + /** + * Manage the content of a repository. + * * @link http://developer.github.com/v3/repos/contents/ * * @return Contents */ public function contents() { - return new Contents($this->client); + return new Contents($this->getClient()); } /** - * Manage the content of a repository + * Manage the content of a repository. + * * @link http://developer.github.com/v3/repos/downloads/ * * @return Downloads */ public function downloads() { - return new Downloads($this->client); + return new Downloads($this->getClient()); } /** - * Manage the releases of a repository (Currently Undocumented) - * @link http://developer.github.com/v3/repos/ + * Manage the releases of a repository (Currently Undocumented). + * + * @link http://developer.github.com/v3/repos/ * * @return Releases */ public function releases() { - return new Releases($this->client); + return new Releases($this->getClient()); } /** - * Manage the deploy keys of a repository + * Manage the deploy keys of a repository. + * * @link http://developer.github.com/v3/repos/keys/ * * @return DeployKeys */ public function keys() { - return new DeployKeys($this->client); + return new DeployKeys($this->getClient()); } /** - * Manage the forks of a repository + * Manage the forks of a repository. + * * @link http://developer.github.com/v3/repos/forks/ * * @return Forks */ public function forks() { - return new Forks($this->client); + return new Forks($this->getClient()); + } + + /** + * Manage the stargazers of a repository. + * + * @link https://developer.github.com/v3/activity/starring/#list-stargazers + * + * @return Stargazers + */ + public function stargazers() + { + return new Stargazers($this->getClient()); } /** - * Manage the hooks of a repository + * Manage the hooks of a repository. + * * @link http://developer.github.com/v3/issues/jooks/ * * @return Hooks */ public function hooks() { - return new Hooks($this->client); + return new Hooks($this->getClient()); } /** - * Manage the labels of a repository + * Manage the labels of a repository. + * * @link http://developer.github.com/v3/issues/labels/ * * @return Labels */ public function labels() { - return new Labels($this->client); + return new Labels($this->getClient()); } /** - * Manage the statuses of a repository + * Manage the statuses of a repository. + * * @link http://developer.github.com/v3/repos/statuses/ * * @return Statuses */ public function statuses() { - return new Statuses($this->client); + return new Statuses($this->getClient()); } /** - * Get the branch(es) of a repository + * Get the branch(es) of a repository. + * * @link http://developer.github.com/v3/repos/ * * @param string $username the username * @param string $repository the name of the repository * @param string $branch the name of the branch + * @param array $parameters parameters for the query string * * @return array list of the repository branches */ - public function branches($username, $repository, $branch = null) + public function branches($username, $repository, $branch = null, array $parameters = []) { - $url = 'repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches'; + $url = '/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches'; if (null !== $branch) { $url .= '/'.rawurlencode($branch); } - return $this->get($url); + return $this->get($url, $parameters); + } + + /** + * Sync a fork branch with the upstream repository. + * + * @link https://docs.github.com/en/rest/branches/branches#sync-a-fork-branch-with-the-upstream-repository + * + * @return array|string + */ + public function mergeUpstream(string $username, string $repository, string $branchName) + { + return $this->post( + '/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/merge-upstream', + ['branch' => $branchName] + ); + } + + /** + * Manage the protection of a repository branch. + * + * @link https://developer.github.com/v3/repos/branches/#get-branch-protection + * + * @return Protection + */ + public function protection() + { + return new Protection($this->getClient()); } /** - * Get the contributors of a repository + * Get the contributors of a repository. + * * @link http://developer.github.com/v3/repos/ * - * @param string $username the user who owns the repository - * @param string $repository the name of the repository - * @param boolean $includingAnonymous by default, the list only shows GitHub users. - * You can include non-users too by setting this to true + * @param string $username the user who owns the repository + * @param string $repository the name of the repository + * @param bool $includingAnonymous by default, the list only shows GitHub users. + * You can include non-users too by setting this to true + * * @return array list of the repo contributors */ public function contributors($username, $repository, $includingAnonymous = false) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/contributors', array( - 'anon' => $includingAnonymous ?: null - )); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/contributors', [ + 'anon' => $includingAnonymous ?: null, + ]); } /** - * Get the language breakdown of a repository + * Get the language breakdown of a repository. + * * @link http://developer.github.com/v3/repos/ * * @param string $username the user who owns the repository @@ -327,25 +603,28 @@ public function contributors($username, $repository, $includingAnonymous = false */ public function languages($username, $repository) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/languages'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/languages'); } /** - * Get the tags of a repository + * Get the tags of a repository. + * * @link http://developer.github.com/v3/repos/ * * @param string $username the user who owns the repository * @param string $repository the name of the repository + * @param array $params the additional parameters like milestone, assignees, labels, sort, direction * * @return array list of the repository tags */ - public function tags($username, $repository) + public function tags($username, $repository, array $params = []) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/tags'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/tags', $params); } /** - * Get the teams of a repository + * Get the teams of a repository. + * * @link http://developer.github.com/v3/repos/ * * @param string $username the user who owns the repo @@ -355,25 +634,26 @@ public function tags($username, $repository) */ public function teams($username, $repository) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/teams'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/teams'); } /** - * @param string $username - * @param string $repository - * @param integer $page + * @param string $username + * @param string $repository + * @param int $page * * @return array */ - public function watchers($username, $repository, $page = 1) + public function subscribers($username, $repository, $page = 1) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/watchers', array( - 'page' => $page - )); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/subscribers', [ + 'page' => $page, + ]); } /** - * Perform a merge + * Perform a merge. + * * @link http://developer.github.com/v3/repos/merging/ * * @param string $username @@ -382,14 +662,248 @@ public function watchers($username, $repository, $page = 1) * @param string $head The head to merge. This can be a branch name or a commit SHA1. * @param string $message Commit message to use for the merge commit. If omitted, a default message will be used. * - * @return array|null + * @return array|string */ public function merge($username, $repository, $base, $head, $message = null) { - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/merges', array( - 'base' => $base, - 'head' => $head, - 'commit_message' => $message - )); + $parameters = [ + 'base' => $base, + 'head' => $head, + ]; + + if (is_string($message)) { + $parameters['commit_message'] = $message; + } + + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/merges', $parameters); + } + + /** + * @param string $username + * @param string $repository + * @param array $parameters + * + * @return array + */ + public function milestones($username, $repository, array $parameters = []) + { + return $this->get('/repos/'.rawurldecode($username).'/'.rawurldecode($repository).'/milestones', $parameters); + } + + /** + * @link https://docs.github.com/en/rest/reference/repos#enable-automated-security-fixes + * + * @param string $username + * @param string $repository + * + * @return array|string + */ + public function enableAutomatedSecurityFixes(string $username, string $repository) + { + $this->acceptHeaderValue = 'application/vnd.github.london-preview+json'; + + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/automated-security-fixes'); + } + + /** + * @link https://docs.github.com/en/rest/reference/repos#disable-automated-security-fixes + * + * @param string $username + * @param string $repository + * + * @return array|string + */ + public function disableAutomatedSecurityFixes(string $username, string $repository) + { + $this->acceptHeaderValue = 'application/vnd.github.london-preview+json'; + + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/automated-security-fixes'); + } + + public function projects() + { + return new Projects($this->getClient()); + } + + public function traffic() + { + return new Traffic($this->getClient()); + } + + public function pages() + { + return new Pages($this->getClient()); + } + + /** + * @param string $username + * @param string $repository + * @param int $page + * + * @return array|string + * + * @see https://developer.github.com/v3/activity/events/#list-repository-events + */ + public function events($username, $repository, $page = 1) + { + return $this->get('/repos/'.rawurldecode($username).'/'.rawurldecode($repository).'/events', ['page' => $page]); + } + + /** + * Get the community profile metrics for a repository. + * + * @link https://developer.github.com/v3/repos/community/#retrieve-community-profile-metrics + * + * @param string $username + * @param string $repository + * + * @return array + */ + public function communityProfile($username, $repository) + { + //This api is in preview mode, so set the correct accept-header + $this->acceptHeaderValue = 'application/vnd.github.black-panther-preview+json'; + + return $this->get('/repos/'.rawurldecode($username).'/'.rawurldecode($repository).'/community/profile'); + } + + /** + * Get the contents of a repository's code of conduct. + * + * @link https://developer.github.com/v3/codes_of_conduct/#get-the-contents-of-a-repositorys-code-of-conduct + * + * @param string $username + * @param string $repository + * + * @return array + */ + public function codeOfConduct($username, $repository) + { + //This api is in preview mode, so set the correct accept-header + $this->acceptHeaderValue = 'application/vnd.github.scarlet-witch-preview+json'; + + return $this->get('/repos/'.rawurldecode($username).'/'.rawurldecode($repository).'/community/code_of_conduct'); + } + + /** + * List all topics for a repository. + * + * @link https://developer.github.com/v3/repos/#list-all-topics-for-a-repository + * + * @param string $username + * @param string $repository + * + * @return array + */ + public function topics($username, $repository) + { + //This api is in preview mode, so set the correct accept-header + $this->acceptHeaderValue = 'application/vnd.github.mercy-preview+json'; + + return $this->get('/repos/'.rawurldecode($username).'/'.rawurldecode($repository).'/topics'); + } + + /** + * Replace all topics for a repository. + * + * @link https://developer.github.com/v3/repos/#replace-all-topics-for-a-repository + * + * @param string $username + * @param string $repository + * @param array $topics + * + * @return array + */ + public function replaceTopics($username, $repository, array $topics) + { + //This api is in preview mode, so set the correct accept-header + $this->acceptHeaderValue = 'application/vnd.github.mercy-preview+json'; + + return $this->put('/repos/'.rawurldecode($username).'/'.rawurldecode($repository).'/topics', ['names' => $topics]); + } + + /** + * Transfer a repository. + * + * @link https://developer.github.com/v3/repos/#transfer-a-repository + * + * @param string $username + * @param string $repository + * @param string $newOwner + * @param array $teamId + * + * @return array + */ + public function transfer($username, $repository, $newOwner, $teamId = []) + { + return $this->post('/repos/'.rawurldecode($username).'/'.rawurldecode($repository).'/transfer', ['new_owner' => $newOwner, 'team_id' => $teamId]); + } + + /** + * Create a repository using a template. + * + * @link https://developer.github.com/v3/repos/#create-a-repository-using-a-template + * + * @return array + */ + public function createFromTemplate(string $templateOwner, string $templateRepo, array $parameters = []) + { + //This api is in preview mode, so set the correct accept-header + $this->acceptHeaderValue = 'application/vnd.github.baptiste-preview+json'; + + return $this->post('/repos/'.rawurldecode($templateOwner).'/'.rawurldecode($templateRepo).'/generate', $parameters); + } + + /** + * Check if vulnerability alerts are enabled for a repository. + * + * @link https://developer.github.com/v3/repos/#check-if-vulnerability-alerts-are-enabled-for-a-repository + * + * @param string $username the username + * @param string $repository the repository + * + * @return array|string + */ + public function isVulnerabilityAlertsEnabled(string $username, string $repository) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/vulnerability-alerts'); + } + + /** + * Enable vulnerability alerts for a repository. + * + * @link https://developer.github.com/v3/repos/#enable-vulnerability-alerts + * + * @param string $username the username + * @param string $repository the repository + * + * @return array|string + */ + public function enableVulnerabilityAlerts(string $username, string $repository) + { + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/vulnerability-alerts'); + } + + /** + * Disable vulnerability alerts for a repository. + * + * @link https://developer.github.com/v3/repos/#disable-vulnerability-alerts + * + * @param string $username the username + * @param string $repository the repository + * + * @return array|string + */ + public function disableVulnerabilityAlerts(string $username, string $repository) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/vulnerability-alerts'); + } + + /** + * @return SecretScanning + */ + public function secretScanning(): SecretScanning + { + return new SecretScanning($this->getClient()); } } diff --git a/lib/Github/Api/Repository/Actions/Artifacts.php b/lib/Github/Api/Repository/Actions/Artifacts.php new file mode 100644 index 00000000000..84f3b0604af --- /dev/null +++ b/lib/Github/Api/Repository/Actions/Artifacts.php @@ -0,0 +1,82 @@ +get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/artifacts', $parameters); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#list-workflow-run-artifacts + * + * @param string $username + * @param string $repository + * @param int $runId + * + * @return array + */ + public function runArtifacts(string $username, string $repository, int $runId) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/runs/'.$runId.'/artifacts'); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#get-an-artifact + * + * @param string $username + * @param string $repository + * @param int $artifactId + * + * @return array + */ + public function show(string $username, string $repository, int $artifactId) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/artifacts/'.$artifactId); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#delete-an-artifact + * + * @param string $username + * @param string $repository + * @param int $artifactId + * + * @return array + */ + public function remove(string $username, string $repository, int $artifactId) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/artifacts/'.$artifactId); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#download-an-artifact + * + * @param string $username + * @param string $repository + * @param int $artifactId + * @param string $format + * + * @return array + */ + public function download(string $username, string $repository, int $artifactId, string $format = 'zip') + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/artifacts/'.$artifactId.'/'.$format); + } +} diff --git a/lib/Github/Api/Repository/Actions/Secrets.php b/lib/Github/Api/Repository/Actions/Secrets.php new file mode 100644 index 00000000000..2085a133f7a --- /dev/null +++ b/lib/Github/Api/Repository/Actions/Secrets.php @@ -0,0 +1,95 @@ +get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/secrets'); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#get-a-repository-secret + * + * @param string $username + * @param string $repository + * @param string $secretName + * + * @return array|string + */ + public function show(string $username, string $repository, string $secretName) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/secrets/'.rawurlencode($secretName)); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#create-or-update-a-repository-secret + * + * @param string $username + * @param string $repository + * @param string $secretName + * @param array $parameters + * + * @return array|string + */ + public function create(string $username, string $repository, string $secretName, array $parameters = []) + { + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/secrets/'.rawurlencode($secretName), $parameters); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#create-or-update-a-repository-secret + * + * @param string $username + * @param string $repository + * @param string $secretName + * @param array $parameters + * + * @return array|string + */ + public function update(string $username, string $repository, string $secretName, array $parameters = []) + { + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/secrets/'.rawurlencode($secretName), $parameters); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#delete-a-repository-secret + * + * @param string $username + * @param string $repository + * @param string $secretName + * + * @return array|string + */ + public function remove(string $username, string $repository, string $secretName) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/secrets/'.rawurlencode($secretName)); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#get-a-repository-public-key + * + * @param string $username + * @param string $repository + * + * @return array|string + */ + public function publicKey(string $username, string $repository) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/secrets/public-key'); + } +} diff --git a/lib/Github/Api/Repository/Actions/SelfHostedRunners.php b/lib/Github/Api/Repository/Actions/SelfHostedRunners.php new file mode 100644 index 00000000000..7eb1a9d4e39 --- /dev/null +++ b/lib/Github/Api/Repository/Actions/SelfHostedRunners.php @@ -0,0 +1,65 @@ +get('/repos/'.rawurlencode($username).'/'.rawurldecode($repository).'/actions/runners'); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#get-a-self-hosted-runner-for-a-repository + * + * @param string $username + * @param string $repository + * @param int $runnerId + * + * @return array|string + */ + public function show(string $username, string $repository, int $runnerId) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurldecode($repository).'/actions/runners/'.$runnerId); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#delete-a-self-hosted-runner-from-a-repository + * + * @param string $username + * @param string $repository + * @param int $runnerId + * + * @return array|string + */ + public function remove(string $username, string $repository, int $runnerId) + { + return $this->delete('/repos/'.rawurldecode($username).'/'.rawurldecode($repository).'/actions/runners/'.$runnerId); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#list-runner-applications-for-a-repository + * + * @param string $username + * @param string $repository + * + * @return array|string + */ + public function applications(string $username, string $repository) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/runners/downloads'); + } +} diff --git a/lib/Github/Api/Repository/Actions/Variables.php b/lib/Github/Api/Repository/Actions/Variables.php new file mode 100644 index 00000000000..7414e82810b --- /dev/null +++ b/lib/Github/Api/Repository/Actions/Variables.php @@ -0,0 +1,81 @@ +get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/variables'); + } + + /** + * @link https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#get-a-repository-variable + * + * @param string $username + * @param string $repository + * @param string $variableName + * + * @return array|string + */ + public function show(string $username, string $repository, string $variableName) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/variables/'.rawurlencode($variableName)); + } + + /** + * @link https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#create-a-repository-variable + * + * @param string $username + * @param string $repository + * @param array $parameters + * + * @return array|string + */ + public function create(string $username, string $repository, array $parameters = []) + { + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/variables', $parameters); + } + + /** + * @link https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#update-a-repository-variable + * + * @param string $username + * @param string $repository + * @param string $variableName + * @param array $parameters + * + * @return array|string + */ + public function update(string $username, string $repository, string $variableName, array $parameters = []) + { + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/variables/'.rawurlencode($variableName), $parameters); + } + + /** + * @link https://docs.github.com/en/rest/actions/variables?apiVersion=2022-11-28#delete-a-repository-variable + * + * @param string $username + * @param string $repository + * @param string $variableName + * + * @return array|string + */ + public function remove(string $username, string $repository, string $variableName) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/variables/'.rawurlencode($variableName)); + } +} diff --git a/lib/Github/Api/Repository/Actions/WorkflowJobs.php b/lib/Github/Api/Repository/Actions/WorkflowJobs.php new file mode 100644 index 00000000000..3167d3dbf81 --- /dev/null +++ b/lib/Github/Api/Repository/Actions/WorkflowJobs.php @@ -0,0 +1,54 @@ +get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/runs/'.$runId.'/jobs', $parameters); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#get-a-job-for-a-workflow-run + * + * @param string $username + * @param string $repository + * @param int $jobId + * + * @return array + */ + public function show(string $username, string $repository, int $jobId) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/jobs/'.$jobId); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#download-job-logs-for-a-workflow-run + * + * @param string $username + * @param string $repository + * @param int $jobId + * + * @return array + */ + public function downloadLogs(string $username, string $repository, int $jobId) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/jobs/'.$jobId.'/logs'); + } +} diff --git a/lib/Github/Api/Repository/Actions/WorkflowRuns.php b/lib/Github/Api/Repository/Actions/WorkflowRuns.php new file mode 100644 index 00000000000..d6f95f1ed94 --- /dev/null +++ b/lib/Github/Api/Repository/Actions/WorkflowRuns.php @@ -0,0 +1,155 @@ +get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/runs', $parameters); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#list-workflow-runs + * + * @param string $username + * @param string $repository + * @param string $workflow + * @param array $parameters + * + * @return array + */ + public function listRuns(string $username, string $repository, string $workflow, array $parameters = []) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/workflows/'.rawurlencode($workflow).'/runs', $parameters); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#get-a-workflow-run + * + * @param string $username + * @param string $repository + * @param int $runId + * @param array $parameters + * + * @return array + */ + public function show(string $username, string $repository, int $runId, array $parameters = []) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/runs/'.$runId, $parameters); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#delete-a-workflow-run + * + * @param string $username + * @param string $repository + * @param int $runId + * + * @return array|string + */ + public function remove(string $username, string $repository, int $runId) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/runs/'.$runId); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#re-run-a-workflow + * + * @param string $username + * @param string $repository + * @param int $runId + * + * @return array + */ + public function rerun(string $username, string $repository, int $runId) + { + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/runs/'.$runId.'/rerun'); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#cancel-a-workflow-run + * + * @param string $username + * @param string $repository + * @param int $runId + * + * @return array + */ + public function cancel(string $username, string $repository, int $runId) + { + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/runs/'.$runId.'/cancel'); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#get-workflow-run-usage + * + * @param string $username + * @param string $repository + * @param int $runId + * + * @return array + */ + public function usage(string $username, string $repository, int $runId) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/runs/'.$runId.'/timing'); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#download-workflow-run-logs + * + * @param string $username + * @param string $repository + * @param int $runId + * + * @return array|string + */ + public function downloadLogs(string $username, string $repository, int $runId) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/runs/'.$runId.'/logs'); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#delete-workflow-run-logs + * + * @param string $username + * @param string $repository + * @param int $runId + * + * @return array|string + */ + public function deleteLogs(string $username, string $repository, int $runId) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/runs/'.$runId.'/logs'); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#approve-a-workflow-run-for-a-fork-pull-request + * + * @param string $username + * @param string $repository + * @param int $runId + * + * @return array|string + * + * @experimental This endpoint is currently in beta. + */ + public function approve(string $username, string $repository, int $runId) + { + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/runs/'.$runId.'/approve'); + } +} diff --git a/lib/Github/Api/Repository/Actions/Workflows.php b/lib/Github/Api/Repository/Actions/Workflows.php new file mode 100644 index 00000000000..9a1c9e31c7b --- /dev/null +++ b/lib/Github/Api/Repository/Actions/Workflows.php @@ -0,0 +1,82 @@ +get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/workflows', $parameters); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#get-a-workflow + * + * @param string $username + * @param string $repository + * @param string|int $workflow + * + * @return array + */ + public function show(string $username, string $repository, $workflow) + { + if (is_string($workflow)) { + $workflow = rawurlencode($workflow); + } + + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/workflows/'.$workflow); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#get-workflow-usage + * + * @param string $username + * @param string $repository + * @param string|int $workflow + * + * @return array|string + */ + public function usage(string $username, string $repository, $workflow) + { + if (is_string($workflow)) { + $workflow = rawurlencode($workflow); + } + + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/workflows/'.$workflow.'/timing'); + } + + /** + * @link https://docs.github.com/en/rest/reference/actions#create-a-workflow-dispatch-event + * + * @param string $username + * @param string $repository + * @param string|int $workflow + * @param string $ref + * @param array $inputs + * + * @return array|string empty + */ + public function dispatches(string $username, string $repository, $workflow, string $ref, ?array $inputs = null) + { + if (is_string($workflow)) { + $workflow = rawurlencode($workflow); + } + $parameters = array_filter(['ref' => $ref, 'inputs' => $inputs]); + + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/actions/workflows/'.$workflow.'/dispatches', $parameters); + } +} diff --git a/lib/Github/Api/Repository/Assets.php b/lib/Github/Api/Repository/Assets.php index 039b31f896b..043016e7801 100644 --- a/lib/Github/Api/Repository/Assets.php +++ b/lib/Github/Api/Repository/Assets.php @@ -3,61 +3,69 @@ namespace Github\Api\Repository; use Github\Api\AbstractApi; +use Github\Api\AcceptHeaderTrait; use Github\Exception\ErrorException; use Github\Exception\MissingArgumentException; -use Github\HttpClient\HttpClient; /** * @link http://developer.github.com/v3/repos/releases/ + * * @author Evgeniy Guseletov */ class Assets extends AbstractApi { + use AcceptHeaderTrait; + /** * Get all release's assets in selected repository - * GET /repos/:owner/:repo/releases/:id/assets + * GET /repos/:owner/:repo/releases/:id/assets. * - * @param string $username the user who owns the repo - * @param string $repository the name of the repo - * @param integer $id the id of the release + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * @param int $id the id of the release * * @return array */ public function all($username, $repository, $id) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/'.rawurlencode($id).'/assets'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/'.$id.'/assets'); } /** * Get an asset in selected repository's release - * GET /repos/:owner/:repo/releases/assets/:id + * GET /repos/:owner/:repo/releases/assets/:id. * - * @param string $username the user who owns the repo - * @param string $repository the name of the repo - * @param integer $id the id of the asset + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * @param int $id the id of the asset * - * @return array + * @return array|string */ - public function show($username, $repository, $id) + public function show($username, $repository, $id, bool $returnBinaryContent = false) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/assets/'.rawurlencode($id)); + if ($returnBinaryContent) { + $this->acceptHeaderValue = 'application/octet-stream'; + } + + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/assets/'.$id); } /** * Create an asset for selected repository's release - * POST /repos/:owner/:repo/releases/:id/assets?name=:filename + * POST /repos/:owner/:repo/releases/:id/assets?name=:filename. * * Creating an asset requires support for server name indentification (SNI) * so this must be supported by your PHP version. + * * @see http://developer.github.com/v3/repos/releases/#upload-a-release-asset * @see http://php.net/manual/en/openssl.constsni.php * - * @param string $username the user who owns the repo - * @param string $repository the name of the repo - * @param integer $id the id of the release - * @param string $name the filename for the asset - * @param string $contentType the content type for the asset - * @param string $content the content of the asset + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * @param int $id the id of the release + * @param string $name the filename for the asset + * @param string $contentType the content type for the asset + * @param string $content the content of the asset * * @throws MissingArgumentException * @throws ErrorException @@ -66,32 +74,24 @@ public function show($username, $repository, $id) */ public function create($username, $repository, $id, $name, $contentType, $content) { - if (!defined('OPENSSL_TLSEXT_SERVER_NAME') || !OPENSSL_TLSEXT_SERVER_NAME) { - throw new ErrorException('Asset upload support requires Server Name Indication. This is not supported se your PHP version. See http://php.net/manual/en/openssl.constsni.php.'); + if (!defined('OPENSSL_TLSEXT_SERVER_NAME') || OPENSSL_TLSEXT_SERVER_NAME == 0) { + throw new ErrorException('Asset upload support requires Server Name Indication. This is not supported by your PHP version. See https://www.php.net/manual/en/openssl.constsni.php.'); } // Asset creation requires a separate endpoint, uploads.github.com. // Change the base url for the HTTP client temporarily while we execute // this request. - $baseUrl = $this->client->getHttpClient()->client->getBaseUrl(); - $this->client->getHttpClient()->client->setBaseUrl('https://uploads.github.com/'); - - $response = $this->postRaw('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/'.rawurlencode($id).'/assets?name='.$name, $content, array('Content-Type' => $contentType)); - - // Reset the base url. - $this->client->getHttpClient()->client->setBaseUrl($baseUrl); - - return $response; + return $this->postRaw('https://uploads.github.com/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/'.$id.'/assets?name='.$name, $content, ['Content-Type' => $contentType]); } /** * Edit an asset in selected repository's release - * PATCH /repos/:owner/:repo/releases/assets/:id + * PATCH /repos/:owner/:repo/releases/assets/:id. * - * @param string $username the user who owns the repo - * @param string $repository the name of the repo - * @param integer $id the id of the asset - * @param array $params request parameters + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * @param int $id the id of the asset + * @param array $params request parameters * * @throws MissingArgumentException * @@ -103,21 +103,21 @@ public function edit($username, $repository, $id, array $params) throw new MissingArgumentException('name'); } - return $this->patch('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/assets/'.rawurlencode($id), $params); + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/assets/'.$id, $params); } /** * Delete an asset in selected repository's release - * DELETE /repos/:owner/:repo/releases/assets/:id + * DELETE /repos/:owner/:repo/releases/assets/:id. * - * @param string $username the user who owns the repo - * @param string $repository the name of the repo - * @param integer $id the id of the asset + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * @param int $id the id of the asset * * @return array */ public function remove($username, $repository, $id) { - return $this->delete('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/assets/'.rawurlencode($id)); + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/assets/'.$id); } } diff --git a/lib/Github/Api/Repository/Checks/CheckRuns.php b/lib/Github/Api/Repository/Checks/CheckRuns.php new file mode 100644 index 00000000000..1ddee3770c8 --- /dev/null +++ b/lib/Github/Api/Repository/Checks/CheckRuns.php @@ -0,0 +1,96 @@ +acceptHeaderValue = 'application/vnd.github.antiope-preview+json'; + + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/check-runs', $params); + } + + /** + * @link https://docs.github.com/en/rest/reference/checks#get-a-check-run + * + * @return array + */ + public function show(string $username, string $repository, int $checkRunId) + { + $this->acceptHeaderValue = 'application/vnd.github.antiope-preview+json'; + + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/check-runs/'.$checkRunId); + } + + /** + * @link https://docs.github.com/en/rest/reference/checks#update-a-check-run + * + * @return array + */ + public function update(string $username, string $repository, int $checkRunId, array $params = []) + { + $this->acceptHeaderValue = 'application/vnd.github.antiope-preview+json'; + + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/check-runs/'.$checkRunId, $params); + } + + /** + * @link https://docs.github.com/en/rest/reference/checks#list-check-run-annotations + * + * @return array + */ + public function annotations(string $username, string $repository, int $checkRunId) + { + $this->acceptHeaderValue = 'application/vnd.github.antiope-preview+json'; + + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/check-runs/'.$checkRunId.'/annotations'); + } + + /** + * @link https://docs.github.com/en/rest/reference/checks#list-check-runs-in-a-check-suite + * + * @return array + */ + public function allForCheckSuite(string $username, string $repository, int $checkSuiteId, array $params = []) + { + $this->acceptHeaderValue = 'application/vnd.github.antiope-preview+json'; + + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/check-suites/'.$checkSuiteId.'/check-runs', $params); + } + + /** + * @link https://docs.github.com/en/rest/reference/checks#list-check-runs-for-a-git-reference + * + * @return array + */ + public function allForReference(string $username, string $repository, string $ref, array $params = []) + { + $this->acceptHeaderValue = 'application/vnd.github.antiope-preview+json'; + + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/commits/'.rawurlencode($ref).'/check-runs', $params); + } + + /** + * @link https://docs.github.com/en/rest/reference/checks#rerequest-a-check-run + * + * @return array + */ + public function rerequest(string $username, string $repository, int $checkRunId) + { + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/check-runs/'.$checkRunId.'/rerequest'); + } +} diff --git a/lib/Github/Api/Repository/Checks/CheckSuites.php b/lib/Github/Api/Repository/Checks/CheckSuites.php new file mode 100644 index 00000000000..40c83a566c1 --- /dev/null +++ b/lib/Github/Api/Repository/Checks/CheckSuites.php @@ -0,0 +1,74 @@ +acceptHeaderValue = 'application/vnd.github.antiope-preview+json'; + + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/check-suites', $params); + } + + /** + * @link https://docs.github.com/en/rest/reference/checks#update-repository-preferences-for-check-suites + * + * @return array + */ + public function updatePreferences(string $username, string $repository, array $params = []) + { + $this->acceptHeaderValue = 'application/vnd.github.antiope-preview+json'; + + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/check-suites/preferences', $params); + } + + /** + * @link https://docs.github.com/en/rest/reference/checks#get-a-check-suite + * + * @return array + */ + public function getCheckSuite(string $username, string $repository, int $checkSuiteId) + { + $this->acceptHeaderValue = 'application/vnd.github.antiope-preview+json'; + + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/check-suites/'.$checkSuiteId); + } + + /** + * @link https://docs.github.com/en/rest/reference/checks#rerequest-a-check-suite + * + * @return array + */ + public function rerequest(string $username, string $repository, int $checkSuiteId) + { + $this->acceptHeaderValue = 'application/vnd.github.antiope-preview+json'; + + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/check-suites/'.$checkSuiteId.'/rerequest'); + } + + /** + * @link https://docs.github.com/en/rest/reference/checks#list-check-suites-for-a-git-reference + * + * @return array + */ + public function allForReference(string $username, string $repository, string $ref, array $params = []) + { + $this->acceptHeaderValue = 'application/vnd.github.antiope-preview+json'; + + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/commits/'.rawurlencode($ref).'/check-suites', $params); + } +} diff --git a/lib/Github/Api/Repository/Collaborators.php b/lib/Github/Api/Repository/Collaborators.php index 89a95068559..5c61b9bfee3 100644 --- a/lib/Github/Api/Repository/Collaborators.php +++ b/lib/Github/Api/Repository/Collaborators.php @@ -6,27 +6,79 @@ /** * @link http://developer.github.com/v3/repos/collaborators/ + * * @author Joseph Bielawski */ class Collaborators extends AbstractApi { - public function all($username, $repository) + /** + * @link https://developer.github.com/v3/repos/collaborators/#list-collaborators + * + * @param string $username + * @param string $repository + * @param array $params + * + * @return array|string + */ + public function all($username, $repository, array $params = []) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/collaborators'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/collaborators', $params); } + /** + * @link https://developer.github.com/v3/repos/collaborators/#check-if-a-user-is-a-collaborator + * + * @param string $username + * @param string $repository + * @param string $collaborator + * + * @return array|string + */ public function check($username, $repository, $collaborator) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/collaborators/'.rawurlencode($collaborator)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/collaborators/'.rawurlencode($collaborator)); } - public function add($username, $repository, $collaborator) + /** + * @link https://developer.github.com/v3/repos/collaborators/#add-user-as-a-collaborator + * + * @param string $username + * @param string $repository + * @param string $collaborator + * @param array $params + * + * @return array|string + */ + public function add($username, $repository, $collaborator, array $params = []) { - return $this->put('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/collaborators/'.rawurlencode($collaborator)); + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/collaborators/'.rawurlencode($collaborator), $params); } + /** + * @link https://developer.github.com/v3/repos/collaborators/#remove-user-as-a-collaborator + * + * @param string $username + * @param string $repository + * @param string $collaborator + * + * @return array|string + */ public function remove($username, $repository, $collaborator) { - return $this->delete('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/collaborators/'.rawurlencode($collaborator)); + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/collaborators/'.rawurlencode($collaborator)); + } + + /** + * @link https://developer.github.com/v3/repos/collaborators/#review-a-users-permission-level + * + * @param string $username + * @param string $repository + * @param string $collaborator + * + * @return array|string + */ + public function permission($username, $repository, $collaborator) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/collaborators/'.rawurlencode($collaborator).'/permission'); } } diff --git a/lib/Github/Api/Repository/Comments.php b/lib/Github/Api/Repository/Comments.php index cce0e5059d6..40eb2b53388 100644 --- a/lib/Github/Api/Repository/Comments.php +++ b/lib/Github/Api/Repository/Comments.php @@ -3,48 +3,51 @@ namespace Github\Api\Repository; use Github\Api\AbstractApi; +use Github\Api\AcceptHeaderTrait; use Github\Exception\MissingArgumentException; /** * @link http://developer.github.com/v3/repos/comments/ + * * @author Joseph Bielawski + * @author Tobias Nyholm */ class Comments extends AbstractApi { + use AcceptHeaderTrait; + + /** + * Configure the body type. + * + * @link https://developer.github.com/v3/repos/comments/#custom-media-types + * + * @param string|null $bodyType + * + * @return $this + */ public function configure($bodyType = null) { - switch ($bodyType) { - case 'raw': - $header = sprintf('Accept: application/vnd.github.%s.raw+json', $this->client->getOption('api_version')); - break; - - case 'text': - $header = sprintf('Accept: application/vnd.github.%s.text+json', $this->client->getOption('api_version')); - break; - - case 'html': - $header = sprintf('Accept: application/vnd.github.%s.html+json', $this->client->getOption('api_version')); - break; - - default: - $header = sprintf('Accept: application/vnd.github.%s.full+json', $this->client->getOption('api_version')); + if (!in_array($bodyType, ['raw', 'text', 'html'])) { + $bodyType = 'full'; } - $this->client->setHeaders(array($header)); + $this->acceptHeaderValue = sprintf('application/vnd.github.%s.%s+json', $this->getApiVersion(), $bodyType); + + return $this; } public function all($username, $repository, $sha = null) { if (null === $sha) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/comments'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/comments'); } - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/commits/'.rawurlencode($sha).'/comments'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/commits/'.rawurlencode($sha).'/comments'); } public function show($username, $repository, $comment) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/comments/'.rawurlencode($comment)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/comments/'.rawurlencode($comment)); } public function create($username, $repository, $sha, array $params) @@ -53,7 +56,7 @@ public function create($username, $repository, $sha, array $params) throw new MissingArgumentException('body'); } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/commits/'.rawurlencode($sha).'/comments', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/commits/'.rawurlencode($sha).'/comments', $params); } public function update($username, $repository, $comment, array $params) @@ -62,11 +65,11 @@ public function update($username, $repository, $comment, array $params) throw new MissingArgumentException('body'); } - return $this->patch('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/comments/'.rawurlencode($comment), $params); + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/comments/'.rawurlencode($comment), $params); } public function remove($username, $repository, $comment) { - return $this->delete('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/comments/'.rawurlencode($comment)); + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/comments/'.rawurlencode($comment)); } } diff --git a/lib/Github/Api/Repository/Commits.php b/lib/Github/Api/Repository/Commits.php index 9c8726bd3b8..0bc5598cbff 100644 --- a/lib/Github/Api/Repository/Commits.php +++ b/lib/Github/Api/Repository/Commits.php @@ -6,22 +6,33 @@ /** * @link http://developer.github.com/v3/repos/commits/ + * * @author Joseph Bielawski */ class Commits extends AbstractApi { public function all($username, $repository, array $params) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/commits', $params); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/commits', $params); } - public function compare($username, $repository, $base, $head) + public function compare($username, $repository, $base, $head, $mediaType = null, array $params = []) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/compare/'.rawurlencode($base).'...'.rawurlencode($head)); + $headers = []; + if (null !== $mediaType) { + $headers['Accept'] = $mediaType; + } + + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/compare/'.rawurlencode($base).'...'.rawurlencode($head), $params, $headers); } public function show($username, $repository, $sha) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/commits/'.rawurlencode($sha)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/commits/'.rawurlencode($sha)); + } + + public function pulls($username, $repository, $sha, array $params = []) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/commits/'.rawurlencode($sha).'/pulls', $params); } } diff --git a/lib/Github/Api/Repository/Contents.php b/lib/Github/Api/Repository/Contents.php index 47ce7a462e8..a3cc1a3ea0e 100644 --- a/lib/Github/Api/Repository/Contents.php +++ b/lib/Github/Api/Repository/Contents.php @@ -3,96 +3,282 @@ namespace Github\Api\Repository; use Github\Api\AbstractApi; -use Github\Exception\InvalidArgumentException; +use Github\Api\AcceptHeaderTrait; use Github\Exception\ErrorException; +use Github\Exception\InvalidArgumentException; +use Github\Exception\MissingArgumentException; +use Github\Exception\TwoFactorAuthenticationRequiredException; /** * @link http://developer.github.com/v3/repos/contents/ + * * @author Joseph Bielawski */ class Contents extends AbstractApi { + use AcceptHeaderTrait; + /** - * Get content of README file in a repository + * Configure the body type. + * + * @link https://developer.github.com/v3/repo/contents/#custom-media-types + * + * @param string|null $bodyType + * + * @return $this + */ + public function configure($bodyType = null) + { + if (!in_array($bodyType, ['html', 'object'])) { + $bodyType = 'raw'; + } + + $this->acceptHeaderValue = sprintf('application/vnd.github.%s.%s', $this->getApiVersion(), $bodyType); + + return $this; + } + + /** + * Get content of README file in a repository. + * * @link http://developer.github.com/v3/repos/contents/ * * @param string $username the user who owns the repository * @param string $repository the name of the repository - * @param null|string $reference reference to a branch or commit + * @param string|null $reference reference to a branch or commit * * @return array information for README file */ public function readme($username, $repository, $reference = null) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/readme', array( - 'ref' => $reference - )); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/readme', [ + 'ref' => $reference, + ]); } /** - * Get contents of any file or directory in a repository + * Get contents of any file or directory in a repository. + * * @link http://developer.github.com/v3/repos/contents/ * + * @param string $username the user who owns the repository + * @param string $repository the name of the repository + * @param string|null $path path to file or directory + * @param string|null $reference reference to a branch or commit + * @param array $requestHeaders request headers + * + * @return array|string information for file | information for each item in directory + */ + public function show($username, $repository, $path = null, $reference = null, $requestHeaders = []) + { + $url = '/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/contents'; + if (null !== $path) { + $url .= '/'.rawurlencode($path); + } + + return $this->get($url, [ + 'ref' => $reference, + ], $requestHeaders); + } + + /** + * Creates a new file in a repository. + * + * @link http://developer.github.com/v3/repos/contents/#create-a-file + * * @param string $username the user who owns the repository * @param string $repository the name of the repository - * @param null|string $path path to file or directory - * @param null|string $reference reference to a branch or commit + * @param string $path path to file + * @param string $content contents of the new file + * @param string $message the commit message + * @param string|null $branch name of a branch + * @param null|array $committer information about the committer * - * @return array information for file | information for each item in directory + * @throws MissingArgumentException + * + * @return array information about the new file */ - public function show($username, $repository, $path = null, $reference = null) + public function create($username, $repository, $path, $content, $message, $branch = null, ?array $committer = null) { - $url = 'repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/contents'; + $url = '/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/contents/'.rawurlencode($path); + + $parameters = [ + 'content' => base64_encode($content), + 'message' => $message, + ]; + + if (null !== $branch) { + $parameters['branch'] = $branch; + } + + if (null !== $committer) { + if (!isset($committer['name'], $committer['email'])) { + throw new MissingArgumentException(['name', 'email']); + } + $parameters['committer'] = $committer; + } + + return $this->put($url, $parameters); + } + + /** + * Checks that a given path exists in a repository. + * + * @param string $username the user who owns the repository + * @param string $repository the name of the repository + * @param string $path path of file to check + * @param string|null $reference reference to a branch or commit + * + * @return bool + */ + public function exists($username, $repository, $path, $reference = null) + { + $url = '/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/contents'; + if (null !== $path) { $url .= '/'.rawurlencode($path); } - return $this->get($url, array( - 'ref' => $reference - )); + try { + $response = $this->head($url, [ + 'ref' => $reference, + ]); + + if ($response->getStatusCode() !== 200) { + return false; + } + } catch (TwoFactorAuthenticationRequiredException $ex) { + throw $ex; + } catch (\Exception $ex) { + return false; + } + + return true; + } + + /** + * Updates the contents of a file in a repository. + * + * @link http://developer.github.com/v3/repos/contents/#update-a-file + * + * @param string $username the user who owns the repository + * @param string $repository the name of the repository + * @param string $path path to file + * @param string $content contents of the new file + * @param string $message the commit message + * @param string $sha blob SHA of the file being replaced + * @param string|null $branch name of a branch + * @param null|array $committer information about the committer + * + * @throws MissingArgumentException + * + * @return array information about the updated file + */ + public function update($username, $repository, $path, $content, $message, $sha, $branch = null, ?array $committer = null) + { + $url = '/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/contents/'.rawurlencode($path); + + $parameters = [ + 'content' => base64_encode($content), + 'message' => $message, + 'sha' => $sha, + ]; + + if (null !== $branch) { + $parameters['branch'] = $branch; + } + + if (null !== $committer) { + if (!isset($committer['name'], $committer['email'])) { + throw new MissingArgumentException(['name', 'email']); + } + $parameters['committer'] = $committer; + } + + return $this->put($url, $parameters); + } + + /** + * Deletes a file from a repository. + * + * @link http://developer.github.com/v3/repos/contents/#delete-a-file + * + * @param string $username the user who owns the repository + * @param string $repository the name of the repository + * @param string $path path to file + * @param string $message the commit message + * @param string $sha blob SHA of the file being deleted + * @param string|null $branch name of a branch + * @param null|array $committer information about the committer + * + * @throws MissingArgumentException + * + * @return array information about the updated file + */ + public function rm($username, $repository, $path, $message, $sha, $branch = null, ?array $committer = null) + { + $url = '/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/contents/'.rawurlencode($path); + + $parameters = [ + 'message' => $message, + 'sha' => $sha, + ]; + + if (null !== $branch) { + $parameters['branch'] = $branch; + } + + if (null !== $committer) { + if (!isset($committer['name'], $committer['email'])) { + throw new MissingArgumentException(['name', 'email']); + } + $parameters['committer'] = $committer; + } + + return $this->delete($url, $parameters); } /** - * Get content of archives in a repository + * Get content of archives in a repository. + * * @link http://developer.github.com/v3/repos/contents/ * * @param string $username the user who owns the repository * @param string $repository the name of the repository * @param string $format format of archive: tarball or zipball - * @param null|string $reference reference to a branch or commit + * @param string|null $reference reference to a branch or commit * - * @return array information for archives + * @return string repository archive binary data */ public function archive($username, $repository, $format, $reference = null) { - if (!in_array($format, array('tarball', 'zipball'))) { + if (!in_array($format, ['tarball', 'zipball'])) { $format = 'tarball'; } - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/'.rawurlencode($format), array( - 'ref' => $reference - )); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/'.rawurlencode($format). + ((null !== $reference) ? ('/'.rawurlencode($reference)) : '')); } /** - * Get the contents of a file in a repository + * Get the contents of a file in a repository. * * @param string $username the user who owns the repository * @param string $repository the name of the repository * @param string $path path to file - * @param null|string $reference reference to a branch or commit - * - * @return null|string content of file, or null in case of base64_decode failure + * @param string|null $reference reference to a branch or commit * * @throws InvalidArgumentException If $path is not a file or if its encoding is different from base64 * @throws ErrorException If $path doesn't include a 'content' index + * + * @return string|null content of file, or null in case of base64_decode failure */ public function download($username, $repository, $path, $reference = null) { $file = $this->show($username, $repository, $path, $reference); - if (!isset($file['type']) || 'file' !== $file['type']) { - throw new InvalidArgumentException(sprintf('Path "%s" is not a file.', $path)); + if (!isset($file['type']) || !in_array($file['type'], ['file', 'symlink'], true)) { + throw new InvalidArgumentException(sprintf('Path "%s" is not a file or a symlink to a file.', $path)); } if (!isset($file['content'])) { @@ -109,4 +295,25 @@ public function download($username, $repository, $path, $reference = null) return base64_decode($file['content']) ?: null; } + + /** + * Get the raw content of a file in a repository. + * + * Use this method instead of the download method if your file is bigger than 1MB + * + * @see https://docs.github.com/en/rest/repos/contents + * + * @param string $username the user who owns the repository + * @param string $repository the name of the repository + * @param string $path path to file + * @param string|null $reference reference to a branch or commit + * + * @return array|string + */ + public function rawDownload($username, $repository, $path, $reference = null) + { + return $this->show($username, $repository, $path, $reference, [ + 'Accept' => 'application/vnd.github.VERSION.raw', + ]); + } } diff --git a/lib/Github/Api/Repository/DeployKeys.php b/lib/Github/Api/Repository/DeployKeys.php index 390835798ac..0e45ccb626a 100644 --- a/lib/Github/Api/Repository/DeployKeys.php +++ b/lib/Github/Api/Repository/DeployKeys.php @@ -7,40 +7,43 @@ /** * @link http://developer.github.com/v3/repos/keys/ + * * @author Joseph Bielawski */ class DeployKeys extends AbstractApi { public function all($username, $repository) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/keys'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/keys'); } public function show($username, $repository, $id) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/keys/'.rawurlencode($id)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/keys/'.rawurlencode($id)); } public function create($username, $repository, array $params) { if (!isset($params['title'], $params['key'])) { - throw new MissingArgumentException(array('title', 'key')); + throw new MissingArgumentException(['title', 'key']); } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/keys', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/keys', $params); } public function update($username, $repository, $id, array $params) { if (!isset($params['title'], $params['key'])) { - throw new MissingArgumentException(array('title', 'key')); + throw new MissingArgumentException(['title', 'key']); } - return $this->patch('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/keys/'.rawurlencode($id), $params); + $this->remove($username, $repository, $id); + + return $this->create($username, $repository, $params); } public function remove($username, $repository, $id) { - return $this->delete('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/keys/'.rawurlencode($id)); + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/keys/'.rawurlencode($id)); } } diff --git a/lib/Github/Api/Repository/Downloads.php b/lib/Github/Api/Repository/Downloads.php index f3b96891c77..c959c61545e 100644 --- a/lib/Github/Api/Repository/Downloads.php +++ b/lib/Github/Api/Repository/Downloads.php @@ -6,12 +6,14 @@ /** * @link http://developer.github.com/v3/repos/downloads/ + * * @author Joseph Bielawski */ class Downloads extends AbstractApi { /** - * List downloads in selected repository + * List downloads in selected repository. + * * @link http://developer.github.com/v3/repos/downloads/#list-downloads-for-a-repository * * @param string $username the user who owns the repo @@ -21,36 +23,38 @@ class Downloads extends AbstractApi */ public function all($username, $repository) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/downloads'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/downloads'); } /** - * Get a download in selected repository + * Get a download in selected repository. + * * @link http://developer.github.com/v3/repos/downloads/#get-a-single-download * - * @param string $username the user who owns the repo - * @param string $repository the name of the repo - * @param integer $id the id of the download file + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * @param int $id the id of the download file * * @return array */ public function show($username, $repository, $id) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/downloads/'.rawurlencode($id)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/downloads/'.$id); } /** - * Delete a download in selected repository + * Delete a download in selected repository. + * * @link http://developer.github.com/v3/repos/downloads/#delete-a-download * - * @param string $username the user who owns the repo - * @param string $repository the name of the repo - * @param integer $id the id of the download file + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * @param int $id the id of the download file * * @return array */ public function remove($username, $repository, $id) { - return $this->delete('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/downloads/'.rawurlencode($id)); + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/downloads/'.$id); } } diff --git a/lib/Github/Api/Repository/Forks.php b/lib/Github/Api/Repository/Forks.php index c165961856e..961dc64944a 100644 --- a/lib/Github/Api/Repository/Forks.php +++ b/lib/Github/Api/Repository/Forks.php @@ -6,21 +6,22 @@ /** * @link http://developer.github.com/v3/repos/forks/ + * * @author Joseph Bielawski */ class Forks extends AbstractApi { - public function all($username, $repository, array $params = array()) + public function all($username, $repository, array $params = []) { - if (isset($params['sort']) && !in_array($params['sort'], array('newest', 'oldest', 'watchers'))) { + if (isset($params['sort']) && !in_array($params['sort'], ['newest', 'oldest', 'watchers'])) { $params['sort'] = 'newest'; } - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/forks', array_merge(array('page' => 1), $params)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/forks', array_merge(['page' => 1], $params)); } - public function create($username, $repository, array $params = array()) + public function create($username, $repository, array $params = []) { - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/forks', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/forks', $params); } } diff --git a/lib/Github/Api/Repository/Hooks.php b/lib/Github/Api/Repository/Hooks.php index ad9e8596ecd..be87e0146b6 100644 --- a/lib/Github/Api/Repository/Hooks.php +++ b/lib/Github/Api/Repository/Hooks.php @@ -6,46 +6,52 @@ use Github\Exception\MissingArgumentException; /** - * @link http://developer.github.com/v3/issues/hooks/ + * @link http://developer.github.com/v3/repos/hooks/ + * * @author Joseph Bielawski */ class Hooks extends AbstractApi { public function all($username, $repository) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/hooks'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/hooks'); } public function show($username, $repository, $id) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/hooks/'.rawurlencode($id)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/hooks/'.rawurlencode($id)); } public function create($username, $repository, array $params) { if (!isset($params['name'], $params['config'])) { - throw new MissingArgumentException(array('name', 'config')); + throw new MissingArgumentException(['name', 'config']); } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/hooks', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/hooks', $params); } public function update($username, $repository, $id, array $params) { - if (!isset($params['name'], $params['config'])) { - throw new MissingArgumentException(array('name', 'config')); + if (!isset($params['config'])) { + throw new MissingArgumentException(['config']); } - return $this->patch('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/hooks/'.rawurlencode($id), $params); + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/hooks/'.rawurlencode($id), $params); + } + + public function ping($username, $repository, $id) + { + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/hooks/'.rawurlencode($id).'/pings'); } public function test($username, $repository, $id) { - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/hooks/'.rawurlencode($id).'/test'); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/hooks/'.rawurlencode($id).'/tests'); } public function remove($username, $repository, $id) { - return $this->delete('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/hooks/'.rawurlencode($id)); + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/hooks/'.rawurlencode($id)); } } diff --git a/lib/Github/Api/Repository/Labels.php b/lib/Github/Api/Repository/Labels.php index e35b4ded71d..28ca4d53c0f 100644 --- a/lib/Github/Api/Repository/Labels.php +++ b/lib/Github/Api/Repository/Labels.php @@ -7,40 +7,37 @@ /** * @link http://developer.github.com/v3/issues/labels/ + * * @author Joseph Bielawski */ class Labels extends AbstractApi { public function all($username, $repository) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels'); } public function show($username, $repository, $label) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels/'.rawurlencode($label)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels/'.rawurlencode($label)); } public function create($username, $repository, array $params) { if (!isset($params['name'], $params['color'])) { - throw new MissingArgumentException(array('name', 'color')); + throw new MissingArgumentException(['name', 'color']); } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels', $params); } public function update($username, $repository, $label, array $params) { - if (!isset($params['name'], $params['color'])) { - throw new MissingArgumentException(array('name', 'color')); - } - - return $this->patch('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels/'.rawurlencode($label), $params); + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels/'.rawurlencode($label), $params); } public function remove($username, $repository, $label) { - return $this->delete('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels/'.rawurlencode($label)); + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/labels/'.rawurlencode($label)); } } diff --git a/lib/Github/Api/Repository/Pages.php b/lib/Github/Api/Repository/Pages.php new file mode 100644 index 00000000000..b641cb957c0 --- /dev/null +++ b/lib/Github/Api/Repository/Pages.php @@ -0,0 +1,60 @@ + + */ +class Pages extends AbstractApi +{ + use AcceptHeaderTrait; + + public function show($username, $repository) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pages'); + } + + public function enable($username, $repository, array $params = []) + { + $this->acceptHeaderValue = 'application/vnd.github.switcheroo-preview+json'; + + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pages', $params); + } + + public function disable($username, $repository) + { + $this->acceptHeaderValue = 'application/vnd.github.switcheroo-preview+json'; + + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pages'); + } + + public function update($username, $repository, array $params = []) + { + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pages', $params); + } + + public function requestBuild($username, $repository) + { + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pages/builds'); + } + + public function builds($username, $repository) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pages/builds'); + } + + public function showLatestBuild($username, $repository) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pages/builds/latest'); + } + + public function showBuild($username, $repository, $id) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/pages/builds/'.rawurlencode($id)); + } +} diff --git a/lib/Github/Api/Repository/Projects.php b/lib/Github/Api/Repository/Projects.php new file mode 100644 index 00000000000..9db29f5578d --- /dev/null +++ b/lib/Github/Api/Repository/Projects.php @@ -0,0 +1,23 @@ +get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/projects', array_merge(['page' => 1], $params)); + } + + public function create($username, $repository, array $params) + { + if (!isset($params['name'])) { + throw new MissingArgumentException(['name']); + } + + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/projects', $params); + } +} diff --git a/lib/Github/Api/Repository/Protection.php b/lib/Github/Api/Repository/Protection.php new file mode 100644 index 00000000000..b559557a944 --- /dev/null +++ b/lib/Github/Api/Repository/Protection.php @@ -0,0 +1,440 @@ + + */ +class Protection extends AbstractApi +{ + use AcceptHeaderTrait; + + /** + * Retrieves configured protection for the provided branch. + * + * @link https://developer.github.com/v3/repos/branches/#get-branch-protection + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * + * @return array The branch protection information + */ + public function show($username, $repository, $branch) + { + // Preview endpoint + $this->acceptHeaderValue = 'application/vnd.github.luke-cage-preview+json'; + + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection'); + } + + /** + * Updates the repo's branch protection. + * + * @link https://developer.github.com/v3/repos/branches/#update-branch-protection + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * @param array $params The branch protection information + * + * @return array The updated branch protection information + */ + public function update($username, $repository, $branch, array $params = []) + { + // Preview endpoint + $this->acceptHeaderValue = 'application/vnd.github.luke-cage-preview+json'; + + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection', $params); + } + + /** + * Remove the repo's branch protection. + * + * @link https://developer.github.com/v3/repos/branches/#remove-branch-protection + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + */ + public function remove($username, $repository, $branch) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection'); + } + + /** + * Get required status checks of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#get-required-status-checks-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * + * @return array The required status checks information + */ + public function showStatusChecks($username, $repository, $branch) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/required_status_checks'); + } + + /** + * Update required status checks of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#update-required-status-checks-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * @param array $params The branch status checks information + * + * @return array The updated branch status checks information + */ + public function updateStatusChecks($username, $repository, $branch, array $params = []) + { + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/required_status_checks', $params); + } + + /** + * Remove required status checks of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#remove-required-status-checks-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + */ + public function removeStatusChecks($username, $repository, $branch) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/required_status_checks'); + } + + /** + * List required status checks contexts of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#list-required-status-checks-contexts-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * + * @return array The required status checks contexts information + */ + public function showStatusChecksContexts($username, $repository, $branch) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/required_status_checks/contexts'); + } + + /** + * Replace required status checks contexts of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#replace-required-status-checks-contexts-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * @param array $params The branch status checks contexts information + * + * @return array The new branch status checks contexts information + */ + public function replaceStatusChecksContexts($username, $repository, $branch, array $params = []) + { + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/required_status_checks/contexts', $params); + } + + /** + * Add required status checks contexts of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#add-required-status-checks-contexts-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * @param array $params The branch status checks contexts information + * + * @return array The updated branch status checks contexts information + */ + public function addStatusChecksContexts($username, $repository, $branch, array $params = []) + { + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/required_status_checks/contexts', $params); + } + + /** + * Remove required status checks contexts of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#remove-required-status-checks-contexts-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * @param array $params The branch status checks contexts information + * + * @return array The updated branch status checks contexts information + */ + public function removeStatusChecksContexts($username, $repository, $branch, array $params = []) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/required_status_checks/contexts', $params); + } + + /** + * Get pull request review enforcement of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#get-pull-request-review-enforcement-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * + * @return array The pull request review enforcement information + */ + public function showPullRequestReviewEnforcement($username, $repository, $branch) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/required_pull_request_reviews'); + } + + /** + * Update pull request review enforcement of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#update-pull-request-review-enforcement-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * @param array $params The branch status checks information + * + * @return array The updated branch status checks information + */ + public function updatePullRequestReviewEnforcement($username, $repository, $branch, array $params = []) + { + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/required_pull_request_reviews', $params); + } + + /** + * Remove pull request review enforcement of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#remove-pull-request-review-enforcement-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + */ + public function removePullRequestReviewEnforcement($username, $repository, $branch) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/required_pull_request_reviews'); + } + + /** + * Get admin enforcement of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#get-admin-enforcement-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * + * @return array The admin enforcement information + */ + public function showAdminEnforcement($username, $repository, $branch) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/enforce_admins'); + } + + /** + * Add admin enforcement of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#add-admin-enforcement-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * + * @return array The updated admin enforcement information + */ + public function addAdminEnforcement($username, $repository, $branch) + { + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/enforce_admins'); + } + + /** + * Remove admin enforcement of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#remove-admin-enforcement-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + */ + public function removeAdminEnforcement($username, $repository, $branch) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/enforce_admins'); + } + + /** + * Get restrictions of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#get-restrictions-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * + * @return array The branch restrictions information + */ + public function showRestrictions($username, $repository, $branch) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/restrictions'); + } + + /** + * Remove restrictions of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#remove-restrictions-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + */ + public function removeRestrictions($username, $repository, $branch) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/restrictions'); + } + + /** + * List team restrictions of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#list-team-restrictions-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * + * @return array The branch team restrictions information + */ + public function showTeamRestrictions($username, $repository, $branch) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/restrictions/teams'); + } + + /** + * Replace team restrictions of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#replace-team-restrictions-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * @param array $params The list of team slugs with push access + * + * @return array The new branch team restrictions information + */ + public function replaceTeamRestrictions($username, $repository, $branch, array $params = []) + { + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/restrictions/teams', $params); + } + + /** + * Add team restrictions of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#add-team-restrictions-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * @param array $params The list of team slugs with push access + * + * @return array The branch team restrictions information + */ + public function addTeamRestrictions($username, $repository, $branch, array $params = []) + { + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/restrictions/teams', $params); + } + + /** + * Remove team restrictions of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#remove-team-restrictions-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * @param array $params The list of team slugs with push access + * + * @return array The updated branch team restrictions information + */ + public function removeTeamRestrictions($username, $repository, $branch, array $params = []) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/restrictions/teams', $params); + } + + /** + * List user restrictions of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#list-user-restrictions-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * + * @return array The branch user restrictions information + */ + public function showUserRestrictions($username, $repository, $branch) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/restrictions/users'); + } + + /** + * Replace user restrictions of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#replace-user-restrictions-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * @param array $params The list of user logins with push access + * + * @return array The new branch user restrictions information + */ + public function replaceUserRestrictions($username, $repository, $branch, array $params = []) + { + return $this->put('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/restrictions/users', $params); + } + + /** + * Add user restrictions of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#add-user-restrictions-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * @param array $params The list of user logins with push access + * + * @return array The branch user restrictions information + */ + public function addUserRestrictions($username, $repository, $branch, array $params = []) + { + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/restrictions/users', $params); + } + + /** + * Remove user restrictions of protected branch. + * + * @link https://developer.github.com/v3/repos/branches/#remove-user-restrictions-of-protected-branch + * + * @param string $username The user who owns the repository + * @param string $repository The name of the repo + * @param string $branch The name of the branch + * @param array $params The list of user logins with push access + * + * @return array The updated branch user restrictions information + */ + public function removeUserRestrictions($username, $repository, $branch, array $params = []) + { + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/branches/'.rawurlencode($branch).'/protection/restrictions/users', $params); + } +} diff --git a/lib/Github/Api/Repository/Releases.php b/lib/Github/Api/Repository/Releases.php index a2ee5201ffe..6cd7fda4f0a 100644 --- a/lib/Github/Api/Repository/Releases.php +++ b/lib/Github/Api/Repository/Releases.php @@ -7,44 +7,87 @@ /** * @link http://developer.github.com/v3/repos/releases/ + * * @author Matthew Simo * @author Evgeniy Guseletov */ class Releases extends AbstractApi { /** - * List releases in selected repository + * Get the latest release. * - * @param string $username the user who owns the repo - * @param string $repository the name of the repo + * @param string $username + * @param string $repository * * @return array */ - public function all($username, $repository) + public function latest($username, $repository) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases'); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/latest'); } /** - * Get a release in selected repository + * List releases for a tag. * - * @param string $username the user who owns the repo - * @param string $repository the name of the repo - * @param integer $id the id of the release + * @param string $username + * @param string $repository + * @param string $tag + * + * @return array + */ + public function tag($username, $repository, $tag) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/tags/'.rawurlencode($tag)); + } + + /** + * List releases in selected repository. + * + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * @param array $params the additional parameters like milestone, assignees, labels, sort, direction + * + * @return array + */ + public function all($username, $repository, array $params = []) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases', $params); + } + + /** + * Get a release in selected repository. + * + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * @param int $id the id of the release * * @return array */ public function show($username, $repository, $id) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/'.rawurlencode($id)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/'.$id); + } + + /** + * Generate release notes content for a release. + * + * @param string $username + * @param string $repository + * @param array $params + * + * @return array + */ + public function generateNotes($username, $repository, array $params) + { + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/generate-notes', $params); } /** - * Create new release in selected repository + * Create new release in selected repository. * - * @param string $username - * @param string $repository - * @param array $params + * @param string $username + * @param string $repository + * @param array $params * * @throws MissingArgumentException * @@ -56,36 +99,36 @@ public function create($username, $repository, array $params) throw new MissingArgumentException('tag_name'); } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases', $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases', $params); } /** - * Edit release in selected repository + * Edit release in selected repository. * - * @param string $username - * @param string $repository - * @param integer $id - * @param array $params + * @param string $username + * @param string $repository + * @param int $id + * @param array $params * * @return array */ public function edit($username, $repository, $id, array $params) { - return $this->patch('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/'.rawurlencode($id), $params); + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/'.$id, $params); } /** - * Delete a release in selected repository (Not thoroughly tested!) + * Delete a release in selected repository (Not thoroughly tested!). * - * @param string $username the user who owns the repo - * @param string $repository the name of the repo - * @param integer $id the id of the release + * @param string $username the user who owns the repo + * @param string $repository the name of the repo + * @param int $id the id of the release * * @return array */ public function remove($username, $repository, $id) { - return $this->delete('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/'.rawurlencode($id)); + return $this->delete('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/releases/'.$id); } /** @@ -93,6 +136,6 @@ public function remove($username, $repository, $id) */ public function assets() { - return new Assets($this->client); + return new Assets($this->getClient()); } } diff --git a/lib/Github/Api/Repository/SecretScanning.php b/lib/Github/Api/Repository/SecretScanning.php new file mode 100644 index 00000000000..968d352c3ec --- /dev/null +++ b/lib/Github/Api/Repository/SecretScanning.php @@ -0,0 +1,64 @@ +get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/secret-scanning/alerts', $params); + } + + /** + * @link https://docs.github.com/en/enterprise-server@3.5/rest/secret-scanning#get-a-secret-scanning-alert + * + * @param string $username + * @param string $repository + * @param int $alertNumber + * + * @return array|string + */ + public function getAlert(string $username, string $repository, int $alertNumber) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/secret-scanning/alerts/'.$alertNumber); + } + + /** + * @link https://docs.github.com/en/enterprise-server@3.5/rest/secret-scanning#update-a-secret-scanning-alert + * + * @param string $username + * @param string $repository + * @param int $alertNumber + * @param array $params + * + * @return array|string + */ + public function updateAlert(string $username, string $repository, int $alertNumber, array $params = []) + { + return $this->patch('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/secret-scanning/alerts/'.$alertNumber, $params); + } + + /** + * @link https://docs.github.com/en/enterprise-server@3.5/rest/secret-scanning#list-locations-for-a-secret-scanning-alert + * + * @param string $username + * @param string $repository + * @param int $alertNumber + * @param array $params + * + * @return array|string + */ + public function locations(string $username, string $repository, int $alertNumber, array $params = []) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/secret-scanning/alerts/'.$alertNumber.'/locations', $params); + } +} diff --git a/lib/Github/Api/Repository/Stargazers.php b/lib/Github/Api/Repository/Stargazers.php new file mode 100644 index 00000000000..bef73b9a6bd --- /dev/null +++ b/lib/Github/Api/Repository/Stargazers.php @@ -0,0 +1,40 @@ + + * @author Tobias Nyholm + */ +class Stargazers extends AbstractApi +{ + use AcceptHeaderTrait; + + /** + * Configure the body type. + * + * @see https://developer.github.com/v3/activity/starring/#alternative-response-with-star-creation-timestamps + * + * @param string $bodyType + * + * @return $this + */ + public function configure($bodyType = null) + { + if ('star' === $bodyType) { + $this->acceptHeaderValue = sprintf('application/vnd.github.%s.star+json', $this->getApiVersion()); + } + + return $this; + } + + public function all($username, $repository) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/stargazers'); + } +} diff --git a/lib/Github/Api/Repository/Statuses.php b/lib/Github/Api/Repository/Statuses.php index 918b2bd4cd6..c62f4edd8b6 100644 --- a/lib/Github/Api/Repository/Statuses.php +++ b/lib/Github/Api/Repository/Statuses.php @@ -7,6 +7,7 @@ /** * @link http://developer.github.com/v3/repos/statuses/ + * * @author Joseph Bielawski */ class Statuses extends AbstractApi @@ -22,27 +23,41 @@ class Statuses extends AbstractApi */ public function show($username, $repository, $sha) { - return $this->get('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/statuses/'.rawurlencode($sha)); + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/commits/'.rawurlencode($sha).'/statuses'); } /** - * @link http://developer.github.com/v3/repos/statuses/#create-a-status + * @link https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref * * @param string $username * @param string $repository * @param string $sha - * @param array $params * * @return array + */ + public function combined($username, $repository, $sha) + { + return $this->get('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/commits/'.rawurlencode($sha).'/status'); + } + + /** + * @link http://developer.github.com/v3/repos/statuses/#create-a-status + * + * @param string $username + * @param string $repository + * @param string $sha + * @param array $params * * @throws MissingArgumentException + * + * @return array */ - public function create($username, $repository, $sha, array $params = array()) + public function create($username, $repository, $sha, array $params = []) { if (!isset($params['state'])) { throw new MissingArgumentException('state'); } - return $this->post('repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/statuses/'.rawurlencode($sha), $params); + return $this->post('/repos/'.rawurlencode($username).'/'.rawurlencode($repository).'/statuses/'.rawurlencode($sha), $params); } } diff --git a/lib/Github/Api/Repository/Traffic.php b/lib/Github/Api/Repository/Traffic.php new file mode 100644 index 00000000000..d5b550c8521 --- /dev/null +++ b/lib/Github/Api/Repository/Traffic.php @@ -0,0 +1,67 @@ + + */ +class Traffic extends AbstractApi +{ + /** + * @link https://developer.github.com/v3/repos/traffic/#list-referrers + * + * @param string $owner + * @param string $repository + * + * @return array + */ + public function referers($owner, $repository) + { + return $this->get('/repos/'.rawurlencode($owner).'/'.rawurlencode($repository).'/traffic/popular/referrers'); + } + + /** + * @link https://developer.github.com/v3/repos/traffic/#list-paths + * + * @param string $owner + * @param string $repository + * + * @return array + */ + public function paths($owner, $repository) + { + return $this->get('/repos/'.rawurlencode($owner).'/'.rawurlencode($repository).'/traffic/popular/paths'); + } + + /** + * @link https://developer.github.com/v3/repos/traffic/#views + * + * @param string $owner + * @param string $repository + * @param string $per + * + * @return array + */ + public function views($owner, $repository, $per = 'day') + { + return $this->get('/repos/'.rawurlencode($owner).'/'.rawurlencode($repository).'/traffic/views?per='.rawurlencode($per)); + } + + /** + * @link https://developer.github.com/v3/repos/traffic/#clones + * + * @param string $owner + * @param string $repository + * @param string $per + * + * @return array + */ + public function clones($owner, $repository, $per = 'day') + { + return $this->get('/repos/'.rawurlencode($owner).'/'.rawurlencode($repository).'/traffic/clones?per='.rawurlencode($per)); + } +} diff --git a/lib/Github/Api/Search.php b/lib/Github/Api/Search.php new file mode 100644 index 00000000000..96a51ea6a46 --- /dev/null +++ b/lib/Github/Api/Search.php @@ -0,0 +1,130 @@ + + */ +class Search extends AbstractApi +{ + use AcceptHeaderTrait; + + /** + * Search repositories by filter (q). + * + * @link https://developer.github.com/v3/search/#search-repositories + * + * @param string $q the filter + * @param string $sort the sort field + * @param string $order asc/desc + * + * @return array list of repositories found + */ + public function repositories($q, $sort = 'updated', $order = 'desc') + { + return $this->get('/search/repositories', ['q' => $q, 'sort' => $sort, 'order' => $order]); + } + + /** + * Search issues by filter (q). + * + * @link https://developer.github.com/v3/search/#search-issues + * + * @param string $q the filter + * @param string $sort the sort field + * @param string $order asc/desc + * + * @return array list of issues found + */ + public function issues($q, $sort = 'updated', $order = 'desc') + { + return $this->get('/search/issues', ['q' => $q, 'sort' => $sort, 'order' => $order]); + } + + /** + * Search code by filter (q). + * + * @link https://developer.github.com/v3/search/#search-code + * + * @param string $q the filter + * @param string $sort the sort field + * @param string $order asc/desc + * + * @return array list of code found + */ + public function code($q, $sort = 'updated', $order = 'desc') + { + return $this->get('/search/code', ['q' => $q, 'sort' => $sort, 'order' => $order]); + } + + /** + * Search code by filter (q), but will return additional data to highlight + * the matched results. + * + * @link https://docs.github.com/en/rest/reference/search#text-match-metadata + * + * @return array list of code found + */ + public function codeWithMatch(string $q, string $sort = 'updated', string $order = 'desc'): array + { + $this->acceptHeaderValue = 'application/vnd.github.v3.text-match+json'; + + return $this->code($q, $sort, $order); + } + + /** + * Search users by filter (q). + * + * @link https://developer.github.com/v3/search/#search-users + * + * @param string $q the filter + * @param string $sort the sort field + * @param string $order asc/desc + * + * @return array list of users found + */ + public function users($q, $sort = 'updated', $order = 'desc') + { + return $this->get('/search/users', ['q' => $q, 'sort' => $sort, 'order' => $order]); + } + + /** + * Search commits by filter (q). + * + * @link https://developer.github.com/v3/search/#search-commits + * + * @param string $q the filter + * @param string $sort the sort field + * @param string $order sort order. asc/desc + * + * @return array + */ + public function commits($q, $sort = null, $order = 'desc') + { + // This api is in preview mode, so set the correct accept-header + $this->acceptHeaderValue = 'application/vnd.github.cloak-preview'; + + return $this->get('/search/commits', ['q' => $q, 'sort' => $sort, 'order' => $order]); + } + + /** + * Search topics by filter (q). + * + * @link https://developer.github.com/v3/search/#search-topics + * + * @param string $q the filter + * + * @return array + */ + public function topics($q) + { + // This api is in preview mode, so set the correct accept-header + $this->acceptHeaderValue = 'application/vnd.github.mercy-preview+json'; + + return $this->get('/search/topics', ['q' => $q]); + } +} diff --git a/lib/Github/Api/User.php b/lib/Github/Api/User.php index 97c3be0fda4..d436a2b835e 100644 --- a/lib/Github/Api/User.php +++ b/lib/Github/Api/User.php @@ -2,114 +2,229 @@ namespace Github\Api; +use Github\Api\User\Migration; + /** - * Searching users, getting user information + * Searching users, getting user information. * * @link http://developer.github.com/v3/users/ + * * @author Joseph Bielawski * @author Thibault Duplessis */ class User extends AbstractApi { /** - * Search users by username: - * @link http://developer.github.com/v3/search/#search-users + * Request all users. + * + * @link https://developer.github.com/v3/users/#get-all-users * - * @param string $keyword the keyword to search + * @param int|null $id ID of the last user that you've seen * * @return array list of users found */ - public function find($keyword) + public function all($id = null) { - return $this->get('legacy/user/search/'.rawurlencode($keyword)); + if (!is_int($id)) { + return $this->get('/users'); + } + + return $this->get('/users', ['since' => $id]); } /** - * Get extended information about a user by its username + * Get extended information about a user by its username. + * * @link http://developer.github.com/v3/users/ * - * @param string $username the username to show - * @return array informations about the user + * @param string $username the username to show + * + * @return array information about the user */ public function show($username) { - return $this->get('users/'.rawurlencode($username)); + return $this->get('/users/'.rawurlencode($username)); + } + + /** + * Get extended information about a user by its id. + * Note: at time of writing this is an undocumented feature but GitHub support have advised that it can be relied on. + * + * @link http://developer.github.com/v3/users/ + * + * @param int $id the id of the user to show + * + * @return array information about the user + */ + public function showById($id) + { + return $this->get('/user/'.$id); + } + + /** + * Get extended information about a user by its username. + * + * @link https://developer.github.com/v3/orgs/ + * + * @param string $username the username to show + * + * @return array information about organizations that user belongs to + */ + public function organizations($username) + { + return $this->get('/users/'.rawurlencode($username).'/orgs'); + } + + /** + * Get user organizations. + * + * @link https://developer.github.com/v3/orgs/#list-your-organizations + * + * @return array information about organizations that authenticated user belongs to + */ + public function orgs() + { + return $this->get('/user/orgs'); } /** - * Request the users that a specific user is following + * Request the users that a specific user is following. + * * @link http://developer.github.com/v3/users/followers/ * - * @param string $username the username - * @return array list of followed users + * @param string $username the username + * @param array $parameters parameters for the query string + * @param array $requestHeaders additional headers to set in the request + * + * @return array list of followed users */ - public function following($username) + public function following($username, array $parameters = [], array $requestHeaders = []) { - return $this->get('users/'.rawurlencode($username).'/following'); + return $this->get('/users/'.rawurlencode($username).'/following', $parameters, $requestHeaders); } /** - * Request the users following a specific user + * Request the users following a specific user. + * * @link http://developer.github.com/v3/users/followers/ * - * @param string $username the username - * @return array list of following users + * @param string $username the username + * @param array $parameters parameters for the query string + * @param array $requestHeaders additional headers to set in the request + * + * @return array list of following users */ - public function followers($username) + public function followers($username, array $parameters = [], array $requestHeaders = []) { - return $this->get('users/'.rawurlencode($username).'/followers'); + return $this->get('/users/'.rawurlencode($username).'/followers', $parameters, $requestHeaders); } /** - * Request the repository that a specific user is watching - * @link http://developer.github.com/v3/repos/watching/ + * Request starred repositories that a specific user has starred. + * + * @link http://developer.github.com/v3/activity/starring/ + * + * @param string $username the username + * @param int $page the page number of the paginated result set + * @param int $perPage the number of results per page + * @param string $sort sort by (possible values: created, updated) + * @param string $direction direction of sort (possible values: asc, desc) * - * @param string $username the username - * @return array list of watched repositories + * @return array list of starred repositories */ - public function watched($username) + public function starred($username, $page = 1, $perPage = 30, $sort = 'created', $direction = 'desc') { - return $this->get('users/'.rawurlencode($username).'/watched'); + return $this->get('/users/'.rawurlencode($username).'/starred', [ + 'page' => $page, + 'per_page' => $perPage, + 'sort' => $sort, + 'direction' => $direction, + ]); } /** - * Get the repositories of a user - * @link http://developer.github.com/v3/repos/ + * Request the repository that a specific user is watching. * - * @param string $username the username - * @return array list of the user repositories + * @link http://developer.github.com/v3/activity/watching/ + * + * @param string $username the username + * + * @return array list of watched repositories + */ + public function subscriptions($username) + { + return $this->get('/users/'.rawurlencode($username).'/subscriptions'); + } + + /** + * List public repositories for the specified user. + * + * @link https://developer.github.com/v3/repos/#list-user-repositories + * + * @param string $username the username + * @param string $type role in the repository + * @param string $sort sort by + * @param string $direction direction of sort, asc or desc + * @param string $visibility visibility of repository + * @param string $affiliation relationship to repository + * + * @return array list of the user repositories + */ + public function repositories($username, $type = 'owner', $sort = 'full_name', $direction = 'asc', $visibility = 'all', $affiliation = 'owner,collaborator,organization_member') + { + return $this->get('/users/'.rawurlencode($username).'/repos', [ + 'type' => $type, + 'sort' => $sort, + 'direction' => $direction, + 'visibility' => $visibility, + 'affiliation' => $affiliation, + ]); + } + + /** + * List repositories that are accessible to the authenticated user. + * + * @link https://developer.github.com/v3/repos/#list-your-repositories + * + * @param array $params visibility, affiliation, type, sort, direction + * + * @return array list of the user repositories */ - public function repositories($username) + public function myRepositories(array $params = []) { - return $this->get('users/'.rawurlencode($username).'/repos'); + return $this->get('/user/repos', $params); } /** - * Get the public gists for a user + * Get the public gists for a user. + * * @link http://developer.github.com/v3/gists/ * - * @param string $username the username - * @return array list of the user gists + * @param string $username the username + * + * @return array list of the user gists */ public function gists($username) { - return $this->get('users/'.rawurlencode($username).'/gists'); + return $this->get('/users/'.rawurlencode($username).'/gists'); } /** - * Get the public keys for a user + * Get the public keys for a user. + * * @link http://developer.github.com/v3/users/keys/#list-public-keys-for-a-user * - * @param string $username the username - * @return array list of the user public keys + * @param string $username the username + * + * @return array list of the user public keys */ public function keys($username) { - return $this->get('users/'.rawurlencode($username).'/keys'); + return $this->get('/users/'.rawurlencode($username).'/keys'); } /** - * List events performed by a user + * List events performed by a user. * * @link http://developer.github.com/v3/activity/events/#list-public-events-performed-by-a-user * @@ -119,6 +234,26 @@ public function keys($username) */ public function publicEvents($username) { - return $this->get('users/'.rawurlencode($username) . '/events/public'); + return $this->get('/users/'.rawurlencode($username).'/events/public'); + } + + /** + * List events performed by an authenticated user. + * + * @link https://docs.github.com/en/rest/reference/activity#list-events-for-the-authenticated-user + * + * @return array + */ + public function events(string $username) + { + return $this->get('/users/'.rawurlencode($username).'/events'); + } + + /** + * @return Migration + */ + public function migration(): Migration + { + return new Migration($this->getClient()); } } diff --git a/lib/Github/Api/User/Migration.php b/lib/Github/Api/User/Migration.php new file mode 100644 index 00000000000..4e1b61ca244 --- /dev/null +++ b/lib/Github/Api/User/Migration.php @@ -0,0 +1,83 @@ +get('/user/migrations', $params); + } + + /** + * @link https://docs.github.com/en/rest/migrations/users?apiVersion=2022-11-28#start-a-user-migration + * + * @param array $params + * + * @return array|string + */ + public function start(array $params) + { + return $this->post('/user/migrations', $params); + } + + /** + * @link https://docs.github.com/en/rest/migrations/users?apiVersion=2022-11-28#get-a-user-migration-status + * + * @param int $migrationId + * @param array $params + * + * @return array|string + */ + public function status(int $migrationId, array $params = []) + { + return $this->get('/user/migrations/'.$migrationId, $params); + } + + /** + * @link https://docs.github.com/en/rest/migrations/users?apiVersion=2022-11-28#delete-a-user-migration-archive + * + * @param int $migrationId + * + * @return array|string + */ + public function deleteArchive(int $migrationId) + { + return $this->delete('/user/migrations/'.$migrationId.'/archive'); + } + + /** + * @link https://docs.github.com/en/rest/migrations/users?apiVersion=2022-11-28#unlock-a-user-repository + * + * @param int $migrationId + * @param string $repository + * + * @return array|string + */ + public function unlockRepo(int $migrationId, string $repository) + { + return $this->delete('/user/migrations/'.$migrationId.'/repos/'.rawurlencode($repository).'/lock'); + } + + /** + * @link https://docs.github.com/en/rest/migrations/users?apiVersion=2022-11-28#list-repositories-for-a-user-migration + * + * @param int $migrationId + * @param array $params + * + * @return array|string + */ + public function repos(int $migrationId, array $params = []) + { + return $this->get('/user/migrations/'.$migrationId.'/repositories', $params); + } +} diff --git a/lib/Github/AuthMethod.php b/lib/Github/AuthMethod.php new file mode 100644 index 00000000000..4a390699a3c --- /dev/null +++ b/lib/Github/AuthMethod.php @@ -0,0 +1,30 @@ + * @@ -17,78 +72,127 @@ class Client { /** - * Constant for authentication method. Indicates the default, but deprecated - * login with username and token in URL. + * Authenticate using a client_id/client_secret combination. + * + * @var string + * + * @deprecated Use the AuthMethod const */ - const AUTH_URL_TOKEN = 'url_token'; + const AUTH_CLIENT_ID = AuthMethod::CLIENT_ID; /** - * Constant for authentication method. Not indicates the new login, but allows - * usage of unauthenticated rate limited requests for given client_id + client_secret + * Authenticate using a GitHub access token. + * + * @var string + * + * @deprecated Use the AuthMethod const */ - const AUTH_URL_CLIENT_ID = 'url_client_id'; + const AUTH_ACCESS_TOKEN = AuthMethod::ACCESS_TOKEN; /** - * Constant for authentication method. Indicates the new favored login method - * with username and password via HTTP Authentication. + * Constant for authentication method. + * + * Indicates JSON Web Token authentication required for GitHub apps access + * to the API. + * + * @var string + * + * @deprecated Use the AuthMethod const */ - const AUTH_HTTP_PASSWORD = 'http_password'; + const AUTH_JWT = AuthMethod::JWT; /** - * Constant for authentication method. Indicates the new login method with - * with username and token via HTTP Authentication. + * @var string */ - const AUTH_HTTP_TOKEN = 'http_token'; + private $apiVersion; /** - * @var array + * @var Builder */ - private $options = array( - 'base_url' => 'https://api.github.com/', - - 'user_agent' => 'php-github-api (http://github.com/KnpLabs/php-github-api)', - 'timeout' => 10, - - 'api_limit' => 5000, - 'api_version' => 'beta', + private $httpClientBuilder; - 'cache_dir' => null - ); + /** + * @var History + */ + private $responseHistory; /** - * The Buzz instance used to communicate with GitHub + * Instantiate a new GitHub client. * - * @var HttpClient + * @param Builder|null $httpClientBuilder + * @param string|null $apiVersion + * @param string|null $enterpriseUrl */ - private $httpClient; + public function __construct(?Builder $httpClientBuilder = null, $apiVersion = null, $enterpriseUrl = null) + { + $this->responseHistory = new History(); + $this->httpClientBuilder = $builder = $httpClientBuilder ?? new Builder(); + $this->apiVersion = $apiVersion ?: 'v3'; + + $builder->addPlugin(new GithubExceptionThrower()); + $builder->addPlugin(new Plugin\HistoryPlugin($this->responseHistory)); + $builder->addPlugin(new Plugin\RedirectPlugin()); + $builder->addPlugin(new Plugin\AddHostPlugin(Psr17FactoryDiscovery::findUriFactory()->createUri('https://api.github.com'))); + $builder->addPlugin(new Plugin\HeaderDefaultsPlugin([ + 'User-Agent' => 'php-github-api (http://github.com/KnpLabs/php-github-api)', + 'Accept' => sprintf('application/vnd.github.%s+json', $this->apiVersion), + ])); + + if ($enterpriseUrl) { + $this->setEnterpriseUrl($enterpriseUrl); + } + } /** - * Instantiate a new GitHub client + * Create a Github\Client using a HTTP client. * - * @param null|HttpClientInterface $httpClient Github http client + * @param ClientInterface $httpClient + * + * @return Client */ - public function __construct(HttpClientInterface $httpClient = null) + public static function createWithHttpClient(ClientInterface $httpClient): self { - $this->httpClient = $httpClient; + $builder = new Builder($httpClient); + + return new self($builder); } /** * @param string $name * - * @return ApiInterface - * * @throws InvalidArgumentException + * + * @return AbstractApi */ - public function api($name) + public function api($name): AbstractApi { switch ($name) { case 'me': case 'current_user': + case 'currentUser': $api = new Api\CurrentUser($this); break; + case 'codeOfConduct': + $api = new Api\Miscellaneous\CodeOfConduct($this); + break; + + case 'deployment': + case 'deployments': + $api = new Api\Deployment($this); + break; + + case 'ent': + case 'enterprise': + $api = new Api\Enterprise($this); + break; + + case 'emojis': + $api = new Api\Miscellaneous\Emojis($this); + break; case 'git': case 'git_data': + case 'gitData': $api = new Api\GitData($this); break; @@ -97,6 +201,14 @@ public function api($name) $api = new Api\Gists($this); break; + case 'gitignore': + $api = new Api\Miscellaneous\Gitignore($this); + break; + + case 'apps': + $api = new Api\Apps($this); + break; + case 'issue': case 'issues': $api = new Api\Issue($this); @@ -106,17 +218,45 @@ public function api($name) $api = new Api\Markdown($this); break; + case 'licenses': + $api = new Api\Miscellaneous\Licenses($this); + break; + + case 'notification': + case 'notifications': + $api = new Api\Notification($this); + break; + case 'organization': case 'organizations': $api = new Api\Organization($this); break; + case 'org_project': + case 'orgProject': + case 'org_projects': + case 'orgProjects': + case 'organization_project': + case 'organizationProject': + case 'organization_projects': + case 'organizationProjects': + $api = new Api\Organization\Projects($this); + break; + case 'pr': + case 'pulls': + case 'pullRequest': case 'pull_request': + case 'pullRequests': case 'pull_requests': $api = new Api\PullRequest($this); break; + case 'rateLimit': + case 'rate_limit': + $api = new Api\RateLimit($this); + break; + case 'repo': case 'repos': case 'repository': @@ -124,6 +264,20 @@ public function api($name) $api = new Api\Repo($this); break; + case 'search': + $api = new Api\Search($this); + break; + + case 'team': + case 'teams': + $api = new Api\Organization\Teams($this); + break; + + case 'member': + case 'members': + $api = new Api\Organization\Members($this); + break; + case 'user': case 'users': $api = new Api\User($this); @@ -134,6 +288,24 @@ public function api($name) $api = new Api\Authorizations($this); break; + case 'meta': + $api = new Api\Meta($this); + break; + + case 'graphql': + $api = new Api\GraphQL($this); + break; + + case 'outsideCollaborators': + case 'outside_collaborators': + $api = new Api\Organization\OutsideCollaborators($this); + break; + + case 'copilotUsage': + case 'copilot_usage': + $api = new Api\Copilot\Usage($this); + break; + default: throw new InvalidArgumentException(sprintf('Undefined api instance called: "%s"', $name)); } @@ -142,97 +314,122 @@ public function api($name) } /** - * Authenticate a user for all next requests + * Authenticate a user for all next requests. * * @param string $tokenOrLogin GitHub private token/username/client ID - * @param null|string $password GitHub password/secret (optionally can contain $authMethod) - * @param null|string $authMethod One of the AUTH_* class constants + * @param string|null $password GitHub password/secret (optionally can contain $authMethod) + * @param string|null $authMethod One of the AUTH_* class constants * * @throws InvalidArgumentException If no authentication method was given + * + * @return void */ - public function authenticate($tokenOrLogin, $password = null, $authMethod = null) + public function authenticate($tokenOrLogin, $password = null, $authMethod = null): void { - if (null === $password && null === $authMethod) { - throw new InvalidArgumentException('You need to specify authentication method!'); + if (null === $authMethod && (AuthMethod::JWT === $password || AuthMethod::ACCESS_TOKEN === $password)) { + $authMethod = $password; + $password = null; } - if (null === $authMethod && in_array($password, array(self::AUTH_URL_TOKEN, self::AUTH_URL_CLIENT_ID, self::AUTH_HTTP_PASSWORD, self::AUTH_HTTP_TOKEN))) { - $authMethod = $password; - $password = null; + if (null === $authMethod) { + throw new InvalidArgumentException('You need to specify authentication method!'); } - $this->getHttpClient()->authenticate($tokenOrLogin, $password, $authMethod); + $this->getHttpClientBuilder()->removePlugin(Authentication::class); + $this->getHttpClientBuilder()->addPlugin(new Authentication($tokenOrLogin, $password, $authMethod)); } /** - * @return HttpClient + * Sets the URL of your GitHub Enterprise instance. + * + * @param string $enterpriseUrl URL of the API in the form of http(s)://hostname + * + * @return void */ - public function getHttpClient() + private function setEnterpriseUrl($enterpriseUrl): void { - if (null === $this->httpClient) { - $this->httpClient = new HttpClient($this->options); + $builder = $this->getHttpClientBuilder(); + $builder->removePlugin(Plugin\AddHostPlugin::class); + $builder->removePlugin(PathPrepend::class); + + $builder->addPlugin(new Plugin\AddHostPlugin(Psr17FactoryDiscovery::findUriFactory()->createUri($enterpriseUrl))); + + // For GHE, v4 API endpoint is at `api/graphql` so we don't want to add the version number + // For earlier versions add the version number after /api + if ($this->getApiVersion() === 'v4') { + $builder->addPlugin(new PathPrepend('/api')); + } else { + $builder->addPlugin(new PathPrepend(sprintf('/api/%s', $this->getApiVersion()))); } - - return $this->httpClient; } /** - * @param HttpClientInterface $httpClient + * @return string */ - public function setHttpClient(HttpClientInterface $httpClient) + public function getApiVersion(): string { - $this->httpClient = $httpClient; + return $this->apiVersion; } /** - * Clears used headers + * Add a cache plugin to cache responses locally. + * + * @param CacheItemPoolInterface $cachePool + * @param array $config + * + * @return void */ - public function clearHeaders() + public function addCache(CacheItemPoolInterface $cachePool, array $config = []): void { - $this->getHttpClient()->clearHeaders(); + $this->getHttpClientBuilder()->addCache($cachePool, $config); } /** - * @param array $headers + * Remove the cache plugin. + * + * @return void */ - public function setHeaders(array $headers) + public function removeCache(): void { - $this->getHttpClient()->setHeaders($headers); + $this->getHttpClientBuilder()->removeCache(); } /** * @param string $name + * @param array $args * - * @return mixed - * - * @throws InvalidArgumentException + * @return AbstractApi */ - public function getOption($name) + public function __call($name, $args): AbstractApi { - if (!array_key_exists($name, $this->options)) { - throw new InvalidArgumentException(sprintf('Undefined option called: "%s"', $name)); + try { + return $this->api($name); + } catch (InvalidArgumentException $e) { + throw new BadMethodCallException(sprintf('Undefined method called: "%s"', $name)); } - - return $this->options[$name]; } /** - * @param string $name - * @param mixed $value - * - * @throws InvalidArgumentException - * @throws InvalidArgumentException + * @return null|\Psr\Http\Message\ResponseInterface */ - public function setOption($name, $value) + public function getLastResponse(): ?ResponseInterface { - if (!array_key_exists($name, $this->options)) { - throw new InvalidArgumentException(sprintf('Undefined option called: "%s"', $name)); - } + return $this->responseHistory->getLastResponse(); + } - if ('api_version' == $name && !in_array($value, array('v3', 'beta'))) { - throw new InvalidArgumentException(sprintf('Invalid API version ("%s"), valid are: %s', $name, implode(', ', array('v3', 'beta')))); - } + /** + * @return HttpMethodsClientInterface + */ + public function getHttpClient(): HttpMethodsClientInterface + { + return $this->getHttpClientBuilder()->getHttpClient(); + } - $this->options[$name] = $value; + /** + * @return Builder + */ + protected function getHttpClientBuilder(): Builder + { + return $this->httpClientBuilder; } } diff --git a/lib/Github/Exception/ApiLimitExceedException.php b/lib/Github/Exception/ApiLimitExceedException.php index 851631cccf8..c21f5c2729e 100644 --- a/lib/Github/Exception/ApiLimitExceedException.php +++ b/lib/Github/Exception/ApiLimitExceedException.php @@ -2,15 +2,45 @@ namespace Github\Exception; +use Throwable; + /** - * ApiLimitExceedException - * * @author Joseph Bielawski */ class ApiLimitExceedException extends RuntimeException { - public function __construct($limit = 5000, $code = 0, $previous = null) + /** @var int */ + private $limit; + /** @var int */ + private $reset; + + /** + * @param int $limit + * @param int $reset + * @param int $code + * @param Throwable|null $previous + */ + public function __construct(int $limit = 5000, int $reset = 1800, int $code = 0, ?Throwable $previous = null) + { + $this->limit = (int) $limit; + $this->reset = (int) $reset; + + parent::__construct(sprintf('You have reached GitHub hourly limit! Actual limit is: %d', $limit), $code, $previous); + } + + /** + * @return int + */ + public function getLimit(): int + { + return $this->limit; + } + + /** + * @return int + */ + public function getResetTime(): int { - parent::__construct('You have reached GitHub hour limit! Actual limit is: '. $limit, $code, $previous); + return $this->reset; } } diff --git a/lib/Github/Exception/BadMethodCallException.php b/lib/Github/Exception/BadMethodCallException.php new file mode 100644 index 00000000000..22753d082f3 --- /dev/null +++ b/lib/Github/Exception/BadMethodCallException.php @@ -0,0 +1,10 @@ + + */ +class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface +{ +} diff --git a/lib/Github/Exception/ErrorException.php b/lib/Github/Exception/ErrorException.php index dbc0056ef56..b569f730779 100644 --- a/lib/Github/Exception/ErrorException.php +++ b/lib/Github/Exception/ErrorException.php @@ -3,11 +3,8 @@ namespace Github\Exception; /** - * ErrorException - * * @author Joseph Bielawski */ class ErrorException extends \ErrorException implements ExceptionInterface { - } diff --git a/lib/Github/Exception/ExceptionInterface.php b/lib/Github/Exception/ExceptionInterface.php index 5984e3a4e75..87e6d2f77fa 100644 --- a/lib/Github/Exception/ExceptionInterface.php +++ b/lib/Github/Exception/ExceptionInterface.php @@ -2,7 +2,8 @@ namespace Github\Exception; -interface ExceptionInterface -{ +use Http\Client\Exception; +interface ExceptionInterface extends Exception +{ } diff --git a/lib/Github/Exception/InvalidArgumentException.php b/lib/Github/Exception/InvalidArgumentException.php index ae30c05125c..75de2cd7515 100644 --- a/lib/Github/Exception/InvalidArgumentException.php +++ b/lib/Github/Exception/InvalidArgumentException.php @@ -3,11 +3,8 @@ namespace Github\Exception; /** - * InvalidArgumentException - * * @author Joseph Bielawski */ class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface { - } diff --git a/lib/Github/Exception/MissingArgumentException.php b/lib/Github/Exception/MissingArgumentException.php index fd14ba01953..742cdc5ac7f 100644 --- a/lib/Github/Exception/MissingArgumentException.php +++ b/lib/Github/Exception/MissingArgumentException.php @@ -2,19 +2,24 @@ namespace Github\Exception; +use Throwable; + /** - * MissingArgumentException - * * @author Joseph Bielawski */ class MissingArgumentException extends ErrorException { - public function __construct($required, $code = 0, $previous = null) + /** + * @param string|array $required + * @param int $code + * @param Throwable|null $previous + */ + public function __construct($required, int $code = 0, ?Throwable $previous = null) { if (is_string($required)) { - $required = array($required); + $required = [$required]; } - parent::__construct(sprintf('One or more of required ("%s") parameters is missing!', implode('", "', $required)), $code, $previous); + parent::__construct(sprintf('One or more of required ("%s") parameters is missing!', implode('", "', $required)), $code, 1, __FILE__, __LINE__, $previous); } } diff --git a/lib/Github/Exception/RuntimeException.php b/lib/Github/Exception/RuntimeException.php index d3cc9fdeebc..827632e97f5 100644 --- a/lib/Github/Exception/RuntimeException.php +++ b/lib/Github/Exception/RuntimeException.php @@ -3,11 +3,8 @@ namespace Github\Exception; /** - * RuntimeException - * * @author Joseph Bielawski */ class RuntimeException extends \RuntimeException implements ExceptionInterface { - } diff --git a/lib/Github/Exception/SsoRequiredException.php b/lib/Github/Exception/SsoRequiredException.php new file mode 100644 index 00000000000..09b9d63db08 --- /dev/null +++ b/lib/Github/Exception/SsoRequiredException.php @@ -0,0 +1,31 @@ +url = $url; + + parent::__construct('Resource protected by organization SAML enforcement. You must grant your personal token access to this organization.', $code, $previous); + } + + /** + * @return string + */ + public function getUrl() + { + return $this->url; + } +} diff --git a/lib/Github/Exception/TwoFactorAuthenticationRequiredException.php b/lib/Github/Exception/TwoFactorAuthenticationRequiredException.php new file mode 100644 index 00000000000..139033dff5b --- /dev/null +++ b/lib/Github/Exception/TwoFactorAuthenticationRequiredException.php @@ -0,0 +1,30 @@ +type = $type; + parent::__construct('Two factor authentication is enabled on this account', $code, $previous); + } + + /** + * @return string + */ + public function getType(): string + { + return $this->type; + } +} diff --git a/lib/Github/Exception/ValidationFailedException.php b/lib/Github/Exception/ValidationFailedException.php index 43e357b4be5..c689e2d695d 100644 --- a/lib/Github/Exception/ValidationFailedException.php +++ b/lib/Github/Exception/ValidationFailedException.php @@ -3,11 +3,10 @@ namespace Github\Exception; /** - * ValidationFailedException + * When GitHub returns with a HTTP response that says our request is invalid. * * @author Joseph Bielawski */ class ValidationFailedException extends ErrorException { - } diff --git a/lib/Github/HttpClient/Builder.php b/lib/Github/HttpClient/Builder.php new file mode 100644 index 00000000000..c77f1ac83d8 --- /dev/null +++ b/lib/Github/HttpClient/Builder.php @@ -0,0 +1,214 @@ + + */ +class Builder +{ + /** + * The object that sends HTTP messages. + * + * @var ClientInterface + */ + private $httpClient; + + /** + * A HTTP client with all our plugins. + * + * @var HttpMethodsClientInterface + */ + private $pluginClient; + + /** + * @var RequestFactoryInterface + */ + private $requestFactory; + + /** + * @var StreamFactoryInterface + */ + private $streamFactory; + + /** + * True if we should create a new Plugin client at next request. + * + * @var bool + */ + private $httpClientModified = true; + + /** + * @var Plugin[] + */ + private $plugins = []; + + /** + * This plugin is special treated because it has to be the very last plugin. + * + * @var Plugin\CachePlugin|null + */ + private $cachePlugin; + + /** + * Http headers. + * + * @var array + */ + private $headers = []; + + /** + * @param ClientInterface|null $httpClient + * @param RequestFactoryInterface|null $requestFactory + * @param StreamFactoryInterface|null $streamFactory + */ + public function __construct( + ?ClientInterface $httpClient = null, + ?RequestFactoryInterface $requestFactory = null, + ?StreamFactoryInterface $streamFactory = null + ) { + $this->httpClient = $httpClient ?? Psr18ClientDiscovery::find(); + $this->requestFactory = $requestFactory ?? Psr17FactoryDiscovery::findRequestFactory(); + $this->streamFactory = $streamFactory ?? Psr17FactoryDiscovery::findStreamFactory(); + } + + /** + * @return HttpMethodsClientInterface + */ + public function getHttpClient(): HttpMethodsClientInterface + { + if ($this->httpClientModified) { + $this->httpClientModified = false; + + $plugins = $this->plugins; + if ($this->cachePlugin) { + $plugins[] = $this->cachePlugin; + } + + $this->pluginClient = new HttpMethodsClient( + (new PluginClientFactory())->createClient($this->httpClient, $plugins), + $this->requestFactory, + $this->streamFactory + ); + } + + return $this->pluginClient; + } + + /** + * Add a new plugin to the end of the plugin chain. + * + * @param Plugin $plugin + * + * @return void + */ + public function addPlugin(Plugin $plugin): void + { + $this->plugins[] = $plugin; + $this->httpClientModified = true; + } + + /** + * Remove a plugin by its fully qualified class name (FQCN). + * + * @param string $fqcn + * + * @return void + */ + public function removePlugin(string $fqcn): void + { + foreach ($this->plugins as $idx => $plugin) { + if ($plugin instanceof $fqcn) { + unset($this->plugins[$idx]); + $this->httpClientModified = true; + } + } + } + + /** + * Clears used headers. + * + * @return void + */ + public function clearHeaders(): void + { + $this->headers = []; + + $this->removePlugin(Plugin\HeaderAppendPlugin::class); + $this->addPlugin(new Plugin\HeaderAppendPlugin($this->headers)); + } + + /** + * @param array $headers + * + * @return void + */ + public function addHeaders(array $headers): void + { + $this->headers = array_merge($this->headers, $headers); + + $this->removePlugin(Plugin\HeaderAppendPlugin::class); + $this->addPlugin(new Plugin\HeaderAppendPlugin($this->headers)); + } + + /** + * @param string $header + * @param string $headerValue + * + * @return void + */ + public function addHeaderValue(string $header, string $headerValue): void + { + if (!isset($this->headers[$header])) { + $this->headers[$header] = $headerValue; + } else { + $this->headers[$header] = array_merge((array) $this->headers[$header], [$headerValue]); + } + + $this->removePlugin(Plugin\HeaderAppendPlugin::class); + $this->addPlugin(new Plugin\HeaderAppendPlugin($this->headers)); + } + + /** + * Add a cache plugin to cache responses locally. + * + * @param CacheItemPoolInterface $cachePool + * @param array $config + * + * @return void + */ + public function addCache(CacheItemPoolInterface $cachePool, array $config = []): void + { + if (!isset($config['cache_key_generator'])) { + $config['cache_key_generator'] = new HeaderCacheKeyGenerator(['Authorization', 'Cookie', 'Accept', 'Content-type']); + } + $this->cachePlugin = Plugin\CachePlugin::clientCache($cachePool, $this->streamFactory, $config); + $this->httpClientModified = true; + } + + /** + * Remove the cache plugin. + * + * @return void + */ + public function removeCache(): void + { + $this->cachePlugin = null; + $this->httpClientModified = true; + } +} diff --git a/lib/Github/HttpClient/Cache/CacheInterface.php b/lib/Github/HttpClient/Cache/CacheInterface.php deleted file mode 100644 index e669f72fe1a..00000000000 --- a/lib/Github/HttpClient/Cache/CacheInterface.php +++ /dev/null @@ -1,51 +0,0 @@ - - */ -interface CacheInterface -{ - /** - * @param string $id The id of the cached resource - * - * @return bool if present - */ - public function has($id); - - /** - * @param string $id The id of the cached resource - * - * @return null|integer The modified since timestamp - */ - public function getModifiedSince($id); - - /** - * @param string $id The id of the cached resource - * - * @return null|string The ETag value - */ - public function getETag($id); - - /** - * @param string $id The id of the cached resource - * - * @return Response The cached response object - * - * @throws \InvalidArgumentException If cache data don't exists - */ - public function get($id); - - /** - * @param string $id The id of the cached resource - * @param Response $response The response to cache - * - * @throws \InvalidArgumentException If cache data cannot be saved - */ - public function set($id, Response $response); -} diff --git a/lib/Github/HttpClient/Cache/FilesystemCache.php b/lib/Github/HttpClient/Cache/FilesystemCache.php deleted file mode 100644 index ff332b57075..00000000000 --- a/lib/Github/HttpClient/Cache/FilesystemCache.php +++ /dev/null @@ -1,85 +0,0 @@ -path = $path; - } - - /** - * {@inheritdoc} - */ - public function get($id) - { - if (false !== $content = @file_get_contents($this->getPath($id))) { - return unserialize($content); - } - - throw new \InvalidArgumentException(sprintf('File "%s" not found', $this->getPath($id))); - } - - /** - * {@inheritdoc} - */ - public function set($id, Response $response) - { - if (!is_dir($this->path)) { - @mkdir($this->path, 0777, true); - } - - if (false === @file_put_contents($this->getPath($id), serialize($response))) { - throw new \InvalidArgumentException(sprintf('Cannot put content in file "%s"', $this->getPath($id))); - } - if (false === @file_put_contents($this->getPath($id).'.etag', $response->getHeader('ETag'))) { - throw new \InvalidArgumentException(sprintf('Cannot put content in file "%s"', $this->getPath($id).'.etag')); - } - } - - /** - * {@inheritdoc} - */ - public function has($id) - { - return file_exists($this->getPath($id)); - } - - /** - * {@inheritdoc} - */ - public function getModifiedSince($id) - { - if ($this->has($id)) { - return filemtime($this->getPath($id)); - } - } - - public function getETag($id) - { - if (file_exists($this->getPath($id).'.etag')) { - return file_get_contents($this->getPath($id).'.etag'); - } - } - - /** - * @param $id string - * - * @return string - */ - protected function getPath($id) - { - return sprintf('%s%s%s', rtrim($this->path, DIRECTORY_SEPARATOR), DIRECTORY_SEPARATOR, md5($id)); - } -} diff --git a/lib/Github/HttpClient/Cache/GaufretteCache.php b/lib/Github/HttpClient/Cache/GaufretteCache.php deleted file mode 100644 index 0797a043b91..00000000000 --- a/lib/Github/HttpClient/Cache/GaufretteCache.php +++ /dev/null @@ -1,71 +0,0 @@ - - */ -class GaufretteCache implements CacheInterface -{ - /** - * @var Filesystem - */ - protected $filesystem; - - /** - * @param Filesystem $filesystem - */ - public function __construct(Filesystem $filesystem) - { - $this->filesystem = $filesystem; - } - - /** - * {@inheritdoc} - */ - public function get($id) - { - $content = $this->filesystem->read($id); - - return unserialize($content); - } - - /** - * {@inheritdoc} - */ - public function set($id, Response $response) - { - $this->filesystem->write($id, serialize($response), true); - $this->filesystem->write($id.'.etag', $response->getHeader('ETag'), true); - } - - /** - * {@inheritdoc} - */ - public function has($id) - { - $this->filesystem->has($id); - } - - /** - * {@inheritdoc} - */ - public function getModifiedSince($id) - { - if ($this->filesystem->has($id)) { - return $this->filesystem->mtime($id); - } - } - - public function getETag($id) - { - if ($this->filesystem->has($id)) { - return $this->filesystem->read($id.'.etag'); - } - } -} diff --git a/lib/Github/HttpClient/CachedHttpClient.php b/lib/Github/HttpClient/CachedHttpClient.php deleted file mode 100644 index dfbe6630f31..00000000000 --- a/lib/Github/HttpClient/CachedHttpClient.php +++ /dev/null @@ -1,85 +0,0 @@ - - */ -class CachedHttpClient extends HttpClient -{ - /** - * @var CacheInterface - */ - protected $cache; - - /** - * @return CacheInterface - */ - public function getCache() - { - if (null === $this->cache) { - $this->cache = new FilesystemCache($this->options['cache_dir'] ?: sys_get_temp_dir().DIRECTORY_SEPARATOR.'php-github-api-cache'); - } - - return $this->cache; - } - - /** - * @param $cache CacheInterface - */ - public function setCache(CacheInterface $cache) - { - $this->cache = $cache; - } - - /** - * {@inheritdoc} - */ - public function request($path, $body = null, $httpMethod = 'GET', array $headers = array(), array $options = array()) - { - $response = parent::request($path, $body, $httpMethod, $headers, $options); - - if (304 == $response->getStatusCode()) { - return $this->getCache()->get($path); - } - - $this->getCache()->set($path, $response); - - return $response; - } - - /** - * Create requests with If-Modified-Since headers - * - * {@inheritdoc} - */ - protected function createRequest($httpMethod, $path, $body = null, array $headers = array(), array $options = array()) - { - $request = parent::createRequest($httpMethod, $path, $body, $headers = array(), $options); - - if ($modifiedAt = $this->getCache()->getModifiedSince($path)) { - $modifiedAt = new \DateTime('@'.$modifiedAt); - $modifiedAt->setTimezone(new \DateTimeZone('GMT')); - - $request->addHeader( - 'If-Modified-Since', - sprintf('%s GMT', $modifiedAt->format('l, d-M-y H:i:s')) - ); - } - if ($etag = $this->getCache()->getETag($path)) { - $request->addHeader( - 'If-None-Match', - $etag - ); - } - - return $request; - } -} diff --git a/lib/Github/HttpClient/HttpClient.php b/lib/Github/HttpClient/HttpClient.php deleted file mode 100644 index 268c1396f56..00000000000 --- a/lib/Github/HttpClient/HttpClient.php +++ /dev/null @@ -1,183 +0,0 @@ - - */ -class HttpClient implements HttpClientInterface -{ - protected $options = array( - 'base_url' => 'https://api.github.com/', - - 'user_agent' => 'php-github-api (http://github.com/KnpLabs/php-github-api)', - 'timeout' => 10, - - 'api_limit' => 5000, - 'api_version' => 'v3', - - 'cache_dir' => null - ); - - protected $headers = array(); - - private $lastResponse; - private $lastRequest; - - /** - * @param array $options - * @param ClientInterface $client - */ - public function __construct(array $options = array(), ClientInterface $client = null) - { - $this->options = array_merge($this->options, $options); - $client = $client ?: new GuzzleClient($this->options['base_url'], $this->options); - $this->client = $client; - - $this->addListener('request.error', array(new ErrorListener($this->options), 'onRequestError')); - $this->clearHeaders(); - } - - /** - * {@inheritDoc} - */ - public function setOption($name, $value) - { - $this->options[$name] = $value; - } - - /** - * {@inheritDoc} - */ - public function setHeaders(array $headers) - { - $this->headers = array_merge($this->headers, $headers); - } - - /** - * Clears used headers - */ - public function clearHeaders() - { - $this->headers = array( - 'Accept' => sprintf('application/vnd.github.%s+json', $this->options['api_version']), - 'User-Agent' => sprintf('%s', $this->options['user_agent']), - ); - } - - public function addListener($eventName, $listener) - { - $this->client->getEventDispatcher()->addListener($eventName, $listener); - } - - /** - * {@inheritDoc} - */ - public function get($path, array $parameters = array(), array $headers = array()) - { - return $this->request($path, null, 'GET', $headers, array('query' => $parameters)); - } - - /** - * {@inheritDoc} - */ - public function post($path, $body = null, array $headers = array()) - { - return $this->request($path, $body, 'POST', $headers); - } - - /** - * {@inheritDoc} - */ - public function patch($path, $body = null, array $headers = array()) - { - return $this->request($path, $body, 'PATCH', $headers); - } - - /** - * {@inheritDoc} - */ - public function delete($path, $body = null, array $headers = array()) - { - return $this->request($path, $body, 'DELETE', $headers); - } - - /** - * {@inheritDoc} - */ - public function put($path, $body, array $headers = array()) - { - return $this->request($path, $body, 'PUT', $headers); - } - - /** - * {@inheritDoc} - */ - public function request($path, $body = null, $httpMethod = 'GET', array $headers = array(), array $options = array()) - { - $request = $this->createRequest($httpMethod, $path, $body, $headers, $options); - $request->addHeaders($headers); - - try { - $response = $this->client->send($request); - } catch (\LogicException $e) { - throw new ErrorException($e->getMessage()); - } catch (\RuntimeException $e) { - throw new RuntimeException($e->getMessage()); - } - - $this->lastRequest = $request; - $this->lastResponse = $response; - - return $response; - } - - /** - * {@inheritDoc} - */ - public function authenticate($tokenOrLogin, $password = null, $method) - { - $this->addListener('request.before_send', array( - new AuthListener($tokenOrLogin, $password, $method), 'onRequestBeforeSend' - )); - } - - /** - * @return Request - */ - public function getLastRequest() - { - return $this->lastRequest; - } - - /** - * @return Response - */ - public function getLastResponse() - { - return $this->lastResponse; - } - - protected function createRequest($httpMethod, $path, $body = null, array $headers = array(), array $options = array()) - { - return $this->client->createRequest( - $httpMethod, - $path, - array_merge($this->headers, $headers), - $body, - $options - ); - } -} diff --git a/lib/Github/HttpClient/HttpClientInterface.php b/lib/Github/HttpClient/HttpClientInterface.php deleted file mode 100644 index a56d7ff7df5..00000000000 --- a/lib/Github/HttpClient/HttpClientInterface.php +++ /dev/null @@ -1,110 +0,0 @@ - - */ -interface HttpClientInterface -{ - /** - * Send a GET request - * - * @param string $path Request path - * @param array $parameters GET Parameters - * @param array $headers Reconfigure the request headers for this call only - * - * @return array Data - */ - public function get($path, array $parameters = array(), array $headers = array()); - - /** - * Send a POST request - * - * @param string $path Request path - * @param mixed $body Request body - * @param array $headers Reconfigure the request headers for this call only - * - * @return array Data - */ - public function post($path, $body = null, array $headers = array()); - - /** - * Send a PATCH request - * - * @param string $path Request path - * @param mixed $body Request body - * @param array $headers Reconfigure the request headers for this call only - * - * @internal param array $parameters Request body - * @return array Data - */ - public function patch($path, $body = null, array $headers = array()); - - /** - * Send a PUT request - * - * @param string $path Request path - * @param mixed $body Request body - * @param array $headers Reconfigure the request headers for this call only - * - * @return array Data - */ - public function put($path, $body, array $headers = array()); - - /** - * Send a DELETE request - * - * @param string $path Request path - * @param mixed $body Request body - * @param array $headers Reconfigure the request headers for this call only - * - * @return array Data - */ - public function delete($path, $body = null, array $headers = array()); - - /** - * Send a request to the server, receive a response, - * decode the response and returns an associative array - * - * @param string $path Request path - * @param mixed $body Request body - * @param string $httpMethod HTTP method to use - * @param array $headers Request headers - * - * @return array Data - */ - public function request($path, $body, $httpMethod = 'GET', array $headers = array()); - - /** - * Change an option value. - * - * @param string $name The option name - * @param mixed $value The value - * - * @throws InvalidArgumentException - */ - public function setOption($name, $value); - - /** - * Set HTTP headers - * - * @param array $headers - */ - public function setHeaders(array $headers); - - /** - * Authenticate a user for all next requests - * - * @param string $tokenOrLogin GitHub private token/username/client ID - * @param null|string $password GitHub password/secret (optionally can contain $authMethod) - * @param null|string $authMethod One of the AUTH_* class constants - * - * @throws InvalidArgumentException If no authentication method was given - */ - public function authenticate($tokenOrLogin, $password, $authMethod); -} diff --git a/lib/Github/HttpClient/Listener/AuthListener.php b/lib/Github/HttpClient/Listener/AuthListener.php deleted file mode 100644 index 41ad42e4642..00000000000 --- a/lib/Github/HttpClient/Listener/AuthListener.php +++ /dev/null @@ -1,68 +0,0 @@ -tokenOrLogin = $tokenOrLogin; - $this->password = $password; - $this->method = $method; - } - - public function onRequestBeforeSend(Event $event) - { - // Skip by default - if (null === $this->method) { - return; - } - - switch ($this->method) { - case Client::AUTH_HTTP_PASSWORD: - $event['request']->setHeader( - 'Authorization', - sprintf('Basic %s', base64_encode($this->tokenOrLogin . ':' . $this->password)) - ); - break; - - case Client::AUTH_HTTP_TOKEN: - $event['request']->setHeader('Authorization', sprintf('token %s', $this->tokenOrLogin)); - break; - - case Client::AUTH_URL_CLIENT_ID: - $url = $event['request']->getUrl(); - - $parameters = array( - 'client_id' => $this->tokenOrLogin, - 'client_secret' => $this->password, - ); - - $url .= (false === strpos($url, '?') ? '?' : '&'); - $url .= utf8_encode(http_build_query($parameters, '', '&')); - - $event['request']->setUrl($url); - break; - - case Client::AUTH_URL_TOKEN: - $url = $event['request']->getUrl(); - $url .= (false === strpos($url, '?') ? '?' : '&'); - $url .= utf8_encode(http_build_query(array('access_token' => $this->tokenOrLogin), '', '&')); - - $event['request']->setUrl($url); - break; - - default: - throw new RuntimeException(sprintf('%s not yet implemented', $this->method)); - break; - } - } -} diff --git a/lib/Github/HttpClient/Listener/ErrorListener.php b/lib/Github/HttpClient/Listener/ErrorListener.php deleted file mode 100644 index 60cbc5a80fd..00000000000 --- a/lib/Github/HttpClient/Listener/ErrorListener.php +++ /dev/null @@ -1,86 +0,0 @@ - - */ -class ErrorListener -{ - /** - * @var array - */ - private $options; - - /** - * @param array $options - */ - public function __construct(array $options) - { - $this->options = $options; - } - - /** - * {@inheritDoc} - */ - public function onRequestError(Event $event) - { - /** @var $request \Guzzle\Http\Message\Request */ - $request = $event['request']; - $response = $request->getResponse(); - - if ($response->isClientError() || $response->isServerError()) { - $remaining = (string) $response->getHeader('X-RateLimit-Remaining'); - - if (null != $remaining && 1 > $remaining && 'rate_limit' !== substr($request->getResource(), 1, 10)) { - throw new ApiLimitExceedException($this->options['api_limit']); - } - - $content = ResponseMediator::getContent($response); - if (is_array($content) && isset($content['message'])) { - if (400 == $response->getStatusCode()) { - throw new ErrorException($content['message'], 400); - } elseif (422 == $response->getStatusCode() && isset($content['errors'])) { - $errors = array(); - foreach ($content['errors'] as $error) { - switch ($error['code']) { - case 'missing': - $errors[] = sprintf('The %s %s does not exist, for resource "%s"', $error['field'], $error['value'], $error['resource']); - break; - - case 'missing_field': - $errors[] = sprintf('Field "%s" is missing, for resource "%s"', $error['field'], $error['resource']); - break; - - case 'invalid': - $errors[] = sprintf('Field "%s" is invalid, for resource "%s"', $error['field'], $error['resource']); - break; - - case 'already_exists': - $errors[] = sprintf('Field "%s" already exists, for resource "%s"', $error['field'], $error['resource']); - break; - - default: - $errors[] = $error['message']; - break; - - } - } - - throw new ValidationFailedException('Validation Failed: ' . implode(', ', $errors), 422); - } - } - - throw new RuntimeException(isset($content['message']) ? $content['message'] : $content, $response->getStatusCode()); - }; - } -} diff --git a/lib/Github/HttpClient/Message/ResponseMediator.php b/lib/Github/HttpClient/Message/ResponseMediator.php index 72fe7c7129e..a72ccef7ed4 100644 --- a/lib/Github/HttpClient/Message/ResponseMediator.php +++ b/lib/Github/HttpClient/Message/ResponseMediator.php @@ -2,35 +2,47 @@ namespace Github\HttpClient\Message; -use Guzzle\Http\Message\Response; use Github\Exception\ApiLimitExceedException; +use Psr\Http\Message\ResponseInterface; -class ResponseMediator +final class ResponseMediator { - public static function getContent(Response $response) + /** + * @param ResponseInterface $response + * + * @return array|string + */ + public static function getContent(ResponseInterface $response) { - $body = $response->getBody(true); - $content = json_decode($body, true); - - if (JSON_ERROR_NONE !== json_last_error()) { - return $body; + $body = $response->getBody()->__toString(); + if (strpos($response->getHeaderLine('Content-Type'), 'application/json') === 0) { + $content = json_decode($body, true); + if (JSON_ERROR_NONE === json_last_error()) { + return $content; + } } - return $content; + return $body; } - public static function getPagination(Response $response) + /** + * @param ResponseInterface $response + * + * @return array + */ + public static function getPagination(ResponseInterface $response): array { - $header = $response->getHeader('Link'); + $header = self::getHeader($response, 'Link'); - if (empty($header)) { - return null; + if (null === $header) { + return []; } - $pagination = array(); + $pagination = []; foreach (explode(',', $header) as $link) { preg_match('/<(.*)>; rel="(.*)"/i', trim($link, ','), $match); + /** @var string[] $match */ if (3 === count($match)) { $pagination[$match[2]] = $match[1]; } @@ -39,12 +51,40 @@ public static function getPagination(Response $response) return $pagination; } - public static function getApiLimit(Response $response) + /** + * @param ResponseInterface $response + * + * @return string|null + */ + public static function getApiLimit(ResponseInterface $response): ?string { - $remainingCalls = $response->getHeader('X-RateLimit-Remaining'); + $remainingCallsHeader = self::getHeader($response, 'X-RateLimit-Remaining'); + + if (null === $remainingCallsHeader) { + return null; + } - if (null !== $remainingCalls && 1 > $remainingCalls) { + $remainingCalls = (int) $remainingCallsHeader; + + if (1 > $remainingCalls) { throw new ApiLimitExceedException($remainingCalls); } + + return $remainingCallsHeader; + } + + /** + * Get the value for a single header. + * + * @param ResponseInterface $response + * @param string $name + * + * @return string|null + */ + public static function getHeader(ResponseInterface $response, string $name): ?string + { + $headers = $response->getHeader($name); + + return array_shift($headers); } } diff --git a/lib/Github/HttpClient/Plugin/Authentication.php b/lib/Github/HttpClient/Plugin/Authentication.php new file mode 100644 index 00000000000..91ed9caa2cf --- /dev/null +++ b/lib/Github/HttpClient/Plugin/Authentication.php @@ -0,0 +1,71 @@ + + */ +final class Authentication implements Plugin +{ + /** + * @var string + */ + private $tokenOrLogin; + + /** + * @var string|null + */ + private $password; + + /** + * @var string|null + */ + private $method; + + /** + * @param string $tokenOrLogin GitHub private token/username/client ID + * @param string|null $password GitHub password/secret (optionally can contain $method) + * @param string|null $method One of the AUTH_* class constants + */ + public function __construct(string $tokenOrLogin, ?string $password, ?string $method) + { + $this->tokenOrLogin = $tokenOrLogin; + $this->password = $password; + $this->method = $method; + } + + /** + * @return Promise + */ + public function handleRequest(RequestInterface $request, callable $next, callable $first): Promise + { + $request = $request->withHeader( + 'Authorization', + $this->getAuthorizationHeader() + ); + + return $next($request); + } + + private function getAuthorizationHeader(): string + { + switch ($this->method) { + case AuthMethod::CLIENT_ID: + return sprintf('Basic %s', base64_encode($this->tokenOrLogin.':'.$this->password)); + case AuthMethod::ACCESS_TOKEN: + return sprintf('token %s', $this->tokenOrLogin); + case AuthMethod::JWT: + return sprintf('Bearer %s', $this->tokenOrLogin); + default: + throw new RuntimeException(sprintf('%s not yet implemented', $this->method)); + } + } +} diff --git a/lib/Github/HttpClient/Plugin/GithubExceptionThrower.php b/lib/Github/HttpClient/Plugin/GithubExceptionThrower.php new file mode 100644 index 00000000000..9479aaaf2be --- /dev/null +++ b/lib/Github/HttpClient/Plugin/GithubExceptionThrower.php @@ -0,0 +1,174 @@ + + * @author Tobias Nyholm + */ +final class GithubExceptionThrower implements Plugin +{ + /** + * @return Promise + */ + public function handleRequest(RequestInterface $request, callable $next, callable $first): Promise + { + return $next($request)->then(function (ResponseInterface $response) use ($request) { + if ($response->getStatusCode() < 400 || $response->getStatusCode() > 600) { + $this->checkGraphqlErrors($response); + + return $response; + } + + // If error: + $remaining = ResponseMediator::getHeader($response, 'X-RateLimit-Remaining'); + if ((429 === $response->getStatusCode()) && null !== $remaining && 1 > $remaining && 'rate_limit' !== substr($request->getRequestTarget(), 1, 10)) { + $limit = (int) ResponseMediator::getHeader($response, 'X-RateLimit-Limit'); + $reset = (int) ResponseMediator::getHeader($response, 'X-RateLimit-Reset'); + + throw new ApiLimitExceedException($limit, $reset); + } + + if ((401 === $response->getStatusCode()) && $response->hasHeader('X-GitHub-OTP') && 0 === strpos((string) ResponseMediator::getHeader($response, 'X-GitHub-OTP'), 'required;')) { + $type = substr((string) ResponseMediator::getHeader($response, 'X-GitHub-OTP'), 9); + + throw new TwoFactorAuthenticationRequiredException($type); + } + + $content = ResponseMediator::getContent($response); + if (is_array($content) && isset($content['message'])) { + if (400 === $response->getStatusCode()) { + throw new ErrorException(sprintf('%s (%s)', $content['message'], $response->getReasonPhrase()), 400); + } + + if (422 === $response->getStatusCode() && isset($content['errors'])) { + $errors = []; + foreach ($content['errors'] as $error) { + switch ($error['code'] ?? null) { + case 'missing': + $errors[] = sprintf('The %s %s does not exist, for resource "%s"', $error['field'], $error['value'], $error['resource']); + break; + + case 'missing_field': + $errors[] = sprintf('Field "%s" is missing, for resource "%s"', $error['field'], $error['resource']); + break; + + case 'invalid': + if (isset($error['message'])) { + $errors[] = sprintf('Field "%s" is invalid, for resource "%s": "%s"', $error['field'], $error['resource'], $error['message']); + } else { + $errors[] = sprintf('Field "%s" is invalid, for resource "%s"', $error['field'], $error['resource']); + } + break; + + case 'already_exists': + $errors[] = sprintf('Field "%s" already exists, for resource "%s"', $error['field'], $error['resource']); + break; + + default: + if (is_string($error)) { + $errors[] = $error; + + break; + } + + if (isset($error['message'])) { + $errors[] = $error['message']; + } + break; + } + } + + throw new ValidationFailedException( + $errors ? 'Validation Failed: '.implode(', ', $errors) : 'Validation Failed', + 422 + ); + } + } + + if (502 == $response->getStatusCode() && isset($content['errors']) && is_array($content['errors'])) { + $errors = []; + foreach ($content['errors'] as $error) { + if (isset($error['message'])) { + $errors[] = $error['message']; + } + } + + throw new RuntimeException(implode(', ', $errors), 502); + } + + if ((403 === $response->getStatusCode()) && $response->hasHeader('X-GitHub-SSO') && 0 === strpos((string) ResponseMediator::getHeader($response, 'X-GitHub-SSO'), 'required;')) { + // The header will look something like this: + // required; url=https://github.com/orgs/octodocs-test/sso?authorization_request=AZSCKtL4U8yX1H3sCQIVnVgmjmon5fWxks5YrqhJgah0b2tlbl9pZM4EuMz4 + // So we strip out the first 14 characters, leaving only the URL. + // @see https://developer.github.com/v3/auth/#authenticating-for-saml-sso + $url = substr((string) ResponseMediator::getHeader($response, 'X-GitHub-SSO'), 14); + + throw new SsoRequiredException($url); + } + + $remaining = ResponseMediator::getHeader($response, 'X-RateLimit-Remaining'); + if ((403 === $response->getStatusCode()) && null !== $remaining && 1 > $remaining && isset($content['message']) && (0 === strpos($content['message'], 'API rate limit exceeded'))) { + $limit = (int) ResponseMediator::getHeader($response, 'X-RateLimit-Limit'); + $reset = (int) ResponseMediator::getHeader($response, 'X-RateLimit-Reset'); + + throw new ApiLimitExceedException($limit, $reset); + } + + $reset = (int) ResponseMediator::getHeader($response, 'X-RateLimit-Reset'); + if ((403 === $response->getStatusCode()) && 0 < $reset && isset($content['message']) && (0 === strpos($content['message'], 'You have exceeded a secondary rate limit'))) { + $limit = (int) ResponseMediator::getHeader($response, 'X-RateLimit-Limit'); + + throw new ApiLimitExceedException($limit, $reset); + } + + throw new RuntimeException(isset($content['message']) ? $content['message'] : $content, $response->getStatusCode()); + }); + } + + /** + * The graphql api doesn't return a 5xx http status for errors. Instead it returns a 200 with an error body. + * + * @throws RuntimeException + */ + private function checkGraphqlErrors(ResponseInterface $response): void + { + if ($response->getStatusCode() !== 200) { + return; + } + + $content = ResponseMediator::getContent($response); + if (!is_array($content)) { + return; + } + + if (!isset($content['errors']) || !is_array($content['errors'])) { + return; + } + + $errors = []; + foreach ($content['errors'] as $error) { + if (isset($error['message'])) { + $errors[] = $error['message']; + } + } + + if (empty($errors)) { + return; + } + + throw new RuntimeException(implode(', ', $errors)); + } +} diff --git a/lib/Github/HttpClient/Plugin/History.php b/lib/Github/HttpClient/Plugin/History.php new file mode 100644 index 00000000000..341c288a6ea --- /dev/null +++ b/lib/Github/HttpClient/Plugin/History.php @@ -0,0 +1,44 @@ + + */ +final class History implements Journal +{ + /** + * @var ResponseInterface|null + */ + private $lastResponse; + + /** + * @return ResponseInterface|null + */ + public function getLastResponse(): ?ResponseInterface + { + return $this->lastResponse; + } + + /** + * @return void + */ + public function addSuccess(RequestInterface $request, ResponseInterface $response): void + { + $this->lastResponse = $response; + } + + /** + * @return void + */ + public function addFailure(RequestInterface $request, ClientExceptionInterface $exception): void + { + } +} diff --git a/lib/Github/HttpClient/Plugin/PathPrepend.php b/lib/Github/HttpClient/Plugin/PathPrepend.php new file mode 100644 index 00000000000..c1077299607 --- /dev/null +++ b/lib/Github/HttpClient/Plugin/PathPrepend.php @@ -0,0 +1,46 @@ + + */ +final class PathPrepend implements Plugin +{ + /** + * @var string + */ + private $path; + + /** + * @param string $path + */ + public function __construct(string $path) + { + $this->path = $path; + } + + /** + * @param RequestInterface $request + * @param callable $next + * @param callable $first + * + * @return Promise + */ + public function handleRequest(RequestInterface $request, callable $next, callable $first): Promise + { + $currentPath = $request->getUri()->getPath(); + if (strpos($currentPath, $this->path) !== 0) { + $uri = $request->getUri()->withPath($this->path.$currentPath); + $request = $request->withUri($uri); + } + + return $next($request); + } +} diff --git a/lib/Github/ResultPager.php b/lib/Github/ResultPager.php index 7483194ba3b..fb8739c4a1c 100644 --- a/lib/Github/ResultPager.php +++ b/lib/Github/ResultPager.php @@ -2,108 +2,159 @@ namespace Github; -use Github\Api\ApiInterface; +use Closure; +use Generator; +use Github\Api\AbstractApi; use Github\HttpClient\Message\ResponseMediator; +use ValueError; /** - * Pager class for supporting pagination in github classes + * Pager class for supporting pagination in github classes. * * @author Ramon de la Fuente * @author Mitchel Verschoof + * @author Graham Campbell */ class ResultPager implements ResultPagerInterface { /** - * @var \Github\Client client + * The default number of entries to request per page. + * + * @var int + */ + private const PER_PAGE = 100; + + /** + * The client to use for pagination. + * + * @var Client */ - protected $client; + private $client; /** - * @var array pagination - * Comes from pagination headers in Github API results + * The number of entries to request per page. + * + * @var int */ - protected $pagination; + private $perPage; /** - * The Github client to use for pagination. This must be the same - * instance that you got the Api instance from, i.e.: + * The pagination result from the API. + * + * @var array + */ + private $pagination; + + /** + * Create a new result pager instance. + * + * Example code: * * $client = new \Github\Client(); * $api = $client->api('someApi'); * $pager = new \Github\ResultPager($client); * - * @param \Github\Client $client + * @param Client $client + * @param int|null $perPage * + * @return void */ - public function __construct(Client $client) + public function __construct(Client $client, ?int $perPage = null) { + if (null !== $perPage && ($perPage < 1 || $perPage > 100)) { + throw new ValueError(sprintf('%s::__construct(): Argument #2 ($perPage) must be between 1 and 100, or null', self::class)); + } + $this->client = $client; + $this->perPage = $perPage ?? self::PER_PAGE; + $this->pagination = []; } /** * {@inheritdoc} */ - public function getPagination() + public function fetch(AbstractApi $api, string $method, array $parameters = []): array { - return $this->pagination; + $paginatorPerPage = $this->perPage; + $closure = Closure::bind(function (AbstractApi $api) use ($paginatorPerPage) { + $clone = clone $api; + $clone->perPage = $paginatorPerPage; + + return $clone; + }, null, AbstractApi::class); + + $api = $closure($api); + $result = $api->$method(...$parameters); + + if ($result === '') { + $result = []; + } + + $this->postFetch(true); + + return $result; } /** * {@inheritdoc} */ - public function fetch(ApiInterface $api, $method, array $parameters = array()) + public function fetchAll(AbstractApi $api, string $method, array $parameters = []): array { - $result = call_user_func_array(array($api, $method), $parameters); - $this->postFetch(); - - return $result; + return iterator_to_array($this->fetchAllLazy($api, $method, $parameters)); } /** * {@inheritdoc} */ - public function fetchAll(ApiInterface $api, $method, array $parameters = array()) + public function fetchAllLazy(AbstractApi $api, string $method, array $parameters = []): Generator { - // get the perPage from the api - $perPage = $api->getPerPage(); - - // Set parameters per_page to GitHub max to minimize number of requests - $api->setPerPage(100); - - $result = array(); - $result = call_user_func_array(array($api, $method), $parameters); - $this->postFetch(); + $result = $this->fetch($api, $method, $parameters); + + foreach ($result['items'] ?? $result as $key => $item) { + if (is_string($key)) { + yield $key => $item; + } else { + yield $item; + } + } while ($this->hasNext()) { - $result = array_merge($result, $this->fetchNext()); + $result = $this->fetchNext(); + + foreach ($result['items'] ?? $result as $key => $item) { + if (is_string($key)) { + yield $key => $item; + } else { + yield $item; + } + } } - - // restore the perPage - $api->setPerPage($perPage); - - return $result; } /** * {@inheritdoc} */ - public function postFetch() + public function postFetch(/* $skipDeprecation = false */): void { - $this->pagination = ResponseMediator::getPagination($this->client->getHttpClient()->getLastResponse()); + if (func_num_args() === 0 || (func_num_args() > 0 && false === func_get_arg(0))) { + trigger_deprecation('KnpLabs/php-github-api', '3.2', 'The "%s" method is deprecated and will be removed.', __METHOD__); + } + + $this->setPagination(); } /** * {@inheritdoc} */ - public function hasNext() + public function hasNext(): bool { - return $this->has('next'); + return isset($this->pagination['next']); } /** * {@inheritdoc} */ - public function fetchNext() + public function fetchNext(): array { return $this->get('next'); } @@ -111,15 +162,15 @@ public function fetchNext() /** * {@inheritdoc} */ - public function hasPrevious() + public function hasPrevious(): bool { - return $this->has('prev'); + return isset($this->pagination['prev']); } /** * {@inheritdoc} */ - public function fetchPrevious() + public function fetchPrevious(): array { return $this->get('prev'); } @@ -127,7 +178,7 @@ public function fetchPrevious() /** * {@inheritdoc} */ - public function fetchFirst() + public function fetchFirst(): array { return $this->get('first'); } @@ -135,29 +186,31 @@ public function fetchFirst() /** * {@inheritdoc} */ - public function fetchLast() + public function fetchLast(): array { return $this->get('last'); } /** - * {@inheritdoc} + * @param string $key + * + * @return array */ - protected function has($key) + protected function get(string $key): array { - return !empty($this->pagination) && isset($this->pagination[$key]); + if (!isset($this->pagination[$key])) { + return []; + } + + $result = $this->client->getHttpClient()->get($this->pagination[$key]); + + $this->postFetch(true); + + return ResponseMediator::getContent($result); } - /** - * {@inheritdoc} - */ - protected function get($key) + private function setPagination(): void { - if ($this->has($key)) { - $result = $this->client->getHttpClient()->get($this->pagination[$key]); - $this->postFetch(); - - return ResponseMediator::getContent($result); - } + $this->pagination = ResponseMediator::getPagination($this->client->getLastResponse()); } } diff --git a/lib/Github/ResultPagerInterface.php b/lib/Github/ResultPagerInterface.php index 7604fd0ecea..bf7618ee411 100644 --- a/lib/Github/ResultPagerInterface.php +++ b/lib/Github/ResultPagerInterface.php @@ -2,83 +2,103 @@ namespace Github; -use Github\Api\ApiInterface; +use Generator; +use Github\Api\AbstractApi; /** - * Pager interface + * Pager interface. * * @author Ramon de la Fuente * @author Mitchel Verschoof + * @author Graham Campbell */ interface ResultPagerInterface { - /** - * @return null|array pagination result of last request + * Fetch a single result (page) from an api call. + * + * @param AbstractApi $api the Api instance + * @param string $method the method name to call on the Api instance + * @param array $parameters the method parameters in an array + * + * @return array returns the result of the Api::$method() call */ - public function getPagination(); + public function fetch(AbstractApi $api, string $method, array $parameters = []): array; /** - * Fetch a single result (page) from an api call + * Fetch all results (pages) from an api call. * - * @param ApiInterface $api the Api instance - * @param string $method the method name to call on the Api instance - * @param array $parameters the method parameters in an array + * Use with care - there is no maximum. * - * @return array returns the result of the Api::$method() call + * @param AbstractApi $api the Api instance + * @param string $method the method name to call on the Api instance + * @param array $parameters the method parameters in an array + * + * @return array returns a merge of the results of the Api::$method() call */ - public function fetch(ApiInterface $api, $method, array $parameters = array()); + public function fetchAll(AbstractApi $api, string $method, array $parameters = []): array; /** - * Fetch all results (pages) from an api call - * Use with care - there is no maximum + * Lazily fetch all results (pages) from an api call. * - * @param ApiInterface $api the Api instance - * @param string $method the method name to call on the Api instance - * @param array $parameters the method parameters in an array + * Use with care - there is no maximum. * - * @return array returns a merge of the results of the Api::$method() call + * @param AbstractApi $api the Api instance + * @param string $method the method name to call on the Api instance + * @param array $parameters the method parameters in an array + * + * @return \Generator returns a merge of the results of the Api::$method() call */ - public function fetchAll(ApiInterface $api, $method, array $parameters = array()); + public function fetchAllLazy(AbstractApi $api, string $method, array $parameters = []): Generator; /** - * Method that performs the actual work to refresh the pagination property + * Method that performs the actual work to refresh the pagination property. + * + * @deprecated since 3.2 and will be removed in 4.0. + * + * @return void */ - public function postFetch(); + public function postFetch(): void; /** - * Check to determine the availability of a next page + * Check to determine the availability of a next page. + * * @return bool */ - public function hasNext(); + public function hasNext(): bool; /** - * Check to determine the availability of a previous page + * Check to determine the availability of a previous page. + * * @return bool */ - public function hasPrevious(); + public function hasPrevious(): bool; /** - * Fetch the next page + * Fetch the next page. + * * @return array */ - public function fetchNext(); + public function fetchNext(): array; /** - * Fetch the previous page + * Fetch the previous page. + * * @return array */ - public function fetchPrevious(); + public function fetchPrevious(): array; /** - * Fetch the first page + * Fetch the first page. + * * @return array */ - public function fetchFirst(); + public function fetchFirst(): array; /** - * Fetch the last page + * Fetch the last page. + * * @return array */ - public function fetchLast(); + public function fetchLast(): array; } diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 00000000000..9e84171f2c5 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,15 @@ +parameters: + checkMissingIterableValueType: false + + level: 6 + paths: + - lib + + ignoreErrors: + # Ignore typehint errors on api classes + - + message: '#Method (.*) with no typehint specified\.#' + path: lib/Github/Api + - + message: '#Method (.*) has no return typehint specified\.#' + path: lib/Github/Api diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 619d9706a7a..98d2e51cc8f 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -8,8 +8,7 @@ convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" - syntaxCheck="false" - bootstrap="test/bootstrap.php" + bootstrap="vendor/autoload.php" > @@ -19,7 +18,7 @@ - functional + integration @@ -28,4 +27,8 @@ ./lib/Github/ + + + + diff --git a/test/Github/Tests/Api/AbstractApiTest.php b/test/Github/Tests/Api/AbstractApiTest.php index f3982e398e6..53e0eb6970a 100644 --- a/test/Github/Tests/Api/AbstractApiTest.php +++ b/test/Github/Tests/Api/AbstractApiTest.php @@ -3,29 +3,38 @@ namespace Github\Tests\Api; use Github\Api\AbstractApi; -use Guzzle\Http\Message\Response; +use GuzzleHttp\Psr7\Response; +use GuzzleHttp\Psr7\Utils; +use Http\Client\Common\HttpMethodsClientInterface; -class AbstractApiTest extends \PHPUnit_Framework_TestCase +class AbstractApiTest extends TestCase { /** * @test */ public function shouldPassGETRequestToClient() { - $expectedArray = array('value'); + $expectedArray = ['value']; - $httpClient = $this->getHttpMock(); + $httpClient = $this->getHttpMethodsMock(['get']); $httpClient ->expects($this->any()) ->method('get') - ->with('/path', array('param1' => 'param1value'), array('header1' => 'header1value')) - ->will($this->returnValue($expectedArray)); - $client = $this->getClientMock(); - $client->setHttpClient($httpClient); + ->with('/path?param1=param1value', ['header1' => 'header1value']) + ->will($this->returnValue($this->getPSR7Response($expectedArray))); + $client = $this->getMockBuilder(\Github\Client::class) + ->setMethods(['getHttpClient']) + ->getMock(); + $client->expects($this->any()) + ->method('getHttpClient') + ->willReturn($httpClient); $api = $this->getAbstractApiObject($client); - $this->assertEquals($expectedArray, $api->get('/path', array('param1' => 'param1value'), array('header1' => 'header1value'))); + $actual = $this->getMethod($api, 'get') + ->invokeArgs($api, ['/path', ['param1' => 'param1value'], ['header1' => 'header1value']]); + + $this->assertEquals($expectedArray, $actual); } /** @@ -33,20 +42,27 @@ public function shouldPassGETRequestToClient() */ public function shouldPassPOSTRequestToClient() { - $expectedArray = array('value'); + $expectedArray = ['value']; - $httpClient = $this->getHttpMock(); + $httpClient = $this->getHttpMethodsMock(['post']); $httpClient ->expects($this->once()) ->method('post') - ->with('/path', array('param1' => 'param1value'), array('option1' => 'option1value')) - ->will($this->returnValue($expectedArray)); - $client = $this->getClientMock(); - $client->setHttpClient($httpClient); + ->with('/path', ['option1' => 'option1value'], json_encode(['param1' => 'param1value'])) + ->will($this->returnValue($this->getPSR7Response($expectedArray))); + + $client = $this->getMockBuilder(\Github\Client::class) + ->setMethods(['getHttpClient']) + ->getMock(); + $client->expects($this->any()) + ->method('getHttpClient') + ->willReturn($httpClient); $api = $this->getAbstractApiObject($client); + $actual = $this->getMethod($api, 'post') + ->invokeArgs($api, ['/path', ['param1' => 'param1value'], ['option1' => 'option1value']]); - $this->assertEquals($expectedArray, $api->post('/path', array('param1' => 'param1value'), array('option1' => 'option1value'))); + $this->assertEquals($expectedArray, $actual); } /** @@ -54,20 +70,27 @@ public function shouldPassPOSTRequestToClient() */ public function shouldPassPATCHRequestToClient() { - $expectedArray = array('value'); + $expectedArray = ['value']; - $httpClient = $this->getHttpMock(); + $httpClient = $this->getHttpMethodsMock(['patch']); $httpClient ->expects($this->once()) ->method('patch') - ->with('/path', array('param1' => 'param1value'), array('option1' => 'option1value')) - ->will($this->returnValue($expectedArray)); - $client = $this->getClientMock(); - $client->setHttpClient($httpClient); + ->with('/path', ['option1' => 'option1value'], json_encode(['param1' => 'param1value'])) + ->will($this->returnValue($this->getPSR7Response($expectedArray))); + + $client = $this->getMockBuilder(\Github\Client::class) + ->setMethods(['getHttpClient']) + ->getMock(); + $client->expects($this->any()) + ->method('getHttpClient') + ->willReturn($httpClient); $api = $this->getAbstractApiObject($client); + $actual = $this->getMethod($api, 'patch') + ->invokeArgs($api, ['/path', ['param1' => 'param1value'], ['option1' => 'option1value']]); - $this->assertEquals($expectedArray, $api->patch('/path', array('param1' => 'param1value'), array('option1' => 'option1value'))); + $this->assertEquals($expectedArray, $actual); } /** @@ -75,20 +98,27 @@ public function shouldPassPATCHRequestToClient() */ public function shouldPassPUTRequestToClient() { - $expectedArray = array('value'); + $expectedArray = ['value']; - $httpClient = $this->getHttpMock(); + $httpClient = $this->getHttpMethodsMock(['put']); $httpClient ->expects($this->once()) ->method('put') - ->with('/path', array('param1' => 'param1value'), array('option1' => 'option1value')) - ->will($this->returnValue($expectedArray)); - $client = $this->getClientMock(); - $client->setHttpClient($httpClient); + ->with('/path', ['option1' => 'option1value'], json_encode(['param1' => 'param1value'])) + ->will($this->returnValue($this->getPSR7Response($expectedArray))); + + $client = $this->getMockBuilder('Github\Client') + ->setMethods(['getHttpClient']) + ->getMock(); + $client->expects($this->any()) + ->method('getHttpClient') + ->willReturn($httpClient); $api = $this->getAbstractApiObject($client); + $actual = $this->getMethod($api, 'put') + ->invokeArgs($api, ['/path', ['param1' => 'param1value'], ['option1' => 'option1value']]); - $this->assertEquals($expectedArray, $api->put('/path', array('param1' => 'param1value'), array('option1' => 'option1value'))); + $this->assertEquals($expectedArray, $actual); } /** @@ -96,20 +126,27 @@ public function shouldPassPUTRequestToClient() */ public function shouldPassDELETERequestToClient() { - $expectedArray = array('value'); + $expectedArray = ['value']; - $httpClient = $this->getHttpMock(); + $httpClient = $this->getHttpMethodsMock(['delete']); $httpClient ->expects($this->once()) ->method('delete') - ->with('/path', array('param1' => 'param1value'), array('option1' => 'option1value')) - ->will($this->returnValue($expectedArray)); - $client = $this->getClientMock(); - $client->setHttpClient($httpClient); + ->with('/path', ['option1' => 'option1value'], json_encode(['param1' => 'param1value'])) + ->will($this->returnValue($this->getPSR7Response($expectedArray))); + + $client = $this->getMockBuilder('Github\Client') + ->setMethods(['getHttpClient']) + ->getMock(); + $client->expects($this->any()) + ->method('getHttpClient') + ->willReturn($httpClient); $api = $this->getAbstractApiObject($client); + $actual = $this->getMethod($api, 'delete') + ->invokeArgs($api, ['/path', ['param1' => 'param1value'], ['option1' => 'option1value']]); - $this->assertEquals($expectedArray, $api->delete('/path', array('param1' => 'param1value'), array('option1' => 'option1value'))); + $this->assertEquals($expectedArray, $actual); } /** @@ -117,111 +154,86 @@ public function shouldPassDELETERequestToClient() */ public function shouldNotPassEmptyRefToClient() { - $expectedResponse = new Response('value'); + $expectedArray = ['value']; - $httpClient = $this->getHttpMock(); + $httpClient = $this->getHttpMethodsMock(['get']); $httpClient ->expects($this->any()) ->method('get') - ->with('/path', array()) - ->will($this->returnValue($expectedResponse)); - $client = $this->getClientMock(); - $client->setHttpClient($httpClient); - - $api = new ExposedAbstractApiTestInstance($client); - $api->get('/path', array('ref' => null)); - } + ->with('/path', []) + ->will($this->returnValue($this->getPSR7Response($expectedArray))); - protected function getAbstractApiObject($client) - { - return new AbstractApiTestInstance($client); - } + $client = $this->getMockBuilder(\Github\Client::class) + ->setMethods(['getHttpClient']) + ->getMock(); + $client->expects($this->any()) + ->method('getHttpClient') + ->willReturn($httpClient); - /** - * @return \Github\Client - */ - protected function getClientMock() - { - return new \Github\Client($this->getHttpMock()); - } - - /** - * @return \Github\HttpClient\HttpClientInterface - */ - protected function getHttpMock() - { - return $this->getMock('Github\HttpClient\HttpClient', array(), array(array(), $this->getHttpClientMock())); - } - - protected function getHttpClientMock() - { - $mock = $this->getMock('Guzzle\Http\Client', array('send')); - $mock - ->expects($this->any()) - ->method('send'); + $api = $this->getAbstractApiObject($client); + $actual = $this->getMethod($api, 'get')->invokeArgs($api, ['/path', ['ref' => null]]); - return $mock; + $this->assertIsArray($actual); } -} -class AbstractApiTestInstance extends AbstractApi -{ /** - * {@inheritDoc} + * @param $client + * + * @return \PHPUnit\Framework\MockObject\MockObject */ - public function get($path, array $parameters = array(), $requestHeaders = array()) + protected function getAbstractApiObject($client) { - return $this->client->getHttpClient()->get($path, $parameters, $requestHeaders); + return $this->getMockBuilder($this->getApiClass()) + ->setMethods(null) + ->setConstructorArgs([$client]) + ->getMock(); } /** - * {@inheritDoc} + * @return string */ - public function post($path, array $parameters = array(), $requestHeaders = array()) + protected function getApiClass() { - return $this->client->getHttpClient()->post($path, $parameters, $requestHeaders); + return AbstractApi::class; } /** - * {@inheritDoc} + * @return \Github\Client */ - public function postRaw($path, $body, $requestHeaders = array()) + protected function getClientMock() { - return $this->client->getHttpClient()->post($path, $body, $requestHeaders); + return new \Github\Client($this->getHttpMethodsMock()); } /** - * {@inheritDoc} + * Return a HttpMethods client mock. + * + * @param array $methods + * + * @return \Http\Client\Common\HttpMethodsClientInterface */ - public function patch($path, array $parameters = array(), $requestHeaders = array()) + protected function getHttpMethodsMock(array $methods = []) { - return $this->client->getHttpClient()->patch($path, $parameters, $requestHeaders); - } + $mock = $this->createMock(HttpMethodsClientInterface::class); - /** - * {@inheritDoc} - */ - public function put($path, array $parameters = array(), $requestHeaders = array()) - { - return $this->client->getHttpClient()->put($path, $parameters, $requestHeaders); - } + $mock + ->expects($this->any()) + ->method('sendRequest'); - /** - * {@inheritDoc} - */ - public function delete($path, array $parameters = array(), $requestHeaders = array()) - { - return $this->client->getHttpClient()->delete($path, $parameters, $requestHeaders); + return $mock; } -} -class ExposedAbstractApiTestInstance extends AbstractApi -{ /** - * {@inheritDoc} + * @param $expectedArray + * + * @return Response */ - public function get($path, array $parameters = array(), $requestHeaders = array()) + private function getPSR7Response($expectedArray) { - return parent::get($path, $parameters, $requestHeaders); + return new Response( + 200, + ['Content-Type' => 'application/json'], + Utils::streamFor(json_encode($expectedArray)) + ); } } diff --git a/test/Github/Tests/Api/App/HookTest.php b/test/Github/Tests/Api/App/HookTest.php new file mode 100644 index 00000000000..f2ed6ae5ab4 --- /dev/null +++ b/test/Github/Tests/Api/App/HookTest.php @@ -0,0 +1,109 @@ + 'json', + 'insecure_ssl' => 0, + 'secret' => '********', + 'url' => 'https://localhost/', + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/app/hook/config', []) + ->willReturn($result); + + $this->assertEquals($result, $api->showConfig()); + } + + /** + * @test + */ + public function shouldUpdateHookConfiguration() + { + $parameters = [ + 'content_type' => 'json', + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('patch') + ->with('/app/hook/config', $parameters) + ->willReturn([]); + + $this->assertEquals([], $api->updateConfig($parameters)); + } + + /** + * @test + */ + public function shouldListHookDelivieries() + { + $result = []; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/app/hook/deliveries', []) + ->willReturn($result); + + $this->assertEquals($result, $api->deliveries()); + } + + /** + * @test + */ + public function shouldListHookDeliviery() + { + $result = []; + + $delivery = 1234567; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/app/hook/deliveries/'.$delivery, []) + ->willReturn($result); + + $this->assertEquals($result, $api->delivery($delivery)); + } + + /** + * @test + */ + public function shouldRedeliveryHook() + { + $result = []; + + $delivery = 1234567; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/app/hook/deliveries/'.$delivery.'/attempts', []) + ->willReturn($result); + + $this->assertEquals($result, $api->redeliver($delivery)); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\App\Hook::class; + } +} diff --git a/test/Github/Tests/Api/AppTest.php b/test/Github/Tests/Api/AppTest.php new file mode 100644 index 00000000000..b813a11dd1f --- /dev/null +++ b/test/Github/Tests/Api/AppTest.php @@ -0,0 +1,187 @@ + 'v1.1f699f1069f60xxx', + 'expires_at' => '2016-07-11T22:14:10Z', + ]; + $installationId = 'installation1'; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/app/installations/'.$installationId.'/access_tokens', []) + ->willReturn($result); + + $this->assertEquals($result, $api->createInstallationToken($installationId)); + } + + /** + * @test + */ + public function shouldFindInstallationsForApplication() + { + $result = ['installation1', 'installation2']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/app/installations') + ->willReturn($result); + + $this->assertEquals($result, $api->findInstallations()); + } + + /** + * @test + */ + public function shouldGetInstallationForApplication() + { + $result = ['installation1']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/app/installations/1234') + ->willReturn($result); + + $this->assertEquals($result, $api->getInstallation('1234')); + } + + /** + * @test + */ + public function shouldGetInstallationForOrganization() + { + $result = ['installation1']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/orgs/1234/installation') + ->willReturn($result); + + $this->assertEquals($result, $api->getInstallationForOrganization('1234')); + } + + /** + * @test + */ + public function shouldGetInstallationForRepo() + { + $result = ['installation1']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/MyOrg/MyRepo/installation') + ->willReturn($result); + + $this->assertEquals($result, $api->getInstallationForRepo('MyOrg', 'MyRepo')); + } + + /** + * @test + */ + public function shouldGetInstallationForUser() + { + $result = ['installation1']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/users/octocat/installation') + ->willReturn($result); + + $this->assertEquals($result, $api->getInstallationForUser('octocat')); + } + + /** + * @test + */ + public function shouldDeleteInstallationForApplication() + { + $id = 123; + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/app/installations/'.$id); + + $api->removeInstallation($id); + } + + /** + * @test + */ + public function shouldGetRepositoriesFromInstallation() + { + $result = ['repo1', 'repo2']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/installation/repositories', ['user_id' => '1234']) + ->willReturn($result); + + $this->assertEquals($result, $api->listRepositories('1234')); + } + + /** + * @test + */ + public function shouldAddRepositoryToInstallation() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/installations/1234/repositories/5678'); + + $api->addRepository('1234', '5678'); + } + + /** + * @test + */ + public function shouldRemoveRepositoryToInstallation() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/installations/1234/repositories/5678'); + + $api->removeRepository('1234', '5678'); + } + + /** + * @test + */ + public function shouldGetAuthenticatedApp() + { + $api = $this->getApiMock(); + + $result = ['authenticatedApp1']; + + $api->expects($this->once()) + ->method('get') + ->with('/app') + ->willReturn($result); + + $this->assertEquals($result, $api->getAuthenticatedApp()); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Apps::class; + } +} diff --git a/test/Github/Tests/Api/AuthorizationsTest.php b/test/Github/Tests/Api/AuthorizationsTest.php deleted file mode 100644 index 901c5095244..00000000000 --- a/test/Github/Tests/Api/AuthorizationsTest.php +++ /dev/null @@ -1,111 +0,0 @@ - '123')); - - $api = $this->getApiMock(); - $api->expects($this->once()) - ->method('get') - ->with('authorizations') - ->will($this->returnValue($expectedArray)); - - $this->assertEquals($expectedArray, $api->all()); - } - - /** - * @test - */ - public function shouldShowAuthorization() - { - $id = 123; - $expectedArray = array('id' => $id); - - $api = $this->getApiMock(); - $api->expects($this->once()) - ->method('get') - ->with('authorizations/'.$id) - ->will($this->returnValue($expectedArray)); - - $this->assertEquals($expectedArray, $api->show($id)); - } - - /** - * @test - */ - public function shouldCheckAuthorization() - { - $id = 123; - $token = 'abc'; - $expectedArray = array('id' => $id); - - $api = $this->getApiMock(); - $api->expects($this->once()) - ->method('get') - ->with('authorizations/'.$id.'/tokens/'.$token) - ->will($this->returnValue($expectedArray)); - - $this->assertEquals($expectedArray, $api->check($id, $token)); - } - - /** - * @test - */ - public function shouldAuthorization() - { - $input = array( - 'note' => '', - ); - - $api = $this->getApiMock(); - $api->expects($this->once()) - ->method('post') - ->with('authorizations', $input); - - $api->create($input); - } - - /** - * @test - */ - public function shouldUpdateAuthorization() - { - $id = 123; - $input = array( - 'note' => '', - ); - - $api = $this->getApiMock(); - $api->expects($this->once()) - ->method('patch') - ->with('authorizations/'.$id, $input); - - $api->update($id, $input); - } - - /** - * @test - */ - public function shouldDeleteAuthorization() - { - $id = 123; - $api = $this->getApiMock(); - $api->expects($this->once()) - ->method('delete') - ->with('authorizations/'.$id); - - $api->remove($id); - } - - protected function getApiClass() - { - return 'Github\Api\Authorizations'; - } -} diff --git a/test/Github/Tests/Api/Copilot/UsageTest.php b/test/Github/Tests/Api/Copilot/UsageTest.php new file mode 100644 index 00000000000..c14c3e3ffa8 --- /dev/null +++ b/test/Github/Tests/Api/Copilot/UsageTest.php @@ -0,0 +1,78 @@ +getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/copilot/usage', []) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->orgUsageSummary('KnpLabs')); + } + + /** + * @test + */ + public function shouldGetOrgTeamUsageSummary(): void + { + $expectedValue = ['usage1', 'usage2']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/team/php-github-api/copilot/usage', []) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->orgTeamUsageSummary('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldGetEnterpriseUsageSummary(): void + { + $expectedValue = ['usage1', 'usage2']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/enterprises/KnpLabs/copilot/usage', []) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->enterpriseUsageSummary('KnpLabs')); + } + + /** + * @test + */ + public function shouldGetEnterpriseTeamUsageSummary(): void + { + $expectedValue = ['usage1', 'usage2']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/enterprises/KnpLabs/team/php-github-api/copilot/usage', []) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->enterpriseTeamUsageSummary('KnpLabs', 'php-github-api')); + } + + protected function getApiClass(): string + { + return Usage::class; + } +} diff --git a/test/Github/Tests/Api/CurrentUser/DeployKeysTest.php b/test/Github/Tests/Api/CurrentUser/DeployKeysTest.php index 4075e44040b..4f147e25e02 100644 --- a/test/Github/Tests/Api/CurrentUser/DeployKeysTest.php +++ b/test/Github/Tests/Api/CurrentUser/DeployKeysTest.php @@ -1,7 +1,8 @@ '12', 'key' => 'ssh-rsa ...'); + $expectedValue = ['id' => '12', 'key' => 'ssh-rsa ...']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('user/keys/12') + ->with('/user/keys/12') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show(12)); @@ -27,12 +28,12 @@ public function shouldShowKey() */ public function shouldGetKeys() { - $expectedValue = array(array('id' => '12', 'key' => 'ssh-rsa ...')); + $expectedValue = [['id' => '12', 'key' => 'ssh-rsa ...']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('user/keys') + ->with('/user/keys') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all()); @@ -43,13 +44,13 @@ public function shouldGetKeys() */ public function shouldCreateKey() { - $expectedValue = array('id' => '123', 'key' => 'ssh-rsa ...'); - $data = array('title' => 'my key', 'key' => 'ssh-rsa ...'); + $expectedValue = ['id' => '123', 'key' => 'ssh-rsa ...']; + $data = ['title' => 'my key', 'key' => 'ssh-rsa ...']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('user/keys', $data) + ->with('/user/keys', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create($data)); @@ -57,11 +58,11 @@ public function shouldCreateKey() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateKeyWithoutTitleParam() { - $data = array('key' => 'ssh-rsa ...'); + $this->expectException(MissingArgumentException::class); + $data = ['key' => 'ssh-rsa ...']; $api = $this->getApiMock(); $api->expects($this->never()) @@ -72,11 +73,11 @@ public function shouldNotCreateKeyWithoutTitleParam() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateKeyWithoutKeyParam() { - $data = array('title' => 'my key'); + $this->expectException(MissingArgumentException::class); + $data = ['title' => 'my key']; $api = $this->getApiMock(); $api->expects($this->never()) @@ -85,71 +86,27 @@ public function shouldNotCreateKeyWithoutKeyParam() $api->create($data); } - /** - * @test - */ - public function shouldUpdateKey() - { - $expectedValue = array('id' => '123', 'key' => 'ssh-rsa ...'); - $data = array('title' => 'my key', 'key' => 'ssh-rsa ...'); - - $api = $this->getApiMock(); - $api->expects($this->once()) - ->method('patch') - ->with('user/keys/123', $data) - ->will($this->returnValue($expectedValue)); - - $this->assertEquals($expectedValue, $api->update(123, $data)); - } - - /** - * @test - * @expectedException Github\Exception\MissingArgumentException - */ - public function shouldNotUpdateKeyWithoutTitleParam() - { - $data = array('key' => 'ssh-rsa ...'); - - $api = $this->getApiMock(); - $api->expects($this->never()) - ->method('patch'); - - $api->update(123, $data); - } - - /** - * @test - * @expectedException Github\Exception\MissingArgumentException - */ - public function shouldNotUpdateKeyWithoutKeyParam() - { - $data = array('title' => 'my key'); - - $api = $this->getApiMock(); - $api->expects($this->never()) - ->method('patch'); - - $api->update(123, $data); - } - /** * @test */ public function shouldRemoveKey() { - $expectedValue = array('some value'); + $expectedValue = ['some value']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('user/keys/123') + ->with('/user/keys/123') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->remove(123)); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\CurrentUser\DeployKeys'; + return \Github\Api\CurrentUser\PublicKeys::class; } } diff --git a/test/Github/Tests/Api/CurrentUser/EmailsTest.php b/test/Github/Tests/Api/CurrentUser/EmailsTest.php index 9dbf81ac697..1fed2a0d780 100644 --- a/test/Github/Tests/Api/CurrentUser/EmailsTest.php +++ b/test/Github/Tests/Api/CurrentUser/EmailsTest.php @@ -1,7 +1,8 @@ getApiMock(); $api->expects($this->once()) ->method('get') - ->with('user/emails') + ->with('/user/emails') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all()); @@ -27,12 +28,12 @@ public function shouldGetEmails() */ public function shouldRemoveEmail() { - $expectedValue = array('some value'); + $expectedValue = ['some value']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('user/emails', array('email@example.com')) + ->with('/user/emails', ['email@example.com']) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->remove('email@example.com')); @@ -43,28 +44,28 @@ public function shouldRemoveEmail() */ public function shouldRemoveEmails() { - $expectedValue = array('some value'); + $expectedValue = ['some value']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('user/emails', array('email@example.com', 'email2@example.com')) + ->with('/user/emails', ['email@example.com', 'email2@example.com']) ->will($this->returnValue($expectedValue)); - $this->assertEquals($expectedValue, $api->remove(array('email@example.com', 'email2@example.com'))); + $this->assertEquals($expectedValue, $api->remove(['email@example.com', 'email2@example.com'])); } /** * @test - * @expectedException Github\Exception\InvalidArgumentException */ public function shouldNotRemoveEmailsWhenAreNotPass() { + $this->expectException(InvalidArgumentException::class); $api = $this->getApiMock(); $api->expects($this->any()) ->method('delete'); - $api->remove(array()); + $api->remove([]); } /** @@ -72,12 +73,12 @@ public function shouldNotRemoveEmailsWhenAreNotPass() */ public function shouldAddEmail() { - $expectedValue = array('some value'); + $expectedValue = ['some value']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('user/emails', array('email@example.com')) + ->with('/user/emails', ['email@example.com']) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->add('email@example.com')); @@ -88,32 +89,51 @@ public function shouldAddEmail() */ public function shouldAddEmails() { - $expectedValue = array('some value'); + $expectedValue = ['some value']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('user/emails', array('email@example.com', 'email2@example.com')) + ->with('/user/emails', ['email@example.com', 'email2@example.com']) ->will($this->returnValue($expectedValue)); - $this->assertEquals($expectedValue, $api->add(array('email@example.com', 'email2@example.com'))); + $this->assertEquals($expectedValue, $api->add(['email@example.com', 'email2@example.com'])); } /** * @test - * @expectedException Github\Exception\InvalidArgumentException */ public function shouldNotAddEmailsWhenAreNotPass() { + $this->expectException(InvalidArgumentException::class); $api = $this->getApiMock(); $api->expects($this->any()) ->method('post'); - $api->add(array()); + $api->add([]); } + /** + * @test + */ + public function shouldToggleVisibility() + { + $expectedValue = ['primary email info']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('patch') + ->with('/user/email/visibility') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->toggleVisibility()); + } + + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\CurrentUser\Emails'; + return \Github\Api\CurrentUser\Emails::class; } } diff --git a/test/Github/Tests/Api/CurrentUser/FollowersTest.php b/test/Github/Tests/Api/CurrentUser/FollowersTest.php index 9d0174fc2ea..19b4b0faab6 100644 --- a/test/Github/Tests/Api/CurrentUser/FollowersTest.php +++ b/test/Github/Tests/Api/CurrentUser/FollowersTest.php @@ -1,6 +1,6 @@ 'l3l0'), - array('login' => 'cordoval') - ); + $expectedValue = [ + ['login' => 'l3l0'], + ['login' => 'cordoval'], + ]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('user/following') + ->with('/user/following') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all()); @@ -33,7 +33,7 @@ public function shouldCheckFollower() $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('user/following/l3l0') + ->with('/user/following/l3l0') ->will($this->returnValue(null)); $this->assertNull($api->check('l3l0')); @@ -47,7 +47,7 @@ public function shouldFollowUser() $api = $this->getApiMock(); $api->expects($this->once()) ->method('put') - ->with('user/following/l3l0') + ->with('/user/following/l3l0') ->will($this->returnValue(null)); $this->assertNull($api->follow('l3l0')); @@ -61,14 +61,17 @@ public function shouldUnfollowUser() $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('user/following/l3l0') + ->with('/user/following/l3l0') ->will($this->returnValue(null)); $this->assertNull($api->unfollow('l3l0')); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\CurrentUser\Followers'; + return \Github\Api\CurrentUser\Followers::class; } } diff --git a/test/Github/Tests/Api/CurrentUser/MembershipsTest.php b/test/Github/Tests/Api/CurrentUser/MembershipsTest.php new file mode 100644 index 00000000000..aef9f374c23 --- /dev/null +++ b/test/Github/Tests/Api/CurrentUser/MembershipsTest.php @@ -0,0 +1,96 @@ + [ + 'login' => 'octocat', + 'id' => 1, + ], + 'user' => [ + 'login' => 'defunkt', + 'id' => 3, + ], + ], + [ + 'organization' => [ + 'login' => 'invitocat', + 'id' => 2, + ], + 'user' => [ + 'login' => 'defunkt', + 'id' => 3, + ], + ], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/user/memberships/orgs') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->all()); + } + + /** + * @test + */ + public function shouldGetMembershipsForOrganization() + { + $expectedValue = [ + 'organization' => [ + 'login' => 'invitocat', + 'id' => 2, + ], + 'user' => [ + 'login' => 'defunkt', + 'id' => 3, + ], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/user/memberships/orgs/invitocat') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->organization('invitocat')); + } + + /** + * @test + */ + public function shouldEditMembershipsForOrganization() + { + $expectedValue = [ + 'state' => 'active', + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('patch') + ->with('/user/memberships/orgs/invitocat') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->edit('invitocat')); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\CurrentUser\Memberships::class; + } +} diff --git a/test/Github/Tests/Api/CurrentUser/StarringTest.php b/test/Github/Tests/Api/CurrentUser/StarringTest.php new file mode 100644 index 00000000000..2210aaf2197 --- /dev/null +++ b/test/Github/Tests/Api/CurrentUser/StarringTest.php @@ -0,0 +1,77 @@ + 'l3l0/test'], + ['name' => 'cordoval/test'], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/user/starred') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->all()); + } + + /** + * @test + */ + public function shouldCheckStar() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/user/starred/l3l0/test') + ->will($this->returnValue(null)); + + $this->assertNull($api->check('l3l0', 'test')); + } + + /** + * @test + */ + public function shouldStarUser() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/user/starred/l3l0/test') + ->will($this->returnValue(null)); + + $this->assertNull($api->star('l3l0', 'test')); + } + + /** + * @test + */ + public function shouldUnstarUser() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/user/starred/l3l0/test') + ->will($this->returnValue(null)); + + $this->assertNull($api->unstar('l3l0', 'test')); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\CurrentUser\Starring::class; + } +} diff --git a/test/Github/Tests/Api/CurrentUser/WatchersTest.php b/test/Github/Tests/Api/CurrentUser/WatchersTest.php index 15e009f6a08..81491eab153 100644 --- a/test/Github/Tests/Api/CurrentUser/WatchersTest.php +++ b/test/Github/Tests/Api/CurrentUser/WatchersTest.php @@ -1,6 +1,6 @@ 'l3l0/test'), - array('name' => 'cordoval/test') - ); + $expectedValue = [ + ['name' => 'l3l0/test'], + ['name' => 'cordoval/test'], + ]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('user/watched') + ->with('/user/subscriptions') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all()); @@ -33,7 +33,7 @@ public function shouldCheckWatcher() $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('user/watched/l3l0/test') + ->with('/user/subscriptions/l3l0/test') ->will($this->returnValue(null)); $this->assertNull($api->check('l3l0', 'test')); @@ -47,7 +47,7 @@ public function shouldWatchUser() $api = $this->getApiMock(); $api->expects($this->once()) ->method('put') - ->with('user/watched/l3l0/test') + ->with('/user/subscriptions/l3l0/test') ->will($this->returnValue(null)); $this->assertNull($api->watch('l3l0', 'test')); @@ -61,14 +61,17 @@ public function shouldUnwatchUser() $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('user/watched/l3l0/test') + ->with('/user/subscriptions/l3l0/test') ->will($this->returnValue(null)); $this->assertNull($api->unwatch('l3l0', 'test')); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\CurrentUser\Watchers'; + return \Github\Api\CurrentUser\Watchers::class; } } diff --git a/test/Github/Tests/Api/CurrentUserTest.php b/test/Github/Tests/Api/CurrentUserTest.php index 36316f3c02e..5de99f5c911 100644 --- a/test/Github/Tests/Api/CurrentUserTest.php +++ b/test/Github/Tests/Api/CurrentUserTest.php @@ -9,12 +9,12 @@ class CurrentUserTest extends TestCase */ public function shouldShowCurrentUser() { - $expectedArray = array('id' => 1, 'username' => 'l3l0'); + $expectedArray = ['id' => 1, 'username' => 'l3l0']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('user') + ->with('/user') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->show()); @@ -25,15 +25,15 @@ public function shouldShowCurrentUser() */ public function shouldUpdateCurrentUserData() { - $expectedArray = array('id' => 1, 'username' => 'l3l0'); + $expectedArray = ['id' => 1, 'username' => 'l3l0']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('user', array('value' => 'toChange')) + ->with('/user', ['value' => 'toChange']) ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->update(array('value' => 'toChange'))); + $this->assertEquals($expectedArray, $api->update(['value' => 'toChange'])); } /** @@ -41,12 +41,12 @@ public function shouldUpdateCurrentUserData() */ public function shouldGetUserFollowers() { - $expectedArray = array(array('id' => 1, 'username' => 'l3l0test')); + $expectedArray = [['id' => 1, 'username' => 'l3l0test']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('user/followers', array('page' => 1)) + ->with('/user/followers', ['page' => 1]) ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->followers(1)); @@ -57,31 +57,47 @@ public function shouldGetUserFollowers() */ public function shouldGetIssuesAssignedToUser() { - $expectedArray = array(array('id' => 1, 'title' => 'issues')); + $expectedArray = [['id' => 1, 'title' => 'issues']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('issues', array('page' => 1, 'some' => 'param')) + ->with('/issues', ['page' => 1, 'some' => 'param']) ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->issues(array('some' => 'param'))); + $this->assertEquals($expectedArray, $api->issues(['some' => 'param'])); } /** * @test */ - public function shouldGetWatchedRepositories() + public function shouldGetInstallations() { - $expectedArray = array(array('id' => 1, 'name' => 'l3l0repo')); + $result = ['installation1', 'installation2']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('user/watched', array('page' => 1)) + ->with('/user/installations') + ->willReturn($result); + + $this->assertEquals($result, $api->installations()); + } + + /** + * @test + */ + public function shouldGetRepositoriesByInstallation() + { + $expectedArray = [['id' => 1, 'name' => 'l3l0repo']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/user/installations/42/repositories', ['page' => 1]) ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->watched(1)); + $this->assertEquals($expectedArray, $api->repositoriesByInstallation(42)); } /** @@ -91,7 +107,7 @@ public function shouldGetDeployKeysApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\CurrentUser\DeployKeys', $api->keys()); + $this->assertInstanceOf(\Github\Api\CurrentUser\PublicKeys::class, $api->keys()); } /** @@ -101,7 +117,7 @@ public function shouldGetEmailsApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\CurrentUser\Emails', $api->emails()); + $this->assertInstanceOf(\Github\Api\CurrentUser\Emails::class, $api->emails()); } /** @@ -111,7 +127,7 @@ public function shouldGetFollowersApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\CurrentUser\Followers', $api->follow()); + $this->assertInstanceOf(\Github\Api\CurrentUser\Followers::class, $api->follow()); } /** @@ -121,7 +137,7 @@ public function shouldGetNotificationsApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\CurrentUser\Notifications', $api->notifications()); + $this->assertInstanceOf(\Github\Api\CurrentUser\Notifications::class, $api->notifications()); } /** @@ -131,11 +147,24 @@ public function shouldGetWatchersApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\CurrentUser\Watchers', $api->watchers()); + $this->assertInstanceOf(\Github\Api\CurrentUser\Watchers::class, $api->watchers()); } + /** + * @test + */ + public function shouldGetStarredApiObject() + { + $api = $this->getApiMock(); + + $this->assertInstanceOf(\Github\Api\CurrentUser\Starring::class, $api->starring()); + } + + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\CurrentUser'; + return \Github\Api\CurrentUser::class; } } diff --git a/test/Github/Tests/Api/Deployment/EnvironmentsTest.php b/test/Github/Tests/Api/Deployment/EnvironmentsTest.php new file mode 100644 index 00000000000..ab761ab90cf --- /dev/null +++ b/test/Github/Tests/Api/Deployment/EnvironmentsTest.php @@ -0,0 +1,73 @@ +getApiMock(); + + $api->expects($this->once()) + ->method('put') + ->with('/repos/KnpLabs/php-github-api/environments/production'); + + $api->createOrUpdate('KnpLabs', 'php-github-api', 'production'); + } + + /** + * @test + */ + public function shouldGetAllEnvironments() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/environments'); + + $api->all('KnpLabs', 'php-github-api'); + } + + /** + * @test + */ + public function shouldShowEnvironment() + { + $expectedValue = 'production'; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/environments/production') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 'production')); + } + + /** + * @test + */ + public function shouldDeleteEnvironment() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/environments/production') + ->will($this->returnValue(null)); + + $this->assertNull($api->remove('KnpLabs', 'php-github-api', 'production')); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Deployment\Environments::class; + } +} diff --git a/test/Github/Tests/Api/Deployment/PoliciesTest.php b/test/Github/Tests/Api/Deployment/PoliciesTest.php new file mode 100644 index 00000000000..6b387881ce7 --- /dev/null +++ b/test/Github/Tests/Api/Deployment/PoliciesTest.php @@ -0,0 +1,91 @@ +getApiMock(); + + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/environments/production/deployment-branch-policies'); + + $api->create('KnpLabs', 'php-github-api', 'production', [ + 'name' => 'name', + ]); + } + + /** + * @test + */ + public function shouldUpdatePolicy() + { + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('put') + ->with('/repos/KnpLabs/php-github-api/environments/production/deployment-branch-policies/1'); + + $api->update('KnpLabs', 'php-github-api', 'production', 1, [ + 'name' => 'name', + ]); + } + + /** + * @test + */ + public function shouldGetAllPolicies() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/environments/production/deployment-branch-policies'); + + $api->all('KnpLabs', 'php-github-api', 'production'); + } + + /** + * @test + */ + public function shouldShowPolicy() + { + $expectedValue = 'production'; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/environments/production/deployment-branch-policies/1') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 'production', 1)); + } + + /** + * @test + */ + public function shouldDeletePolicy() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/environments/production/deployment-branch-policies/1') + ->will($this->returnValue(null)); + + $this->assertNull($api->remove('KnpLabs', 'php-github-api', 'production', 1)); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Deployment\Policies::class; + } +} diff --git a/test/Github/Tests/Api/DeploymentTest.php b/test/Github/Tests/Api/DeploymentTest.php new file mode 100644 index 00000000000..8741ee625f7 --- /dev/null +++ b/test/Github/Tests/Api/DeploymentTest.php @@ -0,0 +1,148 @@ +getApiMock(); + $deploymentData = ['ref' => 'fd6a5f9e5a430dddae8d6a8ea378f913d3a766f9']; + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/deployments', $deploymentData); + + $api->create('KnpLabs', 'php-github-api', $deploymentData); + } + + /** + * @test + */ + public function shouldGetAllDeployments() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/deployments'); + + $api->all('KnpLabs', 'php-github-api'); + } + + /** + * @test + */ + public function shouldGetAllDeploymentsWithFilterParameters() + { + $api = $this->getApiMock(); + $filterData = ['foo' => 'bar', 'bar' => 'foo']; + + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/deployments', $filterData); + + $api->all('KnpLabs', 'php-github-api', $filterData); + } + + /** + * @test + */ + public function shouldShowDeployment() + { + $expectedValue = ['id' => 123, 'ref' => 'master']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/deployments/123') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 123)); + } + + /** + * @test + */ + public function shouldDeleteDeployment() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/deployments/123') + ->will($this->returnValue(null)); + + $this->assertNull($api->remove('KnpLabs', 'php-github-api', 123)); + } + + /** + * @test + */ + public function shouldCreateStatusUpdate() + { + $api = $this->getApiMock(); + $statusData = ['state' => 'pending', 'description' => 'waiting to start']; + + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/deployments/1/statuses', $statusData); + + $api->updateStatus('KnpLabs', 'php-github-api', 1, $statusData); + } + + /** + * @test + */ + public function shouldRejectStatusUpdateWithoutStateField() + { + $this->expectException(MissingArgumentException::class); + $api = $this->getApiMock(); + $statusData = ['description' => 'waiting to start']; + + $api->updateStatus('KnpLabs', 'php-github-api', 1, $statusData); + } + + /** + * @test + */ + public function shouldGetAllStatuses() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/deployments/1/statuses'); + + $api->getStatuses('KnpLabs', 'php-github-api', 1); + } + + /** + * @test + */ + public function shouldGetEnvironmentsApiObject() + { + $api = $this->getApiMock(); + + $this->assertInstanceOf(\Github\Api\Deployment\Environments::class, $api->environments()); + } + + /** + * @test + */ + public function shouldGetPoliciesApiObject() + { + $api = $this->getApiMock(); + + $this->assertInstanceOf(\Github\Api\Deployment\Policies::class, $api->policies()); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Deployment::class; + } +} diff --git a/test/Github/Tests/Api/Enterprise/LicenseTest.php b/test/Github/Tests/Api/Enterprise/LicenseTest.php new file mode 100644 index 00000000000..b8d988a6146 --- /dev/null +++ b/test/Github/Tests/Api/Enterprise/LicenseTest.php @@ -0,0 +1,39 @@ + 1400, + 'seats_used' => 1316, + 'seats_available' => 84, + 'kind' => 'standard', + 'days_until_expiration' => 365, + 'expire_at' => '2016/02/06 12:41:52 -0600', + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/enterprise/settings/license') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show()); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Enterprise\License::class; + } +} diff --git a/test/Github/Tests/Api/Enterprise/ManagementConsoleTest.php b/test/Github/Tests/Api/Enterprise/ManagementConsoleTest.php new file mode 100644 index 00000000000..fd1d2064f66 --- /dev/null +++ b/test/Github/Tests/Api/Enterprise/ManagementConsoleTest.php @@ -0,0 +1,117 @@ +getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/setup/api/configcheck', ['license_md5' => $this->getLicenseHash()]) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->configcheck($this->getLicenseHash())); + } + + /** + * @test + */ + public function shouldShowSettingsData() + { + $expectedJson = '{ "enterprise": { "private_mode": false, "github_hostname": "ghe.local", "auth_mode": + "default", "storage_mode": "rootfs", "admin_password": null, "configuration_id": 1401777404, + "configuration_run_count": 4, "package_version": "11.10.332", "avatar": { "enabled": false, "uri": "" }, + "customer": { "name": "GitHub", "email": "stannis@themannis.biz", "uuid": + "af6cac80-e4e1-012e-d822-1231380e52e9", + "secret_key_data": "-----BEGIN PGP PRIVATE KEY BLOCK-----\nVersion: GnuPG v1.4.10 (GNU/Linux)\n\nlQcYBE5TCgsBEACk4yHpUcapplebaumBMXYMiLF+nCQ0lxpx...\n-----END PGP PRIVATE KEY BLOCK-----\n", + "public_key_data": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v1.4.10 (GNU/Linux)\n\nmI0ETqzZYgEEALSe6snowdenXyqvLfSQ34HWD6C7....\n-----END PGP PUBLIC KEY BLOCK-----\n" }, + "license": { "seats": 0, "evaluation": false, "expire_at": "2015-04-27T00:00:00-07:00", "perpetual": false, + "unlimited_seating": true, "support_key": "ssh-rsa AAAAB3N....", "ssh_allowed": true }, "github_ssl": + { "enabled": false, "cert": null, "key": null }, "ldap": { "host": "", "port": "", "base": [ ], "uid": "", + "bind_dn": "", "password": "", "method": "Plain", "user_groups": [ ], "admin_group": "" }, "cas": { "url": "" }, + "github_oauth": { "client_id": "12313412", "client_secret": "kj123131132", "organization_name": + "Homestar Runners", "organization_team": "homestarrunners/owners" }, "smtp": { "enabled": true, "address": + "smtp.example.com", "authentication": "plain", "port": "1234", "domain": "blah", "username": "foo", "user_name": + "mr_foo", "enable_starttls_auto": true, "password": "bar", "support_address": "enterprise@github.com", + "noreply_address": "noreply@github.com" }, "dns": { "primary_nameserver": "8.8.8.8", "secondary_nameserver": + "8.8.4.4" }, "ntp": { "primary_server": "0.ubuntu.pool.ntp.org", "secondary_server": "1.ubuntu.pool.ntp.org" }, + "timezone": { "identifier": "UTC" }, "device": { "path": "/dev/xyz" }, "snmp": { "enabled": false, + "community": "" }, "rsyslog": { "enabled": false, "server": "", "protocol_name": "TCP" }, "assets": { "storage": + "file", "bucket": null, "host_name": null, "key_id": null, "access_key": null }, "pages": { "enabled": true }, + "collectd": { "enabled": false, "server": "", "port": "", "encryption": "", "username": "foo", "password": + "bar" } }, "run_list": [ "role[configure]" ] }'; + $expectedArray = json_decode($expectedJson, true); + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/setup/api/settings', ['license_md5' => $this->getLicenseHash()]) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->settings($this->getLicenseHash())); + } + + /** + * @test + */ + public function shouldShowMaintenanceStatus() + { + $expectedJson = '{ "status": "scheduled", "scheduled_time": "Tuesday, January 22 at 15 => 34 -0800", + "connection_services": [ { "name": "git operations", "number": 0 }, { "name": "mysql queries", "number": 233 }, + { "name": "resque jobs", "number": 54 } ] }'; + $expectedArray = json_decode($expectedJson, true); + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/setup/api/maintenance', ['license_md5' => $this->getLicenseHash()]) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->maintenance($this->getLicenseHash())); + } + + /** + * @test + */ + public function shouldShowAuthorizedKeys() + { + $expectedJson = '[ { "key": "ssh-rsa AAAAB3NzaC1yc2EAAAAB...", "pretty-print": + "ssh-rsa 01:14:0f:f2:0f:e2:fe:e8:f4:72:62:af:75:f7:1a:88:3e:04:92:64" }, + { "key": "ssh-rsa AAAAB3NzaC1yc2EAAAAB...", "pretty-print": + "ssh-rsa 01:14:0f:f2:0f:e2:fe:e8:f4:72:62:af:75:f7:1a:88:3e:04:92:64" } ]'; + $expectedArray = json_decode($expectedJson, true); + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/setup/api/settings/authorized-keys', ['license_md5' => $this->getLicenseHash()]) + ->will($this->returnValue($expectedArray)); + $this->assertEquals($expectedArray, $api->keys($this->getLicenseHash())); + } + + protected function getLicenseHash() + { + return '1234567890abcdefghijklmnopqrstuv'; + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Enterprise\ManagementConsole::class; + } +} diff --git a/test/Github/Tests/Api/Enterprise/SecretScanningTest.php b/test/Github/Tests/Api/Enterprise/SecretScanningTest.php new file mode 100644 index 00000000000..cc5b14b6547 --- /dev/null +++ b/test/Github/Tests/Api/Enterprise/SecretScanningTest.php @@ -0,0 +1,41 @@ + 1, 'state' => 'resolved', 'resolution' => 'false_positive'], + ['number' => 2, 'state' => 'open', 'resolution' => null], + ['number' => 3, 'state' => 'resolved', 'resolution' => 'wont_fix'], + ['number' => 4, 'state' => 'resolved', 'resolution' => 'revoked'], + ]; + + /** @var SecretScanning|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/enterprises/KnpLabs/secret-scanning/alerts') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->alerts('KnpLabs', [ + 'state' => 'all', + ])); + } + + protected function getApiClass() + { + return \Github\Api\Enterprise\SecretScanning::class; + } +} diff --git a/test/Github/Tests/Api/Enterprise/StatsTest.php b/test/Github/Tests/Api/Enterprise/StatsTest.php new file mode 100644 index 00000000000..f97060e0a14 --- /dev/null +++ b/test/Github/Tests/Api/Enterprise/StatsTest.php @@ -0,0 +1,94 @@ +getStatsData(); + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/enterprise/stats/all') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show('all')); + } + + /** + * @test + * + * @dataProvider getTypes + */ + public function shouldShowStatsByType($type) + { + $expectedArray = $this->getStatsData($type); + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with(sprintf('/enterprise/stats/%s', $type)) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, call_user_func([$api, $type])); + } + + /** + * @return array + */ + public function getTypes() + { + return [ + ['issues'], + ['hooks'], + ['milestones'], + ['orgs'], + ['comments'], + ['pages'], + ['users'], + ['gists'], + ['pulls'], + ['repos'], + ['all'], + ]; + } + + /** + * @param string $key + * + * @return mixed + */ + protected function getStatsData($key = '') + { + $json = '{"repos":{"total_repos": 212, "root_repos": 194, "fork_repos": 18, "org_repos": 51, + "total_pushes": 3082, "total_wikis": 15 }, "hooks": { "total_hooks": 27, "active_hooks": 23, + "inactive_hooks": 4 }, "pages": { "total_pages": 36 }, "orgs": { "total_orgs": 33, "disabled_orgs": 0, + "total_teams": 60, "total_team_members": 314 }, "users": { "total_users": 254, "admin_users": 45, + "suspended_users": 21 }, "pulls": { "total_pulls": 86, "merged_pulls": 60, "mergeable_pulls": 21, + "unmergeable_pulls": 3 }, "issues": { "total_issues": 179, "open_issues": 83, "closed_issues": 96 }, + "milestones": { "total_milestones": 7, "open_milestones": 6, "closed_milestones": 1 }, "gists": + { "total_gists": 178, "private_gists": 151, "public_gists": 25 }, "comments": { "total_commit_comments": 6, + "total_gist_comments": 28, "total_issue_comments": 366, "total_pull_request_comments": 30 } }'; + $stats = json_decode($json, true); + if (is_null($key)) { + return $stats; + } elseif (array_key_exists($key, $stats)) { + return $stats[$key]; + } + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Enterprise\Stats::class; + } +} diff --git a/test/Github/Tests/Api/Enterprise/UserAdminTest.php b/test/Github/Tests/Api/Enterprise/UserAdminTest.php new file mode 100644 index 00000000000..37b97a43447 --- /dev/null +++ b/test/Github/Tests/Api/Enterprise/UserAdminTest.php @@ -0,0 +1,47 @@ +getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/users/l3l0/suspended') + ->will($this->returnValue($expectedArray)); + $this->assertEquals($expectedArray, $api->suspend('l3l0')); + } + + /** + * @test + */ + public function shouldUnsuspendUser() + { + $expectedArray = []; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/users/l3l0/suspended') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->unsuspend('l3l0')); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Enterprise\UserAdmin::class; + } +} diff --git a/test/Github/Tests/Api/EnterpriseTest.php b/test/Github/Tests/Api/EnterpriseTest.php new file mode 100644 index 00000000000..eb69b8e05d0 --- /dev/null +++ b/test/Github/Tests/Api/EnterpriseTest.php @@ -0,0 +1,54 @@ +getApiMock(); + + $this->assertInstanceOf(\Github\Api\Enterprise\Stats::class, $api->stats()); + } + + /** + * @test + */ + public function shouldGetEnterpriseLicenseApiObject() + { + $api = $this->getApiMock(); + + $this->assertInstanceOf(\Github\Api\Enterprise\License::class, $api->license()); + } + + /** + * @test + */ + public function shouldGetEnterpriseManagementConsoleApiObject() + { + $api = $this->getApiMock(); + + $this->assertInstanceOf(\Github\Api\Enterprise\ManagementConsole::class, $api->console()); + } + + /** + * @test + */ + public function shouldGetEnterpriseUserAdminApiObject() + { + $api = $this->getApiMock(); + + $this->assertInstanceOf(\Github\Api\Enterprise\UserAdmin::class, $api->userAdmin()); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Enterprise::class; + } +} diff --git a/test/Github/Tests/Api/Environment/SecretsTest.php b/test/Github/Tests/Api/Environment/SecretsTest.php new file mode 100644 index 00000000000..0609a64f0f6 --- /dev/null +++ b/test/Github/Tests/Api/Environment/SecretsTest.php @@ -0,0 +1,116 @@ + 'name', 'created_at' => 'created_at', 'updated_at' => 'updated_at'], + ['name' => 'name', 'created_at' => 'created_at', 'updated_at' => 'updated_at'], + ['name' => 'name', 'created_at' => 'created_at', 'updated_at' => 'updated_at'], + ]; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repositories/3948501/environments/production/secrets') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all(3948501, 'production')); + } + + /** + * @test + */ + public function shouldGetEnvironmentSecret() + { + $expectedArray = []; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repositories/3948501/environments/production/secrets/secretName') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show(3948501, 'production', 'secretName')); + } + + /** + * @test + */ + public function shouldUpdateOrCreateEnvironmentSecret() + { + $expectedValue = 'response'; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('put') + ->with('/repositories/3948501/environments/production/secrets/secretName') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->createOrUpdate(3948501, 'production', 'secretName', [ + 'encrypted_value' => 'foo', 'key_id' => 'key_id', + ])); + } + + /** + * @test + */ + public function shouldRemoveEnvironmentSecret() + { + $expectedValue = 'response'; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('delete') + ->with('/repositories/3948501/environments/production/secrets/secretName') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->remove(3948501, 'production', 'secretName')); + } + + /** + * @test + */ + public function shouldGetPublicKey() + { + $expectedArray = ['key_id' => 'key_id', 'key' => 'foo']; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repositories/3948501/environments/production/secrets/public-key') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->publicKey(3948501, 'production')); + } + + protected function getApiClass() + { + return Secrets::class; + } +} diff --git a/test/Github/Tests/Api/Environment/VariablesTest.php b/test/Github/Tests/Api/Environment/VariablesTest.php new file mode 100644 index 00000000000..0fc01193fd1 --- /dev/null +++ b/test/Github/Tests/Api/Environment/VariablesTest.php @@ -0,0 +1,118 @@ + 'name', 'value' => 'value', 'created_at' => 'created_at', 'updated_at' => 'updated_at'], + ['name' => 'name', 'value' => 'value', 'created_at' => 'created_at', 'updated_at' => 'updated_at'], + ['name' => 'name', 'value' => 'value', 'created_at' => 'created_at', 'updated_at' => 'updated_at'], + ]; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repositories/3948501/environments/production/variables') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all(3948501, 'production')); + } + + /** + * @test + */ + public function shouldGetEnvironmentVariable() + { + $expectedArray = []; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repositories/3948501/environments/production/variables/variableName') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show(3948501, 'production', 'variableName')); + } + + /** + * @test + */ + public function shouldCreateEnvironmentVariable() + { + $expectedValue = 'response'; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('post') + ->with('/repositories/3948501/environments/production/variables') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->create(3948501, 'production', [ + 'name' => 'foo', 'value' => 'bar', + ])); + } + + /** + * @test + */ + public function shouldUpdateEnvironmentVariable() + { + $expectedValue = 'response'; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('patch') + ->with('/repositories/3948501/environments/production/variables/variableName') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->update(3948501, 'production', 'variableName', [ + 'name' => 'variableName', 'value' => 'bar', + ])); + } + + /** + * @test + */ + public function shouldRemoveEnvironmentVariable() + { + $expectedValue = 'response'; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('delete') + ->with('/repositories/3948501/environments/production/variables/variableName') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->remove(3948501, 'production', 'variableName')); + } + + protected function getApiClass() + { + return Variables::class; + } +} diff --git a/test/Github/Tests/Api/Gist/CommentsTest.php b/test/Github/Tests/Api/Gist/CommentsTest.php new file mode 100644 index 00000000000..9f0b88fda9e --- /dev/null +++ b/test/Github/Tests/Api/Gist/CommentsTest.php @@ -0,0 +1,97 @@ +getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/gists/123/comments') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->all('123')); + } + + /** + * @test + */ + public function shouldShowGistComment() + { + $expectedValue = ['comment1']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/gists/123/comments/123') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->show(123, 123)); + } + + /** + * @test + */ + public function shouldCreateGistComment() + { + $expectedValue = ['comment1data']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/gists/123/comments', ['body' => 'Test body']) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->create('123', 'Test body')); + } + + /** + * @test + */ + public function shouldUpdateGistComment() + { + $expectedValue = ['comment1data']; + $data = ['body' => 'body test']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('patch') + ->with('/gists/123/comments/233', $data) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->update(123, 233, 'body test')); + } + + /** + * @test + */ + public function shouldRemoveComment() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/gists/123/comments/233') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->remove(123, 233)); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Gist\Comments::class; + } +} diff --git a/test/Github/Tests/Api/GistsTest.php b/test/Github/Tests/Api/GistsTest.php index 1ba6a8c7386..ff4673e4082 100644 --- a/test/Github/Tests/Api/GistsTest.php +++ b/test/Github/Tests/Api/GistsTest.php @@ -2,6 +2,8 @@ namespace Github\Tests\Api; +use Github\Exception\MissingArgumentException; + class GistsTest extends TestCase { /** @@ -9,15 +11,15 @@ class GistsTest extends TestCase */ public function shouldGetStarredGists() { - $expectedArray = array(array('id' => '123')); + $expectedArray = [['id' => '123']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('gists/starred') + ->with('/gists/starred') ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->all('starred')); + $this->assertEquals($expectedArray, $api->all('starred')); } /** @@ -25,15 +27,15 @@ public function shouldGetStarredGists() */ public function shouldGetAllGists() { - $expectedArray = array(array('id' => '123')); + $expectedArray = [['id' => '123']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('gists') + ->with('/gists') ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->all()); + $this->assertEquals($expectedArray, $api->all()); } /** @@ -41,15 +43,57 @@ public function shouldGetAllGists() */ public function shouldShowGist() { - $expectedArray = array('id' => '123'); + $expectedArray = ['id' => '123']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/gists/123') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show(123)); + } + + /** + * @test + */ + public function shouldShowGistWithSpecificReference() + { + $expectedArray = ['id' => '123', 'sha' => 'd189dbd4c5d96442db74ebcb62bb38e661a0c8ce']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('gists/123') + ->with('/gists/123/d189dbd4c5d96442db74ebcb62bb38e661a0c8ce') ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->show(123)); + $this->assertEquals($expectedArray, $api->revision(123, 'd189dbd4c5d96442db74ebcb62bb38e661a0c8ce')); + } + + /** + * @test + */ + public function shouldShowCommits() + { + $expectedArray = ['id' => '123']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/gists/123/commits') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->commits(123)); + } + + /** + * @test + */ + public function shouldGetCommentsApiObject() + { + $api = $this->getApiMock(); + + $this->assertInstanceOf(\Github\Api\Gist\Comments::class, $api->comments()); } /** @@ -57,27 +101,43 @@ public function shouldShowGist() */ public function shouldForkGist() { - $expectedArray = array('id' => '123'); + $expectedArray = ['id' => '123']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('gists/123/fork') + ->with('/gists/123/fork') ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->fork(123)); + $this->assertEquals($expectedArray, $api->fork(123)); + } + + /** + * @test + */ + public function shouldListGistForks() + { + $expectedArray = ['id' => '123']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/gists/123/forks') + ->will($this->returnValue($expectedArray)); + + $api->forks(123); } /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateGistWithoutFile() { - $input = array( + $this->expectException(MissingArgumentException::class); + $input = [ 'description' => '', 'public' => false, - ); + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -91,15 +151,15 @@ public function shouldNotCreateGistWithoutFile() */ public function shouldCheckGist() { - $expectedArray = array('id' => '123'); + $expectedArray = ['id' => '123']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('gists/123/star') + ->with('/gists/123/star') ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->check(123)); + $this->assertEquals($expectedArray, $api->check(123)); } /** @@ -107,15 +167,15 @@ public function shouldCheckGist() */ public function shouldStarGist() { - $expectedArray = array('id' => '123'); + $expectedArray = ['id' => '123']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('put') - ->with('gists/123/star') + ->with('/gists/123/star') ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->star(123)); + $this->assertEquals($expectedArray, $api->star(123)); } /** @@ -123,15 +183,15 @@ public function shouldStarGist() */ public function shouldUnstarGist() { - $expectedArray = array('id' => '123'); + $expectedArray = ['id' => '123']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('gists/123/star') + ->with('/gists/123/star') ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->unstar(123)); + $this->assertEquals($expectedArray, $api->unstar(123)); } /** @@ -139,20 +199,20 @@ public function shouldUnstarGist() */ public function shouldCreateAnonymousGist() { - $input = array( + $input = [ 'description' => '', 'public' => false, - 'files' => array( - 'filename.txt' => array( - 'content' => 'content' - ) - ) - ); + 'files' => [ + 'filename.txt' => [ + 'content' => 'content', + ], + ], + ]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('gists', $input); + ->with('/gists', $input); $api->create($input); } @@ -162,23 +222,23 @@ public function shouldCreateAnonymousGist() */ public function shouldUpdateGist() { - $input = array( + $input = [ 'description' => 'jimbo', - 'files' => array( - 'filename.txt' => array( + 'files' => [ + 'filename.txt' => [ 'filename' => 'new_name.txt', - 'content' => 'content' - ), - 'filename_new.txt' => array( - 'content' => 'content new' - ) - ) - ); + 'content' => 'content', + ], + 'filename_new.txt' => [ + 'content' => 'content new', + ], + ], + ]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('gists/5', $input); + ->with('/gists/5', $input); $api->update(5, $input); } @@ -191,13 +251,16 @@ public function shouldDeleteGist() $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('gists/5'); + ->with('/gists/5'); $api->remove(5); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Gists'; + return \Github\Api\Gists::class; } } diff --git a/test/Github/Tests/Api/GitData/BlobsTest.php b/test/Github/Tests/Api/GitData/BlobsTest.php index cd9d1c8e1b3..4b87ed33e41 100644 --- a/test/Github/Tests/Api/GitData/BlobsTest.php +++ b/test/Github/Tests/Api/GitData/BlobsTest.php @@ -1,7 +1,8 @@ 'some data'); + $expectedValue = ['blob' => 'some data']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/l3l0/l3l0repo/git/blobs/123456sha') + ->with('/repos/l3l0/l3l0repo/git/blobs/123456sha') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('l3l0', 'l3l0repo', '123456sha')); @@ -27,22 +28,22 @@ public function shouldShowBlob() */ public function shouldShowRawBlob() { - $expectedValue = array('blob' => 'some data'); + $expectedValue = ['blob' => 'some data']; $client = $this->getMockBuilder('Github\Client') ->disableOriginalConstructor() ->getMock(); $api = $this->getMockBuilder($this->getApiClass()) - ->setMethods(array('configure', 'get')) - ->setConstructorArgs(array($client)) + ->setMethods(['configure', 'get']) + ->setConstructorArgs([$client]) ->getMock(); $api->expects($this->once()) ->method('configure') ->with('raw'); $api->expects($this->once()) ->method('get') - ->with('repos/l3l0/l3l0repo/git/blobs/123456sha') + ->with('/repos/l3l0/l3l0repo/git/blobs/123456sha') ->will($this->returnValue($expectedValue)); $api->configure('raw'); @@ -55,13 +56,13 @@ public function shouldShowRawBlob() */ public function shouldCreateBlob() { - $expectedValue = array('blob' => 'some data'); - $data = array('content' => 'some cotent', 'encoding' => 'utf8'); + $expectedValue = ['blob' => 'some data']; + $data = ['content' => 'some cotent', 'encoding' => 'utf8']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/l3l0/l3l0repo/git/blobs', $data) + ->with('/repos/l3l0/l3l0repo/git/blobs', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('l3l0', 'l3l0repo', $data)); @@ -69,11 +70,11 @@ public function shouldCreateBlob() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ - public function shouldNotCreateBlobWithoutEncoding() + public function shouldNotCreateBlobWithoutContent() { - $data = array('content' => 'some cotent'); + $this->expectException(MissingArgumentException::class); + $data = ['encoding' => 'utf8']; $api = $this->getApiMock(); $api->expects($this->never()) @@ -83,22 +84,10 @@ public function shouldNotCreateBlobWithoutEncoding() } /** - * @test - * @expectedException Github\Exception\MissingArgumentException + * @return string */ - public function shouldNotCreateBlobWithoutContent() - { - $data = array('encoding' => 'utf8'); - - $api = $this->getApiMock(); - $api->expects($this->never()) - ->method('post'); - - $api->create('l3l0', 'l3l0repo', $data); - } - protected function getApiClass() { - return 'Github\Api\GitData\Blobs'; + return \Github\Api\GitData\Blobs::class; } } diff --git a/test/Github/Tests/Api/GitData/CommitsTest.php b/test/Github/Tests/Api/GitData/CommitsTest.php index a665d90a495..20903f3e1f2 100644 --- a/test/Github/Tests/Api/GitData/CommitsTest.php +++ b/test/Github/Tests/Api/GitData/CommitsTest.php @@ -1,7 +1,8 @@ '123', 'comitter'); + $expectedValue = ['sha' => '123', 'comitter']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/git/commits/123') + ->with('/repos/KnpLabs/php-github-api/git/commits/123') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 123)); @@ -27,13 +28,13 @@ public function shouldShowCommitUsingSha() */ public function shouldCreateCommit() { - $expectedValue = array('sha' => '123', 'comitter'); - $data = array('message' => 'some message', 'tree' => 1234, 'parents' => array()); + $expectedValue = ['sha' => '123', 'comitter']; + $data = ['message' => 'some message', 'tree' => 1234, 'parents' => []]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/git/commits', $data) + ->with('/repos/KnpLabs/php-github-api/git/commits', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', $data)); @@ -41,11 +42,11 @@ public function shouldCreateCommit() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateCommitWithoutMessageParam() { - $data = array('tree' => 1234, 'parents' => array()); + $this->expectException(MissingArgumentException::class); + $data = ['tree' => 1234, 'parents' => []]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -56,11 +57,11 @@ public function shouldNotCreateCommitWithoutMessageParam() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateCommitWithoutTreeParam() { - $data = array('message' => 'some message', 'parents' => array()); + $this->expectException(MissingArgumentException::class); + $data = ['message' => 'some message', 'parents' => []]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -71,11 +72,11 @@ public function shouldNotCreateCommitWithoutTreeParam() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateCommitWithoutParentsParam() { - $data = array('message' => 'some message', 'tree' => '12334'); + $this->expectException(MissingArgumentException::class); + $data = ['message' => 'some message', 'tree' => '12334']; $api = $this->getApiMock(); $api->expects($this->never()) @@ -84,8 +85,11 @@ public function shouldNotCreateCommitWithoutParentsParam() $api->create('KnpLabs', 'php-github-api', $data); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\GitData\Commits'; + return \Github\Api\GitData\Commits::class; } } diff --git a/test/Github/Tests/Api/GitData/ReferencesTest.php b/test/Github/Tests/Api/GitData/ReferencesTest.php index 39d44ac7ee6..70f17cde1d8 100644 --- a/test/Github/Tests/Api/GitData/ReferencesTest.php +++ b/test/Github/Tests/Api/GitData/ReferencesTest.php @@ -1,22 +1,39 @@ 'some data']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/l3l0/l3l0repo/git/refs/master/some%2A%26%40%23branch/dasd1212') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->show('l3l0', 'l3l0repo', 'master/some*&@#branch/dasd1212')); + } + /** * @test */ public function shouldShowReference() { - $expectedValue = array('reference' => 'some data'); + $expectedValue = ['reference' => 'some data']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/l3l0/l3l0repo/git/refs/123456sha') + ->with('/repos/l3l0/l3l0repo/git/refs/123456sha') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('l3l0', 'l3l0repo', '123456sha')); @@ -27,12 +44,12 @@ public function shouldShowReference() */ public function shouldRemoveReference() { - $expectedValue = array('reference' => 'some data'); + $expectedValue = ['reference' => 'some data']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('repos/l3l0/l3l0repo/git/refs/123456sha') + ->with('/repos/l3l0/l3l0repo/git/refs/123456sha') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->remove('l3l0', 'l3l0repo', '123456sha')); @@ -43,28 +60,44 @@ public function shouldRemoveReference() */ public function shouldGetAllRepoReferences() { - $expectedValue = array(array('reference' => 'some data')); + $expectedValue = [['reference' => 'some data']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/l3l0/l3l0repo/git/refs') + ->with('/repos/l3l0/l3l0repo/git/refs') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('l3l0', 'l3l0repo')); } + /** + * @test + */ + public function shouldGetAllMatchingReferences() + { + $expectedValue = [['reference' => 'some data']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/l3l0/l3l0repo/git/matching-refs/heads/refName') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->matching('l3l0', 'l3l0repo', 'heads/refName')); + } + /** * @test */ public function shouldGetAllRepoBranches() { - $expectedValue = array(array('branch' => 'some data')); + $expectedValue = [['branch' => 'some data']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/l3l0/l3l0repo/git/refs/heads') + ->with('/repos/l3l0/l3l0repo/git/refs/heads') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->branches('l3l0', 'l3l0repo')); @@ -75,12 +108,12 @@ public function shouldGetAllRepoBranches() */ public function shouldGetAllRepoTags() { - $expectedValue = array(array('tag' => 'some data')); + $expectedValue = [['tag' => 'some data']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/l3l0/l3l0repo/git/refs/tags') + ->with('/repos/l3l0/l3l0repo/git/refs/tags') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->tags('l3l0', 'l3l0repo')); @@ -91,13 +124,13 @@ public function shouldGetAllRepoTags() */ public function shouldCreateReference() { - $expectedValue = array('reference' => 'some data'); - $data = array('ref' => '122', 'sha' => '1234'); + $expectedValue = ['reference' => 'some data']; + $data = ['ref' => '122', 'sha' => '1234']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/l3l0/l3l0repo/git/refs', $data) + ->with('/repos/l3l0/l3l0repo/git/refs', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('l3l0', 'l3l0repo', $data)); @@ -105,11 +138,11 @@ public function shouldCreateReference() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateReferenceWithoutShaParam() { - $data = array('ref' => '123'); + $this->expectException(MissingArgumentException::class); + $data = ['ref' => '123']; $api = $this->getApiMock(); $api->expects($this->never()) @@ -120,11 +153,11 @@ public function shouldNotCreateReferenceWithoutShaParam() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateReferenceWithoutRefsParam() { - $data = array('sha' => '1234'); + $this->expectException(MissingArgumentException::class); + $data = ['sha' => '1234']; $api = $this->getApiMock(); $api->expects($this->never()) @@ -138,13 +171,13 @@ public function shouldNotCreateReferenceWithoutRefsParam() */ public function shouldUpdateReference() { - $expectedValue = array('reference' => 'some data'); - $data = array('sha' => '12345sha'); + $expectedValue = ['reference' => 'some data']; + $data = ['sha' => '12345sha']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('repos/l3l0/l3l0repo/git/refs/someRefs', $data) + ->with('/repos/l3l0/l3l0repo/git/refs/someRefs', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->update('l3l0', 'l3l0repo', 'someRefs', $data)); @@ -152,11 +185,11 @@ public function shouldUpdateReference() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNoUpdateReferenceWithoutSha() { - $data = array(); + $this->expectException(MissingArgumentException::class); + $data = []; $api = $this->getApiMock(); $api->expects($this->never()) @@ -165,8 +198,11 @@ public function shouldNoUpdateReferenceWithoutSha() $api->update('l3l0', 'l3l0repo', 'someRefs', $data); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\GitData\References'; + return \Github\Api\GitData\References::class; } } diff --git a/test/Github/Tests/Api/GitData/TagsTest.php b/test/Github/Tests/Api/GitData/TagsTest.php index cd9cf8e536d..83230175554 100644 --- a/test/Github/Tests/Api/GitData/TagsTest.php +++ b/test/Github/Tests/Api/GitData/TagsTest.php @@ -1,7 +1,8 @@ '123', 'comitter'); + $expectedValue = ['sha' => '123', 'comitter']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/git/tags/123') + ->with('/repos/KnpLabs/php-github-api/git/tags/123') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 123)); @@ -27,12 +28,12 @@ public function shouldShowTagUsingSha() */ public function shouldGetAllTags() { - $expectedValue = array(array('sha' => '123', 'tagger')); + $expectedValue = [['sha' => '123', 'tagger']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/git/refs/tags') + ->with('/repos/KnpLabs/php-github-api/git/refs/tags') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api')); @@ -43,23 +44,23 @@ public function shouldGetAllTags() */ public function shouldCreateTag() { - $expectedValue = array('sha' => '123', 'comitter'); - $data = array( + $expectedValue = ['sha' => '123', 'comitter']; + $data = [ 'message' => 'some message', 'tag' => 'v2.2', 'object' => 'test', 'type' => 'unsigned', - 'tagger' => array( + 'tagger' => [ 'name' => 'l3l0', 'email' => 'leszek.prabucki@gmail.com', - 'date' => date('Y-m-d H:i:s') - ) - ); + 'date' => date('Y-m-d H:i:s'), + ], + ]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/git/tags', $data) + ->with('/repos/KnpLabs/php-github-api/git/tags', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', $data)); @@ -67,20 +68,20 @@ public function shouldCreateTag() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateTagWithoutMessageParam() { - $data = array( + $this->expectException(MissingArgumentException::class); + $data = [ 'tag' => 'v2.2', 'object' => 'test', 'type' => 'unsigned', - 'tagger' => array( + 'tagger' => [ 'name' => 'l3l0', 'email' => 'leszek.prabucki@gmail.com', - 'date' => date('Y-m-d H:i:s') - ) - ); + 'date' => date('Y-m-d H:i:s'), + ], + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -91,19 +92,18 @@ public function shouldNotCreateTagWithoutMessageParam() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ - public function shouldNotCreateTagWithoutTaggerParam() + public function shouldCreateTagWithoutTaggerParam() { - $data = array( + $data = [ 'message' => 'some message', 'tag' => 'v2.2', 'object' => 'test', 'type' => 'unsigned', - ); + ]; $api = $this->getApiMock(); - $api->expects($this->never()) + $api->expects($this->once()) ->method('post'); $api->create('KnpLabs', 'php-github-api', $data); @@ -111,20 +111,20 @@ public function shouldNotCreateTagWithoutTaggerParam() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateTagWithoutTaggerNameParam() { - $data = array( + $this->expectException(MissingArgumentException::class); + $data = [ 'message' => 'some message', 'tag' => 'v2.2', 'object' => 'test', 'type' => 'unsigned', - 'tagger' => array( + 'tagger' => [ 'email' => 'leszek.prabucki@gmail.com', - 'date' => date('Y-m-d H:i:s') - ) - ); + 'date' => date('Y-m-d H:i:s'), + ], + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -135,20 +135,20 @@ public function shouldNotCreateTagWithoutTaggerNameParam() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateTagWithoutTaggerEmailParam() { - $data = array( + $this->expectException(MissingArgumentException::class); + $data = [ 'message' => 'some message', 'tag' => 'v2.2', 'object' => 'test', 'type' => 'unsigned', - 'tagger' => array( + 'tagger' => [ 'name' => 'l3l0', - 'date' => date('Y-m-d H:i:s') - ) - ); + 'date' => date('Y-m-d H:i:s'), + ], + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -159,20 +159,20 @@ public function shouldNotCreateTagWithoutTaggerEmailParam() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateTagWithoutTaggerDateParam() { - $data = array( + $this->expectException(MissingArgumentException::class); + $data = [ 'message' => 'some message', 'tag' => 'v2.2', 'object' => 'test', 'type' => 'unsigned', - 'tagger' => array( + 'tagger' => [ 'name' => 'l3l0', 'email' => 'leszek.prabucki@gmail.com', - ) - ); + ], + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -183,20 +183,20 @@ public function shouldNotCreateTagWithoutTaggerDateParam() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateTagWithoutTagParam() { - $data = array( + $this->expectException(MissingArgumentException::class); + $data = [ 'message' => 'some message', 'object' => 'test', 'type' => 'unsigned', - 'tagger' => array( + 'tagger' => [ 'name' => 'l3l0', 'email' => 'leszek.prabucki@gmail.com', - 'date' => date('Y-m-d H:i:s') - ) - ); + 'date' => date('Y-m-d H:i:s'), + ], + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -207,20 +207,20 @@ public function shouldNotCreateTagWithoutTagParam() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateTagWithoutObjectParam() { - $data = array( + $this->expectException(MissingArgumentException::class); + $data = [ 'message' => 'some message', 'tag' => 'v2.2', 'type' => 'unsigned', - 'tagger' => array( + 'tagger' => [ 'name' => 'l3l0', 'email' => 'leszek.prabucki@gmail.com', - 'date' => date('Y-m-d H:i:s') - ) - ); + 'date' => date('Y-m-d H:i:s'), + ], + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -231,20 +231,20 @@ public function shouldNotCreateTagWithoutObjectParam() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateTagWithoutTypeParam() { - $data = array( + $this->expectException(MissingArgumentException::class); + $data = [ 'message' => 'some message', 'tag' => 'v2.2', 'object' => 'test', - 'tagger' => array( + 'tagger' => [ 'name' => 'l3l0', 'email' => 'leszek.prabucki@gmail.com', - 'date' => date('Y-m-d H:i:s') - ) - ); + 'date' => date('Y-m-d H:i:s'), + ], + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -253,8 +253,11 @@ public function shouldNotCreateTagWithoutTypeParam() $api->create('KnpLabs', 'php-github-api', $data); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\GitData\Tags'; + return \Github\Api\GitData\Tags::class; } } diff --git a/test/Github/Tests/Api/GitData/TreesTest.php b/test/Github/Tests/Api/GitData/TreesTest.php index dc4a8211b20..0b415f1fb1c 100644 --- a/test/Github/Tests/Api/GitData/TreesTest.php +++ b/test/Github/Tests/Api/GitData/TreesTest.php @@ -1,7 +1,8 @@ '123', 'comitter'); + $expectedValue = ['sha' => '123', 'comitter']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/git/trees/123', array('recursive' => null)) + ->with('/repos/KnpLabs/php-github-api/git/trees/123', []) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 123)); @@ -27,28 +28,28 @@ public function shouldShowTreeUsingSha() */ public function shouldCreateTreeUsingSha() { - $expectedValue = array('sha' => '123', 'comitter'); - $data = array( - 'tree' => array( - array( + $expectedValue = ['sha' => '123', 'comitter']; + $data = [ + 'tree' => [ + [ 'path' => 'path', 'mode' => 'mode', 'type' => 'type', - 'sha' => '1234' - ), - array( + 'sha' => '1234', + ], + [ 'path' => 'htap', 'mode' => 'edom', 'type' => 'epyt', - 'sha' => '4321' - ), - ) - ); + 'sha' => '4321', + ], + ], + ]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/git/trees', $data) + ->with('/repos/KnpLabs/php-github-api/git/trees', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', $data)); @@ -59,28 +60,28 @@ public function shouldCreateTreeUsingSha() */ public function shouldCreateTreeUsingContent() { - $expectedValue = array('sha' => '123', 'comitter'); - $data = array( - 'tree' => array( - array( + $expectedValue = ['sha' => '123', 'comitter']; + $data = [ + 'tree' => [ + [ 'path' => 'path', 'mode' => 'mode', 'type' => 'type', - 'content' => 'content' - ), - array( + 'content' => 'content', + ], + [ 'path' => 'htap', 'mode' => 'edom', 'type' => 'epyt', - 'content' => 'tnetnoc' - ), - ) - ); + 'content' => 'tnetnoc', + ], + ], + ]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/git/trees', $data) + ->with('/repos/KnpLabs/php-github-api/git/trees', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', $data)); @@ -88,17 +89,17 @@ public function shouldCreateTreeUsingContent() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateTreeWithoutShaAndContentParam() { - $data = array( - 'tree' => array( + $this->expectException(MissingArgumentException::class); + $data = [ + 'tree' => [ 'path' => 'path', 'mode' => 'mode', 'type' => 'type', - ) - ); + ], + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -109,17 +110,17 @@ public function shouldNotCreateTreeWithoutShaAndContentParam() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateTreeWithoutPathParam() { - $data = array( - 'tree' => array( + $this->expectException(MissingArgumentException::class); + $data = [ + 'tree' => [ 'mode' => 'mode', 'type' => 'type', - 'content' => 'content' - ) - ); + 'content' => 'content', + ], + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -130,17 +131,17 @@ public function shouldNotCreateTreeWithoutPathParam() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateTreeWithoutModeParam() { - $data = array( - 'tree' => array( + $this->expectException(MissingArgumentException::class); + $data = [ + 'tree' => [ 'path' => 'path', 'type' => 'type', - 'content' => 'content' - ) - ); + 'content' => 'content', + ], + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -151,17 +152,17 @@ public function shouldNotCreateTreeWithoutModeParam() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateTreeWithoutTypeParam() { - $data = array( - 'tree' => array( + $this->expectException(MissingArgumentException::class); + $data = [ + 'tree' => [ 'path' => 'path', 'mode' => 'mode', - 'content' => 'content' - ) - ); + 'content' => 'content', + ], + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -172,11 +173,11 @@ public function shouldNotCreateTreeWithoutTypeParam() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateTreeWithoutTreeParam() { - $data = array(); + $this->expectException(MissingArgumentException::class); + $data = []; $api = $this->getApiMock(); $api->expects($this->never()) @@ -187,13 +188,13 @@ public function shouldNotCreateTreeWithoutTreeParam() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateTreeWhenTreeParamIsNotArray() { - $data = array( - 'tree' => '' - ); + $this->expectException(MissingArgumentException::class); + $data = [ + 'tree' => '', + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -202,8 +203,11 @@ public function shouldNotCreateTreeWhenTreeParamIsNotArray() $api->create('KnpLabs', 'php-github-api', $data); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\GitData\Trees'; + return \Github\Api\GitData\Trees::class; } } diff --git a/test/Github/Tests/Api/GitDataTest.php b/test/Github/Tests/Api/GitDataTest.php index cdbfcc6571e..4c25936b994 100644 --- a/test/Github/Tests/Api/GitDataTest.php +++ b/test/Github/Tests/Api/GitDataTest.php @@ -11,7 +11,7 @@ public function shouldGetBlobsApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\GitData\Blobs', $api->blobs()); + $this->assertInstanceOf(\Github\Api\GitData\Blobs::class, $api->blobs()); } /** @@ -21,7 +21,7 @@ public function shouldGetCommitsApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\GitData\Commits', $api->commits()); + $this->assertInstanceOf(\Github\Api\GitData\Commits::class, $api->commits()); } /** @@ -31,7 +31,7 @@ public function shouldGetReferencesApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\GitData\References', $api->references()); + $this->assertInstanceOf(\Github\Api\GitData\References::class, $api->references()); } /** @@ -41,7 +41,7 @@ public function shouldGetTagsApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\GitData\Tags', $api->tags()); + $this->assertInstanceOf(\Github\Api\GitData\Tags::class, $api->tags()); } /** @@ -51,11 +51,14 @@ public function shouldGetTreesApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\GitData\Trees', $api->trees()); + $this->assertInstanceOf(\Github\Api\GitData\Trees::class, $api->trees()); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\GitData'; + return \Github\Api\GitData::class; } } diff --git a/test/Github/Tests/Api/GraphQLTest.php b/test/Github/Tests/Api/GraphQLTest.php new file mode 100644 index 00000000000..b241cc5ae90 --- /dev/null +++ b/test/Github/Tests/Api/GraphQLTest.php @@ -0,0 +1,58 @@ +getApiMock(); + + $api->expects($this->once()) + ->method('post') + ->with($this->equalTo('/graphql'), $this->equalTo(['query' => 'bar'])) + ->will($this->returnValue('foo')); + + $result = $api->execute('bar'); + $this->assertEquals('foo', $result); + } + + /** + * @test + */ + public function shouldSupportGraphQLVariables() + { + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('post') + ->with('/graphql', $this->arrayHasKey('variables')); + + $api->execute('bar', ['variable' => 'foo']); + } + + /** + * @test + */ + public function shouldJSONEncodeGraphQLVariables() + { + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('post') + ->with('/graphql', $this->equalTo([ + 'query' => 'bar', + 'variables' => '{"variable":"foo"}', + ])); + + $api->execute('bar', ['variable' => 'foo']); + } + + protected function getApiClass() + { + return \Github\Api\GraphQL::class; + } +} diff --git a/test/Github/Tests/Api/Issue/AssigneesTest.php b/test/Github/Tests/Api/Issue/AssigneesTest.php new file mode 100644 index 00000000000..b6939a1b59e --- /dev/null +++ b/test/Github/Tests/Api/Issue/AssigneesTest.php @@ -0,0 +1,108 @@ +getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/knplabs/php-github-api/assignees'); + + $api->listAvailable('knplabs', 'php-github-api'); + } + + /** + * @test + */ + public function shouldCheckAssignee() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/knplabs/php-github-api/assignees/test-user'); + + $api->check('knplabs', 'php-github-api', 'test-user'); + } + + /** + * @test + */ + public function shouldNotAddAssigneeMissingParameter() + { + $this->expectException(MissingArgumentException::class); + $data = []; + + $api = $this->getApiMock(); + $api->expects($this->never()) + ->method('post'); + + $api->add('knplabs', 'php-github-api', 4, $data); + } + + /** + * @test + */ + public function shouldAddAssignee() + { + $data = [ + 'assignees' => ['test-user'], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/knplabs/php-github-api/issues/4/assignees', $data); + + $api->add('knplabs', 'php-github-api', 4, $data); + } + + /** + * @test + */ + public function shouldNotRemoveAssigneeMissingParameter() + { + $this->expectException(MissingArgumentException::class); + $data = []; + + $api = $this->getApiMock(); + $api->expects($this->never()) + ->method('delete'); + + $api->remove('knplabs', 'php-github-api', 4, $data); + } + + /** + * @test + */ + public function shouldRemoveAssignee() + { + $data = [ + 'assignees' => ['test-user'], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/knplabs/php-github-api/issues/4/assignees', $data); + + $api->remove('knplabs', 'php-github-api', 4, $data); + } + + /** + * @return string + */ + protected function getApiClass() + { + return Assignees::class; + } +} diff --git a/test/Github/Tests/Api/Issue/CommentsTest.php b/test/Github/Tests/Api/Issue/CommentsTest.php index 687dc3a35f7..3a8db85a922 100644 --- a/test/Github/Tests/Api/Issue/CommentsTest.php +++ b/test/Github/Tests/Api/Issue/CommentsTest.php @@ -2,6 +2,7 @@ namespace Github\Tests\Api\Issue; +use Github\Exception\MissingArgumentException; use Github\Tests\Api\TestCase; class CommentsTest extends TestCase @@ -11,28 +12,46 @@ class CommentsTest extends TestCase */ public function shouldGetAllIssueComments() { - $expectedValue = array(array('comment1data'), array('comment2data')); + $expectedValue = [['comment1data'], ['comment2data']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/issues/123/comments', array('page' => 1)) + ->with('/repos/KnpLabs/php-github-api/issues/123/comments', []) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api', 123)); } + /** + * @test + */ + public function shouldGetAllIssueCommentsBySpecifyParameters() + { + $expectedValue = [['comment1data'], ['comment2data']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/issues/123/comments', ['since' => '1990-08-03T00:00:00Z']) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api', 123, [ + 'since' => '1990-08-03T00:00:00Z', + ])); + } + /** * @test */ public function shouldShowIssueComment() { - $expectedValue = array('comment1'); + $expectedValue = ['comment1']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/issues/comments/123') + ->with('/repos/KnpLabs/php-github-api/issues/comments/123') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 123)); @@ -40,11 +59,11 @@ public function shouldShowIssueComment() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateWithoutBody() { - $data = array(); + $this->expectException(MissingArgumentException::class); + $data = []; $api = $this->getApiMock(); $api->expects($this->never()) @@ -58,13 +77,13 @@ public function shouldNotCreateWithoutBody() */ public function shouldCreateIssueComment() { - $expectedValue = array('comment1data'); - $data = array('body' => 'test body'); + $expectedValue = ['comment1data']; + $data = ['body' => 'test body']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/issues/123/comments', $data) + ->with('/repos/KnpLabs/php-github-api/issues/123/comments', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', '123', $data)); @@ -72,11 +91,11 @@ public function shouldCreateIssueComment() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotUpdateWithoutBody() { - $data = array('somedata'); + $this->expectException(MissingArgumentException::class); + $data = ['somedata']; $api = $this->getApiMock(); $api->expects($this->never()) @@ -90,13 +109,13 @@ public function shouldNotUpdateWithoutBody() */ public function shouldUpdateIssueComment() { - $expectedValue = array('comment1data'); - $data = array('body' => 'body test'); + $expectedValue = ['comment1data']; + $data = ['body' => 'body test']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('repos/KnpLabs/php-github-api/issues/comments/233', $data) + ->with('/repos/KnpLabs/php-github-api/issues/comments/233', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->update('KnpLabs', 'php-github-api', '233', $data)); @@ -107,19 +126,22 @@ public function shouldUpdateIssueComment() */ public function shouldRemoveComment() { - $expectedValue = array('someOutput'); + $expectedValue = ['someOutput']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('repos/KnpLabs/php-github-api/issues/comments/123') + ->with('/repos/KnpLabs/php-github-api/issues/comments/123') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', 123)); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Issue\Comments'; + return \Github\Api\Issue\Comments::class; } } diff --git a/test/Github/Tests/Api/Issue/EventsTest.php b/test/Github/Tests/Api/Issue/EventsTest.php index a86aa02cfc4..37139936c63 100644 --- a/test/Github/Tests/Api/Issue/EventsTest.php +++ b/test/Github/Tests/Api/Issue/EventsTest.php @@ -11,12 +11,12 @@ class EventsTest extends TestCase */ public function shouldGetAllRepoIssuesEvents() { - $expectedValue = array(array('event1data'), array('event2data')); + $expectedValue = [['event1data'], ['event2data']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/issues/events', array('page' => 1)) + ->with('/repos/KnpLabs/php-github-api/issues/events', ['page' => 1]) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api')); @@ -27,12 +27,12 @@ public function shouldGetAllRepoIssuesEvents() */ public function shouldGetIssueEvents() { - $expectedValue = array(array('event1data'), array('event2data')); + $expectedValue = [['event1data'], ['event2data']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/issues/123/events', array('page' => 1)) + ->with('/repos/KnpLabs/php-github-api/issues/123/events', ['page' => 1]) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api', 123)); @@ -43,19 +43,22 @@ public function shouldGetIssueEvents() */ public function shouldShowIssueEvent() { - $expectedValue = array('event1'); + $expectedValue = ['event1']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/issues/events/123') + ->with('/repos/KnpLabs/php-github-api/issues/events/123') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 123)); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Issue\Events'; + return \Github\Api\Issue\Events::class; } } diff --git a/test/Github/Tests/Api/Issue/LabelsTest.php b/test/Github/Tests/Api/Issue/LabelsTest.php index 1bfa73c69ca..ec55ccc54cb 100644 --- a/test/Github/Tests/Api/Issue/LabelsTest.php +++ b/test/Github/Tests/Api/Issue/LabelsTest.php @@ -2,25 +2,25 @@ namespace Github\Tests\Api\Issue; +use Github\Exception\InvalidArgumentException; use Github\Tests\Api\TestCase; class LabelsTest extends TestCase { - /** * @test */ public function shouldGetProjectLabels() { - $expectedValue = array( - array('name' => 'l3l0repo'), - array('name' => 'other'), - ); + $expectedValue = [ + ['name' => 'l3l0repo'], + ['name' => 'other'], + ]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/labels', array()) + ->with('/repos/KnpLabs/php-github-api/labels', []) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api')); @@ -31,12 +31,12 @@ public function shouldGetProjectLabels() */ public function shouldGetAllIssueLabels() { - $expectedValue = array(array('name' => 'label')); + $expectedValue = [['name' => 'label']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/issues/123/labels') + ->with('/repos/KnpLabs/php-github-api/issues/123/labels') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api', '123')); @@ -47,46 +47,95 @@ public function shouldGetAllIssueLabels() */ public function shouldCreateLabel() { - $expectedValue = array(array('name' => 'label', 'color' => 'FFFFFF')); - $data = array('name' => 'label'); + $expectedValue = [['name' => 'label', 'color' => 'FFFFFF']]; + $data = ['name' => 'label']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/labels', $data + array('color' => 'FFFFFF')) + ->with('/repos/KnpLabs/php-github-api/labels', $data + ['color' => 'FFFFFF']) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', $data)); } + /** + * @test + */ + public function shouldGetSingleLabel() + { + $expectedValue = [['name' => 'label1']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/labels/label1') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 'label1')); + } + /** * @test */ public function shouldCreateLabelWithColor() { - $expectedValue = array(array('name' => 'label', 'color' => '111111')); - $data = array('name' => 'label', 'color' => '111111'); + $expectedValue = [['name' => 'label', 'color' => '111111']]; + $data = ['name' => 'label', 'color' => '111111']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/labels', $data) + ->with('/repos/KnpLabs/php-github-api/labels', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', $data)); } + /** + * @test + */ + public function shouldDeleteLabel() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/labels/foo') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->deleteLabel('KnpLabs', 'php-github-api', 'foo')); + } + + /** + * @test + */ + public function shouldUpdateLabel() + { + $expectedValue = [['name' => 'bar', 'color' => 'FFF']]; + $data = ['name' => 'bar', 'color' => 'FFF']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('patch') + ->with('/repos/KnpLabs/php-github-api/labels/foo', $data) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->update('KnpLabs', 'php-github-api', 'foo', 'bar', 'FFF')); + } + /** * @test */ public function shouldRemoveLabel() { - $expectedValue = array('someOutput'); + $expectedValue = ['someOutput']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('repos/KnpLabs/php-github-api/issues/123/labels/somename') + ->with('/repos/KnpLabs/php-github-api/issues/123/labels/somename') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', 123, 'somename')); @@ -97,12 +146,12 @@ public function shouldRemoveLabel() */ public function shouldAddOneLabel() { - $expectedValue = array('label' => 'somename'); + $expectedValue = ['label' => 'somename']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/issues/123/labels', array('labelname')) + ->with('/repos/KnpLabs/php-github-api/issues/123/labels', ['labelname']) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->add('KnpLabs', 'php-github-api', 123, 'labelname')); @@ -113,15 +162,15 @@ public function shouldAddOneLabel() */ public function shouldAddManyLabels() { - $expectedValue = array('label' => 'somename'); + $expectedValue = ['label' => 'somename']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/issues/123/labels', array('labelname', 'labelname2')) + ->with('/repos/KnpLabs/php-github-api/issues/123/labels', ['labelname', 'labelname2']) ->will($this->returnValue($expectedValue)); - $this->assertEquals($expectedValue, $api->add('KnpLabs', 'php-github-api', 123, array('labelname', 'labelname2'))); + $this->assertEquals($expectedValue, $api->add('KnpLabs', 'php-github-api', 123, ['labelname', 'labelname2'])); } /** @@ -129,13 +178,13 @@ public function shouldAddManyLabels() */ public function shouldReplaceLabels() { - $expectedValue = array(array('label' => 'somename')); - $data = array('labels' => array('labelname')); + $expectedValue = [['label' => 'somename']]; + $data = ['labels' => ['labelname']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('put') - ->with('repos/KnpLabs/php-github-api/issues/123/labels', $data) + ->with('/repos/KnpLabs/php-github-api/issues/123/labels', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->replace('KnpLabs', 'php-github-api', 123, $data)); @@ -143,15 +192,15 @@ public function shouldReplaceLabels() /** * @test - * @expectedException Github\Exception\InvalidArgumentException */ public function shouldNotAddWhenDoNotHaveLabelsToAdd() { + $this->expectException(InvalidArgumentException::class); $api = $this->getApiMock(); $api->expects($this->any()) ->method('post'); - $api->add('KnpLabs', 'php-github-api', 123, array()); + $api->add('KnpLabs', 'php-github-api', 123, []); } /** @@ -159,19 +208,22 @@ public function shouldNotAddWhenDoNotHaveLabelsToAdd() */ public function shouldClearLabels() { - $expectedValue = array('someOutput'); + $expectedValue = ['someOutput']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('repos/KnpLabs/php-github-api/issues/123/labels') + ->with('/repos/KnpLabs/php-github-api/issues/123/labels') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->clear('KnpLabs', 'php-github-api', 123)); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Issue\Labels'; + return \Github\Api\Issue\Labels::class; } } diff --git a/test/Github/Tests/Api/Issue/MilestonesTest.php b/test/Github/Tests/Api/Issue/MilestonesTest.php index 7ada6eff888..6a1996e0bbc 100644 --- a/test/Github/Tests/Api/Issue/MilestonesTest.php +++ b/test/Github/Tests/Api/Issue/MilestonesTest.php @@ -2,6 +2,7 @@ namespace Github\Tests\Api\Issue; +use Github\Exception\MissingArgumentException; use Github\Tests\Api\TestCase; class MilestonesTest extends TestCase @@ -11,12 +12,12 @@ class MilestonesTest extends TestCase */ public function shouldGetMilestones() { - $expectedValue = array(array('name' => 'l3l0repo')); + $expectedValue = [['name' => 'l3l0repo']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/milestones', array('page' => 1, 'state' => 'open', 'sort' => 'due_date', 'direction' => 'desc')) + ->with('/repos/KnpLabs/php-github-api/milestones', ['page' => 1, 'state' => 'open', 'sort' => 'due_date', 'direction' => 'asc']) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api')); @@ -27,13 +28,13 @@ public function shouldGetMilestones() */ public function shouldCreateMilestone() { - $expectedValue = array(array('title' => 'milestone')); - $data = array('title' => 'milestone'); + $expectedValue = [['title' => 'milestone']]; + $data = ['title' => 'milestone']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/milestones', $data) + ->with('/repos/KnpLabs/php-github-api/milestones', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', $data)); @@ -41,12 +42,12 @@ public function shouldCreateMilestone() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateMilestoneWithoutTitle() { - $expectedValue = array(array('title' => 'milestone')); - $data = array(); + $this->expectException(MissingArgumentException::class); + $expectedValue = [['title' => 'milestone']]; + $data = []; $api = $this->getApiMock(); $api->expects($this->never()) @@ -60,15 +61,15 @@ public function shouldNotCreateMilestoneWithoutTitle() */ public function shouldSetStateToOpenWhileCreationWhenStateParamNotRecognized() { - $expectedValue = array('title' => 'l3l0repo'); + $expectedValue = ['title' => 'l3l0repo']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/milestones', array('state' => 'open', 'title' => 'milestone')) + ->with('/repos/KnpLabs/php-github-api/milestones', ['state' => 'open', 'title' => 'milestone']) ->will($this->returnValue($expectedValue)); - $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', array('state' => 'clos', 'title' => 'milestone'))); + $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', ['state' => 'clos', 'title' => 'milestone'])); } /** @@ -76,13 +77,13 @@ public function shouldSetStateToOpenWhileCreationWhenStateParamNotRecognized() */ public function shouldUpdateMilestone() { - $expectedValue = array(array('title' => 'milestone')); - $data = array('title' => 'milestone'); + $expectedValue = [['title' => 'milestone']]; + $data = ['title' => 'milestone']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('repos/KnpLabs/php-github-api/milestones/123', array('title' => 'milestone')) + ->with('/repos/KnpLabs/php-github-api/milestones/123', ['title' => 'milestone']) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->update('KnpLabs', 'php-github-api', 123, $data)); @@ -93,13 +94,13 @@ public function shouldUpdateMilestone() */ public function shouldUpdateMilestoneWithClosedStatus() { - $expectedValue = array(array('title' => 'milestone')); - $data = array('title' => 'milestone', 'status' => 'closed'); + $expectedValue = [['title' => 'milestone']]; + $data = ['title' => 'milestone', 'status' => 'closed']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('repos/KnpLabs/php-github-api/milestones/123', $data) + ->with('/repos/KnpLabs/php-github-api/milestones/123', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->update('KnpLabs', 'php-github-api', 123, $data)); @@ -110,13 +111,13 @@ public function shouldUpdateMilestoneWithClosedStatus() */ public function shouldSetStateToOpenWhileUpdateWhenStateParamNotRecognized() { - $expectedValue = array('title' => 'l3l0repo'); - $data = array('title' => 'milestone', 'state' => 'some'); + $expectedValue = ['title' => 'l3l0repo']; + $data = ['title' => 'milestone', 'state' => 'some']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('repos/KnpLabs/php-github-api/milestones/123', array('state' => 'open', 'title' => 'milestone')) + ->with('/repos/KnpLabs/php-github-api/milestones/123', ['state' => 'open', 'title' => 'milestone']) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->update('KnpLabs', 'php-github-api', 123, $data)); @@ -127,15 +128,15 @@ public function shouldSetStateToOpenWhileUpdateWhenStateParamNotRecognized() */ public function shouldSortByDueDateWhenSortParamNotRecognized() { - $expectedValue = array(array('name' => 'l3l0repo')); + $expectedValue = [['name' => 'l3l0repo']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/milestones', array('page' => 1, 'state' => 'open', 'sort' => 'due_date', 'direction' => 'desc')) + ->with('/repos/KnpLabs/php-github-api/milestones', ['page' => 1, 'state' => 'open', 'sort' => 'due_date', 'direction' => 'asc']) ->will($this->returnValue($expectedValue)); - $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api', array('sort' => 'completenes'))); + $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api', ['sort' => 'completenes'])); } /** @@ -143,15 +144,15 @@ public function shouldSortByDueDateWhenSortParamNotRecognized() */ public function shouldSetStateToOpenWhenStateParamNotRecognized() { - $expectedValue = array(array('name' => 'l3l0repo')); + $expectedValue = [['name' => 'l3l0repo']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/milestones', array('page' => 1, 'state' => 'open', 'sort' => 'due_date', 'direction' => 'desc')) + ->with('/repos/KnpLabs/php-github-api/milestones', ['page' => 1, 'state' => 'open', 'sort' => 'due_date', 'direction' => 'asc']) ->will($this->returnValue($expectedValue)); - $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api', array('state' => 'clos'))); + $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api', ['state' => 'clos'])); } /** @@ -159,15 +160,15 @@ public function shouldSetStateToOpenWhenStateParamNotRecognized() */ public function shouldSetDirectionToDescWhenDirectionParamNotRecognized() { - $expectedValue = array(array('name' => 'l3l0repo')); + $expectedValue = [['name' => 'l3l0repo']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/milestones', array('page' => 1, 'state' => 'open', 'sort' => 'due_date', 'direction' => 'desc')) + ->with('/repos/KnpLabs/php-github-api/milestones', ['page' => 1, 'state' => 'open', 'sort' => 'due_date', 'direction' => 'asc']) ->will($this->returnValue($expectedValue)); - $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api', array('direction' => 'des'))); + $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api', ['direction' => 'asc'])); } /** @@ -175,12 +176,12 @@ public function shouldSetDirectionToDescWhenDirectionParamNotRecognized() */ public function shouldRemoveMilestones() { - $expectedValue = array('someOutput'); + $expectedValue = ['someOutput']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('repos/KnpLabs/php-github-api/milestones/123') + ->with('/repos/KnpLabs/php-github-api/milestones/123') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', 123)); @@ -191,12 +192,12 @@ public function shouldRemoveMilestones() */ public function shouldShowMilestone() { - $expectedValue = array('someOutput'); + $expectedValue = ['someOutput']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/milestones/123') + ->with('/repos/KnpLabs/php-github-api/milestones/123') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 123)); @@ -207,19 +208,22 @@ public function shouldShowMilestone() */ public function shouldGetMilestoneLabels() { - $expectedValue = array(array('label'), array('label2')); + $expectedValue = [['label'], ['label2']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/milestones/123/labels') + ->with('/repos/KnpLabs/php-github-api/milestones/123/labels') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->labels('KnpLabs', 'php-github-api', 123)); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Issue\Milestones'; + return \Github\Api\Issue\Milestones::class; } } diff --git a/test/Github/Tests/Api/Issue/TimelineTest.php b/test/Github/Tests/Api/Issue/TimelineTest.php new file mode 100644 index 00000000000..401219af32b --- /dev/null +++ b/test/Github/Tests/Api/Issue/TimelineTest.php @@ -0,0 +1,35 @@ +getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/issues/123/timeline', []) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api', 123)); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Issue\Timeline::class; + } +} diff --git a/test/Github/Tests/Api/IssueTest.php b/test/Github/Tests/Api/IssueTest.php index cdd7ba7f3b1..a151076ce1f 100644 --- a/test/Github/Tests/Api/IssueTest.php +++ b/test/Github/Tests/Api/IssueTest.php @@ -2,6 +2,8 @@ namespace Github\Tests\Api; +use Github\Exception\MissingArgumentException; + class IssueTest extends TestCase { /** @@ -9,17 +11,17 @@ class IssueTest extends TestCase */ public function shouldGetIssues() { - $data = array( - 'state' => 'open' - ); - $sentData = $data + array( - 'page' => 1 - ); + $data = [ + 'state' => 'open', + ]; + $sentData = $data + [ + 'page' => 1, + ]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/ornicar/php-github-api/issues', $sentData); + ->with('/repos/ornicar/php-github-api/issues', $sentData); $api->all('ornicar', 'php-github-api', $data); } @@ -29,24 +31,24 @@ public function shouldGetIssues() */ public function shouldGetIssuesUsingAdditionalParameters() { - $expectedArray = array(array('id' => '123')); - $data = array( + $expectedArray = [['id' => '123']]; + $data = [ 'state' => 'open', 'milestone' => '*', - 'assignee' => 'l3l0', + 'assignee' => 'l3l0', 'mentioned' => 'l3l0', - 'labels' => 'bug,@high', - 'sort' => 'created', - 'direction' => 'asc' - ); - $sentData = $data + array( - 'page' => 1 - ); + 'labels' => 'bug,@high', + 'sort' => 'created', + 'direction' => 'asc', + ]; + $sentData = $data + [ + 'page' => 1, + ]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/ornicar/php-github-api/issues', $sentData) + ->with('/repos/ornicar/php-github-api/issues', $sentData) ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->all('ornicar', 'php-github-api', $data)); @@ -57,12 +59,12 @@ public function shouldGetIssuesUsingAdditionalParameters() */ public function shouldShowIssue() { - $expectedArray = array('id' => '123'); + $expectedArray = ['id' => '123']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/ornicar/php-github-api/issues/14') + ->with('/repos/ornicar/php-github-api/issues/14') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->show('ornicar', 'php-github-api', 14)); @@ -73,28 +75,28 @@ public function shouldShowIssue() */ public function shouldCreateIssue() { - $data = array( + $data = [ 'title' => 'some title', - 'body' => 'some body' - ); + 'body' => 'some body', + ]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/ornicar/php-github-api/issues', $data); + ->with('/repos/ornicar/php-github-api/issues', $data); $api->create('ornicar', 'php-github-api', $data); } /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateIssueWithoutTitle() { - $data = array( - 'body' => 'some body' - ); + $this->expectException(MissingArgumentException::class); + $data = [ + 'body' => 'some body', + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -105,17 +107,17 @@ public function shouldNotCreateIssueWithoutTitle() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ - public function shouldNotCreateIssueWithoutBody() + public function shouldCreateIssueWithoutBody() { - $data = array( - 'title' => 'some title' - ); + $data = [ + 'title' => 'some title', + ]; $api = $this->getApiMock(); - $api->expects($this->never()) - ->method('post'); + $api->expects($this->once()) + ->method('post') + ->with('/repos/ornicar/php-github-api/issues', $data); $api->create('ornicar', 'php-github-api', $data); } @@ -125,14 +127,14 @@ public function shouldNotCreateIssueWithoutBody() */ public function shouldCloseIssue() { - $data = array( + $data = [ 'state' => 'closed', - ); + ]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('repos/ornicar/php-github-api/issues/14', $data); + ->with('/repos/ornicar/php-github-api/issues/14', $data); $api->update('ornicar', 'php-github-api', 14, $data); } @@ -142,14 +144,14 @@ public function shouldCloseIssue() */ public function shouldReOpenIssue() { - $data = array( + $data = [ 'state' => 'open', - ); + ]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('repos/ornicar/php-github-api/issues/14', $data); + ->with('/repos/ornicar/php-github-api/issues/14', $data); $api->update('ornicar', 'php-github-api', 14, $data); } @@ -157,93 +159,88 @@ public function shouldReOpenIssue() /** * @test */ - public function shouldSearchOpenIssues() + public function shouldGetCommentsApiObject() { - $expectedArray = array(array('id' => '123')); - $api = $this->getApiMock(); - $api->expects($this->once()) - ->method('get') - ->with('legacy/issues/search/KnpLabs/php-github-api/open/Invalid%20Commits') - ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->find('KnpLabs', 'php-github-api', 'open', 'Invalid Commits')); + $this->assertInstanceOf(\Github\Api\Issue\Comments::class, $api->comments()); } /** * @test */ - public function shouldSearchClosedIssues() + public function shouldGetEventsApiObject() { - $expectedArray = array(array('id' => '123')); - $api = $this->getApiMock(); - $api->expects($this->once()) - ->method('get') - ->with('legacy/issues/search/KnpLabs/php-github-api/closed/Invalid%20Commits') - ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->find('KnpLabs', 'php-github-api', 'closed', 'Invalid Commits')); + $this->assertInstanceOf(\Github\Api\Issue\Events::class, $api->events()); } /** * @test */ - public function shouldSearchOpenIssuesWhenStateNotRecognized() + public function shouldGetLabelsApiObject() { - $expectedArray = array(array('id' => '123')); - $api = $this->getApiMock(); - $api->expects($this->once()) - ->method('get') - ->with('legacy/issues/search/KnpLabs/php-github-api/open/Invalid%20Commits') - ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->find('KnpLabs', 'php-github-api', 'abc', 'Invalid Commits')); + $this->assertInstanceOf(\Github\Api\Issue\Labels::class, $api->labels()); } /** * @test */ - public function shouldGetCommentsApiObject() + public function shouldGetMilestonesApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\Issue\Comments', $api->comments()); + $this->assertInstanceOf(\Github\Api\Issue\Milestones::class, $api->milestones()); } /** * @test */ - public function shouldGetEventsApiObject() + public function shouldGetTimelineApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\Issue\Events', $api->events()); + $this->assertInstanceOf(\Github\Api\Issue\Timeline::class, $api->timeline()); } /** * @test */ - public function shouldGetLabelsApiObject() + public function shouldLockIssue() { + $parameters = []; + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/repos/knplabs/php-github-api/issues/1/lock', $parameters); - $this->assertInstanceOf('Github\Api\Issue\Labels', $api->labels()); + $api->lock('knplabs', 'php-github-api', '1'); } /** * @test */ - public function shouldGetMilestonesApiObject() + public function shouldUnlockIssue() { + $parameters = []; + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/knplabs/php-github-api/issues/1/lock', $parameters); - $this->assertInstanceOf('Github\Api\Issue\Milestones', $api->milestones()); + $api->unlock('knplabs', 'php-github-api', '1'); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Issue'; + return \Github\Api\Issue::class; } } diff --git a/test/Github/Tests/Api/MetaTest.php b/test/Github/Tests/Api/MetaTest.php new file mode 100644 index 00000000000..9275e5a1f1b --- /dev/null +++ b/test/Github/Tests/Api/MetaTest.php @@ -0,0 +1,37 @@ + [ + '127.0.0.1/32', + ], + 'git' => [ + '127.0.0.1/32', + ], + 'verifiable_password_authentication' => true, + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->service()); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Meta::class; + } +} diff --git a/test/Github/Tests/Api/Miscellaneous/CodeOfConductTest.php b/test/Github/Tests/Api/Miscellaneous/CodeOfConductTest.php new file mode 100644 index 00000000000..0e07dea5752 --- /dev/null +++ b/test/Github/Tests/Api/Miscellaneous/CodeOfConductTest.php @@ -0,0 +1,54 @@ + 'CoC1'], + ['name' => 'CoC2'], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/codes_of_conduct') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all()); + } + + /** + * @test + */ + public function shouldGetSingleCodeOfConducts() + { + $expectedArray = [ + 'name' => 'CoC', + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/codes_of_conduct/contributor_covenant') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show('contributor_covenant')); + } + + /** + * @return string + */ + protected function getApiClass() + { + return CodeOfConduct::class; + } +} diff --git a/test/Github/Tests/Api/Miscellaneous/EmojisTest.php b/test/Github/Tests/Api/Miscellaneous/EmojisTest.php new file mode 100644 index 00000000000..b4408b80aa1 --- /dev/null +++ b/test/Github/Tests/Api/Miscellaneous/EmojisTest.php @@ -0,0 +1,36 @@ + 'https://github.global.ssl.fastly.net/images/icons/emoji/+1.png?v5', + '-1' => 'https://github.global.ssl.fastly.net/images/icons/emoji/-1.png?v5', + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/emojis') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all()); + } + + /** + * @return string + */ + protected function getApiClass() + { + return Emojis::class; + } +} diff --git a/test/Github/Tests/Api/Miscellaneous/GitignoreTest.php b/test/Github/Tests/Api/Miscellaneous/GitignoreTest.php new file mode 100644 index 00000000000..6a244adaef5 --- /dev/null +++ b/test/Github/Tests/Api/Miscellaneous/GitignoreTest.php @@ -0,0 +1,60 @@ +getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/gitignore/templates') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all()); + } + + /** + * @test + */ + public function shouldGetTemplate() + { + $expectedArray = [ + 'name' => 'C', + 'source' => "# Object files\n*.o\n\n# Libraries\n*.lib\n*.a", + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/gitignore/templates/C') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show('C')); + } + + /** + * @return string + */ + protected function getApiClass() + { + return Gitignore::class; + } +} diff --git a/test/Github/Tests/Api/Miscellaneous/LicensesTest.php b/test/Github/Tests/Api/Miscellaneous/LicensesTest.php new file mode 100644 index 00000000000..ed504c9b4aa --- /dev/null +++ b/test/Github/Tests/Api/Miscellaneous/LicensesTest.php @@ -0,0 +1,54 @@ + 'mit'], + ['key' => 'apache-2.0'], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/licenses') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all()); + } + + /** + * @test + */ + public function shouldGetSingleLicenses() + { + $expectedArray = [ + 'key' => 'gpl-2.0', + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/licenses/gpl-2.0') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show('gpl-2.0')); + } + + /** + * @return string + */ + protected function getApiClass() + { + return Licenses::class; + } +} diff --git a/test/Github/Tests/Api/MarkdownTest.php b/test/Github/Tests/Api/Miscellaneous/MarkdownTest.php similarity index 62% rename from test/Github/Tests/Api/MarkdownTest.php rename to test/Github/Tests/Api/Miscellaneous/MarkdownTest.php index 6208a4b84e5..b327a1b83c8 100644 --- a/test/Github/Tests/Api/MarkdownTest.php +++ b/test/Github/Tests/Api/Miscellaneous/MarkdownTest.php @@ -1,6 +1,8 @@ getApiMock(); $api->expects($this->once()) ->method('post') - ->with('markdown', array('text' => $input, 'mode' => 'markdown')); + ->with('/markdown', ['text' => $input, 'mode' => 'markdown']); $api->render($input); } @@ -24,12 +26,12 @@ public function shouldRenderMarkdown() */ public function shouldRenderMarkdownUsingGfmMode() { - $input = 'Hello world github/linguist#1 **cool**, and #1!'; + $input = 'Hello world github/linguist#1 **cool**, and #1!'; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('markdown', array('text' => $input, 'mode' => 'gfm')); + ->with('/markdown', ['text' => $input, 'mode' => 'gfm']); $api->render($input, 'gfm'); } @@ -39,12 +41,12 @@ public function shouldRenderMarkdownUsingGfmMode() */ public function shouldSetModeToMarkdownWhenIsNotRecognized() { - $input = 'Hello world github/linguist#1 **cool**, and #1!'; + $input = 'Hello world github/linguist#1 **cool**, and #1!'; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('markdown', array('text' => $input, 'mode' => 'markdown')); + ->with('/markdown', ['text' => $input, 'mode' => 'markdown']); $api->render($input, 'abc'); } @@ -54,17 +56,17 @@ public function shouldSetModeToMarkdownWhenIsNotRecognized() */ public function shouldSetContextOnlyForGfmMode() { - $input = 'Hello world github/linguist#1 **cool**, and #1!'; + $input = 'Hello world github/linguist#1 **cool**, and #1!'; $apiWithMarkdown = $this->getApiMock(); $apiWithMarkdown->expects($this->once()) ->method('post') - ->with('markdown', array('text' => $input, 'mode' => 'markdown')); + ->with('/markdown', ['text' => $input, 'mode' => 'markdown']); $apiWithGfm = $this->getApiMock(); $apiWithGfm->expects($this->once()) ->method('post') - ->with('markdown', array('text' => $input, 'mode' => 'gfm', 'context' => 'someContext')); + ->with('/markdown', ['text' => $input, 'mode' => 'gfm', 'context' => 'someContext']); $apiWithMarkdown->render($input, 'markdown', 'someContext'); $apiWithGfm->render($input, 'gfm', 'someContext'); @@ -75,18 +77,21 @@ public function shouldSetContextOnlyForGfmMode() */ public function shouldRenderRawFile() { - $file = 'file'; + $file = 'file'; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('markdown/raw', array('file' => $file)); + ->with('/markdown/raw', ['file' => $file]); $api->renderRaw($file); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Markdown'; + return \Github\Api\Markdown::class; } } diff --git a/test/Github/Tests/Api/NotificationTest.php b/test/Github/Tests/Api/NotificationTest.php new file mode 100644 index 00000000000..7ef3e64ba45 --- /dev/null +++ b/test/Github/Tests/Api/NotificationTest.php @@ -0,0 +1,153 @@ + false, + 'participating' => false, + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/notifications', $parameters); + + $api->all(); + } + + /** + * @test + */ + public function shouldGetNotificationsSince() + { + $since = new DateTime('now'); + + $parameters = [ + 'all' => false, + 'participating' => false, + 'since' => $since->format(DateTime::ISO8601), + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/notifications', $parameters); + + $api->all(false, false, $since); + } + + /** + * @test + */ + public function shouldGetNotificationsBefore() + { + $before = new DateTime('now'); + + $parameters = [ + 'all' => false, + 'participating' => false, + 'before' => $before->format(DateTime::ISO8601), + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/notifications', $parameters); + + $api->all(false, false, null, $before); + } + + /** + * @test + */ + public function shouldGetNotificationsIncludingAndParticipating() + { + $parameters = [ + 'all' => true, + 'participating' => true, + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/notifications', $parameters); + + $api->all(true, true); + } + + /** + * @test + */ + public function shouldMarkNotificationsAsRead() + { + $parameters = []; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/notifications', $parameters); + + $api->markRead(); + } + + /** + * @test + */ + public function shouldMarkNotificationsAsReadForGivenDate() + { + $since = new DateTime('now'); + + $parameters = [ + 'last_read_at' => $since->format(DateTime::ISO8601), + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/notifications', $parameters); + + $api->markRead($since); + } + + /** + * @test + */ + public function shouldMarkThreadAsRead() + { + $id = mt_rand(1, time()); + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('patch') + ->with('/notifications/threads/'.$id); + + $api->markThreadRead($id); + } + + public function shouldGetNotification() + { + $id = mt_rand(1, time()); + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/notification/'.$id); + + $api->id($id); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Notification::class; + } +} diff --git a/test/Github/Tests/Api/Organization/Actions/SecretsTest.php b/test/Github/Tests/Api/Organization/Actions/SecretsTest.php new file mode 100644 index 00000000000..324b706975d --- /dev/null +++ b/test/Github/Tests/Api/Organization/Actions/SecretsTest.php @@ -0,0 +1,219 @@ + 'name', 'created_at' => 'created_at', 'updated_at' => 'updated_at', 'visibility' => 'all'], + ['name' => 'name', 'created_at' => 'created_at', 'updated_at' => 'updated_at', 'visibility' => 'private'], + ['name' => 'name', 'created_at' => 'created_at', 'updated_at' => 'updated_at', 'visibility' => 'selected'], + ]; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/actions/secrets') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all('KnpLabs')); + } + + /** + * @test + */ + public function shouldGetOrganizationSecret() + { + $expectedArray = []; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/actions/secrets/secretName') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show('KnpLabs', 'secretName')); + } + + /** + * @test + */ + public function shouldCreateOrganizationSecret() + { + $expectedValue = 'response'; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('put') + ->with('/orgs/KnpLabs/actions/secrets/secretName') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->create('KnpLabs', 'secretName', [ + 'encrypted_value' => 'foo', 'visibility' => 'all', 'selected_repository_ids' => [1, 2, 3], + ])); + } + + /** + * @test + */ + public function shouldUpdateOrganizationSecret() + { + $expectedValue = 'response'; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('put') + ->with('/orgs/KnpLabs/actions/secrets/secretName') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->update('KnpLabs', 'secretName', [ + 'key_id' => 'keyId', + 'encrypted_value' => 'encryptedValue', + 'visibility' => 'private', + ])); + } + + /** + * @test + */ + public function shouldRemoveOrganizationSecret() + { + $expectedValue = 'response'; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('delete') + ->with('/orgs/KnpLabs/actions/secrets/secretName') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'secretName')); + } + + /** + * @test + */ + public function shouldGetSelectedRepositories() + { + $expectedArray = [1, 2, 3]; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/actions/secrets/secretName/repositories') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->selectedRepositories('KnpLabs', 'secretName')); + } + + /** + * @test + */ + public function shouldSetSelectedRepositories() + { + $expectedArray = [ + 'selected_repository_ids' => [1, 2, 3], + ]; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('put') + ->with('/orgs/KnpLabs/actions/secrets/secretName/repositories') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->setSelectedRepositories('KnpLabs', 'secretName', [ + 'selected_repository_ids' => [1, 2, 3], + ])); + } + + /** + * @test + */ + public function shouldAddSecret() + { + $expectedValue = 'response'; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('put') + ->with('/orgs/KnpLabs/actions/secrets/secretName/repositories/1') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->addSecret('KnpLabs', '1', 'secretName')); + } + + /** + * @test + */ + public function shouldRemoveSecret() + { + $expectedValue = 'response'; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('delete') + ->with('/orgs/KnpLabs/actions/secrets/secretName/repositories/1') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->removeSecret('KnpLabs', '1', 'secretName')); + } + + /** + * @test + */ + public function shouldGetPublicKey() + { + $expectedArray = ['key_id' => 'key_id', 'key' => 'foo']; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/actions/secrets/public-key') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->publicKey('KnpLabs')); + } + + protected function getApiClass() + { + return Secrets::class; + } +} diff --git a/test/Github/Tests/Api/Organization/Actions/SelfHostedRunnersTest.php b/test/Github/Tests/Api/Organization/Actions/SelfHostedRunnersTest.php new file mode 100644 index 00000000000..e313a88202a --- /dev/null +++ b/test/Github/Tests/Api/Organization/Actions/SelfHostedRunnersTest.php @@ -0,0 +1,115 @@ + 1, + 'name' => 'MBP', + 'os' => 'macos', + 'status' => 'online', + ], + [ + 'id' => 2, + 'name' => 'iMac', + 'os' => 'macos', + 'status' => 'offline', + ], + ]; + + /** @var SelfHostedRunners|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/actions/runners') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all('KnpLabs')); + } + + /** + * @test + */ + public function shouldGetSelfHostedRunner() + { + $expectedArray = [ + 'id' => 1, + 'name' => 'MBP', + 'os' => 'macos', + 'status' => 'online', + ]; + + /** @var SelfHostedRunners|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/actions/runners/1') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show('KnpLabs', 1)); + } + + /** + * @test + */ + public function shouldRemoveSelfHostedRunner() + { + $expectedValue = 'response'; + + /** @var SelfHostedRunners|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('delete') + ->with('/orgs/KnpLabs/actions/runners/1') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->remove('KnpLabs', 1)); + } + + /** + * @test + */ + public function shouldGetSelfHostedRunnerApps() + { + $expectedArray = [ + ['os' => 'osx', 'architecture' => 'x64', 'download_url' => 'download_url', 'filename' => 'filename'], + ['os' => 'linux', 'architecture' => 'x64', 'download_url' => 'download_url', 'filename' => 'filename'], + ['os' => 'linux', 'architecture' => 'arm', 'download_url' => 'download_url', 'filename' => 'filename'], + ['os' => 'win', 'architecture' => 'x64', 'download_url' => 'download_url', 'filename' => 'filename'], + ['os' => 'linux', 'architecture' => 'arm64', 'download_url' => 'download_url', 'filename' => 'filename'], + ]; + + /** @var SelfHostedRunners|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/actions/runners/downloads') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->applications('KnpLabs')); + } + + protected function getApiClass() + { + return SelfHostedRunners::class; + } +} diff --git a/test/Github/Tests/Api/Organization/Actions/VariablesTest.php b/test/Github/Tests/Api/Organization/Actions/VariablesTest.php new file mode 100644 index 00000000000..98d5072377e --- /dev/null +++ b/test/Github/Tests/Api/Organization/Actions/VariablesTest.php @@ -0,0 +1,198 @@ + 'name', 'value' => 'value', 'created_at' => 'created_at', 'updated_at' => 'updated_at', 'visibility' => 'all'], + ['name' => 'name', 'value' => 'value', 'created_at' => 'created_at', 'updated_at' => 'updated_at', 'visibility' => 'private'], + ['name' => 'name', 'value' => 'value', 'created_at' => 'created_at', 'updated_at' => 'updated_at', 'visibility' => 'selected'], + ]; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/actions/variables') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all('KnpLabs')); + } + + /** + * @test + */ + public function shouldGetOrganizationVariable() + { + $expectedArray = []; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/actions/variables/variableName') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show('KnpLabs', 'variableName')); + } + + /** + * @test + */ + public function shouldCreateOrganizationVariable() + { + $expectedValue = 'response'; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('post') + ->with('/orgs/KnpLabs/actions/variables') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->create('KnpLabs', [ + 'name' => 'foo', 'value' => 'value', 'visibility' => 'all', + ])); + } + + /** + * @test + */ + public function shouldUpdateOrganizationVariable() + { + $expectedValue = 'response'; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('patch') + ->with('/orgs/KnpLabs/actions/variables/variableName') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->update('KnpLabs', 'variableName', [ + 'name' => 'foo', 'value' => 'value', 'visibility' => 'private', + ])); + } + + /** + * @test + */ + public function shouldRemoveOrganizationVariable() + { + $expectedValue = 'response'; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('delete') + ->with('/orgs/KnpLabs/actions/variables/variableName') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'variableName')); + } + + /** + * @test + */ + public function shouldGetSelectedRepositories() + { + $expectedArray = [1, 2, 3]; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/actions/variables/variableName/repositories') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->selectedRepositories('KnpLabs', 'variableName')); + } + + /** + * @test + */ + public function shouldSetSelectedRepositories() + { + $expectedArray = [ + 'selected_repository_ids' => [1, 2, 3], + ]; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('put') + ->with('/orgs/KnpLabs/actions/variables/variableName/repositories') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->setSelectedRepositories('KnpLabs', 'variableName', [ + 'selected_repository_ids' => [1, 2, 3], + ])); + } + + /** + * @test + */ + public function shouldAddRepository() + { + $expectedValue = 'response'; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('put') + ->with('/orgs/KnpLabs/actions/variables/variableName/repositories/1') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->addRepository('KnpLabs', 1, 'variableName')); + } + + /** + * @test + */ + public function shouldRemoveRepository() + { + $expectedValue = 'response'; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('delete') + ->with('/orgs/KnpLabs/actions/variables/variableName/repositories/1') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->removeRepository('KnpLabs', 1, 'variableName')); + } + + protected function getApiClass() + { + return Variables::class; + } +} diff --git a/test/Github/Tests/Api/Organization/HooksTest.php b/test/Github/Tests/Api/Organization/HooksTest.php new file mode 100644 index 00000000000..82d586a087e --- /dev/null +++ b/test/Github/Tests/Api/Organization/HooksTest.php @@ -0,0 +1,160 @@ + 'hook']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/hooks') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->all('KnpLabs')); + } + + /** + * @test + */ + public function shouldShowHook() + { + $expectedValue = ['hook' => 'somename']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/hooks/123') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->show('KnpLabs', 123)); + } + + /** + * @test + */ + public function shouldRemoveHook() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/orgs/KnpLabs/hooks/123') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->remove('KnpLabs', 123)); + } + + /** + * @test + */ + public function shouldNotCreateHookWithoutName() + { + $this->expectException(MissingArgumentException::class); + $data = ['config' => 'conf']; + + $api = $this->getApiMock(); + $api->expects($this->never()) + ->method('post'); + + $api->create('KnpLabs', $data); + } + + /** + * @test + */ + public function shouldNotCreateHookWithoutConfig() + { + $this->expectException(MissingArgumentException::class); + $data = ['name' => 'test']; + + $api = $this->getApiMock(); + $api->expects($this->never()) + ->method('post'); + + $api->create('KnpLabs', $data); + } + + /** + * @test + */ + public function shouldCreateHook() + { + $expectedValue = ['hook' => 'somename']; + $data = ['name' => 'test', 'config' => 'someconfig']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/orgs/KnpLabs/hooks', $data) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->create('KnpLabs', $data)); + } + + /** + * @test + */ + public function shouldNotUpdateHookWithoutConfig() + { + $this->expectException(MissingArgumentException::class); + $data = []; + + $api = $this->getApiMock(); + $api->expects($this->never()) + ->method('patch'); + + $api->update('KnpLabs', 123, $data); + } + + /** + * @test + */ + public function shouldUpdateHook() + { + $expectedValue = ['hook' => 'somename']; + $data = ['config' => 'config']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('patch') + ->with('/orgs/KnpLabs/hooks/123', $data) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->update('KnpLabs', 123, $data)); + } + + /** + * @test + */ + public function shouldPingHook() + { + $expectedValue = null; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/orgs/KnpLabs/hooks/123/pings') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->ping('KnpLabs', 123)); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Organization\Hooks::class; + } +} diff --git a/test/Github/Tests/Api/Organization/MembersTest.php b/test/Github/Tests/Api/Organization/MembersTest.php index 7111766b82e..58ff1ea3c08 100644 --- a/test/Github/Tests/Api/Organization/MembersTest.php +++ b/test/Github/Tests/Api/Organization/MembersTest.php @@ -11,12 +11,12 @@ class MembersTest extends TestCase */ public function shouldGetAllOrganizationMembers() { - $expectedValue = array(array('username' => 'l3l0')); + $expectedValue = [['username' => 'l3l0']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('orgs/KnpLabs/members') + ->with('/orgs/KnpLabs/members') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs')); @@ -27,12 +27,12 @@ public function shouldGetAllOrganizationMembers() */ public function shouldGetPublicOrganizationMembers() { - $expectedValue = array(array('username' => 'l3l0')); + $expectedValue = [['username' => 'l3l0']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('orgs/KnpLabs/public_members') + ->with('/orgs/KnpLabs/public_members') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', true)); @@ -48,12 +48,28 @@ public function shouldCheckIfOrganizationMember() $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('orgs/KnpLabs/public_members/l3l0') + ->with('/orgs/KnpLabs/public_members/l3l0') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->check('KnpLabs', 'l3l0')); } + /** + * @test + */ + public function shouldAddOrganizationMember() + { + $expectedValue = 'response'; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/orgs/KnpLabs/memberships/l3l0') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->add('KnpLabs', 'l3l0')); + } + /** * @test */ @@ -64,7 +80,7 @@ public function shouldRemoveOrganizationMember() $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('orgs/KnpLabs/members/l3l0') + ->with('/orgs/KnpLabs/members/l3l0') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'l3l0')); @@ -80,7 +96,7 @@ public function shouldPublicizeOrganizationMembership() $api = $this->getApiMock(); $api->expects($this->once()) ->method('put') - ->with('orgs/KnpLabs/public_members/l3l0') + ->with('/orgs/KnpLabs/public_members/l3l0') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->publicize('KnpLabs', 'l3l0')); @@ -96,7 +112,7 @@ public function shouldConcealOrganizationMembership() $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('orgs/KnpLabs/public_members/l3l0') + ->with('/orgs/KnpLabs/public_members/l3l0') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->conceal('KnpLabs', 'l3l0')); @@ -107,19 +123,22 @@ public function shouldConcealOrganizationMembership() */ public function shouldShowOrganizationMember() { - $expectedValue = array('username' => 'l3l0'); + $expectedValue = ['username' => 'l3l0']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('orgs/KnpLabs/members/l3l0') + ->with('/orgs/KnpLabs/members/l3l0') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('KnpLabs', 'l3l0')); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Organization\Members'; + return \Github\Api\Organization\Members::class; } } diff --git a/test/Github/Tests/Api/Organization/OrganizationRolesTest.php b/test/Github/Tests/Api/Organization/OrganizationRolesTest.php new file mode 100644 index 00000000000..f2d801afceb --- /dev/null +++ b/test/Github/Tests/Api/Organization/OrganizationRolesTest.php @@ -0,0 +1,187 @@ + 1, + 'roles' => [[ + 'id' => 1, + 'name' => 'all_repo_admin', + 'description' => 'Grants admin access to all repositories in the organization.', + 'permissions' => [], + 'organization' => null, + 'created_at' => '2023-01-01T00:00:00Z', + 'updated_at' => '2023-01-01T00:00:00Z', + 'source' => 'Predefined', + 'base_role' => 'admin', + ]], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/orgs/acme/organization-roles') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->all('acme')); + } + + /** + * @test + */ + public function shouldShowSingleOrganizationRole() + { + $expectedValue = [ + 'id' => 1, + 'name' => 'all_repo_admin', + 'description' => 'Grants admin access to all repositories in the organization.', + 'permissions' => [], + 'organization' => null, + 'created_at' => '2023-01-01T00:00:00Z', + 'updated_at' => '2023-01-01T00:00:00Z', + 'source' => 'Predefined', + 'base_role' => 'admin', + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/orgs/acme/organization-roles/1') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->show('acme', 1)); + } + + /** + * @test + */ + public function shouldGetAllTeamsWithRole() + { + $expectedValue = [['name' => 'Acme Admins']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/orgs/acme/organization-roles/1/teams') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->listTeamsWithRole('acme', 1)); + } + + /** + * @test + */ + public function shouldAssignRoleToTeam() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/orgs/acme/organization-roles/teams/acme-admins/1') + ->will($this->returnValue('')); + + $api->assignRoleToTeam('acme', 1, 'acme-admins'); + } + + /** + * @test + */ + public function shouldRemoveRoleFromTeam() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/orgs/acme/organization-roles/teams/acme-admins/1') + ->will($this->returnValue('')); + + $api->removeRoleFromTeam('acme', 1, 'acme-admins'); + } + + /** + * @test + */ + public function shouldRemoveAllRolesFromTeam() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/orgs/acme/organization-roles/teams/acme-admins') + ->will($this->returnValue('')); + + $api->removeAllRolesFromTeam('acme', 'acme-admins'); + } + + /** + * @test + */ + public function shouldGetAllUsersWithRole() + { + $expectedValue = [['username' => 'Admin']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/orgs/acme/organization-roles/1/users') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->listUsersWithRole('acme', 1)); + } + + /** + * @test + */ + public function shouldAssignRoleToUser() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/orgs/acme/organization-roles/users/admin/1') + ->will($this->returnValue('')); + + $api->assignRoleToUser('acme', 1, 'admin'); + } + + /** + * @test + */ + public function shouldRemoveRoleFromUser() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/orgs/acme/organization-roles/users/admin/1') + ->will($this->returnValue('')); + + $api->removeRoleFromUser('acme', 1, 'admin'); + } + + /** + * @test + */ + public function shouldRemoveAllRolesFromUser() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/orgs/acme/organization-roles/users/admin') + ->will($this->returnValue('')); + + $api->removeAllRolesFromUser('acme', 'admin'); + } + + protected function getApiClass(): string + { + return OrganizationRoles::class; + } +} diff --git a/test/Github/Tests/Api/Organization/OutsideCollaboratorsTest.php b/test/Github/Tests/Api/Organization/OutsideCollaboratorsTest.php new file mode 100644 index 00000000000..eb74b266c09 --- /dev/null +++ b/test/Github/Tests/Api/Organization/OutsideCollaboratorsTest.php @@ -0,0 +1,66 @@ + 'KnpLabs']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/outside_collaborators') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->all('KnpLabs')); + } + + /** + * @test + */ + public function shouldConvertAnOrganizationMemberToOutsideCollaborator() + { + $expectedValue = 'expectedResponse'; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/orgs/KnpLabs/outside_collaborators/username') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->convert('KnpLabs', 'username')); + } + + /** + * @test + */ + public function shouldRemoveAnOutsideCollaboratorFromAnOrganization() + { + $expectedValue = 'expectedResponse'; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/orgs/KnpLabs/outside_collaborators/username') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'username')); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Organization\OutsideCollaborators::class; + } +} diff --git a/test/Github/Tests/Api/Organization/ProjectsTest.php b/test/Github/Tests/Api/Organization/ProjectsTest.php new file mode 100644 index 00000000000..05d607e34d8 --- /dev/null +++ b/test/Github/Tests/Api/Organization/ProjectsTest.php @@ -0,0 +1,65 @@ + 'Test project 1']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/projects') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->all('KnpLabs')); + } + + /** + * @test + */ + public function shouldNotCreateWithoutName() + { + $this->expectException(MissingArgumentException::class); + $data = []; + + $api = $this->getApiMock(); + $api->expects($this->never()) + ->method('post'); + + $api->create('KnpLabs', $data); + } + + /** + * @test + */ + public function shouldCreateColumn() + { + $expectedValue = ['project1data']; + $data = ['name' => 'Project 1']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/orgs/KnpLabs/projects', $data) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->create('KnpLabs', $data)); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Organization\Projects::class; + } +} diff --git a/test/Github/Tests/Api/Organization/SecretScanningTest.php b/test/Github/Tests/Api/Organization/SecretScanningTest.php new file mode 100644 index 00000000000..01b8f844007 --- /dev/null +++ b/test/Github/Tests/Api/Organization/SecretScanningTest.php @@ -0,0 +1,41 @@ + 1, 'state' => 'resolved', 'resolution' => 'false_positive'], + ['number' => 2, 'state' => 'open', 'resolution' => null], + ['number' => 3, 'state' => 'resolved', 'resolution' => 'wont_fix'], + ['number' => 4, 'state' => 'resolved', 'resolution' => 'revoked'], + ]; + + /** @var SecretScanning|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/orgs/KnpLabs/secret-scanning/alerts') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->alerts('KnpLabs', [ + 'state' => 'all', + ])); + } + + protected function getApiClass() + { + return \Github\Api\Organization\SecretScanning::class; + } +} diff --git a/test/Github/Tests/Api/Organization/TeamsTest.php b/test/Github/Tests/Api/Organization/TeamsTest.php index 6877b3b480c..18b476986aa 100644 --- a/test/Github/Tests/Api/Organization/TeamsTest.php +++ b/test/Github/Tests/Api/Organization/TeamsTest.php @@ -2,6 +2,7 @@ namespace Github\Tests\Api\Organization; +use Github\Exception\MissingArgumentException; use Github\Tests\Api\TestCase; class TeamsTest extends TestCase @@ -11,12 +12,12 @@ class TeamsTest extends TestCase */ public function shouldGetAllOrganizationTeams() { - $expectedValue = array(array('name' => 'KnpWorld'), array('name' => 'KnpFrance'), array('name' => 'KnpMontreal')); + $expectedValue = [['name' => 'KnpWorld'], ['name' => 'KnpFrance'], ['name' => 'KnpMontreal']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('orgs/KnpLabs/teams') + ->with('/orgs/KnpLabs/teams') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs')); @@ -32,10 +33,10 @@ public function shouldCheckIfMemberIsInOrganizationTeam() $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('teams/KnpWorld/members/l3l0') + ->with('/orgs/KnpLabs/teams/KnpWorld/memberships/l3l0') ->will($this->returnValue($expectedValue)); - $this->assertEquals($expectedValue, $api->check('KnpWorld', 'l3l0')); + $this->assertEquals($expectedValue, $api->check('KnpWorld', 'l3l0', 'KnpLabs')); } /** @@ -48,10 +49,10 @@ public function shouldRemoveOrganizationTeam() $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('teams/KnpWorld') + ->with('/orgs/KnpLabs/teams/KnpWorld') ->will($this->returnValue($expectedValue)); - $this->assertEquals($expectedValue, $api->remove('KnpWorld')); + $this->assertEquals($expectedValue, $api->remove('KnpWorld', 'KnpLabs')); } /** @@ -59,15 +60,15 @@ public function shouldRemoveOrganizationTeam() */ public function shouldShowOrganizationTeam() { - $expectedValue = array('username' => 'l3l0'); + $expectedValue = ['username' => 'l3l0']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('teams/KnpWorld') + ->with('/orgs/KnpLabs/teams/KnpWorld') ->will($this->returnValue($expectedValue)); - $this->assertEquals($expectedValue, $api->show('KnpWorld')); + $this->assertEquals($expectedValue, $api->show('KnpWorld', 'KnpLabs')); } /** @@ -75,15 +76,15 @@ public function shouldShowOrganizationTeam() */ public function shouldGetTeamMembers() { - $expectedValue = array(array('username' => 'l3l0')); + $expectedValue = [['username' => 'l3l0']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('teams/KnpWorld/members') + ->with('/orgs/KnpLabs/teams/KnpWorld/members') ->will($this->returnValue($expectedValue)); - $this->assertEquals($expectedValue, $api->members('KnpWorld')); + $this->assertEquals($expectedValue, $api->members('KnpWorld', 'KnpLabs')); } /** @@ -91,15 +92,15 @@ public function shouldGetTeamMembers() */ public function shouldAddTeamMembers() { - $expectedValue = array('username' => 'l3l0'); + $expectedValue = ['username' => 'l3l0']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('put') - ->with('teams/KnpWorld/members/l3l0') + ->with('/orgs/KnpLabs/teams/KnpWorld/memberships/l3l0') ->will($this->returnValue($expectedValue)); - $this->assertEquals($expectedValue, $api->addMember('KnpWorld', 'l3l0')); + $this->assertEquals($expectedValue, $api->addMember('KnpWorld', 'l3l0', 'KnpLabs')); } /** @@ -107,15 +108,15 @@ public function shouldAddTeamMembers() */ public function shouldRemoveTeamMembers() { - $expectedValue = array('username' => 'l3l0'); + $expectedValue = ['username' => 'l3l0']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('teams/KnpWorld/members/l3l0') + ->with('/orgs/KnpLabs/teams/KnpWorld/memberships/l3l0') ->will($this->returnValue($expectedValue)); - $this->assertEquals($expectedValue, $api->removeMember('KnpWorld', 'l3l0')); + $this->assertEquals($expectedValue, $api->removeMember('KnpWorld', 'l3l0', 'KnpLabs')); } /** @@ -123,12 +124,28 @@ public function shouldRemoveTeamMembers() */ public function shouldGetTeamRepositories() { - $expectedValue = array(array('name' => 'l3l0repo')); + $expectedValue = [['name' => 'l3l0repo']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('teams/KnpWorld/repos') + ->with('/orgs/KnpLabs/teams/KnpWorld/repos') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->repositories('KnpWorld', 'KnpLabs')); + } + + /** + * @test + */ + public function shouldGetTeamRepositoriesViaLegacy() + { + $expectedValue = [['name' => 'l3l0repo']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/teams/KnpWorld/repos') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->repositories('KnpWorld')); @@ -139,12 +156,12 @@ public function shouldGetTeamRepositories() */ public function shouldGetTeamRepository() { - $expectedValue = array('name' => 'l3l0repo'); + $expectedValue = ['name' => 'l3l0repo']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('teams/KnpWorld/repos/l3l0/l3l0Repo') + ->with('/teams/KnpWorld/repos/l3l0/l3l0Repo') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->repository('KnpWorld', 'l3l0', 'l3l0Repo')); @@ -155,12 +172,12 @@ public function shouldGetTeamRepository() */ public function shouldAddTeamRepository() { - $expectedValue = array('name' => 'l3l0repo'); + $expectedValue = ['name' => 'l3l0repo']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('put') - ->with('teams/KnpWorld/repos/l3l0/l3l0Repo') + ->with('/orgs/l3l0/teams/KnpWorld/repos/l3l0/l3l0Repo') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->addRepository('KnpWorld', 'l3l0', 'l3l0Repo')); @@ -171,12 +188,12 @@ public function shouldAddTeamRepository() */ public function shouldRemoveTeamRepository() { - $expectedValue = array('name' => 'l3l0repo'); + $expectedValue = ['name' => 'l3l0repo']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('teams/KnpWorld/repos/l3l0/l3l0Repo') + ->with('/orgs/l3l0/teams/KnpWorld/repos/l3l0/l3l0Repo') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->removeRepository('KnpWorld', 'l3l0', 'l3l0Repo')); @@ -184,11 +201,11 @@ public function shouldRemoveTeamRepository() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateTeamWithoutName() { - $data = array(); + $this->expectException(MissingArgumentException::class); + $data = []; $api = $this->getApiMock(); $api->expects($this->never()) @@ -202,13 +219,13 @@ public function shouldNotCreateTeamWithoutName() */ public function shouldCreateOrganizationTeam() { - $expectedValue = array('name' => 'KnpWorld'); - $data = array('name' => 'KnpWorld'); + $expectedValue = ['name' => 'KnpWorld']; + $data = ['name' => 'KnpWorld']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('orgs/KnpLabs/teams', $data) + ->with('/orgs/KnpLabs/teams', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', $data)); @@ -219,13 +236,13 @@ public function shouldCreateOrganizationTeam() */ public function shouldCreateOrganizationTeamWithRepoName() { - $expectedValue = array('name' => 'KnpWorld'); - $data = array('name' => 'KnpWorld', 'repo_names' => 'somerepo'); + $expectedValue = ['name' => 'KnpWorld']; + $data = ['name' => 'KnpWorld', 'repo_names' => 'somerepo']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('orgs/KnpLabs/teams', array('name' => 'KnpWorld', 'repo_names' => array('somerepo'))) + ->with('/orgs/KnpLabs/teams', ['name' => 'KnpWorld', 'repo_names' => ['somerepo']]) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', $data)); @@ -236,13 +253,13 @@ public function shouldCreateOrganizationTeamWithRepoName() */ public function shouldCreateWithPullPermissionWhenPermissionParamNotRecognized() { - $expectedValue = array('name' => 'KnpWorld'); - $data = array('name' => 'KnpWorld', 'permission' => 'someinvalid'); + $expectedValue = ['name' => 'KnpWorld']; + $data = ['name' => 'KnpWorld', 'permission' => 'someinvalid']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('orgs/KnpLabs/teams', array('name' => 'KnpWorld', 'permission' => 'pull')) + ->with('/orgs/KnpLabs/teams', ['name' => 'KnpWorld', 'permission' => 'pull']) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', $data)); @@ -250,17 +267,17 @@ public function shouldCreateWithPullPermissionWhenPermissionParamNotRecognized() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotUpdateTeamWithoutName() { - $data = array(); + $this->expectException(MissingArgumentException::class); + $data = []; $api = $this->getApiMock(); $api->expects($this->never()) ->method('patch'); - $api->update('KnpWorld', $data); + $api->update('KnpWorld', $data, 'KnpLabs'); } /** @@ -268,16 +285,16 @@ public function shouldNotUpdateTeamWithoutName() */ public function shouldUpdateOrganizationTeam() { - $expectedValue = array('name' => 'KnpWorld'); - $data = array('name' => 'KnpWorld'); + $expectedValue = ['name' => 'KnpWorld']; + $data = ['name' => 'KnpWorld']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('teams/KnpWorld', $data) + ->with('/orgs/KnpLabs/teams/KnpWorld', $data) ->will($this->returnValue($expectedValue)); - $this->assertEquals($expectedValue, $api->update('KnpWorld', $data)); + $this->assertEquals($expectedValue, $api->update('KnpWorld', $data, 'KnpLabs')); } /** @@ -285,20 +302,23 @@ public function shouldUpdateOrganizationTeam() */ public function shouldUpdateWithPullPermissionWhenPermissionParamNotRecognized() { - $expectedValue = array('name' => 'KnpWorld'); - $data = array('name' => 'KnpWorld', 'permission' => 'someinvalid'); + $expectedValue = ['name' => 'KnpWorld']; + $data = ['name' => 'KnpWorld', 'permission' => 'someinvalid']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('teams/KnpWorld', array('name' => 'KnpWorld', 'permission' => 'pull')) + ->with('/orgs/KnpLabs/teams/KnpWorld', ['name' => 'KnpWorld', 'permission' => 'pull']) ->will($this->returnValue($expectedValue)); - $this->assertEquals($expectedValue, $api->update('KnpWorld', $data)); + $this->assertEquals($expectedValue, $api->update('KnpWorld', $data, 'KnpLabs')); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Organization\Teams'; + return \Github\Api\Organization\Teams::class; } } diff --git a/test/Github/Tests/Api/OrganizationTest.php b/test/Github/Tests/Api/OrganizationTest.php index b1497c2f4c4..2b920662691 100644 --- a/test/Github/Tests/Api/OrganizationTest.php +++ b/test/Github/Tests/Api/OrganizationTest.php @@ -4,17 +4,33 @@ class OrganizationTest extends TestCase { + /** + * @test + */ + public function shouldGetAllOrganizations() + { + $expectedValue = [['login' => 'KnpLabs']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/organizations?since=1') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->all(1)); + } + /** * @test */ public function shouldShowOrganization() { - $expectedArray = array('id' => 1, 'name' => 'KnpLabs'); + $expectedArray = ['id' => 1, 'name' => 'KnpLabs']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('orgs/KnpLabs') + ->with('/orgs/KnpLabs') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->show('KnpLabs')); @@ -25,15 +41,15 @@ public function shouldShowOrganization() */ public function shouldUpdateOrganization() { - $expectedArray = array('id' => 1, 'name' => 'KnpLabs'); + $expectedArray = ['id' => 1, 'name' => 'KnpLabs']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('orgs/KnpLabs', array('value' => 'toUpdate')) + ->with('/orgs/KnpLabs', ['value' => 'toUpdate']) ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->update('KnpLabs', array('value' => 'toUpdate'))); + $this->assertEquals($expectedArray, $api->update('KnpLabs', ['value' => 'toUpdate'])); } /** @@ -41,12 +57,12 @@ public function shouldUpdateOrganization() */ public function shouldGetOrganizationRepositories() { - $expectedArray = array(array('id' => 1, 'username' => 'KnpLabs', 'name' => 'php-github-api')); + $expectedArray = [['id' => 1, 'username' => 'KnpLabs', 'name' => 'php-github-api']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('orgs/KnpLabs/repos', array('type' => 'all')) + ->with('/orgs/KnpLabs/repos', ['type' => 'all', 'page' => 1]) ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->repositories('KnpLabs')); @@ -59,7 +75,7 @@ public function shouldGetMembersApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\Organization\Members', $api->members()); + $this->assertInstanceOf(\Github\Api\Organization\Members::class, $api->members()); } /** @@ -69,11 +85,34 @@ public function shouldGetTeamsApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\Organization\Teams', $api->teams()); + $this->assertInstanceOf(\Github\Api\Organization\Teams::class, $api->teams()); } + /** + * @test + */ + public function shouldGetSelfHostedRunnersApiObject() + { + $api = $this->getApiMock(); + + $this->assertInstanceOf(\Github\Api\Organization\Actions\SelfHostedRunners::class, $api->runners()); + } + + /** + * @test + */ + public function shouldGetVariablesApiObject() + { + $api = $this->getApiMock(); + + $this->assertInstanceOf(\Github\Api\Organization\Actions\Variables::class, $api->variables()); + } + + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Organization'; + return \Github\Api\Organization::class; } } diff --git a/test/Github/Tests/Api/Project/CardsTest.php b/test/Github/Tests/Api/Project/CardsTest.php new file mode 100644 index 00000000000..8b3b37090db --- /dev/null +++ b/test/Github/Tests/Api/Project/CardsTest.php @@ -0,0 +1,131 @@ +getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/projects/columns/123/cards') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->all(123)); + } + + /** + * @test + */ + public function shouldShowCard() + { + $expectedValue = ['card1']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/projects/columns/cards/123') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->show(123)); + } + + /** + * @test + */ + public function shouldCreateCard() + { + $expectedValue = ['card1data']; + $data = ['content_id' => '123', 'content_type' => 'Issue']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/projects/columns/1234/cards', $data) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->create('1234', $data)); + } + + /** + * @test + */ + public function shouldUpdateCard() + { + $expectedValue = ['note1data']; + $data = ['note' => 'note test']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('patch') + ->with('/projects/columns/cards/123', $data) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->update(123, $data)); + } + + /** + * @test + */ + public function shouldRemoveCard() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/projects/columns/cards/123') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->deleteCard(123)); + } + + /** + * @test + */ + public function shouldNotMoveWithoutPosition() + { + $this->expectException(MissingArgumentException::class); + $data = []; + + $api = $this->getApiMock(); + $api->expects($this->never()) + ->method('post'); + + $api->move('123', $data); + } + + /** + * @test + */ + public function shouldMoveCard() + { + $expectedValue = ['card1']; + $data = ['position' => 'top']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/projects/columns/cards/123/moves') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->move(123, $data)); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Project\Cards::class; + } +} diff --git a/test/Github/Tests/Api/Project/ColumnsTest.php b/test/Github/Tests/Api/Project/ColumnsTest.php new file mode 100644 index 00000000000..7df1225190b --- /dev/null +++ b/test/Github/Tests/Api/Project/ColumnsTest.php @@ -0,0 +1,171 @@ +getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/projects/123/columns') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->all(123)); + } + + /** + * @test + */ + public function shouldShowColumn() + { + $expectedValue = ['column1']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/projects/columns/123') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->show(123)); + } + + /** + * @test + */ + public function shouldNotCreateWithoutName() + { + $this->expectException(MissingArgumentException::class); + $data = []; + + $api = $this->getApiMock(); + $api->expects($this->never()) + ->method('post'); + + $api->create('123', $data); + } + + /** + * @test + */ + public function shouldCreateColumn() + { + $expectedValue = ['column1data']; + $data = ['name' => 'column 1']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/projects/123/columns', $data) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->create(123, $data)); + } + + /** + * @test + */ + public function shouldNotUpdateWithoutName() + { + $this->expectException(MissingArgumentException::class); + $data = []; + + $api = $this->getApiMock(); + $api->expects($this->never()) + ->method('post'); + + $api->update('123', $data); + } + + /** + * @test + */ + public function shouldUpdateColumn() + { + $expectedValue = ['column1data']; + $data = ['name' => 'column 1 update']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('patch') + ->with('/projects/columns/123', $data) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->update(123, $data)); + } + + /** + * @test + */ + public function shouldRemoveCard() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/projects/columns/123') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->deleteColumn(123)); + } + + /** + * @test + */ + public function shouldNotMoveWithoutPosition() + { + $this->expectException(MissingArgumentException::class); + $data = []; + + $api = $this->getApiMock(); + $api->expects($this->never()) + ->method('post'); + + $api->move('123', $data); + } + + /** + * @test + */ + public function shouldMoveCard() + { + $expectedValue = ['card1']; + $data = ['position' => 'first']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/projects/columns/123/moves') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->move(123, $data)); + } + + /** + * @test + */ + public function shouldGetCardsApiObject() + { + $api = $this->getApiMock(); + + $this->assertInstanceOf('Github\Api\Project\Cards', $api->cards()); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Project\Columns::class; + } +} diff --git a/test/Github/Tests/Api/Project/ProjectsTest.php b/test/Github/Tests/Api/Project/ProjectsTest.php new file mode 100644 index 00000000000..0dc7e2645a5 --- /dev/null +++ b/test/Github/Tests/Api/Project/ProjectsTest.php @@ -0,0 +1,76 @@ + 'Test project 1']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/projects/123') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->show(123)); + } + + /** + * @test + */ + public function shouldUpdateProject() + { + $expectedValue = ['project1data']; + $data = ['name' => 'Project 1 update']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('patch') + ->with('/projects/123', $data) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->update(123, $data)); + } + + /** + * @test + */ + public function shouldRemoveProject() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/projects/123') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->deleteProject(123)); + } + + /** + * @test + */ + public function shouldGetColumnsApiObject() + { + $api = $this->getApiMock(); + + $this->assertInstanceOf('Github\Api\Project\Columns', $api->columns()); + } + + /** + * @return string + */ + protected function getApiClass() + { + return AbstractProjectApi::class; + } +} diff --git a/test/Github/Tests/Api/PullRequest/CommentsTest.php b/test/Github/Tests/Api/PullRequest/CommentsTest.php new file mode 100644 index 00000000000..c180607e837 --- /dev/null +++ b/test/Github/Tests/Api/PullRequest/CommentsTest.php @@ -0,0 +1,495 @@ + 'https://api.github.com/repos/octocat/Hello-World/pulls/comments/1', + 'id' => 1, + 'pull_request_review_id' => 42, + 'diff_hunk' => '@@ -16,33 +16,40 @@ public class Connection => IConnection...', + 'path' => 'file1.txt', + 'position' => 1, + 'original_position' => 4, + 'commit_id' => '6dcb09b5b57875f334f61aebed695e2e4193db5e', + 'original_commit_id' => '9c48853fa3dc5c1c3d6f1f1cd1f2743e72652840', + 'user' => [ + 'login' => 'octocat', + 'id' => 1, + 'avatar_url' => 'https://github.com/images/error/octocat_happy.gif', + 'gravatar_id' => '', + 'url' => 'https://api.github.com/users/octocat', + 'html_url' => 'https://github.com/octocat', + 'followers_url' => 'https://api.github.com/users/octocat/followers', + 'following_url' => 'https://api.github.com/users/octocat/following[/other_user]', + 'gists_url' => 'https://api.github.com/users/octocat/gists[/gist_id]', + 'starred_url' => 'https://api.github.com/users/octocat/starred[/owner][/repo]', + 'subscriptions_url' => 'https://api.github.com/users/octocat/subscriptions', + 'organizations_url' => 'https://api.github.com/users/octocat/orgs', + 'repos_url' => 'https://api.github.com/users/octocat/repos', + 'events_url' => 'https://api.github.com/users/octocat/events[/privacy]', + 'received_events_url' => 'https://api.github.com/users/octocat/received_events', + 'type' => 'User', + 'site_admin' => false, + ], + 'body' => 'Great stuff', + 'created_at' => '2011-04-14T16:00:49Z', + 'updated_at' => '2011-04-14T16:00:49Z', + 'html_url' => 'https://github.com/octocat/Hello-World/pull/1#discussion-diff-1', + 'pull_request_url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/1', + '_links' => [ + 'self' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/comments/1', + ], + 'html' => [ + 'href' => 'https://github.com/octocat/Hello-World/pull/1#discussion-diff-1', + ], + 'pull_request' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/1', + ], + ], + ], + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/octocat/Hello-World/pulls/12/comments') + ->willReturn($expectedValue); + + $this->assertSame($expectedValue, $api->all('octocat', 'Hello-World', 12)); + } + + /** + * @test + */ + public function shouldGetAllReviewComments() + { + $expectedValue = [ + [ + 'url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/comments/1', + 'id' => 1, + 'pull_request_review_id' => 42, + 'diff_hunk' => '@@ -16,33 +16,40 @@ public class Connection => IConnection...', + 'path' => 'file1.txt', + 'position' => 1, + 'original_position' => 4, + 'commit_id' => '6dcb09b5b57875f334f61aebed695e2e4193db5e', + 'original_commit_id' => '9c48853fa3dc5c1c3d6f1f1cd1f2743e72652840', + 'user' => [ + 'login' => 'octocat', + 'id' => 1, + 'avatar_url' => 'https://github.com/images/error/octocat_happy.gif', + 'gravatar_id' => '', + 'url' => 'https://api.github.com/users/octocat', + 'html_url' => 'https://github.com/octocat', + 'followers_url' => 'https://api.github.com/users/octocat/followers', + 'following_url' => 'https://api.github.com/users/octocat/following[/other_user]', + 'gists_url' => 'https://api.github.com/users/octocat/gists[/gist_id]', + 'starred_url' => 'https://api.github.com/users/octocat/starred[/owner][/repo]', + 'subscriptions_url' => 'https://api.github.com/users/octocat/subscriptions', + 'organizations_url' => 'https://api.github.com/users/octocat/orgs', + 'repos_url' => 'https://api.github.com/users/octocat/repos', + 'events_url' => 'https://api.github.com/users/octocat/events[/privacy]', + 'received_events_url' => 'https://api.github.com/users/octocat/received_events', + 'type' => 'User', + 'site_admin' => false, + ], + 'body' => 'Great stuff', + 'created_at' => '2011-04-14T16:00:49Z', + 'updated_at' => '2011-04-14T16:00:49Z', + 'html_url' => 'https://github.com/octocat/Hello-World/pull/1#discussion-diff-1', + 'pull_request_url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/1', + '_links' => [ + 'self' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/comments/1', + ], + 'html' => [ + 'href' => 'https://github.com/octocat/Hello-World/pull/1#discussion-diff-1', + ], + 'pull_request' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/1', + ], + ], + ], + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/octocat/Hello-World/pulls/comments') + ->willReturn($expectedValue); + + $this->assertSame($expectedValue, $api->all('octocat', 'Hello-World')); + } + + /** + * @test + */ + public function shouldShowReviewComment() + { + $expectedValue = [ + 'url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/comments/1', + 'id' => 1, + 'pull_request_review_id' => 42, + 'diff_hunk' => '@@ -16,33 +16,40 @@ public class Connection => IConnection...', + 'path' => 'file1.txt', + 'position' => 1, + 'original_position' => 4, + 'commit_id' => '6dcb09b5b57875f334f61aebed695e2e4193db5e', + 'original_commit_id' => '9c48853fa3dc5c1c3d6f1f1cd1f2743e72652840', + 'user' => [ + 'login' => 'octocat', + 'id' => 1, + 'avatar_url' => 'https://github.com/images/error/octocat_happy.gif', + 'gravatar_id' => '', + 'url' => 'https://api.github.com/users/octocat', + 'html_url' => 'https://github.com/octocat', + 'followers_url' => 'https://api.github.com/users/octocat/followers', + 'following_url' => 'https://api.github.com/users/octocat/following[/other_user]', + 'gists_url' => 'https://api.github.com/users/octocat/gists[/gist_id]', + 'starred_url' => 'https://api.github.com/users/octocat/starred[/owner][/repo]', + 'subscriptions_url' => 'https://api.github.com/users/octocat/subscriptions', + 'organizations_url' => 'https://api.github.com/users/octocat/orgs', + 'repos_url' => 'https://api.github.com/users/octocat/repos', + 'events_url' => 'https://api.github.com/users/octocat/events[/privacy]', + 'received_events_url' => 'https://api.github.com/users/octocat/received_events', + 'type' => 'User', + 'site_admin' => false, + ], + 'body' => 'Great stuff', + 'created_at' => '2011-04-14T16:00:49Z', + 'updated_at' => '2011-04-14T16:00:49Z', + 'html_url' => 'https://github.com/octocat/Hello-World/pull/1#discussion-diff-1', + 'pull_request_url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/1', + '_links' => [ + 'self' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/comments/1', + ], + 'html' => [ + 'href' => 'https://github.com/octocat/Hello-World/pull/1#discussion-diff-1', + ], + 'pull_request' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/1', + ], + ], + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/octocat/Hello-World/pulls/comments/1') + ->willReturn($expectedValue); + + $this->assertSame($expectedValue, $api->show('octocat', 'Hello-World', 1)); + } + + /** + * @test + */ + public function shouldCreateReviewComment() + { + $expectedValue = [ + 'url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/comments/1', + 'id' => 1, + 'pull_request_review_id' => 42, + 'diff_hunk' => '@@ -16,33 +16,40 @@ public class Connection => IConnection...', + 'path' => 'file1.txt', + 'position' => 1, + 'original_position' => 4, + 'commit_id' => '6dcb09b5b57875f334f61aebed695e2e4193db5e', + 'original_commit_id' => '9c48853fa3dc5c1c3d6f1f1cd1f2743e72652840', + 'user' => [ + 'login' => 'octocat', + 'id' => 1, + 'avatar_url' => 'https://github.com/images/error/octocat_happy.gif', + 'gravatar_id' => '', + 'url' => 'https://api.github.com/users/octocat', + 'html_url' => 'https://github.com/octocat', + 'followers_url' => 'https://api.github.com/users/octocat/followers', + 'following_url' => 'https://api.github.com/users/octocat/following[/other_user]', + 'gists_url' => 'https://api.github.com/users/octocat/gists[/gist_id]', + 'starred_url' => 'https://api.github.com/users/octocat/starred[/owner][/repo]', + 'subscriptions_url' => 'https://api.github.com/users/octocat/subscriptions', + 'organizations_url' => 'https://api.github.com/users/octocat/orgs', + 'repos_url' => 'https://api.github.com/users/octocat/repos', + 'events_url' => 'https://api.github.com/users/octocat/events[/privacy]', + 'received_events_url' => 'https://api.github.com/users/octocat/received_events', + 'type' => 'User', + 'site_admin' => false, + ], + 'body' => 'Great stuff', + 'created_at' => '2011-04-14T16:00:49Z', + 'updated_at' => '2011-04-14T16:00:49Z', + 'html_url' => 'https://github.com/octocat/Hello-World/pull/1#discussion-diff-1', + 'pull_request_url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/1', + '_links' => [ + 'self' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/comments/1', + ], + 'html' => [ + 'href' => 'https://github.com/octocat/Hello-World/pull/1#discussion-diff-1', + ], + 'pull_request' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/1', + ], + ], + ]; + $data = [ + 'commit_id' => '6dcb09b5b57875f334f61aebed695e2e4193db5e', + 'path' => 'file1.txt', + 'position' => 4, + 'body' => 'Nice change', + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/octocat/Hello-World/pulls/1/comments', $data) + ->willReturn($expectedValue); + + $this->assertSame($expectedValue, $api->create('octocat', 'Hello-World', 1, $data)); + } + + /** + * @test + */ + public function shouldNotCreateReviewCommentWithoutCommitId() + { + $this->expectException(MissingArgumentException::class); + $data = [ + 'path' => 'file1.txt', + 'position' => 4, + 'body' => 'Nice change', + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->never()) + ->method('post') + ; + + $api->create('octocat', 'Hello-World', 1, $data); + } + + /** + * @test + */ + public function shouldNotCreateReviewCommentWithoutPath() + { + $this->expectException(MissingArgumentException::class); + $data = [ + 'commit_id' => '6dcb09b5b57875f334f61aebed695e2e4193db5e', + 'position' => 4, + 'body' => 'Nice change', + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->never()) + ->method('post') + ; + + $api->create('octocat', 'Hello-World', 1, $data); + } + + /** + * @test + */ + public function shouldNotCreateReviewCommentWithoutPosition() + { + $this->expectException(MissingArgumentException::class); + $data = [ + 'commit_id' => '6dcb09b5b57875f334f61aebed695e2e4193db5e', + 'path' => 'file1.txt', + 'body' => 'Nice change', + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->never()) + ->method('post') + ; + + $api->create('octocat', 'Hello-World', 1, $data); + } + + /** + * @test + */ + public function shouldNotCreateReviewCommentWithoutBody() + { + $this->expectException(MissingArgumentException::class); + $data = [ + 'commit_id' => '6dcb09b5b57875f334f61aebed695e2e4193db5e', + 'path' => 'file1.txt', + 'position' => 4, + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->never()) + ->method('post') + ; + + $api->create('octocat', 'Hello-World', 1, $data); + } + + /** + * @test + */ + public function shouldUpdateReviewComment() + { + $expectedValue = [ + 'url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/comments/1', + 'id' => 1, + 'pull_request_review_id' => 42, + 'diff_hunk' => '@@ -16,33 +16,40 @@ public class Connection => IConnection...', + 'path' => 'file1.txt', + 'position' => 1, + 'original_position' => 4, + 'commit_id' => '6dcb09b5b57875f334f61aebed695e2e4193db5e', + 'original_commit_id' => '9c48853fa3dc5c1c3d6f1f1cd1f2743e72652840', + 'user' => [ + 'login' => 'octocat', + 'id' => 1, + 'avatar_url' => 'https://github.com/images/error/octocat_happy.gif', + 'gravatar_id' => '', + 'url' => 'https://api.github.com/users/octocat', + 'html_url' => 'https://github.com/octocat', + 'followers_url' => 'https://api.github.com/users/octocat/followers', + 'following_url' => 'https://api.github.com/users/octocat/following[/other_user]', + 'gists_url' => 'https://api.github.com/users/octocat/gists[/gist_id]', + 'starred_url' => 'https://api.github.com/users/octocat/starred[/owner][/repo]', + 'subscriptions_url' => 'https://api.github.com/users/octocat/subscriptions', + 'organizations_url' => 'https://api.github.com/users/octocat/orgs', + 'repos_url' => 'https://api.github.com/users/octocat/repos', + 'events_url' => 'https://api.github.com/users/octocat/events[/privacy]', + 'received_events_url' => 'https://api.github.com/users/octocat/received_events', + 'type' => 'User', + 'site_admin' => false, + ], + 'body' => 'Great stuff', + 'created_at' => '2011-04-14T16:00:49Z', + 'updated_at' => '2011-04-14T16:00:49Z', + 'html_url' => 'https://github.com/octocat/Hello-World/pull/1#discussion-diff-1', + 'pull_request_url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/1', + '_links' => [ + 'self' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/comments/1', + ], + 'html' => [ + 'href' => 'https://github.com/octocat/Hello-World/pull/1#discussion-diff-1', + ], + 'pull_request' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/1', + ], + ], + ]; + $data = [ + 'body' => 'Nice change', + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('patch') + ->with('/repos/octocat/Hello-World/pulls/comments/1', $data) + ->willReturn($expectedValue); + + $this->assertSame($expectedValue, $api->update('octocat', 'Hello-World', 1, $data)); + } + + /** + * @test + */ + public function shouldNotUpdateReviewCommentWithoutBody() + { + $this->expectException(MissingArgumentException::class); + $expectedValue = [ + 'url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/comments/1', + 'id' => 1, + 'pull_request_review_id' => 42, + 'diff_hunk' => '@@ -16,33 +16,40 @@ public class Connection => IConnection...', + 'path' => 'file1.txt', + 'position' => 1, + 'original_position' => 4, + 'commit_id' => '6dcb09b5b57875f334f61aebed695e2e4193db5e', + 'original_commit_id' => '9c48853fa3dc5c1c3d6f1f1cd1f2743e72652840', + 'user' => [ + 'login' => 'octocat', + 'id' => 1, + 'avatar_url' => 'https://github.com/images/error/octocat_happy.gif', + 'gravatar_id' => '', + 'url' => 'https://api.github.com/users/octocat', + 'html_url' => 'https://github.com/octocat', + 'followers_url' => 'https://api.github.com/users/octocat/followers', + 'following_url' => 'https://api.github.com/users/octocat/following[/other_user]', + 'gists_url' => 'https://api.github.com/users/octocat/gists[/gist_id]', + 'starred_url' => 'https://api.github.com/users/octocat/starred[/owner][/repo]', + 'subscriptions_url' => 'https://api.github.com/users/octocat/subscriptions', + 'organizations_url' => 'https://api.github.com/users/octocat/orgs', + 'repos_url' => 'https://api.github.com/users/octocat/repos', + 'events_url' => 'https://api.github.com/users/octocat/events[/privacy]', + 'received_events_url' => 'https://api.github.com/users/octocat/received_events', + 'type' => 'User', + 'site_admin' => false, + ], + 'body' => 'Great stuff', + 'created_at' => '2011-04-14T16:00:49Z', + 'updated_at' => '2011-04-14T16:00:49Z', + 'html_url' => 'https://github.com/octocat/Hello-World/pull/1#discussion-diff-1', + 'pull_request_url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/1', + '_links' => [ + 'self' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/comments/1', + ], + 'html' => [ + 'href' => 'https://github.com/octocat/Hello-World/pull/1#discussion-diff-1', + ], + 'pull_request' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/1', + ], + ], + ]; + + $api = $this->getApiMock(); + $api->expects($this->never()) + ->method('patch') + ; + + $this->assertSame($expectedValue, $api->update('octocat', 'Hello-World', 1, [])); + } + + /** + * @test + */ + public function shouldDeleteReviewComment() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/octocat/Hello-World/pulls/comments/1') + ; + + $api->remove('octocat', 'Hello-World', 1); + } + + protected function getApiClass() + { + return Comments::class; + } +} diff --git a/test/Github/Tests/Api/PullRequest/ReviewRequestTest.php b/test/Github/Tests/Api/PullRequest/ReviewRequestTest.php new file mode 100644 index 00000000000..3335b4a3494 --- /dev/null +++ b/test/Github/Tests/Api/PullRequest/ReviewRequestTest.php @@ -0,0 +1,65 @@ + 80], + ['id' => 81], + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/octocat/Hello-World/pulls/12/requested_reviewers') + ->willReturn($expectedValue); + + $this->assertSame($expectedValue, $api->all('octocat', 'Hello-World', 12)); + } + + /** + * @test + */ + public function shouldCreateReviewRequest() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/octocat/Hello-World/pulls/12/requested_reviewers', ['reviewers' => ['testuser'], 'team_reviewers' => ['testteam']]) + ; + + $api->create('octocat', 'Hello-World', 12, ['testuser'], ['testteam']); + } + + /** + * @test + */ + public function shouldDeleteReviewRequest() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/octocat/Hello-World/pulls/12/requested_reviewers', ['reviewers' => ['testuser'], 'team_reviewers' => ['testteam']]) + ; + + $api->remove('octocat', 'Hello-World', 12, ['testuser'], ['testteam']); + } + + /** + * @return string + */ + protected function getApiClass() + { + return ReviewRequest::class; + } +} diff --git a/test/Github/Tests/Api/PullRequest/ReviewTest.php b/test/Github/Tests/Api/PullRequest/ReviewTest.php new file mode 100644 index 00000000000..eb94203bc68 --- /dev/null +++ b/test/Github/Tests/Api/PullRequest/ReviewTest.php @@ -0,0 +1,455 @@ + 80, + 'user' => [ + 'login' => 'octocat', + 'id' => 1, + 'avatar_url' => 'https://github.com/images/error/octocat_happy.gif', + 'gravatar_id' => '', + 'url' => 'https://api.github.com/users/octocat', + 'html_url' => 'https://github.com/octocat', + 'followers_url' => 'https://api.github.com/users/octocat/followers', + 'following_url' => 'https://api.github.com/users/octocat/following{/other_user}', + 'gists_url' => 'https://api.github.com/users/octocat/gists{/gist_id}', + 'starred_url' => 'https://api.github.com/users/octocat/starred{/owner}{/repo}', + 'subscriptions_url' => 'https://api.github.com/users/octocat/subscriptions', + 'organizations_url' => 'https://api.github.com/users/octocat/orgs', + 'repos_url' => 'https://api.github.com/users/octocat/repos', + 'events_url' => 'https://api.github.com/users/octocat/events{/privacy}', + 'received_events_url' => 'https://api.github.com/users/octocat/received_events', + 'type' => 'User', + 'site_admin' => false, + ], + 'body' => 'Here is the body for the review.', + 'commit_id' => 'ecdd80bb57125d7ba9641ffaa4d7d2c19d3f3091', + 'state' => 'APPROVED', + 'html_url' => 'https://github.com/octocat/Hello-World/pull/12#pullrequestreview-80', + 'pull_request_url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/12', + '_links' => [ + 'html' => [ + 'href' => 'https://github.com/octocat/Hello-World/pull/12#pullrequestreview-80', + ], + 'pull_request' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/12', + ], + ], + ], + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/octocat/Hello-World/pulls/12/reviews') + ->willReturn($expectedValue); + + $this->assertSame($expectedValue, $api->all('octocat', 'Hello-World', 12)); + } + + /** + * @test + */ + public function shouldShowReview() + { + $expectedValue = [ + 'id' => 80, + 'user' => [ + 'login' => 'octocat', + 'id' => 1, + 'avatar_url' => 'https://github.com/images/error/octocat_happy.gif', + 'gravatar_id' => '', + 'url' => 'https://api.github.com/users/octocat', + 'html_url' => 'https://github.com/octocat', + 'followers_url' => 'https://api.github.com/users/octocat/followers', + 'following_url' => 'https://api.github.com/users/octocat/following{/other_user}', + 'gists_url' => 'https://api.github.com/users/octocat/gists{/gist_id}', + 'starred_url' => 'https://api.github.com/users/octocat/starred{/owner}{/repo}', + 'subscriptions_url' => 'https://api.github.com/users/octocat/subscriptions', + 'organizations_url' => 'https://api.github.com/users/octocat/orgs', + 'repos_url' => 'https://api.github.com/users/octocat/repos', + 'events_url' => 'https://api.github.com/users/octocat/events{/privacy}', + 'received_events_url' => 'https://api.github.com/users/octocat/received_events', + 'type' => 'User', + 'site_admin' => false, + ], + 'body' => 'Here is the body for the review.', + 'commit_id' => 'ecdd80bb57125d7ba9641ffaa4d7d2c19d3f3091', + 'state' => 'APPROVED', + 'html_url' => 'https://github.com/octocat/Hello-World/pull/12#pullrequestreview-80', + 'pull_request_url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/12', + '_links' => [ + 'html' => [ + 'href' => 'https://github.com/octocat/Hello-World/pull/12#pullrequestreview-80', + ], + 'pull_request' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/12', + ], + ], + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/octocat/Hello-World/pulls/12/reviews/80') + ->willReturn($expectedValue); + + $this->assertSame($expectedValue, $api->show('octocat', 'Hello-World', 12, 80)); + } + + /** + * @test + */ + public function shouldDeleteReview() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/octocat/Hello-World/pulls/12/reviews/80') + ; + + $api->remove('octocat', 'Hello-World', 12, 80); + } + + /** + * @test + */ + public function shouldShowReviewComments() + { + $expectedValue = [ + [ + 'url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/comments/1', + 'id' => 1, + 'pull_request_review_id' => 42, + 'diff_hunk' => '@@ -16,33 +16,40 @@ public class Connection => IConnection...', + 'path' => 'file1.txt', + 'position' => 1, + 'original_position' => 4, + 'commit_id' => '6dcb09b5b57875f334f61aebed695e2e4193db5e', + 'original_commit_id' => '9c48853fa3dc5c1c3d6f1f1cd1f2743e72652840', + 'user' => [ + 'login' => 'octocat', + 'id' => 1, + 'avatar_url' => 'https://github.com/images/error/octocat_happy.gif', + 'gravatar_id' => '', + 'url' => 'https://api.github.com/users/octocat', + 'html_url' => 'https://github.com/octocat', + 'followers_url' => 'https://api.github.com/users/octocat/followers', + 'following_url' => 'https://api.github.com/users/octocat/following[/other_user]', + 'gists_url' => 'https://api.github.com/users/octocat/gists[/gist_id]', + 'starred_url' => 'https://api.github.com/users/octocat/starred[/owner][/repo]', + 'subscriptions_url' => 'https://api.github.com/users/octocat/subscriptions', + 'organizations_url' => 'https://api.github.com/users/octocat/orgs', + 'repos_url' => 'https://api.github.com/users/octocat/repos', + 'events_url' => 'https://api.github.com/users/octocat/events[/privacy]', + 'received_events_url' => 'https://api.github.com/users/octocat/received_events', + 'type' => 'User', + 'site_admin' => false, + ], + 'body' => 'Great stuff', + 'created_at' => '2011-04-14T16:00:49Z', + 'updated_at' => '2011-04-14T16:00:49Z', + 'html_url' => 'https://github.com/octocat/Hello-World/pull/1#discussion-diff-1', + 'pull_request_url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/1', + '_links' => [ + 'self' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/comments/1', + ], + 'html' => [ + 'href' => 'https://github.com/octocat/Hello-World/pull/1#discussion-diff-1', + ], + 'pull_request' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/1', + ], + ], + ], + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/octocat/Hello-World/pulls/1/reviews/42/comments') + ->willReturn($expectedValue); + + $this->assertSame($expectedValue, $api->comments('octocat', 'Hello-World', 1, 42)); + } + + /** + * @test + */ + public function shouldCreateReviewComment() + { + $data = [ + 'event' => 'APPROVE', + 'body' => 'Nice change', + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->once()) + ->method('post') + ->with('/repos/octocat/Hello-World/pulls/12/reviews') + ; + + $api->create('octocat', 'Hello-World', 12, $data); + } + + /** + * @test + */ + public function shouldCreatePendingReviewWithoutEvent() + { + $data = [ + 'body' => 'Nice change', + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->once()) + ->method('post') + ->with('/repos/octocat/Hello-World/pulls/12/reviews') + ; + + $api->create('octocat', 'Hello-World', 12, $data); + } + + /** + * @test + */ + public function shouldNotCreateReviewWithInvalidEvent() + { + $this->expectException(InvalidArgumentException::class); + $data = [ + 'event' => 'DISMISSED', + 'body' => 'Nice change', + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->never()) + ->method('post') + ; + + $api->create('octocat', 'Hello-World', 12, $data); + } + + /** + * @test + */ + public function shouldSubmitReviewComment() + { + $expectedValue = [ + 'id' => 80, + 'user' => [ + 'login' => 'octocat', + 'id' => 1, + 'avatar_url' => 'https://github.com/images/error/octocat_happy.gif', + 'gravatar_id' => '', + 'url' => 'https://api.github.com/users/octocat', + 'html_url' => 'https://github.com/octocat', + 'followers_url' => 'https://api.github.com/users/octocat/followers', + 'following_url' => 'https://api.github.com/users/octocat/following{/other_user}', + 'gists_url' => 'https://api.github.com/users/octocat/gists{/gist_id}', + 'starred_url' => 'https://api.github.com/users/octocat/starred{/owner}{/repo}', + 'subscriptions_url' => 'https://api.github.com/users/octocat/subscriptions', + 'organizations_url' => 'https://api.github.com/users/octocat/orgs', + 'repos_url' => 'https://api.github.com/users/octocat/repos', + 'events_url' => 'https://api.github.com/users/octocat/events{/privacy}', + 'received_events_url' => 'https://api.github.com/users/octocat/received_events', + 'type' => 'User', + 'site_admin' => false, + ], + 'body' => 'Here is the body for the review.', + 'commit_id' => 'ecdd80bb57125d7ba9641ffaa4d7d2c19d3f3091', + 'state' => 'APPROVED', + 'html_url' => 'https://github.com/octocat/Hello-World/pull/12#pullrequestreview-80', + 'pull_request_url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/12', + '_links' => [ + 'html' => [ + 'href' => 'https://github.com/octocat/Hello-World/pull/12#pullrequestreview-80', + ], + 'pull_request' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/12', + ], + ], + ]; + $data = [ + 'event' => 'APPROVE', + 'body' => 'Nice change', + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->once()) + ->method('post') + ->with('/repos/octocat/Hello-World/pulls/12/reviews/80/events') + ->willReturn($expectedValue); + + $this->assertSame($expectedValue, $api->submit('octocat', 'Hello-World', 12, 80, $data)); + } + + /** + * @test + */ + public function shouldNotSubmitReviewWithoutEvent() + { + $this->expectException(MissingArgumentException::class); + $data = [ + 'body' => 'Nice change', + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->never()) + ->method('post') + ; + + $api->submit('octocat', 'Hello-World', 12, 80, $data); + } + + /** + * @test + */ + public function shouldNotSubmitReviewWithInvalidEvent() + { + $this->expectException(InvalidArgumentException::class); + $data = [ + 'event' => 'DISMISSED', + 'body' => 'Nice change', + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->never()) + ->method('post') + ; + + $api->submit('octocat', 'Hello-World', 12, 80, $data); + } + + /** + * @test + */ + public function shouldDismissReview() + { + $expectedValue = [ + 'id' => 80, + 'user' => [ + 'login' => 'octocat', + 'id' => 1, + 'avatar_url' => 'https://github.com/images/error/octocat_happy.gif', + 'gravatar_id' => '', + 'url' => 'https://api.github.com/users/octocat', + 'html_url' => 'https://github.com/octocat', + 'followers_url' => 'https://api.github.com/users/octocat/followers', + 'following_url' => 'https://api.github.com/users/octocat/following{/other_user}', + 'gists_url' => 'https://api.github.com/users/octocat/gists{/gist_id}', + 'starred_url' => 'https://api.github.com/users/octocat/starred{/owner}{/repo}', + 'subscriptions_url' => 'https://api.github.com/users/octocat/subscriptions', + 'organizations_url' => 'https://api.github.com/users/octocat/orgs', + 'repos_url' => 'https://api.github.com/users/octocat/repos', + 'events_url' => 'https://api.github.com/users/octocat/events{/privacy}', + 'received_events_url' => 'https://api.github.com/users/octocat/received_events', + 'type' => 'User', + 'site_admin' => false, + ], + 'body' => 'Here is the body for the review.', + 'commit_id' => 'ecdd80bb57125d7ba9641ffaa4d7d2c19d3f3091', + 'state' => 'APPROVED', + 'html_url' => 'https://github.com/octocat/Hello-World/pull/12#pullrequestreview-80', + 'pull_request_url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/12', + '_links' => [ + 'html' => [ + 'href' => 'https://github.com/octocat/Hello-World/pull/12#pullrequestreview-80', + ], + 'pull_request' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/12', + ], + ], + ]; + + $api = $this->getApiMock(); + $api + ->expects($this->once()) + ->method('put') + ->with('/repos/octocat/Hello-World/pulls/12/reviews/80/dismissals') + ->willReturn($expectedValue); + + $this->assertSame($expectedValue, $api->dismiss('octocat', 'Hello-World', 12, 80, 'Dismiss reason')); + } + + /** + * @test + */ + public function shouldUpdateReviewComment() + { + $expectedValue = [ + 'id' => 80, + 'node_id' => 'MDE3OlB1bGxSZXF1ZXN0UmV2aWV3ODA=', + 'user' => [ + 'login' => 'octocat', + 'id' => 1, + 'avatar_url' => 'https://github.com/images/error/octocat_happy.gif', + 'gravatar_id' => '', + 'url' => 'https://api.github.com/users/octocat', + 'html_url' => 'https://github.com/octocat', + 'followers_url' => 'https://api.github.com/users/octocat/followers', + 'following_url' => 'https://api.github.com/users/octocat/following{/other_user}', + 'gists_url' => 'https://api.github.com/users/octocat/gists{/gist_id}', + 'starred_url' => 'https://api.github.com/users/octocat/starred{/owner}{/repo}', + 'subscriptions_url' => 'https://api.github.com/users/octocat/subscriptions', + 'organizations_url' => 'https://api.github.com/users/octocat/orgs', + 'repos_url' => 'https://api.github.com/users/octocat/repos', + 'events_url' => 'https://api.github.com/users/octocat/events{/privacy}', + 'received_events_url' => 'https://api.github.com/users/octocat/received_events', + 'type' => 'User', + 'site_admin' => false, + ], + 'body' => 'Great stuff', + 'commit_id' => 'ecdd80bb57125d7ba9641ffaa4d7d2c19d3f3091', + 'state' => 'CHANGES_REQUESTED', + 'html_url' => 'https://github.com/octocat/Hello-World/pull/12#pullrequestreview-80', + 'pull_request_url' => 'https://api.github.com/repos/octocat/Hello-World/pulls/12', + '_links' => [ + 'html' => [ + 'href' => 'https://github.com/octocat/Hello-World/pull/12#pullrequestreview-80', + ], + 'pull_request' => [ + 'href' => 'https://api.github.com/repos/octocat/Hello-World/pulls/12', + ], + ], + ]; + $body = 'Nice change'; + + $api = $this->getApiMock(); + $api + ->expects($this->once()) + ->method('put') + ->with('/repos/octocat/Hello-World/pulls/12/reviews/80') + ->willReturn($expectedValue); + + $this->assertSame($expectedValue, $api->update('octocat', 'Hello-World', 12, 80, $body)); + } + + protected function getApiClass() + { + return Review::class; + } +} diff --git a/test/Github/Tests/Api/PullRequestTest.php b/test/Github/Tests/Api/PullRequestTest.php index ac38dc4513d..54cc34f55e0 100644 --- a/test/Github/Tests/Api/PullRequestTest.php +++ b/test/Github/Tests/Api/PullRequestTest.php @@ -2,6 +2,8 @@ namespace Github\Tests\Api; +use Github\Exception\MissingArgumentException; + class PullRequestTest extends TestCase { /** @@ -9,12 +11,12 @@ class PullRequestTest extends TestCase */ public function shouldGetAllPullRequests() { - $expectedArray = array('pr1', 'pr2'); + $expectedArray = ['pr1', 'pr2']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/ezsystems/ezpublish/pulls') + ->with('/repos/ezsystems/ezpublish/pulls') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->all('ezsystems', 'ezpublish')); @@ -25,15 +27,15 @@ public function shouldGetAllPullRequests() */ public function shouldGetOpenPullRequests() { - $expectedArray = array('pr1', 'pr2'); + $expectedArray = ['pr1', 'pr2']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/ezsystems/ezpublish/pulls', array('state' => 'open', 'per_page' => 30, 'page' => 1)) + ->with('/repos/ezsystems/ezpublish/pulls', ['state' => 'open']) ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->all('ezsystems', 'ezpublish', 'open')); + $this->assertEquals($expectedArray, $api->all('ezsystems', 'ezpublish', ['state' => 'open'])); } /** @@ -41,15 +43,15 @@ public function shouldGetOpenPullRequests() */ public function shouldGetClosedPullRequests() { - $expectedArray = array('pr1', 'pr2'); + $expectedArray = ['pr1', 'pr2']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/ezsystems/ezpublish/pulls', array('state' => 'closed', 'per_page' => 30, 'page' => 1)) + ->with('/repos/ezsystems/ezpublish/pulls', ['state' => 'closed']) ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->all('ezsystems', 'ezpublish', 'closed')); + $this->assertEquals($expectedArray, $api->all('ezsystems', 'ezpublish', ['state' => 'closed'])); } /** @@ -57,13 +59,13 @@ public function shouldGetClosedPullRequests() */ public function shouldShowPullRequest() { - $expectedArray = array('id' => 'id', 'sha' => '123123'); + $expectedArray = ['id' => 'id', 'sha' => '123123']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/ezsystems/ezpublish/pulls/15') + ->with('/repos/ezsystems/ezpublish/pulls/15') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->show('ezsystems', 'ezpublish', '15')); @@ -74,47 +76,101 @@ public function shouldShowPullRequest() */ public function shouldShowCommitsFromPullRequest() { - $expectedArray = array(array('id' => 'id', 'sha' => '123123')); + $expectedArray = [['id' => 'id', 'sha' => '123123']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/ezsystems/ezpublish/pulls/15/commits') + ->with('/repos/ezsystems/ezpublish/pulls/15/commits') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->commits('ezsystems', 'ezpublish', '15')); } + /** + * @test + */ + public function shouldShowCommitsFromPullRequestForPage() + { + $expectedArray = [['id' => 'id', 'sha' => '123123']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/ezsystems/ezpublish/pulls/15/commits', ['page' => 2, 'per_page' => 30]) + ->willReturn($expectedArray); + + $this->assertEquals($expectedArray, $api->commits('ezsystems', 'ezpublish', '15', ['page' => 2, 'per_page' => 30])); + } + /** * @test */ public function shouldShowFilesFromPullRequest() { - $expectedArray = array(array('id' => 'id', 'sha' => '123123')); + $expectedArray = [['id' => 'id', 'sha' => '123123']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/ezsystems/ezpublish/pulls/15/files') + ->with('/repos/ezsystems/ezpublish/pulls/15/files') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->files('ezsystems', 'ezpublish', '15')); } + /** + * @test + */ + public function shouldShowFilesFromPullRequestForPage() + { + $expectedArray = [['id' => 'id', 'sha' => '123123']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/ezsystems/ezpublish/pulls/15/files', ['page' => 2, 'per_page' => 30]) + ->willReturn($expectedArray); + + $this->assertSame($expectedArray, $api->files('ezsystems', 'ezpublish', '15', ['page' => 2, 'per_page' => 30])); + } + + /** + * @test + */ + public function shouldShowStatusesFromPullRequest() + { + $expectedArray = [['id' => 'id', 'sha' => '123123']]; + $expectedArray['_links']['statuses']['href'] = '/repos/ezsystems/ezpublish/pulls/15/statuses'; + + $api = $this->getApiMock(); + + $api->expects($this->exactly(2)) + ->method('get') + ->withConsecutive( + [$this->equalTo('/repos/ezsystems/ezpublish/pulls/15')], + [$this->equalTo('/repos/ezsystems/ezpublish/pulls/15/statuses')] + ) + ->willReturn($expectedArray) + ; + + $this->assertEquals($expectedArray, $api->status('ezsystems', 'ezpublish', '15')); + } + /** * @test */ public function shouldUpdatePullRequests() { - $expectedArray = array('id' => 15, 'sha' => '123123'); + $expectedArray = ['id' => 15, 'sha' => '123123']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('repos/ezsystems/ezpublish/pulls/15', array('state' => 'open', 'some' => 'param')) + ->with('/repos/ezsystems/ezpublish/pulls/15', ['state' => 'open', 'some' => 'param']) ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->update('ezsystems', 'ezpublish', 15, array('state' => 'aa', 'some' => 'param'))); + $this->assertEquals($expectedArray, $api->update('ezsystems', 'ezpublish', 15, ['state' => 'aa', 'some' => 'param'])); } /** @@ -122,12 +178,12 @@ public function shouldUpdatePullRequests() */ public function shouldCheckIfPullRequestIsMerged() { - $expectedArray = array('some' => 'response'); + $expectedArray = ['some' => 'response']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/ezsystems/ezpublish/pulls/15/merge') + ->with('/repos/ezsystems/ezpublish/pulls/15/merge') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->merged('ezsystems', 'ezpublish', 15)); @@ -138,15 +194,47 @@ public function shouldCheckIfPullRequestIsMerged() */ public function shouldMergePullRequest() { - $expectedArray = array('some' => 'response'); + $expectedArray = ['some' => 'response']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('put') - ->with('repos/ezsystems/ezpublish/pulls/15/merge', array('commit_message' => 'Merged something')) + ->with('/repos/ezsystems/ezpublish/pulls/15/merge', ['commit_message' => 'Merged something', 'sha' => str_repeat('A', 40), 'merge_method' => 'merge']) ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->merge('ezsystems', 'ezpublish', 15, 'Merged something')); + $this->assertEquals($expectedArray, $api->merge('ezsystems', 'ezpublish', 15, 'Merged something', str_repeat('A', 40))); + } + + /** + * @test + */ + public function shouldMergePullRequestWithSquashAsBool() + { + $expectedArray = ['some' => 'response']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/repos/ezsystems/ezpublish/pulls/15/merge', ['commit_message' => 'Merged something', 'sha' => str_repeat('A', 40), 'merge_method' => 'squash']) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->merge('ezsystems', 'ezpublish', 15, 'Merged something', str_repeat('A', 40), true)); + } + + /** + * @test + */ + public function shouldMergePullRequestWithMergeMethod() + { + $expectedArray = ['some' => 'response']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/repos/ezsystems/ezpublish/pulls/15/merge', ['commit_message' => 'Merged something', 'sha' => str_repeat('A', 40), 'merge_method' => 'rebase']) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->merge('ezsystems', 'ezpublish', 15, 'Merged something', str_repeat('A', 40), 'rebase')); } /** @@ -154,17 +242,17 @@ public function shouldMergePullRequest() */ public function shouldCreatePullRequestUsingTitle() { - $data = array( - 'base' => 'master', - 'head' => 'virtualtestbranch', + $data = [ + 'base' => 'master', + 'head' => 'virtualtestbranch', 'title' => 'TITLE: Testing pull-request creation from PHP Github API', - 'body' => 'BODY: Testing pull-request creation from PHP Github API' - ); + 'body' => 'BODY: Testing pull-request creation from PHP Github API', + ]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/ezsystems/ezpublish/pulls', $data); + ->with('/repos/ezsystems/ezpublish/pulls', $data); $api->create('ezsystems', 'ezpublish', $data); } @@ -174,31 +262,52 @@ public function shouldCreatePullRequestUsingTitle() */ public function shouldCreatePullRequestUsingIssueId() { - $data = array( - 'base' => 'master', - 'head' => 'virtualtestbranch', - 'issue' => 25 - ); + $data = [ + 'base' => 'master', + 'head' => 'virtualtestbranch', + 'issue' => 25, + ]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/ezsystems/ezpublish/pulls', $data); + ->with('/repos/ezsystems/ezpublish/pulls', $data); + + $api->create('ezsystems', 'ezpublish', $data); + } + + /** + * @test + */ + public function shouldCreateDraftPullRequest() + { + $data = [ + 'base' => 'master', + 'head' => 'virtualtestbranch', + 'title' => 'TITLE: Testing draft pull-request creation from PHP Github API', + 'body' => 'BODY: Testing draft pull-request creation from PHP Github API', + 'draft' => 'true', + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/ezsystems/ezpublish/pulls', $data); $api->create('ezsystems', 'ezpublish', $data); } /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreatePullRequestWithoutBase() { - $data = array( - 'head' => 'virtualtestbranch', + $this->expectException(MissingArgumentException::class); + $data = [ + 'head' => 'virtualtestbranch', 'title' => 'TITLE: Testing pull-request creation from PHP Github API', - 'body' => 'BODY: Testing pull-request creation from PHP Github API' - ); + 'body' => 'BODY: Testing pull-request creation from PHP Github API', + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -209,15 +318,15 @@ public function shouldNotCreatePullRequestWithoutBase() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreatePullRequestWithoutHead() { - $data = array( - 'base' => 'master', + $this->expectException(MissingArgumentException::class); + $data = [ + 'base' => 'master', 'title' => 'TITLE: Testing pull-request creation from PHP Github API', - 'body' => 'BODY: Testing pull-request creation from PHP Github API' - ); + 'body' => 'BODY: Testing pull-request creation from PHP Github API', + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -228,15 +337,15 @@ public function shouldNotCreatePullRequestWithoutHead() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreatePullRequestUsingTitleButWithoutBody() { - $data = array( - 'base' => 'master', - 'head' => 'virtualtestbranch', + $this->expectException(MissingArgumentException::class); + $data = [ + 'base' => 'master', + 'head' => 'virtualtestbranch', 'title' => 'TITLE: Testing pull-request creation from PHP Github API', - ); + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -247,14 +356,14 @@ public function shouldNotCreatePullRequestUsingTitleButWithoutBody() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreatePullRequestWithoutIssueIdOrTitle() { - $data = array( - 'base' => 'master', - 'head' => 'virtualtestbranch', - ); + $this->expectException(MissingArgumentException::class); + $data = [ + 'base' => 'master', + 'head' => 'virtualtestbranch', + ]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -270,11 +379,24 @@ public function shouldGetCommentsApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\PullRequest\Comments', $api->comments()); + $this->assertInstanceOf(\Github\Api\PullRequest\Comments::class, $api->comments()); } + /** + * @test + */ + public function shouldGetReviewApiObject() + { + $api = $this->getApiMock(); + + $this->assertInstanceOf(\Github\Api\PullRequest\Review::class, $api->reviews()); + } + + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\PullRequest'; + return \Github\Api\PullRequest::class; } } diff --git a/test/Github/Tests/Api/RateLimitTest.php b/test/Github/Tests/Api/RateLimitTest.php new file mode 100644 index 00000000000..d13d001d890 --- /dev/null +++ b/test/Github/Tests/Api/RateLimitTest.php @@ -0,0 +1,90 @@ + [ + 'core' => [ + 'limit' => 5000, + 'remaining' => 4999, + 'reset' => 1372700873, + ], + 'search' => [ + 'limit' => 30, + 'remaining' => 18, + 'reset' => 1372697452, + ], + 'graphql' => [ + 'limit' => 5000, + 'remaining' => 4030, + 'reset' => 1372697452, + ], + ], + ]; + + /** + * @var RateLimit + */ + protected $api; + + /** + * @before + */ + public function initMocks() + { + $this->api = $this->getApiMock(); + $this->api->expects($this->once()) + ->method('get') + ->with('/rate_limit') + ->will($this->returnValue($this->expectedArray)); + } + + /** + * @test + */ + public function shouldReturnArrayOfLimitInstances() + { + $this->assertContainsOnlyInstancesOf(RateLimit\RateLimitResource::class, $this->api->getResources()); + } + + /** + * @test + */ + public function shouldReturnRemainingGraphQLRequests() + { + $this->assertSame(4030, $this->api->getResource('graphql')->getRemaining()); + } + + /** + * @test + */ + public function shouldReturnResetForSearch() + { + $this->assertSame(1372697452, $this->api->getResource('search')->getReset()); + } + + /** + * @test + */ + public function shouldReturnFalseWhenResourceIsNotFound() + { + $this->assertFalse($this->api->getResource('non-exitent')); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\RateLimit::class; + } +} diff --git a/test/Github/Tests/Api/RepoTest.php b/test/Github/Tests/Api/RepoTest.php index db125a72622..786c27d97b5 100644 --- a/test/Github/Tests/Api/RepoTest.php +++ b/test/Github/Tests/Api/RepoTest.php @@ -2,6 +2,9 @@ namespace Github\Tests\Api; +use Github\Api\Repo; +use PHPUnit\Framework\MockObject\MockObject; + class RepoTest extends TestCase { /** @@ -9,12 +12,12 @@ class RepoTest extends TestCase */ public function shouldShowRepository() { - $expectedArray = array('id' => 1, 'name' => 'repoName'); + $expectedArray = ['id' => 1, 'name' => 'repoName']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api') + ->with('/repos/KnpLabs/php-github-api') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->show('KnpLabs', 'php-github-api')); @@ -23,39 +26,59 @@ public function shouldShowRepository() /** * @test */ - public function shouldSearchRepositories() + public function shouldShowRepositoryById() { - $expectedArray = array( - array('id' => 1, 'name' => 'php'), - array('id' => 2, 'name' => 'php-cs') - ); + $expectedArray = ['id' => 123456, 'name' => 'repoName']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('legacy/repos/search/php', array('myparam' => 2, 'start_page' => 1)) + ->with('/repositories/123456') ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->find('php', array('myparam' => 2))); + $this->assertEquals($expectedArray, $api->showById(123456)); } /** * @test */ - public function shouldPaginateFoundRepositories() + public function shouldGetAllRepositories() { - $expectedArray = array( - array('id' => 3, 'name' => 'fork of php'), - array('id' => 4, 'name' => 'fork of php-cs') - ); + $expectedArray = [ + ['id' => 1, 'name' => 'dummy project'], + ['id' => 2, 'name' => 'awesome another project'], + ['id' => 3, 'name' => 'fork of php'], + ['id' => 4, 'name' => 'fork of php-cs'], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repositories') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all()); + } + + /** + * @test + */ + public function shouldGetAllRepositoriesStartingIndex() + { + $expectedArray = [ + ['id' => 1, 'name' => 'dummy project'], + ['id' => 2, 'name' => 'awesome another project'], + ['id' => 3, 'name' => 'fork of php'], + ['id' => 4, 'name' => 'fork of php-cs'], + ]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('legacy/repos/search/php', array('start_page' => 2)) + ->with('/repositories', ['since' => 2]) ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->find('php', array('start_page' => 2))); + $this->assertEquals($expectedArray, $api->all(2)); } /** @@ -63,21 +86,22 @@ public function shouldPaginateFoundRepositories() */ public function shouldCreateRepositoryUsingNameOnly() { - $expectedArray = array('id' => 1, 'name' => 'l3l0Repo'); + $expectedArray = ['id' => 1, 'name' => 'l3l0Repo']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('user/repos', array( - 'name' => 'l3l0Repo', - 'description' => '', - 'homepage' => '', - 'private' => false, - 'has_issues' => false, - 'has_wiki' => false, + ->with('/user/repos', [ + 'name' => 'l3l0Repo', + 'description' => '', + 'homepage' => '', + 'private' => false, + 'has_issues' => false, + 'has_wiki' => false, 'has_downloads' => false, - 'auto_init' => false - )) + 'auto_init' => false, + 'has_projects' => true, + ]) ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->create('l3l0Repo')); @@ -88,21 +112,22 @@ public function shouldCreateRepositoryUsingNameOnly() */ public function shouldCreateRepositoryForOrganization() { - $expectedArray = array('id' => 1, 'name' => 'KnpLabsRepo'); + $expectedArray = ['id' => 1, 'name' => 'KnpLabsRepo']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('orgs/KnpLabs/repos', array( - 'name' => 'KnpLabsRepo', - 'description' => '', - 'homepage' => '', - 'private' => false, - 'has_issues' => false, - 'has_wiki' => false, + ->with('/orgs/KnpLabs/repos', [ + 'name' => 'KnpLabsRepo', + 'description' => '', + 'homepage' => '', + 'private' => false, + 'has_issues' => false, + 'has_wiki' => false, 'has_downloads' => false, - 'auto_init' => false - )) + 'auto_init' => false, + 'has_projects' => true, + ]) ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->create('KnpLabsRepo', '', '', true, 'KnpLabs')); @@ -111,17 +136,60 @@ public function shouldCreateRepositoryForOrganization() /** * @test */ - public function shouldGetRepositoryWatchers() + public function shouldCreateRepositoryWithInternalVisibility() { - $expectedArray = array(array('id' => 1, 'username' => 'l3l0')); + $expectedArray = ['id' => 1, 'name' => 'KnpLabsRepo']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/user/repos', [ + 'name' => 'KnpLabsRepo', + 'description' => '', + 'homepage' => '', + 'has_issues' => false, + 'has_wiki' => false, + 'has_downloads' => false, + 'auto_init' => false, + 'has_projects' => true, + 'visibility' => 'internal', + 'private' => false, + ]) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals( + $expectedArray, + $api->create( + 'KnpLabsRepo', + '', + '', + false, + null, + false, + false, + false, + null, + false, + true, + 'internal' + ) + ); + } + + /** + * @test + */ + public function shouldGetRepositorySubscribers() + { + $expectedArray = [['id' => 1, 'username' => 'l3l0']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/watchers', array('page' => 2)) + ->with('/repos/KnpLabs/php-github-api/subscribers', ['page' => 2]) ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->watchers('KnpLabs', 'php-github-api', 2)); + $this->assertEquals($expectedArray, $api->subscribers('KnpLabs', 'php-github-api', 2)); } /** @@ -129,12 +197,12 @@ public function shouldGetRepositoryWatchers() */ public function shouldGetRepositoryTags() { - $expectedArray = array(array('sha' => 1234)); + $expectedArray = [['sha' => 1234]]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/tags') + ->with('/repos/KnpLabs/php-github-api/tags') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->tags('KnpLabs', 'php-github-api')); @@ -145,12 +213,12 @@ public function shouldGetRepositoryTags() */ public function shouldGetRepositoryBranches() { - $expectedArray = array(array('sha' => 1234, 'name' => 'master')); + $expectedArray = [['sha' => 1234, 'name' => 'master']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/branches') + ->with('/repos/KnpLabs/php-github-api/branches') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->branches('KnpLabs', 'php-github-api')); @@ -161,44 +229,118 @@ public function shouldGetRepositoryBranches() */ public function shouldGetRepositoryBranch() { - $expectedArray = array('sha' => 1234, 'name' => 'master'); + $expectedArray = ['sha' => 1234, 'name' => 'master']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/branches/master') + ->with('/repos/KnpLabs/php-github-api/branches/master') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->branches('KnpLabs', 'php-github-api', 'master')); } + /** + * @test + */ + public function shouldMergeUpstreamRepository() + { + $expectedArray = [ + 'message' => 'Successfully fetched and fast-forwarded from upstream upstreamRepo:main', + 'merge_type' => 'fast-forward', + 'merge_branch' => 'upstreamRepo:main', + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/merge-upstream', ['branch' => 'main']) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->mergeUpstream('KnpLabs', 'php-github-api', 'main')); + } + /** * @test */ public function shouldGetRepositoryLanguages() { - $expectedArray = array('lang1', 'lang2'); + $expectedArray = ['lang1', 'lang2']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/languages') + ->with('/repos/KnpLabs/php-github-api/languages') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->languages('KnpLabs', 'php-github-api')); } + /** + * @test + */ + public function shouldGetRepositoryMilestones() + { + $expectedArray = ['milestone1', 'milestone2']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/milestones') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->milestones('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldEnableAutomatedSecurityFixes() + { + $expectedResponse = 'response'; + + /** @var Repo|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('put') + ->with('/repos/KnpLabs/php-github-api/automated-security-fixes') + ->will($this->returnValue($expectedResponse)); + + $this->assertEquals($expectedResponse, $api->enableAutomatedSecurityFixes('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldDisableAutomatedSecurityFixes() + { + $expectedResponse = 'response'; + + /** @var Repo|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/automated-security-fixes') + ->will($this->returnValue($expectedResponse)); + + $this->assertEquals($expectedResponse, $api->disableAutomatedSecurityFixes('KnpLabs', 'php-github-api')); + } + /** * @test */ public function shouldGetContributorsExcludingAnonymousOnes() { - $expectedArray = array('contrib1', 'contrib2'); + $expectedArray = ['contrib1', 'contrib2']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/contributors', array('anon' => null)) + ->with('/repos/KnpLabs/php-github-api/contributors', ['anon' => null]) ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->contributors('KnpLabs', 'php-github-api', false)); @@ -209,12 +351,12 @@ public function shouldGetContributorsExcludingAnonymousOnes() */ public function shouldGetContributorsIncludingAnonymousOnes() { - $expectedArray = array('contrib1', 'contrib2'); + $expectedArray = ['contrib1', 'contrib2']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/contributors', array('anon' => true)) + ->with('/repos/KnpLabs/php-github-api/contributors', ['anon' => true]) ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->contributors('KnpLabs', 'php-github-api', true)); @@ -225,12 +367,12 @@ public function shouldGetContributorsIncludingAnonymousOnes() */ public function shouldGetRepositoryTeams() { - $expectedArray = array(array('id' => 1234), array('id' => 2345)); + $expectedArray = [['id' => 1234], ['id' => 2345]]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/teams') + ->with('/repos/KnpLabs/php-github-api/teams') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->teams('KnpLabs', 'php-github-api')); @@ -241,21 +383,22 @@ public function shouldGetRepositoryTeams() */ public function shouldCreateUsingAllParams() { - $expectedArray = array('id' => 1, 'name' => 'l3l0Repo'); + $expectedArray = ['id' => 1, 'name' => 'l3l0Repo']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('user/repos', array( - 'name' => 'l3l0Repo', - 'description' => 'test', - 'homepage' => 'http://l3l0.eu', - 'private' => true, - 'has_issues' => false, - 'has_wiki' => false, + ->with('/user/repos', [ + 'name' => 'l3l0Repo', + 'description' => 'test', + 'homepage' => 'http://l3l0.eu', + 'private' => true, + 'has_issues' => false, + 'has_wiki' => false, 'has_downloads' => false, - 'auto_init' => false - )) + 'auto_init' => false, + 'has_projects' => true, + ]) ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->create('l3l0Repo', 'test', 'http://l3l0.eu', false)); @@ -266,15 +409,15 @@ public function shouldCreateUsingAllParams() */ public function shouldUpdate() { - $expectedArray = array('id' => 1, 'name' => 'l3l0Repo'); + $expectedArray = ['id' => 1, 'name' => 'l3l0Repo']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('repos/l3l0Repo/test', array('description' => 'test', 'homepage' => 'http://l3l0.eu')) + ->with('/repos/l3l0Repo/test', ['description' => 'test', 'homepage' => 'http://l3l0.eu']) ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->update('l3l0Repo', 'test', array('description' => 'test', 'homepage' => 'http://l3l0.eu'))); + $this->assertEquals($expectedArray, $api->update('l3l0Repo', 'test', ['description' => 'test', 'homepage' => 'http://l3l0.eu'])); } /** @@ -285,7 +428,7 @@ public function shouldDelete() $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('repos/l3l0Repo/test') + ->with('/repos/l3l0Repo/test') ->will($this->returnValue(null)); $this->assertNull($api->remove('l3l0Repo', 'test')); @@ -296,15 +439,15 @@ public function shouldDelete() */ public function shouldNotDelete() { - $expectedArray = array('message' => 'Not Found'); + $expectedArray = ['message' => 'Not Found']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('repos/l3l0Repo/uknown-repo') + ->with('/repos/l3l0Repo/unknown-repo') ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->remove('l3l0Repo', 'uknown-repo')); + $this->assertEquals($expectedArray, $api->remove('l3l0Repo', 'unknown-repo')); } /** @@ -314,7 +457,7 @@ public function shouldGetCollaboratorsApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\Repository\Collaborators', $api->collaborators()); + $this->assertInstanceOf(\Github\Api\Repository\Collaborators::class, $api->collaborators()); } /** @@ -324,7 +467,7 @@ public function shouldGetCommentsApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\Repository\Comments', $api->comments()); + $this->assertInstanceOf(\Github\Api\Repository\Comments::class, $api->comments()); } /** @@ -334,7 +477,7 @@ public function shouldGetCommitsApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\Repository\Commits', $api->commits()); + $this->assertInstanceOf(\Github\Api\Repository\Commits::class, $api->commits()); } /** @@ -344,7 +487,7 @@ public function shouldGetContentsApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\Repository\Contents', $api->contents()); + $this->assertInstanceOf(\Github\Api\Repository\Contents::class, $api->contents()); } /** @@ -354,7 +497,7 @@ public function shouldGetDeployKeysApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\Repository\DeployKeys', $api->keys()); + $this->assertInstanceOf(\Github\Api\Repository\DeployKeys::class, $api->keys()); } /** @@ -364,7 +507,7 @@ public function shouldGetDownloadsApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\Repository\Downloads', $api->downloads()); + $this->assertInstanceOf(\Github\Api\Repository\Downloads::class, $api->downloads()); } /** @@ -374,7 +517,7 @@ public function shouldGetForksApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\Repository\Forks', $api->forks()); + $this->assertInstanceOf(\Github\Api\Repository\Forks::class, $api->forks()); } /** @@ -384,7 +527,7 @@ public function shouldGetHooksApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\Repository\Hooks', $api->hooks()); + $this->assertInstanceOf(\Github\Api\Repository\Hooks::class, $api->hooks()); } /** @@ -394,7 +537,7 @@ public function shouldGetLabelsApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\Repository\Labels', $api->labels()); + $this->assertInstanceOf(\Github\Api\Repository\Labels::class, $api->labels()); } /** @@ -404,7 +547,17 @@ public function shouldGetStatusesApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\Repository\Statuses', $api->statuses()); + $this->assertInstanceOf(\Github\Api\Repository\Statuses::class, $api->statuses()); + } + + /** + * @test + */ + public function shouldGetStargazersApiObject() + { + $api = $this->getApiMock(); + + $this->assertInstanceOf(\Github\Api\Repository\Stargazers::class, $api->stargazers()); } /** @@ -414,11 +567,223 @@ public function shouldGetReleasesApiObject() { $api = $this->getApiMock(); - $this->assertInstanceOf('Github\Api\Repository\Releases', $api->releases()); + $this->assertInstanceOf(\Github\Api\Repository\Releases::class, $api->releases()); } + /** + * @test + */ + public function shouldGetVariablesApiObject() + { + $api = $this->getApiMock(); + + $this->assertInstanceOf(\Github\Api\Repository\Actions\Variables::class, $api->variables()); + } + + /** + * @test + */ + public function shouldGetCommitActivity() + { + $expectedArray = [['days' => [0, 3, 26, 20, 39, 1, 0], 'total' => 89, 'week' => 1336280400]]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/stats/commit_activity') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->activity('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldGetRepositoryEvents() + { + $expectedArray = ['id' => 6122723754, 'type' => 'ForkEvent']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/events', [ + 'page' => 3, + ]) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->events('KnpLabs', 'php-github-api', 3)); + } + + /** + * @test + */ + public function shouldGetRepositoryCommunityProfile() + { + $expectedArray = ['health_percentage' => 100, 'description' => 'A simple PHP GitHub API client...']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/community/profile') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->communityProfile('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldGetRepositoryCodeOfConduct() + { + $expectedArray = ['name' => 'Contributor Covenant', 'url' => 'http://...']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/community/code_of_conduct') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->codeOfConduct('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldGetRepositoryTopics() + { + $expectedArray = ['names' => ['octocat', 'atom', 'electron', 'API']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/topics') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->topics('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldReplaceRepositoryTopics() + { + $expectedArray = ['id' => 6122723754, 'type' => 'ForkEvent']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/repos/KnpLabs/php-github-api/topics', [ + 'names' => ['octocat', 'atom', 'electron', 'API'], + ]) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->replaceTopics('KnpLabs', 'php-github-api', ['octocat', 'atom', 'electron', 'API'])); + } + + /** + * @test + */ + public function shouldTransferRepository() + { + $expectedArray = ['id' => 1, 'name' => 'php-github-api']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/transfer', [ + 'new_owner' => 'github', + 'team_id' => [1234, 1235], + ]) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->transfer('KnpLabs', 'php-github-api', 'github', [1234, 1235])); + } + + /** + * @test + */ + public function shouldCreateRepositoryUsingTemplate() + { + $expectedArray = [ + 'id' => 1, + 'name' => 'newrepo', + 'full_name' => 'johndoe/newrepo', + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/acme/template/generate', [ + 'name' => 'newrepo', + 'owner' => 'johndoe', + ]) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->createFromTemplate('acme', 'template', [ + 'name' => 'newrepo', + 'owner' => 'johndoe', + ])); + } + + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Repo'; + return \Github\Api\Repo::class; + } + + /** + * @test + */ + public function shouldCheckVulnerabilityAlertsEnabled() + { + $expectedResponse = ''; + + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/vulnerability-alerts') + ->will($this->returnValue($expectedResponse)); + + $this->assertEquals($expectedResponse, $api->isVulnerabilityAlertsEnabled('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldEnableVulnerabilityAlerts() + { + $expectedResponse = ''; + + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('put') + ->with('/repos/KnpLabs/php-github-api/vulnerability-alerts') + ->will($this->returnValue($expectedResponse)); + + $this->assertEquals($expectedResponse, $api->enableVulnerabilityAlerts('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldDisableVulnerabilityAlerts() + { + $expectedResponse = ''; + + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/vulnerability-alerts') + ->will($this->returnValue($expectedResponse)); + + $this->assertEquals($expectedResponse, $api->disableVulnerabilityAlerts('KnpLabs', 'php-github-api')); } } diff --git a/test/Github/Tests/Api/Repository/Actions/ArtifactsTest.php b/test/Github/Tests/Api/Repository/Actions/ArtifactsTest.php new file mode 100644 index 00000000000..90ace988bab --- /dev/null +++ b/test/Github/Tests/Api/Repository/Actions/ArtifactsTest.php @@ -0,0 +1,96 @@ + 'id', + 'node_id' => 'node_id', + 'name' => 'name', + 'size_in_bytes' => 453, + 'url' => 'foo', + 'archive_download_url' => 'foo', + 'expired' => false, + 'created_at' => '2020-01-10T14:59:22Z', + 'expires_at' => '2020-01-21T14:59:22Z', + ], + ]; + + /** @var Artifacts|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/artifacts') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldGetRunArtifacts() + { + $expectedArray = [ + [ + 'id' => 'id', + 'node_id' => 'node_id', + 'name' => 'name', + 'size_in_bytes' => 453, + 'url' => 'foo', + 'archive_download_url' => 'foo', + 'expired' => false, + 'created_at' => '2020-01-10T14:59:22Z', + 'expires_at' => '2020-01-21T14:59:22Z', + ], + ]; + + /** @var Artifacts|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/runs/1/artifacts') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->runArtifacts('KnpLabs', 'php-github-api', 1)); + } + + /** + * @test + */ + public function shouldRemoveArtifact() + { + $expectedValue = 'response'; + + /** @var Artifacts|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/actions/artifacts/1') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', 1)); + } + + protected function getApiClass() + { + return Artifacts::class; + } +} diff --git a/test/Github/Tests/Api/Repository/Actions/SecretsTest.php b/test/Github/Tests/Api/Repository/Actions/SecretsTest.php new file mode 100644 index 00000000000..5a5e20a4616 --- /dev/null +++ b/test/Github/Tests/Api/Repository/Actions/SecretsTest.php @@ -0,0 +1,136 @@ + 'GH_TOKEN', 'created_at' => 'created_at', 'updated_at' => 'updated_at'], + ['name' => 'GIST_ID', 'created_at' => 'created_at', 'updated_at' => 'updated_at'], + ]; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/secrets') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldGetSecret() + { + $expectedArray = ['name' => 'name', 'created_at' => 'created_at', 'updated_at' => 'updated_at']; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/secrets/secretName') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show('KnpLabs', 'php-github-api', 'secretName')); + } + + /** + * @test + */ + public function shouldCreateSecret() + { + $expectedValue = 'response'; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('put') + ->with('/repos/KnpLabs/php-github-api/actions/secrets/secretName') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', 'secretName', [ + 'encrypted_value' => 'encryptedValue', + ])); + } + + /** + * @test + */ + public function shouldUpdateSecret() + { + $expectedValue = 'response'; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('put') + ->with('/repos/KnpLabs/php-github-api/actions/secrets/secretName') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->update('KnpLabs', 'php-github-api', 'secretName', [ + 'key_id' => 'keyId', 'encrypted_value' => 'encryptedValue', + ])); + } + + /** + * @test + */ + public function shouldRemoveSecret() + { + $expectedValue = 'response'; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/actions/secrets/secretName') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', 'secretName')); + } + + /** + * @test + */ + public function shouldGetPublicKey() + { + $expectedArray = ['key_id' => 'key_id', 'key' => 'foo']; + + /** @var Secrets|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/secrets/public-key') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->publicKey('KnpLabs', 'php-github-api')); + } + + protected function getApiClass() + { + return Secrets::class; + } +} diff --git a/test/Github/Tests/Api/Repository/Actions/SelfHostedRunnersTest.php b/test/Github/Tests/Api/Repository/Actions/SelfHostedRunnersTest.php new file mode 100644 index 00000000000..67c8eade4bd --- /dev/null +++ b/test/Github/Tests/Api/Repository/Actions/SelfHostedRunnersTest.php @@ -0,0 +1,115 @@ + 1, + 'name' => 'MBP', + 'os' => 'macos', + 'status' => 'online', + ], + [ + 'id' => 2, + 'name' => 'iMac', + 'os' => 'macos', + 'status' => 'offline', + ], + ]; + + /** @var SelfHostedRunners|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/runners') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldGetSelfHostedRunner() + { + $expectedArray = [ + 'id' => 1, + 'name' => 'MBP', + 'os' => 'macos', + 'status' => 'online', + ]; + + /** @var SelfHostedRunners|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/runners/1') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show('KnpLabs', 'php-github-api', 1)); + } + + /** + * @test + */ + public function shouldRemoveSelfHostedRunner() + { + $expectedValue = 'response'; + + /** @var SelfHostedRunners|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/actions/runners/1') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', 1)); + } + + /** + * @test + */ + public function shouldGetSelfHostedRunnerApps() + { + $expectedArray = [ + ['os' => 'osx', 'architecture' => 'x64', 'download_url' => 'download_url', 'filename' => 'filename'], + ['os' => 'linux', 'architecture' => 'x64', 'download_url' => 'download_url', 'filename' => 'filename'], + ['os' => 'linux', 'architecture' => 'arm', 'download_url' => 'download_url', 'filename' => 'filename'], + ['os' => 'win', 'architecture' => 'x64', 'download_url' => 'download_url', 'filename' => 'filename'], + ['os' => 'linux', 'architecture' => 'arm64', 'download_url' => 'download_url', 'filename' => 'filename'], + ]; + + /** @var SelfHostedRunners|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/runners/downloads') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->applications('KnpLabs', 'php-github-api')); + } + + protected function getApiClass() + { + return SelfHostedRunners::class; + } +} diff --git a/test/Github/Tests/Api/Repository/Actions/VariablesTest.php b/test/Github/Tests/Api/Repository/Actions/VariablesTest.php new file mode 100644 index 00000000000..e362d31f7bc --- /dev/null +++ b/test/Github/Tests/Api/Repository/Actions/VariablesTest.php @@ -0,0 +1,119 @@ + 'GH_TOKEN', 'value' => 'value', 'created_at' => 'created_at', 'updated_at' => 'updated_at'], + ['name' => 'GIST_ID', 'value' => 'value', 'created_at' => 'created_at', 'updated_at' => 'updated_at'], + ]; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/variables') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldGetVariable() + { + $expectedArray = ['name' => 'name', 'value' => 'value', 'created_at' => 'created_at', 'updated_at' => 'updated_at']; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/variables/variableName') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show('KnpLabs', 'php-github-api', 'variableName')); + } + + /** + * @test + */ + public function shouldCreateVariable() + { + $expectedValue = 'response'; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/actions/variables') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', [ + 'name' => 'name', + 'value' => 'value', + ])); + } + + /** + * @test + */ + public function shouldUpdateVariable() + { + $expectedValue = 'response'; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('patch') + ->with('/repos/KnpLabs/php-github-api/actions/variables/variableName') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->update('KnpLabs', 'php-github-api', 'variableName', [ + 'name' => 'name', + 'value' => 'value', + ])); + } + + /** + * @test + */ + public function shouldRemoveVariable() + { + $expectedValue = 'response'; + + /** @var Variables|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/actions/variables/variableName') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', 'variableName')); + } + + protected function getApiClass() + { + return Variables::class; + } +} diff --git a/test/Github/Tests/Api/Repository/Actions/WorkflowJobsTest.php b/test/Github/Tests/Api/Repository/Actions/WorkflowJobsTest.php new file mode 100644 index 00000000000..4af8b52ebc9 --- /dev/null +++ b/test/Github/Tests/Api/Repository/Actions/WorkflowJobsTest.php @@ -0,0 +1,57 @@ + 'id', 'run_id' => 'run_id', 'status' => 'completed', 'conclusion' => 'success'], + ]; + + /** @var WorkflowJobs|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/runs/1/jobs') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all('KnpLabs', 'php-github-api', 1)); + } + + /** + * @test + */ + public function shouldShowWorkflowJob() + { + $expectedArray = [ + 'id' => 'id', 'run_id' => 'run_id', 'status' => 'completed', 'conclusion' => 'success', + ]; + + /** @var WorkflowJobs|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/jobs/1') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show('KnpLabs', 'php-github-api', 1)); + } + + protected function getApiClass() + { + return WorkflowJobs::class; + } +} diff --git a/test/Github/Tests/Api/Repository/Actions/WorkflowRunsTest.php b/test/Github/Tests/Api/Repository/Actions/WorkflowRunsTest.php new file mode 100644 index 00000000000..1c5af0badc9 --- /dev/null +++ b/test/Github/Tests/Api/Repository/Actions/WorkflowRunsTest.php @@ -0,0 +1,223 @@ + 'id', + 'event' => 'push', + 'status' => 'queued', + ], + ]; + + /** @var WorkflowRuns|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/runs') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldGetWorkflowRuns() + { + $expectedArray = [ + [ + 'id' => 'id', + 'name' => 'CI', + 'event' => 'push', + 'status' => 'completed', + 'conclusion' => 'success', + 'workflow_id' => 3441570, + ], + ]; + + /** @var WorkflowRuns|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/workflows/3441570/runs') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->listRuns('KnpLabs', 'php-github-api', 3441570)); + } + + /** + * @test + */ + public function shouldShowWorkflowRun() + { + $expectedArray = ['id' => 'id', 'name' => 'CI']; + + /** @var WorkflowRuns|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/runs/374473304') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show('KnpLabs', 'php-github-api', 374473304)); + } + + /** + * @test + */ + public function shouldDeleteWorkflowRun() + { + $expectedValue = 'response'; + + /** @var WorkflowRuns|MockObject $api */ + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/actions/runs/374473304') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', 374473304)); + } + + /** + * @test + */ + public function shouldGetWorkflowRunUsage() + { + $expectedArray = [ + 'billable' => [ + 'UBUNTU' => ['total_ms' => 180000, 'jobs' => 1], + 'MACOS' => ['total_ms' => 240000, 'jobs' => 1], + 'WINDOWS' => ['total_ms' => 300000, 'jobs' => 1], + ], + 'run_duration_ms' => 500000, + ]; + + /** @var WorkflowRuns|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/runs/374473304/timing') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->usage('KnpLabs', 'php-github-api', 374473304)); + } + + /** + * @test + */ + public function shouldRerunWorkflowRun() + { + $expectedValue = 'response'; + + /** @var WorkflowRuns|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/actions/runs/374473304/rerun') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->rerun('KnpLabs', 'php-github-api', 374473304)); + } + + /** + * @test + */ + public function shouldCancelWorkflowRun() + { + $expectedValue = 'response'; + + /** @var WorkflowRuns|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/actions/runs/374473304/cancel') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->cancel('KnpLabs', 'php-github-api', 374473304)); + } + + /** + * @test + */ + public function shouldDownloadWorkflowRunLogs() + { + $expectedValue = 'response'; + + /** @var WorkflowRuns|MockObject $api */ + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/runs/374473304/logs') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->downloadLogs('KnpLabs', 'php-github-api', 374473304)); + } + + /** + * @test + */ + public function shouldDeleteWorkflowRunLogs() + { + $expectedValue = 'response'; + + /** @var WorkflowRuns|MockObject $api */ + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/actions/runs/374473304/logs') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->deleteLogs('KnpLabs', 'php-github-api', 374473304)); + } + + /** + * @test + */ + public function shouldApproveWorkflowRunLogs() + { + $expectedValue = 'response'; + + /** @var WorkflowRuns|MockObject $api */ + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/actions/runs/374473304/approve') + ->will($this->returnValue($expectedValue)); + + $this->assertSame($expectedValue, $api->approve('KnpLabs', 'php-github-api', 374473304)); + } + + protected function getApiClass() + { + return WorkflowRuns::class; + } +} diff --git a/test/Github/Tests/Api/Repository/Actions/WorkflowsTest.php b/test/Github/Tests/Api/Repository/Actions/WorkflowsTest.php new file mode 100644 index 00000000000..7413fc5d7c0 --- /dev/null +++ b/test/Github/Tests/Api/Repository/Actions/WorkflowsTest.php @@ -0,0 +1,116 @@ + 'id', + 'node_id' => 'node_id', + 'name' => 'CI', + 'path' => '.github/workflows/ci.yml', + 'state' => 'active', + 'created_at' => '2020-11-07T15:09:45.000Z', + 'updated_at' => '2020-11-07T15:09:45.000Z', + ], + ]; + + /** @var Workflows|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/workflows') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldShowWorkflow() + { + $expectedArray = [ + 'id' => 'id', + 'node_id' => 'node_id', + 'name' => 'CI', + 'path' => '.github/workflows/ci.yml', + 'state' => 'active', + 'created_at' => '2020-11-07T15:09:45.000Z', + 'updated_at' => '2020-11-07T15:09:45.000Z', + ]; + + /** @var Workflows|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/workflows/1') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->show('KnpLabs', 'php-github-api', 1)); + } + + /** + * @test + */ + public function shouldGetWorkflowUsage() + { + $expectedArray = [ + 'billable' => [ + 'UBUNTU' => ['total_ms' => 180000, 'jobs' => 1], + 'MACOS' => ['total_ms' => 240000, 'jobs' => 1], + 'WINDOWS' => ['total_ms' => 300000, 'jobs' => 1], + ], + ]; + + /** @var Workflows|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/actions/workflows/1/timing') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->usage('KnpLabs', 'php-github-api', 1)); + } + + /** + * @test + */ + public function shouldDispatchWorkflow() + { + // empty + $expectedArray = []; + + /** @var Workflows|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/actions/workflows/1/dispatches') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->dispatches('KnpLabs', 'php-github-api', 1, 'main')); + } + + protected function getApiClass() + { + return Workflows::class; + } +} diff --git a/test/Github/Tests/Api/Repository/AssetsTest.php b/test/Github/Tests/Api/Repository/AssetsTest.php index 2e560193a6c..6cea75fe975 100644 --- a/test/Github/Tests/Api/Repository/AssetsTest.php +++ b/test/Github/Tests/Api/Repository/AssetsTest.php @@ -2,6 +2,7 @@ namespace Github\Tests\Api\Repository; +use Github\Exception\MissingArgumentException; use Github\Tests\Api\TestCase; class AssetsTest extends TestCase @@ -11,13 +12,13 @@ class AssetsTest extends TestCase */ public function shouldGetAllReleaseAssets() { - $expectedValue = array(array('asset1data'), array('asset2data')); + $expectedValue = [['asset1data'], ['asset2data']]; $id = 76; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/releases/'.$id.'/assets') + ->with('/repos/KnpLabs/php-github-api/releases/'.$id.'/assets') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api', $id)); @@ -28,13 +29,13 @@ public function shouldGetAllReleaseAssets() */ public function shouldGetSingleReleaseAsset() { - $expectedValue = array('assetData'); + $expectedValue = ['assetData']; $assetId = 2; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/releases/assets/'.$assetId) + ->with('/repos/KnpLabs/php-github-api/releases/assets/'.$assetId) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', $assetId)); @@ -42,10 +43,17 @@ public function shouldGetSingleReleaseAsset() /** * @test + * * @requires PHP 5.3.4 */ public function shouldCreateReleaseAsset() { + if (!defined('OPENSSL_TLSEXT_SERVER_NAME') || !OPENSSL_TLSEXT_SERVER_NAME) { + return $this->markTestSkipped( + 'Asset upload support requires Server Name Indication. This is not supported by your PHP version.' + ); + } + $name = 'asset.gzip'; $body = 'assetCreatedData'; $contentType = 'application/gzip'; @@ -54,7 +62,7 @@ public function shouldCreateReleaseAsset() $api = $this->getApiMock(); $api->expects($this->once()) ->method('postRaw') - ->with('repos/KnpLabs/php-github-api/releases/'. $releaseId .'/assets?name='.$name) + ->with('https://uploads.github.com/repos/KnpLabs/php-github-api/releases/'.$releaseId.'/assets?name='.$name) ->will($this->returnValue($body)); $this->assertEquals($body, $api->create('KnpLabs', 'php-github-api', $releaseId, $name, $contentType, $body)); @@ -65,14 +73,14 @@ public function shouldCreateReleaseAsset() */ public function shouldEditReleaseAsset() { - $expectedValue = array('assetUpdatedData'); + $expectedValue = ['assetUpdatedData']; $assetId = 5; - $data = array('name' => 'asset111_name_qweqwe'); + $data = ['name' => 'asset111_name_qweqwe']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('repos/KnpLabs/php-github-api/releases/assets/'.$assetId) + ->with('/repos/KnpLabs/php-github-api/releases/assets/'.$assetId) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->edit('KnpLabs', 'php-github-api', $assetId, $data)); @@ -80,12 +88,12 @@ public function shouldEditReleaseAsset() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotEditReleaseAssetWithoutName() { + $this->expectException(MissingArgumentException::class); $assetId = 5; - $data = array('not_a_name' => 'just a value'); + $data = ['not_a_name' => 'just a value']; $api = $this->getApiMock(); $api->expects($this->never()) @@ -99,20 +107,23 @@ public function shouldNotEditReleaseAssetWithoutName() */ public function shouldRemoveReleaseAsset() { - $expectedValue = array('assetUpdatedData'); + $expectedValue = ['assetUpdatedData']; $assetId = 5; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('repos/KnpLabs/php-github-api/releases/assets/'.$assetId) + ->with('/repos/KnpLabs/php-github-api/releases/assets/'.$assetId) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', $assetId)); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Repository\Assets'; + return \Github\Api\Repository\Assets::class; } } diff --git a/test/Github/Tests/Api/Repository/Checks/CheckRunsTest.php b/test/Github/Tests/Api/Repository/Checks/CheckRunsTest.php new file mode 100644 index 00000000000..66bb5277c4b --- /dev/null +++ b/test/Github/Tests/Api/Repository/Checks/CheckRunsTest.php @@ -0,0 +1,123 @@ + 'success']; + $data = ['head_sha' => 'commitSHA123456', 'name' => 'my check']; + + /** @var CheckRuns|MockObject $api */ + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/check-runs', $data) + ->willReturn($expectedValue); + + $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', $data)); + } + + /** + * @test + */ + public function shouldShowSingleCheckRun() + { + /** @var CheckRuns|MockObject $api */ + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/check-runs/14'); + + $api->show('KnpLabs', 'php-github-api', 14); + } + + /** + * @test + */ + public function shouldUpdateCheck() + { + $expectedValue = ['state' => 'success']; + $data = ['head_sha' => 'commitSHA123456', 'name' => 'my check']; + + /** @var CheckRuns|MockObject $api */ + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('patch') + ->with('/repos/KnpLabs/php-github-api/check-runs/123', $data) + ->willReturn($expectedValue); + + $this->assertEquals($expectedValue, $api->update('KnpLabs', 'php-github-api', 123, $data)); + } + + /** + * @test + */ + public function shouldListCheckRunAnnotations() + { + /** @var CheckRuns|MockObject $api */ + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/check-runs/14/annotations'); + + $api->annotations('KnpLabs', 'php-github-api', 14); + } + + /** + * @test + */ + public function shouldGetAllChecksForCheckSuite() + { + $params = ['test' => true]; + /** @var CheckRuns|MockObject $api */ + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/check-suites/123/check-runs', $params); + + $api->allForCheckSuite('KnpLabs', 'php-github-api', 123, $params); + } + + /** + * @test + */ + public function shouldGetAllChecksForReference() + { + $params = ['test' => true]; + /** @var CheckRuns|MockObject $api */ + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/commits/cb4abc15424c0015b4468d73df55efb8b60a4a3d/check-runs', $params); + + $api->allForReference('KnpLabs', 'php-github-api', 'cb4abc15424c0015b4468d73df55efb8b60a4a3d', $params); + } + + /** + * @test + */ + public function shouldRerequestCheckRun() + { + /** @var CheckRuns|MockObject $api */ + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/check-runs/123/rerequest'); + + $api->rerequest('KnpLabs', 'php-github-api', 123); + } + + protected function getApiClass(): string + { + return CheckRuns::class; + } +} diff --git a/test/Github/Tests/Api/Repository/Checks/CheckSuitsTest.php b/test/Github/Tests/Api/Repository/Checks/CheckSuitsTest.php new file mode 100644 index 00000000000..87d8831d0da --- /dev/null +++ b/test/Github/Tests/Api/Repository/Checks/CheckSuitsTest.php @@ -0,0 +1,93 @@ + 'success']; + $data = ['head_sha' => 'commitSHA123456', 'name' => 'my check']; + + /** @var CheckSuites|MockObject $api */ + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/check-suites', $data) + ->willReturn($expectedValue); + + $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', $data)); + } + + /** + * @test + */ + public function shouldUpdateCheckSuitePreferences() + { + $expectedValue = ['preferences' => []]; + $data = ['preference_1' => true]; + + /** @var CheckSuites|MockObject $api */ + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('patch') + ->with('/repos/KnpLabs/php-github-api/check-suites/preferences', $data) + ->willReturn($expectedValue); + + $this->assertEquals($expectedValue, $api->updatePreferences('KnpLabs', 'php-github-api', $data)); + } + + /** + * @test + */ + public function shouldGetCheckSuite() + { + /** @var CheckSuites|MockObject $api */ + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/check-suites/14'); + + $api->getCheckSuite('KnpLabs', 'php-github-api', 14); + } + + /** + * @test + */ + public function shouldRerequest() + { + /** @var CheckSuites|MockObject $api */ + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/check-suites/14/rerequest'); + + $api->rerequest('KnpLabs', 'php-github-api', 14); + } + + /** + * @test + */ + public function shouldGetAllCheckSuitesForReference() + { + /** @var CheckSuites|MockObject $api */ + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/commits/cb4abc15424c0015b4468d73df55efb8b60a4a3d/check-suites'); + + $api->allForReference('KnpLabs', 'php-github-api', 'cb4abc15424c0015b4468d73df55efb8b60a4a3d'); + } + + protected function getApiClass(): string + { + return CheckSuites::class; + } +} diff --git a/test/Github/Tests/Api/Repository/CollaboratorsTest.php b/test/Github/Tests/Api/Repository/CollaboratorsTest.php index 6f8c924151a..8bf57d96791 100644 --- a/test/Github/Tests/Api/Repository/CollaboratorsTest.php +++ b/test/Github/Tests/Api/Repository/CollaboratorsTest.php @@ -11,12 +11,12 @@ class CollaboratorsTest extends TestCase */ public function shouldGetAllRepositoryCollaborators() { - $expectedValue = array(array('username' => 'l3l0')); + $expectedValue = [['username' => 'l3l0']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/collaborators') + ->with('/repos/KnpLabs/php-github-api/collaborators') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api')); @@ -32,7 +32,7 @@ public function shouldCheckIfRepositoryCollaborator() $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/collaborators/l3l0') + ->with('/repos/KnpLabs/php-github-api/collaborators/l3l0') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->check('KnpLabs', 'php-github-api', 'l3l0')); @@ -48,7 +48,7 @@ public function shouldAddRepositoryCollaborator() $api = $this->getApiMock(); $api->expects($this->once()) ->method('put') - ->with('repos/KnpLabs/php-github-api/collaborators/l3l0') + ->with('/repos/KnpLabs/php-github-api/collaborators/l3l0') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->add('KnpLabs', 'php-github-api', 'l3l0')); @@ -64,14 +64,33 @@ public function shouldRemoveRepositoryCollaborator() $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('repos/KnpLabs/php-github-api/collaborators/l3l0') + ->with('/repos/KnpLabs/php-github-api/collaborators/l3l0') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', 'l3l0')); } + /** + * @test + */ + public function shouldGetRepositoryCollaboratorPermission() + { + $expectedValue = [['permission' => 'admin', 'user' => 'l3l0']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/collaborators/l3l0/permission') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->permission('KnpLabs', 'php-github-api', 'l3l0')); + } + + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Repository\Collaborators'; + return \Github\Api\Repository\Collaborators::class; } } diff --git a/test/Github/Tests/Api/Repository/CommentsTest.php b/test/Github/Tests/Api/Repository/CommentsTest.php index b8220905a43..949bf4e231d 100644 --- a/test/Github/Tests/Api/Repository/CommentsTest.php +++ b/test/Github/Tests/Api/Repository/CommentsTest.php @@ -2,6 +2,7 @@ namespace Github\Tests\Api\Repository; +use Github\Exception\MissingArgumentException; use Github\Tests\Api\TestCase; class CommentsTest extends TestCase @@ -11,12 +12,12 @@ class CommentsTest extends TestCase */ public function shouldGetAllRepositoryComments() { - $expectedValue = array(array('comment1data'), array('comment2data')); + $expectedValue = [['comment1data'], ['comment2data']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/comments') + ->with('/repos/KnpLabs/php-github-api/comments') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api')); @@ -27,12 +28,12 @@ public function shouldGetAllRepositoryComments() */ public function shouldGetSpecificCommitRepositoryComments() { - $expectedValue = array(array('comment1data'), array('comment2data')); + $expectedValue = [['comment1data'], ['comment2data']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/commits/commitSHA123456/comments') + ->with('/repos/KnpLabs/php-github-api/commits/commitSHA123456/comments') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api', 'commitSHA123456')); @@ -43,12 +44,12 @@ public function shouldGetSpecificCommitRepositoryComments() */ public function shouldShowComment() { - $expectedValue = array('comment1'); + $expectedValue = ['comment1']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/comments/123') + ->with('/repos/KnpLabs/php-github-api/comments/123') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 123)); @@ -56,11 +57,11 @@ public function shouldShowComment() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateWithoutBody() { - $data = array('line' => 53, 'path' => 'test.php', 'position' => 2); + $this->expectException(MissingArgumentException::class); + $data = ['line' => 53, 'path' => 'test.php', 'position' => 2]; $api = $this->getApiMock(); $api->expects($this->never()) @@ -74,13 +75,13 @@ public function shouldNotCreateWithoutBody() */ public function shouldCreateRepositoryCommitComment() { - $expectedValue = array('comment1data'); - $data = array('body' => 'test body', 'line' => 53, 'path' => 'test.php', 'position' => 2); + $expectedValue = ['comment1data']; + $data = ['body' => 'test body', 'line' => 53, 'path' => 'test.php', 'position' => 2]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/commits/commitSHA123456/comments', $data) + ->with('/repos/KnpLabs/php-github-api/commits/commitSHA123456/comments', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', 'commitSHA123456', $data)); @@ -91,13 +92,13 @@ public function shouldCreateRepositoryCommitComment() */ public function shouldCreateRepositoryCommitCommentWithoutLine() { - $expectedValue = array('comment1data'); - $data = array('body' => 'body', 'path' => 'test.php', 'position' => 2); + $expectedValue = ['comment1data']; + $data = ['body' => 'body', 'path' => 'test.php', 'position' => 2]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/commits/commitSHA123456/comments', $data) + ->with('/repos/KnpLabs/php-github-api/commits/commitSHA123456/comments', $data) ->will($this->returnValue($expectedValue)); $api->create('KnpLabs', 'php-github-api', 'commitSHA123456', $data); @@ -105,15 +106,15 @@ public function shouldCreateRepositoryCommitCommentWithoutLine() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotUpdateWithoutBody() { + $this->expectException(MissingArgumentException::class); $api = $this->getApiMock(); $api->expects($this->never()) ->method('patch'); - $api->update('KnpLabs', 'php-github-api', 'commitSHA123456', array()); + $api->update('KnpLabs', 'php-github-api', 'commitSHA123456', []); } /** @@ -121,13 +122,13 @@ public function shouldNotUpdateWithoutBody() */ public function shouldUpdateComment() { - $expectedValue = array('comment1data'); - $data = array('body' => 'body test'); + $expectedValue = ['comment1data']; + $data = ['body' => 'body test']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('repos/KnpLabs/php-github-api/comments/123', $data) + ->with('/repos/KnpLabs/php-github-api/comments/123', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->update('KnpLabs', 'php-github-api', 123, $data)); @@ -138,19 +139,22 @@ public function shouldUpdateComment() */ public function shouldRemoveComment() { - $expectedValue = array('someOutput'); + $expectedValue = ['someOutput']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('repos/KnpLabs/php-github-api/comments/123') + ->with('/repos/KnpLabs/php-github-api/comments/123') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', 123)); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Repository\Comments'; + return \Github\Api\Repository\Comments::class; } } diff --git a/test/Github/Tests/Api/Repository/CommitsTest.php b/test/Github/Tests/Api/Repository/CommitsTest.php index b36f81b16c0..9d1b3288afe 100644 --- a/test/Github/Tests/Api/Repository/CommitsTest.php +++ b/test/Github/Tests/Api/Repository/CommitsTest.php @@ -11,13 +11,13 @@ class CommitsTest extends TestCase */ public function shouldGetAllRepositoryCommits() { - $expectedValue = array('commit' => array(), 'comitter'); - $data = array('sha' => 'v3'); + $expectedValue = ['commit' => [], 'comitter']; + $data = ['sha' => 'v3']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/commits', $data) + ->with('/repos/KnpLabs/php-github-api/commits', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api', $data)); @@ -28,12 +28,12 @@ public function shouldGetAllRepositoryCommits() */ public function shouldCompareTwoCommits() { - $expectedValue = array('someCompareChanges'); + $expectedValue = ['someCompareChanges']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/compare/v3...HEAD') + ->with('/repos/KnpLabs/php-github-api/compare/v3...HEAD') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->compare('KnpLabs', 'php-github-api', 'v3', 'HEAD')); @@ -44,19 +44,41 @@ public function shouldCompareTwoCommits() */ public function shouldShowCommitUsingSha() { - $expectedValue = array('sha' => '123', 'comitter'); + $expectedValue = ['sha' => '123', 'comitter']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/commits/123') + ->with('/repos/KnpLabs/php-github-api/commits/123') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 123)); } + /** + * @test + */ + public function shouldGetAllPullRequestsUsingSha() + { + $expectedValue = [ + ['number' => '1', 'title' => 'My first PR'], + ['number' => '2', 'title' => 'Another PR'], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/commits/123/pulls') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->pulls('KnpLabs', 'php-github-api', 123)); + } + + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Repository\Commits'; + return \Github\Api\Repository\Commits::class; } } diff --git a/test/Github/Tests/Api/Repository/ContentsTest.php b/test/Github/Tests/Api/Repository/ContentsTest.php index 0eb91a4cd15..81a79db64fa 100644 --- a/test/Github/Tests/Api/Repository/ContentsTest.php +++ b/test/Github/Tests/Api/Repository/ContentsTest.php @@ -2,7 +2,10 @@ namespace Github\Tests\Api\Repository; +use Github\Exception\MissingArgumentException; +use Github\Exception\TwoFactorAuthenticationRequiredException; use Github\Tests\Api\TestCase; +use GuzzleHttp\Psr7\Response; class ContentsTest extends TestCase { @@ -16,7 +19,7 @@ public function shouldShowContentForGivenPath() $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/contents/test%2FGithub%2FTests%2FApi%2FRepository%2FContentsTest.php', array('ref' => null)) + ->with('/repos/KnpLabs/php-github-api/contents/test%2FGithub%2FTests%2FApi%2FRepository%2FContentsTest.php', ['ref' => null]) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 'test/Github/Tests/Api/Repository/ContentsTest.php')); @@ -32,12 +35,187 @@ public function shouldShowReadme() $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/readme', array('ref' => null)) + ->with('/repos/KnpLabs/php-github-api/readme', ['ref' => null]) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->readme('KnpLabs', 'php-github-api')); } + /** + * @test + */ + public function shouldReturnTrueWhenFileExists() + { + $response = new Response(200); + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('head') + ->with('/repos/KnpLabs/php-github-api/contents/composer.json', ['ref' => null]) + ->will($this->returnValue($response)); + + $this->assertTrue($api->exists('KnpLabs', 'php-github-api', 'composer.json')); + } + + public function getFailureStubsForExistsTest() + { + $response = new Response(403); + + return [ + [$this->throwException(new \ErrorException())], + [$this->returnValue($response)], + ]; + } + + /** + * @param \PHPUnit_Framework_MockObject_Stub|\PHPUnit\Framework\MockObject\Stub\Exception + * + * @test + * + * @dataProvider getFailureStubsForExistsTest + */ + public function shouldReturnFalseWhenFileIsNotFound($failureStub) + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('head') + ->with('/repos/KnpLabs/php-github-api/contents/composer.json', ['ref' => null]) + ->will($failureStub); + + $this->assertFalse($api->exists('KnpLabs', 'php-github-api', 'composer.json')); + } + + /** + * @test + */ + public function shouldBubbleTwoFactorAuthenticationRequiredExceptionsWhenCheckingFileRequiringAuth() + { + $this->expectException(TwoFactorAuthenticationRequiredException::class); + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('head') + ->with('/repos/KnpLabs/php-github-api/contents/composer.json', ['ref' => null]) + ->will($this->throwException(new TwoFactorAuthenticationRequiredException(0))); + + $api->exists('KnpLabs', 'php-github-api', 'composer.json'); + } + + /** + * @test + */ + public function shouldCreateNewFile() + { + $expectedArray = ['content' => 'some data']; + $content = ' 'committer name', 'email' => 'email@example.com']; + $parameters = [ + 'content' => base64_encode($content), + 'message' => $message, + 'committer' => $committer, + 'branch' => $branch, + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/repos/KnpLabs/php-github-api/contents/test%2FGithub%2FTests%2FApi%2FRepository%2FContentsTest.php', $parameters) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->create('KnpLabs', 'php-github-api', 'test/Github/Tests/Api/Repository/ContentsTest.php', $content, $message, $branch, $committer)); + } + + /** + * @test + */ + public function shouldThrowExceptionWhenCreateNewFileWithInvalidCommitter() + { + $this->expectException(MissingArgumentException::class); + $this->expectExceptionMessage('One or more of required ("name", "email") parameters is missing!'); + $committer = ['invalid_key' => 'some data']; + $api = $this->getApiMock(); + $api->create('KnpLabs', 'php-github-api', 'test/Github/Tests/Api/Repository/ContentsTest.php', 'some content', 'a commit message', null, $committer); + } + + /** + * @test + */ + public function shouldUpdateFile() + { + $expectedArray = ['content' => 'some data']; + $content = ' 'committer name', 'email' => 'email@example.com']; + $parameters = [ + 'content' => base64_encode($content), + 'message' => $message, + 'committer' => $committer, + 'branch' => $branch, + 'sha' => $sha, + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/repos/KnpLabs/php-github-api/contents/test%2FGithub%2FTests%2FApi%2FRepository%2FContentsTest.php', $parameters) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->update('KnpLabs', 'php-github-api', 'test/Github/Tests/Api/Repository/ContentsTest.php', $content, $message, $sha, $branch, $committer)); + } + + /** + * @test + */ + public function shouldThrowExceptionWhenUpdateFileWithInvalidCommitter() + { + $this->expectException(MissingArgumentException::class); + $this->expectExceptionMessage('One or more of required ("name", "email") parameters is missing!'); + $committer = ['invalid_key' => 'some data']; + $api = $this->getApiMock(); + $api->update('KnpLabs', 'php-github-api', 'test/Github/Tests/Api/Repository/ContentsTest.php', 'some content', 'a commit message', null, null, $committer); + } + + /** + * @test + */ + public function shouldDeleteFile() + { + $expectedArray = ['content' => 'some data']; + $message = 'a commit message'; + $sha = 'a sha'; + $branch = 'master'; + $committer = ['name' => 'committer name', 'email' => 'email@example.com']; + $parameters = [ + 'message' => $message, + 'committer' => $committer, + 'branch' => $branch, + 'sha' => $sha, + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/contents/test%2FGithub%2FTests%2FApi%2FRepository%2FContentsTest.php', $parameters) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->rm('KnpLabs', 'php-github-api', 'test/Github/Tests/Api/Repository/ContentsTest.php', $message, $sha, $branch, $committer)); + } + + /** + * @test + */ + public function shouldThrowExceptionWhenDeleteFileWithInvalidCommitter() + { + $this->expectException(MissingArgumentException::class); + $this->expectExceptionMessage('One or more of required ("name", "email") parameters is missing!'); + $committer = ['invalid_key' => 'some data']; + $api = $this->getApiMock(); + $api->rm('KnpLabs', 'php-github-api', 'test/Github/Tests/Api/Repository/ContentsTest.php', 'a commit message', null, null, $committer); + } + /** * @test */ @@ -48,7 +226,7 @@ public function shouldFetchTarballArchiveWhenFormatNotRecognized() $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/tarball', array('ref' => null)) + ->with('/repos/KnpLabs/php-github-api/tarball') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->archive('KnpLabs', 'php-github-api', 'someFormat')); @@ -64,7 +242,7 @@ public function shouldFetchTarballArchive() $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/tarball', array('ref' => null)) + ->with('/repos/KnpLabs/php-github-api/tarball') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->archive('KnpLabs', 'php-github-api', 'tarball')); @@ -80,12 +258,28 @@ public function shouldFetchZipballArchive() $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/zipball', array('ref' => null)) + ->with('/repos/KnpLabs/php-github-api/zipball') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->archive('KnpLabs', 'php-github-api', 'zipball')); } + /** + * @test + */ + public function shouldFetchZipballArchiveByReference() + { + $expectedValue = 'zip'; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/zipball/master') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->archive('KnpLabs', 'php-github-api', 'zipball', 'master')); + } + /** * @test */ @@ -100,7 +294,7 @@ public function shouldDownloadForGivenPath() $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/contents/test%2FGithub%2FTests%2FApi%2FRepository%2FContentsTest.php', array('ref' => null)) + ->with('/repos/KnpLabs/php-github-api/contents/test%2FGithub%2FTests%2FApi%2FRepository%2FContentsTest.php', ['ref' => null]) ->will($this->returnValue($getValue)); $this->assertEquals($expectedValue, $api->download('KnpLabs', 'php-github-api', 'test/Github/Tests/Api/Repository/ContentsTest.php')); @@ -120,14 +314,34 @@ public function shouldDownloadForSpacedPath() $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/mads379/scala.tmbundle/contents/Syntaxes%2FSimple%20Build%20Tool.tmLanguage', array('ref' => null)) + ->with('/repos/mads379/scala.tmbundle/contents/Syntaxes%2FSimple%20Build%20Tool.tmLanguage', ['ref' => null]) ->will($this->returnValue($getValue)); $this->assertEquals($expectedValue, $api->download('mads379', 'scala.tmbundle', 'Syntaxes/Simple Build Tool.tmLanguage')); } + /** + * @test + */ + public function shouldRawDownloadForGivenPath() + { + // The show() method return + $getValue = include __DIR__.'/fixtures/ContentsDownloadFixture.php'; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/contents/test%2FGithub%2FTests%2FApi%2FRepository%2FContentsTest.php', ['ref' => null]) + ->will($this->returnValue($getValue)); + + $this->assertEquals($getValue, $api->rawDownload('KnpLabs', 'php-github-api', 'test/Github/Tests/Api/Repository/ContentsTest.php')); + } + + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Repository\Contents'; + return \Github\Api\Repository\Contents::class; } } diff --git a/test/Github/Tests/Api/Repository/DeployKeysTest.php b/test/Github/Tests/Api/Repository/DeployKeysTest.php index a235bad8f0b..2962390bc83 100644 --- a/test/Github/Tests/Api/Repository/DeployKeysTest.php +++ b/test/Github/Tests/Api/Repository/DeployKeysTest.php @@ -2,6 +2,7 @@ namespace Github\Tests\Api\Repository; +use Github\Exception\MissingArgumentException; use Github\Tests\Api\TestCase; class DeployKeysTest extends TestCase @@ -11,12 +12,12 @@ class DeployKeysTest extends TestCase */ public function shouldGetAllRepositoryDeployKeys() { - $expectedValue = array(array('name' => 'key')); + $expectedValue = [['name' => 'key']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/keys') + ->with('/repos/KnpLabs/php-github-api/keys') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api')); @@ -27,12 +28,12 @@ public function shouldGetAllRepositoryDeployKeys() */ public function shouldShowDeployKey() { - $expectedValue = array('key' => 'somename'); + $expectedValue = ['key' => 'somename']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/keys/123') + ->with('/repos/KnpLabs/php-github-api/keys/123') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 123)); @@ -43,12 +44,12 @@ public function shouldShowDeployKey() */ public function shouldRemoveDeployKey() { - $expectedValue = array('someOutput'); + $expectedValue = ['someOutput']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('repos/KnpLabs/php-github-api/keys/123') + ->with('/repos/KnpLabs/php-github-api/keys/123') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', 123)); @@ -56,11 +57,11 @@ public function shouldRemoveDeployKey() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateDeployKeyWithoutName() { - $data = array('config' => 'conf'); + $this->expectException(MissingArgumentException::class); + $data = ['config' => 'conf']; $api = $this->getApiMock(); $api->expects($this->never()) @@ -71,11 +72,11 @@ public function shouldNotCreateDeployKeyWithoutName() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateDeployKeyWithoutColor() { - $data = array('name' => 'test'); + $this->expectException(MissingArgumentException::class); + $data = ['name' => 'test']; $api = $this->getApiMock(); $api->expects($this->never()) @@ -89,13 +90,13 @@ public function shouldNotCreateDeployKeyWithoutColor() */ public function shouldCreateDeployKey() { - $expectedValue = array('key' => 'somename'); - $data = array('title' => 'test', 'key' => 'ssh-rsa 1231234232'); + $expectedValue = ['key' => 'somename']; + $data = ['title' => 'test', 'key' => 'ssh-rsa 1231234232']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/keys', $data) + ->with('/repos/KnpLabs/php-github-api/keys', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', $data)); @@ -103,30 +104,34 @@ public function shouldCreateDeployKey() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotUpdateDeployKeyWithoutTitle() { - $data = array('key' => 'ssh-rsa 12323213'); + $this->expectException(MissingArgumentException::class); + $data = ['key' => 'ssh-rsa 12323213']; $api = $this->getApiMock(); $api->expects($this->never()) - ->method('patch'); + ->method('delete'); + $api->expects($this->never()) + ->method('post'); $api->update('KnpLabs', 'php-github-api', 123, $data); } /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotUpdateDeployKeyWithoutKey() { - $data = array('title' => 'test'); + $this->expectException(MissingArgumentException::class); + $data = ['title' => 'test']; $api = $this->getApiMock(); $api->expects($this->never()) - ->method('patch'); + ->method('delete'); + $api->expects($this->never()) + ->method('post'); $api->update('KnpLabs', 'php-github-api', 123, $data); } @@ -136,20 +141,27 @@ public function shouldNotUpdateDeployKeyWithoutKey() */ public function shouldUpdateDeployKey() { - $expectedValue = array('key' => 'somename'); - $data = array('title' => 'test', 'key' => 'ssh-rsa 12312312321...'); + $expectedValue = ['key' => 'somename']; + $data = ['title' => 'test', 'key' => 'ssh-rsa 12312312321...']; $api = $this->getApiMock(); $api->expects($this->once()) - ->method('patch') - ->with('repos/KnpLabs/php-github-api/keys/123', $data) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/keys/123') + ->will($this->returnValue($expectedValue)); + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/keys', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->update('KnpLabs', 'php-github-api', 123, $data)); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Repository\DeployKeys'; + return \Github\Api\Repository\DeployKeys::class; } } diff --git a/test/Github/Tests/Api/Repository/DownloadsTest.php b/test/Github/Tests/Api/Repository/DownloadsTest.php index b352c12efbf..f73b71491e4 100644 --- a/test/Github/Tests/Api/Repository/DownloadsTest.php +++ b/test/Github/Tests/Api/Repository/DownloadsTest.php @@ -11,12 +11,12 @@ class DownloadsTest extends TestCase */ public function shouldGetAllRepositoryDownloads() { - $expectedValue = array(array('download')); + $expectedValue = [['download']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/downloads') + ->with('/repos/KnpLabs/php-github-api/downloads') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api')); @@ -27,12 +27,12 @@ public function shouldGetAllRepositoryDownloads() */ public function shouldShowRepositoryDownload() { - $expectedValue = array('download'); + $expectedValue = ['download']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/downloads/l3l0') + ->with('/repos/KnpLabs/php-github-api/downloads/l3l0') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 'l3l0')); @@ -48,14 +48,17 @@ public function shouldRemoveRepositoryDownload() $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('repos/KnpLabs/php-github-api/downloads/l3l0') + ->with('/repos/KnpLabs/php-github-api/downloads/l3l0') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', 'l3l0')); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Repository\Downloads'; + return \Github\Api\Repository\Downloads::class; } } diff --git a/test/Github/Tests/Api/Repository/ForksTest.php b/test/Github/Tests/Api/Repository/ForksTest.php index 151fbc3837b..fbc6eb67212 100644 --- a/test/Github/Tests/Api/Repository/ForksTest.php +++ b/test/Github/Tests/Api/Repository/ForksTest.php @@ -11,12 +11,12 @@ class ForksTest extends TestCase */ public function shouldGetForks() { - $expectedValue = array(array('name' => 'l3l0repo')); + $expectedValue = [['name' => 'l3l0repo']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/forks', array('page' => 1)) + ->with('/repos/KnpLabs/php-github-api/forks', ['page' => 1]) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api')); @@ -27,13 +27,13 @@ public function shouldGetForks() */ public function shouldCreateFork() { - $expectedValue = array(array('name' => 'l3l0repo')); - $data = array('someparam'); + $expectedValue = [['name' => 'l3l0repo']]; + $data = ['someparam']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/forks', $data) + ->with('/repos/KnpLabs/php-github-api/forks', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', $data)); @@ -44,19 +44,22 @@ public function shouldCreateFork() */ public function shouldSortByNewestWhenSortParamNotRecognized() { - $expectedValue = array(array('name' => 'l3l0repo')); + $expectedValue = [['name' => 'l3l0repo']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/forks', array('page' => 1, 'sort' => 'newest')) + ->with('/repos/KnpLabs/php-github-api/forks', ['page' => 1, 'sort' => 'newest']) ->will($this->returnValue($expectedValue)); - $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api', array('sort' => 'oldes'))); + $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api', ['sort' => 'oldes'])); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Repository\Forks'; + return \Github\Api\Repository\Forks::class; } } diff --git a/test/Github/Tests/Api/Repository/HooksTest.php b/test/Github/Tests/Api/Repository/HooksTest.php index 6744d8c9158..00cdc69df2c 100644 --- a/test/Github/Tests/Api/Repository/HooksTest.php +++ b/test/Github/Tests/Api/Repository/HooksTest.php @@ -2,6 +2,7 @@ namespace Github\Tests\Api\Repository; +use Github\Exception\MissingArgumentException; use Github\Tests\Api\TestCase; class HooksTest extends TestCase @@ -11,12 +12,12 @@ class HooksTest extends TestCase */ public function shouldGetAllRepositoryHooks() { - $expectedValue = array(array('name' => 'hook')); + $expectedValue = [['name' => 'hook']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/hooks') + ->with('/repos/KnpLabs/php-github-api/hooks') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api')); @@ -27,12 +28,12 @@ public function shouldGetAllRepositoryHooks() */ public function shouldShowHook() { - $expectedValue = array('hook' => 'somename'); + $expectedValue = ['hook' => 'somename']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/hooks/123') + ->with('/repos/KnpLabs/php-github-api/hooks/123') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 123)); @@ -43,12 +44,12 @@ public function shouldShowHook() */ public function shouldRemoveHook() { - $expectedValue = array('someOutput'); + $expectedValue = ['someOutput']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('repos/KnpLabs/php-github-api/hooks/123') + ->with('/repos/KnpLabs/php-github-api/hooks/123') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', 123)); @@ -56,11 +57,11 @@ public function shouldRemoveHook() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateHookWithoutName() { - $data = array('config' => 'conf'); + $this->expectException(MissingArgumentException::class); + $data = ['config' => 'conf']; $api = $this->getApiMock(); $api->expects($this->never()) @@ -71,11 +72,11 @@ public function shouldNotCreateHookWithoutName() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateHookWithoutColor() { - $data = array('name' => 'test'); + $this->expectException(MissingArgumentException::class); + $data = ['name' => 'test']; $api = $this->getApiMock(); $api->expects($this->never()) @@ -89,13 +90,13 @@ public function shouldNotCreateHookWithoutColor() */ public function shouldCreateHook() { - $expectedValue = array('hook' => 'somename'); - $data = array('name' => 'test', 'config' => 'someconfig'); + $expectedValue = ['hook' => 'somename']; + $data = ['name' => 'test', 'config' => 'someconfig']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/hooks', $data) + ->with('/repos/KnpLabs/php-github-api/hooks', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', $data)); @@ -103,26 +104,11 @@ public function shouldCreateHook() /** * @test - * @expectedException Github\Exception\MissingArgumentException - */ - public function shouldNotUpdateHookWithoutName() - { - $data = array('config' => 'someconf'); - - $api = $this->getApiMock(); - $api->expects($this->never()) - ->method('patch'); - - $api->update('KnpLabs', 'php-github-api', 123, $data); - } - - /** - * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotUpdateHookWithoutConfig() { - $data = array('name' => 'test'); + $this->expectException(MissingArgumentException::class); + $data = ['name' => 'test']; $api = $this->getApiMock(); $api->expects($this->never()) @@ -136,13 +122,13 @@ public function shouldNotUpdateHookWithoutConfig() */ public function shouldUpdateHook() { - $expectedValue = array('hook' => 'somename'); - $data = array('name' => 'test', 'config' => 'config'); + $expectedValue = ['hook' => 'somename']; + $data = ['name' => 'test', 'config' => 'config']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('repos/KnpLabs/php-github-api/hooks/123', $data) + ->with('/repos/KnpLabs/php-github-api/hooks/123', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->update('KnpLabs', 'php-github-api', 123, $data)); @@ -153,19 +139,22 @@ public function shouldUpdateHook() */ public function shouldTestHook() { - $expectedValue = array(array('name' => 'hook')); + $expectedValue = [['name' => 'hook']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/hooks/123/test') + ->with('/repos/KnpLabs/php-github-api/hooks/123/tests') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->test('KnpLabs', 'php-github-api', 123)); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Repository\Hooks'; + return \Github\Api\Repository\Hooks::class; } } diff --git a/test/Github/Tests/Api/Repository/LabelsTest.php b/test/Github/Tests/Api/Repository/LabelsTest.php index 6526ec4b3bb..4fe2fd81493 100644 --- a/test/Github/Tests/Api/Repository/LabelsTest.php +++ b/test/Github/Tests/Api/Repository/LabelsTest.php @@ -2,6 +2,7 @@ namespace Github\Tests\Api\Repository; +use Github\Exception\MissingArgumentException; use Github\Tests\Api\TestCase; class LabelsTest extends TestCase @@ -11,12 +12,12 @@ class LabelsTest extends TestCase */ public function shouldGetAllRepositoryLabelss() { - $expectedValue = array(array('name' => 'label')); + $expectedValue = [['name' => 'label']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/labels') + ->with('/repos/KnpLabs/php-github-api/labels') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api')); @@ -27,12 +28,12 @@ public function shouldGetAllRepositoryLabelss() */ public function shouldShowLabel() { - $expectedValue = array('label' => 'somename'); + $expectedValue = ['label' => 'somename']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/labels/somename') + ->with('/repos/KnpLabs/php-github-api/labels/somename') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 'somename')); @@ -43,12 +44,12 @@ public function shouldShowLabel() */ public function shouldRemoveLabel() { - $expectedValue = array('someOutput'); + $expectedValue = ['someOutput']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('repos/KnpLabs/php-github-api/labels/somename') + ->with('/repos/KnpLabs/php-github-api/labels/somename') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', 'somename')); @@ -56,11 +57,11 @@ public function shouldRemoveLabel() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateLabelWithoutName() { - $data = array('color' => 'red'); + $this->expectException(MissingArgumentException::class); + $data = ['color' => 'red']; $api = $this->getApiMock(); $api->expects($this->never()) @@ -71,11 +72,11 @@ public function shouldNotCreateLabelWithoutName() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateLabelWithoutColor() { - $data = array('name' => 'test'); + $this->expectException(MissingArgumentException::class); + $data = ['name' => 'test']; $api = $this->getApiMock(); $api->expects($this->never()) @@ -89,67 +90,40 @@ public function shouldNotCreateLabelWithoutColor() */ public function shouldCreateLabel() { - $expectedValue = array('label' => 'somename'); - $data = array('name' => 'test', 'color' => 'red'); + $expectedValue = ['label' => 'somename']; + $data = ['name' => 'test', 'color' => 'red']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/labels', $data) + ->with('/repos/KnpLabs/php-github-api/labels', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', $data)); } - /** - * @test - * @expectedException Github\Exception\MissingArgumentException - */ - public function shouldNotUpdateLabelWithoutName() - { - $data = array('color' => 'red'); - - $api = $this->getApiMock(); - $api->expects($this->never()) - ->method('patch'); - - $api->update('KnpLabs', 'php-github-api', 'labelName', $data); - } - - /** - * @test - * @expectedException Github\Exception\MissingArgumentException - */ - public function shouldNotUpdateLabelWithoutColor() - { - $data = array('name' => 'test'); - - $api = $this->getApiMock(); - $api->expects($this->never()) - ->method('patch'); - - $api->update('KnpLabs', 'php-github-api', 'labelName', $data); - } - /** * @test */ public function shouldUpdateLabel() { - $expectedValue = array('label' => 'somename'); - $data = array('name' => 'test', 'color' => 'red'); + $expectedValue = ['name' => 'test']; + $data = ['new_name' => 'test', 'color' => 'red']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('repos/KnpLabs/php-github-api/labels/labelName', $data) + ->with('/repos/KnpLabs/php-github-api/labels/labelName', $data) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->update('KnpLabs', 'php-github-api', 'labelName', $data)); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Repository\Labels'; + return \Github\Api\Repository\Labels::class; } } diff --git a/test/Github/Tests/Api/Repository/PagesTest.php b/test/Github/Tests/Api/Repository/PagesTest.php new file mode 100644 index 00000000000..2fde0df1622 --- /dev/null +++ b/test/Github/Tests/Api/Repository/PagesTest.php @@ -0,0 +1,150 @@ + 'built']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/pages') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldEnablePages() + { + $params = [ + 'source' => [ + 'branch' => 'master', + 'path' => '/path', + ], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/pages', $params); + + $api->enable('KnpLabs', 'php-github-api', $params); + } + + /** + * @test + */ + public function shouldDisablePages() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/pages'); + + $api->disable('KnpLabs', 'php-github-api'); + } + + /** + * @test + */ + public function shouldUpdatePages() + { + $params = [ + 'source' => 'master /docs', + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/repos/KnpLabs/php-github-api/pages', $params); + + $api->update('KnpLabs', 'php-github-api', $params); + } + + /** + * @test + */ + public function shouldRequestPagesBuild() + { + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/pages/builds'); + + $api->requestBuild('KnpLabs', 'php-github-api'); + } + + /** + * @test + */ + public function shouldGetAllPagesBuilds() + { + $expectedValue = [['status' => 'built']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/pages/builds') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->builds('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldGetLatestPagesBuild() + { + $expectedValue = ['status' => 'built']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/pages/builds/latest') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->showLatestBuild('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function showGetOnePagesBuild() + { + $expectedValue = ['status' => 'built']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/pages/builds/some') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->showBuild('KnpLabs', 'php-github-api', 'some')); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Repository\Pages::class; + } +} diff --git a/test/Github/Tests/Api/Repository/ProjectsTest.php b/test/Github/Tests/Api/Repository/ProjectsTest.php new file mode 100644 index 00000000000..225bda4baf6 --- /dev/null +++ b/test/Github/Tests/Api/Repository/ProjectsTest.php @@ -0,0 +1,65 @@ + 'Test project 1']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/projects') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldNotCreateWithoutName() + { + $this->expectException(MissingArgumentException::class); + $data = []; + + $api = $this->getApiMock(); + $api->expects($this->never()) + ->method('post'); + + $api->create('KnpLabs', 'php-github-api', $data); + } + + /** + * @test + */ + public function shouldCreateColumn() + { + $expectedValue = ['project1data']; + $data = ['name' => 'Project 1']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/projects', $data) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', $data)); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Repository\Projects::class; + } +} diff --git a/test/Github/Tests/Api/Repository/ProtectionTest.php b/test/Github/Tests/Api/Repository/ProtectionTest.php new file mode 100644 index 00000000000..f4f711dce74 --- /dev/null +++ b/test/Github/Tests/Api/Repository/ProtectionTest.php @@ -0,0 +1,444 @@ +getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 'master')); + } + + /** + * @test + */ + public function shouldUpdateProtection() + { + $expectedValue = ['required_status_checks', 'required_pull_reqeust_reviews', 'restrictions']; + $data = ['required_status_checks' => null]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection', $data) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->update('KnpLabs', 'php-github-api', 'master', $data)); + } + + /** + * @test + */ + public function shouldRemoveProtection() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', 'master')); + } + + /** + * @test + */ + public function shouldShowStatusChecks() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/required_status_checks') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->showStatusChecks('KnpLabs', 'php-github-api', 'master')); + } + + /** + * @test + */ + public function shouldUpdateStatusChecks() + { + $expectedValue = ['someOutput']; + $data = ['someInput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('patch') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/required_status_checks') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->updateStatusChecks('KnpLabs', 'php-github-api', 'master', $data)); + } + + /** + * @test + */ + public function shouldRemoveStatusChecks() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/required_status_checks') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->removeStatusChecks('KnpLabs', 'php-github-api', 'master')); + } + + /** + * @test + */ + public function shouldShowStatusChecksContexts() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/required_status_checks/contexts') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->showStatusChecksContexts('KnpLabs', 'php-github-api', 'master')); + } + + /** + * @test + */ + public function shouldReplaceStatusChecksContexts() + { + $expectedValue = ['someOutput']; + $data = ['someInput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/required_status_checks/contexts') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->replaceStatusChecksContexts('KnpLabs', 'php-github-api', 'master', $data)); + } + + /** + * @test + */ + public function shouldAddStatusChecksContexts() + { + $expectedValue = ['someOutput']; + $data = ['someInput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/required_status_checks/contexts') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->addStatusChecksContexts('KnpLabs', 'php-github-api', 'master', $data)); + } + + /** + * @test + */ + public function shouldRemoveStatusChecksContexts() + { + $expectedValue = ['someOutput']; + $data = ['someInput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/required_status_checks/contexts') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->removeStatusChecksContexts('KnpLabs', 'php-github-api', 'master', $data)); + } + + /** + * @test + */ + public function shouldShowPullRequestReviewEnforcement() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/required_pull_request_reviews') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->showPullRequestReviewEnforcement('KnpLabs', 'php-github-api', 'master')); + } + + /** + * @test + */ + public function shouldUpdatePullRequestReviewEnforcement() + { + $expectedValue = ['someOutput']; + $data = ['someInput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('patch') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/required_pull_request_reviews') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->updatePullRequestReviewEnforcement('KnpLabs', 'php-github-api', 'master', $data)); + } + + /** + * @test + */ + public function shouldRemovePullRequestReviewEnforcement() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/required_pull_request_reviews') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->removePullRequestReviewEnforcement('KnpLabs', 'php-github-api', 'master')); + } + + /** + * @test + */ + public function shouldShowAdminEnforcement() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/enforce_admins') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->showAdminEnforcement('KnpLabs', 'php-github-api', 'master')); + } + + /** + * @test + */ + public function shouldAddAdminEnforcement() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/enforce_admins') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->addAdminEnforcement('KnpLabs', 'php-github-api', 'master')); + } + + /** + * @test + */ + public function shouldRemoveAdminEnforcement() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/enforce_admins') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->removeAdminEnforcement('KnpLabs', 'php-github-api', 'master')); + } + + /** + * @test + */ + public function shouldShowRestrictions() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/restrictions') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->showRestrictions('KnpLabs', 'php-github-api', 'master')); + } + + /** + * @test + */ + public function shouldRemoveRestrictions() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/restrictions') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->removeRestrictions('KnpLabs', 'php-github-api', 'master')); + } + + /** + * @test + */ + public function shouldShowTeamRestrictions() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/restrictions/teams') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->showTeamRestrictions('KnpLabs', 'php-github-api', 'master')); + } + + /** + * @test + */ + public function shouldReplaceTeamRestrictions() + { + $expectedValue = ['someOutput']; + $data = ['someInput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/restrictions/teams') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->replaceTeamRestrictions('KnpLabs', 'php-github-api', 'master', $data)); + } + + /** + * @test + */ + public function shouldAddTeamRestrictions() + { + $expectedValue = ['someOutput']; + $data = ['someInput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/restrictions/teams') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->addTeamRestrictions('KnpLabs', 'php-github-api', 'master', $data)); + } + + /** + * @test + */ + public function shouldRemoveTeamRestrictions() + { + $expectedValue = ['someOutput']; + $data = ['someInput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/restrictions/teams') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->removeTeamRestrictions('KnpLabs', 'php-github-api', 'master', $data)); + } + + /** + * @test + */ + public function shouldShowUserRestrictions() + { + $expectedValue = ['someOutput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/restrictions/users') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->showUserRestrictions('KnpLabs', 'php-github-api', 'master')); + } + + /** + * @test + */ + public function shouldReplaceUserRestrictions() + { + $expectedValue = ['someOutput']; + $data = ['someInput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/restrictions/users') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->replaceUserRestrictions('KnpLabs', 'php-github-api', 'master', $data)); + } + + /** + * @test + */ + public function shouldAddUserRestrictions() + { + $expectedValue = ['someOutput']; + $data = ['someInput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/restrictions/users') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->addUserRestrictions('KnpLabs', 'php-github-api', 'master', $data)); + } + + /** + * @test + */ + public function shouldRemoveUserRestrictions() + { + $expectedValue = ['someOutput']; + $data = ['someInput']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('/repos/KnpLabs/php-github-api/branches/master/protection/restrictions/users') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->removeUserRestrictions('KnpLabs', 'php-github-api', 'master', $data)); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Repository\Protection::class; + } +} diff --git a/test/Github/Tests/Api/Repository/ReleasesTest.php b/test/Github/Tests/Api/Repository/ReleasesTest.php index c9fac0a0f80..dda8999a163 100644 --- a/test/Github/Tests/Api/Repository/ReleasesTest.php +++ b/test/Github/Tests/Api/Repository/ReleasesTest.php @@ -2,21 +2,58 @@ namespace Github\Tests\Api\Repository; +use Github\Exception\MissingArgumentException; use Github\Tests\Api\TestCase; class ReleasesTest extends TestCase { + /** + * @test + */ + public function shouldGetLatestRelease() + { + $expectedValue = ['latest_release_data']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/releases/latest') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->latest('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldGetReleaseByTag() + { + $expectedValue = ['latest_release_data']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/releases/tags/5f078080e01e0365690920d618f12342d2c941c8') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->tag( + 'KnpLabs', + 'php-github-api', + '5f078080e01e0365690920d618f12342d2c941c8' + )); + } + /** * @test */ public function shouldGetAllRepositoryReleases() { - $expectedValue = array(array('release1data'), array('release2data')); + $expectedValue = [['release1data'], ['release2data']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/releases') + ->with('/repos/KnpLabs/php-github-api/releases') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api')); @@ -27,30 +64,50 @@ public function shouldGetAllRepositoryReleases() */ public function shouldGetSingleRepositoryRelease() { - $expectedValue = array('releaseData'); + $expectedValue = ['releaseData']; $id = 331; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('repos/KnpLabs/php-github-api/releases/'.$id) + ->with('/repos/KnpLabs/php-github-api/releases/'.$id) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', $id)); } + /** + * @test + */ + public function shouldGenerateReleaseNotes() + { + $expectedValue = [ + 'name' => 'Release v1.0.0 is now available!', + 'body' => '##Changes in Release v1.0.0 ... ##Contributors @monalisa', + ]; + $data = ['tag_name' => 'some-tag']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/releases/generate-notes') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->generateNotes('KnpLabs', 'php-github-api', $data)); + } + /** * @test */ public function shouldCreateRepositoryRelease() { - $expectedValue = array('newReleaseData'); - $data = array('tag_name' => '1.1'); + $expectedValue = ['newReleaseData']; + $data = ['tag_name' => '1.1']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('post') - ->with('repos/KnpLabs/php-github-api/releases') + ->with('/repos/KnpLabs/php-github-api/releases') ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', $data)); @@ -58,11 +115,11 @@ public function shouldCreateRepositoryRelease() /** * @test - * @expectedException Github\Exception\MissingArgumentException */ public function shouldNotCreateRepositoryReleaseWithoutTagName() { - $data = array('not_a_tag_name' => '1.1'); + $this->expectException(MissingArgumentException::class); + $data = ['not_a_tag_name' => '1.1']; $api = $this->getApiMock(); $api->expects($this->never()) @@ -76,14 +133,14 @@ public function shouldNotCreateRepositoryReleaseWithoutTagName() */ public function shouldEditRepositoryRelease() { - $expectedValue = array('updatedData'); + $expectedValue = ['updatedData']; $id = 332; - $data = array('some' => 'thing'); + $data = ['some' => 'thing']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('patch') - ->with('repos/KnpLabs/php-github-api/releases/'.$id) + ->with('/repos/KnpLabs/php-github-api/releases/'.$id) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->edit('KnpLabs', 'php-github-api', $id, $data)); @@ -94,13 +151,13 @@ public function shouldEditRepositoryRelease() */ public function shouldRemoveRepositoryRelease() { - $expectedValue = array('deleted'); + $expectedValue = ['deleted']; $id = 333; $api = $this->getApiMock(); $api->expects($this->once()) ->method('delete') - ->with('repos/KnpLabs/php-github-api/releases/'.$id) + ->with('/repos/KnpLabs/php-github-api/releases/'.$id) ->will($this->returnValue($expectedValue)); $this->assertEquals($expectedValue, $api->remove('KnpLabs', 'php-github-api', $id)); @@ -116,8 +173,11 @@ public function shouldGetAssetsApiObject() $this->assertInstanceOf('Github\Api\Repository\Assets', $api->assets()); } + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\Repository\Releases'; + return \Github\Api\Repository\Releases::class; } } diff --git a/test/Github/Tests/Api/Repository/SecretScanningTest.php b/test/Github/Tests/Api/Repository/SecretScanningTest.php new file mode 100644 index 00000000000..e2e98dfa879 --- /dev/null +++ b/test/Github/Tests/Api/Repository/SecretScanningTest.php @@ -0,0 +1,132 @@ + 1, 'state' => 'resolved', 'resolution' => 'false_positive'], + ['number' => 2, 'state' => 'open', 'resolution' => null], + ['number' => 3, 'state' => 'resolved', 'resolution' => 'wont_fix'], + ['number' => 4, 'state' => 'resolved', 'resolution' => 'revoked'], + ]; + + /** @var SecretScanning|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/secret-scanning/alerts') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->alerts('KnpLabs', 'php-github-api', [ + 'state' => 'all', + ])); + } + + /** + * @test + */ + public function shouldGetAlert() + { + $expectedArray = ['number' => 1, 'state' => 'resolved', 'resolution' => 'false_positive']; + + /** @var SecretScanning|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/secret-scanning/alerts/1') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->getAlert('KnpLabs', 'php-github-api', 1)); + } + + /** + * @test + */ + public function shouldUpdateAlert() + { + $expectedArray = ['number' => 1, 'state' => 'resolved', 'resolution' => 'false_positive']; + + /** @var SecretScanning|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('patch') + ->with('/repos/KnpLabs/php-github-api/secret-scanning/alerts/2') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->updateAlert('KnpLabs', 'php-github-api', 2, [ + 'state' => 'resolved', + 'resolution' => 'false_positive', + ])); + } + + /** + * @test + */ + public function shouldGetLocations() + { + $expectedArray = [ + [ + 'type' => 'commit', + 'details' => [ + 'path' => '/example/secrets.txt', + 'start_line' => 1, + 'end_line' => 1, + 'start_column' => 1, + 'end_column' => 64, + 'blob_sha' => 'af5626b4a114abcb82d63db7c8082c3c4756e51b', + 'blob_url' => 'https://HOSTNAME/repos/octocat/hello-world/git/blobs/af5626b4a114abcb82d63db7c8082c3c4756e51b', + 'commit_sha' => 'f14d7debf9775f957cf4f1e8176da0786431f72b', + 'commit_url' => 'https://HOSTNAME/repos/octocat/hello-world/git/commits/f14d7debf9775f957cf4f1e8176da0786431f72b', + ], + ], + [ + 'type' => 'commit', + 'details' => [ + 'path' => '/example/secrets.txt', + 'start_line' => 5, + 'end_line' => 5, + 'start_column' => 1, + 'end_column' => 64, + 'blob_sha' => '9def38117ab2d8355b982429aa924e268b4b0065', + 'blob_url' => 'https://HOSTNAME/repos/octocat/hello-world/git/blobs/9def38117ab2d8355b982429aa924e268b4b0065', + 'commit_sha' => '588483b99a46342501d99e3f10630cfc1219ea32', + 'commit_url' => 'https://HOSTNAME/repos/octocat/hello-world/git/commits/588483b99a46342501d99e3f10630cfc1219ea32', + ], + ], + ]; + + /** @var SecretScanning|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/secret-scanning/alerts/2/locations') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->locations('KnpLabs', 'php-github-api', 2, [ + 'per_page' => 10, + ])); + } + + protected function getApiClass() + { + return \Github\Api\Repository\SecretScanning::class; + } +} diff --git a/test/Github/Tests/Api/Repository/StargazersTest.php b/test/Github/Tests/Api/Repository/StargazersTest.php new file mode 100644 index 00000000000..0552100556c --- /dev/null +++ b/test/Github/Tests/Api/Repository/StargazersTest.php @@ -0,0 +1,49 @@ + 'nidup']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/stargazers') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api')); + } + + /** + * @test + */ + public function shouldGetAllRepositoryStargazersWithAlternativeResponse() + { + $expectedValue = [['starred_at' => '2013-10-01T13:22:01Z', 'user' => ['login' => 'nidup']]]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/stargazers') + ->will($this->returnValue($expectedValue)); + $api->configure('star'); + + $this->assertEquals($expectedValue, $api->all('KnpLabs', 'php-github-api')); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Repository\Stargazers::class; + } +} diff --git a/test/Github/Tests/Api/Repository/StatusesTest.php b/test/Github/Tests/Api/Repository/StatusesTest.php new file mode 100644 index 00000000000..e253955f25a --- /dev/null +++ b/test/Github/Tests/Api/Repository/StatusesTest.php @@ -0,0 +1,98 @@ + 'success', 'context' => 'Travis'], + ['state' => 'pending', 'context' => 'Travis'], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/commits/commitSHA123456/statuses') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->show('KnpLabs', 'php-github-api', 'commitSHA123456')); + } + + /** + * @test + */ + public function shouldShowCombinedCommitStatuses() + { + $expectedValue = [ + [ + 'state' => 'success', + 'statuses' => [ + [ + 'state' => 'success', + 'context' => 'Travis', + ], + [ + 'state' => 'success', + 'context' => 'Jenkins', + ], + ], + ], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/repos/KnpLabs/php-github-api/commits/commitSHA123456/status') + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->combined('KnpLabs', 'php-github-api', 'commitSHA123456')); + } + + /** + * @test + */ + public function shouldNotCreateWithoutStatus() + { + $this->expectException(MissingArgumentException::class); + $data = []; + + $api = $this->getApiMock(); + $api->expects($this->never()) + ->method('post'); + + $api->create('KnpLabs', 'php-github-api', 'commitSHA123456', $data); + } + + /** + * @test + */ + public function shouldCreateCommitStatus() + { + $expectedValue = ['state' => 'success']; + $data = ['state' => 'success']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('/repos/KnpLabs/php-github-api/statuses/commitSHA123456', $data) + ->will($this->returnValue($expectedValue)); + + $this->assertEquals($expectedValue, $api->create('KnpLabs', 'php-github-api', 'commitSHA123456', $data)); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Repository\Statuses::class; + } +} diff --git a/test/Github/Tests/Api/Repository/TrafficTest.php b/test/Github/Tests/Api/Repository/TrafficTest.php new file mode 100644 index 00000000000..b6136cebe86 --- /dev/null +++ b/test/Github/Tests/Api/Repository/TrafficTest.php @@ -0,0 +1,80 @@ + 'github.com', 'count' => 112, 'uniques' => 15]); + + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with('/repos/knplabs/php-github-api/traffic/popular/referrers') + ->will($this->returnValue($expectedValue)); + + $result = $api->referers('knplabs', 'php-github-api'); + + $this->assertEquals($expectedValue, $result); + } + + public function shouldgetPaths() + { + $expectedValue = json_encode(['path' => '/knplabs/php-github-api', 'title' => 'KnpLabs/php-github-api: A simple PHP GitHub API client, Object Oriented, tested and documented. For 5.5+.', 'count' => 203, 'uniques' => 54]); + + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with('/repos/knplabs/php-github-api/traffic/popular/paths') + ->will($this->returnValue($expectedValue)); + + $result = $api->paths('knplabs', 'php-github-api'); + + $this->assertEquals($expectedValue, $result); + } + + public function shouldgetViews() + { + $expectedValue = json_encode(['count' => 813, 'uniques' => 61, 'views' => [['timestamp' => '2017-03-12T00:00:00Z', 'count' => 40, 'uniques' => 3]]]); + + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with('/repos/knplabs/php-github-api/traffic/views?per=day') + ->will($this->returnValue($expectedValue)); + + $result = $api->views('knplabs', 'php-github-api'); + + $this->assertEquals($expectedValue, $result); + } + + public function shouldgetClones() + { + $expectedValue = json_encode(['count' => 813, 'uniques' => 61, 'clones' => [['timestamp' => '2017-03-12T00:00:00Z', 'count' => 14, 'uniques' => 8]]]); + + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with('/repos/knplabs/php-github-api/traffic/clones?per=day') + ->will($this->returnValue($expectedValue)); + + $result = $api->clones('knplabs', 'php-github-api'); + + $this->assertEquals($expectedValue, $result); + } + + protected function getApiClass() + { + return \Github\Api\Repository\Traffic::class; + } +} diff --git a/test/Github/Tests/Api/SearchTest.php b/test/Github/Tests/Api/SearchTest.php new file mode 100644 index 00000000000..feecb7b5a74 --- /dev/null +++ b/test/Github/Tests/Api/SearchTest.php @@ -0,0 +1,269 @@ + '0']]; + + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with( + '/search/repositories', + ['q' => 'query text', 'sort' => 'updated', 'order' => 'desc'] + ) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->repositories('query text')); + } + + /** + * @test + */ + public function shouldSearchRepositoriesRegardingSortAndOrder() + { + $expectedArray = [['total_count' => '0']]; + + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with( + '/search/repositories', + ['q' => 'query text', 'sort' => 'created', 'order' => 'asc'] + ) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals( + $expectedArray, + $api->repositories('query text', 'created', 'asc') + ); + } + + /** + * @test + */ + public function shouldSearchIssuesByQuery() + { + $expectedArray = [['total_count' => '0']]; + + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with( + '/search/issues', + ['q' => 'query text', 'sort' => 'updated', 'order' => 'desc'] + ) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->issues('query text')); + } + + /** + * @test + */ + public function shouldSearchIssuesRegardingSortAndOrder() + { + $expectedArray = [['total_count' => '0']]; + + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with( + '/search/issues', + ['q' => 'query text', 'sort' => 'created', 'order' => 'asc'] + ) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals( + $expectedArray, + $api->issues('query text', 'created', 'asc') + ); + } + + /** + * @test + */ + public function shouldSearchCodeByQuery() + { + $expectedArray = [['total_count' => '0']]; + + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with( + '/search/code', + ['q' => 'query text', 'sort' => 'updated', 'order' => 'desc'] + ) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->code('query text')); + } + + /** + * @test + */ + public function shouldSearchCodeRegardingSortAndOrder() + { + $expectedArray = [['total_count' => '0']]; + + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with( + '/search/code', + ['q' => 'query text', 'sort' => 'created', 'order' => 'asc'] + ) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals( + $expectedArray, + $api->code('query text', 'created', 'asc') + ); + } + + /** + * @test + */ + public function shouldSearchCodeWithMatchByQuery() + { + $expectedArray = [['total_count' => '0']]; + + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with( + '/search/code', + ['q' => 'query text', 'sort' => 'updated', 'order' => 'desc'] + ) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->codeWithMatch('query text')); + } + + /** + * @test + */ + public function shouldSearchCodeWithMatchRegardingSortAndOrder() + { + $expectedArray = [['total_count' => '0']]; + + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with( + '/search/code', + ['q' => 'query text', 'sort' => 'created', 'order' => 'asc'] + ) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals( + $expectedArray, + $api->codeWithMatch('query text', 'created', 'asc') + ); + } + + /** + * @test + */ + public function shouldSearchUsersByQuery() + { + $expectedArray = [['total_count' => '0']]; + + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with( + '/search/users', + ['q' => 'query text', 'sort' => 'updated', 'order' => 'desc'] + ) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->users('query text')); + } + + /** + * @test + */ + public function shouldSearchUsersRegardingSortAndOrder() + { + $expectedArray = [['total_count' => '0']]; + + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with( + '/search/users', + ['q' => 'query text', 'sort' => 'created', 'order' => 'asc'] + ) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals( + $expectedArray, + $api->users('query text', 'created', 'asc') + ); + } + + /** + * @test + */ + public function shouldSearchCommitsRegardingSortAndOrder() + { + $expectedArray = ['total_count' => '0']; + + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with('/search/commits', ['q' => 'query text', 'sort' => 'author-date', 'order' => 'asc']) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals( + $expectedArray, + $api->commits('query text', 'author-date', 'asc') + ); + } + + /** + * @test + */ + public function shouldSearchTopics() + { + $expectedArray = ['total_count' => '0']; + + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with('/search/topics', ['q' => 'query text']) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals( + $expectedArray, + $api->topics('query text') + ); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\Search::class; + } +} diff --git a/test/Github/Tests/Api/TestCase.php b/test/Github/Tests/Api/TestCase.php index b96f0e43bbb..4fd6a49234c 100644 --- a/test/Github/Tests/Api/TestCase.php +++ b/test/Github/Tests/Api/TestCase.php @@ -2,25 +2,48 @@ namespace Github\Tests\Api; -abstract class TestCase extends \PHPUnit_Framework_TestCase +use Github\Client; +use Psr\Http\Client\ClientInterface; +use ReflectionMethod; + +abstract class TestCase extends \PHPUnit\Framework\TestCase { + /** + * @return string + */ abstract protected function getApiClass(); + /** + * @return \PHPUnit\Framework\MockObject\MockObject + */ protected function getApiMock() { - $httpClient = $this->getMock('Guzzle\Http\Client', array('send')); + $httpClient = $this->getMockBuilder(ClientInterface::class) + ->setMethods(['sendRequest']) + ->getMock(); $httpClient ->expects($this->any()) - ->method('send'); + ->method('sendRequest'); - $mock = $this->getMock('Github\HttpClient\HttpClient', array(), array(array(), $httpClient)); - - $client = new \Github\Client($mock); - $client->setHttpClient($mock); + $client = Client::createWithHttpClient($httpClient); return $this->getMockBuilder($this->getApiClass()) - ->setMethods(array('get', 'post', 'postRaw', 'patch', 'delete', 'put')) - ->setConstructorArgs(array($client)) + ->setMethods(['get', 'post', 'postRaw', 'patch', 'delete', 'put', 'head']) + ->setConstructorArgs([$client]) ->getMock(); } + + /** + * @param object $object + * @param string $methodName + * + * @return ReflectionMethod + */ + protected function getMethod($object, $methodName) + { + $method = new ReflectionMethod($object, $methodName); + $method->setAccessible(true); + + return $method; + } } diff --git a/test/Github/Tests/Api/User/MigrationTest.php b/test/Github/Tests/Api/User/MigrationTest.php new file mode 100644 index 00000000000..3ee1620a3ae --- /dev/null +++ b/test/Github/Tests/Api/User/MigrationTest.php @@ -0,0 +1,186 @@ + 79, + 'state' => 'pending', + 'lock_repositories' => true, + 'repositories' => [ + [ + 'id' => 1296269, + 'name' => 'Hello-World', + 'full_name' => 'octocat/Hello-World', + ], + ], + ], + [ + 'id' => 2, + 'name' => 'pending', + 'lock_repositories' => false, + 'repositories' => [ + [ + 'id' => 123, + 'name' => 'php-github-api', + 'full_name' => 'KnpLabs/php-github-api', + ], + ], + ], + ]; + + /** @var Migration|MockObject $api */ + $api = $this->getApiMock(); + + $api + ->expects($this->once()) + ->method('get') + ->with('/user/migrations') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->list()); + } + + /** + * @test + */ + public function shouldStartMigration() + { + $expectedArray = [ + 'id' => 79, + 'state' => 'pending', + 'lock_repositories' => true, + 'repositories' => [ + [ + 'id' => 1296269, + 'name' => 'Hello-World', + 'full_name' => 'octocat/Hello-World', + ], + ], + ]; + + /** @var Migration|MockObject $api */ + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('post') + ->with('/user/migrations') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->start([ + 'lock_repositories' => true, + 'repositories' => [ + 'KnpLabs/php-github-api', + ], + ])); + } + + /** + * @test + */ + public function shouldGetMigrationStatus() + { + $expectedArray = [ + 'id' => 79, + 'state' => 'exported', + 'lock_repositories' => true, + 'repositories' => [ + [ + 'id' => 1296269, + 'name' => 'Hello-World', + 'full_name' => 'octocat/Hello-World', + ], + ], + ]; + + /** @var Migration|MockObject $api */ + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with('/user/migrations/79') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->status(79)); + } + + /** + * @test + */ + public function shouldDeleteMigrationArchive() + { + /** @var Migration|MockObject $api */ + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('delete') + ->with('/user/migrations/79/archive') + ->will($this->returnValue(204)); + + $this->assertEquals(204, $api->deleteArchive(79)); + } + + /** + * @test + */ + public function shouldUnlockUserRepo() + { + /** @var Migration|MockObject $api */ + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('delete') + ->with('/user/migrations/79/repos/php-github-api/lock') + ->will($this->returnValue(204)); + + $this->assertEquals(204, $api->unlockRepo(79, 'php-github-api')); + } + + /** + * @test + */ + public function shouldListRepos() + { + $expectedArray = [ + [ + 'id' => 1296269, + 'name' => 'Hello-World', + 'full_name' => 'test/Hello-World', + ], + [ + 'id' => 234324, + 'name' => 'Hello-World2', + 'full_name' => 'test/Hello-World2', + ], + ]; + + /** @var Migration|MockObject $api */ + $api = $this->getApiMock(); + + $api->expects($this->once()) + ->method('get') + ->with('/user/migrations/79/repositories') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->repos(79)); + } + + /** + * @return string + */ + protected function getApiClass() + { + return \Github\Api\User\Migration::class; + } +} diff --git a/test/Github/Tests/Api/UserTest.php b/test/Github/Tests/Api/UserTest.php index dd3811dd8fb..0be80a28f01 100644 --- a/test/Github/Tests/Api/UserTest.php +++ b/test/Github/Tests/Api/UserTest.php @@ -9,12 +9,12 @@ class UserTest extends TestCase */ public function shouldShowUser() { - $expectedArray = array('id' => 1, 'username' => 'l3l0'); + $expectedArray = ['id' => 1, 'username' => 'l3l0']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('users/l3l0') + ->with('/users/l3l0') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->show('l3l0')); @@ -23,20 +23,98 @@ public function shouldShowUser() /** * @test */ - public function shouldSearchUsers() + public function shouldShowByIdUser() { - $expectedArray = array( - array('id' => 1, 'username' => 'l3l0'), - array('id' => 2, 'username' => 'l3l0test') - ); + $expectedArray = ['id' => 1, 'username' => 'l3l0']; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('legacy/user/search/l3l0') + ->with('/user/1') ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->find('l3l0')); + $this->assertEquals($expectedArray, $api->showById(1)); + } + + /** + * @test + */ + public function shouldGetUserOrganizations() + { + $expectedArray = [[ + 'id' => 202732, + 'url' => 'https://api.github.com/orgs/KnpLabs', + 'repos_url' => 'https://api.github.com/orgs/KnpLabs/repos', + 'events_url' => 'https://api.github.com/orgs/KnpLabs/events', + 'members_url' => 'https://api.github.com/orgs/KnpLabs/members{/member}', + 'public_members_url' => 'https://api.github.com/orgs/KnpLabs/public_members{/member}', + ]]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/users/l3l0/orgs') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->organizations('l3l0')); + } + + public function shouldGetUserOrgs() + { + $expectedArray = [[ + 'id' => 202732, + 'url' => 'https://api.github.com/orgs/KnpLabs', + 'repos_url' => 'https://api.github.com/orgs/KnpLabs/repos', + 'events_url' => 'https://api.github.com/orgs/KnpLabs/events', + 'members_url' => 'https://api.github.com/orgs/KnpLabs/members{/member}', + 'public_members_url' => 'https://api.github.com/orgs/KnpLabs/public_members{/member}', + ]]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/user/orgs') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->orgs()); + } + + /** + * @test + */ + public function shouldGetAllUsers() + { + $expectedArray = [ + ['id' => 1, 'username' => 'l3l0'], + ['id' => 2, 'username' => 'l3l0test'], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/users') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all()); + } + + /** + * @test + */ + public function shouldGetAllUsersSince() + { + $expectedArray = [ + ['id' => 3, 'username' => 'test3'], + ['id' => 4, 'username' => 'test4'], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/users', ['since' => 2]) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->all(2)); } /** @@ -44,12 +122,12 @@ public function shouldSearchUsers() */ public function shouldGetFollowingUsers() { - $expectedArray = array(array('id' => 1, 'username' => 'l3l0test')); + $expectedArray = [['id' => 1, 'username' => 'l3l0test']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('users/l3l0/following') + ->with('/users/l3l0/following') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->following('l3l0')); @@ -60,12 +138,12 @@ public function shouldGetFollowingUsers() */ public function shouldGetUserFollowers() { - $expectedArray = array(array('id' => 1, 'username' => 'l3l0test')); + $expectedArray = [['id' => 1, 'username' => 'l3l0test']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('users/l3l0/followers') + ->with('/users/l3l0/followers') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->followers('l3l0')); @@ -74,17 +152,33 @@ public function shouldGetUserFollowers() /** * @test */ - public function shouldGetWatchedRepositories() + public function shouldGetStarredToRepositories() + { + $expectedArray = [['id' => 1, 'name' => 'l3l0repo']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/users/l3l0/starred', ['page' => 2, 'per_page' => 30, 'sort' => 'created', 'direction' => 'desc']) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->starred('l3l0', 2)); + } + + /** + * @test + */ + public function shouldGetSubscriptionsToRepositories() { - $expectedArray = array(array('id' => 1, 'name' => 'l3l0repo')); + $expectedArray = [['id' => 1, 'name' => 'l3l0repo']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('users/l3l0/watched') + ->with('/users/l3l0/subscriptions') ->will($this->returnValue($expectedArray)); - $this->assertEquals($expectedArray, $api->watched('l3l0')); + $this->assertEquals($expectedArray, $api->subscriptions('l3l0')); } /** @@ -92,35 +186,76 @@ public function shouldGetWatchedRepositories() */ public function shouldGetUserRepositories() { - $expectedArray = array(array('id' => 1, 'name' => 'l3l0repo')); + $expectedArray = [['id' => 1, 'name' => 'l3l0repo']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('users/l3l0/repos') + ->with('/users/l3l0/repos', ['type' => 'owner', 'sort' => 'full_name', 'direction' => 'asc', 'visibility' => 'all', 'affiliation' => 'owner,collaborator,organization_member']) ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->repositories('l3l0')); } + /** + * @test + */ + public function shouldGetMyRepositories() + { + $expectedArray = [['id' => 1, 'name' => 'l3l0repo']]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get')->with('/user/repos', []) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->myRepositories()); + } + /** * @test */ public function shouldGetUserGists() { - $expectedArray = array(array('id' => 1, 'name' => 'l3l0repo')); + $expectedArray = [['id' => 1, 'name' => 'l3l0repo']]; $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('users/l3l0/gists') + ->with('/users/l3l0/gists') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->gists('l3l0')); } + /** + * @test + */ + public function shouldGetAuthorizedUserEvents() + { + $expectedArray = [ + [ + 'id' => 1, + 'actor' => [ + 'id' => 1, + 'login' => 'l3l0', + ], + ], + ]; + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('/users/l3l0/events') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->events('l3l0')); + } + + /** + * @return string + */ protected function getApiClass() { - return 'Github\Api\User'; + return \Github\Api\User::class; } } diff --git a/test/Github/Tests/ClientTest.php b/test/Github/Tests/ClientTest.php index 29e926b246a..e5992284404 100644 --- a/test/Github/Tests/ClientTest.php +++ b/test/Github/Tests/ClientTest.php @@ -2,10 +2,18 @@ namespace Github\Tests; +use Github\Api; +use Github\AuthMethod; use Github\Client; +use Github\Exception\BadMethodCallException; use Github\Exception\InvalidArgumentException; +use Github\HttpClient\Builder; +use Github\HttpClient\Plugin\Authentication; +use GuzzleHttp\Psr7\Response; +use Psr\Http\Client\ClientInterface; +use Psr\Http\Message\RequestInterface; -class ClientTest extends \PHPUnit_Framework_TestCase +class ClientTest extends \PHPUnit\Framework\TestCase { /** * @test @@ -14,7 +22,7 @@ public function shouldNotHaveToPassHttpClientToConstructor() { $client = new Client(); - $this->assertInstanceOf('Github\HttpClient\HttpClient', $client->getHttpClient()); + $this->assertInstanceOf(ClientInterface::class, $client->getHttpClient()); } /** @@ -22,162 +30,221 @@ public function shouldNotHaveToPassHttpClientToConstructor() */ public function shouldPassHttpClientInterfaceToConstructor() { - $client = new Client($this->getHttpClientMock()); + $httpClientMock = $this->getMockBuilder(ClientInterface::class) + ->getMock(); - $this->assertInstanceOf('Github\HttpClient\HttpClientInterface', $client->getHttpClient()); + $client = Client::createWithHttpClient($httpClientMock); + + $this->assertInstanceOf(ClientInterface::class, $client->getHttpClient()); } /** * @test + * * @dataProvider getAuthenticationFullData */ public function shouldAuthenticateUsingAllGivenParameters($login, $password, $method) { - $httpClient = $this->getHttpClientMock(); - $httpClient->expects($this->once()) - ->method('authenticate') - ->with($login, $password, $method); + $builder = $this->getMockBuilder(Builder::class) + ->setMethods(['addPlugin', 'removePlugin']) + ->disableOriginalConstructor() + ->getMock(); + $builder->expects($this->once()) + ->method('addPlugin') + ->with($this->equalTo(new Authentication($login, $password, $method))); + $builder->expects($this->once()) + ->method('removePlugin') + ->with(Authentication::class); + + $client = $this->getMockBuilder(\Github\Client::class) + ->disableOriginalConstructor() + ->setMethods(['getHttpClientBuilder']) + ->getMock(); + $client->expects($this->any()) + ->method('getHttpClientBuilder') + ->willReturn($builder); - $client = new Client($httpClient); $client->authenticate($login, $password, $method); } public function getAuthenticationFullData() { - return array( - array('login', 'password', Client::AUTH_HTTP_PASSWORD), - array('token', null, Client::AUTH_HTTP_TOKEN), - array('token', null, Client::AUTH_URL_TOKEN), - array('client_id', 'client_secret', Client::AUTH_URL_CLIENT_ID), - ); + return [ + ['token', null, AuthMethod::ACCESS_TOKEN], + ['client_id', 'client_secret', AuthMethod::CLIENT_ID], + ['token', null, AuthMethod::JWT], + ]; } /** * @test - * @dataProvider getAuthenticationPartialData */ - public function shouldAuthenticateUsingGivenParameters($token, $method) - { - $httpClient = $this->getHttpClientMock(); - $httpClient->expects($this->once()) - ->method('authenticate') - ->with($token, null, $method); - - $client = new Client($httpClient); - $client->authenticate($token, $method); - } - - public function getAuthenticationPartialData() + public function shouldAuthenticateUsingGivenParameters() { - return array( - array('token', Client::AUTH_HTTP_TOKEN), - array('token', Client::AUTH_URL_TOKEN), - ); + $builder = $this->getMockBuilder(Builder::class) + ->setMethods(['addPlugin', 'removePlugin']) + ->getMock(); + $builder->expects($this->once()) + ->method('addPlugin') + ->with($this->equalTo(new Authentication('token', null, AuthMethod::ACCESS_TOKEN))); + + $builder->expects($this->once()) + ->method('removePlugin') + ->with(Authentication::class); + + $client = $this->getMockBuilder(\Github\Client::class) + ->disableOriginalConstructor() + ->setMethods(['getHttpClientBuilder']) + ->getMock(); + $client->expects($this->any()) + ->method('getHttpClientBuilder') + ->willReturn($builder); + + $client->authenticate('token', AuthMethod::ACCESS_TOKEN); } /** * @test - * @expectedException InvalidArgumentException */ public function shouldThrowExceptionWhenAuthenticatingWithoutMethodSet() { - $httpClient = $this->getHttpClientMock(array('addListener')); + $this->expectException(InvalidArgumentException::class); + $client = new Client(); - $client = new Client($httpClient); $client->authenticate('login', null, null); } /** * @test + * + * @dataProvider getApiClassesProvider */ - public function shouldClearHeadersLazy() + public function shouldGetApiInstance($apiName, $class) { - $httpClient = $this->getHttpClientMock(array('clearHeaders')); - $httpClient->expects($this->once())->method('clearHeaders'); + $client = new Client(); - $client = new Client($httpClient); - $client->clearHeaders(); + $this->assertInstanceOf($class, $client->api($apiName)); } /** * @test + * + * @dataProvider getApiClassesProvider */ - public function shouldSetHeadersLaizly() + public function shouldGetMagicApiInstance($apiName, $class) { - $headers = array('header1', 'header2'); - - $httpClient = $this->getHttpClientMock(); - $httpClient->expects($this->once())->method('setHeaders')->with($headers); + $client = new Client(); - $client = new Client($httpClient); - $client->setHeaders($headers); + $this->assertInstanceOf($class, $client->$apiName()); } /** * @test - * @dataProvider getApiClassesProvider */ - public function shouldGetApiInstance($apiName, $class) + public function shouldNotGetApiInstance() { + $this->expectException(InvalidArgumentException::class); $client = new Client(); - - $this->assertInstanceOf($class, $client->api($apiName)); + $client->api('do_not_exist'); } /** * @test - * @expectedException InvalidArgumentException */ - public function shouldNotGetApiInstance() + public function shouldNotGetMagicApiInstance() { + $this->expectException(BadMethodCallException::class); $client = new Client(); - $client->api('do_not_exist'); + $client->doNotExist(); } public function getApiClassesProvider() { - return array( - array('user', 'Github\Api\User'), - array('users', 'Github\Api\User'), + return [ + ['user', Api\User::class], + ['users', Api\User::class], + + ['me', Api\CurrentUser::class], + ['current_user', Api\CurrentUser::class], + ['currentUser', Api\CurrentUser::class], + + ['git', Api\GitData::class], + ['git_data', Api\GitData::class], + ['gitData', Api\GitData::class], - array('me', 'Github\Api\CurrentUser'), - array('current_user', 'Github\Api\CurrentUser'), + ['gist', Api\Gists::class], + ['gists', Api\Gists::class], - array('git', 'Github\Api\GitData'), - array('git_data', 'Github\Api\GitData'), + ['issue', Api\Issue::class], + ['issues', Api\Issue::class], - array('gist', 'Github\Api\Gists'), - array('gists', 'Github\Api\Gists'), + ['markdown', Api\Markdown::class], - array('issue', 'Github\Api\Issue'), - array('issues', 'Github\Api\Issue'), + ['organization', Api\Organization::class], + ['organizations', Api\Organization::class], - array('markdown', 'Github\Api\Markdown'), + ['repo', Api\Repo::class], + ['repos', Api\Repo::class], + ['repository', Api\Repo::class], + ['repositories', Api\Repo::class], - array('organization', 'Github\Api\Organization'), - array('organizations', 'Github\Api\Organization'), + ['search', Api\Search::class], - array('repo', 'Github\Api\Repo'), - array('repos', 'Github\Api\Repo'), - array('repository', 'Github\Api\Repo'), - array('repositories', 'Github\Api\Repo'), + ['pr', Api\PullRequest::class], + ['pullRequest', Api\PullRequest::class], + ['pull_request', Api\PullRequest::class], + ['pullRequests', Api\PullRequest::class], + ['pull_requests', Api\PullRequest::class], - array('pr', 'Github\Api\PullRequest'), - array('pull_request', 'Github\Api\PullRequest'), - array('pull_requests', 'Github\Api\PullRequest'), + ['authorization', Api\Authorizations::class], + ['authorizations', Api\Authorizations::class], - array('authorization', 'Github\Api\Authorizations'), - array('authorizations', 'Github\Api\Authorizations'), - ); + ['meta', Api\Meta::class], + + ['outsideCollaborators', Api\Organization\OutsideCollaborators::class], + ['outside_collaborators', Api\Organization\OutsideCollaborators::class], + ]; } - public function getHttpClientMock(array $methods = array()) + /** + * Make sure that the URL is correct when using enterprise. + */ + public function testEnterpriseUrl() { - $methods = array_merge( - array('get', 'post', 'patch', 'put', 'delete', 'request', 'setOption', 'setHeaders', 'authenticate'), - $methods - ); + $httpClientMock = $this->getMockBuilder(ClientInterface::class) + ->setMethods(['sendRequest']) + ->getMock(); + + $httpClientMock->expects($this->once()) + ->method('sendRequest') + ->with($this->callback(function (RequestInterface $request) { + return (string) $request->getUri() === 'https://foobar.com/api/v3/enterprise/stats/all'; + })) + ->willReturn(new Response(200, [], '[]')); + + $httpClientBuilder = new Builder($httpClientMock); + $client = new Client($httpClientBuilder, null, 'https://foobar.com'); + $client->enterprise()->stats()->show('all'); + } - return $this->getMock('Github\HttpClient\HttpClientInterface', $methods); + /** + * Make sure that the prepend is correct when using the v4 endpoint on Enterprise. + */ + public function testEnterprisePrependGraphQLV4() + { + $httpClientMock = $this->getMockBuilder(ClientInterface::class) + ->setMethods(['sendRequest']) + ->getMock(); + + $httpClientMock->expects($this->once()) + ->method('sendRequest') + ->with($this->callback(function (RequestInterface $request) { + return (string) $request->getUri() === 'https://foobar.com/api/graphql'; + })) + ->willReturn(new Response(200, [], '[]')); + + $httpClientBuilder = new Builder($httpClientMock); + $client = new Client($httpClientBuilder, 'v4', 'https://foobar.com'); + $client->graphql()->execute('query'); } } diff --git a/test/Github/Tests/Functional/CacheTest.php b/test/Github/Tests/Functional/CacheTest.php new file mode 100644 index 00000000000..bd217dc5dc2 --- /dev/null +++ b/test/Github/Tests/Functional/CacheTest.php @@ -0,0 +1,71 @@ + + */ +class CacheTest extends \PHPUnit\Framework\TestCase +{ + /** + * @test + */ + public function shouldServeCachedResponse() + { + $mockClient = new \Http\Mock\Client(); + $mockClient->addResponse($this->getCurrentUserResponse('nyholm')); + $mockClient->addResponse($this->getCurrentUserResponse('octocat')); + + $github = Client::createWithHttpClient($mockClient); + $github->addCache(new ArrayAdapter(), ['default_ttl' => 600]); + + $github->authenticate('fake_token_aaa', AuthMethod::ACCESS_TOKEN); + $userA = $github->currentUser()->show(); + $this->assertEquals('nyholm', $userA['login']); + + $userB = $github->currentUser()->show(); + $this->assertEquals('nyholm', $userB['login'], 'Two request following each other should be cached.'); + } + + /** + * @test + */ + public function shouldVaryOnAuthorization() + { + $mockClient = new \Http\Mock\Client(); + $mockClient->addResponse($this->getCurrentUserResponse('nyholm')); + $mockClient->addResponse($this->getCurrentUserResponse('octocat')); + + $github = Client::createWithHttpClient($mockClient); + $github->addCache(new ArrayAdapter(), ['default_ttl' => 600]); + + $github->authenticate('fake_token_aaa', AuthMethod::ACCESS_TOKEN); + $userA = $github->currentUser()->show(); + $this->assertEquals('nyholm', $userA['login']); + + $github->authenticate('fake_token_bbb', AuthMethod::ACCESS_TOKEN); + $userB = $github->currentUser()->show(); + $this->assertEquals('octocat', $userB['login'], 'We must vary on the Authorization header.'); + } + + private function getCurrentUserResponse($username) + { + $headers = [ + 'Content-Type' => 'application/json', + ]; + + $body = Utils::streamFor(json_encode([ + 'login' => $username, + ])); + + return new Response(200, $headers, $body); + } +} diff --git a/test/Github/Tests/Functional/ResultPagerTest.php b/test/Github/Tests/Functional/ResultPagerTest.php deleted file mode 100644 index 9c67b39d25a..00000000000 --- a/test/Github/Tests/Functional/ResultPagerTest.php +++ /dev/null @@ -1,29 +0,0 @@ -client->api('user'); - $repositoriesApi->setPerPage(10); - - $pager = new ResultPager($this->client); - - $repositories = $pager->fetch($repositoriesApi, 'repositories', array('KnpLabs')); - $this->assertCount(10, $repositories); - - $repositoriesApi->setPerPage(20); - $repositories = $pager->fetch($repositoriesApi, 'repositories', array('KnpLabs')); - $this->assertCount(20, $repositories); - } -} diff --git a/test/Github/Tests/HttpClient/BuilderTest.php b/test/Github/Tests/HttpClient/BuilderTest.php new file mode 100644 index 00000000000..33d21025f0e --- /dev/null +++ b/test/Github/Tests/HttpClient/BuilderTest.php @@ -0,0 +1,76 @@ + + */ +class BuilderTest extends \PHPUnit\Framework\TestCase +{ + /** + * @test + */ + public function shouldClearHeaders() + { + $builder = $this->getMockBuilder(\Github\HttpClient\Builder::class) + ->setMethods(['addPlugin', 'removePlugin']) + ->getMock(); + $builder->expects($this->once()) + ->method('addPlugin') + ->with($this->isInstanceOf(Plugin\HeaderAppendPlugin::class)); + + $builder->expects($this->once()) + ->method('removePlugin') + ->with(Plugin\HeaderAppendPlugin::class); + + $builder->clearHeaders(); + } + + /** + * @test + */ + public function shouldAddHeaders() + { + $headers = ['header1', 'header2']; + + $client = $this->getMockBuilder(\Github\HttpClient\Builder::class) + ->setMethods(['addPlugin', 'removePlugin']) + ->getMock(); + $client->expects($this->once()) + ->method('addPlugin') + // TODO verify that headers exists + ->with($this->isInstanceOf(Plugin\HeaderAppendPlugin::class)); + + $client->expects($this->once()) + ->method('removePlugin') + ->with(Plugin\HeaderAppendPlugin::class); + + $client->addHeaders($headers); + } + + /** + * @test + */ + public function appendingHeaderShouldAddAndRemovePlugin() + { + $expectedHeaders = [ + 'Accept' => 'application/vnd.github.v3', + ]; + + $client = $this->getMockBuilder(\Github\HttpClient\Builder::class) + ->setMethods(['removePlugin', 'addPlugin']) + ->getMock(); + + $client->expects($this->once()) + ->method('removePlugin') + ->with(Plugin\HeaderAppendPlugin::class); + + $client->expects($this->once()) + ->method('addPlugin') + ->with(new Plugin\HeaderAppendPlugin($expectedHeaders)); + + $client->addHeaderValue('Accept', 'application/vnd.github.v3'); + } +} diff --git a/test/Github/Tests/HttpClient/Cache/FilesystemCacheTest.php b/test/Github/Tests/HttpClient/Cache/FilesystemCacheTest.php deleted file mode 100644 index 54efdd49ba4..00000000000 --- a/test/Github/Tests/HttpClient/Cache/FilesystemCacheTest.php +++ /dev/null @@ -1,43 +0,0 @@ -set('test', new Response(200)); - - $this->assertNotNull($cache->get('test')); - } - - /** - * @test - */ - public function shouldGetATimestampForExistingFile() - { - $cache = new FilesystemCache('/tmp/github-api-test'); - - $cache->set('test', new Response(200)); - - $this->assertInternalType('int', $cache->getModifiedSince('test')); - } - - /** - * @test - */ - public function shouldNotGetATimestampForInexistingFile() - { - $cache = new FilesystemCache('/tmp/github-api-test'); - - $this->assertNull($cache->getModifiedSince('test2')); - } -} diff --git a/test/Github/Tests/HttpClient/Cache/GaufretteCacheTest.php b/test/Github/Tests/HttpClient/Cache/GaufretteCacheTest.php deleted file mode 100644 index 2a84f14ad54..00000000000 --- a/test/Github/Tests/HttpClient/Cache/GaufretteCacheTest.php +++ /dev/null @@ -1,84 +0,0 @@ -markTestSkipped('Gaufrette not installed.'); - } - } - - /** - * @test - */ - public function shouldStoreAResponseForAGivenKey() - { - $response = new Response(200); - $filesystem = $this->getMockBuilder('Gaufrette\Filesystem')->disableOriginalConstructor()->getMock(); - $filesystem - ->expects($this->once()) - ->method('write') - ->with('test', serialize($response)) - ; - $filesystem - ->expects($this->once()) - ->method('read') - ->with('test') - ->will($this->returnValue('a:0:{}')) - ; - - $cache = new GaufretteCache($filesystem); - $cache->set('test', $response); - $this->assertNotNull($cache->get('test')); - } - - /** - * @test - */ - public function shouldGetATimestampForExistingFile() - { - $response = new Response(200); - $filesystem = $this->getMockBuilder('Gaufrette\Filesystem')->disableOriginalConstructor()->getMock(); - $filesystem - ->expects($this->once()) - ->method('has') - ->with('test') - ->will($this->returnValue(true)) - ; - $filesystem - ->expects($this->once()) - ->method('mtime') - ->with('test') - ->will($this->returnValue(100)) - ; - - $cache = new GaufretteCache($filesystem); - $cache->set('test', new Response(200)); - - $this->assertInternalType('int', $cache->getModifiedSince('test')); - } - - /** - * @test - */ - public function shouldNotGetATimestampForInexistingFile() - { - $filesystem = $this->getMockBuilder('Gaufrette\Filesystem')->disableOriginalConstructor()->getMock(); - $filesystem - ->expects($this->once()) - ->method('has') - ->with('test2') - ->will($this->returnValue(false)) - ; - - $cache = new GaufretteCache($filesystem); - - $this->assertNull($cache->getModifiedSince('test2')); - } -} diff --git a/test/Github/Tests/HttpClient/CachedHttpClientTest.php b/test/Github/Tests/HttpClient/CachedHttpClientTest.php deleted file mode 100644 index 477b3e2eab3..00000000000 --- a/test/Github/Tests/HttpClient/CachedHttpClientTest.php +++ /dev/null @@ -1,78 +0,0 @@ -getCacheMock(); - $response = new Response(200); - - $client = $this->getBrowserMock(); - $client->expects($this->once()) - ->method('send') - ->will($this->returnValue($response)); - - $httpClient = new CachedHttpClient(array('base_url' => ''), $client); - $httpClient->setCache($cache); - - $cache->expects($this->once())->method('set')->with('test', $response); - $httpClient->get('test'); - } - - /** - * @test - */ - public function shouldGetCachedResponseWhileResourceNotModified() - { - $cache = $this->getCacheMock(); - $response = new Response(304); - - $client = $this->getBrowserMock(); - $client->expects($this->once()) - ->method('send') - ->will($this->returnValue($response)); - - $httpClient = new CachedHttpClient(array('base_url' => ''), $client); - $httpClient->setCache($cache); - $httpClient->fakeResponse = $response; - - $cache->expects($this->once())->method('get')->with('test'); - - $httpClient->get('test'); - } - - /** - * @test - */ - public function shouldRenewCacheWhenResourceHasChanged() - { - $cache = $this->getCacheMock(); - $response = new Response(200); - - $client = $this->getBrowserMock(); - $client->expects($this->once()) - ->method('send') - ->will($this->returnValue($response)); - - $httpClient = new CachedHttpClient(array('base_url' => ''), $client); - $httpClient->setCache($cache); - - $cache->expects($this->once())->method('set')->with('test', $response); - $cache->expects($this->once())->method('getModifiedSince')->with('test')->will($this->returnValue(1256953732)); - - $httpClient->get('test'); - } - - public function getCacheMock() - { - return $this->getMock('Github\HttpClient\Cache\CacheInterface'); - } -} diff --git a/test/Github/Tests/HttpClient/HttpClientTest.php b/test/Github/Tests/HttpClient/HttpClientTest.php deleted file mode 100644 index cb83e9af96d..00000000000 --- a/test/Github/Tests/HttpClient/HttpClientTest.php +++ /dev/null @@ -1,276 +0,0 @@ - 33 - ), $this->getBrowserMock()); - - $this->assertEquals(33, $httpClient->getOption('timeout')); - $this->assertEquals(5000, $httpClient->getOption('api_limit')); - } - - /** - * @test - */ - public function shouldBeAbleToSetOption() - { - $httpClient = new TestHttpClient(array(), $this->getBrowserMock()); - $httpClient->setOption('timeout', 666); - - $this->assertEquals(666, $httpClient->getOption('timeout')); - } - - /** - * @test - * @dataProvider getAuthenticationFullData - */ - public function shouldAuthenticateUsingAllGivenParameters($login, $password, $method) - { - $client = new GuzzleClient(); - $listeners = $client->getEventDispatcher()->getListeners('request.before_send'); - $this->assertCount(1, $listeners); - - $httpClient = new TestHttpClient(array(), $client); - $httpClient->authenticate($login, $password, $method); - - $listeners = $client->getEventDispatcher()->getListeners('request.before_send'); - $this->assertCount(2, $listeners); - - $authListener = $listeners[1][0]; - $this->assertInstanceOf('Github\HttpClient\Listener\AuthListener', $authListener); - } - - public function getAuthenticationFullData() - { - return array( - array('login', 'password', Client::AUTH_HTTP_PASSWORD), - array('token', null, Client::AUTH_HTTP_TOKEN), - array('token', null, Client::AUTH_URL_TOKEN), - array('client_id', 'client_secret', Client::AUTH_URL_CLIENT_ID), - ); - } - - /** - * @test - */ - public function shouldDoGETRequest() - { - $path = '/some/path'; - $parameters = array('a' => 'b'); - $headers = array('c' => 'd'); - - $client = $this->getBrowserMock(); - - $httpClient = new HttpClient(array(), $client); - $httpClient->get($path, $parameters, $headers); - } - - /** - * @test - */ - public function shouldDoPOSTRequest() - { - $path = '/some/path'; - $body = 'a = b'; - $headers = array('c' => 'd'); - - $client = $this->getBrowserMock(); - $client->expects($this->once()) - ->method('createRequest') - ->with('POST', $path, $this->isType('array'), $body); - - $httpClient = new HttpClient(array(), $client); - $httpClient->post($path, $body, $headers); - } - - /** - * @test - */ - public function shouldDoPOSTRequestWithoutContent() - { - $path = '/some/path'; - - $client = $this->getBrowserMock(); - $client->expects($this->once()) - ->method('createRequest') - ->with('POST', $path, $this->isType('array')); - - $httpClient = new HttpClient(array(), $client); - $httpClient->post($path); - } - - /** - * @test - */ - public function shouldDoPATCHRequest() - { - $path = '/some/path'; - $body = 'a = b'; - $headers = array('c' => 'd'); - - $client = $this->getBrowserMock(); - - $httpClient = new HttpClient(array(), $client); - $httpClient->patch($path, $body, $headers); - } - - /** - * @test - */ - public function shouldDoDELETERequest() - { - $path = '/some/path'; - $body = 'a = b'; - $headers = array('c' => 'd'); - - $client = $this->getBrowserMock(); - - $httpClient = new HttpClient(array(), $client); - $httpClient->delete($path, $body, $headers); - } - - /** - * @test - */ - public function shouldDoPUTRequest() - { - $path = '/some/path'; - $headers = array('c' => 'd'); - - $client = $this->getBrowserMock(); - - $httpClient = new HttpClient(array(), $client); - $httpClient->put($path, $headers); - } - - /** - * @test - */ - public function shouldDoCustomRequest() - { - $path = '/some/path'; - $body = 'a = b'; - $options = array('c' => 'd'); - - $client = $this->getBrowserMock(); - - $httpClient = new HttpClient(array(), $client); - $httpClient->request($path, $body, 'HEAD', $options); - } - - /** - * @test - */ - public function shouldHandlePagination() - { - $path = '/some/path'; - $body = 'a = b'; - $headers = array('c' => 'd'); - - $response = new Response(200); - $response->addHeader('Link', "; rel=\"page2\", \n; rel=\"page4\""); - - $client = $this->getBrowserMock(); - - $httpClient = new HttpClient(array(), $client); - $httpClient->request($path, $body, 'HEAD', $headers); - - $this->assertEquals(array('page2' => 'page1', 'page4' => 'page3'), ResponseMediator::getPagination($response)); - } - - /** - * @test - */ - public function shouldAllowToReturnRawContent() - { - $path = '/some/path'; - $parameters = array('a = b'); - $headers = array('c' => 'd'); - - $message = $this->getMock('Guzzle\Http\Message\Response', array(), array(200)); - $message->expects($this->once()) - ->method('getBody') - ->will($this->returnValue('Just raw context')); - - $client = $this->getBrowserMock(); - $client->expects($this->once()) - ->method('send') - ->will($this->returnValue($message)); - - $httpClient = new TestHttpClient(array(), $client); - $response = $httpClient->get($path, $parameters, $headers); - - $this->assertEquals("Just raw context", $response->getBody()); - $this->assertInstanceOf('Guzzle\Http\Message\MessageInterface', $response); - } - - /** - * @test - * @expectedException \Github\Exception\ApiLimitExceedException - */ - public function shouldThrowExceptionWhenApiIsExceeded() - { - $path = '/some/path'; - $parameters = array('a = b'); - $headers = array('c' => 'd'); - - $response = new Response(403); - $response->addHeader('X-RateLimit-Remaining', 0); - - $mockPlugin = new MockPlugin(); - $mockPlugin->addResponse($response); - - $client = new GuzzleClient('http://123.com/'); - $client->addSubscriber($mockPlugin); - - $httpClient = new TestHttpClient(array(), $client); - $httpClient->get($path, $parameters, $headers); - } - - protected function getBrowserMock(array $methods = array()) - { - $mock = $this->getMock( - 'Guzzle\Http\Client', - array_merge( - array('send', 'createRequest'), - $methods - ) - ); - - $mock->expects($this->any()) - ->method('createRequest') - ->will($this->returnValue($this->getMock('Guzzle\Http\Message\Request', array(), array('GET', 'some')))); - - return $mock; - } -} - -class TestHttpClient extends HttpClient -{ - public function getOption($name, $default = null) - { - return isset($this->options[$name]) ? $this->options[$name] : $default; - } - - public function request($path, $body, $httpMethod = 'GET', array $headers = array(), array $options = array()) - { - $request = $this->client->createRequest($httpMethod, $path); - - return $this->client->send($request); - } -} diff --git a/test/Github/Tests/HttpClient/Listener/AuthListenerTest.php b/test/Github/Tests/HttpClient/Listener/AuthListenerTest.php deleted file mode 100644 index d071687488d..00000000000 --- a/test/Github/Tests/HttpClient/Listener/AuthListenerTest.php +++ /dev/null @@ -1,138 +0,0 @@ -onRequestBeforeSend($this->getEventMock()); - } - - /** - * @test - */ - public function shouldDoNothingForHaveNullMethod() - { - $request = $this->getMock('Guzzle\Http\Message\RequestInterface'); - $request->expects($this->never()) - ->method('addHeader'); - $request->expects($this->never()) - ->method('fromUrl'); - $request->expects($this->never()) - ->method('getUrl'); - - $listener = new AuthListener('test', 'pass', null); - $listener->onRequestBeforeSend($this->getEventMock($request)); - } - - /** - * @test - */ - public function shouldDoNothingForPostSend() - { - $request = $this->getMock('Guzzle\Http\Message\RequestInterface'); - $request->expects($this->never()) - ->method('addHeader'); - $request->expects($this->never()) - ->method('fromUrl'); - $request->expects($this->never()) - ->method('getUrl'); - - $listener = new AuthListener('login', 'somepassphrase', Client::AUTH_HTTP_PASSWORD); - $listener->onRequestBeforeSend($this->getEventMock($request)); - } - - /** - * @test - */ - public function shouldSetAuthBasicHeaderForAuthPassMethod() - { - $expected = 'Basic '.base64_encode('login2:pass42323'); - - $request = $this->getMock('Guzzle\Http\Message\RequestInterface'); - $request->expects($this->once()) - ->method('setHeader') - ->with('Authorization', $expected); - $request->expects($this->once()) - ->method('getHeader') - ->with('Authorization') - ->will($this->returnValue($expected)); - - $listener = new AuthListener('login2', 'pass42323', Client::AUTH_HTTP_PASSWORD); - $listener->onRequestBeforeSend($this->getEventMock($request)); - - $this->assertEquals($expected, $request->getHeader('Authorization')); - } - - /** - * @test - */ - public function shouldSetAuthTokenHeaderForAuthPassMethod() - { - $expected = 'token test'; - - $request = $this->getMock('Guzzle\Http\Message\RequestInterface'); - $request->expects($this->once()) - ->method('setHeader') - ->with('Authorization', $expected); - $request->expects($this->once()) - ->method('getHeader') - ->with('Authorization') - ->will($this->returnValue($expected)); - - $listener = new AuthListener('test', null, Client::AUTH_HTTP_TOKEN); - $listener->onRequestBeforeSend($this->getEventMock($request)); - - $this->assertEquals($expected, $request->getHeader('Authorization')); - } - - /** - * @test - */ - public function shouldSetTokenInUrlForAuthUrlMethod() - { - $request = new Request('GET', '/res'); - - $listener = new AuthListener('test', null, Client::AUTH_URL_TOKEN); - $listener->onRequestBeforeSend($this->getEventMock($request)); - - $this->assertEquals('/res?access_token=test', $request->getUrl()); - } - - /** - * @test - */ - public function shouldSetClientDetailsInUrlForAuthUrlMethod() - { - $request = new Request('GET', '/res'); - - $listener = new AuthListener('clientId', 'clientSecret', Client::AUTH_URL_CLIENT_ID); - $listener->onRequestBeforeSend($this->getEventMock($request)); - - $this->assertEquals('/res?client_id=clientId&client_secret=clientSecret', $request->getUrl()); - } - - private function getEventMock($request = null) - { - $mock = $this->getMockBuilder('Guzzle\Common\Event')->getMock(); - - if ($request) { - $mock->expects($this->any()) - ->method('offsetGet') - ->will($this->returnValue($request)); - } - - return $mock; - } -} diff --git a/test/Github/Tests/HttpClient/Listener/ErrorListenerTest.php b/test/Github/Tests/HttpClient/Listener/ErrorListenerTest.php deleted file mode 100644 index 8bb0bfa177f..00000000000 --- a/test/Github/Tests/HttpClient/Listener/ErrorListenerTest.php +++ /dev/null @@ -1,178 +0,0 @@ -getMockBuilder('Guzzle\Http\Message\Response')->disableOriginalConstructor()->getMock(); - $response->expects($this->once()) - ->method('isClientError') - ->will($this->returnValue(false)); - - $listener = new ErrorListener(array('api_limit' => 5000)); - $listener->onRequestError($this->getEventMock($response)); - } - - /** - * @test - * @expectedException \Github\Exception\ApiLimitExceedException - */ - public function shouldFailWhenApiLimitWasExceed() - { - $response = $this->getMockBuilder('Guzzle\Http\Message\Response')->disableOriginalConstructor()->getMock(); - $response->expects($this->once()) - ->method('isClientError') - ->will($this->returnValue(true)); - $response->expects($this->once()) - ->method('getHeader') - ->with('X-RateLimit-Remaining') - ->will($this->returnValue(0)); - - $listener = new ErrorListener(array('api_limit' => 5000)); - $listener->onRequestError($this->getEventMock($response)); - } - - /** - * @test - * @expectedException \Github\Exception\RuntimeException - */ - public function shouldNotPassWhenContentWasNotValidJson() - { - $response = $this->getMockBuilder('Guzzle\Http\Message\Response')->disableOriginalConstructor()->getMock(); - $response->expects($this->once()) - ->method('isClientError') - ->will($this->returnValue(true)); - $response->expects($this->once()) - ->method('getHeader') - ->with('X-RateLimit-Remaining') - ->will($this->returnValue(5000)); - $response->expects($this->once()) - ->method('getBody') - ->will($this->returnValue('fail')); - - $listener = new ErrorListener(array('api_limit' => 5000)); - $listener->onRequestError($this->getEventMock($response)); - } - - /** - * @test - * @expectedException \Github\Exception\RuntimeException - */ - public function shouldNotPassWhenContentWasValidJsonButStatusIsNotCovered() - { - $response = $this->getMockBuilder('Guzzle\Http\Message\Response')->disableOriginalConstructor()->getMock(); - $response->expects($this->once()) - ->method('isClientError') - ->will($this->returnValue(true)); - $response->expects($this->once()) - ->method('getHeader') - ->with('X-RateLimit-Remaining') - ->will($this->returnValue(5000)); - $response->expects($this->once()) - ->method('getBody') - ->will($this->returnValue(json_encode(array('message' => 'test')))); - $response->expects($this->any()) - ->method('getStatusCode') - ->will($this->returnValue(404)); - - $listener = new ErrorListener(array('api_limit' => 5000)); - $listener->onRequestError($this->getEventMock($response)); - } - - /** - * @test - * @expectedException \Github\Exception\ErrorException - */ - public function shouldNotPassWhen400IsSent() - { - $response = $this->getMockBuilder('Guzzle\Http\Message\Response')->disableOriginalConstructor()->getMock(); - $response->expects($this->once()) - ->method('isClientError') - ->will($this->returnValue(true)); - $response->expects($this->once()) - ->method('getHeader') - ->with('X-RateLimit-Remaining') - ->will($this->returnValue(5000)); - $response->expects($this->once()) - ->method('getBody') - ->will($this->returnValue(json_encode(array('message' => 'test')))); - $response->expects($this->any()) - ->method('getStatusCode') - ->will($this->returnValue(400)); - - $listener = new ErrorListener(array('api_limit' => 5000)); - $listener->onRequestError($this->getEventMock($response)); - } - - /** - * @test - * @dataProvider getErrorCodesProvider - * @expectedException \Github\Exception\ValidationFailedException - */ - public function shouldNotPassWhen422IsSentWithErrorCode($errorCode) - { - $content = json_encode(array( - 'message' => 'Validation Failed', - 'errors' => array( - array( - 'code' => $errorCode, - 'field' => 'test', - 'value' => 'wrong', - 'resource' => 'fake' - ) - ) - )); - - $response = $this->getMockBuilder('Guzzle\Http\Message\Response')->disableOriginalConstructor()->getMock(); - $response->expects($this->once()) - ->method('isClientError') - ->will($this->returnValue(true)); - $response->expects($this->once()) - ->method('getHeader') - ->with('X-RateLimit-Remaining') - ->will($this->returnValue(5000)); - $response->expects($this->once()) - ->method('getBody') - ->will($this->returnValue($content)); - $response->expects($this->any()) - ->method('getStatusCode') - ->will($this->returnValue(422)); - - $listener = new ErrorListener(array('api_limit' => 5000)); - $listener->onRequestError($this->getEventMock($response)); - } - - public function getErrorCodesProvider() - { - return array( - array('missing'), - array('missing_field'), - array('invalid'), - array('already_exists'), - ); - } - - private function getEventMock($response) - { - $mock = $this->getMockBuilder('Guzzle\Common\Event')->getMock(); - - $request = $this->getMockBuilder('Guzzle\Http\Message\Request')->disableOriginalConstructor()->getMock(); - - $request->expects($this->any()) - ->method('getResponse') - ->will($this->returnValue($response)); - - $mock->expects($this->any()) - ->method('offsetGet') - ->will($this->returnValue($request)); - - return $mock; - } -} diff --git a/test/Github/Tests/HttpClient/Message/ResponseMediatorTest.php b/test/Github/Tests/HttpClient/Message/ResponseMediatorTest.php new file mode 100644 index 00000000000..b6216d57044 --- /dev/null +++ b/test/Github/Tests/HttpClient/Message/ResponseMediatorTest.php @@ -0,0 +1,84 @@ + + */ +class ResponseMediatorTest extends \PHPUnit\Framework\TestCase +{ + public function testGetContent() + { + $body = ['foo' => 'bar']; + $response = new Response( + 200, + ['Content-Type' => 'application/json'], + Utils::streamFor(json_encode($body)) + ); + + $this->assertEquals($body, ResponseMediator::getContent($response)); + } + + /** + * If content-type is not json we should get the raw body. + */ + public function testGetContentNotJson() + { + $body = 'foobar'; + $response = new Response( + 200, + [], + Utils::streamFor($body) + ); + + $this->assertEquals($body, ResponseMediator::getContent($response)); + } + + /** + * Make sure we return the body if we have invalid json. + */ + public function testGetContentInvalidJson() + { + $body = 'foobar'; + $response = new Response( + 200, + ['Content-Type' => 'application/json'], + Utils::streamFor($body) + ); + + $this->assertEquals($body, ResponseMediator::getContent($response)); + } + + public function testGetPagination() + { + $header = '; rel="first",; rel="next",; rel="prev",; rel="last",'; + + $pagination = [ + 'first' => 'https://github.com', + 'next' => 'https://github.com', + 'prev' => 'https://github.com', + 'last' => 'https://github.com', + ]; + + // response mock + $response = new Response(200, ['link' => $header]); + $result = ResponseMediator::getPagination($response); + + $this->assertEquals($pagination, $result); + } + + public function testGetHeader() + { + $header = 'application/json'; + $response = new Response( + 200, + ['Content-Type' => $header] + ); + + $this->assertEquals($header, ResponseMediator::getHeader($response, 'content-type')); + } +} diff --git a/test/Github/Tests/HttpClient/Plugin/AuthenticationTest.php b/test/Github/Tests/HttpClient/Plugin/AuthenticationTest.php new file mode 100644 index 00000000000..be937684d01 --- /dev/null +++ b/test/Github/Tests/HttpClient/Plugin/AuthenticationTest.php @@ -0,0 +1,49 @@ +handleRequest($request, static function ($request) use (&$newRequest) { + /** @var Request $newRequest */ + $newRequest = $request; + + return new FulfilledPromise('FOO'); + }, static function () { + throw new \RuntimeException('Did not expect plugin to call first'); + }); + + $this->assertNotNull($newRequest); + + if ($expectedHeader) { + $this->assertContains($expectedHeader, $newRequest->getHeader('Authorization')); + } else { + $this->assertEquals($expectedUrl, $newRequest->getUri()->__toString()); + } + } + + public function getAuthenticationData() + { + return [ + ['access_token', null, AuthMethod::ACCESS_TOKEN, 'token access_token'], + ['client_id', 'client_secret', AuthMethod::CLIENT_ID, sprintf('Basic %s', base64_encode('client_id'.':'.'client_secret'))], + ['jwt_token', null, AuthMethod::JWT, 'Bearer jwt_token'], + ]; + } +} diff --git a/test/Github/Tests/HttpClient/Plugin/GithubExceptionThrowerTest.php b/test/Github/Tests/HttpClient/Plugin/GithubExceptionThrowerTest.php new file mode 100644 index 00000000000..7cb7dfe33a8 --- /dev/null +++ b/test/Github/Tests/HttpClient/Plugin/GithubExceptionThrowerTest.php @@ -0,0 +1,253 @@ + + */ +class GithubExceptionThrowerTest extends TestCase +{ + /** + * @dataProvider responseProvider + */ + public function testHandleRequest(ResponseInterface $response, ?ExceptionInterface $exception = null): void + { + $request = new Request('GET', 'https://api.github.com/issues'); + + $promise = new HttpFulfilledPromise($response); + + $plugin = new GithubExceptionThrower(); + + $result = $plugin->handleRequest( + $request, + function (RequestInterface $request) use ($promise) { + return $promise; + }, + function (RequestInterface $request) use ($promise) { + return $promise; + } + ); + + if ($exception) { + $this->assertInstanceOf(HttpRejectedPromise::class, $result); + } else { + $this->assertInstanceOf(HttpFulfilledPromise::class, $result); + } + + if ($exception) { + $this->expectException(get_class($exception)); + $this->expectExceptionCode($exception->getCode()); + $this->expectExceptionMessageMatches('/'.preg_quote($exception->getMessage(), '/').'$/'); + } + + $result->wait(); + } + + /** + * @return array + */ + public static function responseProvider() + { + return [ + '200 Response' => [ + 'response' => new Response(), + 'exception' => null, + ], + 'Rate Limit Exceeded' => [ + 'response' => new Response( + 429, + [ + 'Content-Type' => 'application/json', + 'X-RateLimit-Remaining' => 0, + 'X-RateLimit-Limit' => 5000, + ], + '' + ), + 'exception' => new \Github\Exception\ApiLimitExceedException(5000), + ], + 'Rate Limit Exceeded via 403 status' => [ + 'response' => new Response( + 403, + [ + 'Content-Type' => 'application/json', + 'X-RateLimit-Remaining' => 0, + 'X-RateLimit-Limit' => 5000, + 'X-RateLimit-Reset' => 1609245810, + ], + json_encode( + [ + 'message' => 'API rate limit exceeded for installation ID xxxxxxx.', + ] + ) + ), + 'exception' => new \Github\Exception\ApiLimitExceedException(5000), + ], + 'Secondary Rate Limit Exceeded via 403 status' => [ + 'response' => new Response( + 403, + [ + 'Content-Type' => 'application/json', + 'X-RateLimit-Remaining' => 100, + 'X-RateLimit-Limit' => 5000, + 'X-RateLimit-Reset' => 1609245810, + ], + json_encode( + [ + 'message' => 'You have exceeded a secondary rate limit and have been temporarily blocked from content creation. Please retry your request again later. If you reach out to GitHub Support for help, please include the request ID #xxxxxxx.', + ] + ) + ), + 'exception' => new \Github\Exception\ApiLimitExceedException(5000), + ], + 'Two Factor Authentication Required' => [ + 'response' => new Response( + 401, + [ + 'Content-Type' => 'application/json', + 'X-GitHub-OTP' => 'required; :2fa-type', + ], + '' + ), + 'exception' => new \Github\Exception\TwoFactorAuthenticationRequiredException('2fa-type'), + ], + '400 Bad Request' => [ + 'response' => new Response( + 400, + [ + 'Content-Type' => 'application/json', + ], + json_encode( + [ + 'message' => 'Problems parsing JSON', + ] + ) + ), + 'exception' => new \Github\Exception\ErrorException('Problems parsing JSON (Bad Request)', 400), + ], + '422 Unprocessable Entity' => [ + 'response' => new Response( + 422, + [ + 'Content-Type' => 'application/json', + ], + json_encode( + [ + 'message' => 'Bad Request', + 'errors' => [ + [ + 'code' => 'missing', + 'field' => 'field', + 'value' => 'value', + 'resource' => 'resource', + ], + ], + ] + ) + ), + 'exception' => new \Github\Exception\ErrorException('Validation Failed: The field value does not exist, for resource "resource"', 422), + ], + '502 Response' => [ + 'response' => new Response( + 502, + [ + 'Content-Type' => 'application/json', + ], + json_encode( + [ + 'errors' => [ + ['message' => 'Something went wrong with executing your query'], + ], + ] + ) + ), + 'exception' => new \Github\Exception\RuntimeException('Something went wrong with executing your query', 502), + ], + 'Sso required Response' => [ + 'response' => new Response( + 403, + [ + 'Content-Type' => 'application/json', + 'X-GitHub-SSO' => 'required; url=https://github.com/orgs/octodocs-test/sso?authorization_request=AZSCKtL4U8yX1H3sCQIVnVgmjmon5fWxks5YrqhJgah0b2tlbl9pZM4EuMz4', + ] + ), + 'exception' => new \Github\Exception\SsoRequiredException('https://github.com/orgs/octodocs-test/sso?authorization_request=AZSCKtL4U8yX1H3sCQIVnVgmjmon5fWxks5YrqhJgah0b2tlbl9pZM4EuMz4'), + ], + 'Default handling' => [ + 'response' => new Response( + 555, + [], + 'Error message' + ), + 'exception' => new \Github\Exception\RuntimeException('Error message', 555), + ], + 'Graphql error response (200)' => [ + 'response' => new Response( + 200, + [ + 'content-type' => 'application/json', + ], + json_encode( + [ + 'errors' => [ + [ + ['path' => ['query', 'repository']], + 'message' => 'Field "xxxx" doesn\'t exist on type "Issue"', + ], + [ + ['path' => ['query', 'repository']], + 'message' => 'Field "dummy" doesn\'t exist on type "PullRequest"', + ], + ], + ] + ) + ), + 'exception' => new \Github\Exception\RuntimeException('Field "xxxx" doesn\'t exist on type "Issue", Field "dummy" doesn\'t exist on type "PullRequest"'), + ], + 'Grapql requires authentication' => [ + 'response' => new Response( + 401, + [ + 'content-type' => 'application/json', + 'X-RateLimit-Limit' => 0, + 'X-RateLimit-Remaining' => 0, + 'X-RateLimit-Reset' => 1609245810, + 'X-RateLimit-Used' => 0, + ], + json_encode( + [ + 'message' => 'This endpoint requires you to be authenticated.', + 'documentation_url' => 'https://docs.github.com/v3/#authentication', + ] + ) + ), + 'exception' => new \Github\Exception\RuntimeException('This endpoint requires you to be authenticated.', 401), + ], + 'Cannot delete active deployment' => [ + 'response' => new Response( + 422, + [ + 'content-type' => 'application/json', + ], + json_encode( + [ + 'message' => 'Validation Failed', + 'errors' => ['We cannot delete an active deployment unless it is the only deployment in a given environment.'], + 'documentation_url' => 'https://docs.github.com/rest/reference/repos#delete-a-deployment', + ] + ) + ), + 'exception' => new \Github\Exception\ValidationFailedException('Validation Failed: We cannot delete an active deployment unless it is the only deployment in a given environment.', 422), + ], + ]; + } +} diff --git a/test/Github/Tests/HttpClient/Plugin/PathPrependTest.php b/test/Github/Tests/HttpClient/Plugin/PathPrependTest.php new file mode 100644 index 00000000000..f5d4052d94d --- /dev/null +++ b/test/Github/Tests/HttpClient/Plugin/PathPrependTest.php @@ -0,0 +1,42 @@ + + */ +class PathPrependTest extends TestCase +{ + /** + * @dataProvider uris + */ + public function testPathIsPrepended($uri, $expectedPath) + { + $request = new Request('GET', $uri); + $plugin = new PathPrepend('/api/v3'); + + $newRequest = null; + $plugin->handleRequest($request, function ($request) use (&$newRequest) { + $newRequest = $request; + + return new FulfilledPromise('FOO'); + }, function () { + throw new \RuntimeException('Did not expect plugin to call first'); + }); + + $this->assertEquals($expectedPath, $newRequest->getUri()->getPath()); + } + + public static function uris() + { + return [ + ['http://example.com/foo/bar/api', '/api/v3/foo/bar/api'], + ['http://example.com/api/v3/foo/bar/api', '/api/v3/foo/bar/api'], + ]; + } +} diff --git a/test/Github/Tests/Functional/CommitTest.php b/test/Github/Tests/Integration/CommitTest.php similarity index 80% rename from test/Github/Tests/Functional/CommitTest.php rename to test/Github/Tests/Integration/CommitTest.php index 4aec0b3cc60..2134bab2f65 100644 --- a/test/Github/Tests/Functional/CommitTest.php +++ b/test/Github/Tests/Integration/CommitTest.php @@ -1,9 +1,9 @@ client->api('repo')->commits()->all($username, $repo, array('sha' => $branch)); - $commit = array_pop($commits); + $commits = $this->client->api('repo')->commits()->all($username, $repo, ['sha' => $branch]); + $commit = array_pop($commits); $this->assertArrayHasKey('url', $commit); $this->assertArrayHasKey('committer', $commit); @@ -32,7 +32,7 @@ public function shouldRetrieveCommitsForRepositoryBranch() public function shouldRetrieveCommitBySha() { $username = 'KnpLabs'; - $repo = 'php-github-api'; + $repo = 'php-github-api'; $commit = $this->client->api('repo')->commits()->show($username, $repo, '6df3adf5bd16745299c6429e163265daed430fa1'); @@ -50,10 +50,10 @@ public function shouldRetrieveCommitBySha() public function shouldRetrieveCommitsForFile() { $username = 'KnpLabs'; - $repo = 'php-github-api'; - $branch = 'master'; + $repo = 'php-github-api'; + $branch = 'master'; - $commits = $this->client->api('repo')->commits()->all($username, $repo, array('sha' => $branch, 'path' => 'composer.json')); + $commits = $this->client->api('repo')->commits()->all($username, $repo, ['sha' => $branch, 'path' => 'composer.json']); $commit = array_pop($commits); $this->assertArrayHasKey('url', $commit); diff --git a/test/Github/Tests/Functional/GistTest.php b/test/Github/Tests/Integration/GistTest.php similarity index 92% rename from test/Github/Tests/Functional/GistTest.php rename to test/Github/Tests/Integration/GistTest.php index f4464facc66..deb079f57e6 100644 --- a/test/Github/Tests/Functional/GistTest.php +++ b/test/Github/Tests/Integration/GistTest.php @@ -1,9 +1,11 @@ expectException(RuntimeException::class); $this->client->api('gists')->all('starred'); } diff --git a/test/Github/Tests/Functional/IssueCommentTest.php b/test/Github/Tests/Integration/IssueCommentTest.php similarity index 86% rename from test/Github/Tests/Functional/IssueCommentTest.php rename to test/Github/Tests/Integration/IssueCommentTest.php index 2a9220763e3..0cb39a1f8e3 100644 --- a/test/Github/Tests/Functional/IssueCommentTest.php +++ b/test/Github/Tests/Integration/IssueCommentTest.php @@ -1,9 +1,9 @@ client->api('issue')->comments()->all($username, $repo, $issue); - $comment = array_pop($comments); + $comment = array_pop($comments); $this->assertArrayHasKey('id', $comment); $this->assertArrayHasKey('url', $comment); @@ -31,12 +31,13 @@ public function shouldRetrieveCommentsForIssue() /** * @test + * * @depends shouldRetrieveCommentsForIssue */ public function shouldRetrieveSingleComment($commentId) { $username = 'KnpLabs'; - $repo = 'php-github-api'; + $repo = 'php-github-api'; $comment = $this->client->api('issue')->comments()->show($username, $repo, $commentId); @@ -54,9 +55,9 @@ public function shouldRetrieveSingleComment($commentId) public function shouldCreateCommentForIssue() { $username = 'KnpLabs'; - $repo = 'php-github-api'; - $issue = 13; - $params = array('body' => '%'); + $repo = 'php-github-api'; + $issue = 13; + $params = ['body' => '%']; $comment = $this->client->api('issue')->comments()->create($username, $repo, $issue, $params); @@ -69,15 +70,17 @@ public function shouldCreateCommentForIssue() return $comment['id']; } + /** * @test + * * @depends shouldCreateCommentForIssue */ public function shouldUpdateCommentByCommentId($commentId) { $username = 'KnpLabs'; - $repo = 'php-github-api'; - $params = array('body' => 'test update'); + $repo = 'php-github-api'; + $params = ['body' => 'test update']; $comment = $this->client->api('issue')->comments()->update($username, $repo, $commentId, $params); @@ -93,12 +96,13 @@ public function shouldUpdateCommentByCommentId($commentId) /** * @test + * * @depends shouldUpdateCommentByCommentId */ public function shouldRemoveCommentByCommentId($commentId) { $username = 'KnpLabs'; - $repo = 'php-github-api'; + $repo = 'php-github-api'; $this->client->api('issue')->comments()->remove($username, $repo, $commentId); } diff --git a/test/Github/Tests/Functional/MarkdownTest.php b/test/Github/Tests/Integration/MarkdownTest.php similarity index 67% rename from test/Github/Tests/Functional/MarkdownTest.php rename to test/Github/Tests/Integration/MarkdownTest.php index 6bf704e85c5..1dd956019fe 100644 --- a/test/Github/Tests/Functional/MarkdownTest.php +++ b/test/Github/Tests/Integration/MarkdownTest.php @@ -1,9 +1,11 @@ client->api('markdown'); - $input = 'Hello world github/linguist#1 **cool**, and #1!'; + $input = 'Hello world github/linguist#1 **cool**, and #1!'; $output = '

Hello world github/linguist#1 cool, and #1!

'; - $html = $api->render($input); + $html = $api->render($input); $this->assertEquals($output, $html); - $input = 'Hello world KnpLabs/KnpBundles#1 **cool**, and #1!'; + $input = 'Hello world KnpLabs/KnpBundles#1 **cool**, and #1!'; $output = '

Hello world KnpLabs/KnpBundles#1 cool, and #1!

'; - $html = $api->render($input, 'gfm' , 'KnpLabs/KnpMenu'); + $html = $api->render($input, 'gfm', 'KnpLabs/KnpMenu'); $this->assertEquals($output, $html); } diff --git a/test/Github/Tests/Integration/RateLimitTest.php b/test/Github/Tests/Integration/RateLimitTest.php new file mode 100644 index 00000000000..b003e5b0604 --- /dev/null +++ b/test/Github/Tests/Integration/RateLimitTest.php @@ -0,0 +1,35 @@ +client->api('rate_limit')->getRateLimits(); + + $this->assertArrayHasKey('resources', $response); + $this->assertArrayHasKey('resources', $response); + $this->assertSame(['core' => ['limit' => 60]], $response['resources']); + } + + /** + * @test + */ + public function shouldRetrieveRateLimitsAndReturnLimitInstances() + { + $response = $this->client->api('rate_limit')->getLimits(); + + $this->assertIsArray($response); + $this->assertContainsOnlyInstancesOf(RateLimitResource::class, $response); + $this->assertEquals(60, $response->getLimit('core')->getLimit()); + } +} diff --git a/test/Github/Tests/Functional/RepoCommentTest.php b/test/Github/Tests/Integration/RepoCommentTest.php similarity index 84% rename from test/Github/Tests/Functional/RepoCommentTest.php rename to test/Github/Tests/Integration/RepoCommentTest.php index 3897f8214d5..352dac4b7ff 100644 --- a/test/Github/Tests/Functional/RepoCommentTest.php +++ b/test/Github/Tests/Integration/RepoCommentTest.php @@ -1,9 +1,9 @@ client->api('repo')->comments()->all($username, $repo); - $comment = array_pop($comments); + $comment = array_pop($comments); $this->assertArrayHasKey('line', $comment); $this->assertArrayHasKey('body', $comment); @@ -32,11 +32,11 @@ public function shouldRetrieveComments() public function shouldRetrieveCommentsForCommit() { $username = 'fabpot'; - $repo = 'Twig'; - $sha = '3506cfad1d946f4a87e8c55849a18044efe2d5dc'; + $repo = 'Twig'; + $sha = '3506cfad1d946f4a87e8c55849a18044efe2d5dc'; $comments = $this->client->api('repo')->comments()->all($username, $repo, $sha); - $comment = array_pop($comments); + $comment = array_pop($comments); $this->assertArrayHasKey('line', $comment); $this->assertArrayHasKey('body', $comment); @@ -52,9 +52,9 @@ public function shouldRetrieveCommentsForCommit() public function shouldCreateCommentForCommit() { $username = 'KnpLabs'; - $repo = 'php-github-api'; - $sha = '22655813eb54e7d4e21545e396f919bcd245b50d'; - $params = array('body' => '%'); + $repo = 'php-github-api'; + $sha = '22655813eb54e7d4e21545e396f919bcd245b50d'; + $params = ['body' => '%']; $comment = $this->client->api('repo')->comments()->create($username, $repo, $sha, $params); @@ -70,12 +70,13 @@ public function shouldCreateCommentForCommit() /** * @test + * * @depends shouldCreateCommentForCommit */ public function shouldShowCommentByCommentId($commentId) { $username = 'KnpLabs'; - $repo = 'php-github-api'; + $repo = 'php-github-api'; $comment = $this->client->api('repo')->comments()->show($username, $repo, $commentId); @@ -91,13 +92,14 @@ public function shouldShowCommentByCommentId($commentId) /** * @test + * * @depends shouldShowCommentByCommentId */ public function shouldUpdateCommentByCommentId($commentId) { $username = 'KnpLabs'; - $repo = 'php-github-api'; - $params = array('body' => 'test update'); + $repo = 'php-github-api'; + $params = ['body' => 'test update']; $comment = $this->client->api('repo')->comments()->update($username, $repo, $commentId, $params); @@ -113,12 +115,13 @@ public function shouldUpdateCommentByCommentId($commentId) /** * @test + * * @depends shouldUpdateCommentByCommentId */ public function shouldRemoveCommentByCommentId($commentId) { $username = 'KnpLabs'; - $repo = 'php-github-api'; + $repo = 'php-github-api'; $this->client->api('repo')->comments()->remove($username, $repo, $commentId); } diff --git a/test/Github/Tests/Functional/RepoTest.php b/test/Github/Tests/Integration/RepoTest.php similarity index 74% rename from test/Github/Tests/Functional/RepoTest.php rename to test/Github/Tests/Integration/RepoTest.php index ce25d545ee6..2d958e35713 100644 --- a/test/Github/Tests/Functional/RepoTest.php +++ b/test/Github/Tests/Integration/RepoTest.php @@ -1,9 +1,9 @@ client->setHeaders( - array('Accept' => sprintf( + $this->client->addHeaders( + ['Accept' => sprintf( 'application/vnd.github.%s.diff', - $this->client->getOption('api_version') - )) + $this->client->getApiVersion() + )] ); $diff = $this->client->api('pull_request')->show('KnpLabs', 'php-github-api', '92'); - $this->assertTrue('string' === gettype($diff)); + $this->assertIsString($diff); } /** @@ -38,17 +38,35 @@ public function shouldRetrieveRawBlob() 'e50d5e946385cff052636e2f09f36b03d1c368f4' ); - $this->assertInternalType('string', $contents); + $this->assertIsString($contents); $this->assertStringStartsWith('client->api('git_data')->blobs(); + $api->configure('raw'); + + $contents = $api->show( + 'KnpLabs', + 'php-github-api', + 'dc16d3e77fd4e40638cb722927ffe15fa85b1434' + ); + + $this->assertIsString($contents); + $this->assertStringStartsWith('{', $contents); + } + /** * @test */ public function shouldRetrieveContributorsList() { $username = 'KnpLabs'; - $repo = 'php-github-api'; + $repo = 'php-github-api'; $contributors = $this->client->api('repo')->contributors($username, $repo); $contributor = array_pop($contributors); @@ -67,7 +85,7 @@ public function shouldRetrieveContributorsList() public function shouldShowRepo() { $username = 'KnpLabs'; - $repo = 'php-github-api'; + $repo = 'php-github-api'; $repo = $this->client->api('repo')->show($username, $repo); diff --git a/test/Github/Tests/Integration/ResultPagerTest.php b/test/Github/Tests/Integration/ResultPagerTest.php new file mode 100644 index 00000000000..4dd24e37904 --- /dev/null +++ b/test/Github/Tests/Integration/ResultPagerTest.php @@ -0,0 +1,38 @@ +client->search(); + + $pager = $this->createPager(); + $users = $pager->fetch($searchApi, 'users', ['location:Kyiv']); + $this->assertCount(10, $users); + } + + private function createPager() + { + return new ResultPager($this->client); + } +} diff --git a/test/Github/Tests/Functional/TestCase.php b/test/Github/Tests/Integration/TestCase.php similarity index 78% rename from test/Github/Tests/Functional/TestCase.php rename to test/Github/Tests/Integration/TestCase.php index ef51c1a52c9..d101b1b1efe 100644 --- a/test/Github/Tests/Functional/TestCase.php +++ b/test/Github/Tests/Integration/TestCase.php @@ -1,19 +1,25 @@ client->api('current_user')->update(array('email' => 'leszek.prabucki@gmail.com')); + $this->expectException(RuntimeException::class); + $this->client->api('current_user')->update(['email' => 'leszek.prabucki@gmail.com']); } /** @@ -69,19 +71,19 @@ public function shouldGetFollowersUsers() /** * @test - * @expectedException \Github\Exception\RuntimeException */ public function shouldNotFollowUserWithoutAuthorization() { + $this->expectException(RuntimeException::class); $this->client->api('current_user')->follow()->follow('KnpLabs'); } /** * @test - * @expectedException \Github\Exception\RuntimeException */ public function shouldNotUnfollowUserWithoutAuthorization() { + $this->expectException(RuntimeException::class); $this->client->api('current_user')->follow()->unfollow('KnpLabs'); } @@ -110,4 +112,51 @@ public function shouldGetReposBeingWatched() $this->assertArrayHasKey('git_url', $repo); $this->assertArrayHasKey('svn_url', $repo); } + + /** + * @test + */ + public function shouldGetReposBeingStarred() + { + $username = 'l3l0'; + + $repos = $this->client->api('user')->starred($username); + $repo = array_pop($repos); + + $this->assertArrayHasKey('id', $repo); + $this->assertArrayHasKey('name', $repo); + $this->assertArrayHasKey('description', $repo); + $this->assertArrayHasKey('url', $repo); + $this->assertArrayHasKey('has_wiki', $repo); + $this->assertArrayHasKey('has_issues', $repo); + $this->assertArrayHasKey('forks', $repo); + $this->assertArrayHasKey('updated_at', $repo); + $this->assertArrayHasKey('created_at', $repo); + $this->assertArrayHasKey('pushed_at', $repo); + $this->assertArrayHasKey('open_issues', $repo); + $this->assertArrayHasKey('ssh_url', $repo); + $this->assertArrayHasKey('git_url', $repo); + $this->assertArrayHasKey('svn_url', $repo); + } + + /** + * @test + */ + public function shouldGetEventsForAuthenticatedUserBeignWatched() + { + $username = 'l3l0'; + + $events = $this->client->api('user')->events($username); + $event = array_pop($events); + + $this->assertArrayHasKey('id', $event); + $this->assertArrayHasKey('type', $event); + $this->assertArrayHasKey('actor', $event); + $this->assertArrayHasKey('login', $event['actor']); + $this->assertArrayHasKey('repo', $event); + $this->assertArrayHasKey('name', $event['repo']); + $this->assertArrayHasKey('payload', $event); + $this->assertArrayHasKey('public', $event); + $this->assertArrayHasKey('created_at', $event); + } } diff --git a/test/Github/Tests/Mock/PaginatedResponse.php b/test/Github/Tests/Mock/PaginatedResponse.php new file mode 100644 index 00000000000..296adf86457 --- /dev/null +++ b/test/Github/Tests/Mock/PaginatedResponse.php @@ -0,0 +1,50 @@ + + */ +class PaginatedResponse extends Response +{ + protected $loopCount; + + protected $content; + + public function __construct($loopCount, array $content = []) + { + $this->loopCount = $loopCount; + $this->content = $content; + + parent::__construct(200, ['Content-Type' => 'application/json'], Utils::streamFor(json_encode($content))); + } + + public function getHeader($header): array + { + if ($header === 'Link') { + if ($this->loopCount > 1) { + $header = [sprintf('; rel="next"', $this->loopCount)]; + } else { + $header = ['; rel="prev"']; + } + + $this->loopCount--; + + return $header; + } + + return parent::getHeader($header); + } + + public function hasHeader($header): bool + { + if ($header === 'Link') { + return true; + } + + return parent::hasHeader($header); + } +} diff --git a/test/Github/Tests/Mock/TestHttpClient.php b/test/Github/Tests/Mock/TestHttpClient.php deleted file mode 100644 index 7b52d8807cc..00000000000 --- a/test/Github/Tests/Mock/TestHttpClient.php +++ /dev/null @@ -1,65 +0,0 @@ - array(), - 'post' => array(), - 'patch' => array(), - 'put' => array(), - 'delete' => array(), - ); - public $options = array(); - public $headers = array(); - - public function authenticate($tokenOrLogin, $password, $authMethod) - { - $this->authenticated = true; - } - - public function setOption($key, $value) - { - $this->options[$key] = $value; - } - - public function setHeaders(array $headers) - { - $this->headers = $headers; - } - - public function get($path, array $parameters = array(), array $headers = array()) - { - $this->requests['get'][] = $path; - } - - public function post($path, $body = null, array $headers = array()) - { - $this->requests['post'][] = $path; - } - - public function patch($path, $body = null, array $headers = array()) - { - $this->requests['patch'][] = $path; - } - - public function put($path, array $options = array(), array $headers = array()) - { - $this->requests['put'][] = $path; - } - - public function delete($path, $body = null, array $headers = array()) - { - $this->requests['delete'][] = $path; - } - - public function request($path, array $parameters = array(), $httpMethod = 'GET', array $headers = array()) - { - $this->requests[$httpMethod][] = $path; - } -} diff --git a/test/Github/Tests/Mock/TestResponse.php b/test/Github/Tests/Mock/TestResponse.php deleted file mode 100644 index 9d102844138..00000000000 --- a/test/Github/Tests/Mock/TestResponse.php +++ /dev/null @@ -1,39 +0,0 @@ -loopCount = $loopCount; - $this->content = $content; - } - - /** - * {@inheritDoc} - */ - public function getBody($asString = false) - { - return json_encode($this->content); - } - - public function getHeader($header = null) - { - if ($this->loopCount) { - $header = sprintf('; rel="next"', $this->loopCount); - } else { - $header = '; rel="prev"'; - } - - $this->loopCount--; - - return $header; - } -} diff --git a/test/Github/Tests/ResultPagerTest.php b/test/Github/Tests/ResultPagerTest.php index df7f0e11c85..b898528483b 100644 --- a/test/Github/Tests/ResultPagerTest.php +++ b/test/Github/Tests/ResultPagerTest.php @@ -2,251 +2,303 @@ namespace Github\Tests; -use Github; +use Github\Api\Issue; +use Github\Api\Organization\Members; +use Github\Api\Repo; +use Github\Api\Repository\Statuses; +use Github\Api\Search; +use Github\Api\User; use Github\Client; use Github\ResultPager; -use Github\HttpClient\HttpClientInterface; -use Github\Tests\Mock\TestResponse; +use Github\Tests\Mock\PaginatedResponse; +use GuzzleHttp\Psr7\Response; +use GuzzleHttp\Psr7\Utils; +use Http\Client\HttpClient; +use Psr\Http\Client\ClientInterface; +use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; /** - * ResultPagerTest - * * @author Ramon de la Fuente * @author Mitchel Verschoof + * @author Tobias Nyholm */ -class ResultPagerTest extends \PHPUnit_Framework_TestCase +class ResultPagerTest extends \PHPUnit\Framework\TestCase { + use ExpectDeprecationTrait; + + public function provideFetchCases() + { + return [ + ['fetchAll'], + ['fetchAllLazy'], + ]; + } + /** - * @test + * @test provideFetchCases * - * description fetchAll + * @dataProvider provideFetchCases */ - public function shouldGetAllResults() + public function shouldGetAllResults(string $fetchMethod) { - $amountLoops = 3; - $content = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); - $responseMock = new TestResponse($amountLoops, $content); + $amountLoops = 3; + $content = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + $response = new PaginatedResponse($amountLoops, $content); // httpClient mock - $httpClientMock = $this->getHttpClientMock($responseMock); + $httpClientMock = $this->getMockBuilder(ClientInterface::class) + ->onlyMethods(['sendRequest']) + ->getMock(); $httpClientMock ->expects($this->exactly($amountLoops)) - ->method('get') - ->will($this->returnValue($responseMock)); + ->method('sendRequest') + ->will($this->returnValue($response)); - $clientMock = $this->getClientMock($httpClientMock); + $client = Client::createWithHttpClient($httpClientMock); // memberApi Mock - $memberApiMock = $this->getApiMock('Github\Api\Organization\Members'); - $memberApiMock - ->expects($this->once()) - ->method('all') - ->will($this->returnValue(array())); + $memberApi = new Members($client); - $method = 'all'; - $parameters = array('netwerven'); + $method = 'all'; + $parameters = ['netwerven']; // Run fetchAll on result paginator - $paginator = new Github\ResultPager($clientMock); - $result = $paginator->fetchAll($memberApiMock, $method, $parameters); + $paginator = new ResultPager($client); + + $result = $paginator->$fetchMethod($memberApi, $method, $parameters); + + if (is_array($result)) { + $this->assertSame('fetchAll', $fetchMethod); + } else { + $result = iterator_to_array($result); + } - $this->assertEquals($amountLoops * count($content), count($result)); + $this->assertCount($amountLoops * count($content), $result); } /** * @test * - * description fetch + * response in a search api has different format: + * + * { + * "total_count": 1, + * "incomplete_results": false, + * "items": [] + * } + * + * and we need to extract result from `items` */ - public function shouldGetSomeResults() + public function shouldGetAllSearchResults() { - $pagination = array('next' => 'http://github.com/next'); - $resultContent = 'organization test'; + $amountLoops = 3; - $responseMock = $this->getResponseMock('; rel="next"'); - $httpClient = $this->getHttpClientMock($responseMock); - $client = $this->getClientMock($httpClient); + $content = [ + 'total_count' => 12, + 'items' => [1, 2, 3, 4], + ]; + $response = new PaginatedResponse($amountLoops, $content); - $organizationApiMock = $this->getApiMock('Github\Api\Organization'); + // httpClient mock + $httpClientMock = $this->getMockBuilder(ClientInterface::class) + ->onlyMethods(['sendRequest']) + ->getMock(); + $httpClientMock + ->expects($this->exactly($amountLoops)) + ->method('sendRequest') + ->willReturn($response); - $organizationApiMock - ->expects($this->once()) - ->method('show') - ->with('github') - ->will($this->returnValue($resultContent)); + $client = Client::createWithHttpClient($httpClientMock); - $paginator = new Github\ResultPager($client); - $result = $paginator->fetch($organizationApiMock, 'show', array('github')); + $searchApi = new Search($client); + $method = 'users'; + $paginator = new ResultPager($client); + $result = $paginator->fetchAll($searchApi, $method, ['knplabs']); - $this->assertEquals($resultContent, $result); - $this->assertEquals($pagination, $paginator->getPagination()); + $this->assertCount($amountLoops * count($content['items']), $result); } /** * @test - * - * description postFetch */ - public function postFetch() + public function shouldHandleEmptyContributorListWith204Header() { - $header = <<; rel="first", -; rel="next", -; rel="prev", -; rel="last", -TEXT; - - $pagination = array( - 'first' => 'http://github.com', - 'next' => 'http://github.com', - 'prev' => 'http://github.com', - 'last' => 'http://github.com' - ); - - // response mock - $responseMock = $this->getMock('Guzzle\Http\Message\Response', array(), array(200)); - $responseMock - ->expects($this->any()) - ->method('getHeader') - ->with('Link') - ->will($this->returnValue($header)); - - $httpClient = $this->getHttpClientMock($responseMock); - $client = $this->getClientMock($httpClient); - - $paginator = new Github\ResultPager($client); - $paginator->postFetch(); + // Set up a 204 response with an empty body + $response = new Response(204, [], ''); + $username = 'testuser'; + $reponame = 'testrepo'; + + // Mock the HttpClient to return the empty response + $httpClientMock = $this->getMockBuilder(HttpClient::class) + ->onlyMethods(['sendRequest']) + ->getMock(); + $httpClientMock + ->method('sendRequest') + ->willReturn($response); - $this->assertEquals($paginator->getPagination(), $pagination); - } + $client = Client::createWithHttpClient($httpClientMock); - /** - * @test - * - * description fetchNext - */ - public function fetchNext() - { - $header = '; rel="next"'; - $pagination = array('next' => 'http://github.com/next'); - $resultContent = 'fetch test'; - - $responseMock = $this->getResponseMock($header); - $responseMock - ->expects($this->once()) - ->method('getBody') - ->will($this->returnValue($resultContent)); - // Expected 2 times, 1 for setup and 1 for the actual test - $responseMock - ->expects($this->exactly(2)) - ->method('getHeader') - ->with('Link'); - - $httpClient = $this->getHttpClientMock($responseMock); - - $httpClient - ->expects($this->once()) - ->method('get') - ->with($pagination['next']) - ->will($this->returnValue($responseMock)); - - $client = $this->getClientMock($httpClient); - - $paginator = new Github\ResultPager($client); - $paginator->postFetch(); + $repoApi = new Repo($client); + + $paginator = $this->getMockBuilder(ResultPager::class) + ->setConstructorArgs([$client]) // Pass the Client in the constructor + ->onlyMethods(['fetchAll']) + ->getMock(); + $paginator->expects($this->once()) + ->method('fetchAll') + ->with($repoApi, 'contributors', [$username, $reponame]) + ->willReturn([]); - $this->assertEquals($paginator->fetchNext(), $resultContent); + $this->assertEquals([], $paginator->fetchAll($repoApi, 'contributors', [$username, $reponame])); } - /** - * @test - * - * description hasNext - */ - public function shouldHaveNext() + public function testFetch() { - $responseMock = $this->getResponseMock('; rel="next"'); - $httpClient = $this->getHttpClientMock($responseMock); - $client = $this->getClientMock($httpClient); + $result = ['foo']; + $method = 'all'; + $parameters = ['baz']; + $api = $this->getMockBuilder(Members::class) + ->disableOriginalConstructor() + ->onlyMethods(['all']) + ->getMock(); + $api->expects($this->once()) + ->method('all') + ->with(...$parameters) + ->willReturn($result); - $paginator = new Github\ResultPager($client); - $paginator->postFetch(); + $paginator = $this->getMockBuilder(ResultPager::class) + ->disableOriginalConstructor() + ->onlyMethods(['postFetch']) + ->getMock(); - $this->assertEquals($paginator->hasNext(), true); - $this->assertEquals($paginator->hasPrevious(), false); + $paginator->expects($this->once()) + ->method('postFetch'); + + $this->assertEquals($result, $paginator->fetch($api, $method, $parameters)); } - /** - * @test - * - * description hasPrevious - */ - public function shouldHavePrevious() + public function testEmptyFetch() { - $responseMock = $this->getResponseMock('; rel="prev"'); - $httpClient = $this->getHttpClientMock($responseMock); - $client = $this->getClientMock($httpClient); + $parameters = ['username']; + $api = $this->getMockBuilder(User::class) + ->disableOriginalConstructor() + ->onlyMethods(['events']) + ->getMock(); + $api->expects($this->once()) + ->method('events') + ->with(...$parameters) + ->willReturn(''); + + $paginator = $this->getMockBuilder(ResultPager::class) + ->disableOriginalConstructor() + ->onlyMethods(['postFetch']) + ->getMock(); - $paginator = new Github\ResultPager($client); - $paginator->postFetch(); + $paginator->expects($this->once()) + ->method('postFetch'); - $this->assertEquals($paginator->hasPrevious(), true); - $this->assertEquals($paginator->hasNext(), false); + $this->assertEquals([], $paginator->fetch($api, 'events', $parameters)); } - protected function getResponseMock($header) + public function testFetchAllPreserveKeys() { - // response mock - $responseMock = $this->getMock('Guzzle\Http\Message\Response', array(), array(200)); - $responseMock - ->expects($this->any()) - ->method('getHeader') - ->with('Link') - ->will($this->returnValue($header)); - - return $responseMock; + $content = [ + 'state' => 'success', + 'statuses' => [ + ['description' => 'status 1', 'state' => 'success'], + ['description' => 'status 2', 'state' => 'failure'], + ], + 'sha' => '43068834af7e501778708ed13106de95f782328c', + ]; + + $response = new Response(200, ['Content-Type' => 'application/json'], Utils::streamFor(json_encode($content))); + + // httpClient mock + $httpClientMock = $this->getMockBuilder(HttpClient::class) + ->onlyMethods(['sendRequest']) + ->getMock(); + $httpClientMock + ->method('sendRequest') + ->willReturn($response); + + $client = Client::createWithHttpClient($httpClientMock); + + $api = new Statuses($client); + $paginator = new ResultPager($client); + $result = $paginator->fetchAll($api, 'combined', ['knplabs', 'php-github-api', '43068834af7e501778708ed13106de95f782328c']); + + $this->assertArrayHasKey('state', $result); + $this->assertArrayHasKey('statuses', $result); + $this->assertCount(2, $result['statuses']); } - protected function getClientMock(HttpClientInterface $httpClient = null) + public function testFetchAllWithoutKeys() { - // if no httpClient isset use the default HttpClient mock - if (!$httpClient) { - $httpClient = $this->getHttpClientMock(); - } + $content = [ + ['title' => 'issue 1'], + ['title' => 'issue 2'], + ['title' => 'issue 3'], + ]; + + $response = new PaginatedResponse(3, $content); - $client = new \Github\Client($httpClient); - $client->setHttpClient($httpClient); + // httpClient mock + $httpClientMock = $this->getMockBuilder(HttpClient::class) + ->onlyMethods(['sendRequest']) + ->getMock(); + $httpClientMock + ->expects($this->exactly(3)) + ->method('sendRequest') + ->willReturn($response); + + $client = Client::createWithHttpClient($httpClientMock); + + $api = new Issue($client); + $paginator = new ResultPager($client); + $result = $paginator->fetchAll($api, 'all', ['knplabs', 'php-github-api']); - return $client; + $this->assertCount(9, $result); } - protected function getHttpClientMock($responseMock = null) + public function testFetchAll() { - // mock the client interface - $clientInterfaceMock = $this->getMock('Guzzle\Http\Client', array('send')); - $clientInterfaceMock - ->expects($this->any()) - ->method('send'); - - // create the httpClient mock - $httpClientMock = $this->getMock('Github\HttpClient\HttpClient', array(), array(array(), $clientInterfaceMock)); - - if ($responseMock) { - $httpClientMock - ->expects($this->any()) - ->method('getLastResponse') - ->will($this->returnValue($responseMock)); - } + $content = [ + ['title' => 'issue 1'], + ['title' => 'issue 2'], + ['title' => 'issue 3'], + ]; + + $response = new PaginatedResponse(3, $content); + + // httpClient mock + $httpClientMock = $this->getMockBuilder(HttpClient::class) + ->onlyMethods(['sendRequest']) + ->getMock(); + $httpClientMock + ->expects($this->exactly(3)) + ->method('sendRequest') + ->willReturn($response); + + $client = Client::createWithHttpClient($httpClientMock); - return $httpClientMock; + $api = new Issue($client); + $paginator = new ResultPager($client); + $result = $paginator->fetchAll($api, 'all', ['knplabs', 'php-github-api']); + + $this->assertCount(9, $result); } - protected function getApiMock($apiClass) + /** + * @group legacy + */ + public function testPostFetchDeprecation() { - $client = $this->getClientMock(); + $this->expectDeprecation('Since KnpLabs/php-github-api 3.2: The "Github\ResultPager::postFetch" method is deprecated and will be removed.'); - return $this->getMockBuilder($apiClass) - ->setConstructorArgs(array($client)) - ->getMock(); + $clientMock = $this->createMock(Client::class); + $clientMock->method('getLastResponse')->willReturn(new PaginatedResponse(3, [])); + + $paginator = new ResultPager($clientMock); + $paginator->postFetch(); } } diff --git a/test/bootstrap.php b/test/bootstrap.php deleted file mode 100644 index 416d08990eb..00000000000 --- a/test/bootstrap.php +++ /dev/null @@ -1,18 +0,0 @@ -add('Github\Tests', __DIR__); - -return $loader;