1
0
Fork 0

Check missing-from-lock-file required packages when running install and fail when there are any (#11195)

pull/11230/head
PrinsFrank 2022-12-16 16:48:24 +01:00 committed by GitHub
parent b1f3f8b8fa
commit 6d1b36be3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 71 additions and 43 deletions

View File

@ -1020,21 +1020,11 @@ parameters:
count: 1 count: 1
path: ../src/Composer/Command/UpdateCommand.php path: ../src/Composer/Command/UpdateCommand.php
-
message: "#^Only booleans are allowed in a negated boolean, array\\<Composer\\\\Package\\\\BasePackage\\> given\\.$#"
count: 1
path: ../src/Composer/Command/ValidateCommand.php
- -
message: "#^Only booleans are allowed in an elseif condition, array\\<string\\> given\\.$#" message: "#^Only booleans are allowed in an elseif condition, array\\<string\\> given\\.$#"
count: 3 count: 3
path: ../src/Composer/Command/ValidateCommand.php path: ../src/Composer/Command/ValidateCommand.php
-
message: "#^Only booleans are allowed in an if condition, array\\<Composer\\\\Package\\\\BasePackage\\> given\\.$#"
count: 1
path: ../src/Composer/Command/ValidateCommand.php
- -
message: "#^Only booleans are allowed in an if condition, array\\<string\\> given\\.$#" message: "#^Only booleans are allowed in an if condition, array\\<string\\> given\\.$#"
count: 5 count: 5

View File

@ -100,35 +100,7 @@ EOT
} }
if ($locker->isLocked()) { if ($locker->isLocked()) {
$missingRequirements = false; $lockErrors = array_merge($lockErrors, $locker->getMissingRequirementInfo($composer->getPackage(), true));
$sets = [
['repo' => $locker->getLockedRepository(false), 'method' => 'getRequires', 'description' => 'Required'],
['repo' => $locker->getLockedRepository(true), 'method' => 'getDevRequires', 'description' => 'Required (in require-dev)'],
];
foreach ($sets as $set) {
$installedRepo = new InstalledRepository([$set['repo']]);
foreach (call_user_func([$composer->getPackage(), $set['method']]) as $link) {
if (PlatformRepository::isPlatformPackage($link->getTarget())) {
continue;
}
if (!$installedRepo->findPackagesWithReplacersAndProviders($link->getTarget(), $link->getConstraint())) {
if ($results = $installedRepo->findPackagesWithReplacersAndProviders($link->getTarget())) {
$provider = reset($results);
$lockErrors[] = '- ' . $set['description'].' package "' . $link->getTarget() . '" is in the lock file as "'.$provider->getPrettyVersion().'" but that does not satisfy your constraint "'.$link->getPrettyConstraint().'".';
} else {
$lockErrors[] = '- ' . $set['description'].' package "' . $link->getTarget() . '" is not present in the lock file.';
}
$missingRequirements = true;
}
}
}
if ($missingRequirements) {
$lockErrors[] = 'This usually happens when composer files are incorrectly merged or the composer.json file is manually edited.';
$lockErrors[] = 'Read more about correctly resolving merge conflicts https://getcomposer.org/doc/articles/resolving-merge-conflicts.md';
$lockErrors[] = 'and prefer using the "require" command over editing the composer.json file directly https://getcomposer.org/doc/03-cli.md#require';
}
} }
$this->outputResult($io, $file, $errors, $warnings, $checkPublish, $publishErrors, $checkLock, $lockErrors, true); $this->outputResult($io, $file, $errors, $warnings, $checkPublish, $publishErrors, $checkLock, $lockErrors, true);

View File

@ -711,6 +711,13 @@ class Installer
$this->io->writeError('<warning>Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. It is recommended that you run `composer update` or `composer update <package name>`.</warning>', true, IOInterface::QUIET); $this->io->writeError('<warning>Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. It is recommended that you run `composer update` or `composer update <package name>`.</warning>', true, IOInterface::QUIET);
} }
$missingRequirementInfo = $this->locker->getMissingRequirementInfo($this->package, $this->devMode);
if ($missingRequirementInfo !== []) {
$this->io->writeError($missingRequirementInfo);
return self::ERROR_LOCK_FILE_INVALID;
}
foreach ($lockedRepository->getPackages() as $package) { foreach ($lockedRepository->getPackages() as $package) {
$request->fixLockedPackage($package); $request->fixLockedPackage($package);
} }

View File

@ -15,7 +15,9 @@ namespace Composer\Package;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Installer\InstallationManager; use Composer\Installer\InstallationManager;
use Composer\Pcre\Preg; use Composer\Pcre\Preg;
use Composer\Repository\InstalledRepository;
use Composer\Repository\LockArrayRepository; use Composer\Repository\LockArrayRepository;
use Composer\Repository\PlatformRepository;
use Composer\Util\ProcessExecutor; use Composer\Util\ProcessExecutor;
use Composer\Package\Dumper\ArrayDumper; use Composer\Package\Dumper\ArrayDumper;
use Composer\Package\Loader\ArrayLoader; use Composer\Package\Loader\ArrayLoader;
@ -496,4 +498,45 @@ class Locker
return $datetime ? $datetime->format(DATE_RFC3339) : null; return $datetime ? $datetime->format(DATE_RFC3339) : null;
} }
/**
* @return array<string>
*/
public function getMissingRequirementInfo(RootPackageInterface $package, bool $includeDev): array
{
$missingRequirementInfo = [];
$missingRequirements = false;
$sets = [['repo' => $this->getLockedRepository(false), 'method' => 'getRequires', 'description' => 'Required']];
if ($includeDev === true) {
$sets[] = ['repo' => $this->getLockedRepository(true), 'method' => 'getDevRequires', 'description' => 'Required (in require-dev)'];
}
foreach ($sets as $set) {
$installedRepo = new InstalledRepository([$set['repo']]);
foreach (call_user_func([$package, $set['method']]) as $link) {
if (PlatformRepository::isPlatformPackage($link->getTarget())) {
continue;
}
if ($installedRepo->findPackagesWithReplacersAndProviders($link->getTarget(), $link->getConstraint()) === []) {
$results = $installedRepo->findPackagesWithReplacersAndProviders($link->getTarget());
if ($results !== []) {
$provider = reset($results);
$missingRequirementInfo[] = '- ' . $set['description'].' package "' . $link->getTarget() . '" is in the lock file as "'.$provider->getPrettyVersion().'" but that does not satisfy your constraint "'.$link->getPrettyConstraint().'".';
} else {
$missingRequirementInfo[] = '- ' . $set['description'].' package "' . $link->getTarget() . '" is not present in the lock file.';
}
$missingRequirements = true;
}
}
}
if ($missingRequirements) {
$missingRequirementInfo[] = 'This usually happens when composer files are incorrectly merged or the composer.json file is manually edited.';
$missingRequirementInfo[] = 'Read more about correctly resolving merge conflicts https://getcomposer.org/doc/articles/resolving-merge-conflicts.md';
$missingRequirementInfo[] = 'and prefer using the "require" command over editing the composer.json file directly https://getcomposer.org/doc/03-cli.md#require';
}
return $missingRequirementInfo;
}
} }

View File

@ -1,5 +1,5 @@
--TEST-- --TEST--
Requirements from the composer file are not installed if the lock file is present Requirements from the composer file are not installed if the lock file is present, but fails on missing requirements
--COMPOSER-- --COMPOSER--
{ {
"repositories": [ "repositories": [
@ -30,5 +30,13 @@ Requirements from the composer file are not installed if the lock file is presen
} }
--RUN-- --RUN--
install install
--EXPECT-OUTPUT--
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
- Required package "newly-required/pkg" is not present in the lock file.
This usually happens when composer files are incorrectly merged or the composer.json file is manually edited.
Read more about correctly resolving merge conflicts https://getcomposer.org/doc/articles/resolving-merge-conflicts.md
and prefer using the "require" command over editing the composer.json file directly https://getcomposer.org/doc/03-cli.md#require
--EXPECT-EXIT-CODE--
4
--EXPECT-- --EXPECT--
Installing required/pkg (1.0.0)

View File

@ -1,5 +1,5 @@
--TEST-- --TEST--
The locked version will not get overwritten by an install The locked version will not get overwritten by an install but fails on invalid packages
--COMPOSER-- --COMPOSER--
{ {
"repositories": [ "repositories": [
@ -37,5 +37,13 @@ The locked version will not get overwritten by an install
] ]
--RUN-- --RUN--
install install
--EXPECT-OUTPUT--
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
- Required package "foo/bar" is in the lock file as "1.0.0" but that does not satisfy your constraint "2.0.0".
This usually happens when composer files are incorrectly merged or the composer.json file is manually edited.
Read more about correctly resolving merge conflicts https://getcomposer.org/doc/articles/resolving-merge-conflicts.md
and prefer using the "require" command over editing the composer.json file directly https://getcomposer.org/doc/03-cli.md#require
--EXPECT-EXIT-CODE--
4
--EXPECT-- --EXPECT--
Upgrading foo/baz (1.0.0 => 2.0.0)