Skip to content

Commit 6e001f6

Browse files
pjcdawkinsclaude
andcommitted
build: add PHPStan static analysis at level 5
Add phpstan/phpstan ^2 at level 5 with a baseline of 13 errors (all interface method gaps on ClientInterface and ConnectorInterface). Globally ignore new.static (deliberate polymorphism pattern). Add PHPStan step to GitHub Actions CI and a Makefile with lint/test targets. Fixes found by PHPStan: - Project::systemInformation() return type missing false case - RestoreOptions: redundant @return PHPDocs conflicting with native static return type - LogItem: static:: to self:: for private method - Tree::getBlob(): always-true instanceof and unreachable code - Resolver: always-true explode() assignment in condition - ResourceWithReferences: always-true getResponse() check - Result::getEntity(): redundant isset() on initialized property - Subscription::create(): new self() vs new static() return mismatch - EnvironmentTest: incorrect @var annotation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 61c1a74 commit 6e001f6

19 files changed

Lines changed: 185 additions & 36 deletions

.github/workflows/ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,11 @@ jobs:
2626
- name: Install dependencies
2727
run: composer install --no-progress --no-suggest --no-interaction
2828

29+
- name: Run ECS
30+
run: ./vendor/bin/ecs check
31+
32+
- name: Run PHPStan
33+
run: ./vendor/bin/phpstan analyse
34+
2935
- name: Run PHPUnit tests
3036
run: ./vendor/bin/phpunit

Makefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.PHONY: lint lint-ecs lint-phpstan test
2+
3+
lint: lint-ecs lint-phpstan
4+
5+
lint-ecs:
6+
./vendor/bin/ecs check
7+
8+
lint-phpstan:
9+
./vendor/bin/phpstan analyse
10+
11+
test:
12+
./vendor/bin/phpunit

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
},
1313
"require-dev": {
1414
"phpunit/phpunit": "^11",
15-
"symplify/easy-coding-standard": "^12.3"
15+
"symplify/easy-coding-standard": "^12.3",
16+
"phpstan/phpstan": "^2"
1617
},
1718
"autoload": {
1819
"psr-4": {

composer.lock

Lines changed: 54 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

phpstan-baseline.neon

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
parameters:
2+
ignoreErrors:
3+
-
4+
message: '#^Call to an undefined method GuzzleHttp\\ClientInterface\:\:get\(\)\.$#'
5+
identifier: method.notFound
6+
count: 1
7+
path: src/Model/Activity.php
8+
9+
-
10+
message: '#^Call to an undefined method GuzzleHttp\\ClientInterface\:\:patch\(\)\.$#'
11+
identifier: method.notFound
12+
count: 1
13+
path: src/Model/Organization/Address.php
14+
15+
-
16+
message: '#^Call to an undefined method GuzzleHttp\\ClientInterface\:\:get\(\)\.$#'
17+
identifier: method.notFound
18+
count: 2
19+
path: src/Model/Organization/Organization.php
20+
21+
-
22+
message: '#^Call to an undefined method GuzzleHttp\\ClientInterface\:\:patch\(\)\.$#'
23+
identifier: method.notFound
24+
count: 1
25+
path: src/Model/Organization/Organization.php
26+
27+
-
28+
message: '#^Call to an undefined method GuzzleHttp\\ClientInterface\:\:patch\(\)\.$#'
29+
identifier: method.notFound
30+
count: 1
31+
path: src/Model/Organization/Profile.php
32+
33+
-
34+
message: '#^Call to an undefined method GuzzleHttp\\ClientInterface\:\:get\(\)\.$#'
35+
identifier: method.notFound
36+
count: 1
37+
path: src/Model/Ref/Resolver.php
38+
39+
-
40+
message: '#^Call to an undefined method GuzzleHttp\\ClientInterface\:\:get\(\)\.$#'
41+
identifier: method.notFound
42+
count: 1
43+
path: src/Model/SetupOptions.php
44+
45+
-
46+
message: '#^Call to an undefined method GuzzleHttp\\ClientInterface\:\:patch\(\)\.$#'
47+
identifier: method.notFound
48+
count: 1
49+
path: src/Model/Team/Team.php
50+
51+
-
52+
message: '#^Call to an undefined method GuzzleHttp\\ClientInterface\:\:patch\(\)\.$#'
53+
identifier: method.notFound
54+
count: 1
55+
path: src/Model/UserAccess/ProjectUserAccess.php
56+
57+
-
58+
message: '#^Call to an undefined method GuzzleHttp\\ClientInterface\:\:post\(\)\.$#'
59+
identifier: method.notFound
60+
count: 1
61+
path: src/PlatformClient.php

phpstan.neon

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
includes:
2+
- phpstan-baseline.neon
3+
4+
parameters:
5+
level: 5
6+
paths:
7+
- src
8+
- tests
9+
ignoreErrors:
10+
# Deliberate pattern: resource classes use new static() for polymorphism.
11+
-
12+
identifier: new.static

src/Connection/ConnectorInterface.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ public function getClient(): ClientInterface;
5353
*/
5454
public function setApiToken(string $token, string $type);
5555

56+
/**
57+
* Get the connector configuration.
58+
*/
59+
public function getConfig(): array;
60+
61+
/**
62+
* Returns the access token saved in the session, if any.
63+
*/
64+
public function getAccessToken(): ?string;
65+
5666
/**
5767
* Get the configured API gateway URL (without trailing slash).
5868
*/

src/Model/ActivityLog/LogItem.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public function __toString()
3434
*/
3535
public static function singleFromJson(string $str): self|false
3636
{
37-
$data = static::decode($str);
37+
$data = self::decode($str);
3838
if (isset($data['data']['timestamp'], $data['data']['message'])) {
3939
$id = isset($data['_id']) ? (string) $data['_id'] : '';
4040
return new static($data['data']['timestamp'], $data['data']['message'], $id);
@@ -43,7 +43,7 @@ public static function singleFromJson(string $str): self|false
4343
}
4444

4545
/**
46-
* @return static[]
46+
* @return self[]
4747
*@deprecated use LogItem::multipleFromJsonStreamWithSeal() instead
4848
*/
4949
public static function multipleFromJsonStream(string $str): array
@@ -77,7 +77,7 @@ public static function multipleFromJsonStreamWithSeal(string $str): array
7777
if ($line === '') {
7878
continue;
7979
}
80-
$data = static::decode($line);
80+
$data = self::decode($line);
8181
if (is_array($data)) {
8282
if (! empty($data['seal'])) {
8383
$seal = true;

src/Model/AutoscalingSettings.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace Platformsh\Client\Model;
46

57
/**
68
* Represents environment autoscaling settings.
7-
*
89
*/
9-
class AutoscalingSettings extends ApiResourceBase {}
10+
class AutoscalingSettings extends ApiResourceBase
11+
{
12+
}

src/Model/Backups/RestoreOptions.php

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,45 +16,30 @@ class RestoreOptions
1616

1717
private ?string $resourcesInit;
1818

19-
/**
20-
* @return RestoreOptions
21-
*/
2219
public function setEnvironmentName(?string $environmentName): static
2320
{
2421
$this->environmentName = $environmentName;
2522
return $this;
2623
}
2724

28-
/**
29-
* @return RestoreOptions
30-
*/
3125
public function setBranchFrom(?string $branchFrom): static
3226
{
3327
$this->branchFrom = $branchFrom;
3428
return $this;
3529
}
3630

37-
/**
38-
* @return RestoreOptions
39-
*/
4031
public function setRestoreCode(?bool $restoreCode): static
4132
{
4233
$this->restoreCode = $restoreCode;
4334
return $this;
4435
}
4536

46-
/**
47-
* @return RestoreOptions
48-
*/
4937
public function setRestoreResources(?bool $restoreResources): static
5038
{
5139
$this->restoreResources = $restoreResources;
5240
return $this;
5341
}
5442

55-
/**
56-
* @return RestoreOptions
57-
*/
5843
public function setResourcesInit(?string $init): static
5944
{
6045
$this->resourcesInit = $init;

0 commit comments

Comments
 (0)