1
0
Fork 0

Update deps, constrain a few types to non-empty-strings

pull/11113/head
Jordi Boggiano 2022-10-11 16:51:47 +02:00
parent 436a112651
commit 8600894003
34 changed files with 246 additions and 183 deletions

74
composer.lock generated
View File

@ -941,16 +941,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v5.4.12", "version": "v5.4.13",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "c072aa8f724c3af64e2c7a96b796a4863d24dba1" "reference": "3f97f6c7b7e26848a90c0c0cfb91eeb2bb8618be"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/c072aa8f724c3af64e2c7a96b796a4863d24dba1", "url": "https://api.github.com/repos/symfony/console/zipball/3f97f6c7b7e26848a90c0c0cfb91eeb2bb8618be",
"reference": "c072aa8f724c3af64e2c7a96b796a4863d24dba1", "reference": "3f97f6c7b7e26848a90c0c0cfb91eeb2bb8618be",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1020,7 +1020,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v5.4.12" "source": "https://github.com/symfony/console/tree/v5.4.13"
}, },
"funding": [ "funding": [
{ {
@ -1036,7 +1036,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-08-17T13:18:05+00:00" "time": "2022-08-26T13:50:20+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
@ -1107,16 +1107,16 @@
}, },
{ {
"name": "symfony/filesystem", "name": "symfony/filesystem",
"version": "v5.4.12", "version": "v5.4.13",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/filesystem.git", "url": "https://github.com/symfony/filesystem.git",
"reference": "2d67c1f9a1937406a9be3171b4b22250c0a11447" "reference": "ac09569844a9109a5966b9438fc29113ce77cf51"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/2d67c1f9a1937406a9be3171b4b22250c0a11447", "url": "https://api.github.com/repos/symfony/filesystem/zipball/ac09569844a9109a5966b9438fc29113ce77cf51",
"reference": "2d67c1f9a1937406a9be3171b4b22250c0a11447", "reference": "ac09569844a9109a5966b9438fc29113ce77cf51",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1151,7 +1151,7 @@
"description": "Provides basic utilities for the filesystem", "description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/filesystem/tree/v5.4.12" "source": "https://github.com/symfony/filesystem/tree/v5.4.13"
}, },
"funding": [ "funding": [
{ {
@ -1167,7 +1167,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-08-02T13:48:16+00:00" "time": "2022-09-21T19:53:16+00:00"
}, },
{ {
"name": "symfony/finder", "name": "symfony/finder",
@ -1871,16 +1871,16 @@
}, },
{ {
"name": "symfony/string", "name": "symfony/string",
"version": "v5.4.12", "version": "v5.4.13",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/string.git", "url": "https://github.com/symfony/string.git",
"reference": "2fc515e512d721bf31ea76bd02fe23ada4640058" "reference": "2900c668a32138a34118740de3e4d5a701801f53"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/2fc515e512d721bf31ea76bd02fe23ada4640058", "url": "https://api.github.com/repos/symfony/string/zipball/2900c668a32138a34118740de3e4d5a701801f53",
"reference": "2fc515e512d721bf31ea76bd02fe23ada4640058", "reference": "2900c668a32138a34118740de3e4d5a701801f53",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1937,7 +1937,7 @@
"utf8" "utf8"
], ],
"support": { "support": {
"source": "https://github.com/symfony/string/tree/v5.4.12" "source": "https://github.com/symfony/string/tree/v5.4.13"
}, },
"funding": [ "funding": [
{ {
@ -1953,22 +1953,22 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-08-12T17:03:11+00:00" "time": "2022-09-01T01:52:16+00:00"
} }
], ],
"packages-dev": [ "packages-dev": [
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.8.5", "version": "1.8.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "f6598a5ff12ca4499a836815e08b4d77a2ddeb20" "reference": "08310ce271984587e2a4cda94e1ac66510a6ea07"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/f6598a5ff12ca4499a836815e08b4d77a2ddeb20", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/08310ce271984587e2a4cda94e1ac66510a6ea07",
"reference": "f6598a5ff12ca4499a836815e08b4d77a2ddeb20", "reference": "08310ce271984587e2a4cda94e1ac66510a6ea07",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1998,7 +1998,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/phpstan/phpstan/issues", "issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/1.8.5" "source": "https://github.com/phpstan/phpstan/tree/1.8.8"
}, },
"funding": [ "funding": [
{ {
@ -2014,7 +2014,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-09-07T16:05:32+00:00" "time": "2022-10-06T12:51:57+00:00"
}, },
{ {
"name": "phpstan/phpstan-deprecation-rules", "name": "phpstan/phpstan-deprecation-rules",
@ -2120,21 +2120,21 @@
}, },
{ {
"name": "phpstan/phpstan-strict-rules", "name": "phpstan/phpstan-strict-rules",
"version": "1.4.3", "version": "1.4.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git", "url": "https://github.com/phpstan/phpstan-strict-rules.git",
"reference": "431b3d6e8040075de196680cd5bc95735987b4ae" "reference": "23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/431b3d6e8040075de196680cd5bc95735987b4ae", "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6",
"reference": "431b3d6e8040075de196680cd5bc95735987b4ae", "reference": "23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.2 || ^8.0", "php": "^7.2 || ^8.0",
"phpstan/phpstan": "^1.8.3" "phpstan/phpstan": "^1.8.6"
}, },
"require-dev": { "require-dev": {
"nikic/php-parser": "^4.13.0", "nikic/php-parser": "^4.13.0",
@ -2162,22 +2162,22 @@
"description": "Extra strict and opinionated rules for PHPStan", "description": "Extra strict and opinionated rules for PHPStan",
"support": { "support": {
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues", "issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.4.3" "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.4.4"
}, },
"time": "2022-08-26T15:05:46+00:00" "time": "2022-09-21T11:38:17+00:00"
}, },
{ {
"name": "phpstan/phpstan-symfony", "name": "phpstan/phpstan-symfony",
"version": "1.2.13", "version": "1.2.14",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan-symfony.git", "url": "https://github.com/phpstan/phpstan-symfony.git",
"reference": "016e441a19a2af79ca0c60920ba0d61747b4e855" "reference": "f7dd737329504115adaa987697a759a66dd2ee8a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/016e441a19a2af79ca0c60920ba0d61747b4e855", "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/f7dd737329504115adaa987697a759a66dd2ee8a",
"reference": "016e441a19a2af79ca0c60920ba0d61747b4e855", "reference": "f7dd737329504115adaa987697a759a66dd2ee8a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2233,9 +2233,9 @@
"description": "Symfony Framework extensions and rules for PHPStan", "description": "Symfony Framework extensions and rules for PHPStan",
"support": { "support": {
"issues": "https://github.com/phpstan/phpstan-symfony/issues", "issues": "https://github.com/phpstan/phpstan-symfony/issues",
"source": "https://github.com/phpstan/phpstan-symfony/tree/1.2.13" "source": "https://github.com/phpstan/phpstan-symfony/tree/1.2.14"
}, },
"time": "2022-08-28T13:34:45+00:00" "time": "2022-10-05T11:19:29+00:00"
}, },
{ {
"name": "symfony/phpunit-bridge", "name": "symfony/phpunit-bridge",

View File

@ -722,7 +722,7 @@ EOT
$out($iniMessage, 'comment'); $out($iniMessage, 'comment');
} }
return !$warnings && !$errors ? true : $output; return count($warnings) === 0 && count($errors) === 0 ? true : $output;
} }
/** /**

View File

@ -123,7 +123,7 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
$retries = 3; $retries = 3;
$distUrls = $package->getDistUrls(); $distUrls = $package->getDistUrls();
/** @var array<array{base: string, processed: string, cacheKey: string}> $urls */ /** @var non-empty-array<array{base: non-empty-string, processed: non-empty-string, cacheKey: string}> $urls */
$urls = []; $urls = [];
foreach ($distUrls as $index => $url) { foreach ($distUrls as $index => $url) {
$processedUrl = $this->processUrl($package, $url); $processedUrl = $this->processUrl($package, $url);
@ -151,7 +151,6 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
$accept = null; $accept = null;
$reject = null; $reject = null;
$download = function () use ($io, $output, $httpDownloader, $cache, $cacheKeyGenerator, $eventDispatcher, $package, $fileName, &$urls, &$accept, &$reject) { $download = function () use ($io, $output, $httpDownloader, $cache, $cacheKeyGenerator, $eventDispatcher, $package, $fileName, &$urls, &$accept, &$reject) {
/** @var array{base: string, processed: string, cacheKey: string} $url */
$url = reset($urls); $url = reset($urls);
$index = key($urls); $index = key($urls);
@ -435,9 +434,9 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
* Process the download url * Process the download url
* *
* @param PackageInterface $package package the url is coming from * @param PackageInterface $package package the url is coming from
* @param string $url download url * @param non-empty-string $url download url
* @throws \RuntimeException If any problem with the url * @throws \RuntimeException If any problem with the url
* @return string url * @return non-empty-string url
*/ */
protected function processUrl(PackageInterface $package, string $url): string protected function processUrl(PackageInterface $package, string $url): string
{ {

View File

@ -38,17 +38,17 @@ class Package extends BasePackage
protected $sourceUrl; protected $sourceUrl;
/** @var ?string */ /** @var ?string */
protected $sourceReference; protected $sourceReference;
/** @var ?array<int, array{url: string, preferred: bool}> */ /** @var ?array<int, array{url: non-empty-string, preferred: bool}> */
protected $sourceMirrors; protected $sourceMirrors;
/** @var ?string */ /** @var ?non-empty-string */
protected $distType; protected $distType;
/** @var ?string */ /** @var ?non-empty-string */
protected $distUrl; protected $distUrl;
/** @var ?string */ /** @var ?string */
protected $distReference; protected $distReference;
/** @var ?string */ /** @var ?string */
protected $distSha1Checksum; protected $distSha1Checksum;
/** @var ?array<int, array{url: string, preferred: bool}> */ /** @var ?array<int, array{url: non-empty-string, preferred: bool}> */
protected $distMirrors; protected $distMirrors;
/** @var string */ /** @var string */
protected $version; protected $version;
@ -276,7 +276,7 @@ class Package extends BasePackage
*/ */
public function setDistType(?string $type): void public function setDistType(?string $type): void
{ {
$this->distType = $type; $this->distType = $type === '' ? null : $type;
} }
/** /**
@ -288,11 +288,11 @@ class Package extends BasePackage
} }
/** /**
* @param string $url * @param string|null $url
*/ */
public function setDistUrl(?string $url): void public function setDistUrl(?string $url): void
{ {
$this->distUrl = $url; $this->distUrl = $url === '' ? null : $url;
} }
/** /**
@ -658,9 +658,9 @@ class Package extends BasePackage
/** /**
* @param mixed[]|null $mirrors * @param mixed[]|null $mirrors
* *
* @return string[] * @return non-empty-string[]
* *
* @phpstan-param list<array{url: string, preferred: bool}>|null $mirrors * @phpstan-param list<array{url: non-empty-string, preferred: bool}>|null $mirrors
*/ */
protected function getUrls(?string $url, ?array $mirrors, ?string $ref, ?string $type, string $urlType): array protected function getUrls(?string $url, ?array $mirrors, ?string $ref, ?string $type, string $urlType): array
{ {

View File

@ -141,12 +141,12 @@ interface PackageInterface
/** /**
* Returns the source mirrors of this package * Returns the source mirrors of this package
* *
* @return ?array<int, array{url: string, preferred: bool}> * @return ?array<int, array{url: non-empty-string, preferred: bool}>
*/ */
public function getSourceMirrors(): ?array; public function getSourceMirrors(): ?array;
/** /**
* @param null|array<int, array{url: string, preferred: bool}> $mirrors * @param null|array<int, array{url: non-empty-string, preferred: bool}> $mirrors
*/ */
public function setSourceMirrors(?array $mirrors): void; public function setSourceMirrors(?array $mirrors): void;
@ -160,14 +160,14 @@ interface PackageInterface
/** /**
* Returns the url of the distribution archive of this version * Returns the url of the distribution archive of this version
* *
* @return ?string * @return ?non-empty-string
*/ */
public function getDistUrl(): ?string; public function getDistUrl(): ?string;
/** /**
* Returns the urls of the distribution archive of this version, including mirrors * Returns the urls of the distribution archive of this version, including mirrors
* *
* @return string[] * @return non-empty-string[]
*/ */
public function getDistUrls(): array; public function getDistUrls(): array;
@ -188,12 +188,12 @@ interface PackageInterface
/** /**
* Returns the dist mirrors of this package * Returns the dist mirrors of this package
* *
* @return ?array<int, array{url: string, preferred: bool}> * @return ?array<int, array{url: non-empty-string, preferred: bool}>
*/ */
public function getDistMirrors(): ?array; public function getDistMirrors(): ?array;
/** /**
* @param null|array<int, array{url: string, preferred: bool}> $mirrors * @param null|array<int, array{url: non-empty-string, preferred: bool}> $mirrors
*/ */
public function setDistMirrors(?array $mirrors): void; public function setDistMirrors(?array $mirrors): void;

View File

@ -28,7 +28,7 @@ class PreFileDownloadEvent extends Event
private $httpDownloader; private $httpDownloader;
/** /**
* @var string * @var non-empty-string
*/ */
private $processedUrl; private $processedUrl;
@ -55,8 +55,9 @@ class PreFileDownloadEvent extends Event
/** /**
* Constructor. * Constructor.
* *
* @param string $name The event name * @param string $name The event name
* @param mixed $context * @param mixed $context
* @param non-empty-string $processedUrl
*/ */
public function __construct(string $name, HttpDownloader $httpDownloader, string $processedUrl, string $type, $context = null) public function __construct(string $name, HttpDownloader $httpDownloader, string $processedUrl, string $type, $context = null)
{ {
@ -74,6 +75,8 @@ class PreFileDownloadEvent extends Event
/** /**
* Retrieves the processed URL that will be downloaded. * Retrieves the processed URL that will be downloaded.
*
* @return non-empty-string
*/ */
public function getProcessedUrl(): string public function getProcessedUrl(): string
{ {
@ -83,7 +86,7 @@ class PreFileDownloadEvent extends Event
/** /**
* Sets the processed URL that will be downloaded. * Sets the processed URL that will be downloaded.
* *
* @param string $processedUrl New processed URL * @param non-empty-string $processedUrl New processed URL
*/ */
public function setProcessedUrl(string $processedUrl): void public function setProcessedUrl(string $processedUrl): void
{ {

View File

@ -55,9 +55,9 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
private $repoConfig; private $repoConfig;
/** @var mixed[] */ /** @var mixed[] */
private $options; private $options;
/** @var string */ /** @var non-empty-string */
private $url; private $url;
/** @var string */ /** @var non-empty-string */
private $baseUrl; private $baseUrl;
/** @var IOInterface */ /** @var IOInterface */
private $io; private $io;
@ -67,17 +67,17 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
private $loop; private $loop;
/** @var Cache */ /** @var Cache */
protected $cache; protected $cache;
/** @var ?string */ /** @var ?non-empty-string */
protected $notifyUrl = null; protected $notifyUrl = null;
/** @var ?string */ /** @var ?non-empty-string */
protected $searchUrl = null; protected $searchUrl = null;
/** @var ?string a URL containing %package% which can be queried to get providers of a given name */ /** @var ?non-empty-string a URL containing %package% which can be queried to get providers of a given name */
protected $providersApiUrl = null; protected $providersApiUrl = null;
/** @var bool */ /** @var bool */
protected $hasProviders = false; protected $hasProviders = false;
/** @var ?string */ /** @var ?non-empty-string */
protected $providersUrl = null; protected $providersUrl = null;
/** @var ?string */ /** @var ?non-empty-string */
protected $listUrl = null; protected $listUrl = null;
/** @var bool Indicates whether a comprehensive list of packages this repository might provide is expressed in the repository root. **/ /** @var bool Indicates whether a comprehensive list of packages this repository might provide is expressed in the repository root. **/
protected $hasAvailablePackageList = false; protected $hasAvailablePackageList = false;
@ -85,7 +85,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
protected $availablePackages = null; protected $availablePackages = null;
/** @var ?array<non-empty-string> */ /** @var ?array<non-empty-string> */
protected $availablePackagePatterns = null; protected $availablePackagePatterns = null;
/** @var ?string */ /** @var ?non-empty-string */
protected $lazyProvidersUrl = null; protected $lazyProvidersUrl = null;
/** @var ?array<string, array{sha256: string}> */ /** @var ?array<string, array{sha256: string}> */
protected $providerListing; protected $providerListing;
@ -95,9 +95,9 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
private $allowSslDowngrade = false; private $allowSslDowngrade = false;
/** @var ?EventDispatcher */ /** @var ?EventDispatcher */
private $eventDispatcher; private $eventDispatcher;
/** @var ?array<string, array<int, array{url: string, preferred: bool}>> */ /** @var ?array<string, array<int, array{url: non-empty-string, preferred: bool}>> */
private $sourceMirrors; private $sourceMirrors;
/** @var ?array<int, array{url: string, preferred: bool}> */ /** @var ?array<int, array{url: non-empty-string, preferred: bool}> */
private $distMirrors; private $distMirrors;
/** @var bool */ /** @var bool */
private $degradedMode = false; private $degradedMode = false;
@ -133,7 +133,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
/** /**
* @param array<string, mixed> $repoConfig * @param array<string, mixed> $repoConfig
* @phpstan-param array{url: string, options?: mixed[], type?: 'composer', allow_ssl_downgrade?: bool} $repoConfig * @phpstan-param array{url: non-empty-string, options?: mixed[], type?: 'composer', allow_ssl_downgrade?: bool} $repoConfig
*/ */
public function __construct(array $repoConfig, IOInterface $io, Config $config, HttpDownloader $httpDownloader, ?EventDispatcher $eventDispatcher = null) public function __construct(array $repoConfig, IOInterface $io, Config $config, HttpDownloader $httpDownloader, ?EventDispatcher $eventDispatcher = null)
{ {
@ -143,8 +143,11 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
$repoConfig['url'] = 'http://'.$repoConfig['url']; $repoConfig['url'] = 'http://'.$repoConfig['url'];
} }
$repoConfig['url'] = rtrim($repoConfig['url'], '/'); $repoConfig['url'] = rtrim($repoConfig['url'], '/');
if ($repoConfig['url'] === '') {
throw new \InvalidArgumentException('The repository url must not be an empty string');
}
if (strpos($repoConfig['url'], 'https?') === 0) { if (str_starts_with($repoConfig['url'], 'https?')) {
$repoConfig['url'] = (extension_loaded('openssl') ? 'https' : 'http') . substr($repoConfig['url'], 6); $repoConfig['url'] = (extension_loaded('openssl') ? 'https' : 'http') . substr($repoConfig['url'], 6);
} }
@ -168,7 +171,9 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
$this->url = $match['proto'].'://repo.packagist.org'; $this->url = $match['proto'].'://repo.packagist.org';
} }
$this->baseUrl = rtrim(Preg::replace('{(?:/[^/\\\\]+\.json)?(?:[?#].*)?$}', '', $this->url), '/'); $baseUrl = rtrim(Preg::replace('{(?:/[^/\\\\]+\.json)?(?:[?#].*)?$}', '', $this->url), '/');
assert($baseUrl !== '');
$this->baseUrl = $baseUrl;
$this->io = $io; $this->io = $io;
$this->cache = new Cache($io, $config->get('cache-repo-dir').'/'.Preg::replace('{[^a-z0-9.]}i', '-', Url::sanitize($this->url)), 'a-z0-9.$~'); $this->cache = new Cache($io, $config->get('cache-repo-dir').'/'.Preg::replace('{[^a-z0-9.]}i', '-', Url::sanitize($this->url)), 'a-z0-9.$~');
$this->cache->setReadOnly($config->get('cache-read-only')); $this->cache->setReadOnly($config->get('cache-read-only'));
@ -1265,6 +1270,10 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
return $this->rootData = $data; return $this->rootData = $data;
} }
/**
* @param non-empty-string $url
* @return non-empty-string
*/
private function canonicalizeUrl(string $url): string private function canonicalizeUrl(string $url): string
{ {
if ('/' === $url[0]) { if ('/' === $url[0]) {
@ -1416,6 +1425,10 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
*/ */
protected function fetchFile(string $filename, ?string $cacheKey = null, ?string $sha256 = null, bool $storeLastModifiedTime = false) protected function fetchFile(string $filename, ?string $cacheKey = null, ?string $sha256 = null, bool $storeLastModifiedTime = false)
{ {
if ('' === $filename) {
throw new \InvalidArgumentException('$filename should not be an empty string');
}
if (null === $cacheKey) { if (null === $cacheKey) {
$cacheKey = $filename; $cacheKey = $filename;
$filename = $this->baseUrl.'/'.$filename; $filename = $this->baseUrl.'/'.$filename;
@ -1519,6 +1532,10 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
*/ */
private function fetchFileIfLastModified(string $filename, string $cacheKey, string $lastModifiedTime) private function fetchFileIfLastModified(string $filename, string $cacheKey, string $lastModifiedTime)
{ {
if ('' === $filename) {
throw new \InvalidArgumentException('$filename should not be an empty string');
}
try { try {
$options = $this->options; $options = $this->options;
if ($this->eventDispatcher) { if ($this->eventDispatcher) {
@ -1578,6 +1595,10 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
private function asyncFetchFile(string $filename, string $cacheKey, ?string $lastModifiedTime = null): PromiseInterface private function asyncFetchFile(string $filename, string $cacheKey, ?string $lastModifiedTime = null): PromiseInterface
{ {
if ('' === $filename) {
throw new \InvalidArgumentException('$filename should not be an empty string');
}
if (isset($this->packagesNotFoundCache[$filename])) { if (isset($this->packagesNotFoundCache[$filename])) {
return \React\Promise\resolve(['packages' => []]); return \React\Promise\resolve(['packages' => []]);
} }

View File

@ -21,6 +21,10 @@ use Composer\Pcre\Preg;
*/ */
class ComposerMirror class ComposerMirror
{ {
/**
* @param non-empty-string $mirrorUrl
* @return non-empty-string
*/
public static function processUrl(string $mirrorUrl, string $packageName, string $version, ?string $reference, ?string $type, ?string $prettyVersion = null): string public static function processUrl(string $mirrorUrl, string $packageName, string $version, ?string $reference, ?string $type, ?string $prettyVersion = null): string
{ {
if ($reference) { if ($reference) {
@ -35,9 +39,16 @@ class ComposerMirror
$to[] = $prettyVersion; $to[] = $prettyVersion;
} }
return str_replace($from, $to, $mirrorUrl); $url = str_replace($from, $to, $mirrorUrl);
assert($url !== '');
return $url;
} }
/**
* @param non-empty-string $mirrorUrl
* @return string
*/
public static function processGitUrl(string $mirrorUrl, string $packageName, string $url, ?string $type): string public static function processGitUrl(string $mirrorUrl, string $packageName, string $url, ?string $type): string
{ {
if (Preg::isMatch('#^(?:(?:https?|git)://github\.com/|git@github\.com:)([^/]+)/(.+?)(?:\.git)?$#', $url, $match)) { if (Preg::isMatch('#^(?:(?:https?|git)://github\.com/|git@github\.com:)([^/]+)/(.+?)(?:\.git)?$#', $url, $match)) {
@ -55,6 +66,10 @@ class ComposerMirror
); );
} }
/**
* @param non-empty-string $mirrorUrl
* @return string
*/
public static function processHgUrl(string $mirrorUrl, string $packageName, string $url, string $type): string public static function processHgUrl(string $mirrorUrl, string $packageName, string $url, string $type): string
{ {
return self::processGitUrl($mirrorUrl, $packageName, $url, $type); return self::processGitUrl($mirrorUrl, $packageName, $url, $type);

View File

@ -29,7 +29,7 @@ use React\Promise\Promise;
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
* @author Nicolas Grekas <p@tchwork.com> * @author Nicolas Grekas <p@tchwork.com>
* @phpstan-type Attributes array{retryAuthFailure: bool, redirects: int<0, max>, retries: int<0, max>, storeAuth: 'prompt'|bool} * @phpstan-type Attributes array{retryAuthFailure: bool, redirects: int<0, max>, retries: int<0, max>, storeAuth: 'prompt'|bool}
* @phpstan-type Job array{url: string, origin: string, attributes: Attributes, options: mixed[], progress: mixed[], curlHandle: resource, filename: string|null, headerHandle: resource, bodyHandle: resource, resolve: callable, reject: callable} * @phpstan-type Job array{url: non-empty-string, origin: string, attributes: Attributes, options: mixed[], progress: mixed[], curlHandle: \CurlHandle, filename: string|null, headerHandle: resource, bodyHandle: resource, resolve: callable, reject: callable}
*/ */
class CurlDownloader class CurlDownloader
{ {
@ -125,6 +125,7 @@ class CurlDownloader
/** /**
* @param mixed[] $options * @param mixed[] $options
* @param non-empty-string $url
* *
* @return int internal job id * @return int internal job id
*/ */
@ -143,16 +144,18 @@ class CurlDownloader
* @param mixed[] $options * @param mixed[] $options
* *
* @param array{retryAuthFailure?: bool, redirects?: int<0, max>, retries?: int<0, max>, storeAuth?: 'prompt'|bool} $attributes * @param array{retryAuthFailure?: bool, redirects?: int<0, max>, retries?: int<0, max>, storeAuth?: 'prompt'|bool} $attributes
* @param non-empty-string $url
* *
* @return int internal job id * @return int internal job id
*/ */
private function initDownload(callable $resolve, callable $reject, string $origin, string $url, array $options, ?string $copyTo = null, array $attributes = []): int private function initDownload(callable $resolve, callable $reject, string $origin, string $url, array $options, ?string $copyTo = null, array $attributes = []): int
{ {
// set defaults in a PHPStan-happy way (array_merge is not well supported) $attributes = array_merge([
$attributes['retryAuthFailure'] = $attributes['retryAuthFailure'] ?? true; 'retryAuthFailure' => true,
$attributes['redirects'] = $attributes['redirects'] ?? 0; 'redirects' => 0,
$attributes['retries'] = $attributes['retries'] ?? 0; 'retries' => 0,
$attributes['storeAuth'] = $attributes['storeAuth'] ?? false; 'storeAuth' => false,
], $attributes);
$originalOptions = $options; $originalOptions = $options;
@ -167,22 +170,24 @@ class CurlDownloader
throw new \RuntimeException('Failed to open a temp stream to store curl headers'); throw new \RuntimeException('Failed to open a temp stream to store curl headers');
} }
if ($copyTo) { if ($copyTo !== null) {
$errorMessage = ''; $bodyTarget = $copyTo.'~';
// @phpstan-ignore-next-line
set_error_handler(static function ($code, $msg) use (&$errorMessage): void {
if ($errorMessage) {
$errorMessage .= "\n";
}
$errorMessage .= Preg::replace('{^fopen\(.*?\): }', '', $msg);
});
$bodyHandle = fopen($copyTo.'~', 'w+b');
restore_error_handler();
if (!$bodyHandle) {
throw new TransportException('The "'.$url.'" file could not be written to '.$copyTo.': '.$errorMessage);
}
} else { } else {
$bodyHandle = @fopen('php://temp/maxmemory:524288', 'w+b'); $bodyTarget = 'php://temp/maxmemory:524288';
}
$errorMessage = '';
// @phpstan-ignore-next-line
set_error_handler(static function ($code, $msg) use (&$errorMessage): void {
if ($errorMessage) {
$errorMessage .= "\n";
}
$errorMessage .= Preg::replace('{^fopen\(.*?\): }', '', $msg);
});
$bodyHandle = fopen($bodyTarget, 'w+b');
restore_error_handler();
if (false === $bodyHandle) {
throw new TransportException('The "'.$url.'" file could not be written to '.($copyTo ?? 'a temporary file').': '.$errorMessage);
} }
curl_setopt($curlHandle, CURLOPT_URL, $url); curl_setopt($curlHandle, CURLOPT_URL, $url);
@ -229,7 +234,9 @@ class CurlDownloader
// Always set CURLOPT_PROXY to enable/disable proxy handling // Always set CURLOPT_PROXY to enable/disable proxy handling
// Any proxy authorization is included in the proxy url // Any proxy authorization is included in the proxy url
$proxy = $this->proxyManager->getProxyForRequest($url); $proxy = $this->proxyManager->getProxyForRequest($url);
curl_setopt($curlHandle, CURLOPT_PROXY, $proxy->getUrl()); if ($proxy->getUrl() !== '') {
curl_setopt($curlHandle, CURLOPT_PROXY, $proxy->getUrl());
}
// Curl needs certificate locations for secure proxies. // Curl needs certificate locations for secure proxies.
// CURLOPT_PROXY_SSL_VERIFY_PEER/HOST are enabled by default // CURLOPT_PROXY_SSL_VERIFY_PEER/HOST are enabled by default
@ -373,8 +380,8 @@ class CurlDownloader
rewind($job['bodyHandle']); rewind($job['bodyHandle']);
$contents = stream_get_contents($job['bodyHandle']); $contents = stream_get_contents($job['bodyHandle']);
} }
$response = new CurlResponse(['url' => $progress['url']], $statusCode, $headers, $contents, $progress); $response = new CurlResponse(['url' => $job['url']], $statusCode, $headers, $contents, $progress);
$this->io->writeError('['.$statusCode.'] '.Url::sanitize($progress['url']), true, IOInterface::DEBUG); $this->io->writeError('['.$statusCode.'] '.Url::sanitize($job['url']), true, IOInterface::DEBUG);
} else { } else {
$maxFileSize = $job['options']['max_file_size'] ?? null; $maxFileSize = $job['options']['max_file_size'] ?? null;
rewind($job['bodyHandle']); rewind($job['bodyHandle']);
@ -389,8 +396,8 @@ class CurlDownloader
$contents = stream_get_contents($job['bodyHandle']); $contents = stream_get_contents($job['bodyHandle']);
} }
$response = new CurlResponse(['url' => $progress['url']], $statusCode, $headers, $contents, $progress); $response = new CurlResponse(['url' => $job['url']], $statusCode, $headers, $contents, $progress);
$this->io->writeError('['.$statusCode.'] '.Url::sanitize($progress['url']), true, IOInterface::DEBUG); $this->io->writeError('['.$statusCode.'] '.Url::sanitize($job['url']), true, IOInterface::DEBUG);
} }
fclose($job['bodyHandle']); fclose($job['bodyHandle']);
@ -456,9 +463,6 @@ class CurlDownloader
} }
foreach ($this->jobs as $i => $curlHandle) { foreach ($this->jobs as $i => $curlHandle) {
if (!isset($this->jobs[$i])) {
continue;
}
$curlHandle = $this->jobs[$i]['curlHandle']; $curlHandle = $this->jobs[$i]['curlHandle'];
$progress = array_diff_key(curl_getinfo($curlHandle), self::$timeInfo); $progress = array_diff_key(curl_getinfo($curlHandle), self::$timeInfo);
@ -569,6 +573,7 @@ class CurlDownloader
/** /**
* @param Job $job * @param Job $job
* @param non-empty-string $url
* *
* @param array{retryAuthFailure?: bool, redirects?: int<0, max>, storeAuth?: 'prompt'|bool, retries?: int<1, max>} $attributes * @param array{retryAuthFailure?: bool, redirects?: int<0, max>, storeAuth?: 'prompt'|bool, retries?: int<1, max>} $attributes
*/ */
@ -586,6 +591,7 @@ class CurlDownloader
/** /**
* @param Job $job * @param Job $job
* @param non-empty-string $url
* *
* @param array{retryAuthFailure?: bool, redirects?: int<0, max>, storeAuth?: 'prompt'|bool, retries: int<1, max>} $attributes * @param array{retryAuthFailure?: bool, redirects?: int<0, max>, storeAuth?: 'prompt'|bool, retries: int<1, max>} $attributes
*/ */

View File

@ -74,6 +74,8 @@ class ProxyManager
/** /**
* Returns a RequestProxy instance for the request url * Returns a RequestProxy instance for the request url
*
* @param non-empty-string $requestUrl
*/ */
public function getProxyForRequest(string $requestUrl): RequestProxy public function getProxyForRequest(string $requestUrl): RequestProxy
{ {

View File

@ -17,7 +17,7 @@ use Composer\Pcre\Preg;
use Composer\Util\HttpDownloader; use Composer\Util\HttpDownloader;
/** /**
* @phpstan-import-type Request from HttpDownloader * @phpstan-type Request array{url: non-empty-string, options?: mixed[], copyTo?: string|null}
*/ */
class Response class Response
{ {
@ -31,7 +31,7 @@ class Response
private $body; private $body;
/** /**
* @param Request $request * @param Request $request
* @param list<string> $headers * @param list<string> $headers
*/ */
public function __construct(array $request, ?int $code, array $headers, ?string $body) public function __construct(array $request, ?int $code, array $headers, ?string $body)

View File

@ -27,7 +27,7 @@ use React\Promise\PromiseInterface;
/** /**
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
* @phpstan-type Request array{url: string, options?: mixed[], copyTo?: ?string} * @phpstan-type Request array{url: non-empty-string, options: mixed[], copyTo: string|null}
* @phpstan-type Job array{id: int, status: int, request: Request, sync: bool, origin: string, resolve?: callable, reject?: callable, curl_id?: int, response?: Response, exception?: TransportException} * @phpstan-type Job array{id: int, status: int, request: Request, sync: bool, origin: string, resolve?: callable, reject?: callable, curl_id?: int, response?: Response, exception?: TransportException}
*/ */
class HttpDownloader class HttpDownloader
@ -104,6 +104,9 @@ class HttpDownloader
*/ */
public function get(string $url, array $options = []) public function get(string $url, array $options = [])
{ {
if ('' === $url) {
throw new \InvalidArgumentException('$url must not be an empty string');
}
[$job] = $this->addJob(['url' => $url, 'options' => $options, 'copyTo' => null], true); [$job] = $this->addJob(['url' => $url, 'options' => $options, 'copyTo' => null], true);
$this->wait($job['id']); $this->wait($job['id']);
@ -123,6 +126,9 @@ class HttpDownloader
*/ */
public function add(string $url, array $options = []) public function add(string $url, array $options = [])
{ {
if ('' === $url) {
throw new \InvalidArgumentException('$url must not be an empty string');
}
[, $promise] = $this->addJob(['url' => $url, 'options' => $options, 'copyTo' => null]); [, $promise] = $this->addJob(['url' => $url, 'options' => $options, 'copyTo' => null]);
return $promise; return $promise;
@ -140,6 +146,9 @@ class HttpDownloader
*/ */
public function copy(string $url, string $to, array $options = []) public function copy(string $url, string $to, array $options = [])
{ {
if ('' === $url) {
throw new \InvalidArgumentException('$url must not be an empty string');
}
[$job] = $this->addJob(['url' => $url, 'options' => $options, 'copyTo' => $to], true); [$job] = $this->addJob(['url' => $url, 'options' => $options, 'copyTo' => $to], true);
$this->wait($job['id']); $this->wait($job['id']);
@ -158,6 +167,9 @@ class HttpDownloader
*/ */
public function addCopy(string $url, string $to, array $options = []) public function addCopy(string $url, string $to, array $options = [])
{ {
if ('' === $url) {
throw new \InvalidArgumentException('$url must not be an empty string');
}
[, $promise] = $this->addJob(['url' => $url, 'options' => $options, 'copyTo' => $to]); [, $promise] = $this->addJob(['url' => $url, 'options' => $options, 'copyTo' => $to]);
return $promise; return $promise;
@ -295,6 +307,9 @@ class HttpDownloader
$job['status'] = self::STATUS_STARTED; $job['status'] = self::STATUS_STARTED;
$this->runningJobs++; $this->runningJobs++;
assert(isset($job['resolve']));
assert(isset($job['reject']));
$resolve = $job['resolve']; $resolve = $job['resolve'];
$reject = $job['reject']; $reject = $job['reject'];
$url = $job['request']['url']; $url = $job['request']['url'];
@ -397,6 +412,7 @@ class HttpDownloader
} }
if ($this->jobs[$index]['status'] === self::STATUS_FAILED) { if ($this->jobs[$index]['status'] === self::STATUS_FAILED) {
assert(isset($this->jobs[$index]['exception']));
throw $this->jobs[$index]['exception']; throw $this->jobs[$index]['exception'];
} }

View File

@ -38,7 +38,7 @@ class RemoteFilesystem
private $bytesMax; private $bytesMax;
/** @var string */ /** @var string */
private $originUrl; private $originUrl;
/** @var string */ /** @var non-empty-string */
private $fileUrl; private $fileUrl;
/** @var ?string */ /** @var ?string */
private $fileName; private $fileName;
@ -98,7 +98,7 @@ class RemoteFilesystem
* Copy the remote file in local. * Copy the remote file in local.
* *
* @param string $originUrl The origin URL * @param string $originUrl The origin URL
* @param string $fileUrl The file URL * @param non-empty-string $fileUrl The file URL
* @param string $fileName the local filename * @param string $fileName the local filename
* @param bool $progress Display the progression * @param bool $progress Display the progression
* @param mixed[] $options Additional context options * @param mixed[] $options Additional context options
@ -114,7 +114,7 @@ class RemoteFilesystem
* Get the content. * Get the content.
* *
* @param string $originUrl The origin URL * @param string $originUrl The origin URL
* @param string $fileUrl The file URL * @param non-empty-string $fileUrl The file URL
* @param bool $progress Display the progression * @param bool $progress Display the progression
* @param mixed[] $options Additional context options * @param mixed[] $options Additional context options
* *
@ -206,7 +206,7 @@ class RemoteFilesystem
* Get file content or copy action. * Get file content or copy action.
* *
* @param string $originUrl The origin URL * @param string $originUrl The origin URL
* @param string $fileUrl The file URL * @param non-empty-string $fileUrl The file URL
* @param mixed[] $additionalOptions context options * @param mixed[] $additionalOptions context options
* @param string $fileName the local filename * @param string $fileName the local filename
* @param bool $progress Display the progression * @param bool $progress Display the progression

View File

@ -30,7 +30,7 @@ final class StreamContextFactory
/** /**
* Creates a context supporting HTTP proxies * Creates a context supporting HTTP proxies
* *
* @param string $url URL the context is to be used for * @param non-empty-string $url URL the context is to be used for
* @phpstan-param array{http?: array{follow_location?: int, max_redirects?: int, header?: string|array<string>}} $defaultOptions * @phpstan-param array{http?: array{follow_location?: int, max_redirects?: int, header?: string|array<string>}} $defaultOptions
* @param mixed[] $defaultOptions Options to merge with the default * @param mixed[] $defaultOptions Options to merge with the default
* @param mixed[] $defaultParams Parameters to specify on the context * @param mixed[] $defaultParams Parameters to specify on the context
@ -57,6 +57,7 @@ final class StreamContextFactory
} }
/** /**
* @param non-empty-string $url
* @param mixed[] $options * @param mixed[] $options
* @param bool $forCurl When true, will not add proxy values as these are handled separately * @param bool $forCurl When true, will not add proxy values as these are handled separately
* @phpstan-return array{http: array{header: string[], proxy?: string, request_fulluri: bool}, ssl?: mixed[]} * @phpstan-return array{http: array{header: string[], proxy?: string, request_fulluri: bool}, ssl?: mixed[]}

View File

@ -21,7 +21,8 @@ use Composer\Pcre\Preg;
class Url class Url
{ {
/** /**
* @return string the updated URL * @param non-empty-string $url
* @return non-empty-string the updated URL
*/ */
public static function updateDistReference(Config $config, string $url, string $ref): string public static function updateDistReference(Config $config, string $url, string $ref): string
{ {
@ -54,9 +55,15 @@ class Url
$url = Preg::replace('{(/api/v[34]/projects/[^/]+/repository/archive\.(?:zip|tar\.gz|tar\.bz2|tar)\?sha=).+$}i', '${1}'.$ref, $url); $url = Preg::replace('{(/api/v[34]/projects/[^/]+/repository/archive\.(?:zip|tar\.gz|tar\.bz2|tar)\?sha=).+$}i', '${1}'.$ref, $url);
} }
assert($url !== '');
return $url; return $url;
} }
/**
* @param non-empty-string $url
* @return non-empty-string
*/
public static function getOrigin(Config $config, string $url): string public static function getOrigin(Config $config, string $url): string
{ {
if (0 === strpos($url, 'file://')) { if (0 === strpos($url, 'file://')) {
@ -87,7 +94,7 @@ class Url
&& !in_array($origin, $config->get('gitlab-domains'), true) && !in_array($origin, $config->get('gitlab-domains'), true)
) { ) {
foreach ($config->get('gitlab-domains') as $gitlabDomain) { foreach ($config->get('gitlab-domains') as $gitlabDomain) {
if (0 === strpos($gitlabDomain, $origin)) { if ($gitlabDomain !== '' && str_starts_with($gitlabDomain, $origin)) {
return $gitlabDomain; return $gitlabDomain;
} }
} }

View File

@ -8,7 +8,7 @@ Installing double aliased package
"package": [ "package": [
{ {
"name": "a/a", "version": "dev-master", "name": "a/a", "version": "dev-master",
"dist": { "type": "file", "url": "" }, "dist": { "type": "file", "url": "https://example.org" },
"require": { "require": {
"b/b": "dev-master" "b/b": "dev-master"
}, },
@ -17,7 +17,7 @@ Installing double aliased package
{ {
"name": "b/b", "version": "dev-foo", "name": "b/b", "version": "dev-foo",
"extra": { "branch-alias": { "dev-foo": "1.0.x-dev" } }, "extra": { "branch-alias": { "dev-foo": "1.0.x-dev" } },
"dist": { "type": "file", "url": "" } "dist": { "type": "file", "url": "https://example.org" }
} }
] ]
} }

View File

@ -8,7 +8,7 @@ Installs a dev package forcing it's reference
"package": [ "package": [
{ {
"name": "a/a", "version": "dev-main", "name": "a/a", "version": "dev-main",
"source": { "reference": "abc123", "url": "", "type": "git" }, "source": { "reference": "abc123", "url": "https://example.org", "type": "git" },
"default-branch": true "default-branch": true
} }
] ]

View File

@ -8,14 +8,14 @@ Updating a dev package selects its newest version but no providers
"package": [ "package": [
{ {
"name": "a/replacer", "version": "dev-master", "name": "a/replacer", "version": "dev-master",
"source": { "reference": "wrong", "url": "", "type": "git" }, "source": { "reference": "wrong", "url": "https://example.org", "type": "git" },
"replace": { "replace": {
"a/installed": "dev-master" "a/installed": "dev-master"
} }
}, },
{ {
"name": "a/installed", "version": "dev-master", "name": "a/installed", "version": "dev-master",
"source": { "reference": "newref", "url": "", "type": "git" } "source": { "reference": "newref", "url": "https://example.org", "type": "git" }
} }
] ]
} }
@ -29,7 +29,7 @@ Updating a dev package selects its newest version but no providers
[ [
{ {
"name": "a/installed", "version": "dev-master", "name": "a/installed", "version": "dev-master",
"source": { "reference": "oldref", "url": "", "type": "git" } "source": { "reference": "oldref", "url": "https://example.org", "type": "git" }
} }
] ]
--RUN-- --RUN--

View File

@ -8,7 +8,7 @@ Updating a dev package to its latest ref should pick up new dependencies
"package": [ "package": [
{ {
"name": "a/devpackage", "version": "dev-main", "name": "a/devpackage", "version": "dev-main",
"source": { "reference": "newref", "url": "", "type": "git" }, "source": { "reference": "newref", "url": "https://example.org", "type": "git" },
"require": { "require": {
"a/dependency": "*" "a/dependency": "*"
}, },
@ -16,7 +16,7 @@ Updating a dev package to its latest ref should pick up new dependencies
}, },
{ {
"name": "a/dependency", "version": "dev-main", "name": "a/dependency", "version": "dev-main",
"source": { "reference": "ref", "url": "", "type": "git" }, "source": { "reference": "ref", "url": "https://example.org", "type": "git" },
"require": {}, "require": {},
"default-branch": true "default-branch": true
} }
@ -32,7 +32,7 @@ Updating a dev package to its latest ref should pick up new dependencies
[ [
{ {
"name": "a/devpackage", "version": "dev-main", "name": "a/devpackage", "version": "dev-main",
"source": { "reference": "oldref", "url": "", "type": "git" }, "source": { "reference": "oldref", "url": "https://example.org", "type": "git" },
"require": {}, "require": {},
"default-branch": true "default-branch": true
} }

View File

@ -8,23 +8,23 @@ Downgrading from unstable to more stable package should work even if already ins
"package": [ "package": [
{ {
"name": "a/a", "version": "dev-master", "name": "a/a", "version": "dev-master",
"source": { "reference": "abcd", "url": "", "type": "git" }, "source": { "reference": "abcd", "url": "https://example.org", "type": "git" },
"default-branch": true "default-branch": true
}, },
{ {
"name": "a/a", "version": "1.0.0", "name": "a/a", "version": "1.0.0",
"source": { "reference": "1.0.0", "url": "", "type": "git" }, "source": { "reference": "1.0.0", "url": "https://example.org", "type": "git" },
"dist": { "reference": "1.0.0", "url": "", "type": "zip", "shasum": "" } "dist": { "reference": "1.0.0", "url": "https://example.org", "type": "zip", "shasum": "" }
}, },
{ {
"name": "b/b", "version": "dev-master", "name": "b/b", "version": "dev-master",
"source": { "reference": "abcd", "url": "", "type": "git" }, "source": { "reference": "abcd", "url": "https://example.org", "type": "git" },
"default-branch": true "default-branch": true
}, },
{ {
"name": "b/b", "version": "1.0.0", "name": "b/b", "version": "1.0.0",
"source": { "reference": "1.0.0", "url": "", "type": "git" }, "source": { "reference": "1.0.0", "url": "https://example.org", "type": "git" },
"dist": { "reference": "1.0.0", "url": "", "type": "zip", "shasum": "" } "dist": { "reference": "1.0.0", "url": "https://example.org", "type": "zip", "shasum": "" }
} }
] ]
} }
@ -38,12 +38,12 @@ Downgrading from unstable to more stable package should work even if already ins
[ [
{ {
"name": "a/a", "version": "dev-master", "name": "a/a", "version": "dev-master",
"source": { "reference": "abcd", "url": "", "type": "git" }, "source": { "reference": "abcd", "url": "https://example.org", "type": "git" },
"default-branch": true "default-branch": true
}, },
{ {
"name": "b/b", "version": "dev-master", "name": "b/b", "version": "dev-master",
"source": { "reference": "abcd", "url": "", "type": "git" }, "source": { "reference": "abcd", "url": "https://example.org", "type": "git" },
"default-branch": true "default-branch": true
} }
] ]

View File

@ -9,12 +9,12 @@ Updates installed alias packages in dry-run mode
{ {
"name": "a/a", "version": "dev-master", "name": "a/a", "version": "dev-master",
"require": { "b/b": "2.0.*" }, "require": { "b/b": "2.0.*" },
"source": { "reference": "abcdef", "url": "", "type": "git" }, "source": { "reference": "abcdef", "url": "https://example.org", "type": "git" },
"extra": { "branch-alias": { "dev-master": "1.0.x-dev" } } "extra": { "branch-alias": { "dev-master": "1.0.x-dev" } }
}, },
{ {
"name": "b/b", "version": "dev-master", "name": "b/b", "version": "dev-master",
"source": { "reference": "123456", "url": "", "type": "git" }, "source": { "reference": "123456", "url": "https://example.org", "type": "git" },
"extra": { "branch-alias": { "dev-master": "2.0.x-dev" } } "extra": { "branch-alias": { "dev-master": "2.0.x-dev" } }
} }
] ]
@ -30,12 +30,12 @@ Updates installed alias packages in dry-run mode
{ {
"name": "a/a", "version": "dev-master", "name": "a/a", "version": "dev-master",
"require": { "b/b": "2.0.*" }, "require": { "b/b": "2.0.*" },
"source": { "reference": "abcdef", "url": "", "type": "git" }, "source": { "reference": "abcdef", "url": "https://example.org", "type": "git" },
"extra": { "branch-alias": { "dev-master": "1.0.x-dev" } } "extra": { "branch-alias": { "dev-master": "1.0.x-dev" } }
}, },
{ {
"name": "b/b", "version": "dev-master", "name": "b/b", "version": "dev-master",
"source": { "reference": "123456", "url": "", "type": "git" }, "source": { "reference": "123456", "url": "https://example.org", "type": "git" },
"extra": { "branch-alias": { "dev-master": "2.0.x-dev" } } "extra": { "branch-alias": { "dev-master": "2.0.x-dev" } }
} }
] ]

View File

@ -9,12 +9,12 @@ Updates installed alias packages
{ {
"name": "a/a", "version": "dev-master", "name": "a/a", "version": "dev-master",
"require": { "b/b": "2.0.*" }, "require": { "b/b": "2.0.*" },
"source": { "reference": "abcdef", "url": "", "type": "git" }, "source": { "reference": "abcdef", "url": "https://example.org", "type": "git" },
"extra": { "branch-alias": { "dev-master": "1.0.x-dev" } } "extra": { "branch-alias": { "dev-master": "1.0.x-dev" } }
}, },
{ {
"name": "b/b", "version": "dev-master", "name": "b/b", "version": "dev-master",
"source": { "reference": "123456", "url": "", "type": "git" }, "source": { "reference": "123456", "url": "https://example.org", "type": "git" },
"extra": { "branch-alias": { "dev-master": "2.0.x-dev" } } "extra": { "branch-alias": { "dev-master": "2.0.x-dev" } }
} }
] ]
@ -30,12 +30,12 @@ Updates installed alias packages
{ {
"name": "a/a", "version": "dev-master", "name": "a/a", "version": "dev-master",
"require": { "b/b": "2.0.*" }, "require": { "b/b": "2.0.*" },
"source": { "reference": "abcdef", "url": "", "type": "git" }, "source": { "reference": "abcdef", "url": "https://example.org", "type": "git" },
"extra": { "branch-alias": { "dev-master": "1.0.x-dev" } } "extra": { "branch-alias": { "dev-master": "1.0.x-dev" } }
}, },
{ {
"name": "b/b", "version": "dev-master", "name": "b/b", "version": "dev-master",
"source": { "reference": "123456", "url": "", "type": "git" }, "source": { "reference": "123456", "url": "https://example.org", "type": "git" },
"extra": { "branch-alias": { "dev-master": "2.0.x-dev" } } "extra": { "branch-alias": { "dev-master": "2.0.x-dev" } }
} }
] ]

View File

@ -8,7 +8,7 @@ Updating a dev package forcing it's reference, using dry run, should not do anyt
"package": [ "package": [
{ {
"name": "a/a", "version": "dev-master", "name": "a/a", "version": "dev-master",
"source": { "reference": "abc123", "url": "", "type": "git" } "source": { "reference": "abc123", "url": "https://example.org", "type": "git" }
} }
] ]
} }
@ -21,8 +21,8 @@ Updating a dev package forcing it's reference, using dry run, should not do anyt
[ [
{ {
"name": "a/a", "version": "dev-master", "name": "a/a", "version": "dev-master",
"source": { "reference": "def000", "url": "", "type": "git" }, "source": { "reference": "def000", "url": "https://example.org", "type": "git" },
"dist": { "reference": "def000", "url": "", "type": "zip", "shasum": "" } "dist": { "reference": "def000", "url": "https://example.org", "type": "zip", "shasum": "" }
} }
] ]
--RUN-- --RUN--

View File

@ -8,7 +8,7 @@ Updating a dev package forcing it's reference should not do anything if the refe
"package": [ "package": [
{ {
"name": "a/a", "version": "dev-master", "name": "a/a", "version": "dev-master",
"source": { "reference": "abc123", "url": "", "type": "git" } "source": { "reference": "abc123", "url": "https://example.org", "type": "git" }
} }
] ]
} }
@ -21,8 +21,8 @@ Updating a dev package forcing it's reference should not do anything if the refe
[ [
{ {
"name": "a/a", "version": "dev-master", "name": "a/a", "version": "dev-master",
"source": { "reference": "def000", "url": "", "type": "git" }, "source": { "reference": "def000", "url": "https://example.org", "type": "git" },
"dist": { "reference": "def000", "url": "", "type": "zip", "shasum": "" } "dist": { "reference": "def000", "url": "https://example.org", "type": "zip", "shasum": "" }
} }
] ]
--RUN-- --RUN--

View File

@ -8,7 +8,7 @@ Updating a dev package should update to the latest available reference
"package": [ "package": [
{ {
"name": "a/a", "version": "dev-master", "name": "a/a", "version": "dev-master",
"source": { "reference": "abc123", "url": "", "type": "git" } "source": { "reference": "abc123", "url": "https://example.org", "type": "git" }
} }
] ]
} }
@ -21,8 +21,8 @@ Updating a dev package should update to the latest available reference
[ [
{ {
"name": "a/a", "version": "dev-master", "name": "a/a", "version": "dev-master",
"source": { "reference": "def000", "url": "", "type": "git" }, "source": { "reference": "def000", "url": "https://example.org", "type": "git" },
"dist": { "reference": "def000", "url": "", "type": "zip", "shasum": "" } "dist": { "reference": "def000", "url": "https://example.org", "type": "zip", "shasum": "" }
} }
] ]
--RUN-- --RUN--

View File

@ -8,7 +8,7 @@ Updates a dev package forcing its reference
"package": [ "package": [
{ {
"name": "a/a", "version": "dev-master", "name": "a/a", "version": "dev-master",
"source": { "reference": "abc123", "url": "", "type": "git" } "source": { "reference": "abc123", "url": "https://example.org", "type": "git" }
} }
] ]
} }
@ -21,7 +21,7 @@ Updates a dev package forcing its reference
[ [
{ {
"name": "a/a", "version": "dev-master", "name": "a/a", "version": "dev-master",
"source": { "reference": "abc123", "url": "", "type": "git" } "source": { "reference": "abc123", "url": "https://example.org", "type": "git" }
} }
] ]
--RUN-- --RUN--

View File

@ -12,7 +12,7 @@ Installing locked dev packages should remove old dependencies
"packages": [ "packages": [
{ {
"name": "a/devpackage", "version": "dev-master", "name": "a/devpackage", "version": "dev-master",
"source": { "reference": "newref", "url": "", "type": "git" }, "source": { "reference": "newref", "url": "https://example.org", "type": "git" },
"require": {}, "require": {},
"default-branch": true "default-branch": true
} }
@ -28,7 +28,7 @@ Installing locked dev packages should remove old dependencies
[ [
{ {
"name": "a/devpackage", "version": "dev-master", "name": "a/devpackage", "version": "dev-master",
"source": { "reference": "oldref", "url": "", "type": "git" }, "source": { "reference": "oldref", "url": "https://example.org", "type": "git" },
"require": { "require": {
"a/dependency": "*" "a/dependency": "*"
}, },
@ -36,7 +36,7 @@ Installing locked dev packages should remove old dependencies
}, },
{ {
"name": "a/dependency", "version": "dev-master", "name": "a/dependency", "version": "dev-master",
"source": { "reference": "ref", "url": "", "type": "git" }, "source": { "reference": "ref", "url": "https://example.org", "type": "git" },
"require": {}, "require": {},
"default-branch": true "default-branch": true
} }

View File

@ -24,7 +24,7 @@ use PHPUnit\Framework\AssertionFailedError;
class HttpDownloaderMock extends HttpDownloader class HttpDownloaderMock extends HttpDownloader
{ {
/** /**
* @var array<array{url: string, options: array<mixed>|null, status: int, body: string, headers: list<string>}>|null * @var array<array{url: non-empty-string, options: array<mixed>|null, status: int, body: string, headers: list<string>}>|null
*/ */
private $expectations = null; private $expectations = null;
/** /**
@ -52,7 +52,7 @@ class HttpDownloaderMock extends HttpDownloader
} }
/** /**
* @param array<array{url: string, options?: array<mixed>, status?: int, body?: string, headers?: array<string>}> $expectations * @param array<array{url: non-empty-string, options?: array<mixed>, status?: int, body?: string, headers?: array<string>}> $expectations
* @param bool $strict set to true if you want to provide *all* expected http requests, and not just a subset you are interested in testing * @param bool $strict set to true if you want to provide *all* expected http requests, and not just a subset you are interested in testing
* @param array{status?: int, body?: string, headers?: array<string>} $defaultHandler default URL handler for undefined requests if not in strict mode * @param array{status?: int, body?: string, headers?: array<string>} $defaultHandler default URL handler for undefined requests if not in strict mode
*/ */
@ -64,23 +64,11 @@ class HttpDownloaderMock extends HttpDownloader
throw new \UnexpectedValueException('Unexpected keys in process execution step: '.implode(', ', array_keys($diff))); throw new \UnexpectedValueException('Unexpected keys in process execution step: '.implode(', ', array_keys($diff)));
} }
// set defaults in a PHPStan-happy way (array_merge is not well supported) return array_merge($default, $expect);
$expect['url'] = $expect['url'] ?? $default['url'];
$expect['options'] = $expect['options'] ?? $default['options'];
$expect['status'] = $expect['status'] ?? $default['status'];
$expect['body'] = $expect['body'] ?? $default['body'];
$expect['headers'] = $expect['headers'] ?? $default['headers'];
return $expect;
}, $expectations); }, $expectations);
$this->strict = $strict; $this->strict = $strict;
// set defaults in a PHPStan-happy way (array_merge is not well supported) $this->defaultHandler = array_merge($this->defaultHandler, $defaultHandler);
$defaultHandler['status'] = $defaultHandler['status'] ?? $this->defaultHandler['status'];
$defaultHandler['body'] = $defaultHandler['body'] ?? $this->defaultHandler['body'];
$defaultHandler['headers'] = $defaultHandler['headers'] ?? $this->defaultHandler['headers'];
$this->defaultHandler = $defaultHandler;
} }
public function assertComplete(): void public function assertComplete(): void
@ -107,6 +95,10 @@ class HttpDownloaderMock extends HttpDownloader
public function get($fileUrl, $options = []): Response public function get($fileUrl, $options = []): Response
{ {
if ('' === $fileUrl) {
throw new \LogicException('url cannot be an empty string');
}
$this->log[] = $fileUrl; $this->log[] = $fileUrl;
if (is_array($this->expectations) && count($this->expectations) > 0 && $fileUrl === $this->expectations[0]['url'] && ($this->expectations[0]['options'] === null || $options === $this->expectations[0]['options'])) { if (is_array($this->expectations) && count($this->expectations) > 0 && $fileUrl === $this->expectations[0]['url'] && ($this->expectations[0]['options'] === null || $options === $this->expectations[0]['options'])) {
@ -128,6 +120,7 @@ class HttpDownloaderMock extends HttpDownloader
/** /**
* @param string[] $headers * @param string[] $headers
* @param non-empty-string $url
*/ */
private function respond(string $url, int $status, array $headers, string $body): Response private function respond(string $url, int $status, array $headers, string $body): Response
{ {

View File

@ -74,23 +74,11 @@ class ProcessExecutorMock extends ProcessExecutor
throw new \UnexpectedValueException('Unexpected keys in process execution step: '.implode(', ', array_keys($diff))); throw new \UnexpectedValueException('Unexpected keys in process execution step: '.implode(', ', array_keys($diff)));
} }
// set defaults in a PHPStan-happy way (array_merge is not well supported) return array_merge($default, $expect);
$expect['cmd'] = $expect['cmd'] ?? $default['cmd'];
$expect['return'] = $expect['return'] ?? $default['return'];
$expect['stdout'] = $expect['stdout'] ?? $default['stdout'];
$expect['stderr'] = $expect['stderr'] ?? $default['stderr'];
$expect['callback'] = $expect['callback'] ?? $default['callback'];
return $expect;
}, $expectations); }, $expectations);
$this->strict = $strict; $this->strict = $strict;
// set defaults in a PHPStan-happy way (array_merge is not well supported) $this->defaultHandler = array_merge($this->defaultHandler, $defaultHandler);
$defaultHandler['return'] = $defaultHandler['return'] ?? $this->defaultHandler['return'];
$defaultHandler['stdout'] = $defaultHandler['stdout'] ?? $this->defaultHandler['stdout'];
$defaultHandler['stderr'] = $defaultHandler['stderr'] ?? $this->defaultHandler['stderr'];
$this->defaultHandler = $defaultHandler;
} }
public function assertComplete(): void public function assertComplete(): void

View File

@ -274,6 +274,8 @@ class ComposerRepositoryTest extends TestCase
/** /**
* @dataProvider provideCanonicalizeUrlTestCases * @dataProvider provideCanonicalizeUrlTestCases
* @param non-empty-string $url
* @param non-empty-string $repositoryUrl
*/ */
public function testCanonicalizeUrl(string $expected, string $url, string $repositoryUrl): void public function testCanonicalizeUrl(string $expected, string $url, string $repositoryUrl): void
{ {

View File

@ -86,6 +86,8 @@ class GitLabDriverTest extends TestCase
/** /**
* @dataProvider provideInitializeUrls * @dataProvider provideInitializeUrls
* @param non-empty-string $url
* @param non-empty-string $apiUrl
*/ */
public function testInitialize(string $url, string $apiUrl): GitLabDriver public function testInitialize(string $url, string $apiUrl): GitLabDriver
{ {
@ -126,6 +128,8 @@ JSON;
/** /**
* @dataProvider provideInitializeUrls * @dataProvider provideInitializeUrls
* @param non-empty-string $url
* @param non-empty-string $apiUrl
*/ */
public function testInitializePublicProject(string $url, string $apiUrl): GitLabDriver public function testInitializePublicProject(string $url, string $apiUrl): GitLabDriver
{ {
@ -164,6 +168,8 @@ JSON;
/** /**
* @dataProvider provideInitializeUrls * @dataProvider provideInitializeUrls
* @param non-empty-string $url
* @param non-empty-string $apiUrl
*/ */
public function testInitializePublicProjectAsAnonymous(string $url, string $apiUrl): GitLabDriver public function testInitializePublicProjectAsAnonymous(string $url, string $apiUrl): GitLabDriver
{ {

View File

@ -72,6 +72,7 @@ class ProxyManagerTest extends TestCase
* *
* @param array<string, mixed> $server * @param array<string, mixed> $server
* @param mixed[] $expectedOptions * @param mixed[] $expectedOptions
* @param non-empty-string $url
*/ */
public function testGetProxyForRequest(array $server, string $url, string $expectedUrl, array $expectedOptions, bool $expectedSecure, string $expectedMessage): void public function testGetProxyForRequest(array $server, string $url, string $expectedUrl, array $expectedOptions, bool $expectedSecure, string $expectedMessage): void
{ {

View File

@ -276,6 +276,7 @@ class RemoteFilesystemTest extends TestCase
* Tests that a BitBucket public download is correctly retrieved. * Tests that a BitBucket public download is correctly retrieved.
* *
* @dataProvider provideBitbucketPublicDownloadUrls * @dataProvider provideBitbucketPublicDownloadUrls
* @param non-empty-string $url
*/ */
public function testBitBucketPublicDownload(string $url, string $contents): void public function testBitBucketPublicDownload(string $url, string $contents): void
{ {
@ -297,6 +298,7 @@ class RemoteFilesystemTest extends TestCase
* Tests that a BitBucket public download is correctly retrieved when `bitbucket-oauth` is configured. * Tests that a BitBucket public download is correctly retrieved when `bitbucket-oauth` is configured.
* *
* @dataProvider provideBitbucketPublicDownloadUrls * @dataProvider provideBitbucketPublicDownloadUrls
* @param non-empty-string $url
*/ */
public function testBitBucketPublicDownloadWithAuthConfigured(string $url, string $contents): void public function testBitBucketPublicDownloadWithAuthConfigured(string $url, string $contents): void
{ {

View File

@ -22,6 +22,7 @@ class UrlTest extends TestCase
* @dataProvider distRefsProvider * @dataProvider distRefsProvider
* *
* @param array<string, mixed> $conf * @param array<string, mixed> $conf
* @param non-empty-string $url
*/ */
public function testUpdateDistReference(string $url, string $expectedUrl, array $conf = [], string $ref = 'newref'): void public function testUpdateDistReference(string $url, string $expectedUrl, array $conf = [], string $ref = 'newref'): void
{ {