From b3366393526b9ecad82c8ca6ec289a4757667b0c Mon Sep 17 00:00:00 2001 From: Jack Wilkinson Date: Wed, 12 Mar 2025 22:37:12 +0000 Subject: [PATCH 1/6] Added fix for UA contact --- src/Package/Packagist.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Package/Packagist.php b/src/Package/Packagist.php index bd76665..dbef62d 100644 --- a/src/Package/Packagist.php +++ b/src/Package/Packagist.php @@ -27,7 +27,7 @@ class Packagist protected const PACKAGIST_API_URL = 'https://packagist.org/'; protected const PACKAGIST_REPO_URL = 'https://repo.packagist.org/p2/'; - protected static string $agent = 'Winter Packager '; + protected static string $agent = 'Winter Packager '; protected static ?Storage $storage = null; From 32cdf0f9a752f5c5222e38db01425f0f35c4fd2b Mon Sep 17 00:00:00 2001 From: Jack Wilkinson Date: Wed, 12 Mar 2025 22:37:33 +0000 Subject: [PATCH 2/6] Added path to packages objects --- src/Package/DetailedPackage.php | 3 ++- src/Package/DetailedVersionedPackage.php | 2 ++ src/Package/Package.php | 11 +++++++++++ src/Package/VersionedPackage.php | 3 ++- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Package/DetailedPackage.php b/src/Package/DetailedPackage.php index 298eaf2..865789a 100644 --- a/src/Package/DetailedPackage.php +++ b/src/Package/DetailedPackage.php @@ -28,6 +28,7 @@ public function __construct( string $name, string $description = '', protected string $type = 'library', + protected ?string $path = null, protected array $keywords = [], protected string $homepage = '', protected array $authors = [], @@ -42,7 +43,7 @@ public function __construct( protected array $replaces = [], protected string $readme = '', ) { - parent::__construct($namespace, $name, $description, $type); + parent::__construct($namespace, $name, $description, $type, $path); } /** diff --git a/src/Package/DetailedVersionedPackage.php b/src/Package/DetailedVersionedPackage.php index f8f09e8..195df24 100644 --- a/src/Package/DetailedVersionedPackage.php +++ b/src/Package/DetailedVersionedPackage.php @@ -34,6 +34,7 @@ public function __construct( string $name, string $description = '', protected string $type = 'library', + protected ?string $path = null, protected array $keywords = [], protected string $homepage = '', protected array $authors = [], @@ -56,6 +57,7 @@ public function __construct( $name, $description, $type, + $path, $keywords, $homepage, $authors, diff --git a/src/Package/Package.php b/src/Package/Package.php index 2e43201..cdd5260 100644 --- a/src/Package/Package.php +++ b/src/Package/Package.php @@ -26,6 +26,7 @@ public function __construct( protected string $name, protected string $description = '', protected string $type = '', + protected ?string $path = null, ) { } @@ -74,6 +75,16 @@ public function setType(string $type): void $this->type = $type; } + public function getPath(): ?string + { + return $this->path; + } + + public function setPath(string $path): void + { + $this->path = $path; + } + public function toDetailed(): DetailedPackage { $details = Packagist::getPackage($this->namespace, $this->name); diff --git a/src/Package/VersionedPackage.php b/src/Package/VersionedPackage.php index 8ccca14..013d2ee 100644 --- a/src/Package/VersionedPackage.php +++ b/src/Package/VersionedPackage.php @@ -20,11 +20,12 @@ public function __construct( string $name, string $description = '', string $type = '', + string $path = '', protected string $version = '', protected string $latestVersion = '', protected VersionStatus $updateStatus = VersionStatus::UP_TO_DATE, ) { - parent::__construct($namespace, $name, $description, $type); + parent::__construct($namespace, $name, $description, $type, $path); $this->versionNormalized = $this->normalizeVersion($this->version); } From fd61fe6e063318b86696d1ecbec6ca65f7eac028 Mon Sep 17 00:00:00 2001 From: Jack Wilkinson Date: Wed, 12 Mar 2025 22:38:10 +0000 Subject: [PATCH 3/6] Added commands and added extra functionality --- src/Commands/Remove.php | 69 ++++++++++++++++++++++++++++++ src/Commands/RequireCommand.php | 74 +++++++++++++++++++++++++++++++++ src/Commands/Search.php | 11 ++++- src/Commands/Show.php | 6 ++- src/Commands/Update.php | 20 +++++---- 5 files changed, 168 insertions(+), 12 deletions(-) create mode 100644 src/Commands/Remove.php create mode 100644 src/Commands/RequireCommand.php diff --git a/src/Commands/Remove.php b/src/Commands/Remove.php new file mode 100644 index 0000000..e64e329 --- /dev/null +++ b/src/Commands/Remove.php @@ -0,0 +1,69 @@ +dryRun) { + $arguments['--dry-run'] = true; + } + + if ($this->dev) { + $arguments['--dev'] = true; + } + + $arguments['packages'] = [$this->package]; + + return $arguments; + } + + public function execute() + { + $output = $this->runComposerCommand(); + $message = implode(PHP_EOL, $output['output']); + + if ($output['code'] !== 0) { + throw new CommandException($message); + } + + return $message; + } + + /** + * @inheritDoc + */ + protected function requiresWorkDir(): bool + { + return true; + } + + /** + * @inheritDoc + */ + public function getCommandName(): string + { + return 'remove'; + } +} diff --git a/src/Commands/RequireCommand.php b/src/Commands/RequireCommand.php new file mode 100644 index 0000000..209be1e --- /dev/null +++ b/src/Commands/RequireCommand.php @@ -0,0 +1,74 @@ +dryRun) { + $arguments['--dry-run'] = true; + } + + if ($this->dev) { + $arguments['--dev'] = true; + } + + $arguments['packages'] = [$this->package]; + + return $arguments; + } + + /** + * @throws CommandException + * @throws WorkDirException + */ + public function execute(): string + { + $output = $this->runComposerCommand(); + $message = implode(PHP_EOL, $output['output']); + + if ($output['code'] !== 0) { + throw new CommandException($message); + } + + return $message; + } + + /** + * @inheritDoc + */ + protected function requiresWorkDir(): bool + { + return true; + } + + /** + * @inheritDoc + */ + public function getCommandName(): string + { + return 'require'; + } +} diff --git a/src/Commands/Search.php b/src/Commands/Search.php index abb2a00..155c28d 100644 --- a/src/Commands/Search.php +++ b/src/Commands/Search.php @@ -23,12 +23,14 @@ class Search extends BaseCommand * @param string $query The search query to find packages. * @param string|null $type The type of package to search for. * @param SearchLimitTo $limitTo Limit the returned results. + * @param bool $returnArray Return the search results as an array. */ final public function __construct( Composer $composer, public string $query, public ?string $type = null, - public SearchLimitTo $limitTo = SearchLimitTo::ALL + public SearchLimitTo $limitTo = SearchLimitTo::ALL, + public bool $returnArray = false, ) { parent::__construct($composer); } @@ -44,7 +46,12 @@ public function execute() throw new CommandException(implode(PHP_EOL, $output['output'])); } - $results = json_decode(implode(PHP_EOL, $output['output']), true); + $results = json_decode(implode(PHP_EOL, $output['output']), JSON_OBJECT_AS_ARRAY) ?? []; + + if ($this->returnArray) { + return $results; + } + $packages = []; foreach ($results as $result) { diff --git a/src/Commands/Show.php b/src/Commands/Show.php index e946636..2bacb53 100644 --- a/src/Commands/Show.php +++ b/src/Commands/Show.php @@ -138,6 +138,7 @@ public function execute() description: $result['description'] ?? '', keywords: $result['keywords'] ?? [], type: $result['type'] ?? 'library', + path: $result['path'] ?? null, homepage: $result['homepage'] ?? '', authors: $result['authors'] ?? [], licenses: $result['licenses'] ?? [], @@ -158,6 +159,7 @@ public function execute() description: $result['description'] ?? '', keywords: $result['keywords'] ?? [], type: $result['type'] ?? 'library', + path: $result['path'] ?? null, homepage: $result['homepage'] ?? '', authors: $result['authors'] ?? [], licenses: $result['licenses'] ?? [], @@ -178,9 +180,10 @@ public function execute() $name, $result['description'] ?? '', $result['type'] ?? '', + $result['path'] ?? null, $result['version'], $result['latest'] ?? '', - VersionStatus::tryFrom($result['latest-status'] ?? '') ?? VersionStatus::UP_TO_DATE + VersionStatus::tryFrom($result['latest-status'] ?? '') ?? VersionStatus::UP_TO_DATE, ); } else { return Composer::newPackage( @@ -188,6 +191,7 @@ public function execute() $name, $result['description'] ?? '', $result['type'] ?? '', + $result['path'] ?? null ); } } diff --git a/src/Commands/Update.php b/src/Commands/Update.php index 7e6e1bc..d817916 100644 --- a/src/Commands/Update.php +++ b/src/Commands/Update.php @@ -65,6 +65,7 @@ class Update extends BaseCommand * @param boolean $ignorePlatformReqs Ignore platform reqs when running the update. * @param string $installPreference Set an install preference - must be one of "none", "dist", "source" * @param boolean $ignoreScripts Ignores scripts that run after Composer events. + * @param ?string $package Specify a specific package to update. * @return void */ final public function __construct( @@ -74,18 +75,15 @@ final public function __construct( protected bool $ignorePlatformReqs = false, protected string $installPreference = 'none', protected bool $ignoreScripts = false, - protected bool $dryRun = false + protected bool $dryRun = false, + protected ?string $package = null ) { parent::__construct($composer); - $this->includeDev = $includeDev; - $this->lockFileOnly = $lockFileOnly; - $this->ignorePlatformReqs = $ignorePlatformReqs; - $this->ignoreScripts = $ignoreScripts; - $this->dryRun = $dryRun; - - if (in_array($installPreference, [self::PREFER_NONE, self::PREFER_DIST, self::PREFER_SOURCE])) { - $this->installPreference = $installPreference; + if (!in_array($this->installPreference, [self::PREFER_NONE, self::PREFER_DIST, self::PREFER_SOURCE])) { + throw new \InvalidArgumentException( + 'installPreference is not an allowed value `' . $this->installPreference . '`. See: "none", "dist", "source"' + ); } } @@ -337,6 +335,10 @@ protected function arguments(): array $arguments['--prefer-' . $this->installPreference] = true; } + if ($this->package) { + $arguments['packages'] = [$this->package]; + } + return $arguments; } } From d52ad8d928ec90532c55804e20c5410e5ecaf102 Mon Sep 17 00:00:00 2001 From: Jack Wilkinson Date: Wed, 12 Mar 2025 22:38:31 +0000 Subject: [PATCH 4/6] Added new commands to composer object and added docs --- src/Composer.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Composer.php b/src/Composer.php index ca421d9..f8688ed 100644 --- a/src/Composer.php +++ b/src/Composer.php @@ -4,6 +4,8 @@ use Throwable; use Winter\Packager\Commands\Command; +use Winter\Packager\Enums\SearchLimitTo; +use Winter\Packager\Enums\ShowMode; use Winter\Packager\Package\Collection; use Winter\Packager\Package\Constraint; use Winter\Packager\Package\DetailedPackage; @@ -23,8 +25,10 @@ * @since 0.1.0 * @method \Winter\Packager\Commands\Install i(bool $includeDev = true, bool $lockFileOnly = false, bool $ignorePlatformReqs = false, string $installPreference = 'none', bool $ignoreScripts = false, bool $dryRun = false) Install command * @method \Winter\Packager\Commands\Install install(bool $includeDev = true, bool $lockFileOnly = false, bool $ignorePlatformReqs = false, string $installPreference = 'none', bool $ignoreScripts = false, bool $dryRun = false) Install command - * @method \Winter\Packager\Package\Collection search() Search command - * @method \Winter\Packager\Package\Collection|\Winter\Packager\Package\Package|null show() Show command + * @method \Winter\Packager\Commands\Remove remove(string $package, bool $dryRun = false, bool $dev = false) Remove command + * @method \Winter\Packager\Commands\RequireCommand require(string $package, bool $dryRun = false, bool $dev = false) Require command + * @method \Winter\Packager\Package\Collection search(string $query, ?string $type = null, SearchLimitTo $limitTo = SearchLimitTo::ALL, bool $returnArray = false) Search command + * @method \Winter\Packager\Package\Collection|\Winter\Packager\Package\Package|null show(ShowMode $mode = ShowMode::INSTALLED, ?string $package = null, bool $noDev = false) Show command * @method \Winter\Packager\Commands\Update update(bool $includeDev = true, bool $lockFileOnly = false, bool $ignorePlatformReqs = false, string $installPreference = 'none', bool $ignoreScripts = false, bool $dryRun = false) Update command * @method string version(string $detail = 'version') Version command */ @@ -79,9 +83,11 @@ class Composer * @var array A list of supported commands */ protected array $commands = [ - 'list' => \Winter\Packager\Commands\ListCommand::class, 'i' => \Winter\Packager\Commands\Install::class, 'install' => \Winter\Packager\Commands\Install::class, + 'list' => \Winter\Packager\Commands\ListCommand::class, + 'require' => \Winter\Packager\Commands\RequireCommand::class, + 'remove' => \Winter\Packager\Commands\Remove::class, 'search' => \Winter\Packager\Commands\Search::class, 'show' => \Winter\Packager\Commands\Show::class, 'update' => \Winter\Packager\Commands\Update::class, From e11b126d2eabacc0be92f97671a5fac38bf15e5b Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Sun, 27 Jul 2025 23:58:54 -0600 Subject: [PATCH 5/6] Fix tests --- src/Commands/Search.php | 2 +- src/Commands/Show.php | 1 + src/Composer.php | 129 ++++++++++++++++++++++++++-- src/Package/VersionedPackage.php | 2 +- tests/Cases/Package/PackageTest.php | 24 +++++- 5 files changed, 145 insertions(+), 13 deletions(-) diff --git a/src/Commands/Search.php b/src/Commands/Search.php index 155c28d..30c207b 100644 --- a/src/Commands/Search.php +++ b/src/Commands/Search.php @@ -46,7 +46,7 @@ public function execute() throw new CommandException(implode(PHP_EOL, $output['output'])); } - $results = json_decode(implode(PHP_EOL, $output['output']), JSON_OBJECT_AS_ARRAY) ?? []; + $results = json_decode(implode(PHP_EOL, $output['output']), flags: JSON_OBJECT_AS_ARRAY) ?? []; if ($this->returnArray) { return $results; diff --git a/src/Commands/Show.php b/src/Commands/Show.php index 2bacb53..562a983 100644 --- a/src/Commands/Show.php +++ b/src/Commands/Show.php @@ -76,6 +76,7 @@ public function execute() $name, $result['description'] ?? '', $result['type'] ?? '', + null, $result['version'], $result['latest'] ?? '', VersionStatus::tryFrom($result['latest-status'] ?? '') ?? VersionStatus::UP_TO_DATE diff --git a/src/Composer.php b/src/Composer.php index f8688ed..1eff636 100644 --- a/src/Composer.php +++ b/src/Composer.php @@ -6,6 +6,7 @@ use Winter\Packager\Commands\Command; use Winter\Packager\Enums\SearchLimitTo; use Winter\Packager\Enums\ShowMode; +use Winter\Packager\Enums\VersionStatus; use Winter\Packager\Package\Collection; use Winter\Packager\Package\Constraint; use Winter\Packager\Package\DetailedPackage; @@ -460,37 +461,149 @@ public static function setPackageClass(string|array $type, ?string $class = null /** * Create a new package instance. */ - public static function newPackage(mixed ...$arguments): Package + public static function newPackage( + string $namespace, + string $name, + string $description = '', + string $type = '', + ?string $path = null + ): Package { $class = static::$packageClasses['package']; - return new $class(...$arguments); + return new $class( + namespace: $namespace, + name: $name, + description: $description, + type: $type, + path: $path + ); } /** * Create a new versioned package instance. */ - public static function newVersionedPackage(mixed ...$arguments): VersionedPackage + public static function newVersionedPackage( + string $namespace, + string $name, + string $description = '', + string $type = '', + ?string $path = null, + string $version = '', + string $latestVersion = '', + VersionStatus $updateStatus = VersionStatus::UP_TO_DATE, + ): VersionedPackage { $class = static::$packageClasses['versionedPackage']; - return new $class(...$arguments); + return new $class( + namespace: $namespace, + name: $name, + description: $description, + type: $type, + path: $path, + version: $version, + latestVersion: $latestVersion, + updateStatus: $updateStatus, + ); } /** * Create a new detailed package instance. */ - public static function newDetailedPackage(mixed ...$arguments): DetailedPackage + public static function newDetailedPackage( + string $namespace, + string $name, + string $description = '', + string $type = 'library', + ?string $path = null, + array $keywords = [], + string $homepage = '', + array $authors = [], + array $licenses = [], + array $support = [], + array $funding = [], + array $requires = [], + array $devRequires = [], + array $extras = [], + array $suggests = [], + array $conflicts = [], + array $replaces = [], + string $readme = '', + ): DetailedPackage { $class = static::$packageClasses['detailedPackage']; - return new $class(...$arguments); + return new $class( + namespace: $namespace, + name: $name, + description: $description, + type: $type, + path: $path, + keywords: $keywords, + homepage: $homepage, + authors: $authors, + licenses: $licenses, + support: $support, + funding: $funding, + requires: $requires, + devRequires: $devRequires, + extras: $extras, + suggests: $suggests, + conflicts: $conflicts, + replaces: $replaces, + readme: $readme, + ); } /** * Create a new detailed versioned package instance. */ - public static function newDetailedVersionedPackage(mixed ...$arguments): DetailedVersionedPackage + public static function newDetailedVersionedPackage( + string $namespace, + string $name, + string $description = '', + string $type = 'library', + ?string $path = null, + array $keywords = [], + string $homepage = '', + array $authors = [], + array $licenses = [], + array $support = [], + array $funding = [], + array $requires = [], + array $devRequires = [], + array $extras = [], + array $suggests = [], + array $conflicts = [], + array $replaces = [], + string $readme = '', + string $version = '', + string $latestVersion = '', + VersionStatus $updateStatus = VersionStatus::UP_TO_DATE, + ): DetailedVersionedPackage { $class = static::$packageClasses['detailedVersionedPackage']; - return new $class(...$arguments); + return new $class( + namespace: $namespace, + name: $name, + description: $description, + type: $type, + path: $path, + keywords: $keywords, + homepage: $homepage, + authors: $authors, + licenses: $licenses, + support: $support, + funding: $funding, + requires: $requires, + devRequires: $devRequires, + extras: $extras, + suggests: $suggests, + conflicts: $conflicts, + replaces: $replaces, + readme: $readme, + version: $version, + latestVersion: $latestVersion, + updateStatus: $updateStatus, + ); } /** diff --git a/src/Package/VersionedPackage.php b/src/Package/VersionedPackage.php index 013d2ee..ed4b39c 100644 --- a/src/Package/VersionedPackage.php +++ b/src/Package/VersionedPackage.php @@ -20,7 +20,7 @@ public function __construct( string $name, string $description = '', string $type = '', - string $path = '', + protected ?string $path = null, protected string $version = '', protected string $latestVersion = '', protected VersionStatus $updateStatus = VersionStatus::UP_TO_DATE, diff --git a/tests/Cases/Package/PackageTest.php b/tests/Cases/Package/PackageTest.php index 0cf5ddd..0bf1d8d 100644 --- a/tests/Cases/Package/PackageTest.php +++ b/tests/Cases/Package/PackageTest.php @@ -41,7 +41,13 @@ public function itCanConvertAPackageToADetailedPackage() */ public function itCanConvertAVersionedPackageToADetailedPackage() { - $package = Composer::newVersionedPackage('winter', 'wn-pages-plugin', '', 'winter-plugin', 'v2.0.3'); + $package = Composer::newVersionedPackage( + namespace: 'winter', + name: 'wn-pages-plugin', + description: '', + type: 'winter-plugin', + version: 'v2.0.3' + ); $package = $package->toDetailed(); $this->assertInstanceOf(\Winter\Packager\Package\DetailedVersionedPackage::class, $package); @@ -74,7 +80,13 @@ public function itCanStoreAndRetrieveAPackageFromStorage() ->method('set') ->with('winter', 'wn-pages-plugin', $this->anything(), $this->anything()); - $package = Composer::newVersionedPackage('winter', 'wn-pages-plugin', '', 'winter-plugin', 'v2.0.3'); + $package = Composer::newVersionedPackage( + namespace: 'winter', + name: 'wn-pages-plugin', + description: '', + type: 'winter-plugin', + version: 'v2.0.3' + ); $package = $package->toDetailed(); $storage->expects($this->once()) @@ -85,7 +97,13 @@ public function itCanStoreAndRetrieveAPackageFromStorage() ->method('get') ->with('winter', 'wn-pages-plugin', 'v2.0.3'); - $package = Composer::newVersionedPackage('winter', 'wn-pages-plugin', '', 'winter-plugin', 'v2.0.3'); + $package = Composer::newVersionedPackage( + namespace: 'winter', + name: 'wn-pages-plugin', + description: '', + type: 'winter-plugin', + version: 'v2.0.3' + ); $package = $package->toDetailed(); $this->assertInstanceOf(\Winter\Packager\Package\DetailedVersionedPackage::class, $package); From 18048df7b3f7c8fe72759301c701fddc74b846b6 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Sun, 27 Jul 2025 23:59:08 -0600 Subject: [PATCH 6/6] Fix PHPStan errors --- composer.json | 1 + phpstan.neon | 2 ++ 2 files changed, 3 insertions(+) diff --git a/composer.json b/composer.json index cc126ed..1b6ff31 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,7 @@ "scripts": { "test": "phpunit --testdox --colors=\"auto\"", "tests": "phpunit --testdox --colors=\"auto\"", + "analyze": "./vendor/bin/phpstan analyse", "coverage": "XDEBUG_MODE=coverage phpunit --testdox --colors=\"auto\" --coverage-html=\"coverage\"" }, "require": { diff --git a/phpstan.neon b/phpstan.neon index 0ac8496..bd1fa47 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -5,3 +5,5 @@ parameters: ignoreErrors: - message: '#message has no type specified#' path: src/Exceptions/*.php + - message: '#has parameter .+ with no value type specified in iterable type array#' + path: src/Composer.php