Skip to content

Commit 89eef50

Browse files
macbookandrewIAL32
andauthored
[11.13] Add support for Advanced Search API (#783)
* [11.8] Added search API * Fixed lint issues * Fixed last issue with Search API * remove pagination parameters https://github.com/GitLabPHP/Client/pull/696/files#r857165665 * mark required properties * add state parameter * add newer scopes * add search endpoint to groups and projects * add missing namespaces * fix code style --------- Co-authored-by: Adrian David Castro Tenemaya <adrian.castro@tum.de>
1 parent b3244ef commit 89eef50

File tree

7 files changed

+309
-0
lines changed

7 files changed

+309
-0
lines changed

src/Api/Groups.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
namespace Gitlab\Api;
1616

17+
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
18+
use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException;
1719
use Symfony\Component\OptionsResolver\Options;
1820
use Symfony\Component\OptionsResolver\OptionsResolver;
1921

@@ -979,4 +981,55 @@ public function deleteDeployToken($group_id, int $token_id)
979981
{
980982
return $this->delete('groups/'.self::encodePath($group_id).'/deploy_tokens/'.self::encodePath($token_id));
981983
}
984+
985+
/**
986+
* @param int|string $id
987+
* @param array $parameters {
988+
*
989+
* @var string $scope The scope to search in
990+
* @var string $search The search query
991+
* @var string $state Filter by state. Issues and merge requests are supported; it is ignored for other scopes.
992+
* @var bool $confidential Filter by confidentiality. Issues scope is supported; it is ignored for other scopes.
993+
* @var string $order_by Allowed values are created_at only. If this is not set, the results are either sorted by created_at in descending order for basic search, or by the most relevant documents when using advanced search.
994+
* @var string $sort Return projects sorted in asc or desc order (default is desc)
995+
* }
996+
*
997+
* @throws UndefinedOptionsException If an option name is undefined
998+
* @throws InvalidOptionsException If an option doesn't fulfill the
999+
* specified validation rules
1000+
*
1001+
* @return mixed
1002+
*/
1003+
public function search($id, array $parameters = [])
1004+
{
1005+
$resolver = $this->createOptionsResolver();
1006+
$booleanNormalizer = function (Options $resolver, $value): string {
1007+
return $value ? 'true' : 'false';
1008+
};
1009+
$resolver->setDefined('confidential')
1010+
->setAllowedTypes('confidential', 'bool')
1011+
->setNormalizer('confidential', $booleanNormalizer);
1012+
$scope = [
1013+
'issues',
1014+
'merge_requests',
1015+
'milestones',
1016+
'projects',
1017+
'users',
1018+
'blobs',
1019+
'commits',
1020+
'notes',
1021+
'wiki_blobs',
1022+
];
1023+
$resolver->setRequired('scope')
1024+
->setAllowedValues('scope', $scope);
1025+
$resolver->setRequired('search');
1026+
$resolver->setDefined('order_by')
1027+
->setAllowedValues('order_by', ['created_at']);
1028+
$resolver->setDefined('sort')
1029+
->setAllowedValues('sort', ['asc', 'desc']);
1030+
$resolver->setDefined('state')
1031+
->setAllowedValues('state', ['opened', 'closed']);
1032+
1033+
return $this->get('groups/'.self::encodePath($id).'/search', $resolver->resolve($parameters));
1034+
}
9821035
}

src/Api/Projects.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1781,4 +1781,57 @@ public function deleteProtectedTag($project_id, string $tag_name)
17811781
{
17821782
return $this->delete($this->getProjectPath($project_id, 'protected_tags/'.self::encodePath($tag_name)));
17831783
}
1784+
1785+
/**
1786+
* @param int|string $id
1787+
* @param array $parameters {
1788+
*
1789+
* @var string $scope The scope to search in
1790+
* @var string $search The search query
1791+
* @var string $state Filter by state. Issues and merge requests are supported; it is ignored for other scopes.
1792+
* @var string $ref The name of a repository branch or tag to search on. The project’s default branch is used by default. Applicable only for scopes blobs, commits, and wiki_blobs.
1793+
* @var bool $confidential Filter by confidentiality. Issues scope is supported; it is ignored for other scopes.
1794+
* @var string $order_by Allowed values are created_at only. If this is not set, the results are either sorted by created_at in descending order for basic search, or by the most relevant documents when using advanced search.
1795+
* @var string $sort Return projects sorted in asc or desc order (default is desc)
1796+
* }
1797+
*
1798+
* @throws UndefinedOptionsException If an option name is undefined
1799+
* @throws InvalidOptionsException If an option doesn't fulfill the
1800+
* specified validation rules
1801+
*
1802+
* @return mixed
1803+
*/
1804+
public function search($id, array $parameters = [])
1805+
{
1806+
$resolver = $this->createOptionsResolver();
1807+
$booleanNormalizer = function (Options $resolver, $value): string {
1808+
return $value ? 'true' : 'false';
1809+
};
1810+
$resolver->setDefined('confidential')
1811+
->setAllowedTypes('confidential', 'bool')
1812+
->setNormalizer('confidential', $booleanNormalizer);
1813+
$scope = [
1814+
'blobs',
1815+
'commits',
1816+
'issues',
1817+
'merge_requests',
1818+
'milestones',
1819+
'notes',
1820+
'users',
1821+
'wiki_blobs',
1822+
];
1823+
$resolver->setRequired('scope')
1824+
->setAllowedValues('scope', $scope);
1825+
$resolver->setRequired('search');
1826+
$resolver->setDefined('ref')
1827+
->setAllowedTypes('ref', 'string');
1828+
$resolver->setDefined('order_by')
1829+
->setAllowedValues('order_by', ['created_at']);
1830+
$resolver->setDefined('sort')
1831+
->setAllowedValues('sort', ['asc', 'desc']);
1832+
$resolver->setDefined('state')
1833+
->setAllowedValues('state', ['opened', 'closed']);
1834+
1835+
return $this->get('projects/'.self::encodePath($id).'/search', $resolver->resolve($parameters));
1836+
}
17841837
}

src/Api/Search.php

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Gitlab API library.
7+
*
8+
* (c) Matt Humphrey <matth@windsor-telecom.co.uk>
9+
* (c) Graham Campbell <graham@alt-three.com>
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
namespace Gitlab\Api;
16+
17+
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
18+
use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException;
19+
use Symfony\Component\OptionsResolver\Options;
20+
21+
class Search extends AbstractApi
22+
{
23+
/**
24+
* @param array $parameters {
25+
*
26+
* @var string $scope The scope to search in
27+
* @var string $search The search query
28+
* @var string $state Filter by state. Issues and merge requests are supported; it is ignored for other scopes.
29+
* @var bool $confidential Filter by confidentiality. Issues scope is supported; it is ignored for other scopes.
30+
* @var string $order_by Allowed values are created_at only. If this is not set, the results are either sorted by created_at in descending order for basic search, or by the most relevant documents when using advanced search.
31+
* @var string $sort Return projects sorted in asc or desc order (default is desc)
32+
* }
33+
*
34+
* @throws UndefinedOptionsException If an option name is undefined
35+
* @throws InvalidOptionsException If an option doesn't fulfill the
36+
* specified validation rules
37+
*
38+
* @return mixed
39+
*/
40+
public function all(array $parameters = [])
41+
{
42+
$resolver = $this->createOptionsResolver();
43+
$booleanNormalizer = function (Options $resolver, $value): string {
44+
return $value ? 'true' : 'false';
45+
};
46+
$resolver->setDefined('confidential')
47+
->setAllowedTypes('confidential', 'bool')
48+
->setNormalizer('confidential', $booleanNormalizer);
49+
$scope = [
50+
'projects',
51+
'issues',
52+
'merge_requests',
53+
'milestones',
54+
'snippet_titles',
55+
'wiki_blobs',
56+
'commits',
57+
'blobs',
58+
'notes',
59+
'users',
60+
];
61+
$resolver->setRequired('scope')
62+
->setAllowedValues('scope', $scope);
63+
$resolver->setRequired('search');
64+
$resolver->setDefined('order_by')
65+
->setAllowedValues('order_by', ['created_at']);
66+
$resolver->setDefined('sort')
67+
->setAllowedValues('sort', ['asc', 'desc']);
68+
$resolver->setDefined('state')
69+
->setAllowedValues('state', ['opened', 'closed']);
70+
71+
return $this->get('search', $resolver->resolve($parameters));
72+
}
73+
}

src/Client.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
use Gitlab\Api\ResourceStateEvents;
4141
use Gitlab\Api\ResourceWeightEvents;
4242
use Gitlab\Api\Schedules;
43+
use Gitlab\Api\Search;
4344
use Gitlab\Api\Snippets;
4445
use Gitlab\Api\SystemHooks;
4546
use Gitlab\Api\Tags;
@@ -351,6 +352,14 @@ public function repositoryFiles(): RepositoryFiles
351352
return new RepositoryFiles($this);
352353
}
353354

355+
/**
356+
* @return Search
357+
*/
358+
public function search(): Search
359+
{
360+
return new Search($this);
361+
}
362+
354363
/**
355364
* @return Schedules
356365
*/

tests/Api/GroupsTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,4 +940,36 @@ public function shouldDeleteDeployToken(): void
940940

941941
$this->assertEquals($expectedBool, $api->deleteDeployToken(1, 2));
942942
}
943+
944+
/**
945+
* @test
946+
*/
947+
public function shouldSearchGroups(): void
948+
{
949+
$expectedArray = [
950+
['id' => 6, 'name' => 'Project 6 bla'],
951+
['id' => 7, 'name' => 'Project 7 bla'],
952+
['id' => 8, 'name' => 'Project 8 bla'],
953+
];
954+
955+
$api = $this->getApiMock();
956+
$api->expects($this->once())
957+
->method('get')
958+
->with('groups/123/search', [
959+
'scope' => 'projects',
960+
'confidential' => 'false',
961+
'search' => 'bla',
962+
'order_by' => 'created_at',
963+
'sort' => 'desc',
964+
])
965+
->will($this->returnValue($expectedArray));
966+
967+
$this->assertEquals($expectedArray, $api->search(123, [
968+
'scope' => 'projects',
969+
'confidential' => false,
970+
'search' => 'bla',
971+
'order_by' => 'created_at',
972+
'sort' => 'desc',
973+
]));
974+
}
943975
}

tests/Api/ProjectsTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3017,4 +3017,36 @@ protected function getApiClass()
30173017
{
30183018
return Projects::class;
30193019
}
3020+
3021+
/**
3022+
* @test
3023+
*/
3024+
public function shouldSearchGroups(): void
3025+
{
3026+
$expectedArray = [
3027+
['id' => 6, 'title' => 'Issue 6 bla'],
3028+
['id' => 7, 'title' => 'Issue 7 bla'],
3029+
['id' => 8, 'title' => 'Issue 8 bla'],
3030+
];
3031+
3032+
$api = $this->getApiMock();
3033+
$api->expects($this->once())
3034+
->method('get')
3035+
->with('projects/123/search', [
3036+
'scope' => 'issues',
3037+
'confidential' => 'false',
3038+
'search' => 'bla',
3039+
'order_by' => 'created_at',
3040+
'sort' => 'desc',
3041+
])
3042+
->will($this->returnValue($expectedArray));
3043+
3044+
$this->assertEquals($expectedArray, $api->search(123, [
3045+
'scope' => 'issues',
3046+
'confidential' => false,
3047+
'search' => 'bla',
3048+
'order_by' => 'created_at',
3049+
'sort' => 'desc',
3050+
]));
3051+
}
30203052
}

tests/Api/SearchTest.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Gitlab API library.
7+
*
8+
* (c) Matt Humphrey <matth@windsor-telecom.co.uk>
9+
* (c) Graham Campbell <hello@gjcampbell.co.uk>
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
namespace Gitlab\Tests\Api;
16+
17+
use Gitlab\Api\Search;
18+
19+
class SearchTest extends TestCase
20+
{
21+
/**
22+
* @test
23+
*/
24+
public function shouldGetAll(): void
25+
{
26+
$expectedArray = [
27+
['id' => 6, 'name' => 'Project 6 bla'],
28+
['id' => 7, 'name' => 'Project 7 bla'],
29+
['id' => 8, 'name' => 'Project 8 bla'],
30+
];
31+
32+
$api = $this->getApiMock();
33+
$api->expects($this->once())
34+
->method('get')
35+
->with('search', [
36+
'scope' => 'projects',
37+
'confidential' => 'false',
38+
'search' => 'bla',
39+
'order_by' => 'created_at',
40+
'sort' => 'desc',
41+
])
42+
->will($this->returnValue($expectedArray));
43+
44+
$this->assertEquals($expectedArray, $api->all([
45+
'scope' => 'projects',
46+
'confidential' => false,
47+
'search' => 'bla',
48+
'order_by' => 'created_at',
49+
'sort' => 'desc',
50+
]));
51+
}
52+
53+
protected function getApiClass()
54+
{
55+
return Search::class;
56+
}
57+
}

0 commit comments

Comments
 (0)