diff --git a/src/Api/GroupsEpics.php b/src/Api/GroupsEpics.php new file mode 100644 index 00000000..44df13ae --- /dev/null +++ b/src/Api/GroupsEpics.php @@ -0,0 +1,101 @@ + + * (c) Graham Campbell + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Gitlab\Api; + +class GroupsEpics extends AbstractApi +{ + /** + * @var string + */ + public const STATE_ACTIVE = 'active'; + + /** + * @var string + */ + public const STATE_CLOSED = 'closed'; + + /** + * @param int|string $group_id + * @param array $parameters { + * + * @var int[] $iids return only the epics having the given iids + * @var string $state return only active or closed epics + * @var string $search Return only epics with a title or description matching the provided string. + * } + * + * @return mixed + */ + public function all($group_id, array $parameters = []) + { + $resolver = $this->createOptionsResolver(); + $resolver->setDefined('iids') + ->setAllowedTypes('iids', 'array') + ->setAllowedValues('iids', function (array $value) { + return \count($value) === \count(\array_filter($value, 'is_int')); + }) + ; + $resolver->setDefined('state') + ->setAllowedValues('state', [self::STATE_ACTIVE, self::STATE_CLOSED]) + ; + $resolver->setDefined('search'); + + return $this->get('groups/'.self::encodePath($group_id).'/epics', $resolver->resolve($parameters)); + } + + /** + * @param int|string $group_id + * @param int $epic_id + * + * @return mixed + */ + public function show($group_id, int $epic_id) + { + return $this->get('groups/'.self::encodePath($group_id).'/epics/'.self::encodePath($epic_id)); + } + + /** + * @param int|string $group_id + * @param array $params + * + * @return mixed + */ + public function create($group_id, array $params) + { + return $this->post('groups/'.self::encodePath($group_id).'/epics', $params); + } + + /** + * @param int|string $group_id + * @param int $epic_id + * @param array $params + * + * @return mixed + */ + public function update($group_id, int $epic_id, array $params) + { + return $this->put('groups/'.self::encodePath($group_id).'/epics/'.self::encodePath($epic_id), $params); + } + + /** + * @param int|string $group_id + * @param int $epic_id + * + * @return mixed + */ + public function remove($group_id, int $epic_id) + { + return $this->delete('groups/'.self::encodePath($group_id).'/epics/'.self::encodePath($epic_id)); + } +} diff --git a/src/Client.php b/src/Client.php index d788d931..242b5b61 100644 --- a/src/Client.php +++ b/src/Client.php @@ -19,6 +19,7 @@ use Gitlab\Api\Environments; use Gitlab\Api\Groups; use Gitlab\Api\GroupsBoards; +use Gitlab\Api\GroupsEpics; use Gitlab\Api\GroupsMilestones; use Gitlab\Api\IssueBoards; use Gitlab\Api\IssueLinks; @@ -177,6 +178,14 @@ public function groupsBoards(): GroupsBoards return new GroupsBoards($this); } + /** + * @return GroupsEpics + */ + public function groupsEpics(): GroupsEpics + { + return new GroupsEpics($this); + } + /** * @return GroupsMilestones */ diff --git a/tests/Api/GroupsEpicsTest.php b/tests/Api/GroupsEpicsTest.php new file mode 100644 index 00000000..84f263f1 --- /dev/null +++ b/tests/Api/GroupsEpicsTest.php @@ -0,0 +1,113 @@ + + * (c) Graham Campbell + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Gitlab\Tests\Api; + +use Gitlab\Api\GroupsEpics; + +class GroupsEpicsTest extends TestCase +{ + /** + * @test + */ + public function shouldGetAllEpics(): void + { + $expectedArray = [ + ['id' => 1, 'title' => 'A epic'], + ['id' => 2, 'title' => 'Another epic'], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('groups/1/epics') + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->all(1)); + } + + /** + * @test + */ + public function shouldShowEpic(): void + { + $expectedArray = ['id' => 1, 'name' => 'A epic']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('groups/1/epics/2') + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->show(1, 2)); + } + + /** + * @test + */ + public function shouldCreateEpic(): void + { + $expectedArray = ['id' => 3, 'title' => 'A new epic']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('groups/1/epics', ['description' => 'Some text', 'title' => 'A new epic']) + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->create(1, ['description' => 'Some text', 'title' => 'A new epic'])); + } + + /** + * @test + */ + public function shouldUpdateEpic(): void + { + $expectedArray = ['id' => 3, 'title' => 'Updated epic']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('put') + ->with('groups/1/epics/3', ['title' => 'Updated epic', 'description' => 'Updated description', 'state_event' => 'close']) + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->update(1, 3, ['title' => 'Updated epic', 'description' => 'Updated description', 'state_event' => 'close'])); + } + + /** + * @test + */ + public function shouldRemoveEpic(): void + { + $expectedBool = true; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('groups/1/epics/2') + ->will($this->returnValue($expectedBool)) + ; + + $this->assertEquals($expectedBool, $api->remove(1, 2)); + } + + protected function getApiClass() + { + return GroupsEpics::class; + } +}