Skip to content

Commit 8665629

Browse files
authored
Merge pull request #326 from Art4/add-phpstan
Add phpstan
2 parents 3e2dcb2 + 0c91f76 commit 8665629

File tree

18 files changed

+229
-149
lines changed

18 files changed

+229
-149
lines changed

.github/workflows/tests.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ jobs:
3636
- name: "Install Composer dependencies"
3737
uses: "ramsey/composer-install@v2"
3838

39+
- name: Run static code analysis
40+
if: ${{ matrix.php-versions == '8.2' }}
41+
run: composer run phpstan -- --error-format=github
42+
3943
- name: Run tests
4044
run: vendor/bin/phpunit --coverage-clover .phpunit.cache/clover.xml
4145

.phpstan.neon

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
parameters:
2+
level: 4
3+
4+
paths:
5+
- src/
6+
- tests/
7+
8+
scanDirectories:
9+
- vendor

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
"friendsofphp/php-cs-fixer": "^3",
3333
"phpunit/phpunit": "^9 || 10.2.*",
3434
"guzzlehttp/psr7": "^2",
35-
"php-mock/php-mock-phpunit": "^2.6"
35+
"php-mock/php-mock-phpunit": "^2.6",
36+
"phpstan/phpstan": "^1.10"
3637
},
3738
"autoload": {
3839
"psr-4": {
@@ -46,6 +47,7 @@
4647
},
4748
"scripts": {
4849
"coverage": "phpunit --coverage-html=\".phpunit.cache/code-coverage\"",
50+
"phpstan": "phpstan analyze --memory-limit 512M --configuration .phpstan.neon",
4951
"test": "phpunit"
5052
}
5153
}

src/Redmine/Api/Group.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public function listing($forceUpdate = false)
6363
*
6464
* @throws MissingParameterException Missing mandatory parameters
6565
*
66-
* @return \SimpleXMLElement
66+
* @return string|false
6767
*/
6868
public function create(array $params = [])
6969
{

src/Redmine/Api/Issue.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public function show($id, array $params = [])
7676
*
7777
* @param array $params the new issue data
7878
*
79-
* @return \SimpleXMLElement
79+
* @return string|false
8080
*/
8181
public function create(array $params = [])
8282
{
@@ -174,6 +174,7 @@ public function removeWatcher($id, $watcherUserId)
174174
*/
175175
public function setIssueStatus($id, $status)
176176
{
177+
/** @var IssueStatus */
177178
$api = $this->client->getApi('issue_status');
178179

179180
return $this->update($id, [
@@ -204,31 +205,37 @@ public function addNoteToIssue($id, $note, $privateNote = false)
204205
private function cleanParams(array $params = [])
205206
{
206207
if (isset($params['project'])) {
208+
/** @var Project */
207209
$apiProject = $this->client->getApi('project');
208210
$params['project_id'] = $apiProject->getIdByName($params['project']);
209211
unset($params['project']);
210212
if (isset($params['category'])) {
213+
/** @var IssueCategory */
211214
$apiIssueCategory = $this->client->getApi('issue_category');
212215
$params['category_id'] = $apiIssueCategory->getIdByName($params['project_id'], $params['category']);
213216
unset($params['category']);
214217
}
215218
}
216219
if (isset($params['status'])) {
220+
/** @var IssueStatus */
217221
$apiIssueStatus = $this->client->getApi('issue_status');
218222
$params['status_id'] = $apiIssueStatus->getIdByName($params['status']);
219223
unset($params['status']);
220224
}
221225
if (isset($params['tracker'])) {
226+
/** @var Tracker */
222227
$apiTracker = $this->client->getApi('tracker');
223228
$params['tracker_id'] = $apiTracker->getIdByName($params['tracker']);
224229
unset($params['tracker']);
225230
}
226231
if (isset($params['assigned_to'])) {
232+
/** @var User */
227233
$apiUser = $this->client->getApi('user');
228234
$params['assigned_to_id'] = $apiUser->getIdByUsername($params['assigned_to']);
229235
unset($params['assigned_to']);
230236
}
231237
if (isset($params['author'])) {
238+
/** @var User */
232239
$apiUser = $this->client->getApi('user');
233240
$params['author_id'] = $apiUser->getIdByUsername($params['author']);
234241
unset($params['author']);

src/Redmine/Api/Membership.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public function removeMember($projectId, $userId, array $params = [])
121121
{
122122
$memberships = $this->all($projectId, $params);
123123
if (!isset($memberships['memberships']) || !is_array($memberships['memberships'])) {
124-
return;
124+
return false;
125125
}
126126
$removed = false;
127127
foreach ($memberships['memberships'] as $membership) {

src/Redmine/Api/Project.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public function show($id, array $params = [])
106106
*
107107
* @throws MissingParameterException
108108
*
109-
* @return \SimpleXMLElement
109+
* @return string|false
110110
*/
111111
public function create(array $params = [])
112112
{

src/Redmine/Client/NativeCurlClient.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
namespace Redmine\Client;
66

7-
use Redmine\Api;
87
use Redmine\Exception\ClientException;
98

109
/**
@@ -246,7 +245,9 @@ private function request(string $method, string $path, string $body = ''): bool
246245
/**
247246
* Prepare the request by setting the cURL options.
248247
*
249-
* @return resource a cURL handle on success, <b>FALSE</b> on errors
248+
* BC for PHP 7.4: Do not add the return type because CurlHandle was introduced in PHP 8.0
249+
*
250+
* @return \CurlHandle a cURL handle on success, <b>FALSE</b> on errors
250251
*/
251252
private function createCurl(string $method, string $path, string $body = '')
252253
{
@@ -281,13 +282,13 @@ private function createCurl(string $method, string $path, string $body = '')
281282
$curlOptions[CURLOPT_POSTFIELDS] = $filedata;
282283
$curlOptions[CURLOPT_INFILE] = $file;
283284
$curlOptions[CURLOPT_INFILESIZE] = $size;
284-
} elseif (isset($body)) {
285+
} elseif ($body !== '') {
285286
$curlOptions[CURLOPT_POSTFIELDS] = $body;
286287
}
287288
break;
288289
case 'put':
289290
$curlOptions[CURLOPT_CUSTOMREQUEST] = 'PUT';
290-
if (isset($body)) {
291+
if ($body !== '') {
291292
$curlOptions[CURLOPT_POSTFIELDS] = $body;
292293
}
293294
break;

tests/Fixtures/MockClient.php

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,15 @@
1212
* The runRequest method of this client class just returns the value of
1313
* the path, method and data or the $runRequestReturnValue value if set.
1414
*/
15-
class MockClient implements Client
15+
final class MockClient implements Client
1616
{
1717
use ClientApiTrait;
1818

19+
public static function create()
20+
{
21+
return new self();
22+
}
23+
1924
/**
2025
* Return value the mocked runRequest method should return.
2126
*
@@ -34,22 +39,7 @@ class MockClient implements Client
3439
public $responseCodeMock;
3540
public $responseContentTypeMock;
3641

37-
private string $url;
38-
private string $apikeyOrUsername;
39-
private ?string $password;
40-
41-
/**
42-
* $apikeyOrUsername should be your ApiKey, but it could also be your username.
43-
* $password needs to be set if a username is given (not recommended).
44-
*/
45-
public function __construct(
46-
string $url,
47-
string $apikeyOrUsername,
48-
string $password = null
49-
) {
50-
$this->url = $url;
51-
$this->apikeyOrUsername = $apikeyOrUsername;
52-
$this->password = $password;
42+
private function __construct() {
5343
}
5444

5545
/**

tests/Integration/GroupXmlTest.php

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,10 @@
99

1010
class GroupXmlTest extends TestCase
1111
{
12-
/**
13-
* @var MockClient
14-
*/
15-
private $client;
16-
17-
public function setup(): void
18-
{
19-
$this->client = new MockClient('http://test.local', 'asdf');
20-
}
21-
2212
public function testCreateBlank()
2313
{
24-
$api = $this->client->getApi('group');
14+
/** @var \Redmine\Api\Group */
15+
$api = MockClient::create()->getApi('group');
2516
$this->assertInstanceOf('Redmine\Api\Group', $api);
2617

2718
$this->expectException(MissingParameterException::class);
@@ -32,7 +23,9 @@ public function testCreateBlank()
3223

3324
public function testCreateComplex()
3425
{
35-
$res = $this->client->getApi('group')->create([
26+
/** @var \Redmine\Api\Group */
27+
$api = MockClient::create()->getApi('group');
28+
$res = $api->create([
3629
'name' => 'Developers',
3730
'user_ids' => [3, 5],
3831
]);
@@ -57,7 +50,8 @@ public function testCreateComplex()
5750

5851
public function testUpdateNotImplemented()
5952
{
60-
$api = $this->client->getApi('group');
53+
/** @var \Redmine\Api\Group */
54+
$api = MockClient::create()->getApi('group');
6155
$this->assertInstanceOf('Redmine\Api\Group', $api);
6256

6357
$this->expectException(Exception::class);

0 commit comments

Comments
 (0)