From c005bcb75e82b9b3f363dfe38440c78caf0bcfe9 Mon Sep 17 00:00:00 2001 From: webimpress Date: Wed, 11 Oct 2017 22:56:44 +0100 Subject: [PATCH 1/2] Update composer.json with currently installed version if there is one Do not prompt user if there is installed version of required dependency, just add it to composer and display message how to update the dependency. --- src/Plugin.php | 38 +++++++++++---- test/PluginTest.php | 113 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 133 insertions(+), 18 deletions(-) diff --git a/src/Plugin.php b/src/Plugin.php index 1872a7b..f2f3d21 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -4,7 +4,6 @@ use Composer\Composer; use Composer\DependencyResolver\Operation\InstallOperation; -use Composer\DependencyResolver\Operation\UpdateOperation; use Composer\DependencyResolver\Pool; use Composer\EventDispatcher\EventDispatcher; use Composer\EventDispatcher\EventSubscriberInterface; @@ -37,6 +36,9 @@ class Plugin implements PluginInterface, EventSubscriberInterface /** @var Composer */ private $composer; + /** @var string[] */ + private $installedPackages; + /** @var IOInterface */ private $io; @@ -58,6 +60,11 @@ public function activate(Composer $composer, IOInterface $io) { $this->composer = $composer; $this->io = $io; + + $installedPackages = $this->composer->getRepositoryManager()->getLocalRepository()->getPackages(); + foreach ($installedPackages as $package) { + $this->installedPackages[$package->getName()] = $package->getPrettyVersion(); + } } public function onPostPackage(PackageEvent $event) @@ -145,14 +152,25 @@ private function runInstaller(RootPackageInterface $rootPackage, array $packages private function promptForPackageVersion($name) { - $validator = function ($input) { - $input = trim($input); - return $input ?: false; - }; + // Package is currently installed. Add it to root composer.json + if (isset($this->installedPackages[$name])) { + $this->io->write(sprintf( + 'Added package %s to composer.json with constraint %s;' + . ' to upgrade, run composer require %s:VERSION', + $name, + '^' . $this->installedPackages[$name], + $name + )); + + return '^' . $this->installedPackages[$name]; + } $constraint = $this->io->askAndValidate( - sprintf('Enter the version of %s to require (or leave blank to use the latest version): ', $name), - $validator + sprintf('Enter the version of %s to require (or leave blank to use the latest version): ', $name), + function ($input) { + $input = trim($input); + return $input ?: false; + } ); if ($constraint === false) { @@ -184,11 +202,11 @@ private function createInstaller(Composer $composer, IOInterface $io, RootPackag ); } - private function hasPackage($name) + private function hasPackage($package) { $requires = $this->composer->getPackage()->getRequires(); - foreach ($requires as $link) { - if (strtolower($link->getTarget()) === strtolower($name)) { + foreach ($requires as $name => $link) { + if (strtolower($name) === strtolower($package)) { return true; } } diff --git a/test/PluginTest.php b/test/PluginTest.php index ba3a38e..288a8d3 100644 --- a/test/PluginTest.php +++ b/test/PluginTest.php @@ -18,6 +18,7 @@ use Composer\Package\RootPackageInterface; use Composer\Package\Version\VersionSelector; use Composer\Repository\RepositoryManager; +use Composer\Repository\WritableRepositoryInterface; use org\bovigo\vfs\vfsStream; use PHPUnit\Framework\TestCase; use Prophecy\Argument; @@ -37,11 +38,24 @@ class PluginTest extends TestCase /** @var IOInterface|ObjectProphecy */ private $io; + /** @var WritableRepositoryInterface */ + private $localRepository; + protected function setUp() { parent::setUp(); + $this->localRepository = $this->prophesize(WritableRepositoryInterface::class); + $this->localRepository->getPackages()->willReturn([]); + + $repositoryManager = $this->prophesize(RepositoryManager::class); + $repositoryManager->getLocalRepository()->willReturn($this->localRepository->reveal()); + $this->composer = $this->prophesize(Composer::class); + $this->composer->getRepositoryManager() + ->willReturn($repositoryManager->reveal()) + ->shouldBeCalled(); + $this->io = $this->prophesize(IOInterface::class); $this->plugin = new Plugin(); @@ -244,7 +258,8 @@ public function testInstallSingleDependencyOnPackageUpdate() $this->composer->getConfig()->willReturn($config->reveal()); $this->io->askAndValidate( - 'Enter the version of extra-dependency-foo to require (or leave blank to use the latest version): ', + 'Enter the version of extra-dependency-foo to require' + . ' (or leave blank to use the latest version): ', Argument::type('callable') )->willReturn('17.0.1-dev'); @@ -316,7 +331,8 @@ public function testInstallSingleDependencyOnPackageInstall() $this->composer->getConfig()->willReturn($config->reveal()); $this->io->askAndValidate( - 'Enter the version of extra-dependency-foo to require (or leave blank to use the latest version): ', + 'Enter the version of extra-dependency-foo to require' + . ' (or leave blank to use the latest version): ', Argument::type('callable') )->willReturn('17.0.1-dev'); @@ -396,7 +412,8 @@ public function testInstallOneDependenciesWhenOneIsAlreadyInstalled() $this->composer->getConfig()->willReturn($config->reveal()); $this->io->askAndValidate( - 'Enter the version of extra-dependency-foo to require (or leave blank to use the latest version): ', + 'Enter the version of extra-dependency-foo to require' + . ' (or leave blank to use the latest version): ', Argument::type('callable') )->willReturn('17.0.1-dev'); @@ -474,7 +491,8 @@ public function testInstallSingleDependencyAndAutomaticallyChooseLatestVersion() $this->composer->getConfig()->willReturn($config->reveal()); $this->io->askAndValidate( - 'Enter the version of extra-dependency-foo to require (or leave blank to use the latest version): ', + 'Enter the version of extra-dependency-foo to require' + . ' (or leave blank to use the latest version): ', Argument::type('callable') )->willReturn(false); @@ -500,6 +518,11 @@ public function testInstallSingleDependencyAndAutomaticallyChooseLatestVersion() $this->setUpPool(); $this->assertNull($this->plugin->onPostPackage($event->reveal())); + + $json = file_get_contents(vfsStream::url('project/composer.json')); + $composer = json_decode($json, true); + $this->assertTrue(isset($composer['require']['extra-dependency-foo'])); + $this->assertSame('13.4.2', $composer['require']['extra-dependency-foo']); } public function testInstallSingleDependencyAndAutomaticallyChooseLatestVersionNotFoundMatchingPackage() @@ -532,7 +555,8 @@ public function testInstallSingleDependencyAndAutomaticallyChooseLatestVersionNo $this->composer->getConfig()->willReturn($config->reveal()); $this->io->askAndValidate( - 'Enter the version of extra-dependency-foo to require (or leave blank to use the latest version): ', + 'Enter the version of extra-dependency-foo to require' + . ' (or leave blank to use the latest version): ', Argument::type('callable') )->willReturn(false); @@ -551,6 +575,82 @@ public function testInstallSingleDependencyAndAutomaticallyChooseLatestVersionNo $this->plugin->onPostPackage($event->reveal()); } + public function testUpdateComposerWithCurrentlyInstalledVersion() + { + $installedPackage = $this->prophesize(PackageInterface::class); + $installedPackage->getName()->willReturn('extra-dependency-foo'); + $installedPackage->getPrettyVersion()->willReturn('0.5.1'); + + $this->localRepository->getPackages()->willReturn([$installedPackage->reveal()]); + $this->plugin->activate($this->composer->reveal(), $this->io->reveal()); + + /** @var PackageInterface|ObjectProphecy $package */ + $package = $this->prophesize(PackageInterface::class); + $package->getName()->willReturn('some/component'); + $package->getExtra()->willReturn([ + 'dependency' => [ + 'extra-dependency-foo', + ], + ]); + + $operation = $this->prophesize(InstallOperation::class); + $operation->getPackage()->willReturn($package->reveal()); + + $event = $this->prophesize(PackageEvent::class); + $event->isDevMode()->willReturn(true); + $event->getOperation()->willReturn($operation->reveal()); + + $config = $this->prophesize(Config::class); + $config->get('sort-packages')->willReturn(true); + $config->get(Argument::any())->willReturn(null); + + $rootPackage = $this->prophesize(RootPackageInterface::class); + $rootPackage->getRequires()->willReturn([]); + $rootPackage->setRequires(Argument::that(function ($arguments) { + if (! is_array($arguments)) { + return false; + } + + if (! isset($arguments['extra-dependency-foo'])) { + return false; + } + + $argument = $arguments['extra-dependency-foo']; + + if (! $argument instanceof Link) { + return false; + } + + if ($argument->getTarget() !== 'extra-dependency-foo') { + return false; + } + + if ($argument->getConstraint()->getPrettyString() !== '^0.5.1') { + return false; + } + + if ($argument->getDescription() !== 'requires') { + return false; + } + + return true; + }))->shouldBeCalled(); + $rootPackage->getMinimumStability()->willReturn('stable'); + + $this->composer->getPackage()->willReturn($rootPackage); + $this->composer->getConfig()->willReturn($config->reveal()); + + $this->setUpComposerInstaller(['extra-dependency-foo']); + $this->setUpComposerJson(); + + $this->assertNull($this->plugin->onPostPackage($event->reveal())); + + $json = file_get_contents(vfsStream::url('project/composer.json')); + $composer = json_decode($json, true); + $this->assertTrue(isset($composer['require']['extra-dependency-foo'])); + $this->assertSame('^0.5.1', $composer['require']['extra-dependency-foo']); + } + public function testComposerInstallerFactory() { $r = new ReflectionProperty($this->plugin, 'installerFactory'); @@ -563,9 +663,6 @@ public function testComposerInstallerFactory() $this->composer->getDownloadManager() ->willReturn($this->prophesize(DownloadManager::class)) ->shouldBeCalled(); - $this->composer->getRepositoryManager() - ->willReturn($this->prophesize(RepositoryManager::class)) - ->shouldBeCalled(); $this->composer->getLocker() ->willReturn($this->prophesize(Locker::class)) ->shouldBeCalled(); From 8ffb0f0ad12d8cc3c9f85cd130d0bc8dd1dfd047 Mon Sep 17 00:00:00 2001 From: webimpress Date: Wed, 11 Oct 2017 23:01:01 +0100 Subject: [PATCH 2/2] CS fix - too long line --- src/Plugin.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Plugin.php b/src/Plugin.php index f2f3d21..4439d40 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -166,7 +166,10 @@ private function promptForPackageVersion($name) } $constraint = $this->io->askAndValidate( - sprintf('Enter the version of %s to require (or leave blank to use the latest version): ', $name), + sprintf( + 'Enter the version of %s to require (or leave blank to use the latest version): ', + $name + ), function ($input) { $input = trim($input); return $input ?: false;