diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index adf59f0..bcaf8f9 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -1,11 +1,14 @@ on: push: branches: - - '*.*' + - '2.x' pull_request: null name: static analysis +permissions: + contents: read + jobs: psalm: uses: spiral/gh-actions/.github/workflows/psalm.yml@master diff --git a/psalm-baseline.xml b/psalm-baseline.xml deleted file mode 100644 index 80eff43..0000000 --- a/psalm-baseline.xml +++ /dev/null @@ -1,155 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]]> - - - ]]> - - - - - - - - - - - - getAvailable()]]> - - - - - - - - - - - - - - - - - - - - - - - - getOption('plugin')]]> - getOption('preset')]]> - - - - - - - - - - - - - - - - - - - - - getOption('plugin')]]> - getOption('preset')]]> - - - - - - - - - items, $callback))]]> - items, $filter))]]> - items))]]> - - - - - - - - - - - - - - - - - - - stability]]> - - - - - - - - ]]> - - - - - - - - - - ]]> - - - - - stability->get($input, $io)]]> - - - - - - - - - diff --git a/psalm.xml b/psalm.xml index e275989..faa1d08 100644 --- a/psalm.xml +++ b/psalm.xml @@ -3,7 +3,6 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" - errorBaseline="psalm-baseline.xml" errorLevel="1" hoistConstants="true" resolveFromConfigFile="true" @@ -16,8 +15,7 @@ > - - + diff --git a/src/Archive/Factory.php b/src/Archive/Factory.php index 48e9e9a..0d92588 100644 --- a/src/Archive/Factory.php +++ b/src/Archive/Factory.php @@ -31,6 +31,7 @@ public function __construct() $this->bootDefaultMatchers(); } + #[\Override] public function extend(\Closure $matcher): self { \array_unshift($this->matchers, $matcher); @@ -38,6 +39,7 @@ public function extend(\Closure $matcher): self return $this; } + #[\Override] public function create(\SplFileInfo $file): ArchiveInterface { $errors = []; @@ -60,6 +62,7 @@ public function create(\SplFileInfo $file): ArchiveInterface throw new \InvalidArgumentException($error); } + #[\Override] public function fromAsset(AssetInterface $asset, ?\Closure $progress = null, ?string $temp = null): ArchiveInterface { $temp = $this->getTempDirectory($temp) . '/' . $asset->getName(); @@ -110,7 +113,7 @@ private function matcher(string $extension, \Closure $then): \Closure private function getTempDirectory(?string $temp): string { - if ($temp) { + if ($temp !== null && $temp !== '') { if (! \is_dir($temp) || ! \is_writable($temp)) { throw new \LogicException(\sprintf('Directory "%s" is not writeable', $temp)); } diff --git a/src/Archive/PharArchive.php b/src/Archive/PharArchive.php index 4d28eb8..40711cd 100644 --- a/src/Archive/PharArchive.php +++ b/src/Archive/PharArchive.php @@ -13,6 +13,7 @@ final class PharArchive extends PharAwareArchive { + #[\Override] protected function open(\SplFileInfo $file): \PharData { return new \PharData($file->getPathname()); diff --git a/src/Archive/PharAwareArchive.php b/src/Archive/PharAwareArchive.php index 7dd4449..3fc3c4d 100644 --- a/src/Archive/PharAwareArchive.php +++ b/src/Archive/PharAwareArchive.php @@ -26,6 +26,7 @@ public function __construct(\SplFileInfo $archive) * @param iterable $mappings * @return \Generator */ + #[\Override] public function extract(iterable $mappings): \Generator { $phar = $this->open($this->archive); diff --git a/src/Archive/TarPharArchive.php b/src/Archive/TarPharArchive.php index ba3d119..9b1f570 100644 --- a/src/Archive/TarPharArchive.php +++ b/src/Archive/TarPharArchive.php @@ -13,6 +13,7 @@ final class TarPharArchive extends PharAwareArchive { + #[\Override] protected function open(\SplFileInfo $file): \PharData { return new \PharData($file->getPathname()); diff --git a/src/Archive/ZipPharArchive.php b/src/Archive/ZipPharArchive.php index 87f3581..1f68c86 100644 --- a/src/Archive/ZipPharArchive.php +++ b/src/Archive/ZipPharArchive.php @@ -13,6 +13,7 @@ final class ZipPharArchive extends PharAwareArchive { + #[\Override] protected function open(\SplFileInfo $file): \PharData { $format = \Phar::ZIP | \Phar::GZ; diff --git a/src/Command.php b/src/Command.php index 4eeab5e..ef3fb4b 100644 --- a/src/Command.php +++ b/src/Command.php @@ -37,7 +37,7 @@ protected function getRepository(): RepositoryInterface $client = HttpClient::create([ 'headers' => \array_filter([ - 'authorization' => $token ? 'token ' . $token : null, + 'authorization' => $token !== null && $token !== '' ? 'token ' . $token : null, ]), ]); diff --git a/src/Command/ArchitectureOption.php b/src/Command/ArchitectureOption.php index c572f0f..53e4083 100644 --- a/src/Command/ArchitectureOption.php +++ b/src/Command/ArchitectureOption.php @@ -23,6 +23,7 @@ public function __construct(Command $command, string $name = 'arch', string $sho parent::__construct($command, $name, $short); } + #[\Override] public function get(InputInterface $input, StyleInterface $io): string { $architecture = parent::get($input, $io); @@ -35,11 +36,13 @@ public function get(InputInterface $input, StyleInterface $io): string return $architecture; } + #[\Override] protected function getDescription(): string { return 'Required processor architecture (one of: ' . $this->choices() . ')'; } + #[\Override] protected function default(): string { return Architecture::createFromGlobals(); diff --git a/src/Command/InstallationLocationOption.php b/src/Command/InstallationLocationOption.php index dab28a0..391c531 100644 --- a/src/Command/InstallationLocationOption.php +++ b/src/Command/InstallationLocationOption.php @@ -22,6 +22,7 @@ public function __construct(Command $command, string $name = 'location', string parent::__construct($command, $name, $short); } + #[\Override] public function get(InputInterface $input, StyleInterface $io): string { $location = parent::get($input, $io); @@ -38,11 +39,13 @@ public function get(InputInterface $input, StyleInterface $io): string return $location; } + #[\Override] protected function getDescription(): string { return 'Installation directory'; } + #[\Override] protected function default(): string { return \getcwd() ?: '.'; diff --git a/src/Command/OperatingSystemOption.php b/src/Command/OperatingSystemOption.php index df26d1e..81a111e 100644 --- a/src/Command/OperatingSystemOption.php +++ b/src/Command/OperatingSystemOption.php @@ -23,6 +23,7 @@ public function __construct(Command $command, string $name = 'os', string $short parent::__construct($command, $name, $short); } + #[\Override] public function get(InputInterface $input, StyleInterface $io): string { $os = parent::get($input, $io); @@ -35,11 +36,13 @@ public function get(InputInterface $input, StyleInterface $io): string return $os; } + #[\Override] protected function getDescription(): string { return 'Required operating system (one of: ' . $this->choices() . ')'; } + #[\Override] protected function default(): string { return OperatingSystem::createFromGlobals(); diff --git a/src/Command/Option.php b/src/Command/Option.php index ed9a2f4..583f65f 100644 --- a/src/Command/Option.php +++ b/src/Command/Option.php @@ -30,16 +30,16 @@ public function __construct(Command $command, string $name, ?string $short = nul $this->register($command, $name, $short ?? $name); } + #[\Override] public function getName(): string { return $this->name; } + #[\Override] public function get(InputInterface $input, StyleInterface $io): string { - $result = $input->getOption($this->name) ?: $this->default(); - - return \is_string($result) ? $result : ''; + return self::toString($input->getOption($this->name) ?: $this->default()); } /** @@ -54,6 +54,11 @@ abstract protected function getDescription(): string; abstract protected function default(): ?string; + private static function toString(mixed $value): string + { + return \is_string($value) ? $value : ''; + } + private function register(Command $command, string $name, string $short): void { $command->addOption($name, $short, $this->getMode(), $this->getDescription(), $this->default()); diff --git a/src/Command/StabilityOption.php b/src/Command/StabilityOption.php index fb5ba5d..6561f40 100644 --- a/src/Command/StabilityOption.php +++ b/src/Command/StabilityOption.php @@ -30,6 +30,7 @@ public function __construct(Command $command, string $name = 'stability', string * * @return StabilityType|string */ + #[\Override] public function get(InputInterface $input, StyleInterface $io): string { $stability = parent::get($input, $io); @@ -42,11 +43,13 @@ public function get(InputInterface $input, StyleInterface $io): string return $stability; } + #[\Override] protected function getDescription(): string { return 'Release minimum stability flag'; } + #[\Override] protected function default(): string { return Stability::STABILITY_STABLE; diff --git a/src/Command/VersionFilterOption.php b/src/Command/VersionFilterOption.php index d823ef1..7e4279a 100644 --- a/src/Command/VersionFilterOption.php +++ b/src/Command/VersionFilterOption.php @@ -28,10 +28,10 @@ public function __construct(Command $command, string $name = 'filter', string $s public function choices(ReleasesCollection $releases): string { - $versions = $releases - ->map(static fn(ReleaseInterface $release): string => $release->getVersion()) - ->toArray() - ; + $versions = \array_map( + static fn(ReleaseInterface $release): string => $release->getVersion(), + $releases->toArray(), + ); return \implode(', ', \array_unique($versions)); } @@ -53,11 +53,13 @@ public function find(InputInterface $input, StyleInterface $io, RepositoryInterf return $filtered; } + #[\Override] protected function getDescription(): string { return 'Required version of RoadRunner binaries'; } + #[\Override] protected function default(): string { return RoadRunnerVersion::constraint(); diff --git a/src/Configuration/Generator.php b/src/Configuration/Generator.php index 24ed2da..f7d79b2 100644 --- a/src/Configuration/Generator.php +++ b/src/Configuration/Generator.php @@ -37,6 +37,9 @@ protected function getContent(): array return $content; } + /** + * @param array> $plugins + */ protected function collectSections(array $plugins): void { $sections = \array_merge(self::REQUIRED_SECTIONS, $plugins); @@ -46,9 +49,6 @@ protected function collectSections(array $plugins): void } } - /** - * @psalm-return non-empty-array - */ protected function fromSection(SectionInterface $section): void { if (!isset($this->sections[\get_class($section)])) { diff --git a/src/Configuration/Plugins.php b/src/Configuration/Plugins.php index 4dedad8..e63cdac 100644 --- a/src/Configuration/Plugins.php +++ b/src/Configuration/Plugins.php @@ -18,7 +18,7 @@ final class Plugins { /** - * @psalm-var array + * @psalm-var list> * * Default plugins in a class-string format. */ @@ -40,18 +40,24 @@ final class Plugins private array $requestedPlugins; /** - * @psalm-var non-empty-array> + * @psalm-var list> * * All plugins. */ private array $available; + /** + * @param string[] $plugins + */ private function __construct(array $plugins) { $this->available = $this->getAvailable(); $this->requestedPlugins = $plugins; } + /** + * @param string[] $plugins Plugin short names. + */ public static function fromPlugins(array $plugins): self { return new self($plugins); @@ -70,6 +76,9 @@ public static function fromPreset(string $preset): self }, $plugins)); } + /** + * @return list> + */ public function getPlugins(): array { if ($this->requestedPlugins === []) { @@ -86,6 +95,9 @@ public function getPlugins(): array return $plugins; } + /** + * @return list> + */ private function getAvailable(): array { $finder = new Finder(); @@ -93,11 +105,12 @@ private function getAvailable(): array $locator = new ClassLocator($finder); - /** @var SectionInterface[] $available */ $available = []; foreach ($locator->getClasses() as $class) { if ($this->isPlugin($class)) { - $available[] = $class->getName(); + /** @var class-string $name */ + $name = $class->getName(); + $available[] = $name; } } diff --git a/src/Configuration/Section/AbstractSection.php b/src/Configuration/Section/AbstractSection.php index abe0f1d..47ddb1c 100644 --- a/src/Configuration/Section/AbstractSection.php +++ b/src/Configuration/Section/AbstractSection.php @@ -6,10 +6,12 @@ abstract class AbstractSection implements SectionInterface { + #[\Override] public function getRequired(): array { return []; } + #[\Override] abstract public function render(): array; } diff --git a/src/Configuration/Section/Amqp.php b/src/Configuration/Section/Amqp.php index 162b8be..7d12c67 100644 --- a/src/Configuration/Section/Amqp.php +++ b/src/Configuration/Section/Amqp.php @@ -8,11 +8,13 @@ final class Amqp extends AbstractSection { private const NAME = 'amqp'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Beanstalk.php b/src/Configuration/Section/Beanstalk.php index 5c7c9a5..ed3e14c 100644 --- a/src/Configuration/Section/Beanstalk.php +++ b/src/Configuration/Section/Beanstalk.php @@ -8,11 +8,13 @@ final class Beanstalk extends AbstractSection { private const NAME = 'beanstalk'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Boltdb.php b/src/Configuration/Section/Boltdb.php index 4be4186..cb9ec3b 100644 --- a/src/Configuration/Section/Boltdb.php +++ b/src/Configuration/Section/Boltdb.php @@ -8,11 +8,13 @@ final class Boltdb extends AbstractSection { private const NAME = 'boltdb'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Broadcast.php b/src/Configuration/Section/Broadcast.php index d4bd2de..2b7174e 100644 --- a/src/Configuration/Section/Broadcast.php +++ b/src/Configuration/Section/Broadcast.php @@ -8,11 +8,13 @@ final class Broadcast extends AbstractSection { private const NAME = 'broadcast'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Endure.php b/src/Configuration/Section/Endure.php index 60a17b7..8b0e698 100644 --- a/src/Configuration/Section/Endure.php +++ b/src/Configuration/Section/Endure.php @@ -8,11 +8,13 @@ final class Endure extends AbstractSection { private const NAME = 'endure'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Fileserver.php b/src/Configuration/Section/Fileserver.php index 6e39af4..3f2d1ba 100644 --- a/src/Configuration/Section/Fileserver.php +++ b/src/Configuration/Section/Fileserver.php @@ -8,11 +8,13 @@ final class Fileserver extends AbstractSection { private const NAME = 'fileserver'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Grpc.php b/src/Configuration/Section/Grpc.php index 08ccbf8..1a59de2 100644 --- a/src/Configuration/Section/Grpc.php +++ b/src/Configuration/Section/Grpc.php @@ -8,11 +8,13 @@ final class Grpc extends AbstractSection { private const NAME = 'grpc'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ @@ -46,6 +48,7 @@ public function render(): array ]; } + #[\Override] public function getRequired(): array { return [ diff --git a/src/Configuration/Section/Http.php b/src/Configuration/Section/Http.php index cc8efc7..be74a40 100644 --- a/src/Configuration/Section/Http.php +++ b/src/Configuration/Section/Http.php @@ -8,11 +8,13 @@ final class Http extends AbstractSection { private const NAME = 'http'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ @@ -36,6 +38,7 @@ public function render(): array ]; } + #[\Override] public function getRequired(): array { return [ diff --git a/src/Configuration/Section/Jobs.php b/src/Configuration/Section/Jobs.php index 720913c..dd2a8c6 100644 --- a/src/Configuration/Section/Jobs.php +++ b/src/Configuration/Section/Jobs.php @@ -8,11 +8,13 @@ final class Jobs extends AbstractSection { private const NAME = 'jobs'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ @@ -26,6 +28,7 @@ public function render(): array ]; } + #[\Override] public function getRequired(): array { return [ diff --git a/src/Configuration/Section/Kv.php b/src/Configuration/Section/Kv.php index 24d1645..c56c157 100644 --- a/src/Configuration/Section/Kv.php +++ b/src/Configuration/Section/Kv.php @@ -8,11 +8,13 @@ final class Kv extends AbstractSection { private const NAME = 'kv'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Logs.php b/src/Configuration/Section/Logs.php index 799b9f5..d07efd4 100644 --- a/src/Configuration/Section/Logs.php +++ b/src/Configuration/Section/Logs.php @@ -8,11 +8,13 @@ final class Logs extends AbstractSection { private const NAME = 'logs'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Metrics.php b/src/Configuration/Section/Metrics.php index 5666fff..57f1195 100644 --- a/src/Configuration/Section/Metrics.php +++ b/src/Configuration/Section/Metrics.php @@ -8,11 +8,13 @@ final class Metrics extends AbstractSection { private const NAME = 'metrics'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Nats.php b/src/Configuration/Section/Nats.php index a4a0e38..9afbec3 100644 --- a/src/Configuration/Section/Nats.php +++ b/src/Configuration/Section/Nats.php @@ -8,11 +8,13 @@ final class Nats extends AbstractSection { private const NAME = 'nats'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Otel.php b/src/Configuration/Section/Otel.php index f517ee3..b5523ec 100644 --- a/src/Configuration/Section/Otel.php +++ b/src/Configuration/Section/Otel.php @@ -8,11 +8,13 @@ final class Otel extends AbstractSection { private const NAME = 'otel'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Redis.php b/src/Configuration/Section/Redis.php index 18cccf7..73e0c13 100644 --- a/src/Configuration/Section/Redis.php +++ b/src/Configuration/Section/Redis.php @@ -8,11 +8,13 @@ final class Redis extends AbstractSection { private const NAME = 'redis'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Reload.php b/src/Configuration/Section/Reload.php index 5e59d74..c21664e 100644 --- a/src/Configuration/Section/Reload.php +++ b/src/Configuration/Section/Reload.php @@ -8,11 +8,13 @@ final class Reload extends AbstractSection { private const NAME = 'reload'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Rpc.php b/src/Configuration/Section/Rpc.php index 4e7e860..439656e 100644 --- a/src/Configuration/Section/Rpc.php +++ b/src/Configuration/Section/Rpc.php @@ -8,11 +8,13 @@ final class Rpc extends AbstractSection { private const NAME = 'rpc'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/SectionInterface.php b/src/Configuration/Section/SectionInterface.php index 10c898b..74b862e 100644 --- a/src/Configuration/Section/SectionInterface.php +++ b/src/Configuration/Section/SectionInterface.php @@ -10,5 +10,8 @@ public static function getShortName(): string; public function render(): array; + /** + * @return list> Sections this one depends on. + */ public function getRequired(): array; } diff --git a/src/Configuration/Section/Server.php b/src/Configuration/Section/Server.php index 2699773..6d40417 100644 --- a/src/Configuration/Section/Server.php +++ b/src/Configuration/Section/Server.php @@ -8,11 +8,13 @@ final class Server extends AbstractSection { private const NAME = 'server'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Service.php b/src/Configuration/Section/Service.php index fdfbeb7..626ff3d 100644 --- a/src/Configuration/Section/Service.php +++ b/src/Configuration/Section/Service.php @@ -8,11 +8,13 @@ final class Service extends AbstractSection { private const NAME = 'service'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Sqs.php b/src/Configuration/Section/Sqs.php index a9c1f0c..eaf832e 100644 --- a/src/Configuration/Section/Sqs.php +++ b/src/Configuration/Section/Sqs.php @@ -8,11 +8,13 @@ final class Sqs extends AbstractSection { private const NAME = 'sqs'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Status.php b/src/Configuration/Section/Status.php index 5ede9e1..29e117d 100644 --- a/src/Configuration/Section/Status.php +++ b/src/Configuration/Section/Status.php @@ -8,11 +8,13 @@ final class Status extends AbstractSection { private const NAME = 'status'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Tcp.php b/src/Configuration/Section/Tcp.php index a2c148d..b0ba9c5 100644 --- a/src/Configuration/Section/Tcp.php +++ b/src/Configuration/Section/Tcp.php @@ -8,11 +8,13 @@ final class Tcp extends AbstractSection { private const NAME = 'tcp'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ @@ -44,6 +46,7 @@ public function render(): array ]; } + #[\Override] public function getRequired(): array { return [ diff --git a/src/Configuration/Section/Temporal.php b/src/Configuration/Section/Temporal.php index ae6aaae..49b21b4 100644 --- a/src/Configuration/Section/Temporal.php +++ b/src/Configuration/Section/Temporal.php @@ -8,11 +8,13 @@ final class Temporal extends AbstractSection { private const NAME = 'temporal'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Version.php b/src/Configuration/Section/Version.php index 0c47cc4..bcc0191 100644 --- a/src/Configuration/Section/Version.php +++ b/src/Configuration/Section/Version.php @@ -9,11 +9,13 @@ final class Version extends AbstractSection private const NAME = 'version'; private const CONFIG_VERSION = '3'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/Configuration/Section/Websockets.php b/src/Configuration/Section/Websockets.php index 4692d1b..47c382f 100644 --- a/src/Configuration/Section/Websockets.php +++ b/src/Configuration/Section/Websockets.php @@ -8,11 +8,13 @@ final class Websockets extends AbstractSection { private const NAME = 'websockets'; + #[\Override] public static function getShortName(): string { return self::NAME; } + #[\Override] public function render(): array { return [ diff --git a/src/DownloadProtocBinaryCommand.php b/src/DownloadProtocBinaryCommand.php index 13ebd0b..939717f 100644 --- a/src/DownloadProtocBinaryCommand.php +++ b/src/DownloadProtocBinaryCommand.php @@ -44,11 +44,13 @@ public function __construct(?string $name = null) $this->stability = new StabilityOption($this); } + #[\Override] public function getDescription(): string { return 'Install or update protoc-gen-php-grpc binary'; } + #[\Override] public function execute(InputInterface $input, OutputInterface $output): int { $io = $this->io($input, $output); @@ -113,6 +115,7 @@ private function installBinary( $file = null; while ($extractor->valid()) { $file = $extractor->current(); + \assert($file instanceof \SplFileInfo); if (!$this->checkExisting($file, $io)) { $extractor->send(false); diff --git a/src/Environment/OperatingSystem.php b/src/Environment/OperatingSystem.php index 8ba71a0..05d66f8 100644 --- a/src/Environment/OperatingSystem.php +++ b/src/Environment/OperatingSystem.php @@ -50,7 +50,7 @@ final class OperatingSystem #[ExpectedValues(valuesFromClass: OperatingSystem::class)] public static function createFromGlobals(?array $variables = null): string { - return (new Factory())->createFromGlobals($variables); + return (new Factory())->createFromGlobals(); } public static function isValid(string $value): bool diff --git a/src/Environment/Stability.php b/src/Environment/Stability.php index 30fb089..6eda303 100644 --- a/src/Environment/Stability.php +++ b/src/Environment/Stability.php @@ -53,7 +53,7 @@ final class Stability ]; /** - * @param StabilityType $type + * @param StabilityType|string $type Unknown stabilities weigh as "dev". * @return positive-int|0 */ public static function toInt(string $type): int diff --git a/src/GetBinaryCommand.php b/src/GetBinaryCommand.php index b7c1401..95a59a0 100644 --- a/src/GetBinaryCommand.php +++ b/src/GetBinaryCommand.php @@ -56,6 +56,7 @@ public function __construct(?string $name = null) $this->stability = new StabilityOption($this); } + #[\Override] public function getDescription(): string { return 'Install or update RoadRunner binary'; @@ -65,6 +66,7 @@ public function getDescription(): string * * @throws \Throwable */ + #[\Override] public function execute(InputInterface $input, OutputInterface $output): int { $io = $this->io($input, $output); @@ -84,10 +86,6 @@ public function execute(InputInterface $input, OutputInterface $output): int // List of all available releases $releases = $this->version->find($input, $io, $repository); - /** - * @var AssetInterface $asset - * @var ReleaseInterface $release - */ [$asset, $release] = $this->findAsset($repository, $releases, $input, $io); // Installation @@ -129,6 +127,7 @@ public function execute(InputInterface $input, OutputInterface $output): int return 0; } + #[\Override] protected function configure(): void { $this->addOption( @@ -173,6 +172,7 @@ private function installBinary( $file = null; while ($extractor->valid()) { $file = $extractor->current(); + \assert($file instanceof \SplFileInfo); if (! $this->checkExisting($file, $io)) { $extractor->send(false); @@ -199,7 +199,7 @@ private function installConfig(string $to, InputInterface $in, StyleInterface $i { $to .= '/.rr.yaml'; - if (\is_file($to) || \is_file(\getcwd() . '/.rr.yaml')) { + if (\is_file($to) || \is_file((string) \getcwd() . '/.rr.yaml')) { return false; } @@ -208,9 +208,11 @@ private function installConfig(string $to, InputInterface $in, StyleInterface $i } $generator = new Generator(); - $plugins = $in->getOption('preset') ? - Plugins::fromPreset($in->getOption('preset')) : - Plugins::fromPlugins($in->getOption('plugin')); + /** @var string|null $preset */ + $preset = $in->getOption('preset'); + /** @var string[] $names */ + $names = $in->getOption('plugin'); + $plugins = $preset !== null && $preset !== '' ? Plugins::fromPreset($preset) : Plugins::fromPlugins($names); try { $config = $generator->generate($plugins); @@ -218,6 +220,7 @@ private function installConfig(string $to, InputInterface $in, StyleInterface $i $io->error($e->getMessage()); } + /** @psalm-suppress PossiblyUndefinedVariable https://github.com/roadrunner-php/cli/issues/62 */ \file_put_contents($to, $config); return true; diff --git a/src/MakeConfigCommand.php b/src/MakeConfigCommand.php index 8a531da..5c87e11 100644 --- a/src/MakeConfigCommand.php +++ b/src/MakeConfigCommand.php @@ -25,6 +25,7 @@ public function __construct(?string $name = null) * * @throws \Throwable */ + #[\Override] public function execute(InputInterface $input, OutputInterface $output): int { $io = $this->io($input, $output); @@ -32,14 +33,16 @@ public function execute(InputInterface $input, OutputInterface $output): int $target = $this->location->get($input, $io) . '/.rr.yaml'; - if (\is_file($target) || \is_file(\getcwd() . '/.rr.yaml')) { + if (\is_file($target) || \is_file((string) \getcwd() . '/.rr.yaml')) { return self::FAILURE; } $generator = new Generator(); - $plugins = $input->getOption('preset') ? - Plugins::fromPreset($input->getOption('preset')) : - Plugins::fromPlugins($input->getOption('plugin')); + /** @var string|null $preset */ + $preset = $input->getOption('preset'); + /** @var string[] $names */ + $names = $input->getOption('plugin'); + $plugins = $preset !== null && $preset !== '' ? Plugins::fromPreset($preset) : Plugins::fromPlugins($names); try { $config = $generator->generate($plugins); @@ -52,6 +55,7 @@ public function execute(InputInterface $input, OutputInterface $output): int return self::SUCCESS; } + #[\Override] protected function configure(): void { $this->addOption( diff --git a/src/Repository/Asset.php b/src/Repository/Asset.php index 456607c..8033b11 100644 --- a/src/Repository/Asset.php +++ b/src/Repository/Asset.php @@ -22,11 +22,13 @@ public function __construct(string $name, string $uri) $this->uri = $uri; } + #[\Override] public function getName(): string { return $this->name; } + #[\Override] public function getUri(): string { return $this->uri; diff --git a/src/Repository/Collection.php b/src/Repository/Collection.php index 87297e2..1fa3d13 100644 --- a/src/Repository/Collection.php +++ b/src/Repository/Collection.php @@ -18,6 +18,9 @@ * @template T * * @template-implements \IteratorAggregate + * + * The constructor is final and every subclass is final with a fixed item type, so `new static` is safe. + * @psalm-suppress UnsafeGenericInstantiation */ abstract class Collection implements \IteratorAggregate, \Countable { @@ -122,11 +125,13 @@ public function firstOr(callable $otherwise, ?callable $filter = null): object return $this->first($filter) ?? $otherwise(); } + #[\Override] public function getIterator(): \Traversable { return new \ArrayIterator($this->items); } + #[\Override] public function count(): int { return \count($this->items); diff --git a/src/Repository/GitHub/GitHubAsset.php b/src/Repository/GitHub/GitHubAsset.php index 7f2fd8c..279eb65 100644 --- a/src/Repository/GitHub/GitHubAsset.php +++ b/src/Repository/GitHub/GitHubAsset.php @@ -61,6 +61,7 @@ public static function fromApiResponse(HttpClientInterface $client, array $asset * * @throws ExceptionInterface */ + #[\Override] public function download(?\Closure $progress = null): \Traversable { $response = $this->client->request('GET', $this->getUri(), [ diff --git a/src/Repository/GitHub/GitHubRelease.php b/src/Repository/GitHub/GitHubRelease.php index c9e1a55..80b4886 100644 --- a/src/Repository/GitHub/GitHubRelease.php +++ b/src/Repository/GitHub/GitHubRelease.php @@ -21,7 +21,8 @@ * * @psalm-type GitHubReleaseApiResponse = array { * name: string, - * assets: array + * tag_name: string, + * assets?: array * } */ final class GitHubRelease extends Release @@ -67,6 +68,7 @@ public static function fromApiResponse(GitHubRepository $repository, HttpClientI return new self($client, $name, $version, $repository->getName(), AssetsCollection::from($instantiator)); } + #[\Override] public function getConfig(): string { $config = \vsprintf('https://raw.githubusercontent.com/%s/%s/.rr.yaml', [ @@ -85,7 +87,7 @@ public function getConfig(): string * Note: The return value is "pretty", but that does not mean that the * tag physically exists. * - * @param array { tag_name: string, name: string } $release + * @param GitHubReleaseApiResponse $release */ private static function getTagName(array $release): string { diff --git a/src/Repository/GitHub/GitHubRepository.php b/src/Repository/GitHub/GitHubRepository.php index 4351e14..339eb81 100644 --- a/src/Repository/GitHub/GitHubRepository.php +++ b/src/Repository/GitHub/GitHubRepository.php @@ -54,6 +54,7 @@ public static function create(string $owner, string $name, ?HttpClientInterface * * @throws ExceptionInterface */ + #[\Override] public function getReleases(): ReleasesCollection { return ReleasesCollection::from(function () { @@ -70,6 +71,7 @@ public function getReleases(): ReleasesCollection }); } + #[\Override] public function getName(): string { return $this->name; diff --git a/src/Repository/Release.php b/src/Repository/Release.php index d3d03be..ea7fee2 100644 --- a/src/Repository/Release.php +++ b/src/Repository/Release.php @@ -16,10 +16,16 @@ use JetBrains\PhpStorm\ExpectedValues; use Spiral\RoadRunner\Console\Environment\Stability; +/** + * @psalm-import-type StabilityType from Stability + */ abstract class Release implements ReleaseInterface { private string $name; + /** + * @var StabilityType + */ #[ExpectedValues(valuesFromClass: Stability::class)] private string $stability; @@ -38,37 +44,46 @@ public function __construct(string $name, string $version, string $repository, i $this->stability = $this->parseStability($version); } + #[\Override] public function getName(): string { return $this->name; } + #[\Override] public function getVersion(): string { return $this->version; } + #[\Override] public function getRepositoryName(): string { return $this->repository; } + #[\Override] #[ExpectedValues(valuesFromClass: Stability::class)] public function getStability(): string { return $this->stability; } + #[\Override] public function getAssets(): AssetsCollection { return $this->assets; } + #[\Override] public function satisfies(string $constraint): bool { return Semver::satisfies($this->getName(), $constraint); } + /** + * @return StabilityType + */ private function parseStability(string $version): string { return VersionParser::parseStability($version); diff --git a/src/Repository/ReleaseInterface.php b/src/Repository/ReleaseInterface.php index 5828d6e..cae7dbc 100644 --- a/src/Repository/ReleaseInterface.php +++ b/src/Repository/ReleaseInterface.php @@ -41,9 +41,6 @@ public function getRepositoryName(): string; #[ExpectedValues(valuesFromClass: Stability::class)] public function getStability(): string; - /** - * @return AssetsCollection|iterable - */ public function getAssets(): AssetsCollection; public function satisfies(string $constraint): bool; diff --git a/src/Repository/ReleasesCollection.php b/src/Repository/ReleasesCollection.php index 3048f0d..b885538 100644 --- a/src/Repository/ReleasesCollection.php +++ b/src/Repository/ReleasesCollection.php @@ -94,7 +94,7 @@ public function stability(string $stability): self } /** - * @param StabilityType $stability + * @param StabilityType|string $stability Unknown stabilities weigh as "dev". * @return $this */ public function minimumStability(string $stability): self diff --git a/src/Repository/RepositoriesCollection.php b/src/Repository/RepositoriesCollection.php index 6ebfd2b..0755934 100644 --- a/src/Repository/RepositoriesCollection.php +++ b/src/Repository/RepositoriesCollection.php @@ -26,11 +26,13 @@ public function __construct(array $repositories) $this->repositories = $repositories; } + #[\Override] public function getName(): string { return 'unknown/unknown'; } + #[\Override] public function getReleases(): ReleasesCollection { return ReleasesCollection::from(function () { diff --git a/src/Repository/RepositoryInterface.php b/src/Repository/RepositoryInterface.php index fe1ba66..44d2328 100644 --- a/src/Repository/RepositoryInterface.php +++ b/src/Repository/RepositoryInterface.php @@ -15,8 +15,5 @@ interface RepositoryInterface { public function getName(): string; - /** - * @return ReleasesCollection|iterable - */ public function getReleases(): ReleasesCollection; } diff --git a/src/Repository/Version1/StaticRepository.php b/src/Repository/Version1/StaticRepository.php index 785ccac..f52c458 100644 --- a/src/Repository/Version1/StaticRepository.php +++ b/src/Repository/Version1/StaticRepository.php @@ -1224,11 +1224,13 @@ public function __construct(?HttpClientInterface $client = null) } } + #[\Override] public function getName(): string { return 'spiral/roadrunner'; } + #[\Override] public function getReleases(): ReleasesCollection { return new ReleasesCollection($this->releases); diff --git a/src/VersionsCommand.php b/src/VersionsCommand.php index 7521c51..f828ead 100644 --- a/src/VersionsCommand.php +++ b/src/VersionsCommand.php @@ -38,6 +38,7 @@ public function __construct(?string $name = null) $this->stability = new StabilityOption($this); $this->version = new class($this) extends VersionFilterOption { + #[\Override] protected function default(): string { return '*'; @@ -45,11 +46,13 @@ protected function default(): string }; } + #[\Override] public function getDescription(): string { return 'Returns a list of all available RoadRunner versions'; } + #[\Override] public function execute(InputInterface $input, OutputInterface $output): int { $io = $this->io($input, $output);