From 76229f9ef22c7f99e850a0b1b902da25a1a8da12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angutivik=20Casper=20R=C3=BAnur=20Tausen?= Date: Wed, 6 Mar 2024 13:47:24 +0100 Subject: [PATCH 01/16] Added getGroupPath This is similar to getProjectPath, but for groups. --- src/Api/AbstractApi.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Api/AbstractApi.php b/src/Api/AbstractApi.php index c7026135..11f1fb8e 100644 --- a/src/Api/AbstractApi.php +++ b/src/Api/AbstractApi.php @@ -253,6 +253,16 @@ protected function getProjectPath($id, string $uri): string return 'projects/'.self::encodePath($id).'/'.$uri; } + /** + * @param $id + * @param string $uri + * @return string + */ + protected function getGroupPath($id, string $uri): string + { + return 'groups/'.self::encodePath($id).'/'.$uri; + } + /** * Create a new OptionsResolver with page and per_page options. * From 63aa8d19b994e0312ac82e8d6f56812b7701c3be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angutivik=20Casper=20R=C3=BAnur=20Tausen?= Date: Wed, 6 Mar 2024 13:48:45 +0100 Subject: [PATCH 02/16] Added methods for group access tokens Adds the same functions currently available for project access tokens, but for groups. --- src/Api/Groups.php | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/Api/Groups.php b/src/Api/Groups.php index 5a97e0cf..806c71c7 100644 --- a/src/Api/Groups.php +++ b/src/Api/Groups.php @@ -982,6 +982,75 @@ public function deleteDeployToken($group_id, int $token_id) return $this->delete('groups/'.self::encodePath($group_id).'/deploy_tokens/'.self::encodePath($token_id)); } + /** + * @param $group_id + * @return mixed + */ + public function groupAccessTokens($group_id) + { + return $this->get($this->getGroupPath($group_id, 'access_tokens')); + } + + /** + * @param $group_id + * @param $token_id + * @return mixed + */ + public function groupAccessToken($group_id, $token_id) + { + return $this->get($this->getGroupPath($group_id, 'access_tokens/'.self::encodePath($token_id))); + } + + /** + * @param $group_id + * @param array $parameters + * @return mixed + */ + public function createGroupAccessToken($group_id, array $parameters = []) + { + $resolver = $this->createOptionsResolver(); + $datetimeNormalizer = function (Options $resolver, \DateTimeInterface $value): string { + return $value->format('Y-m-d'); + }; + + $resolver->define('name') + ->required(); + + $resolver->define('scopes') + ->required() + ->allowedTypes('array') + ->allowedValues(function ($scopes) { + $allowed = ['api', 'read_api', 'read_registry', 'write_registry', 'read_repository', 'write_repository']; + foreach ($scopes as $scope) { + if (!\in_array($scope, $allowed, true)) { + return false; + } + } + + return true; + }); + + $resolver->setDefined('access_level') + ->setAllowedTypes('access_level', 'int') + ->setAllowedValues('access_level', [10, 20, 30, 40, 50]); + + $resolver->setDefined('expires_at') + ->setAllowedTypes('expires_at', \DateTimeInterface::class) + ->setNormalizer('expires_at', $datetimeNormalizer); + + return $this->post($this->getGroupPath($group_id, 'access_tokens'), $resolver->resolve($parameters)); + } + + /** + * @param $group_id + * @param $token_id + * @return mixed + */ + public function deleteGroupAccessToken($group_id, $token_id) + { + return $this->delete($this->getGroupPath($group_id, 'access_tokens/'.self::encodePath($token_id))); + } + /** * @param int|string $id * @param array $parameters { From cb932b23bafff5fd9e8bf6205a93f5d80f50917d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angutivik=20Casper=20R=C3=BAnur=20Tausen?= Date: Wed, 6 Mar 2024 14:04:20 +0100 Subject: [PATCH 03/16] Added tests for group access tokens --- tests/Api/GroupsTest.php | 119 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/tests/Api/GroupsTest.php b/tests/Api/GroupsTest.php index 19209bfd..db80b4cc 100644 --- a/tests/Api/GroupsTest.php +++ b/tests/Api/GroupsTest.php @@ -941,6 +941,125 @@ public function shouldDeleteDeployToken(): void $this->assertEquals($expectedBool, $api->deleteDeployToken(1, 2)); } + /** + * @test + */ + public function shouldGetGroupAccessTokens(): void + { + $expectedArray = [ + [ + 'user_id' => 141, + 'scopes' => [ + 'api', + ], + 'name' => 'token', + 'expires_at' => '2021-01-31', + 'id' => 42, + 'active' => true, + 'created_at' => '2021-01-20T22:11:48.151Z', + 'revoked' => false, + ], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('groups/1/access_tokens') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->groupAccessTokens(1)); + } + + /** + * @test + */ + public function shouldGetGroupAccessToken(): void + { + $expectedArray = [ + 'user_id' => 141, + 'scopes' => [ + 'api', + ], + 'name' => 'token', + 'expires_at' => '2021-01-31', + 'id' => 42, + 'active' => true, + 'created_at' => '2021-01-20T22:11:48.151Z', + 'revoked' => false, + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('groups/1/access_tokens/42') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->groupAccessToken(1, 42)); + } + + /** + * @test + */ + public function shouldCreateGroupAccessToken(): void + { + $expectedArray = [ + 'scopes' => [ + 'api', + 'read_repository', + ], + 'active' => true, + 'name' => 'test', + 'revoked' => false, + 'created_at' => '2021-01-21T19:35:37.921Z', + 'user_id' => 166, + 'id' => 58, + 'expires_at' => '2021-01-31', + 'token' => 'D4y...Wzr', + ]; + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with( + 'groups/1/access_tokens', + [ + 'name' => 'test_token', + 'scopes' => [ + 'api', + 'read_repository', + ], + 'access_level' => 30, + 'expires_at' => '2021-01-31', + ] + ) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->createGroupAccessToken(1, [ + 'name' => 'test_token', + 'scopes' => [ + 'api', + 'read_repository', + ], + 'access_level' => 30, + 'expires_at' => new DateTime('2021-01-31'), + ])); + } + + /** + * @test + */ + public function shouldDeleteGroupAccessToken(): void + { + $expectedBool = true; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('groups/1/access_tokens/2') + ->will($this->returnValue($expectedBool)); + + $this->assertEquals($expectedBool, $api->deleteGroupAccessToken(1, 2)); + } + /** * @test */ From d00fb409cee631e974b03c87bd6b9da7d00b6fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angutivik=20Casper=20R=C3=BAnur=20Tausen?= Date: Wed, 6 Mar 2024 14:13:38 +0100 Subject: [PATCH 04/16] Fix PHPDoc style --- src/Api/AbstractApi.php | 1 + src/Api/Groups.php | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/Api/AbstractApi.php b/src/Api/AbstractApi.php index 11f1fb8e..77885239 100644 --- a/src/Api/AbstractApi.php +++ b/src/Api/AbstractApi.php @@ -256,6 +256,7 @@ protected function getProjectPath($id, string $uri): string /** * @param $id * @param string $uri + * * @return string */ protected function getGroupPath($id, string $uri): string diff --git a/src/Api/Groups.php b/src/Api/Groups.php index 806c71c7..0b050894 100644 --- a/src/Api/Groups.php +++ b/src/Api/Groups.php @@ -984,6 +984,7 @@ public function deleteDeployToken($group_id, int $token_id) /** * @param $group_id + * * @return mixed */ public function groupAccessTokens($group_id) @@ -994,6 +995,7 @@ public function groupAccessTokens($group_id) /** * @param $group_id * @param $token_id + * * @return mixed */ public function groupAccessToken($group_id, $token_id) @@ -1004,6 +1006,7 @@ public function groupAccessToken($group_id, $token_id) /** * @param $group_id * @param array $parameters + * * @return mixed */ public function createGroupAccessToken($group_id, array $parameters = []) @@ -1044,6 +1047,7 @@ public function createGroupAccessToken($group_id, array $parameters = []) /** * @param $group_id * @param $token_id + * * @return mixed */ public function deleteGroupAccessToken($group_id, $token_id) From a5f9de4cf19f075d51b74282f40829a891ee7871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angutivik=20Casper=20R=C3=BAnur=20Tausen?= Date: Wed, 6 Mar 2024 15:04:28 +0100 Subject: [PATCH 05/16] Fixed PHP version requirements The require for PHP versions was inaccurate, as this project actually only supports PHP 8.1 and above. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 96efc599..6e8337d0 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ } ], "require": { - "php": "^7.4.15 || ^8.0.2", + "php": "^8.1", "ext-json": "*", "ext-xml": "*", "php-http/cache-plugin": "^1.8.1", From 243da8164a6458fd214529ceea790466458e1a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angutivik=20Casper=20R=C3=BAnur=20Tausen?= Date: Wed, 6 Mar 2024 15:17:47 +0100 Subject: [PATCH 06/16] Added typed parameters and typed returns This has been added to make PHPStan happi. :) --- src/Api/AbstractApi.php | 14 +++++----- src/Api/Groups.php | 62 ++++++++++++++++++++--------------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/Api/AbstractApi.php b/src/Api/AbstractApi.php index 77885239..7861d10a 100644 --- a/src/Api/AbstractApi.php +++ b/src/Api/AbstractApi.php @@ -253,13 +253,13 @@ protected function getProjectPath($id, string $uri): string return 'projects/'.self::encodePath($id).'/'.$uri; } - /** - * @param $id - * @param string $uri - * - * @return string - */ - protected function getGroupPath($id, string $uri): string + /** + * @param string|int $id + * @param string $uri + * + * @return string + */ + protected function getGroupPath(string|int $id, string $uri): string { return 'groups/'.self::encodePath($id).'/'.$uri; } diff --git a/src/Api/Groups.php b/src/Api/Groups.php index 0b050894..c7abbe4a 100644 --- a/src/Api/Groups.php +++ b/src/Api/Groups.php @@ -982,35 +982,35 @@ public function deleteDeployToken($group_id, int $token_id) return $this->delete('groups/'.self::encodePath($group_id).'/deploy_tokens/'.self::encodePath($token_id)); } - /** - * @param $group_id - * - * @return mixed - */ - public function groupAccessTokens($group_id) - { + /** + * @param string|int $group_id + * + * @return mixed + */ + public function groupAccessTokens(string|int $group_id): mixed + { return $this->get($this->getGroupPath($group_id, 'access_tokens')); } - /** - * @param $group_id - * @param $token_id - * - * @return mixed - */ - public function groupAccessToken($group_id, $token_id) - { + /** + * @param string|int $group_id + * @param string|int $token_id + * + * @return mixed + */ + public function groupAccessToken(string|int $group_id, string|int $token_id): mixed + { return $this->get($this->getGroupPath($group_id, 'access_tokens/'.self::encodePath($token_id))); } - /** - * @param $group_id - * @param array $parameters - * - * @return mixed - */ - public function createGroupAccessToken($group_id, array $parameters = []) - { + /** + * @param string|int $group_id + * @param array $parameters + * + * @return mixed + */ + public function createGroupAccessToken(string|int $group_id, array $parameters = []): mixed + { $resolver = $this->createOptionsResolver(); $datetimeNormalizer = function (Options $resolver, \DateTimeInterface $value): string { return $value->format('Y-m-d'); @@ -1044,14 +1044,14 @@ public function createGroupAccessToken($group_id, array $parameters = []) return $this->post($this->getGroupPath($group_id, 'access_tokens'), $resolver->resolve($parameters)); } - /** - * @param $group_id - * @param $token_id - * - * @return mixed - */ - public function deleteGroupAccessToken($group_id, $token_id) - { + /** + * @param string|int $group_id + * @param string|int $token_id + * + * @return mixed + */ + public function deleteGroupAccessToken(string|int $group_id, string|int $token_id): mixed + { return $this->delete($this->getGroupPath($group_id, 'access_tokens/'.self::encodePath($token_id))); } From fb8978f64a17a17f55b8e776ebf7bfceb0d1eb37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angutivik=20Casper=20R=C3=BAnur=20Tausen?= Date: Wed, 6 Mar 2024 15:20:00 +0100 Subject: [PATCH 07/16] Fix the doing of my IDE It added tabs instead of spaces. :( --- src/Api/AbstractApi.php | 12 ++++----- src/Api/Groups.php | 54 ++++++++++++++++++++--------------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/Api/AbstractApi.php b/src/Api/AbstractApi.php index 7861d10a..2f8c8dcb 100644 --- a/src/Api/AbstractApi.php +++ b/src/Api/AbstractApi.php @@ -253,12 +253,12 @@ protected function getProjectPath($id, string $uri): string return 'projects/'.self::encodePath($id).'/'.$uri; } - /** - * @param string|int $id - * @param string $uri - * - * @return string - */ + /** + * @param string|int $id + * @param string $uri + * + * @return string + */ protected function getGroupPath(string|int $id, string $uri): string { return 'groups/'.self::encodePath($id).'/'.$uri; diff --git a/src/Api/Groups.php b/src/Api/Groups.php index c7abbe4a..5e9d6a90 100644 --- a/src/Api/Groups.php +++ b/src/Api/Groups.php @@ -982,35 +982,35 @@ public function deleteDeployToken($group_id, int $token_id) return $this->delete('groups/'.self::encodePath($group_id).'/deploy_tokens/'.self::encodePath($token_id)); } - /** - * @param string|int $group_id - * - * @return mixed - */ + /** + * @param string|int $group_id + * + * @return mixed + */ public function groupAccessTokens(string|int $group_id): mixed - { + { return $this->get($this->getGroupPath($group_id, 'access_tokens')); } - /** - * @param string|int $group_id - * @param string|int $token_id - * - * @return mixed - */ + /** + * @param string|int $group_id + * @param string|int $token_id + * + * @return mixed + */ public function groupAccessToken(string|int $group_id, string|int $token_id): mixed - { + { return $this->get($this->getGroupPath($group_id, 'access_tokens/'.self::encodePath($token_id))); } - /** - * @param string|int $group_id - * @param array $parameters - * - * @return mixed - */ + /** + * @param string|int $group_id + * @param array $parameters + * + * @return mixed + */ public function createGroupAccessToken(string|int $group_id, array $parameters = []): mixed - { + { $resolver = $this->createOptionsResolver(); $datetimeNormalizer = function (Options $resolver, \DateTimeInterface $value): string { return $value->format('Y-m-d'); @@ -1044,14 +1044,14 @@ public function createGroupAccessToken(string|int $group_id, array $parameters = return $this->post($this->getGroupPath($group_id, 'access_tokens'), $resolver->resolve($parameters)); } - /** - * @param string|int $group_id - * @param string|int $token_id - * - * @return mixed - */ + /** + * @param string|int $group_id + * @param string|int $token_id + * + * @return mixed + */ public function deleteGroupAccessToken(string|int $group_id, string|int $token_id): mixed - { + { return $this->delete($this->getGroupPath($group_id, 'access_tokens/'.self::encodePath($token_id))); } From b070c800ae5700a094693cce39a4d67e5b2db9c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angutivik=20Casper=20R=C3=BAnur=20Tausen?= Date: Wed, 6 Mar 2024 15:28:34 +0100 Subject: [PATCH 08/16] Fixed PHPDocs in HttpClient/Pluging/* PHPDocs were faulty (according to PHPStan) in Authentication and ExceptionThrower. The `make test` command should no longer fail. --- src/HttpClient/Plugin/Authentication.php | 2 +- src/HttpClient/Plugin/ExceptionThrower.php | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/HttpClient/Plugin/Authentication.php b/src/HttpClient/Plugin/Authentication.php index 2160f5cd..fb006a67 100644 --- a/src/HttpClient/Plugin/Authentication.php +++ b/src/HttpClient/Plugin/Authentication.php @@ -55,7 +55,7 @@ public function __construct(string $method, string $token, string $sudo = null) * @param callable $next * @param callable $first * - * @return Promise + * @return Promise */ public function handleRequest(RequestInterface $request, callable $next, callable $first): Promise { diff --git a/src/HttpClient/Plugin/ExceptionThrower.php b/src/HttpClient/Plugin/ExceptionThrower.php index 207ecaaa..45e4c121 100644 --- a/src/HttpClient/Plugin/ExceptionThrower.php +++ b/src/HttpClient/Plugin/ExceptionThrower.php @@ -39,10 +39,12 @@ final class ExceptionThrower implements Plugin * Handle the request and return the response coming from the next callable. * * @param RequestInterface $request - * @param callable $next - * @param callable $first + * @param callable $next + * @param callable $first * - * @return Promise + * @return Promise + * @throws ErrorException + * @throws ExceptionInterface */ public function handleRequest(RequestInterface $request, callable $next, callable $first): Promise { From 3b41f1ffe4e0f7245a4f06a61168f4504d023f3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angutivik=20Casper=20R=C3=BAnur=20Tausen?= Date: Wed, 6 Mar 2024 15:32:06 +0100 Subject: [PATCH 09/16] Make StyleCI happy again. It appears to be very picky; I guess this is good practice. --- src/HttpClient/Plugin/Authentication.php | 1 - src/HttpClient/Plugin/ExceptionThrower.php | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HttpClient/Plugin/Authentication.php b/src/HttpClient/Plugin/Authentication.php index fb006a67..923c981f 100644 --- a/src/HttpClient/Plugin/Authentication.php +++ b/src/HttpClient/Plugin/Authentication.php @@ -19,7 +19,6 @@ use Http\Client\Common\Plugin; use Http\Promise\Promise; use Psr\Http\Message\RequestInterface; -use Psr\Http\Message\ResponseInterface; /** * Add authentication to the request. diff --git a/src/HttpClient/Plugin/ExceptionThrower.php b/src/HttpClient/Plugin/ExceptionThrower.php index 45e4c121..33bc2cf0 100644 --- a/src/HttpClient/Plugin/ExceptionThrower.php +++ b/src/HttpClient/Plugin/ExceptionThrower.php @@ -42,9 +42,10 @@ final class ExceptionThrower implements Plugin * @param callable $next * @param callable $first * - * @return Promise * @throws ErrorException * @throws ExceptionInterface + * + * @return Promise */ public function handleRequest(RequestInterface $request, callable $next, callable $first): Promise { From 804b62e4a4deb8b45b9bf5562fa4895105664a50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angutivik=20Casper=20R=C3=BAnur=20Tausen?= Date: Wed, 6 Mar 2024 15:38:14 +0100 Subject: [PATCH 10/16] Remove unsupported PHP versions from tests --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index eb2530e2..7215c075 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: - php: ['7.4', '8.0', '8.1', '8.2', '8.3'] + php: ['8.1', '8.2', '8.3'] steps: - name: Checkout Code From c44e0aa17002b36b35f7c44c60dc36cc7fe6bef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angutivik=20Casper=20R=C3=BAnur=20Tausen?= Date: Tue, 12 Mar 2024 16:45:33 +0100 Subject: [PATCH 11/16] Add rotation functionality for group access tokens --- src/Api/Groups.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Api/Groups.php b/src/Api/Groups.php index 5e9d6a90..a0e133c8 100644 --- a/src/Api/Groups.php +++ b/src/Api/Groups.php @@ -1055,6 +1055,24 @@ public function deleteGroupAccessToken(string|int $group_id, string|int $token_i return $this->delete($this->getGroupPath($group_id, 'access_tokens/'.self::encodePath($token_id))); } + /** + * @param string|int $group_id + * @param string|int $token_id + * @param string $expiry + * + * @return mixed + */ + public function rotateGroupAccessToken(string|int $group_id, string|int $token_id, string $expiry = ''): mixed + { + $regex = '/(?:19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[1-2]\d|3[01])/'; + if ($expiry !== '' && preg_match($regex, $expiry) !== false) { + $uri = 'access_tokens/'.self::encodePath($token_id).'/rotate?expires_at='.$expiry; + return $this->post($this->getGroupPath($group_id, $uri)); + } + + return $this->post($this->getGroupPath($group_id, 'access_tokens/'.self::encodePath($token_id).'/rotate')); + } + /** * @param int|string $id * @param array $parameters { From c5959f1b4e48aedeb5b14ca9632d8a835de1cfaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angutivik=20Casper=20R=C3=BAnur=20Tausen?= Date: Wed, 13 Mar 2024 09:30:01 +0100 Subject: [PATCH 12/16] Made it possible to rotate project access tokens --- src/Api/Projects.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Api/Projects.php b/src/Api/Projects.php index d0c66833..8db76182 100644 --- a/src/Api/Projects.php +++ b/src/Api/Projects.php @@ -1715,6 +1715,24 @@ public function deleteProjectAccessToken($project_id, $token_id) return $this->delete($this->getProjectPath($project_id, 'access_tokens/'.$token_id)); } + /** + * @param string|int $project_id + * @param string|int $token_id + * @param string $expiry + * + * @return mixed + */ + public function rotateProjectAccessToken(string|int $project_id, string|int $token_id, string $expiry = ''): mixed + { + $regex = '/(?:19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[1-2]\d|3[01])/'; + if ($expiry !== '' && preg_match($regex, $expiry) !== false) { + $uri = 'access_tokens/'.self::encodePath($token_id).'/rotate?expires_at='.$expiry; + return $this->post($this->getProjectPath($project_id, $uri)); + } + + return $this->post($this->getProjectPath($project_id, 'access_tokens/'.self::encodePath($token_id).'/rotate')); + } + /** * @param int|string $project_id * From 97e72819556405b4c0a317678557ef38395a7711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angutivik=20Casper=20R=C3=BAnur=20Tausen?= Date: Mon, 18 Mar 2024 09:14:36 +0100 Subject: [PATCH 13/16] Fixed styleci complaints --- src/Api/Groups.php | 2 +- src/Api/Projects.php | 34 +++++++++++++++++----------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Api/Groups.php b/src/Api/Groups.php index a0e133c8..a4b8666e 100644 --- a/src/Api/Groups.php +++ b/src/Api/Groups.php @@ -1065,7 +1065,7 @@ public function deleteGroupAccessToken(string|int $group_id, string|int $token_i public function rotateGroupAccessToken(string|int $group_id, string|int $token_id, string $expiry = ''): mixed { $regex = '/(?:19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[1-2]\d|3[01])/'; - if ($expiry !== '' && preg_match($regex, $expiry) !== false) { + if ('' !== $expiry && false !== \preg_match($regex, $expiry)) { $uri = 'access_tokens/'.self::encodePath($token_id).'/rotate?expires_at='.$expiry; return $this->post($this->getGroupPath($group_id, $uri)); } diff --git a/src/Api/Projects.php b/src/Api/Projects.php index 8db76182..64afe34c 100644 --- a/src/Api/Projects.php +++ b/src/Api/Projects.php @@ -1715,23 +1715,23 @@ public function deleteProjectAccessToken($project_id, $token_id) return $this->delete($this->getProjectPath($project_id, 'access_tokens/'.$token_id)); } - /** - * @param string|int $project_id - * @param string|int $token_id - * @param string $expiry - * - * @return mixed - */ - public function rotateProjectAccessToken(string|int $project_id, string|int $token_id, string $expiry = ''): mixed - { - $regex = '/(?:19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[1-2]\d|3[01])/'; - if ($expiry !== '' && preg_match($regex, $expiry) !== false) { - $uri = 'access_tokens/'.self::encodePath($token_id).'/rotate?expires_at='.$expiry; - return $this->post($this->getProjectPath($project_id, $uri)); - } - - return $this->post($this->getProjectPath($project_id, 'access_tokens/'.self::encodePath($token_id).'/rotate')); - } + /** + * @param string|int $project_id + * @param string|int $token_id + * @param string $expiry + * + * @return mixed + */ + public function rotateProjectAccessToken(string|int $project_id, string|int $token_id, string $expiry = ''): mixed + { + $regex = '/(?:19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[1-2]\d|3[01])/'; + if ('' !== $expiry && false !== \preg_match($regex, $expiry)) { + $uri = 'access_tokens/'.self::encodePath($token_id).'/rotate?expires_at='.$expiry; + return $this->post($this->getProjectPath($project_id, $uri)); + } + + return $this->post($this->getProjectPath($project_id, 'access_tokens/'.self::encodePath($token_id).'/rotate')); + } /** * @param int|string $project_id From 3bc58763f437a6491a54640f107df54f865459ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angutivik=20Casper=20R=C3=BAnur=20Tausen?= Date: Mon, 18 Mar 2024 09:16:41 +0100 Subject: [PATCH 14/16] Fix styleci complain that wasn't previously there --- src/Api/Groups.php | 1 + src/Api/Projects.php | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Api/Groups.php b/src/Api/Groups.php index a4b8666e..d8dcc03c 100644 --- a/src/Api/Groups.php +++ b/src/Api/Groups.php @@ -1067,6 +1067,7 @@ public function rotateGroupAccessToken(string|int $group_id, string|int $token_i $regex = '/(?:19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[1-2]\d|3[01])/'; if ('' !== $expiry && false !== \preg_match($regex, $expiry)) { $uri = 'access_tokens/'.self::encodePath($token_id).'/rotate?expires_at='.$expiry; + return $this->post($this->getGroupPath($group_id, $uri)); } diff --git a/src/Api/Projects.php b/src/Api/Projects.php index 64afe34c..0bac0ca6 100644 --- a/src/Api/Projects.php +++ b/src/Api/Projects.php @@ -1727,6 +1727,7 @@ public function rotateProjectAccessToken(string|int $project_id, string|int $tok $regex = '/(?:19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[1-2]\d|3[01])/'; if ('' !== $expiry && false !== \preg_match($regex, $expiry)) { $uri = 'access_tokens/'.self::encodePath($token_id).'/rotate?expires_at='.$expiry; + return $this->post($this->getProjectPath($project_id, $uri)); } From 6962b87ad4111909c37b84876b7f26f7e9c4fb2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angutivik=20Casper=20R=C3=BAnur=20Tausen?= Date: Mon, 18 Mar 2024 09:58:04 +0100 Subject: [PATCH 15/16] Added tests for access token rotation --- tests/Api/GroupsTest.php | 28 ++++++++++++++++++++++++++++ tests/Api/ProjectsTest.php | 29 +++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/tests/Api/GroupsTest.php b/tests/Api/GroupsTest.php index db80b4cc..38058b35 100644 --- a/tests/Api/GroupsTest.php +++ b/tests/Api/GroupsTest.php @@ -1060,6 +1060,34 @@ public function shouldDeleteGroupAccessToken(): void $this->assertEquals($expectedBool, $api->deleteGroupAccessToken(1, 2)); } + /** + * @test + */ + public function shouldRotateGroupAccessToken(): void + { + $expectedArray = [ + 'scopes' => [ + 'api', + 'read_repository', + ], + 'active' => true, + 'name' => 'test', + 'revoked' => false, + 'created_at' => '2021-01-21T19:35:37.921Z', + 'user_id' => 166, + 'id' => 58, + 'expires_at' => '2021-01-31', + 'token' => 'D4y...Wzr', + ]; + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('groups/1/access_tokens/2/rotate?expires_at=2021-01-31') + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->rotateGroupAccessToken(1, 2, '2021-01-31')); + } + /** * @test */ diff --git a/tests/Api/ProjectsTest.php b/tests/Api/ProjectsTest.php index c3296d62..ef1843f4 100644 --- a/tests/Api/ProjectsTest.php +++ b/tests/Api/ProjectsTest.php @@ -2952,6 +2952,35 @@ public function shouldDeleteProjectAccessToken(): void $this->assertEquals($expectedBool, $api->deleteProjectAccessToken(1, 2)); } + /** + * @test + */ + public function shouldRotateProjectAccessToken(): void + { + $expectedArray = [ + 'scopes' => [ + 'api', + 'read_repository', + ], + 'active' => true, + 'name' => 'test', + 'revoked' => false, + 'created_at' => '2021-01-21T19:35:37.921Z', + 'user_id' => 166, + 'id' => 58, + 'expires_at' => '2021-01-31', + 'token' => 'D4y...Wzr', + ]; + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with( + 'projects/1/access_tokens/2/rotate?expires_at=2021-01-31',) + ->will($this->returnValue($expectedArray)); + + $this->assertEquals($expectedArray, $api->rotateProjectAccessToken(1, 2, '2021-01-31')); + } + /** * @test */ From c7e1e124675722fa9d5de24e04e66954069783ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Angutivik=20Casper=20R=C3=BAnur=20Tausen?= Date: Mon, 18 Mar 2024 09:59:36 +0100 Subject: [PATCH 16/16] Remove overseen comma --- tests/Api/ProjectsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Api/ProjectsTest.php b/tests/Api/ProjectsTest.php index ef1843f4..13495574 100644 --- a/tests/Api/ProjectsTest.php +++ b/tests/Api/ProjectsTest.php @@ -2975,7 +2975,7 @@ public function shouldRotateProjectAccessToken(): void $api->expects($this->once()) ->method('post') ->with( - 'projects/1/access_tokens/2/rotate?expires_at=2021-01-31',) + 'projects/1/access_tokens/2/rotate?expires_at=2021-01-31') ->will($this->returnValue($expectedArray)); $this->assertEquals($expectedArray, $api->rotateProjectAccessToken(1, 2, '2021-01-31'));