From c20e3cdcdb3b3ff35bc0d432fc918cdecd63a7e7 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Wed, 6 May 2026 17:21:29 +0100 Subject: [PATCH 1/2] Remove manual pagination parameters --- CHANGELOG.md | 1 + src/Api/Deployments.php | 9 +++- src/Api/Groups.php | 6 +-- src/Api/PersonalAccessTokens.php | 2 +- src/Api/Projects.php | 16 +++---- src/Api/Registry.php | 9 +--- src/Api/Users.php | 3 +- tests/Api/DeploymentsTest.php | 2 - tests/Api/GroupsTest.php | 20 +-------- tests/Api/PersonalAccessTokensTest.php | 4 -- tests/Api/ProjectsTest.php | 61 +------------------------- tests/Api/RegistryTest.php | 19 +------- tests/Api/UsersTest.php | 14 +----- 13 files changed, 28 insertions(+), 138 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22db7d93..886d940c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * 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 recent list endpoints to rely on the result pager for pagination * Fix `Projects::pipelines` date filters to include time information diff --git a/src/Api/Deployments.php b/src/Api/Deployments.php index 58cde53f..1768ed2a 100644 --- a/src/Api/Deployments.php +++ b/src/Api/Deployments.php @@ -15,6 +15,7 @@ namespace Gitlab\Api; use Symfony\Component\OptionsResolver\Options; +use Symfony\Component\OptionsResolver\OptionsResolver; class Deployments extends AbstractApi { @@ -80,6 +81,12 @@ public function show(int|string $project_id, int $deployment_id): mixed public function mergeRequests(int|string $project_id, int $deployment_id, array $parameters = []): mixed { - return $this->get($this->getProjectPath($project_id, 'deployments/'.$deployment_id.'/merge_requests'), $parameters); + $resolver = new OptionsResolver(); + $resolver->setDefined('state') + ->setAllowedValues('state', ['all', 'merged', 'opened', 'closed', 'locked']) + ; + $resolver->setDefined('labels'); + + return $this->get($this->getProjectPath($project_id, 'deployments/'.$deployment_id.'/merge_requests'), $resolver->resolve($parameters)); } } diff --git a/src/Api/Groups.php b/src/Api/Groups.php index b8ac7b48..1ad1008b 100644 --- a/src/Api/Groups.php +++ b/src/Api/Groups.php @@ -733,11 +733,9 @@ 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 + public function registryRepositories(int|string $group_id): mixed { - $resolver = $this->createOptionsResolver(); - - return $this->get('groups/'.self::encodePath($group_id).'/registry/repositories', $resolver->resolve($parameters)); + return $this->get('groups/'.self::encodePath($group_id).'/registry/repositories'); } private function getGroupSearchResolver(): OptionsResolver diff --git a/src/Api/PersonalAccessTokens.php b/src/Api/PersonalAccessTokens.php index 4d2d141c..81736c9e 100644 --- a/src/Api/PersonalAccessTokens.php +++ b/src/Api/PersonalAccessTokens.php @@ -37,7 +37,7 @@ class PersonalAccessTokens extends AbstractApi */ public function all(array $parameters = []): mixed { - $resolver = $this->createOptionsResolver(); + $resolver = new OptionsResolver(); $datetimeNormalizer = function (Options $resolver, \DateTimeInterface $value): string { return $value->format('c'); }; diff --git a/src/Api/Projects.php b/src/Api/Projects.php index 430f4b23..bae24f7f 100644 --- a/src/Api/Projects.php +++ b/src/Api/Projects.php @@ -1165,7 +1165,7 @@ public function deleteAllMergedBranches(int|string $project_id): mixed */ public function projectAccessTokens(int|string $project_id, array $parameters = []): mixed { - $resolver = $this->createOptionsResolver(); + $resolver = new OptionsResolver(); $datetimeNormalizer = function (Options $resolver, \DateTimeInterface $value): string { return $value->format('c'); }; @@ -1305,11 +1305,9 @@ public function updateJobTokenScope(int|string $project_id, bool $enabled): mixe return $this->patch($this->getProjectPath($project_id, 'job_token_scope'), ['enabled' => $enabled]); } - public function jobTokenScopeAllowlistProjects(int|string $project_id, array $parameters = []): mixed + public function jobTokenScopeAllowlistProjects(int|string $project_id): mixed { - $resolver = $this->createOptionsResolver(); - - return $this->get($this->getProjectPath($project_id, 'job_token_scope/allowlist'), $resolver->resolve($parameters)); + return $this->get($this->getProjectPath($project_id, 'job_token_scope/allowlist')); } public function addJobTokenScopeAllowlistProject(int|string $project_id, int $target_project_id): mixed @@ -1325,11 +1323,9 @@ public function removeJobTokenScopeAllowlistProject(int|string $project_id, int return $this->delete($this->getProjectPath($project_id, 'job_token_scope/allowlist/'.self::encodePath($target_project_id))); } - public function jobTokenScopeAllowlistGroups(int|string $project_id, array $parameters = []): mixed + public function jobTokenScopeAllowlistGroups(int|string $project_id): mixed { - $resolver = $this->createOptionsResolver(); - - return $this->get($this->getProjectPath($project_id, 'job_token_scope/groups_allowlist'), $resolver->resolve($parameters)); + return $this->get($this->getProjectPath($project_id, 'job_token_scope/groups_allowlist')); } public function addJobTokenScopeAllowlistGroup(int|string $project_id, int $target_group_id): mixed @@ -1354,7 +1350,7 @@ public function removeJobTokenScopeAllowlistGroup(int|string $project_id, int $t */ public function registryRepositories(int|string $project_id, array $parameters = []): mixed { - $resolver = $this->createOptionsResolver(); + $resolver = new OptionsResolver(); $booleanNormalizer = function (Options $resolver, $value): string { return $value ? 'true' : 'false'; }; diff --git a/src/Api/Registry.php b/src/Api/Registry.php index 074ff811..89232330 100644 --- a/src/Api/Registry.php +++ b/src/Api/Registry.php @@ -39,14 +39,9 @@ public function removeRepository(int|string $project_id, int $repository_id): mi 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 + public function repositoryTags(int|string $project_id, int $repository_id): mixed { - $resolver = $this->createOptionsResolver(); - - return $this->get( - $this->getProjectPath($project_id, 'registry/repositories/'.self::encodePath($repository_id).'/tags'), - $resolver->resolve($parameters) - ); + return $this->get($this->getProjectPath($project_id, 'registry/repositories/'.self::encodePath($repository_id).'/tags')); } public function repositoryTag(int|string $project_id, int $repository_id, string $tag_name): mixed diff --git a/src/Api/Users.php b/src/Api/Users.php index c26264fa..bfea9c6d 100644 --- a/src/Api/Users.php +++ b/src/Api/Users.php @@ -15,6 +15,7 @@ namespace Gitlab\Api; use Symfony\Component\OptionsResolver\Options; +use Symfony\Component\OptionsResolver\OptionsResolver; class Users extends AbstractApi { @@ -177,7 +178,7 @@ public function usersProjects(int $id, array $parameters = []): mixed */ public function usersContributedProjects(int|string $id, array $parameters = []): mixed { - $resolver = $this->createOptionsResolver(); + $resolver = new OptionsResolver(); $booleanNormalizer = function (Options $resolver, $value): string { return $value ? 'true' : 'false'; }; diff --git a/tests/Api/DeploymentsTest.php b/tests/Api/DeploymentsTest.php index ea3f0575..fed72b67 100644 --- a/tests/Api/DeploymentsTest.php +++ b/tests/Api/DeploymentsTest.php @@ -135,8 +135,6 @@ public function shouldGetDeploymentMergeRequestsWithParameters(): void $parameters = [ 'state' => 'merged', 'labels' => 'release,backend', - 'page' => 2, - 'per_page' => 25, ]; $api = $this->getApiMock(); diff --git a/tests/Api/GroupsTest.php b/tests/Api/GroupsTest.php index 85c45950..e81fc857 100644 --- a/tests/Api/GroupsTest.php +++ b/tests/Api/GroupsTest.php @@ -782,31 +782,13 @@ public function shouldGetGroupRegistryRepositories(): void $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('groups/1/registry/repositories', []) + ->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 { diff --git a/tests/Api/PersonalAccessTokensTest.php b/tests/Api/PersonalAccessTokensTest.php index 8692f646..ea8e8bc2 100644 --- a/tests/Api/PersonalAccessTokensTest.php +++ b/tests/Api/PersonalAccessTokensTest.php @@ -65,8 +65,6 @@ public function shouldGetAllTokensWithFilters(): void 'last_used_after' => $lastUsedAfter->format('c'), 'last_used_before' => $lastUsedBefore->format('c'), 'sort' => 'name_desc', - 'page' => 1, - 'per_page' => 10, ]) ->willReturn($expectedArray) ; @@ -83,8 +81,6 @@ public function shouldGetAllTokensWithFilters(): void 'last_used_after' => $lastUsedAfter, 'last_used_before' => $lastUsedBefore, 'sort' => 'name_desc', - 'page' => 1, - 'per_page' => 10, ])); } diff --git a/tests/Api/ProjectsTest.php b/tests/Api/ProjectsTest.php index 935a490e..019ec69b 100644 --- a/tests/Api/ProjectsTest.php +++ b/tests/Api/ProjectsTest.php @@ -2678,8 +2678,6 @@ public function shouldGetProjectAccessTokensWithFilters(): void 'last_used_after' => $lastUsedAfter->format('c'), 'last_used_before' => $lastUsedBefore->format('c'), 'sort' => 'name_desc', - 'page' => 1, - 'per_page' => 10, ]) ->willReturn($expectedArray); @@ -2694,8 +2692,6 @@ public function shouldGetProjectAccessTokensWithFilters(): void 'last_used_after' => $lastUsedAfter, 'last_used_before' => $lastUsedBefore, 'sort' => 'name_desc', - 'page' => 1, - 'per_page' => 10, ])); } @@ -2878,30 +2874,12 @@ public function shouldGetJobTokenScopeAllowlistProjects(): void $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('projects/1/job_token_scope/allowlist', []) + ->with('projects/1/job_token_scope/allowlist') ->willReturn($expectedArray); $this->assertEquals($expectedArray, $api->jobTokenScopeAllowlistProjects(1)); } - #[Test] - public function shouldGetJobTokenScopeAllowlistProjectsWithPagination(): void - { - $expectedArray = [[ - 'id' => 4, - 'name' => 'Diaspora Client', - 'web_url' => 'https://gitlab.example.com/diaspora/diaspora-client', - ]]; - - $api = $this->getApiMock(); - $api->expects($this->once()) - ->method('get') - ->with('projects/1/job_token_scope/allowlist', ['page' => 2, 'per_page' => 15]) - ->willReturn($expectedArray); - - $this->assertEquals($expectedArray, $api->jobTokenScopeAllowlistProjects(1, ['page' => 2, 'per_page' => 15])); - } - #[Test] public function shouldAddJobTokenScopeAllowlistProject(): void { @@ -2945,30 +2923,12 @@ public function shouldGetJobTokenScopeAllowlistGroups(): void $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('projects/1/job_token_scope/groups_allowlist', []) + ->with('projects/1/job_token_scope/groups_allowlist') ->willReturn($expectedArray); $this->assertEquals($expectedArray, $api->jobTokenScopeAllowlistGroups(1)); } - #[Test] - public function shouldGetJobTokenScopeAllowlistGroupsWithPagination(): void - { - $expectedArray = [[ - 'id' => 4, - 'name' => 'namegroup', - 'web_url' => 'https://gitlab.example.com/groups/diaspora/diaspora-group', - ]]; - - $api = $this->getApiMock(); - $api->expects($this->once()) - ->method('get') - ->with('projects/1/job_token_scope/groups_allowlist', ['page' => 2, 'per_page' => 15]) - ->willReturn($expectedArray); - - $this->assertEquals($expectedArray, $api->jobTokenScopeAllowlistGroups(1, ['page' => 2, 'per_page' => 15])); - } - #[Test] public function shouldAddJobTokenScopeAllowlistGroup(): void { @@ -3034,23 +2994,6 @@ public function shouldGetProjectRegistryRepositoriesWithTags(): void $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 { diff --git a/tests/Api/RegistryTest.php b/tests/Api/RegistryTest.php index 4f8688a3..1879e15e 100644 --- a/tests/Api/RegistryTest.php +++ b/tests/Api/RegistryTest.php @@ -72,29 +72,12 @@ public function shouldGetRepositoryTags(): void $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') - ->with('projects/1/registry/repositories/2/tags', []) + ->with('projects/1/registry/repositories/2/tags') ->willReturn($expectedArray); $this->assertEquals($expectedArray, $api->repositoryTags(1, 2)); } - #[Test] - public function shouldGetRepositoryTagsWithPagination(): void - { - $expectedArray = [ - ['name' => 'v1.0.0', 'path' => 'group/project:v1.0.0'], - ['name' => 'v1.1.0', 'path' => 'group/project:v1.1.0'], - ]; - - $api = $this->getApiMock(); - $api->expects($this->once()) - ->method('get') - ->with('projects/1/registry/repositories/2/tags', ['page' => 2, 'per_page' => 15]) - ->willReturn($expectedArray); - - $this->assertEquals($expectedArray, $api->repositoryTags(1, 2, ['page' => 2, 'per_page' => 15])); - } - #[Test] public function shouldGetRepositoryTag(): void { diff --git a/tests/Api/UsersTest.php b/tests/Api/UsersTest.php index b10a9e3f..c5df475c 100644 --- a/tests/Api/UsersTest.php +++ b/tests/Api/UsersTest.php @@ -307,16 +307,6 @@ public function shouldShowUsersContributedProjectsByUsername(): void $this->assertEquals($expectedArray, $api->usersContributedProjects('matt')); } - #[Test] - public function shouldShowUsersContributedProjectsWithLimit(): void - { - $expectedArray = [$this->getUsersProjectsData()[0]]; - - $api = $this->getUsersProjectsRequestMock('users/1/contributed_projects', $expectedArray, ['per_page' => 1]); - - $this->assertEquals($expectedArray, $api->usersContributedProjects(1, ['per_page' => 1])); - } - #[Test] public function shouldGetAllUsersContributedProjectsSortedByStars(): void { @@ -325,12 +315,12 @@ public function shouldGetAllUsersContributedProjectsSortedByStars(): void $api = $this->getUsersProjectsRequestMock( 'users/1/contributed_projects', $expectedArray, - ['page' => 1, 'per_page' => 5, 'order_by' => 'star_count', 'sort' => 'desc'] + ['order_by' => 'star_count', 'sort' => 'desc'] ); $this->assertEquals( $expectedArray, - $api->usersContributedProjects(1, ['page' => 1, 'per_page' => 5, 'order_by' => 'star_count', 'sort' => 'desc']) + $api->usersContributedProjects(1, ['order_by' => 'star_count', 'sort' => 'desc']) ); } From 43ed317615d833c6d7776c224234a29b7fb4d28e Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Wed, 6 May 2026 17:30:04 +0100 Subject: [PATCH 2/2] Document deployment merge request parameters --- src/Api/Deployments.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Api/Deployments.php b/src/Api/Deployments.php index 1768ed2a..7e0d514a 100644 --- a/src/Api/Deployments.php +++ b/src/Api/Deployments.php @@ -79,6 +79,13 @@ public function show(int|string $project_id, int $deployment_id): mixed return $this->get($this->getProjectPath($project_id, 'deployments/'.$deployment_id)); } + /** + * @param array $parameters { + * + * @var string $state return all merge requests or just those that are opened, closed, locked, or merged + * @var string $labels return merge requests matching a comma separated list of labels + * } + */ public function mergeRequests(int|string $project_id, int $deployment_id, array $parameters = []): mixed { $resolver = new OptionsResolver();