From 32366bc37d6ffd0cf691ce348caecc50db7ff075 Mon Sep 17 00:00:00 2001 From: Uladzimir Tsykun Date: Fri, 17 Mar 2023 09:13:11 +0100 Subject: [PATCH 1/6] Fix basic auth infinite loop (#11320) --- src/Composer/Util/Http/CurlDownloader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Util/Http/CurlDownloader.php b/src/Composer/Util/Http/CurlDownloader.php index aaba93627..edc668a60 100644 --- a/src/Composer/Util/Http/CurlDownloader.php +++ b/src/Composer/Util/Http/CurlDownloader.php @@ -407,7 +407,7 @@ class CurlDownloader $result = $this->isAuthenticatedRetryNeeded($job, $response); if ($result['retry']) { - $this->restartJob($job, $job['url'], ['storeAuth' => $result['storeAuth']]); + $this->restartJob($job, $job['url'], ['storeAuth' => $result['storeAuth'], 'retries' => $job['attributes']['retries'] + 1]); continue; } From 5d2d513f973fab7c9cbb7e011791c01c93f8a983 Mon Sep 17 00:00:00 2001 From: Wim Leers Date: Tue, 14 Mar 2023 15:31:25 +0100 Subject: [PATCH 2/6] Follow-up for #5205: fix high concurrency race condition Composer would fail with an ``` PHP temp directory (/tmp) does not exist or is not writable to Composer. Set sys_temp_dir in your php.ini ``` error when used in parallel. Because it is checking if a file with `md5(microtime())` can be created, which is not sufficiently unique when used in parallel. Since each Composer instance runs in its own process, this can easily be mitigated by not just partitioning based on time of use, but also based on process ID. Original investigation: https://www.drupal.org/project/automatic_updates/issues/3338789#comment-14961390 --- src/Composer/Console/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index bdd6ef6d3..9e585e614 100644 --- a/src/Composer/Console/Application.php +++ b/src/Composer/Console/Application.php @@ -339,7 +339,7 @@ class Application extends BaseApplication // Check system temp folder for usability as it can cause weird runtime issues otherwise Silencer::call(static function () use ($io): void { - $tempfile = sys_get_temp_dir() . '/temp-' . md5(microtime()); + $tempfile = sys_get_temp_dir() . '/temp-' . getmypid() . '-' . md5(microtime()); if (!(file_put_contents($tempfile, __FILE__) && (file_get_contents($tempfile) === __FILE__) && unlink($tempfile) && !file_exists($tempfile))) { $io->writeError(sprintf('PHP temp directory (%s) does not exist or is not writable to Composer. Set sys_temp_dir in your php.ini', sys_get_temp_dir())); } From 685a2e6be2537ed2f5008b877ce12bb5049c6507 Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 20 Mar 2023 19:18:19 +0000 Subject: [PATCH 3/6] Composer support string (#11386) * GitHubDriver: fix support is set to string * GitLabDriver: fix support is set to string * BitbucketDriver: fix support is set to string * Fix PHPStan --- .../Repository/Vcs/GitBitbucketDriver.php | 3 + src/Composer/Repository/Vcs/GitHubDriver.php | 3 + src/Composer/Repository/Vcs/GitLabDriver.php | 3 + .../Repository/Vcs/GitBitbucketDriverTest.php | 81 ++++++++++--------- .../Test/Repository/Vcs/GitHubDriverTest.php | 38 +++++++++ .../Test/Repository/Vcs/GitLabDriverTest.php | 27 +++++++ 6 files changed, 116 insertions(+), 39 deletions(-) diff --git a/src/Composer/Repository/Vcs/GitBitbucketDriver.php b/src/Composer/Repository/Vcs/GitBitbucketDriver.php index c3b8dd8c4..ff9aecafc 100644 --- a/src/Composer/Repository/Vcs/GitBitbucketDriver.php +++ b/src/Composer/Repository/Vcs/GitBitbucketDriver.php @@ -153,6 +153,9 @@ class GitBitbucketDriver extends VcsDriver if ($composer !== null) { // specials for bitbucket + if (isset($composer['support']) && !is_array($composer['support'])) { + $composer['support'] = []; + } if (!isset($composer['support']['source'])) { $label = array_search( $identifier, diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php index 98dbf989a..122b03fa7 100644 --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/src/Composer/Repository/Vcs/GitHubDriver.php @@ -174,6 +174,9 @@ class GitHubDriver extends VcsDriver if ($composer !== null) { // specials for github + if (isset($composer['support']) && !is_array($composer['support'])) { + $composer['support'] = []; + } if (!isset($composer['support']['source'])) { $label = array_search($identifier, $this->getTags()) ?: array_search($identifier, $this->getBranches()) ?: $identifier; $composer['support']['source'] = sprintf('https://%s/%s/%s/tree/%s', $this->originUrl, $this->owner, $this->repository, $label); diff --git a/src/Composer/Repository/Vcs/GitLabDriver.php b/src/Composer/Repository/Vcs/GitLabDriver.php index 77b183e0b..1e13154c5 100644 --- a/src/Composer/Repository/Vcs/GitLabDriver.php +++ b/src/Composer/Repository/Vcs/GitLabDriver.php @@ -167,6 +167,9 @@ class GitLabDriver extends VcsDriver if (null !== $composer) { // specials for gitlab (this data is only available if authentication is provided) + if (isset($composer['support']) && !is_array($composer['support'])) { + $composer['support'] = []; + } if (!isset($composer['support']['source']) && isset($this->project['web_url'])) { $label = array_search($identifier, $this->getTags(), true) ?: array_search($identifier, $this->getBranches(), true) ?: $identifier; $composer['support']['source'] = sprintf('%s/-/tree/%s', $this->project['web_url'], $label); diff --git a/tests/Composer/Test/Repository/Vcs/GitBitbucketDriverTest.php b/tests/Composer/Test/Repository/Vcs/GitBitbucketDriverTest.php index 3a35cd28e..5050b0fb4 100644 --- a/tests/Composer/Test/Repository/Vcs/GitBitbucketDriverTest.php +++ b/tests/Composer/Test/Repository/Vcs/GitBitbucketDriverTest.php @@ -14,6 +14,8 @@ namespace Composer\Test\Repository\Vcs; use Composer\Config; use Composer\Repository\Vcs\GitBitbucketDriver; +use Composer\Repository\Vcs\GitHubDriver; +use Composer\Test\Mock\HttpDownloaderMock; use Composer\Test\TestCase; use Composer\Util\Filesystem; use Composer\Util\ProcessExecutor; @@ -28,7 +30,7 @@ class GitBitbucketDriverTest extends TestCase private $io; /** @var Config */ private $config; - /** @var \Composer\Util\HttpDownloader&\PHPUnit\Framework\MockObject\MockObject */ + /** @var HttpDownloaderMock */ private $httpDownloader; /** @var string */ private $home; @@ -46,9 +48,7 @@ class GitBitbucketDriverTest extends TestCase ], ]); - $this->httpDownloader = $this->getMockBuilder('Composer\Util\HttpDownloader') - ->disableOriginalConstructor() - ->getMock(); + $this->httpDownloader = $this->getHttpDownloaderMock($this->io, $this->config);; } protected function tearDown(): void @@ -83,15 +83,9 @@ class GitBitbucketDriverTest extends TestCase self::expectException('RuntimeException'); self::expectExceptionMessage('https://bitbucket.org/user/repo.git does not appear to be a git repository, use https://bitbucket.org/user/repo but remember that Bitbucket no longer supports the mercurial repositories. https://bitbucket.org/blog/sunsetting-mercurial-support-in-bitbucket'); - $this->httpDownloader->expects($this->once()) - ->method('get') - ->with( - $url = 'https://api.bitbucket.org/2.0/repositories/user/repo?fields=-project%2C-owner', - [] - ) - ->willReturn( - new Response(['url' => $url], 200, [], '{"scm":"hg","website":"","has_wiki":false,"name":"repo","links":{"branches":{"href":"https:\/\/api.bitbucket.org\/2.0\/repositories\/user\/repo\/refs\/branches"},"tags":{"href":"https:\/\/api.bitbucket.org\/2.0\/repositories\/user\/repo\/refs\/tags"},"clone":[{"href":"https:\/\/user@bitbucket.org\/user\/repo","name":"https"},{"href":"ssh:\/\/hg@bitbucket.org\/user\/repo","name":"ssh"}],"html":{"href":"https:\/\/bitbucket.org\/user\/repo"}},"language":"php","created_on":"2015-02-18T16:22:24.688+00:00","updated_on":"2016-05-17T13:20:21.993+00:00","is_private":true,"has_issues":false}') - ); + $this->httpDownloader->expects([ + ['url' => 'https://api.bitbucket.org/2.0/repositories/user/repo?fields=-project%2C-owner', 'body' => '{"scm":"hg","website":"","has_wiki":false,"name":"repo","links":{"branches":{"href":"https:\/\/api.bitbucket.org\/2.0\/repositories\/user\/repo\/refs\/branches"},"tags":{"href":"https:\/\/api.bitbucket.org\/2.0\/repositories\/user\/repo\/refs\/tags"},"clone":[{"href":"https:\/\/user@bitbucket.org\/user\/repo","name":"https"},{"href":"ssh:\/\/hg@bitbucket.org\/user\/repo","name":"ssh"}],"html":{"href":"https:\/\/bitbucket.org\/user\/repo"}},"language":"php","created_on":"2015-02-18T16:22:24.688+00:00","updated_on":"2016-05-17T13:20:21.993+00:00","is_private":true,"has_issues":false}'] + ], true); $driver = $this->getDriver(['url' => 'https://bitbucket.org/user/repo.git']); @@ -109,32 +103,13 @@ class GitBitbucketDriverTest extends TestCase 'https://api.bitbucket.org/2.0/repositories/user/repo/src/main/composer.json', 'https://api.bitbucket.org/2.0/repositories/user/repo/commit/main?fields=date', ]; - $this->httpDownloader->expects($this->any()) - ->method('get') - ->withConsecutive( - [ - $urls[0], [], - ], - [ - $urls[1], [], - ], - [ - $urls[2], [], - ], - [ - $urls[3], [], - ], - [ - $urls[4], [], - ] - ) - ->willReturnOnConsecutiveCalls( - new Response(['url' => $urls[0]], 200, [], '{"mainbranch": {"name": "main"}, "scm":"git","website":"","has_wiki":false,"name":"repo","links":{"branches":{"href":"https:\/\/api.bitbucket.org\/2.0\/repositories\/user\/repo\/refs\/branches"},"tags":{"href":"https:\/\/api.bitbucket.org\/2.0\/repositories\/user\/repo\/refs\/tags"},"clone":[{"href":"https:\/\/user@bitbucket.org\/user\/repo.git","name":"https"},{"href":"ssh:\/\/git@bitbucket.org\/user\/repo.git","name":"ssh"}],"html":{"href":"https:\/\/bitbucket.org\/user\/repo"}},"language":"php","created_on":"2015-02-18T16:22:24.688+00:00","updated_on":"2016-05-17T13:20:21.993+00:00","is_private":true,"has_issues":false}'), - new Response(['url' => $urls[1]], 200, [], '{"values":[{"name":"1.0.1","target":{"hash":"9b78a3932143497c519e49b8241083838c8ff8a1"}},{"name":"1.0.0","target":{"hash":"d3393d514318a9267d2f8ebbf463a9aaa389f8eb"}}]}'), - new Response(['url' => $urls[2]], 200, [], '{"values":[{"name":"main","target":{"hash":"937992d19d72b5116c3e8c4a04f960e5fa270b22"}}]}'), - new Response(['url' => $urls[3]], 200, [], '{"name": "user/repo","description": "test repo","license": "GPL","authors": [{"name": "Name","email": "local@domain.tld"}],"require": {"creator/package": "^1.0"},"require-dev": {"phpunit/phpunit": "~4.8"}}'), - new Response(['url' => $urls[4]], 200, [], '{"date": "2016-05-17T13:19:52+00:00"}') - ); + $this->httpDownloader->expects([ + ['url' => $urls[0], 'body' => '{"mainbranch": {"name": "main"}, "scm":"git","website":"","has_wiki":false,"name":"repo","links":{"branches":{"href":"https:\/\/api.bitbucket.org\/2.0\/repositories\/user\/repo\/refs\/branches"},"tags":{"href":"https:\/\/api.bitbucket.org\/2.0\/repositories\/user\/repo\/refs\/tags"},"clone":[{"href":"https:\/\/user@bitbucket.org\/user\/repo.git","name":"https"},{"href":"ssh:\/\/git@bitbucket.org\/user\/repo.git","name":"ssh"}],"html":{"href":"https:\/\/bitbucket.org\/user\/repo"}},"language":"php","created_on":"2015-02-18T16:22:24.688+00:00","updated_on":"2016-05-17T13:20:21.993+00:00","is_private":true,"has_issues":false}'], + ['url' => $urls[1], 'body' => '{"values":[{"name":"1.0.1","target":{"hash":"9b78a3932143497c519e49b8241083838c8ff8a1"}},{"name":"1.0.0","target":{"hash":"d3393d514318a9267d2f8ebbf463a9aaa389f8eb"}}]}'], + ['url' => $urls[2], 'body' => '{"values":[{"name":"main","target":{"hash":"937992d19d72b5116c3e8c4a04f960e5fa270b22"}}]}'], + ['url' => $urls[3], 'body' => '{"name": "user/repo","description": "test repo","license": "GPL","authors": [{"name": "Name","email": "local@domain.tld"}],"require": {"creator/package": "^1.0"},"require-dev": {"phpunit/phpunit": "~4.8"}}'], + ['url' => $urls[4], 'body' => '{"date": "2016-05-17T13:19:52+00:00"}'], + ], true); $this->assertEquals( 'main', @@ -218,6 +193,34 @@ class GitBitbucketDriverTest extends TestCase $driver->initialize(); } + public function testInvalidSupportData(): void + { + $repoUrl = 'https://bitbucket.org/user/repo.git'; + + $driver = $this->getDriver(['url' => $repoUrl]); + + $urls = [ + 'https://api.bitbucket.org/2.0/repositories/user/repo?fields=-project%2C-owner', + 'https://api.bitbucket.org/2.0/repositories/user/repo/src/main/composer.json', + 'https://api.bitbucket.org/2.0/repositories/user/repo/commit/main?fields=date', + 'https://api.bitbucket.org/2.0/repositories/user/repo/refs/tags?pagelen=100&fields=values.name%2Cvalues.target.hash%2Cnext&sort=-target.date', + 'https://api.bitbucket.org/2.0/repositories/user/repo/refs/branches?pagelen=100&fields=values.name%2Cvalues.target.hash%2Cvalues.heads%2Cnext&sort=-target.date', + ]; + $this->httpDownloader->expects([ + ['url' => $urls[0], 'body' => '{"mainbranch": {"name": "main"}, "scm":"git","website":"","has_wiki":false,"name":"repo","links":{"branches":{"href":"https:\/\/api.bitbucket.org\/2.0\/repositories\/user\/repo\/refs\/branches"},"tags":{"href":"https:\/\/api.bitbucket.org\/2.0\/repositories\/user\/repo\/refs\/tags"},"clone":[{"href":"https:\/\/user@bitbucket.org\/user\/repo.git","name":"https"},{"href":"ssh:\/\/git@bitbucket.org\/user\/repo.git","name":"ssh"}],"html":{"href":"https:\/\/bitbucket.org\/user\/repo"}},"language":"php","created_on":"2015-02-18T16:22:24.688+00:00","updated_on":"2016-05-17T13:20:21.993+00:00","is_private":true,"has_issues":false}'], + ['url' => $urls[1], 'body' => '{"support": "' . $repoUrl . '"}'], + ['url' => $urls[2], 'body' => '{"date": "2016-05-17T13:19:52+00:00"}'], + ['url' => $urls[3], 'body' => '{"values":[{"name":"1.0.1","target":{"hash":"9b78a3932143497c519e49b8241083838c8ff8a1"}},{"name":"1.0.0","target":{"hash":"d3393d514318a9267d2f8ebbf463a9aaa389f8eb"}}]}'], + ['url' => $urls[4], 'body' => '{"values":[{"name":"main","target":{"hash":"937992d19d72b5116c3e8c4a04f960e5fa270b22"}}]}'], + ], true); + + $driver->getRootIdentifier(); + $data = $driver->getComposerInformation('main'); + + $this->assertIsArray($data); + $this->assertSame('https://bitbucket.org/user/repo/src/937992d19d72b5116c3e8c4a04f960e5fa270b22/?at=main', $data['support']['source']); + } + public function testSupports(): void { $this->assertTrue( diff --git a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php index 68cf5e295..8431a1b49 100644 --- a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php +++ b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php @@ -199,6 +199,44 @@ class GitHubDriverTest extends TestCase $this->assertArrayNotHasKey('abandoned', $data); } + public function testInvalidSupportData(): void + { + $repoUrl = 'http://github.com/composer/packagist'; + $repoApiUrl = 'https://api.github.com/repos/composer/packagist'; + $identifier = 'feature/3.2-foo'; + $sha = 'SOMESHA'; + + $io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); + $io->expects($this->any()) + ->method('isInteractive') + ->will($this->returnValue(true)); + + $httpDownloader = $this->getHttpDownloaderMock($io, $this->config); + $httpDownloader->expects( + [ + ['url' => $repoApiUrl, 'body' => '{"master_branch": "test_master", "owner": {"login": "composer"}, "name": "packagist"}'], + ['url' => 'https://api.github.com/repos/composer/packagist/contents/composer.json?ref=feature%2F3.2-foo', 'body' => '{"encoding":"base64","content":"'.base64_encode('{"support": "'.$repoUrl.'" }').'"}'], + ['url' => 'https://api.github.com/repos/composer/packagist/commits/feature%2F3.2-foo', 'body' => '{"commit": {"committer":{ "date": "2012-09-10"}}}'], + ['url' => 'https://api.github.com/repos/composer/packagist/contents/.github/FUNDING.yml', 'body' => '{"encoding": "base64", "content": "'.base64_encode("custom: https://example.com").'"}'], + ], + true + ); + + $repoConfig = [ + 'url' => $repoUrl, + ]; + + $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, $httpDownloader, $this->getProcessExecutorMock()); + $gitHubDriver->initialize(); + $this->setAttribute($gitHubDriver, 'tags', [$identifier => $sha]); + $this->setAttribute($gitHubDriver, 'branches', ['test_master' => $sha]); + + $data = $gitHubDriver->getComposerInformation($identifier); + + $this->assertIsArray($data); + $this->assertSame('https://github.com/composer/packagist/tree/feature/3.2-foo', $data['support']['source']); + } + public function testPublicRepositoryArchived(): void { $repoUrl = 'http://github.com/composer/packagist'; diff --git a/tests/Composer/Test/Repository/Vcs/GitLabDriverTest.php b/tests/Composer/Test/Repository/Vcs/GitLabDriverTest.php index 2f9dae2b9..9d163f567 100644 --- a/tests/Composer/Test/Repository/Vcs/GitLabDriverTest.php +++ b/tests/Composer/Test/Repository/Vcs/GitLabDriverTest.php @@ -244,6 +244,22 @@ JSON; $this->assertEquals($url, $driver->getUrl()); } + public function testInvalidSupportData(): void + { + $driver = $this->testInitialize($repoUrl = 'https://gitlab.com/mygroup/myproject', 'https://gitlab.com/api/v4/projects/mygroup%2Fmyproject'); + $this->setAttribute($driver, 'branches', ['main' => 'SOMESHA']); + $this->setAttribute($driver, 'tags', []); + + $this->httpDownloader->expects([ + ['url' => 'https://gitlab.com/api/v4/projects/mygroup%2Fmyproject/repository/files/composer%2Ejson/raw?ref=SOMESHA', 'body' => '{"support": "'.$repoUrl.'" }'], + ], true); + + $data = $driver->getComposerInformation('main'); + + $this->assertIsArray($data); + $this->assertSame('https://gitlab.com/mygroup/myproject/-/tree/main', $data['support']['source']); + } + public function testGetDist(): void { $driver = $this->testInitialize('https://gitlab.com/mygroup/myproject', 'https://gitlab.com/api/v4/projects/mygroup%2Fmyproject'); @@ -631,4 +647,15 @@ JSON; $driver->initialize(); $this->assertEquals('https://gitlab.com/mygroup/myproject.git', $driver->getRepositoryUrl(), 'Repository URL matches config request for http not git'); } + + /** + * @param object $object + * @param mixed $value + */ + protected function setAttribute($object, string $attribute, $value): void + { + $attr = new \ReflectionProperty($object, $attribute); + $attr->setAccessible(true); + $attr->setValue($object, $value); + } } From d3adecf58370cd5961db968c2b49f5f102b0d8de Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 20 Mar 2023 21:42:14 +0100 Subject: [PATCH 4/6] Fix github header handling to be case insensitive, fixes rate limit extraction (#11366) --- src/Composer/Util/GitHub.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Composer/Util/GitHub.php b/src/Composer/Util/GitHub.php index 2ac30e3b8..43a635450 100644 --- a/src/Composer/Util/GitHub.php +++ b/src/Composer/Util/GitHub.php @@ -161,15 +161,15 @@ class GitHub foreach ($headers as $header) { $header = trim($header); - if (false === strpos($header, 'X-RateLimit-')) { + if (false === stripos($header, 'x-ratelimit-')) { continue; } [$type, $value] = explode(':', $header, 2); - switch ($type) { - case 'X-RateLimit-Limit': + switch (strtolower($type)) { + case 'x-ratelimit-limit': $rateLimit['limit'] = (int) trim($value); break; - case 'X-RateLimit-Reset': + case 'x-ratelimit-reset': $rateLimit['reset'] = date('Y-m-d H:i:s', (int) trim($value)); break; } @@ -206,7 +206,7 @@ class GitHub public function isRateLimited(array $headers): bool { foreach ($headers as $header) { - if (Preg::isMatch('{^X-RateLimit-Remaining: *0$}i', trim($header))) { + if (Preg::isMatch('{^x-ratelimit-remaining: *0$}i', trim($header))) { return true; } } @@ -224,7 +224,7 @@ class GitHub public function requiresSso(array $headers): bool { foreach ($headers as $header) { - if (Preg::isMatch('{^X-GitHub-SSO: required}i', trim($header))) { + if (Preg::isMatch('{^x-github-sso: required}i', trim($header))) { return true; } } From 62f12abcb17e973163f7f4ceda5e76fffaa121e0 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 21 Mar 2023 09:55:28 +0100 Subject: [PATCH 5/6] Fix return type of InstalledVersions::getInstalled, fixes #11304 --- src/Composer/InstalledVersions.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Composer/InstalledVersions.php b/src/Composer/InstalledVersions.php index c6b54af7b..153849aec 100644 --- a/src/Composer/InstalledVersions.php +++ b/src/Composer/InstalledVersions.php @@ -328,7 +328,9 @@ class InstalledVersions if (isset(self::$installedByVendor[$vendorDir])) { $installed[] = self::$installedByVendor[$vendorDir]; } elseif (is_file($vendorDir.'/composer/installed.php')) { - $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require $vendorDir.'/composer/installed.php'; + $installed[] = self::$installedByVendor[$vendorDir] = $required; if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { self::$installed = $installed[count($installed) - 1]; } @@ -340,12 +342,17 @@ class InstalledVersions // only require the installed.php file if this file is loaded from its dumped location, // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 if (substr(__DIR__, -8, 1) !== 'C') { - self::$installed = require __DIR__ . '/installed.php'; + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; } else { self::$installed = array(); } } - $installed[] = self::$installed; + + if (self::$installed !== array()) { + $installed[] = self::$installed; + } return $installed; } From 5c3d8f35dbd0d35049dc00b8c6c178e442e93a65 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 21 Mar 2023 10:36:42 +0100 Subject: [PATCH 6/6] Update deps, fix phpstan issues, update baseline (1711, 49) --- composer.lock | 142 +++++++++--------- phpstan/baseline.neon | 122 +-------------- .../Command/CheckPlatformReqsCommand.php | 8 +- .../Command/PackageDiscoveryTrait.php | 2 +- src/Composer/Downloader/FileDownloader.php | 3 +- src/Composer/InstalledVersions.php | 4 +- .../PHPStan/ConfigReturnTypeExtension.php | 8 +- src/Composer/Package/Archiver/ZipArchiver.php | 2 +- .../Package/Version/VersionGuesser.php | 4 +- src/Composer/SelfUpdate/Versions.php | 4 +- tests/Composer/Test/InstallerTest.php | 3 - .../Test/Mock/ProcessExecutorMock.php | 2 +- .../Test/Util/RemoteFilesystemTest.php | 1 - 13 files changed, 98 insertions(+), 207 deletions(-) diff --git a/composer.lock b/composer.lock index 3d2f9d5e8..ed8f2760a 100644 --- a/composer.lock +++ b/composer.lock @@ -941,16 +941,16 @@ }, { "name": "symfony/console", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "dccb8d251a9017d5994c988b034d3e18aaabf740" + "reference": "c77433ddc6cdc689caf48065d9ea22ca0853fbd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/dccb8d251a9017d5994c988b034d3e18aaabf740", - "reference": "dccb8d251a9017d5994c988b034d3e18aaabf740", + "url": "https://api.github.com/repos/symfony/console/zipball/c77433ddc6cdc689caf48065d9ea22ca0853fbd9", + "reference": "c77433ddc6cdc689caf48065d9ea22ca0853fbd9", "shasum": "" }, "require": { @@ -1020,7 +1020,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.19" + "source": "https://github.com/symfony/console/tree/v5.4.21" }, "funding": [ { @@ -1036,7 +1036,7 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-25T16:59:41+00:00" }, { "name": "symfony/deprecation-contracts", @@ -1107,16 +1107,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "648bfaca6a494f3e22378123bcee2894045dc9d8" + "reference": "e75960b1bbfd2b8c9e483e0d74811d555ca3de9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/648bfaca6a494f3e22378123bcee2894045dc9d8", - "reference": "648bfaca6a494f3e22378123bcee2894045dc9d8", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/e75960b1bbfd2b8c9e483e0d74811d555ca3de9f", + "reference": "e75960b1bbfd2b8c9e483e0d74811d555ca3de9f", "shasum": "" }, "require": { @@ -1151,7 +1151,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.19" + "source": "https://github.com/symfony/filesystem/tree/v5.4.21" }, "funding": [ { @@ -1167,20 +1167,20 @@ "type": "tidelift" } ], - "time": "2023-01-14T19:14:44+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/finder", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "6071aebf810ad13fe8200c224f36103abb37cf1f" + "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/6071aebf810ad13fe8200c224f36103abb37cf1f", - "reference": "6071aebf810ad13fe8200c224f36103abb37cf1f", + "url": "https://api.github.com/repos/symfony/finder/zipball/078e9a5e1871fcfe6a5ce421b539344c21afef19", + "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19", "shasum": "" }, "require": { @@ -1214,7 +1214,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.19" + "source": "https://github.com/symfony/finder/tree/v5.4.21" }, "funding": [ { @@ -1230,7 +1230,7 @@ "type": "tidelift" } ], - "time": "2023-01-14T19:14:44+00:00" + "time": "2023-02-16T09:33:00+00:00" }, { "name": "symfony/polyfill-ctype", @@ -1805,16 +1805,16 @@ }, { "name": "symfony/process", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "c5ba874c9b636dbccf761e22ce750e88ec3f55e1" + "reference": "d4ce417ebcb0b7d090b4c178ed6d3accc518e8bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/c5ba874c9b636dbccf761e22ce750e88ec3f55e1", - "reference": "c5ba874c9b636dbccf761e22ce750e88ec3f55e1", + "url": "https://api.github.com/repos/symfony/process/zipball/d4ce417ebcb0b7d090b4c178ed6d3accc518e8bd", + "reference": "d4ce417ebcb0b7d090b4c178ed6d3accc518e8bd", "shasum": "" }, "require": { @@ -1847,7 +1847,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.19" + "source": "https://github.com/symfony/process/tree/v5.4.21" }, "funding": [ { @@ -1863,7 +1863,7 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-21T19:46:44+00:00" }, { "name": "symfony/service-contracts", @@ -1950,16 +1950,16 @@ }, { "name": "symfony/string", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "0a01071610fd861cc160dfb7e2682ceec66064cb" + "reference": "edac10d167b78b1d90f46a80320d632de0bd9f2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/0a01071610fd861cc160dfb7e2682ceec66064cb", - "reference": "0a01071610fd861cc160dfb7e2682ceec66064cb", + "url": "https://api.github.com/repos/symfony/string/zipball/edac10d167b78b1d90f46a80320d632de0bd9f2f", + "reference": "edac10d167b78b1d90f46a80320d632de0bd9f2f", "shasum": "" }, "require": { @@ -2016,7 +2016,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.19" + "source": "https://github.com/symfony/string/tree/v5.4.21" }, "funding": [ { @@ -2032,22 +2032,22 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-22T08:00:55+00:00" } ], "packages-dev": [ { "name": "phpstan/phpstan", - "version": "1.9.14", + "version": "1.10.7", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "e5fcc96289cf737304286a9b505fbed091f02e58" + "reference": "b10ceb526d9607903c5b2673f1fc8775dbe48975" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e5fcc96289cf737304286a9b505fbed091f02e58", - "reference": "e5fcc96289cf737304286a9b505fbed091f02e58", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b10ceb526d9607903c5b2673f1fc8775dbe48975", + "reference": "b10ceb526d9607903c5b2673f1fc8775dbe48975", "shasum": "" }, "require": { @@ -2076,8 +2076,11 @@ "static analysis" ], "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.9.14" + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" }, "funding": [ { @@ -2093,25 +2096,25 @@ "type": "tidelift" } ], - "time": "2023-01-19T10:47:09+00:00" + "time": "2023-03-16T15:24:20+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", - "version": "1.1.1", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-deprecation-rules.git", - "reference": "2c6792eda026d9c474c14aa018aed312686714db" + "reference": "a22b36b955a2e9a3d39fe533b6c1bb5359f9c319" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/2c6792eda026d9c474c14aa018aed312686714db", - "reference": "2c6792eda026d9c474c14aa018aed312686714db", + "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/a22b36b955a2e9a3d39fe533b6c1bb5359f9c319", + "reference": "a22b36b955a2e9a3d39fe533b6c1bb5359f9c319", "shasum": "" }, "require": { "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.9.3" + "phpstan/phpstan": "^1.10" }, "require-dev": { "php-parallel-lint/php-parallel-lint": "^1.2", @@ -2139,27 +2142,27 @@ "description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.", "support": { "issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues", - "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/1.1.1" + "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/1.1.3" }, - "time": "2022-12-13T14:26:20+00:00" + "time": "2023-03-17T07:50:08+00:00" }, { "name": "phpstan/phpstan-phpunit", - "version": "1.3.3", + "version": "1.3.10", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "54a24bd23e9e80ee918cdc24f909d376c2e273f7" + "reference": "4cc5c6cc38e56bce7ea47c4091814e516d172dc3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/54a24bd23e9e80ee918cdc24f909d376c2e273f7", - "reference": "54a24bd23e9e80ee918cdc24f909d376c2e273f7", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/4cc5c6cc38e56bce7ea47c4091814e516d172dc3", + "reference": "4cc5c6cc38e56bce7ea47c4091814e516d172dc3", "shasum": "" }, "require": { "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.9.3" + "phpstan/phpstan": "^1.10" }, "conflict": { "phpunit/phpunit": "<7.0" @@ -2191,31 +2194,32 @@ "description": "PHPUnit extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.3" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.10" }, - "time": "2022-12-21T15:25:00+00:00" + "time": "2023-03-02T10:25:13+00:00" }, { "name": "phpstan/phpstan-strict-rules", - "version": "1.4.5", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-strict-rules.git", - "reference": "361f75b06066f3fdaba87c1f57bdb1ffc28d6f1d" + "reference": "b7dd96a5503919a43b3cd06a2dced9d4252492f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/361f75b06066f3fdaba87c1f57bdb1ffc28d6f1d", - "reference": "361f75b06066f3fdaba87c1f57bdb1ffc28d6f1d", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/b7dd96a5503919a43b3cd06a2dced9d4252492f2", + "reference": "b7dd96a5503919a43b3cd06a2dced9d4252492f2", "shasum": "" }, "require": { "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.9.7" + "phpstan/phpstan": "^1.10" }, "require-dev": { "nikic/php-parser": "^4.13.0", "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-deprecation-rules": "^1.1", "phpstan/phpstan-phpunit": "^1.0", "phpunit/phpunit": "^9.5" }, @@ -2239,22 +2243,22 @@ "description": "Extra strict and opinionated rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", - "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.4.5" + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.0" }, - "time": "2023-01-11T14:16:29+00:00" + "time": "2023-02-21T10:17:10+00:00" }, { "name": "phpstan/phpstan-symfony", - "version": "1.2.22", + "version": "1.2.23", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-symfony.git", - "reference": "cbf5b9ceadab8365ed46db42dcd23db1a4c26c93" + "reference": "8a8d0538ca943b20beda7e9799e14fb3683262d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/cbf5b9ceadab8365ed46db42dcd23db1a4c26c93", - "reference": "cbf5b9ceadab8365ed46db42dcd23db1a4c26c93", + "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/8a8d0538ca943b20beda7e9799e14fb3683262d4", + "reference": "8a8d0538ca943b20beda7e9799e14fb3683262d4", "shasum": "" }, "require": { @@ -2310,22 +2314,22 @@ "description": "Symfony Framework extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-symfony/issues", - "source": "https://github.com/phpstan/phpstan-symfony/tree/1.2.22" + "source": "https://github.com/phpstan/phpstan-symfony/tree/1.2.23" }, - "time": "2023-02-01T13:26:41+00:00" + "time": "2023-02-06T10:42:02+00:00" }, { "name": "symfony/phpunit-bridge", - "version": "v6.2.5", + "version": "v6.2.7", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "d759e5372de414bef53a688c7aa7e240e4fd8aa2" + "reference": "56965fae0b6b8d271015990eff5240ffff02e185" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/d759e5372de414bef53a688c7aa7e240e4fd8aa2", - "reference": "d759e5372de414bef53a688c7aa7e240e4fd8aa2", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/56965fae0b6b8d271015990eff5240ffff02e185", + "reference": "56965fae0b6b8d271015990eff5240ffff02e185", "shasum": "" }, "require": { @@ -2379,7 +2383,7 @@ "description": "Provides utilities for PHPUnit, especially user deprecation notices management", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v6.2.5" + "source": "https://github.com/symfony/phpunit-bridge/tree/v6.2.7" }, "funding": [ { @@ -2395,7 +2399,7 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:38:09+00:00" + "time": "2023-02-16T09:57:23+00:00" } ], "aliases": [], diff --git a/phpstan/baseline.neon b/phpstan/baseline.neon index 3ba4b362c..a82930c7d 100644 --- a/phpstan/baseline.neon +++ b/phpstan/baseline.neon @@ -240,11 +240,6 @@ parameters: count: 1 path: ../src/Composer/Command/BaseDependencyCommand.php - - - message: "#^Cannot access an offset on array\\\\|Composer\\\\Package\\\\Link\\>\\|Composer\\\\Package\\\\Link\\>\\|Composer\\\\Package\\\\Link\\>\\|Composer\\\\Package\\\\Link\\.$#" - count: 1 - path: ../src/Composer/Command/CheckPlatformReqsCommand.php - - message: "#^Only booleans are allowed in a negated boolean, Composer\\\\Semver\\\\Constraint\\\\ConstraintInterface\\|null given\\.$#" count: 1 @@ -475,11 +470,6 @@ parameters: count: 1 path: ../src/Composer/Command/InitCommand.php - - - message: "#^Left side of && is always false\\.$#" - count: 1 - path: ../src/Composer/Command/InitCommand.php - - message: "#^Only booleans are allowed in a negated boolean, string given\\.$#" count: 1 @@ -510,11 +500,6 @@ parameters: count: 1 path: ../src/Composer/Command/InitCommand.php - - - message: "#^Right side of && is always false\\.$#" - count: 1 - path: ../src/Composer/Command/InitCommand.php - - message: "#^Short ternary operator is not allowed\\. Use null coalesce operator if applicable or consider using long ternary\\.$#" count: 7 @@ -552,11 +537,6 @@ parameters: - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" - count: 2 - path: ../src/Composer/Command/RequireCommand.php - - - - message: "#^Left side of && is always true\\.$#" count: 1 path: ../src/Composer/Command/RequireCommand.php @@ -590,11 +570,6 @@ parameters: count: 1 path: ../src/Composer/Command/RequireCommand.php - - - message: "#^Right side of && is always true\\.$#" - count: 1 - path: ../src/Composer/Command/RequireCommand.php - - message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#" count: 1 @@ -1085,16 +1060,6 @@ parameters: count: 1 path: ../src/Composer/Config/JsonConfigSource.php - - - message: "#^Call to function is_array\\(\\) with array\\ will always evaluate to true\\.$#" - count: 1 - path: ../src/Composer/Console/Application.php - - - - message: "#^Instanceof between Composer\\\\Command\\\\BaseCommand and Composer\\\\Command\\\\BaseCommand will always evaluate to true\\.$#" - count: 1 - path: ../src/Composer/Console/Application.php - - message: "#^Only booleans are allowed in &&, array\\\\|int\\|string\\> given on the left side\\.$#" count: 1 @@ -1460,6 +1425,11 @@ parameters: count: 2 path: ../src/Composer/DependencyResolver/Solver.php + - + message: "#^Method Composer\\\\DependencyResolver\\\\Solver\\:\\:enableDisableLearnedRules\\(\\) is unused\\.$#" + count: 1 + path: ../src/Composer/DependencyResolver/Solver.php + - message: "#^Only booleans are allowed in &&, Composer\\\\DependencyResolver\\\\Rule\\|null given on the left side\\.$#" count: 1 @@ -2030,11 +2000,6 @@ parameters: count: 1 path: ../src/Composer/EventDispatcher/EventDispatcher.php - - - message: "#^Call to function is_callable\\(\\) with callable\\(\\)\\: mixed will always evaluate to true\\.$#" - count: 1 - path: ../src/Composer/EventDispatcher/EventDispatcher.php - - message: "#^Cannot access offset 0 on array\\{0\\: string, 1\\?\\: int\\}\\|int\\|string\\.$#" count: 1 @@ -2180,11 +2145,6 @@ parameters: count: 1 path: ../src/Composer/IO/BaseIO.php - - - message: "#^Instanceof between Symfony\\\\Component\\\\Console\\\\Input\\\\StringInput and Symfony\\\\Component\\\\Console\\\\Input\\\\StreamableInputInterface will always evaluate to true\\.$#" - count: 1 - path: ../src/Composer/IO/BufferIO.php - - message: "#^Only booleans are allowed in a ternary operator condition, Symfony\\\\Component\\\\Console\\\\Formatter\\\\OutputFormatterInterface\\|null given\\.$#" count: 1 @@ -2240,16 +2200,6 @@ parameters: count: 1 path: ../src/Composer/InstalledVersions.php - - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" - count: 1 - path: ../src/Composer/InstalledVersions.php - - - - message: "#^Parameter \\#1 \\$constraints of method Composer\\\\Semver\\\\VersionParser\\:\\:parseConstraints\\(\\) expects string, string\\|null given\\.$#" - count: 1 - path: ../src/Composer/InstalledVersions.php - - message: "#^Cannot call method getPackages\\(\\) on Composer\\\\Repository\\\\LockArrayRepository\\|null\\.$#" count: 1 @@ -2647,12 +2597,7 @@ parameters: - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" - count: 4 - path: ../src/Composer/Package/Archiver/ArchiveManager.php - - - - message: "#^Only booleans are allowed in an if condition, string\\|null given\\.$#" - count: 2 + count: 3 path: ../src/Composer/Package/Archiver/ArchiveManager.php - @@ -3070,21 +3015,6 @@ parameters: count: 1 path: ../src/Composer/Package/Version/VersionGuesser.php - - - message: "#^Strict comparison using \\!\\=\\= between null and array\\{version\\: string\\|null, commit\\: '', pretty_version\\: string\\|null\\} will always evaluate to true\\.$#" - count: 1 - path: ../src/Composer/Package/Version/VersionGuesser.php - - - - message: "#^Strict comparison using \\!\\=\\= between null and array\\{version\\: string\\|null, commit\\: string\\|null, pretty_version\\: string\\|null, feature_version\\?\\: string\\|null, feature_pretty_version\\?\\: string\\|null\\} will always evaluate to true\\.$#" - count: 1 - path: ../src/Composer/Package/Version/VersionGuesser.php - - - - message: "#^Strict comparison using \\!\\=\\= between null and string will always evaluate to true\\.$#" - count: 1 - path: ../src/Composer/Package/Version/VersionGuesser.php - - message: "#^Only booleans are allowed in an if condition, int\\<0, max\\>\\|false given\\.$#" count: 1 @@ -3120,11 +3050,6 @@ parameters: count: 1 path: ../src/Composer/Platform/Runtime.php - - - message: "#^Casting to array\\ something that's already array\\\\.$#" - count: 1 - path: ../src/Composer/Plugin/PluginManager.php - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" count: 3 @@ -3205,11 +3130,6 @@ parameters: count: 2 path: ../src/Composer/Question/StrictConfirmationQuestion.php - - - message: "#^Casting to array\\ something that's already array\\\\.$#" - count: 1 - path: ../src/Composer/Repository/ArrayRepository.php - - message: "#^Method Composer\\\\Repository\\\\ArrayRepository\\:\\:getProviders\\(\\) should return array\\ but returns array\\\\.$#" count: 1 @@ -3415,11 +3335,6 @@ parameters: count: 2 path: ../src/Composer/Repository/FilesystemRepository.php - - - message: "#^Parameter \\#2 \\$content of method Composer\\\\Util\\\\Filesystem\\:\\:filePutContentsIfModified\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: ../src/Composer/Repository/FilesystemRepository.php - - message: "#^Parameter \\#2 \\$installPaths of method Composer\\\\Repository\\\\FilesystemRepository\\:\\:generateInstalledVersions\\(\\) expects array\\, array\\ given\\.$#" count: 1 @@ -3978,11 +3893,6 @@ parameters: count: 1 path: ../src/Composer/Repository/Vcs/SvnDriver.php - - - message: "#^Strict comparison using \\!\\=\\= between string and false will always evaluate to true\\.$#" - count: 2 - path: ../src/Composer/Repository/Vcs/SvnDriver.php - - message: "#^Cannot call method read\\(\\) on Composer\\\\Cache\\|null\\.$#" count: 1 @@ -4303,11 +4213,6 @@ parameters: count: 1 path: ../src/Composer/Util/Http/CurlDownloader.php - - - message: "#^Call to function is_resource\\(\\) with resource will always evaluate to true\\.$#" - count: 2 - path: ../src/Composer/Util/Http/CurlDownloader.php - - message: "#^Cannot access offset 'features' on array\\|false\\.$#" count: 2 @@ -4998,11 +4903,6 @@ parameters: count: 1 path: ../src/Composer/Util/StreamContextFactory.php - - - message: "#^Casting to bool something that's already \\*NEVER\\*\\.$#" - count: 1 - path: ../src/Composer/Util/Svn.php - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" count: 2 @@ -5356,11 +5256,6 @@ parameters: count: 1 path: ../tests/Composer/Test/Installer/InstallerEventTest.php - - - message: "#^Call to function is_array\\(\\) with array\\ will always evaluate to true\\.$#" - count: 1 - path: ../tests/Composer/Test/InstallerTest.php - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" count: 9 @@ -5511,11 +5406,6 @@ parameters: count: 1 path: ../tests/Composer/Test/Platform/VersionTest.php - - - message: "#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) with 'Composer\\\\\\\\Command…' and Composer\\\\Command\\\\BaseCommand will always evaluate to true\\.$#" - count: 1 - path: ../tests/Composer/Test/Plugin/PluginInstallerTest.php - - message: "#^Parameter \\#2 \\$capabilityClassName of method Composer\\\\Plugin\\\\PluginManager\\:\\:getPluginCapability\\(\\) expects class\\-string\\, string given\\.$#" count: 2 diff --git a/src/Composer/Command/CheckPlatformReqsCommand.php b/src/Composer/Command/CheckPlatformReqsCommand.php index 5ac4d6594..e25210075 100644 --- a/src/Composer/Command/CheckPlatformReqsCommand.php +++ b/src/Composer/Command/CheckPlatformReqsCommand.php @@ -69,11 +69,9 @@ EOT } } if (!$input->getOption('no-dev')) { - $requires += $composer->getPackage()->getDevRequires(); - } - - foreach ($requires as $require => $link) { - $requires[$require] = [$link]; + foreach ($composer->getPackage()->getDevRequires() as $require => $link) { + $requires[$require] = [$link]; + } } $installedRepo = new InstalledRepository([$installedRepo, new RootPackageRepository(clone $composer->getPackage())]); diff --git a/src/Composer/Command/PackageDiscoveryTrait.php b/src/Composer/Command/PackageDiscoveryTrait.php index db205a510..1e31abaa3 100644 --- a/src/Composer/Command/PackageDiscoveryTrait.php +++ b/src/Composer/Command/PackageDiscoveryTrait.php @@ -72,7 +72,7 @@ trait PackageDiscoveryTrait // @phpstan-ignore-next-line as RequireCommand does not have the option above so this code is reachable there $file = Factory::getComposerFile(); if (is_file($file) && Filesystem::isReadable($file) && is_array($composer = json_decode((string) file_get_contents($file), true))) { - if (!empty($composer['minimum-stability'])) { + if (isset($composer['minimum-stability'])) { return VersionParser::normalizeStability($composer['minimum-stability']); } } diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php index 8d5cbc0f7..300a7e604 100644 --- a/src/Composer/Downloader/FileDownloader.php +++ b/src/Composer/Downloader/FileDownloader.php @@ -132,7 +132,7 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface $retries = 3; $distUrls = $package->getDistUrls(); - /** @var non-empty-array $urls */ + /** @var array $urls */ $urls = []; foreach ($distUrls as $index => $url) { $processedUrl = $this->processUrl($package, $url); @@ -146,6 +146,7 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface 'cacheKey' => $cacheKeyGenerator($package, $processedUrl), ]; } + assert(count($urls) > 0); $fileName = $this->getFileName($package, $path); $this->filesystem->ensureDirectoryExists($path); diff --git a/src/Composer/InstalledVersions.php b/src/Composer/InstalledVersions.php index 153849aec..51e734a77 100644 --- a/src/Composer/InstalledVersions.php +++ b/src/Composer/InstalledVersions.php @@ -98,7 +98,7 @@ class InstalledVersions { foreach (self::getInstalled() as $installed) { if (isset($installed['versions'][$packageName])) { - return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; } } @@ -119,7 +119,7 @@ class InstalledVersions */ public static function satisfies(VersionParser $parser, $packageName, $constraint) { - $constraint = $parser->parseConstraints($constraint); + $constraint = $parser->parseConstraints((string) $constraint); $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); return $provided->matches($constraint); diff --git a/src/Composer/PHPStan/ConfigReturnTypeExtension.php b/src/Composer/PHPStan/ConfigReturnTypeExtension.php index a1e6359bb..a3081872e 100644 --- a/src/Composer/PHPStan/ConfigReturnTypeExtension.php +++ b/src/Composer/PHPStan/ConfigReturnTypeExtension.php @@ -69,9 +69,11 @@ final class ConfigReturnTypeExtension implements DynamicMethodReturnTypeExtensio } $keyType = $scope->getType($args[0]->value); - if ($keyType instanceof ConstantStringType) { - if (isset($this->properties[$keyType->getValue()])) { - return $this->properties[$keyType->getValue()]; + if (count($keyType->getConstantStrings()) > 0) { + foreach ($keyType->getConstantStrings() as $constantString) { + if (isset($this->properties[$constantString->getValue()])) { + return $this->properties[$constantString->getValue()]; + } } } diff --git a/src/Composer/Package/Archiver/ZipArchiver.php b/src/Composer/Package/Archiver/ZipArchiver.php index 71f512e5c..f8495e26b 100644 --- a/src/Composer/Package/Archiver/ZipArchiver.php +++ b/src/Composer/Package/Archiver/ZipArchiver.php @@ -38,7 +38,7 @@ class ZipArchiver implements ArchiverInterface if ($res === true) { $files = new ArchivableFilesFinder($sources, $excludes, $ignoreFilters); foreach ($files as $file) { - /** @var \SplFileInfo $file */ + /** @var \Symfony\Component\Finder\SplFileInfo $file */ $filepath = strtr($file->getPath()."/".$file->getFilename(), '\\', '/'); $localname = $filepath; if (strpos($localname, $sources . '/') === 0) { diff --git a/src/Composer/Package/Version/VersionGuesser.php b/src/Composer/Package/Version/VersionGuesser.php index d7085c5d5..46116f0b7 100644 --- a/src/Composer/Package/Version/VersionGuesser.php +++ b/src/Composer/Package/Version/VersionGuesser.php @@ -76,7 +76,7 @@ class VersionGuesser } $versionData = $this->guessGitVersion($packageConfig, $path); - if (null !== $versionData && null !== $versionData['version']) { + if (null !== $versionData['version']) { return $this->postprocess($versionData); } @@ -86,7 +86,7 @@ class VersionGuesser } $versionData = $this->guessFossilVersion($path); - if (null !== $versionData && null !== $versionData['version']) { + if (null !== $versionData['version']) { return $this->postprocess($versionData); } diff --git a/src/Composer/SelfUpdate/Versions.php b/src/Composer/SelfUpdate/Versions.php index b6145fc48..045fb22a7 100644 --- a/src/Composer/SelfUpdate/Versions.php +++ b/src/Composer/SelfUpdate/Versions.php @@ -64,8 +64,8 @@ class Versions public function setChannel(string $channel, ?IOInterface $io = null): void { - if (!in_array($channel, self::$channels, true)) { - throw new \InvalidArgumentException('Invalid channel '.$channel.', must be one of: ' . implode(', ', self::$channels)); + if (!in_array($channel, self::CHANNELS, true)) { + throw new \InvalidArgumentException('Invalid channel '.$channel.', must be one of: ' . implode(', ', self::CHANNELS)); } $channelFile = $this->config->get('home').'/update-channel'; diff --git a/tests/Composer/Test/InstallerTest.php b/tests/Composer/Test/InstallerTest.php index 810e2271d..eea6f0d73 100644 --- a/tests/Composer/Test/InstallerTest.php +++ b/tests/Composer/Test/InstallerTest.php @@ -102,9 +102,6 @@ class InstallerTest extends TestCase $repositoryManager = new RepositoryManager($io, $config, $httpDownloader, $eventDispatcher); $repositoryManager->setLocalRepository(new InstalledArrayRepository()); - if (!is_array($repositories)) { - $repositories = [$repositories]; - } foreach ($repositories as $repository) { $repositoryManager->addRepository($repository); } diff --git a/tests/Composer/Test/Mock/ProcessExecutorMock.php b/tests/Composer/Test/Mock/ProcessExecutorMock.php index 96a4a9915..9f633a626 100644 --- a/tests/Composer/Test/Mock/ProcessExecutorMock.php +++ b/tests/Composer/Test/Mock/ProcessExecutorMock.php @@ -63,7 +63,7 @@ class ProcessExecutorMock extends ProcessExecutor */ public function expects(array $expectations, bool $strict = false, array $defaultHandler = ['return' => 0, 'stdout' => '', 'stderr' => '']): void { - /** @var array{cmd: string|list, return: int, stdout: string, stderr: string, callback: callable} $default */ + /** @var array{cmd: string|list, return: int, stdout: string, stderr: string, callback: callable|null} $default */ $default = ['cmd' => '', 'return' => 0, 'stdout' => '', 'stderr' => '', 'callback' => null]; $this->expectations = array_map(static function ($expect) use ($default): array { if (is_string($expect)) { diff --git a/tests/Composer/Test/Util/RemoteFilesystemTest.php b/tests/Composer/Test/Util/RemoteFilesystemTest.php index 1dc2ceebe..a54e700a8 100644 --- a/tests/Composer/Test/Util/RemoteFilesystemTest.php +++ b/tests/Composer/Test/Util/RemoteFilesystemTest.php @@ -280,7 +280,6 @@ class RemoteFilesystemTest extends TestCase */ public function testBitBucketPublicDownload(string $url, string $contents): void { - /** @var ConsoleIO $io */ $io = $this ->getMockBuilder('Composer\IO\ConsoleIO') ->disableOriginalConstructor()