Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Add support for merge request resource label event endpoints
* Add support for merge request and merge request note award emoji endpoints
* Add support for `MergeRequests::remove`
* Add support for container registry endpoints
* Add support for `Environments::stopStale`
* Add support for `last_activity_after` and `last_activity_before` in `Groups::projects`
* Fix `Projects::pipelines` date filters to include time information
Expand Down
7 changes: 7 additions & 0 deletions src/Api/Groups.php
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,13 @@ public function packages(int|string $group_id, array $parameters = []): mixed
return $this->get('groups/'.self::encodePath($group_id).'/packages', $resolver->resolve($parameters));
}

public function registryRepositories(int|string $group_id, array $parameters = []): mixed
{
$resolver = $this->createOptionsResolver();

return $this->get('groups/'.self::encodePath($group_id).'/registry/repositories', $resolver->resolve($parameters));
}

private function getGroupSearchResolver(): OptionsResolver
{
$resolver = $this->getSubgroupSearchResolver();
Expand Down
26 changes: 26 additions & 0 deletions src/Api/Projects.php
Original file line number Diff line number Diff line change
Expand Up @@ -1345,6 +1345,32 @@ public function removeJobTokenScopeAllowlistGroup(int|string $project_id, int $t
return $this->delete($this->getProjectPath($project_id, 'job_token_scope/groups_allowlist/'.self::encodePath($target_group_id)));
}

/**
* @param array $parameters {
*
* @var bool $tags include an array of tags in each repository
* @var bool $tags_count include tags_count in each repository
* }
*/
public function registryRepositories(int|string $project_id, array $parameters = []): mixed
{
$resolver = $this->createOptionsResolver();
$booleanNormalizer = function (Options $resolver, $value): string {
return $value ? 'true' : 'false';
};

$resolver->setDefined('tags')
->setAllowedTypes('tags', 'bool')
->setNormalizer('tags', $booleanNormalizer)
;
$resolver->setDefined('tags_count')
->setAllowedTypes('tags_count', 'bool')
->setNormalizer('tags_count', $booleanNormalizer)
;

return $this->get($this->getProjectPath($project_id, 'registry/repositories'), $resolver->resolve($parameters));
}

public function protectedTags(int|string $project_id): mixed
{
return $this->get('projects/'.self::encodePath($project_id).'/protected_tags');
Expand Down
121 changes: 121 additions & 0 deletions src/Api/Registry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Gitlab API library.
*
* (c) Matt Humphrey <matth@windsor-telecom.co.uk>
* (c) Graham Campbell <hello@gjcampbell.co.uk>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Gitlab\Api;

use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;

class Registry extends AbstractApi
{
/**
* @param array $parameters {
*
* @var bool $tags include an array of tags in the response
* @var bool $tags_count include tags_count in the response
* @var bool $size include the deduplicated size in the response
* }
*/
public function repository(int|string $repository_id, array $parameters = []): mixed
{
$resolver = self::createRepositoryResolver();

return $this->get('registry/repositories/'.self::encodePath($repository_id), $resolver->resolve($parameters));
}

public function removeRepository(int|string $project_id, int $repository_id): mixed
{
return $this->delete($this->getProjectPath($project_id, 'registry/repositories/'.self::encodePath($repository_id)));
}

public function repositoryTags(int|string $project_id, int $repository_id, array $parameters = []): mixed
{
$resolver = $this->createOptionsResolver();

return $this->get(
$this->getProjectPath($project_id, 'registry/repositories/'.self::encodePath($repository_id).'/tags'),
$resolver->resolve($parameters)
);
}

public function repositoryTag(int|string $project_id, int $repository_id, string $tag_name): mixed
{
return $this->get($this->getProjectPath(
$project_id,
'registry/repositories/'.self::encodePath($repository_id).'/tags/'.self::encodePath($tag_name)
));
}

public function removeRepositoryTag(int|string $project_id, int $repository_id, string $tag_name): mixed
{
return $this->delete($this->getProjectPath(
$project_id,
'registry/repositories/'.self::encodePath($repository_id).'/tags/'.self::encodePath($tag_name)
));
}

/**
* @param array $parameters {
*
* @var string $name_regex_delete regex of tag names to delete
* @var string $name_regex_keep regex of tag names to keep
* @var int $keep_n number of latest matching tags to keep
* @var string $older_than delete tags older than this human-readable duration
* }
*/
public function removeRepositoryTags(int|string $project_id, int $repository_id, array $parameters): mixed
{
$resolver = new OptionsResolver();
$resolver->setRequired('name_regex_delete')
->setAllowedTypes('name_regex_delete', 'string')
;
$resolver->setDefined('name_regex_keep')
->setAllowedTypes('name_regex_keep', 'string')
;
$resolver->setDefined('keep_n')
->setAllowedTypes('keep_n', 'int')
;
$resolver->setDefined('older_than')
->setAllowedTypes('older_than', 'string')
;

return $this->delete(
$this->getProjectPath($project_id, 'registry/repositories/'.self::encodePath($repository_id).'/tags'),
$resolver->resolve($parameters)
);
}

private static function createRepositoryResolver(): OptionsResolver
{
$resolver = new OptionsResolver();
$booleanNormalizer = function (Options $resolver, $value): string {
return $value ? 'true' : 'false';
};

$resolver->setDefined('tags')
->setAllowedTypes('tags', 'bool')
->setNormalizer('tags', $booleanNormalizer)
;
$resolver->setDefined('tags_count')
->setAllowedTypes('tags_count', 'bool')
->setNormalizer('tags_count', $booleanNormalizer)
;
$resolver->setDefined('size')
->setAllowedTypes('size', 'bool')
->setNormalizer('size', $booleanNormalizer)
;

return $resolver;
}
}
6 changes: 6 additions & 0 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
use Gitlab\Api\PersonalAccessTokens;
use Gitlab\Api\ProjectNamespaces;
use Gitlab\Api\Projects;
use Gitlab\Api\Registry;
use Gitlab\Api\Repositories;
use Gitlab\Api\RepositoryFiles;
use Gitlab\Api\ResourceIterationEvents;
Expand Down Expand Up @@ -251,6 +252,11 @@ public function projects(): Projects
return new Projects($this);
}

public function registry(): Registry
{
return new Registry($this);
}

public function repositories(): Repositories
{
return new Repositories($this);
Expand Down
36 changes: 36 additions & 0 deletions tests/Api/GroupsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,42 @@ public function shouldGetPackages(): void
$this->assertEquals($expectedArray, $api->packages(1));
}

#[Test]
public function shouldGetGroupRegistryRepositories(): void
{
$expectedArray = [
['id' => 1, 'name' => 'A registry'],
['id' => 2, 'name' => 'Another registry'],
];

$api = $this->getApiMock();
$api->expects($this->once())
->method('get')
->with('groups/1/registry/repositories', [])
->willReturn($expectedArray)
;

$this->assertEquals($expectedArray, $api->registryRepositories(1));
}

#[Test]
public function shouldGetGroupRegistryRepositoriesWithPagination(): void
{
$expectedArray = [
['id' => 1, 'name' => 'A registry'],
['id' => 2, 'name' => 'Another registry'],
];

$api = $this->getApiMock();
$api->expects($this->once())
->method('get')
->with('groups/1/registry/repositories', ['page' => 2, 'per_page' => 15])
->willReturn($expectedArray)
;

$this->assertEquals($expectedArray, $api->registryRepositories(1, ['page' => 2, 'per_page' => 15]));
}

#[Test]
public function shouldGetGroupMergeRequests(): void
{
Expand Down
51 changes: 51 additions & 0 deletions tests/Api/ProjectsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3000,6 +3000,57 @@ public function shouldRemoveJobTokenScopeAllowlistGroup(): void
$this->assertEquals($expectedString, $api->removeJobTokenScopeAllowlistGroup(1, 42));
}

#[Test]
public function shouldGetProjectRegistryRepositories(): void
{
$expectedArray = [
['id' => 1, 'name' => 'A registry'],
['id' => 2, 'name' => 'Another registry'],
];

$api = $this->getApiMock();
$api->expects($this->once())
->method('get')
->with('projects/123/registry/repositories', [])
->willReturn($expectedArray);

$this->assertEquals($expectedArray, $api->registryRepositories(123));
}

#[Test]
public function shouldGetProjectRegistryRepositoriesWithTags(): void
{
$expectedArray = [
['id' => 1, 'name' => 'A registry', 'tags' => ['1.0', '1.1'], 'tags_count' => 2],
['id' => 2, 'name' => 'Another registry', 'tags' => ['2.0', '2.1'], 'tags_count' => 2],
];

$api = $this->getApiMock();
$api->expects($this->once())
->method('get')
->with('projects/123/registry/repositories', ['tags' => 'true', 'tags_count' => 'true'])
->willReturn($expectedArray);

$this->assertEquals($expectedArray, $api->registryRepositories(123, ['tags' => true, 'tags_count' => true]));
}

#[Test]
public function shouldGetProjectRegistryRepositoriesWithPagination(): void
{
$expectedArray = [
['id' => 1, 'name' => 'A registry'],
['id' => 2, 'name' => 'Another registry'],
];

$api = $this->getApiMock();
$api->expects($this->once())
->method('get')
->with('projects/123/registry/repositories', ['page' => 2, 'per_page' => 15])
->willReturn($expectedArray);

$this->assertEquals($expectedArray, $api->registryRepositories(123, ['page' => 2, 'per_page' => 15]));
}

#[Test]
public function shouldUploadAvatar(): void
{
Expand Down
Loading