Skip to content

Commit 76ba6d9

Browse files
[11.9] Deploy Tokens (#701)
Co-authored-by: Graham Campbell <[email protected]>
1 parent 585bce1 commit 76ba6d9

File tree

4 files changed

+439
-0
lines changed

4 files changed

+439
-0
lines changed

src/Api/Groups.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,4 +729,75 @@ private function getSubgroupSearchResolver()
729729

730730
return $resolver;
731731
}
732+
733+
/**
734+
* @param int|string $group_id
735+
* @param bool|null $active
736+
*
737+
* @return mixed
738+
*/
739+
public function deployTokens($group_id, bool $active = null)
740+
{
741+
return $this->get('groups/'.self::encodePath($group_id).'/deploy_tokens', (null !== $active) ? ['active' => $active] : []);
742+
}
743+
744+
/**
745+
* @param int|string $group_id
746+
* @param array $parameters {
747+
*
748+
* @var string $name the name of the deploy token
749+
* @var \DateTimeInterface $expires_at expiration date for the deploy token, does not expire if no value is provided
750+
* @var string $username the username for the deploy token
751+
* @var array $scopes the scopes, one or many of: read_repository, read_registry, write_registry, read_package_registry, write_package_registry
752+
* }
753+
*
754+
* @return mixed
755+
*/
756+
public function createDeployToken($group_id, array $parameters = [])
757+
{
758+
$resolver = $this->createOptionsResolver();
759+
$datetimeNormalizer = function (Options $resolver, \DateTimeInterface $value): string {
760+
return $value->format('c');
761+
};
762+
763+
$resolver->define('name')
764+
->required()
765+
;
766+
767+
$resolver->define('scopes')
768+
->required()
769+
->allowedTypes('array')
770+
->allowedValues(function ($scopes) {
771+
$allowed = ['read_repository', 'read_registry', 'write_registry', 'read_package_registry', 'write_package_registry'];
772+
foreach ($scopes as $scope) {
773+
if (!\in_array($scope, $allowed, true)) {
774+
return false;
775+
}
776+
}
777+
778+
return true;
779+
})
780+
;
781+
$resolver->setDefined('username')
782+
->setAllowedTypes('username', 'string')
783+
;
784+
785+
$resolver->setDefined('expires_at')
786+
->setAllowedTypes('expires_at', \DateTimeInterface::class)
787+
->setNormalizer('expires_at', $datetimeNormalizer)
788+
;
789+
790+
return $this->post('groups/'.self::encodePath($group_id).'/deploy_tokens', $resolver->resolve($parameters));
791+
}
792+
793+
/**
794+
* @param int|string $group_id
795+
* @param int $token_id
796+
*
797+
* @return mixed
798+
*/
799+
public function deleteDeployToken($group_id, int $token_id)
800+
{
801+
return $this->delete('groups/'.self::encodePath($group_id).'/deploy_tokens/'.self::encodePath($token_id));
802+
}
732803
}

src/Api/Projects.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,77 @@ public function enableDeployKey($project_id, int $key_id)
783783
return $this->post($this->getProjectPath($project_id, 'deploy_keys/'.self::encodePath($key_id).'/enable'));
784784
}
785785

786+
/**
787+
* @param int|string $project_id
788+
* @param bool|null $active
789+
*
790+
* @return mixed
791+
*/
792+
public function deployTokens($project_id, bool $active = null)
793+
{
794+
return $this->get($this->getProjectPath($project_id, 'deploy_tokens'), (null !== $active) ? ['active' => $active] : []);
795+
}
796+
797+
/**
798+
* @param int|string $project_id
799+
* @param array $parameters {
800+
*
801+
* @var string $name the name of the deploy token
802+
* @var \DateTimeInterface $expires_at expiration date for the deploy token, does not expire if no value is provided
803+
* @var string $username the username for the deploy token
804+
* @var array $scopes the scopes, one or many of: read_repository, read_registry, write_registry, read_package_registry, write_package_registry
805+
* }
806+
*
807+
* @return mixed
808+
*/
809+
public function createDeployToken($project_id, array $parameters = [])
810+
{
811+
$resolver = $this->createOptionsResolver();
812+
$datetimeNormalizer = function (Options $resolver, \DateTimeInterface $value): string {
813+
return $value->format('c');
814+
};
815+
816+
$resolver->define('name')
817+
->required()
818+
;
819+
820+
$resolver->define('scopes')
821+
->required()
822+
->allowedTypes('array')
823+
->allowedValues(function ($scopes) {
824+
$allowed = ['read_repository', 'read_registry', 'write_registry', 'read_package_registry', 'write_package_registry'];
825+
foreach ($scopes as $scope) {
826+
if (!\in_array($scope, $allowed, true)) {
827+
return false;
828+
}
829+
}
830+
831+
return true;
832+
})
833+
;
834+
$resolver->setDefined('username')
835+
->setAllowedTypes('username', 'string')
836+
;
837+
838+
$resolver->setDefined('expires_at')
839+
->setAllowedTypes('expires_at', \DateTimeInterface::class)
840+
->setNormalizer('expires_at', $datetimeNormalizer)
841+
;
842+
843+
return $this->post($this->getProjectPath($project_id, 'deploy_tokens'), $resolver->resolve($parameters));
844+
}
845+
846+
/**
847+
* @param int|string $project_id
848+
* @param int $token_id
849+
*
850+
* @return mixed
851+
*/
852+
public function deleteDeployToken($project_id, int $token_id)
853+
{
854+
return $this->delete($this->getProjectPath($project_id, 'deploy_tokens/'.self::encodePath($token_id)));
855+
}
856+
786857
/**
787858
* @param int|string $project_id
788859
* @param array $parameters {

tests/Api/GroupsTest.php

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
namespace Gitlab\Tests\Api;
1616

17+
use DateTime;
1718
use Gitlab\Api\Groups;
1819

1920
class GroupsTest extends TestCase
@@ -735,4 +736,152 @@ public function shouldGetGroupMergeRequests(): void
735736

736737
$this->assertEquals($expectedArray, $api->mergeRequests(1, []));
737738
}
739+
740+
/**
741+
* @test
742+
*/
743+
public function shouldGetDeployTokens(): void
744+
{
745+
$expectedArray = [
746+
[
747+
'id' => 1,
748+
'name' => 'MyToken',
749+
'username' => 'gitlab+deploy-token-1',
750+
'expires_at' => '2020-02-14T00:00:00.000Z',
751+
'revoked' => false,
752+
'expired' => false,
753+
'scopes' => [
754+
'read_repository',
755+
'read_registry',
756+
],
757+
],
758+
];
759+
760+
$api = $this->getApiMock();
761+
$api->expects($this->once())
762+
->method('get')
763+
->with('groups/1/deploy_tokens')
764+
->will($this->returnValue($expectedArray));
765+
766+
$this->assertEquals($expectedArray, $api->deployTokens(1));
767+
}
768+
769+
/**
770+
* @test
771+
*/
772+
public function shouldGetActiveDeployTokens(): void
773+
{
774+
$expectedArray = [
775+
[
776+
'id' => 1,
777+
'name' => 'MyToken',
778+
'username' => 'gitlab+deploy-token-1',
779+
'expires_at' => '2020-02-14T00:00:00.000Z',
780+
'revoked' => false,
781+
'expired' => true,
782+
'scopes' => [
783+
'read_repository',
784+
'read_registry',
785+
],
786+
],
787+
];
788+
789+
$api = $this->getApiMock();
790+
$api->expects($this->once())
791+
->method('get')
792+
->with('groups/1/deploy_tokens', ['active' => true])
793+
->will($this->returnValue([]));
794+
795+
$this->assertEquals([], $api->deployTokens(1, true));
796+
}
797+
798+
/**
799+
* @test
800+
*/
801+
public function shouldGetInactiveDeployTokens(): void
802+
{
803+
$expectedArray = [
804+
[
805+
'id' => 1,
806+
'name' => 'MyToken',
807+
'username' => 'gitlab+deploy-token-1',
808+
'expires_at' => '2020-02-14T00:00:00.000Z',
809+
'revoked' => false,
810+
'expired' => true,
811+
'scopes' => [
812+
'read_repository',
813+
'read_registry',
814+
],
815+
],
816+
];
817+
818+
$api = $this->getApiMock();
819+
$api->expects($this->once())
820+
->method('get')
821+
->with('groups/1/deploy_tokens', ['active' => false])
822+
->will($this->returnValue([]));
823+
824+
$this->assertEquals([], $api->deployTokens(1, false));
825+
}
826+
827+
/**
828+
* @test
829+
*/
830+
public function shouldCreateDeployToken(): void
831+
{
832+
$expectedArray = [
833+
'id' => 1,
834+
'name' => 'My Deploy Token',
835+
'username' => 'custom-user',
836+
'token' => 'jMRvtPNxrn3crTAGukpZ',
837+
'expires_at' => '2021-01-01T00:00:00.000Z',
838+
'revoked' => false,
839+
'expired' => false,
840+
'scopes' => [
841+
'read_repository',
842+
'read_registry',
843+
],
844+
];
845+
846+
$api = $this->getApiMock();
847+
$api->expects($this->once())
848+
->method('post')
849+
->with(
850+
'groups/1/deploy_tokens',
851+
[
852+
'name' => 'My Deploy Token',
853+
'scopes' => [
854+
'read_repository',
855+
'read_registry',
856+
],
857+
'expires_at' => (new DateTime('2021-01-01'))->format('c'),
858+
]
859+
)
860+
->will($this->returnValue($expectedArray));
861+
862+
$this->assertEquals($expectedArray, $api->createDeployToken(1, [
863+
'name' => 'My Deploy Token',
864+
'scopes' => [
865+
'read_repository',
866+
'read_registry',
867+
],
868+
'expires_at' => new DateTime('2021-01-01'),
869+
]));
870+
}
871+
872+
/**
873+
* @test
874+
*/
875+
public function shouldDeleteDeployToken(): void
876+
{
877+
$expectedBool = true;
878+
879+
$api = $this->getApiMock();
880+
$api->expects($this->once())
881+
->method('delete')
882+
->with('groups/1/deploy_tokens/2')
883+
->will($this->returnValue($expectedBool));
884+
885+
$this->assertEquals($expectedBool, $api->deleteDeployToken(1, 2));
886+
}
738887
}

0 commit comments

Comments
 (0)