Skip to content

Commit ea1b976

Browse files
authored
Merge pull request #221 from fbourigault/v4-api-8793
Update MergeRequestsApi for V4 compatibility
2 parents 324000b + e6311d8 commit ea1b976

File tree

6 files changed

+246
-230
lines changed

6 files changed

+246
-230
lines changed

UPGRADE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ See [documentation](doc/customize.md) to know how to customize the client timeou
2323
* The second argument of `update`, `remove`, `showComments`, `showComment`, `addComment`, `updateComment`, `removeComment`,
2424
`setTimeEstimate`, `resetTimeEstimate`, `addSpentTime` and `resetSpentTime` methods is now a scoped issue id (iid).
2525

26+
## `Gitlab\Api\MergeRequests` changes
27+
28+
* The `getList`, `getByIid`, `merged`, `opened` and `closed` methods have been removed. Use `all` method instead.
29+
* The `ORDER_BY` and `SORT` class constants have been removed.
30+
* The `all` method now take a single argument which is an associative array of query string parameters.
31+
* The `getNotes` method now take only two arguments, the project id and the merge request iid.
32+
2633
## `Gitlab\Api\Projects` changes
2734

2835
* The `keys`, `key`, `addKey`, `removeKey`, `disableKey` and `enableKey` methods have been removed.

lib/Gitlab/Api/AbstractApi.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
<?php namespace Gitlab\Api;
22

33
use Gitlab\Client;
4+
use Gitlab\HttpClient\Message\QueryStringBuilder;
45
use Gitlab\HttpClient\Message\ResponseMediator;
6+
use Gitlab\Tests\HttpClient\Message\QueryStringBuilderTest;
57
use Http\Discovery\StreamFactoryDiscovery;
68
use Http\Message\MultipartStream\MultipartStreamBuilder;
79
use Http\Message\StreamFactory;
@@ -216,8 +218,9 @@ protected function createOptionsResolver()
216218

217219
private function preparePath($path, array $parameters = [])
218220
{
221+
219222
if (count($parameters) > 0) {
220-
$path .= '?'.http_build_query($parameters);
223+
$path .= '?'.QueryStringBuilder::build($parameters);
221224
}
222225

223226
return $path;

lib/Gitlab/Api/MergeRequests.php

Lines changed: 69 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,71 @@
11
<?php namespace Gitlab\Api;
22

3+
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
4+
use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException;
5+
36
class MergeRequests extends AbstractApi
47
{
58
const STATE_ALL = 'all';
69
const STATE_MERGED = 'merged';
710
const STATE_OPENED = 'opened';
811
const STATE_CLOSED = 'closed';
912

10-
const ORDER_BY = 'created_at';
11-
const SORT = 'asc';
12-
13-
/**
14-
* @param int $project_id
15-
* @param string $state
16-
* @param int $page
17-
* @param int $per_page
18-
* @param string $order_by
19-
* @param string $sort
20-
* @param string $object
21-
* @return mixed
22-
*/
23-
public function getList($project_id, $state = self::STATE_ALL, $page = 1, $per_page = self::PER_PAGE, $order_by = self::ORDER_BY, $sort = self::SORT, $object = 'merge_requests')
24-
{
25-
return $this->get($this->getProjectPath($project_id, $object), array(
26-
'page' => $page,
27-
'per_page' => $per_page,
28-
'state' => $state,
29-
'order_by' => $order_by,
30-
'sort' => $sort
31-
));
32-
}
33-
3413
/**
35-
* @param int $project_id
36-
* @param int $page
37-
* @param int $per_page
38-
* @param string $order_by
39-
* @param string $sort
40-
* @return mixed
41-
*/
42-
public function all($project_id, $page = 1, $per_page = self::PER_PAGE, $order_by = self::ORDER_BY, $sort = self::SORT)
43-
{
44-
return $this->getList($project_id, self::STATE_ALL, $page, $per_page, $order_by, $sort);
45-
}
46-
47-
/**
48-
* @param int $project_id
49-
* @param int $page
50-
* @param int $per_page
51-
* @param string $order_by
52-
* @param string $sort
53-
* @return mixed
54-
*/
55-
public function merged($project_id, $page = 1, $per_page = self::PER_PAGE, $order_by = self::ORDER_BY, $sort = self::SORT)
56-
{
57-
return $this->getList($project_id, self::STATE_MERGED, $page, $per_page, $order_by, $sort);
58-
}
59-
60-
/**
61-
* @param int $project_id
62-
* @param int $page
63-
* @param int $per_page
64-
* @param string $order_by
65-
* @param string $sort
66-
* @return mixed
67-
*/
68-
public function opened($project_id, $page = 1, $per_page = self::PER_PAGE, $order_by = self::ORDER_BY, $sort = self::SORT)
69-
{
70-
return $this->getList($project_id, self::STATE_OPENED, $page, $per_page, $order_by, $sort);
71-
}
72-
73-
/**
74-
* @param int $project_id
75-
* @param int $page
76-
* @param int $per_page
77-
* @param string $order_by
78-
* @param string $sort
14+
* @param int $project_id
15+
* @param array $parameters {
16+
*
17+
* @var int[] $iids Return the request having the given iid.
18+
* @var string $state Return all merge requests or just those that are opened, closed, or
19+
* merged.
20+
* @var string $order_by Return requests ordered by created_at or updated_at fields. Default
21+
* is created_at.
22+
* @var string $sort Return requests sorted in asc or desc order. Default is desc.
23+
* @var string $milestone Return merge requests for a specific milestone.
24+
* @var string $view If simple, returns the iid, URL, title, description, and basic state
25+
* of merge request.
26+
* @var string $labels Return merge requests matching a comma separated list of labels.
27+
* @var \DateTimeInterface $created_after Return merge requests created after the given time (inclusive).
28+
* @var \DateTimeInterface $created_before Return merge requests created before the given time (inclusive).
29+
* }
30+
*
31+
* @throws UndefinedOptionsException If an option name is undefined.
32+
* @throws InvalidOptionsException If an option doesn't fulfill the specified validation rules.
33+
*
7934
* @return mixed
8035
*/
81-
public function closed($project_id, $page = 1, $per_page = self::PER_PAGE, $order_by = self::ORDER_BY, $sort = self::SORT)
82-
{
83-
return $this->getList($project_id, self::STATE_CLOSED, $page, $per_page, $order_by, $sort);
36+
public function all($project_id, array $parameters = [])
37+
{
38+
$resolver = $this->createOptionsResolver();
39+
$datetimeNormalizer = function (\DateTimeInterface $value) {
40+
return $value->format('c');
41+
};
42+
$resolver->setDefined('iids')
43+
->setAllowedTypes('iids', 'array')
44+
->setAllowedValues('iids', function (array $value) {
45+
return count($value) == count(array_filter($value, 'is_int'));
46+
})
47+
;
48+
$resolver->setDefined('state')
49+
->setAllowedValues('state', ['all', 'opened', 'merged', 'closed'])
50+
;
51+
$resolver->setDefined('order_by')
52+
->setAllowedValues('order_by', ['created_at', 'updated_at'])
53+
;
54+
$resolver->setDefined('milestone');
55+
$resolver->setDefined('view')
56+
->setAllowedValues('view', ['simple'])
57+
;
58+
$resolver->setDefined('labels');
59+
$resolver->setDefined('created_after')
60+
->setAllowedTypes('created_after', \DateTimeInterface::class)
61+
->setNormalizer('created_after', $datetimeNormalizer)
62+
;
63+
$resolver->setDefined('created_before')
64+
->setAllowedTypes('created_before', \DateTimeInterface::class)
65+
->setNormalizer('created_before', $datetimeNormalizer)
66+
;
67+
68+
return $this->get($this->getProjectPath($project_id, 'merge_requests'), $resolver->resolve($parameters));
8469
}
8570

8671
/**
@@ -90,7 +75,7 @@ public function closed($project_id, $page = 1, $per_page = self::PER_PAGE, $orde
9075
*/
9176
public function show($project_id, $mr_id)
9277
{
93-
return $this->get($this->getProjectPath($project_id, 'merge_request/'.$this->encodePath($mr_id)));
78+
return $this->get($this->getProjectPath($project_id, 'merge_requests/'.$this->encodePath($mr_id)));
9479
}
9580

9681
/**
@@ -123,7 +108,7 @@ public function create($project_id, $source, $target, $title, $assignee = null,
123108
*/
124109
public function update($project_id, $mr_id, array $params)
125110
{
126-
return $this->put($this->getProjectPath($project_id, 'merge_request/'.$this->encodePath($mr_id)), $params);
111+
return $this->put($this->getProjectPath($project_id, 'merge_requests/'.$this->encodePath($mr_id)), $params);
127112
}
128113

129114
/**
@@ -140,17 +125,18 @@ public function merge($project_id, $mr_id, $message = null)
140125
$params = array('merge_commit_message' => $message);
141126
}
142127

143-
return $this->put($this->getProjectPath($project_id, 'merge_request/'.$this->encodePath($mr_id).'/merge'), $params);
128+
return $this->put($this->getProjectPath($project_id, 'merge_requests/'.$this->encodePath($mr_id).'/merge'), $params);
144129
}
145130

146131
/**
147-
* @param int $project_id
148-
* @param int $mr_id
132+
* @param int $project_id
133+
* @param int $mr_id
134+
*
149135
* @return mixed
150136
*/
151-
public function showNotes($project_id, $mr_id, $page = 1, $per_page = self::PER_PAGE, $order_by = self::ORDER_BY, $sort = 'desc')
137+
public function showNotes($project_id, $mr_id)
152138
{
153-
return $this->getList($project_id, null, $page, $per_page, $order_by, $sort, 'merge_requests/'.$this->encodePath($mr_id).'/notes');
139+
return $this->get($this->getProjectPath($project_id, 'merge_requests/'.$this->encodePath($mr_id).'/notes'));
154140
}
155141

156142
/**
@@ -173,7 +159,7 @@ public function addNote($project_id, $mr_id, $note)
173159
*/
174160
public function showComments($project_id, $mr_id)
175161
{
176-
return $this->get($this->getProjectPath($project_id, 'merge_request/'.$this->encodePath($mr_id).'/comments'));
162+
return $this->get($this->getProjectPath($project_id, 'merge_requests/'.$this->encodePath($mr_id).'/comments'));
177163
}
178164

179165
/**
@@ -184,7 +170,7 @@ public function showComments($project_id, $mr_id)
184170
*/
185171
public function addComment($project_id, $mr_id, $note)
186172
{
187-
return $this->post($this->getProjectPath($project_id, 'merge_request/'.$this->encodePath($mr_id).'/comments'), array(
173+
return $this->post($this->getProjectPath($project_id, 'merge_requests/'.$this->encodePath($mr_id).'/comments'), array(
188174
'note' => $note
189175
));
190176
}
@@ -196,17 +182,7 @@ public function addComment($project_id, $mr_id, $note)
196182
*/
197183
public function changes($project_id, $mr_id)
198184
{
199-
return $this->get($this->getProjectPath($project_id, 'merge_request/'.$this->encodePath($mr_id).'/changes'));
200-
}
201-
202-
/**
203-
* @param $project_id
204-
* @param $mr_iid
205-
* @return mixed
206-
*/
207-
public function getByIid($project_id, $mr_iid)
208-
{
209-
return $this->get($this->getProjectPath($project_id, 'merge_requests'), array('iid' => $mr_iid));
185+
return $this->get($this->getProjectPath($project_id, 'merge_requests/'.$this->encodePath($mr_id).'/changes'));
210186
}
211187

212188
/**
@@ -216,7 +192,7 @@ public function getByIid($project_id, $mr_iid)
216192
*/
217193
public function commits($project_id, $mr_id)
218194
{
219-
return $this->get($this->getProjectPath($project_id, 'merge_request/'.$this->encodePath($mr_id).'/commits'));
195+
return $this->get($this->getProjectPath($project_id, 'merge_requests/'.$this->encodePath($mr_id).'/commits'));
220196
}
221197

222198
/**
@@ -226,7 +202,7 @@ public function commits($project_id, $mr_id)
226202
*/
227203
public function closesIssues($project_id, $mr_id)
228204
{
229-
return $this->get($this->getProjectPath($project_id, 'merge_request/'.$this->encodePath($mr_id).'/closes_issues'));
205+
return $this->get($this->getProjectPath($project_id, 'merge_requests/'.$this->encodePath($mr_id).'/closes_issues'));
230206
}
231207

232208
/**
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
namespace Gitlab\HttpClient\Message;
4+
5+
final class QueryStringBuilder
6+
{
7+
/**
8+
* Encode a query as a query string according to RFC 3986. Indexed arrays are encoded using
9+
* empty squared brackets ([]) unlike http_build_query.
10+
*
11+
* @param mixed $query
12+
*
13+
* @return string
14+
*/
15+
public static function build($query)
16+
{
17+
if (!is_array($query)) {
18+
return rawurlencode($query);
19+
}
20+
return implode('&', array_map(function ($value, $key) {
21+
return static::encode($value, $key);
22+
}, $query, array_keys($query)));
23+
}
24+
25+
/**
26+
* Encode a value
27+
* @param mixed $query
28+
* @param string $prefix
29+
*
30+
* @return string
31+
*/
32+
private static function encode($query, $prefix)
33+
{
34+
if (!is_array($query)) {
35+
return rawurlencode($prefix).'='.rawurlencode($query);
36+
}
37+
38+
$isIndexedArray = static::isIndexedArray($query);
39+
return implode('&', array_map(function ($value, $key) use ($prefix, $isIndexedArray) {
40+
$prefix = $isIndexedArray ? $prefix.'[]' : $prefix.'['.$key.']';
41+
return static::encode($value, $prefix);
42+
}, $query, array_keys($query)));
43+
}
44+
45+
/**
46+
* Tell if the given array is an indexed one (i.e. contains only sequential integer keys starting from 0).
47+
*
48+
* @param array $query
49+
*
50+
* @return bool
51+
*/
52+
public static function isIndexedArray(array $query)
53+
{
54+
if (empty($query) || !isset($query[0])) {
55+
return false;
56+
}
57+
58+
return array_keys($query) === range(0, count($query) - 1);
59+
}
60+
}

0 commit comments

Comments
 (0)