Fix UX when a non-required plugin is still present in vendor dir (#12000)
Composer now skips it and does not prompt if it is not allowed to run, fixes #11944pull/12003/head
parent
37d722e73c
commit
c1be804a0c
|
@ -20,11 +20,13 @@ use Composer\Package\BasePackage;
|
|||
use Composer\Package\CompletePackage;
|
||||
use Composer\Package\Locker;
|
||||
use Composer\Package\Package;
|
||||
use Composer\Package\RootPackageInterface;
|
||||
use Composer\Package\Version\VersionParser;
|
||||
use Composer\PartialComposer;
|
||||
use Composer\Pcre\Preg;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Repository\InstalledRepository;
|
||||
use Composer\Repository\RepositoryUtils;
|
||||
use Composer\Repository\RootPackageRepository;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Package\Link;
|
||||
|
@ -98,7 +100,7 @@ class PluginManager
|
|||
{
|
||||
if (!$this->arePluginsDisabled('local')) {
|
||||
$repo = $this->composer->getRepositoryManager()->getLocalRepository();
|
||||
$this->loadRepository($repo, false);
|
||||
$this->loadRepository($repo, false, $this->composer->getPackage());
|
||||
}
|
||||
|
||||
if ($this->globalComposer !== null && !$this->arePluginsDisabled('global')) {
|
||||
|
@ -445,9 +447,11 @@ class PluginManager
|
|||
*
|
||||
* @param RepositoryInterface $repo Repository to scan for plugins to install
|
||||
*
|
||||
* @phpstan-param ($isGlobalRepo is true ? null : RootPackageInterface) $rootPackage
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function loadRepository(RepositoryInterface $repo, bool $isGlobalRepo): void
|
||||
private function loadRepository(RepositoryInterface $repo, bool $isGlobalRepo, ?RootPackageInterface $rootPackage = null): void
|
||||
{
|
||||
$packages = $repo->getPackages();
|
||||
|
||||
|
@ -462,10 +466,28 @@ class PluginManager
|
|||
}
|
||||
|
||||
$sortedPackages = PackageSorter::sortPackages($packages, $weights);
|
||||
if (!$isGlobalRepo) {
|
||||
$requiredPackages = RepositoryUtils::filterRequiredPackages($packages, $rootPackage, true);
|
||||
}
|
||||
|
||||
foreach ($sortedPackages as $package) {
|
||||
if (!($package instanceof CompletePackage)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_array($package->getType(), ['composer-plugin', 'composer-installer'], true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
!$isGlobalRepo
|
||||
&& !in_array($package, $requiredPackages, true)
|
||||
&& !$this->isPluginAllowed($package->getName(), false, true, false)
|
||||
) {
|
||||
$this->io->writeError('<warning>The "'.$package->getName().'" plugin was not loaded as it is not listed in allow-plugins and is not required by the root package anymore.</warning>');
|
||||
continue;
|
||||
}
|
||||
|
||||
if ('composer-plugin' === $package->getType()) {
|
||||
$this->registerPackage($package, false, $isGlobalRepo);
|
||||
// Backward compatibility
|
||||
|
@ -668,7 +690,7 @@ class PluginManager
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function isPluginAllowed(string $package, bool $isGlobalPlugin, bool $optional = false): bool
|
||||
public function isPluginAllowed(string $package, bool $isGlobalPlugin, bool $optional = false, bool $prompt = true): bool
|
||||
{
|
||||
if ($isGlobalPlugin) {
|
||||
$rules = &$this->allowGlobalPluginRules;
|
||||
|
@ -703,7 +725,7 @@ class PluginManager
|
|||
return false;
|
||||
}
|
||||
|
||||
if ($this->io->isInteractive()) {
|
||||
if ($this->io->isInteractive() && $prompt) {
|
||||
$composer = $isGlobalPlugin && $this->globalComposer !== null ? $this->globalComposer : $this->composer;
|
||||
|
||||
$this->io->writeError('<warning>'.$package.($isGlobalPlugin || $this->runningInGlobalDir ? ' (installed globally)' : '').' contains a Composer plugin which is currently not in your allow-plugins config. See https://getcomposer.org/allow-plugins</warning>');
|
||||
|
|
|
@ -24,23 +24,28 @@ class RepositoryUtils
|
|||
/**
|
||||
* Find all of $packages which are required by $requirer, either directly or transitively
|
||||
*
|
||||
* Require-dev is ignored
|
||||
* Require-dev is ignored by default, you can enable the require-dev of the initial $requirer
|
||||
* packages by passing $includeRequireDev=true, but require-dev of transitive dependencies
|
||||
* are always ignored.
|
||||
*
|
||||
* @template T of PackageInterface
|
||||
* @param array<T> $packages
|
||||
* @param list<T> $bucket Do not pass this in, only used to avoid recursion with circular deps
|
||||
* @return list<T>
|
||||
*/
|
||||
public static function filterRequiredPackages(array $packages, PackageInterface $requirer, array $bucket = []): array
|
||||
public static function filterRequiredPackages(array $packages, PackageInterface $requirer, bool $includeRequireDev = false, array $bucket = []): array
|
||||
{
|
||||
$requires = $requirer->getRequires();
|
||||
if ($includeRequireDev) {
|
||||
$requires = array_merge($requires, $requirer->getDevRequires());
|
||||
}
|
||||
|
||||
foreach ($packages as $candidate) {
|
||||
foreach ($candidate->getNames() as $name) {
|
||||
if (isset($requires[$name])) {
|
||||
if (!in_array($candidate, $bucket, true)) {
|
||||
$bucket[] = $candidate;
|
||||
$bucket = self::filterRequiredPackages($packages, $candidate, $bucket);
|
||||
$bucket = self::filterRequiredPackages($packages, $candidate, false, $bucket);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -24,13 +24,13 @@ class RepositoryUtilsTest extends TestCase
|
|||
* @param PackageInterface[] $pkgs
|
||||
* @param string[] $expected
|
||||
*/
|
||||
public function testFilterRequiredPackages(array $pkgs, PackageInterface $requirer, array $expected): void
|
||||
public function testFilterRequiredPackages(array $pkgs, PackageInterface $requirer, array $expected, bool $includeRequireDev = false): void
|
||||
{
|
||||
$expected = array_map(static function (string $name) use ($pkgs): PackageInterface {
|
||||
return $pkgs[$name];
|
||||
}, $expected);
|
||||
|
||||
self::assertSame($expected, RepositoryUtils::filterRequiredPackages($pkgs, $requirer));
|
||||
self::assertSame($expected, RepositoryUtils::filterRequiredPackages($pkgs, $requirer, $includeRequireDev));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,6 +72,10 @@ class RepositoryUtilsTest extends TestCase
|
|||
self::configureLinks($requirer, ['require-dev' => ['required/a' => '*']]);
|
||||
yield 'require-dev has no effect' => [$pkgs, $requirer, []];
|
||||
|
||||
$requirer = self::getPackage('requirer/pkg');
|
||||
self::configureLinks($requirer, ['require-dev' => ['required/a' => '*']]);
|
||||
yield 'require-dev works if called with it enabled' => [$pkgs, $requirer, ['a'], true];
|
||||
|
||||
$requirer = self::getPackage('requirer/pkg');
|
||||
self::configureLinks($requirer, ['require' => ['required/a' => '*']]);
|
||||
yield 'simple require' => [$pkgs, $requirer, ['a']];
|
||||
|
|
Loading…
Reference in New Issue