diff --git a/src/Api/Deployments.php b/src/Api/Deployments.php index 3770bf9d..27c42637 100644 --- a/src/Api/Deployments.php +++ b/src/Api/Deployments.php @@ -14,12 +14,14 @@ namespace Gitlab\Api; +use Symfony\Component\OptionsResolver\Options; + class Deployments extends AbstractApi { /** * @param array $parameters { * - * @var string $order_by Return deployments ordered by id, iid, created_at, updated_at, + * @var string $order_by Return deployments ordered by id, iid, created_at, updated_at, finished_at, * or ref fields (default is id) * @var string $sort Return deployments sorted in asc or desc order (default is desc) * @var string $status Return deployments filtered by status of deployment allowed @@ -31,17 +33,51 @@ class Deployments extends AbstractApi public function all(int|string $project_id, array $parameters = []): mixed { $resolver = $this->createOptionsResolver(); + + $datetimeNormalizer = function (Options $resolver, \DateTimeInterface $value): string { + $utc = (new \DateTimeImmutable($value->format(\DateTimeImmutable::RFC3339_EXTENDED)))->setTimezone(new \DateTimeZone('UTC')); + + return $utc->format('Y-m-d\TH:i:s.v\Z'); + }; + $resolver->setDefined('order_by') ->setAllowedTypes('order_by', 'string') - ->setAllowedValues('order_by', ['id', 'iid', 'created_at', 'updated_at', 'ref']); + ->setAllowedValues('order_by', ['id', 'iid', 'created_at', 'updated_at', 'finished_at', 'ref']) + ; + $resolver->setDefined('sort') ->setAllowedTypes('sort', 'string') - ->setAllowedValues('sort', ['desc', 'asc']); + ->setAllowedValues('sort', ['asc', 'desc']) + ; + + $resolver->setDefined('updated_after') + ->setAllowedTypes('updated_after', \DateTimeInterface::class) + ->setNormalizer('updated_after', $datetimeNormalizer) + ; + + $resolver->setDefined('updated_before') + ->setAllowedTypes('updated_before', \DateTimeInterface::class) + ->setNormalizer('updated_before', $datetimeNormalizer) + ; + + $resolver->setDefined('finished_after') + ->setAllowedTypes('finished_after', \DateTimeInterface::class) + ->setNormalizer('finished_after', $datetimeNormalizer) + ; + + $resolver->setDefined('finished_before') + ->setAllowedTypes('finished_before', \DateTimeInterface::class) + ->setNormalizer('finished_before', $datetimeNormalizer) + ; + + $resolver->setDefined('environment') + ->setAllowedTypes('environment', 'string') + ; + $resolver->setDefined('status') ->setAllowedTypes('status', 'string') - ->setAllowedValues('status', ['created', 'running', 'success', 'failed', 'canceled', 'blocked']); - $resolver->setDefined('environment') - ->setAllowedTypes('environment', 'string'); + ->setAllowedValues('status', ['created', 'running', 'success', 'failed', 'canceled', 'blocked']) + ; return $this->get($this->getProjectPath($project_id, 'deployments'), $resolver->resolve($parameters)); } diff --git a/src/Api/Projects.php b/src/Api/Projects.php index 32aa168a..19996059 100644 --- a/src/Api/Projects.php +++ b/src/Api/Projects.php @@ -968,7 +968,9 @@ public function deployments(int|string $project_id, array $parameters = []): mix $resolver = $this->createOptionsResolver(); $datetimeNormalizer = function (Options $resolver, \DateTimeInterface $value): string { - return $value->format('c'); + $utc = (new \DateTimeImmutable($value->format(\DateTimeImmutable::RFC3339_EXTENDED)))->setTimezone(new \DateTimeZone('UTC')); + + return $utc->format('Y-m-d\TH:i:s.v\Z'); }; $resolver->setDefined('order_by') diff --git a/tests/Api/DeploymentsTest.php b/tests/Api/DeploymentsTest.php index d6859206..3f370742 100644 --- a/tests/Api/DeploymentsTest.php +++ b/tests/Api/DeploymentsTest.php @@ -323,4 +323,25 @@ public function shouldAllowEmptyArrayIfAllExcludedByFilter(): void $this->assertEquals([], $api->all(1, ['environment' => 'test']) ); } + + #[Test] + public function shouldAllowFilterByUpdateAfter(): void + { + $expectedArray = $this->getMultipleDeploymentsData(); + + $dateTime = new \DateTime(); + $utc = (new \DateTimeImmutable($dateTime->format(\DateTimeImmutable::RFC3339_EXTENDED))) + ->setTimezone(new \DateTimeZone('UTC')); + + $api = $this->getMultipleDeploymentsRequestMock( + 'projects/1/deployments', + $expectedArray, + ['updated_after' => $utc->format('Y-m-d\TH:i:s.v\Z')] + ); + + $this->assertEquals( + $expectedArray, + $api->all(1, ['updated_after' => $dateTime]) + ); + } } diff --git a/tests/Api/ProjectsTest.php b/tests/Api/ProjectsTest.php index 62b5dfcc..9c12faed 100644 --- a/tests/Api/ProjectsTest.php +++ b/tests/Api/ProjectsTest.php @@ -2225,17 +2225,19 @@ public function shouldGetDeploymentsFiltered(): void ['id' => 3, 'sha' => '0000003'], ]; - $time = new DateTime('now'); + $dateTime = new DateTime(); + $utc = (new \DateTimeImmutable($dateTime->format(\DateTimeImmutable::RFC3339_EXTENDED))) + ->setTimezone(new \DateTimeZone('UTC')); $api = $this->getApiMock(); $api->expects($this->once()) ->method('get') ->with('projects/1/deployments', [ - 'updated_after' => $time->format('c'), + 'updated_after' => $utc->format('Y-m-d\TH:i:s.v\Z'), ]) ->willReturn($expectedArray); - $this->assertEquals($expectedArray, $api->deployments(1, ['updated_after' => $time])); + $this->assertEquals($expectedArray, $api->deployments(1, ['updated_after' => $dateTime])); } protected function getMultipleProjectsData(): array