diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 430ba14..6582e98 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -11,6 +11,9 @@
displayDetailsOnTestsThatTriggerWarnings="true"
failOnRisky="true"
failOnWarning="true">
+
+
+
test/unit
diff --git a/src/Command/CommandHelper.php b/src/Command/CommandHelper.php
index 9af22ad..e1c91d6 100644
--- a/src/Command/CommandHelper.php
+++ b/src/Command/CommandHelper.php
@@ -51,15 +51,15 @@ use const PHP_VERSION;
/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */
final class CommandHelper
{
- public const ARG_REQUESTED_PACKAGE_AND_VERSION = 'requested-package-and-version';
- public const OPTION_WITH_PHP_CONFIG = 'with-php-config';
- public const OPTION_WITH_PHP_PATH = 'with-php-path';
- public const OPTION_WITH_PHPIZE_PATH = 'with-phpize-path';
- public const OPTION_WORKING_DIRECTORY = 'working-dir';
+ public const ARG_REQUESTED_PACKAGE_AND_VERSION = 'requested-package-and-version';
+ public const OPTION_WITH_PHP_CONFIG = 'with-php-config';
+ public const OPTION_WITH_PHP_PATH = 'with-php-path';
+ public const OPTION_WITH_PHPIZE_PATH = 'with-phpize-path';
+ public const OPTION_WORKING_DIRECTORY = 'working-dir';
public const OPTION_ALLOW_NON_INTERACTIVE_PROJECT_INSTALL = 'allow-non-interactive-project-install';
- private const OPTION_MAKE_PARALLEL_JOBS = 'make-parallel-jobs';
- private const OPTION_SKIP_ENABLE_EXTENSION = 'skip-enable-extension';
- private const OPTION_FORCE = 'force';
+ private const OPTION_MAKE_PARALLEL_JOBS = 'make-parallel-jobs';
+ private const OPTION_SKIP_ENABLE_EXTENSION = 'skip-enable-extension';
+ private const OPTION_FORCE = 'force';
/** @psalm-suppress UnusedConstructor */
private function __construct()
diff --git a/src/Command/InstallExtensionsForProjectCommand.php b/src/Command/InstallExtensionsForProjectCommand.php
index 391063b..c84f258 100644
--- a/src/Command/InstallExtensionsForProjectCommand.php
+++ b/src/Command/InstallExtensionsForProjectCommand.php
@@ -25,20 +25,22 @@ use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Throwable;
+use function array_column;
use function array_keys;
use function array_map;
use function array_merge;
use function array_walk;
use function assert;
use function chdir;
+use function count;
use function getcwd;
+use function implode;
use function in_array;
use function is_dir;
use function is_string;
@@ -131,7 +133,6 @@ final class InstallExtensionsForProjectCommand extends Command
'Aborting! You are not running in interactive mode, and --%s was not specified.',
CommandHelper::OPTION_ALLOW_NON_INTERACTIVE_PROJECT_INSTALL,
));
- // @todo more details
return Command::FAILURE;
}
@@ -270,6 +271,7 @@ final class InstallExtensionsForProjectCommand extends Command
return;
}
+
$selectedPackageName = substr($selectedPackageAnswer, 0, (int) strpos($selectedPackageAnswer, ':'));
} else {
$selectedPackageName = $matches[0]['name'];
diff --git a/test/integration/Command/InstallExtensionsForProjectCommandTest.php b/test/integration/Command/InstallExtensionsForProjectCommandTest.php
index f4d6c7b..e05f594 100644
--- a/test/integration/Command/InstallExtensionsForProjectCommandTest.php
+++ b/test/integration/Command/InstallExtensionsForProjectCommandTest.php
@@ -101,10 +101,6 @@ final class InstallExtensionsForProjectCommandTest extends TestCase
new Constraint('>=', '1.2.0.0-dev'),
new Constraint('<', '2.0.0.0-dev'),
]), Link::TYPE_REQUIRE, '^1.2'),
-// 'ext-mismatching' => new Link('my/project', 'ext-mismatching', new MultiConstraint([
-// new Constraint('>=', '2.0.0.0-dev'),
-// new Constraint('<', '3.0.0.0-dev'),
-// ]), Link::TYPE_REQUIRE, '^2.0'),
]);
$this->composerFactoryForProject->method('rootPackage')->willReturn($rootPackage);
@@ -119,20 +115,8 @@ final class InstallExtensionsForProjectCommandTest extends TestCase
$this->composerFactoryForProject->method('composer')->willReturn($composer);
-// $this->installedPiePackages->method('allPiePackages')->willReturn([
-// 'mismatching' => new Package(
-// $this->createMock(CompletePackageInterface::class),
-// ExtensionType::PhpModule,
-// ExtensionName::normaliseFromString('mismatching'),
-// 'vendor/mismatching',
-// '1.9.3',
-// null,
-// ),
-// ]);
-
$this->findMatchingPackages->method('for')->willReturn([
['name' => 'vendor1/foobar', 'description' => 'The official foobar implementation'],
- ['name' => 'vendor2/afoobar', 'description' => 'An improved async foobar extension'],
]);
$this->questionHelper->method('ask')->willReturn('vendor1/foobar: The official foobar implementation');
@@ -142,18 +126,65 @@ final class InstallExtensionsForProjectCommandTest extends TestCase
->with('vendor1/foobar:^1.2');
$this->commandTester->execute(
- [],
+ ['--allow-non-interactive-project-install' => true],
['verbosity' => BufferedOutput::VERBOSITY_VERY_VERBOSE],
);
$outputString = $this->commandTester->getDisplay();
- $this->commandTester->assertCommandIsSuccessful();
+ $this->commandTester->assertCommandIsSuccessful($outputString);
self::assertStringContainsString('Checking extensions for your project my/project', $outputString);
self::assertStringContainsString('requires: ext-standard:* ✅ Already installed', $outputString);
self::assertStringContainsString('requires: ext-foobar:^1.2 🚫 Missing', $outputString);
}
+ public function testInstallingExtensionsForPhpProjectWithMultipleMatches(): void
+ {
+ $rootPackage = new RootPackage('my/project', '1.2.3.0', '1.2.3');
+ $rootPackage->setRequires([
+ 'ext-standard' => new Link('my/project', 'ext-standard', new Constraint('=', '*'), Link::TYPE_REQUIRE, '*'),
+ 'ext-foobar' => new Link('my/project', 'ext-foobar', new MultiConstraint([
+ new Constraint('>=', '1.2.0.0-dev'),
+ new Constraint('<', '2.0.0.0-dev'),
+ ]), Link::TYPE_REQUIRE, '^1.2'),
+ ]);
+ $this->composerFactoryForProject->method('rootPackage')->willReturn($rootPackage);
+
+ $installedRepository = new InstalledArrayRepository([$rootPackage]);
+
+ $repositoryManager = $this->createMock(RepositoryManager::class);
+ $repositoryManager->method('getLocalRepository')->willReturn($installedRepository);
+
+ $composer = $this->createMock(Composer::class);
+ $composer->method('getPackage')->willReturn($rootPackage);
+ $composer->method('getRepositoryManager')->willReturn($repositoryManager);
+
+ $this->composerFactoryForProject->method('composer')->willReturn($composer);
+
+ $this->findMatchingPackages->method('for')->willReturn([
+ ['name' => 'vendor1/foobar', 'description' => 'The official foobar implementation'],
+ ['name' => 'vendor2/afoobar', 'description' => 'An improved async foobar extension'],
+ ]);
+
+ $this->questionHelper->method('ask')->willReturn('vendor1/foobar: The official foobar implementation');
+
+ $this->installSelectedPackage->expects(self::never())
+ ->method('withPieCli');
+
+ $this->commandTester->execute(
+ ['--allow-non-interactive-project-install' => true],
+ ['verbosity' => BufferedOutput::VERBOSITY_VERY_VERBOSE],
+ );
+
+ $outputString = $this->commandTester->getDisplay();
+
+ self::assertSame(Command::FAILURE, $this->commandTester->getStatusCode());
+ self::assertStringContainsString('Checking extensions for your project my/project', $outputString);
+ self::assertStringContainsString('requires: ext-standard:* ✅ Already installed', $outputString);
+ self::assertStringContainsString('requires: ext-foobar:^1.2 🚫 Missing', $outputString);
+ self::assertStringContainsString('Multiple packages were found for ext-foobar', $outputString);
+ }
+
public function testInstallingExtensionsForPieProject(): void
{
$rootPackage = new RootPackage('my/project', '1.2.3.0', '1.2.3');