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
144 changes: 144 additions & 0 deletions src/Api/Groups.php
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,119 @@ public function subgroups($group_id, array $parameters = [])
return $this->get('groups/'.self::encodePath($group_id).'/subgroups', $resolver->resolve($parameters));
}

/**
* @param int|string $group_id
* @param array $parameters {
*
* @var string $assignee_id Return issues assigned to the given user id. Mutually exclusive with assignee_username.
* None returns unassigned issues. Any returns issues with an assignee.
* @var string $assignee_username Return issues assigned to the given username. Similar to assignee_id and mutually exclusive with assignee_id.
* In GitLab CE, the assignee_username array should only contain a single value. Otherwise, an invalid parameter error is returned.
* @var int $author_id Return issues created by the given user id. Mutually exclusive with author_username.
* Combine with scope=all or scope=assigned_to_me.
* @var string $author_username Return issues created by the given username. Similar to author_id and mutually exclusive with author_id.
* @var bool $confidential Filter confidential or public issues
* @var \DateTimeInterface $created_after Return issues created after the given time (inclusive)
* @var \DateTimeInterface $created_before Return issues created before the given time (inclusive)
* @var int $iteration_id Return issues assigned to the given iteration ID. None returns issues that do not belong to an iteration. Any returns issues that belong to an iteration. Mutually exclusive with iteration_title.
* @var string $iteration_title Return issues assigned to the iteration with the given title. Similar to iteration_id and mutually exclusive with iteration_id.
* @var string $labels Comma-separated list of label names, issues must have all labels to be returned. None lists all issues with no labels. Any lists all issues with at least one label. No+Label (Deprecated) lists all issues with no labels. Predefined names are case-insensitive.
* @var string $milestone The milestone title. None lists all issues with no milestone. Any lists all issues that have an assigned milestone.
* @var string $my_reaction_emoji Return issues reacted by the authenticated user by the given emoji. None returns issues not given a reaction. Any returns issues given at least one reaction.
* @var bool $non_archived Return issues from non archived projects. Default is true.
* @var string $not Return issues that do not match the parameters supplied. Accepts: labels, milestone, author_id, author_username, assignee_id, assignee_username, my_reaction_emoji, search, in
* @var string $order_by Return issues ordered by created_at, updated_at, priority, due_date, relative_position, label_priority, milestone_due, popularity, weight fields. Default is created_at
* @var string $scope Return issues for the given scope: created_by_me, assigned_to_me or all. Defaults to all.
* @var string $search Search group issues against their title and description
* @var string $sort Return issues sorted in asc or desc order. Default is desc
* @var string $state Return all issues or just those that are opened or closed
* @var \DateTimeInterface $updated_after Return issues updated on or after the given time. Expected in ISO 8601 format (2019-03-15T08:00:00Z)
* @var \DateTimeInterface $updated_before Return issues updated on or before the given time. Expected in ISO 8601 format (2019-03-15T08:00:00Z)
* @var int $weight Return issues with the specified weight. None returns issues with no weight assigned. Any returns issues with a weight assigned.
* @var bool $with_labels_details If true, the response returns more details for each label in labels field: :name, :color, :description, :description_html, :text_color. Default is false.
* }
*
* @return mixed
*/
public function issues($group_id, array $parameters = [])
{
$resolver = $this->createOptionsResolver();
$booleanNormalizer = function (Options $resolver, $value): string {
return $value ? 'true' : 'false';
};
$datetimeNormalizer = function (Options $resolver, \DateTimeInterface $value): string {
return $value->format('c');
};

$resolver->setDefined('assignee_id');
$resolver->setDefined('assignee_username')
->setAllowedTypes('assignee_username', 'string');

$resolver->setDefined('author_id');
$resolver->setDefined('author_username')
->setAllowedTypes('author_username', 'string');

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

$resolver->setDefined('created_after')
->setAllowedTypes('created_after', \DateTimeInterface::class)
->setNormalizer('created_after', $datetimeNormalizer);
$resolver->setDefined('created_before')
->setAllowedTypes('created_before', \DateTimeInterface::class)
->setNormalizer('created_before', $datetimeNormalizer);

$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('iteration_id');
$resolver->setDefined('iteration_title')
->setAllowedTypes('iteration_title', 'string');

$resolver->setDefined('labels')
->setAllowedTypes('labels', 'string');

$resolver->setDefined('milestone')
->setAllowedTypes('milestone', 'string');

$resolver->setDefined('my_reaction_emoji')
->setAllowedTypes('my_reaction_emoji', 'string');

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

$resolver->setDefined('not')
->setAllowedTypes('not', 'string');

$resolver->setDefined('order_by')
->setAllowedValues('order_by', ['created_at', 'updated_at']);
$resolver->setDefined('sort')
->setAllowedValues('sort', ['asc', 'desc']);

$resolver->setDefined('scope')
->setAllowedTypes('scope', 'string');

$resolver->setDefined('search')
->setAllowedTypes('search', 'string');

$resolver->setDefined('state')
->setAllowedValues('state', [self::STATE_ALL, self::STATE_OPENED, self::STATE_CLOSED]);

$resolver->setDefined('weight');

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

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

/**
* @param int|string $group_id
* @param array $parameters
Expand Down Expand Up @@ -618,6 +731,37 @@ public function mergeRequests($group_id, array $parameters = [])
return $this->get('groups/'.self::encodePath($group_id).'/merge_requests', $resolver->resolve($parameters));
}

/**
* @param int|string $group_id
* @param array $parameters {
*
* @var string $state Return opened, upcoming, current (previously started), closed, or all iterations.
* Filtering by started state is deprecated starting with 14.1, please use current instead.
* @var string $search return only iterations with a title matching the provided string
* @var bool $include_ancestors Include iterations from parent group and its ancestors. Defaults to true.
* }
*
* @return mixed
*/
public function iterations($group_id, array $parameters = [])
{
$resolver = $this->createOptionsResolver();
$booleanNormalizer = function (Options $resolver, $value): string {
return $value ? 'true' : 'false';
};

$resolver->setDefined('state')
->setAllowedValues('state', ['opened', 'upcoming', 'current', 'current (previously started)', 'closed', 'all'])
;
$resolver->setDefined('include_ancestors')
->setAllowedTypes('include_ancestors', 'bool')
->setNormalizer('include_ancestors', $booleanNormalizer)
->setDefault('include_ancestors', true)
;

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

/**
* @param int|string $group_id
* @param array $parameters {
Expand Down
13 changes: 12 additions & 1 deletion src/Api/Issues.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@ class Issues extends AbstractApi
* @var int[] $iids return only the issues having the given iid
* @var string $order_by return requests ordered by created_at or updated_at fields (default is created_at)
* @var string $sort return requests sorted in asc or desc order (default is desc)
* @var bool $confidential filter confidential or public issues
* @var bool $confidential filter confidential or public issues
* @var string $search search issues against their title and description
* @var int $assignee_id return issues assigned to the specified user id
* @var int $iteration_id return issues assigned to the specified iteration id
* @var string $iteration_title return issues assigned to the specified iteration title
* }
*
* @return mixed
Expand Down Expand Up @@ -465,6 +468,8 @@ protected function createOptionsResolver(): OptionsResolver
;
$resolver->setDefined('labels');
$resolver->setDefined('milestone');
$resolver->setDefined('milestone_id')
->setAllowedTypes('milestone_id', 'integer');
$resolver->setDefined('with_labels_details')
->setAllowedTypes('with_labels_details', 'bool')
->setNormalizer('with_labels_details', $booleanNormalizer)
Expand Down Expand Up @@ -495,6 +500,12 @@ protected function createOptionsResolver(): OptionsResolver
$resolver->setDefined('assignee_id')
->setAllowedTypes('assignee_id', 'integer')
;
$resolver->setDefined('iteration_id')
->setAllowedTypes('iteration_id', 'integer')
;
$resolver->setDefined('iteration_title')
->setAllowedTypes('iteration_title', 'string')
;
$resolver->setDefined('weight')
->setAllowedTypes('weight', 'integer')
;
Expand Down
31 changes: 31 additions & 0 deletions src/Api/Projects.php
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,37 @@ public function boards($project_id)
return $this->get($this->getProjectPath($project_id, 'boards'));
}

/**
* @param int|string $project_id
* @param array $parameters {
*
* @var string $state Return opened, upcoming, current (previously started), closed, or all iterations.
* Filtering by started state is deprecated starting with 14.1, please use current instead.
* @var string $search return only iterations with a title matching the provided string
* @var bool $include_ancestors Include iterations from parent group and its ancestors. Defaults to true.
* }
*
* @return mixed
*/
public function iterations($project_id, array $parameters = [])
{
$resolver = $this->createOptionsResolver();
$booleanNormalizer = function (Options $resolver, $value): string {
return $value ? 'true' : 'false';
};

$resolver->setDefined('state')
->setAllowedValues('state', ['opened', 'upcoming', 'current', 'current (previously started)', 'closed', 'all'])
;
$resolver->setDefined('include_ancestors')
->setAllowedTypes('include_ancestors', 'bool')
->setNormalizer('include_ancestors', $booleanNormalizer)
->setDefault('include_ancestors', true)
;

return $this->get('projects/'.self::encodePath($project_id).'/iterations', $resolver->resolve($parameters));
}

/**
* Gets a list of all discussion items for a single commit.
*
Expand Down
53 changes: 53 additions & 0 deletions tests/Api/GroupsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,27 @@ public function shouldGetAllSubgroups(): void
$this->assertEquals($expectedArray, $api->subgroups(1, ['page' => 1, 'per_page' => 10]));
}

/**
* @test
*/
public function shouldGetAllIssues(): void
{
$expectedArray = [
['id' => 101, 'name' => 'An issue'],
['id' => 102, 'name' => 'Another issue'],
['id' => 103, 'name' => 'A third issue'],
];

$api = $this->getApiMock();
$api->expects($this->once())
->method('get')
->with('groups/1/issues', ['page' => 1, 'per_page' => 10])
->will($this->returnValue($expectedArray))
;

$this->assertEquals($expectedArray, $api->issues(1, ['page' => 1, 'per_page' => 10]));
}

/**
* @test
*/
Expand Down Expand Up @@ -676,6 +697,38 @@ public function shouldGetAllGroupProjectsIncludingCustomAttributes(): void
$this->assertEquals($expectedArray, $api->projects(1, ['with_custom_attributes' => true]));
}

/**
* @test
*/
public function shouldGetIterations(): void
{
$expectedArray = [
[
'id' => 5,
'iid' => 2,
'sequence' => 1,
'group_id' => 123,
'title' => '2022: Sprint 1',
'description' => '',
'state' => 3,
'created_at' => '2021-09-29T21:24:43.913Z',
'updated_at' => '2022-03-29T19:09:08.368Z',
'start_date' => '2022-01-10',
'due_date' => '2022-01-23',
'web_url' => 'https://example.com/groups/example/-/iterations/34',
],
];

$api = $this->getApiMock();
$api->expects($this->once())
->method('get')
->with('groups/1/iterations')
->will($this->returnValue($expectedArray))
;

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

/**
* @test
*/
Expand Down
8 changes: 4 additions & 4 deletions tests/Api/IssuesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ public function shouldGetGroupIssuesWithParams(): void
$api = $this->getApiMock();
$api->expects($this->once())
->method('get')
->with('groups/1/issues', ['order_by' => 'created_at', 'sort' => 'desc', 'labels' => 'foo,bar', 'state' => 'opened'])
->with('groups/1/issues', ['order_by' => 'created_at', 'sort' => 'desc', 'labels' => 'foo,bar', 'state' => 'opened', 'iteration_title' => 'Title', 'assignee_id' => 1])
->will($this->returnValue($expectedArray))
;

$this->assertEquals($expectedArray, $api->group(1, ['order_by' => 'created_at', 'sort' => 'desc', 'labels' => 'foo,bar', 'state' => 'opened']));
$this->assertEquals($expectedArray, $api->group(1, ['order_by' => 'created_at', 'sort' => 'desc', 'labels' => 'foo,bar', 'state' => 'opened', 'iteration_title' => 'Title', 'assignee_id' => 1]));
}

/**
Expand Down Expand Up @@ -131,11 +131,11 @@ public function shouldGetProjectIssuesWithParams(): void
$api = $this->getApiMock();
$api->expects($this->once())
->method('get')
->with('projects/1/issues', ['order_by' => 'created_at', 'sort' => 'desc', 'labels' => 'foo,bar', 'state' => 'opened'])
->with('projects/1/issues', ['order_by' => 'created_at', 'sort' => 'desc', 'labels' => 'foo,bar', 'state' => 'opened', 'iteration_id' => 1, 'assignee_id' => 2])
->will($this->returnValue($expectedArray))
;

$this->assertEquals($expectedArray, $api->all(1, ['order_by' => 'created_at', 'sort' => 'desc', 'labels' => 'foo,bar', 'state' => 'opened']));
$this->assertEquals($expectedArray, $api->all(1, ['order_by' => 'created_at', 'sort' => 'desc', 'labels' => 'foo,bar', 'state' => 'opened', 'iteration_id' => 1, 'assignee_id' => 2]));
}

/**
Expand Down
32 changes: 32 additions & 0 deletions tests/Api/ProjectsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,38 @@ public function getProjectBoardsExpectedArray()
];
}

/**
* @test
*/
public function shouldGetIterations(): void
{
$expectedArray = [
[
'id' => 5,
'iid' => 2,
'sequence' => 1,
'group_id' => 123,
'title' => '2022: Sprint 1',
'description' => '',
'state' => 3,
'created_at' => '2021-09-29T21:24:43.913Z',
'updated_at' => '2022-03-29T19:09:08.368Z',
'start_date' => '2022-01-10',
'due_date' => '2022-01-23',
'web_url' => 'https://example.com/groups/example/-/iterations/34',
],
];

$api = $this->getApiMock();
$api->expects($this->once())
->method('get')
->with('projects/1/iterations')
->will($this->returnValue($expectedArray))
;

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

/**
* @test
*/
Expand Down