From dbd847adf816c00cdd10b4de7a3cef4b55bafb20 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Wed, 6 May 2026 15:17:35 +0100 Subject: [PATCH 1/2] Add missing group project and pipeline filters --- CHANGELOG.md | 2 ++ src/Api/Groups.php | 41 +++++++++++++++++++++++++------------- src/Api/Projects.php | 32 +++++++++++++++-------------- tests/Api/GroupsTest.php | 40 +++++++++++++++++++++++++++++++++++++ tests/Api/ProjectsTest.php | 12 +++++------ 5 files changed, 92 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35c0465f..f27ec00b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Add support for project CI/CD job token scope endpoints * Add support for merge request resource label event 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 ## [12.0.0] - 2025-02-23 diff --git a/src/Api/Groups.php b/src/Api/Groups.php index 5248e36e..6351b92f 100644 --- a/src/Api/Groups.php +++ b/src/Api/Groups.php @@ -236,20 +236,22 @@ public function removeMember(int|string $group_id, int $user_id): mixed /** * @param array $parameters { * - * @var bool $archived limit by archived status - * @var string $visibility limit by visibility public, internal, or private - * @var string $order_by Return projects ordered by id, name, path, created_at, updated_at, or last_activity_at fields. - * Default is created_at. - * @var string $sort Return projects sorted in asc or desc order (default is desc) - * @var string $search return list of authorized projects matching the search criteria - * @var bool $simple return only the ID, URL, name, and path of each project - * @var bool $owned limit by projects owned by the current user - * @var bool $starred limit by projects starred by the current user - * @var bool $with_issues_enabled Limit by projects with issues feature enabled (default is false) - * @var bool $with_merge_requests_enabled Limit by projects with merge requests feature enabled (default is false) - * @var bool $with_shared Include projects shared to this group (default is true) - * @var bool $include_subgroups Include projects in subgroups of this group (default is false) - * @var bool $with_custom_attributes Include custom attributes in response (admins only). + * @var bool $archived limit by archived status + * @var string $visibility limit by visibility public, internal, or private + * @var string $order_by Return projects ordered by id, name, path, created_at, updated_at, or last_activity_at fields. + * Default is created_at. + * @var string $sort Return projects sorted in asc or desc order (default is desc) + * @var string $search return list of authorized projects matching the search criteria + * @var bool $simple return only the ID, URL, name, and path of each project + * @var bool $owned limit by projects owned by the current user + * @var bool $starred limit by projects starred by the current user + * @var bool $with_issues_enabled Limit by projects with issues feature enabled (default is false) + * @var bool $with_merge_requests_enabled Limit by projects with merge requests feature enabled (default is false) + * @var bool $with_shared Include projects shared to this group (default is true) + * @var bool $include_subgroups Include projects in subgroups of this group (default is false) + * @var bool $with_custom_attributes Include custom attributes in response (admins only). + * @var \DateTimeInterface $last_activity_after Limit by last_activity after specified time + * @var \DateTimeInterface $last_activity_before Limit by last_activity before specified time * } */ public function projects(int|string $id, array $parameters = []): mixed @@ -258,6 +260,9 @@ public function projects(int|string $id, array $parameters = []): mixed $booleanNormalizer = function (Options $resolver, $value): string { return $value ? 'true' : 'false'; }; + $datetimeNormalizer = function (Options $resolver, \DateTimeInterface $value): string { + return $value->format('c'); + }; $resolver->setDefined('archived') ->setAllowedTypes('archived', 'bool') @@ -305,6 +310,14 @@ public function projects(int|string $id, array $parameters = []): mixed ->setAllowedTypes('with_custom_attributes', 'bool') ->setNormalizer('with_custom_attributes', $booleanNormalizer) ; + $resolver->setDefined('last_activity_after') + ->setAllowedTypes('last_activity_after', \DateTimeInterface::class) + ->setNormalizer('last_activity_after', $datetimeNormalizer) + ; + $resolver->setDefined('last_activity_before') + ->setAllowedTypes('last_activity_before', \DateTimeInterface::class) + ->setNormalizer('last_activity_before', $datetimeNormalizer) + ; return $this->get('groups/'.self::encodePath($id).'/projects', $resolver->resolve($parameters)); } diff --git a/src/Api/Projects.php b/src/Api/Projects.php index 1b3f2e51..9effeb46 100644 --- a/src/Api/Projects.php +++ b/src/Api/Projects.php @@ -277,16 +277,18 @@ public function enableRunner(int $project_id, int $runner_id): mixed /** * @param array $parameters { * - * @var string $scope the scope of pipelines, one of: running, pending, finished, branches, tags - * @var string $status the status of pipelines, one of: running, pending, success, failed, canceled, skipped - * @var string $ref the ref of pipelines - * @var string $sha the sha of pipelines - * @var bool $yaml_errors returns pipelines with invalid configurations - * @var string $name the name of the user who triggered pipelines - * @var string $username the username of the user who triggered pipelines - * @var string $order_by order pipelines by id, status, ref, updated_at, or user_id (default: id) - * @var string $order sort pipelines in asc or desc order (default: desc) - * @var string $source the source of the pipeline + * @var string $scope the scope of pipelines, one of: running, pending, finished, branches, tags + * @var string $status the status of pipelines, one of: running, pending, success, failed, canceled, skipped + * @var string $ref the ref of pipelines + * @var string $sha the sha of pipelines + * @var bool $yaml_errors returns pipelines with invalid configurations + * @var string $name the name of the user who triggered pipelines + * @var string $username the username of the user who triggered pipelines + * @var \DateTimeInterface $updated_after Return pipelines updated on or after the given date and time + * @var \DateTimeInterface $updated_before Return pipelines updated on or before the given date and time + * @var string $order_by order pipelines by id, status, ref, updated_at, or user_id (default: id) + * @var string $sort sort pipelines in asc or desc order (default: desc) + * @var string $source the source of the pipeline * } */ public function pipelines(int|string $project_id, array $parameters = []): mixed @@ -296,7 +298,7 @@ public function pipelines(int|string $project_id, array $parameters = []): mixed return $value ? 'true' : 'false'; }; $datetimeNormalizer = function (Options $resolver, \DateTimeInterface $value): string { - return $value->format('Y-m-d'); + return $value->format('c'); }; $resolver->setDefined('scope') @@ -314,12 +316,12 @@ public function pipelines(int|string $project_id, array $parameters = []): mixed $resolver->setDefined('name'); $resolver->setDefined('username'); $resolver->setDefined('updated_after') - ->setAllowedTypes('updated_after', \DateTimeInterface::class) - ->setNormalizer('updated_after', $datetimeNormalizer) + ->setAllowedTypes('updated_after', \DateTimeInterface::class) + ->setNormalizer('updated_after', $datetimeNormalizer) ; $resolver->setDefined('updated_before') - ->setAllowedTypes('updated_before', \DateTimeInterface::class) - ->setNormalizer('updated_before', $datetimeNormalizer) + ->setAllowedTypes('updated_before', \DateTimeInterface::class) + ->setNormalizer('updated_before', $datetimeNormalizer) ; $resolver->setDefined('order_by') ->setAllowedValues('order_by', ['id', 'status', 'ref', 'updated_at', 'user_id']) diff --git a/tests/Api/GroupsTest.php b/tests/Api/GroupsTest.php index 3bd2c7df..6fb9d140 100644 --- a/tests/Api/GroupsTest.php +++ b/tests/Api/GroupsTest.php @@ -663,6 +663,46 @@ public function shouldGetAllGroupProjectsIncludingCustomAttributes(): void $this->assertEquals($expectedArray, $api->projects(1, ['with_custom_attributes' => true])); } + #[Test] + public function shouldGetAllGroupProjectsWithLastActivityAfter(): void + { + $lastActivityAfter = new DateTime('2018-01-01 00:00:00'); + + $expectedArray = [ + ['id' => 1, 'name' => 'A project'], + ['id' => 2, 'name' => 'Another project'], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('groups/1/projects', ['last_activity_after' => $lastActivityAfter->format('c')]) + ->willReturn($expectedArray) + ; + + $this->assertEquals($expectedArray, $api->projects(1, ['last_activity_after' => $lastActivityAfter])); + } + + #[Test] + public function shouldGetAllGroupProjectsWithLastActivityBefore(): void + { + $lastActivityBefore = new DateTime('2018-01-31 00:00:00'); + + $expectedArray = [ + ['id' => 1, 'name' => 'A project'], + ['id' => 2, 'name' => 'Another project'], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('groups/1/projects', ['last_activity_before' => $lastActivityBefore->format('c')]) + ->willReturn($expectedArray) + ; + + $this->assertEquals($expectedArray, $api->projects(1, ['last_activity_before' => $lastActivityBefore])); + } + #[Test] public function shouldGetIterations(): void { diff --git a/tests/Api/ProjectsTest.php b/tests/Api/ProjectsTest.php index 3a102a4e..3599b749 100644 --- a/tests/Api/ProjectsTest.php +++ b/tests/Api/ProjectsTest.php @@ -761,12 +761,12 @@ public function shouldGetPipelineWithDateParam(): void ['id' => 3, 'status' => 'pending', 'ref' => 'test-pipeline'], ]; - $updated_after = new DateTime('2018-01-01 00:00:00'); - $updated_before = new DateTime('2018-01-31 00:00:00'); + $updatedAfter = new DateTime('2018-01-01 00:00:00'); + $updatedBefore = new DateTime('2018-01-31 00:00:00'); $expectedWithArray = [ - 'updated_after' => $updated_after->format('Y-m-d'), - 'updated_before' => $updated_before->format('Y-m-d'), + 'updated_after' => $updatedAfter->format('c'), + 'updated_before' => $updatedBefore->format('c'), ]; $api = $this->getApiMock(); @@ -776,8 +776,8 @@ public function shouldGetPipelineWithDateParam(): void ->willReturn($expectedArray); $this->assertEquals($expectedArray, $api->pipelines(1, [ - 'updated_after' => $updated_after, - 'updated_before' => $updated_before, + 'updated_after' => $updatedAfter, + 'updated_before' => $updatedBefore, ])); } From d0a15b6ea643a1feb6f1aaf5f400f5301d3d2e8c Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Wed, 6 May 2026 14:18:05 +0000 Subject: [PATCH 2/2] Apply fixes from StyleCI --- src/Api/Groups.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Api/Groups.php b/src/Api/Groups.php index 6351b92f..b2131c36 100644 --- a/src/Api/Groups.php +++ b/src/Api/Groups.php @@ -249,7 +249,7 @@ public function removeMember(int|string $group_id, int $user_id): mixed * @var bool $with_merge_requests_enabled Limit by projects with merge requests feature enabled (default is false) * @var bool $with_shared Include projects shared to this group (default is true) * @var bool $include_subgroups Include projects in subgroups of this group (default is false) - * @var bool $with_custom_attributes Include custom attributes in response (admins only). + * @var bool $with_custom_attributes include custom attributes in response (admins only) * @var \DateTimeInterface $last_activity_after Limit by last_activity after specified time * @var \DateTimeInterface $last_activity_before Limit by last_activity before specified time * }