Merge branch 'master' into 2.0

main
Jordi Boggiano 5 years ago
commit b89720b52a

@ -22,6 +22,8 @@ The following options are available with every command:
* **--quiet (-q):** Do not output any message.
* **--no-interaction (-n):** Do not ask any interactive question.
* **--no-plugins:** Disables plugins.
* **--no-cache:** Disables the use of the cache directory. Same as setting the COMPOSER_CACHE_DIR
env var to /dev/null (or NUL on Windows).
* **--working-dir (-d):** If specified, use the given directory as working directory.
* **--profile:** Display timing and memory usage information
* **--ansi:** Force ANSI output.
@ -491,7 +493,7 @@ php composer.phar validate
### Options
* **--no-check-all:** Do not emit a warning if requirements in `composer.json` use unbound version constraints.
* **--no-check-all:** Do not emit a warning if requirements in `composer.json` use unbound or overly strict version constraints.
* **--no-check-lock:** Do not emit an error if `composer.lock` exists and is not up to date.
* **--no-check-publish:** Do not emit an error if `composer.json` is unsuitable for publishing as a package on Packagist but is otherwise valid.
* **--with-dependencies:** Also validate the composer.json of all installed dependencies.

@ -940,9 +940,13 @@ INITIALIZER;
$packageMap,
function ($item) use ($include) {
$package = $item[0];
$name = $package->getName();
foreach ($package->getNames() as $name) {
if (isset($include[$name])) {
return true;
}
}
return isset($include[$name]);
return false;
}
);
}

@ -44,7 +44,7 @@ class Cache
$this->whitelist = $whitelist;
$this->filesystem = $filesystem ?: new Filesystem();
if (preg_match('{(^|[\\\\/])(\$null|NUL|/dev/null)([\\\\/]|$)}', $cacheDir)) {
if (!self::isUsable($cacheDir)) {
$this->enabled = false;
return;
@ -59,6 +59,11 @@ class Cache
}
}
public static function isUsable($path)
{
return !preg_match('{(^|[\\\\/])(\$null|nul|NUL|/dev/null)([\\\\/]|$)}', $path);
}
public function isEnabled()
{
return $this->enabled;

@ -557,7 +557,12 @@ EOT
$finder = new ExecutableFinder();
$gitBin = $finder->find('git');
$cmd = new Process(sprintf('%s config -l', ProcessExecutor::escape($gitBin)));
// TODO in v3 always call with an array
if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
$cmd = new Process(array($gitBin, 'config', '-l'));
} else {
$cmd = new Process(sprintf('%s config -l', ProcessExecutor::escape($gitBin)));
}
$cmd->run();
if ($cmd->isSuccessful()) {

@ -39,7 +39,7 @@ class ValidateCommand extends BaseCommand
->setName('validate')
->setDescription('Validates a composer.json and composer.lock.')
->setDefinition(array(
new InputOption('no-check-all', null, InputOption::VALUE_NONE, 'Do not make a complete validation'),
new InputOption('no-check-all', null, InputOption::VALUE_NONE, 'Do not validate requires for overly strict/loose constraints'),
new InputOption('no-check-lock', null, InputOption::VALUE_NONE, 'Do not check if lock file is up to date'),
new InputOption('no-check-publish', null, InputOption::VALUE_NONE, 'Do not check for publish errors'),
new InputOption('with-dependencies', 'A', InputOption::VALUE_NONE, 'Also validate the composer.json of all installed dependencies'),

@ -193,6 +193,10 @@ class JsonConfigSource implements ConfigSourceInterface
{
$this->manipulateJson('removeSubNode', $type, $name, function (&$config, $type, $name) {
unset($config[$type][$name]);
if (0 === count($config[$type])) {
unset($config[$type]);
}
});
}

@ -118,6 +118,11 @@ class Application extends BaseApplication
)));
ErrorHandler::register($io);
if ($input->hasParameterOption('--no-cache')) {
$io->writeError('Disabling cache usage', true, IOInterface::DEBUG);
putenv('COMPOSER_CACHE_DIR='.(Platform::isWindows() ? 'nul' : '/dev/null'));
}
// switch working dir
if ($newWorkDir = $this->getNewWorkingDir($input)) {
$oldWorkingDir = getcwd();
@ -272,7 +277,7 @@ class Application extends BaseApplication
}
if (isset($startTime)) {
$io->writeError('<info>Memory usage: '.round(memory_get_usage() / 1024 / 1024, 2).'MB (peak: '.round(memory_get_peak_usage() / 1024 / 1024, 2).'MB), time: '.round(microtime(true) - $startTime, 2).'s');
$io->writeError('<info>Memory usage: '.round(memory_get_usage() / 1024 / 1024, 2).'MiB (peak: '.round(memory_get_peak_usage() / 1024 / 1024, 2).'MiB), time: '.round(microtime(true) - $startTime, 2).'s');
}
restore_error_handler();
@ -457,6 +462,7 @@ class Application extends BaseApplication
$definition->addOption(new InputOption('--profile', null, InputOption::VALUE_NONE, 'Display timing and memory usage information'));
$definition->addOption(new InputOption('--no-plugins', null, InputOption::VALUE_NONE, 'Whether to disable plugins.'));
$definition->addOption(new InputOption('--working-dir', '-d', InputOption::VALUE_REQUIRED, 'If specified, use the given directory as working directory.'));
$definition->addOption(new InputOption('--no-cache', null, InputOption::VALUE_NONE, 'Prevent use of the cache'));
return $definition;
}

@ -19,6 +19,7 @@ use Composer\Util\Filesystem;
use Composer\Util\Git as GitUtil;
use Composer\Util\Platform;
use Composer\Util\ProcessExecutor;
use Composer\Cache;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
@ -51,7 +52,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface
$msg = "Cloning ".$this->getShortHash($ref);
$command = 'git clone --no-checkout %url% %path% && cd '.$flag.'%path% && git remote add composer %url% && git fetch composer';
if ($gitVersion && version_compare($gitVersion, '2.3.0-rc0', '>=')) {
if ($gitVersion && version_compare($gitVersion, '2.3.0-rc0', '>=') && Cache::isUsable($cachePath)) {
$this->io->writeError('', true, IOInterface::DEBUG);
$this->io->writeError(sprintf(' Cloning to cache at %s', ProcessExecutor::escape($cachePath)), true, IOInterface::DEBUG);
try {

@ -153,7 +153,7 @@ class ConsoleIO extends BaseIO
$memoryUsage = memory_get_usage() / 1024 / 1024;
$timeSpent = microtime(true) - $this->startTime;
$messages = array_map(function ($message) use ($memoryUsage, $timeSpent) {
return sprintf('[%.1fMB/%.2fs] %s', $memoryUsage, $timeSpent, $message);
return sprintf('[%.1fMiB/%.2fs] %s', $memoryUsage, $timeSpent, $message);
}, (array) $messages);
}

@ -1294,11 +1294,6 @@ class Installer
$rootRequires = array_merge($rootRequires, $rootDevRequires);
$requiredPackageNames = array();
foreach ($rootRequires as $require) {
$requiredPackageNames[] = $require->getTarget();
}
$skipPackages = array();
if (!$this->whitelistAllDependencies) {
foreach ($rootRequires as $require) {
@ -1317,11 +1312,17 @@ class Installer
$packageQueue = new \SplQueue;
$depPackages = $repositorySet->findPackages($packageName, null, false);
$nameMatchesRequiredPackage = in_array($packageName, $requiredPackageNames, true);
$matchesByPattern = array();
// check if the name is a glob pattern that did not match directly
if (!$nameMatchesRequiredPackage) {
if (empty($depPackages)) {
// add any installed package matching the whitelisted name/pattern
$whitelistPatternSearchRegexp = BasePackage::packageNameToRegexp($packageName, '^%s$');
foreach ($localOrLockRepo->search($whitelistPatternSearchRegexp) as $installedPackage) {
$matchesByPattern[] = $repositorySet->findPackages($installedPackage['name'], null, false);
}
// add root requirements which match the whitelisted name/pattern
$whitelistPatternRegexp = BasePackage::packageNameToRegexp($packageName);
foreach ($rootRequiredPackageNames as $rootRequiredPackageName) {
if (preg_match($whitelistPatternRegexp, $rootRequiredPackageName)) {
@ -1331,6 +1332,10 @@ class Installer
}
}
if (!empty($matchesByPattern)) {
$depPackages = array_merge($depPackages, call_user_func_array('array_merge', $matchesByPattern));
}
if (count($depPackages) == 0 && !$nameMatchesRequiredPackage && !in_array($packageName, array('nothing', 'lock', 'mirrors'))) {
$this->io->writeError('<warning>Package "' . $packageName . '" listed for update is not installed. Ignoring.</warning>');
}
@ -1362,7 +1367,7 @@ class Installer
continue;
}
if (isset($skipPackages[$requirePackage->getName()])) {
if (isset($skipPackages[$requirePackage->getName()]) && !preg_match(BasePackage::packageNameToRegexp($packageName), $requirePackage->getName())) {
$this->io->writeError('<warning>Dependency "' . $requirePackage->getName() . '" is also a root requirement, but is not explicitly whitelisted. Ignoring.</warning>');
continue;
}

@ -239,12 +239,13 @@ abstract class BasePackage implements PackageInterface
* Build a regexp from a package name, expanding * globs as required
*
* @param string $whiteListedPattern
* @param bool $wrap Wrap the cleaned string by the given string
* @return string
*/
public static function packageNameToRegexp($whiteListedPattern)
public static function packageNameToRegexp($whiteListedPattern, $wrap = '{^%s$}i')
{
$cleanedWhiteListedPattern = str_replace('\\*', '.*', preg_quote($whiteListedPattern));
return "{^" . $cleanedWhiteListedPattern . "$}i";
return sprintf($wrap, $cleanedWhiteListedPattern);
}
}

@ -12,6 +12,7 @@
namespace Composer\Repository\Vcs;
use Composer\Cache;
use Composer\Config;
use Composer\Util\ProcessExecutor;
use Composer\Util\Filesystem;
@ -45,6 +46,10 @@ class FossilDriver extends VcsDriver
if (Filesystem::isLocalPath($this->url) && is_dir($this->url)) {
$this->checkoutDir = $this->url;
} else {
if (!Cache::isUsable($this->config->get('cache-repo-dir')) || !Cache::isUsable($this->config->get('cache-vcs-dir'))) {
throw new \RuntimeException('FossilDriver requires a usable cache directory, and it looks like you set it to be disabled');
}
$localName = preg_replace('{[^a-z0-9]}i', '-', $this->url);
$this->repoFile = $this->config->get('cache-repo-dir') . '/' . $localName . '.fossil';
$this->checkoutDir = $this->config->get('cache-vcs-dir') . '/' . $localName . '/';

@ -41,6 +41,10 @@ class GitDriver extends VcsDriver
$this->repoDir = $this->url;
$cacheUrl = realpath($this->url);
} else {
if (!Cache::isUsable($this->config->get('cache-vcs-dir'))) {
throw new \RuntimeException('GitDriver requires a usable cache directory, and it looks like you set it to be disabled');
}
$this->repoDir = $this->config->get('cache-vcs-dir') . '/' . preg_replace('{[^a-z0-9.]}i', '-', $this->url) . '/';
GitUtil::cleanEnv();

@ -13,6 +13,7 @@
namespace Composer\Repository\Vcs;
use Composer\Config;
use Composer\Cache;
use Composer\Util\Hg as HgUtils;
use Composer\Util\ProcessExecutor;
use Composer\Util\Filesystem;
@ -37,6 +38,10 @@ class HgDriver extends VcsDriver
if (Filesystem::isLocalPath($this->url)) {
$this->repoDir = $this->url;
} else {
if (!Cache::isUsable($this->config->get('cache-vcs-dir'))) {
throw new \RuntimeException('HgDriver requires a usable cache directory, and it looks like you set it to be disabled');
}
$cacheDir = $this->config->get('cache-vcs-dir');
$this->repoDir = $cacheDir . '/' . preg_replace('{[^a-z0-9]}i', '-', $this->url) . '/';

@ -13,6 +13,7 @@
namespace Composer\Repository\Vcs;
use Composer\Config;
use Composer\Cache;
use Composer\IO\IOInterface;
use Composer\Util\ProcessExecutor;
use Composer\Util\Perforce;
@ -54,6 +55,10 @@ class PerforceDriver extends VcsDriver
return;
}
if (!Cache::isUsable($this->config->get('cache-vcs-dir'))) {
throw new \RuntimeException('PerforceDriver requires a usable cache directory, and it looks like you set it to be disabled');
}
$repoDir = $this->config->get('cache-vcs-dir') . '/' . $this->depot;
$this->perforce = Perforce::create($repoConfig, $this->getUrl(), $repoDir, $this->process, $this->io);
}

@ -370,7 +370,13 @@ class Perforce
public function windowsLogin($password)
{
$command = $this->generateP4Command(' login -a');
$process = new Process($command, null, null, $password);
// TODO in v3 generate command as an array
if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
$process = Process::fromShellCommandline($command, null, null, $password);
} else {
$process = new Process($command, null, null, $password);
}
return $process->run();
}

@ -62,7 +62,13 @@ class ProcessExecutor
$this->captureOutput = func_num_args() > 1;
$this->errorOutput = null;
$process = new Process($command, $cwd, null, null, static::getTimeout());
// TODO in v3, commands should be passed in as arrays of cmd + args
if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
$process = Process::fromShellCommandline($command, $cwd, null, null, static::getTimeout());
} else {
$process = new Process($command, $cwd, null, null, static::getTimeout());
}
$callback = is_callable($output) ? $output : array($this, 'outputHandler');
$process->run($callback);

@ -31,6 +31,11 @@ class ApplicationTest extends TestCase
->with($this->equalTo('--no-plugins'))
->will($this->returnValue(true));
$inputMock->expects($this->at($index++))
->method('hasParameterOption')
->with($this->equalTo('--no-cache'))
->will($this->returnValue(false));
$inputMock->expects($this->at($index++))
->method('getParameterOption')
->with($this->equalTo(array('--working-dir', '-d')))
@ -84,6 +89,11 @@ class ApplicationTest extends TestCase
->with($this->equalTo('--no-plugins'))
->will($this->returnValue(true));
$inputMock->expects($this->at($index++))
->method('hasParameterOption')
->with($this->equalTo('--no-cache'))
->will($this->returnValue(false));
$inputMock->expects($this->at($index++))
->method('getParameterOption')
->with($this->equalTo(array('--working-dir', '-d')))

@ -14,6 +14,7 @@ namespace Composer\Test\Autoload;
use Composer\Autoload\AutoloadGenerator;
use Composer\Package\Link;
use Composer\Semver\Constraint\Constraint;
use Composer\Util\Filesystem;
use Composer\Package\AliasPackage;
use Composer\Package\Package;
@ -419,6 +420,72 @@ class AutoloadGeneratorTest extends TestCase
$this->assertFileExists($this->vendorDir.'/composer/autoload_classmap.php', "ClassMap file needs to be generated, even if empty.");
}
public function testNonDevAutoloadShouldIncludeReplacedPackages()
{
$package = new Package('a', '1.0', '1.0');
$package->setRequires(array(new Link('a', 'a/a')));
$packages = array();
$packages[] = $a = new Package('a/a', '1.0', '1.0');
$packages[] = $b = new Package('b/b', '1.0', '1.0');
$a->setRequires(array(new Link('a/a', 'b/c')));
$b->setAutoload(array('psr-4' => array('B\\' => 'src/')));
$b->setReplaces(
array(new Link('b/b', 'b/c', new Constraint('==', '1.0'), 'replaces'))
);
$this->repository->expects($this->once())
->method('getCanonicalPackages')
->will($this->returnValue($packages));
$this->fs->ensureDirectoryExists($this->vendorDir.'/b/b/src/C');
file_put_contents($this->vendorDir.'/b/b/src/C/C.php', '<?php namespace B\\C; class C {}');
$this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', true, '_5');
$this->assertEquals(
array(
'B\\C\\C' => $this->vendorDir.'/b/b/src/C/C.php',
),
include $this->vendorDir.'/composer/autoload_classmap.php'
);
}
public function testNonDevAutoloadExclusionWithRecursionReplace()
{
$package = new Package('a', '1.0', '1.0');
$package->setRequires(array(
new Link('a', 'a/a'),
));
$packages = array();
$packages[] = $a = new Package('a/a', '1.0', '1.0');
$packages[] = $b = new Package('b/b', '1.0', '1.0');
$a->setAutoload(array('psr-0' => array('A' => 'src/', 'A\\B' => 'lib/')));
$a->setRequires(array(
new Link('a/a', 'c/c'),
));
$b->setAutoload(array('psr-0' => array('B\\Sub\\Name' => 'src/')));
$b->setReplaces(array(
new Link('b/b', 'c/c'),
));
$this->repository->expects($this->once())
->method('getCanonicalPackages')
->will($this->returnValue($packages));
$this->fs->ensureDirectoryExists($this->vendorDir.'/composer');
$this->fs->ensureDirectoryExists($this->vendorDir.'/a/a/src');
$this->fs->ensureDirectoryExists($this->vendorDir.'/a/a/lib');
$this->fs->ensureDirectoryExists($this->vendorDir.'/b/b/src');
$this->generator->dump($this->config, $this->repository, $package, $this->im, 'composer', false, '_5');
$this->assertAutoloadFiles('vendors', $this->vendorDir.'/composer');
$this->assertFileExists($this->vendorDir.'/composer/autoload_classmap.php', "ClassMap file needs to be generated, even if empty.");
}
public function testPSRToClassMapIgnoresNonExistingDir()
{
$package = new Package('a', '1.0', '1.0');

@ -0,0 +1,46 @@
--TEST--
Update with a package whitelist pattern and all-dependencies flag updates packages and their dependencies, even if defined as root dependency, matching the pattern
--COMPOSER--
{
"repositories": [
{
"type": "package",
"package": [
{ "name": "fixed", "version": "1.1.0" },
{ "name": "fixed", "version": "1.0.0" },
{ "name": "whitelisted-component1", "version": "1.1.0" },
{ "name": "whitelisted-component1", "version": "1.0.0" },
{ "name": "whitelisted-component2", "version": "1.1.0", "require": { "dependency": "1.*" } },
{ "name": "whitelisted-component2", "version": "1.0.0", "require": { "dependency": "1.*" } },
{ "name": "dependency", "version": "1.1.0" },
{ "name": "dependency", "version": "1.0.0" },
{ "name": "unrelated", "version": "1.1.0", "require": { "unrelated-dependency": "1.*" } },
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
{ "name": "unrelated-dependency", "version": "1.1.0" },
{ "name": "unrelated-dependency", "version": "1.0.0" }
]
}
],
"require": {
"fixed": "1.*",
"whitelisted-component1": "1.*",
"whitelisted-component2": "1.*",
"dependency": "1.*",
"unrelated": "1.*"
}
}
--INSTALLED--
[
{ "name": "fixed", "version": "1.0.0" },
{ "name": "whitelisted-component1", "version": "1.0.0" },
{ "name": "whitelisted-component2", "version": "1.0.0", "require": { "dependency": "1.0.0" } },
{ "name": "dependency", "version": "1.0.0" },
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
{ "name": "unrelated-dependency", "version": "1.0.0" }
]
--RUN--
update whitelisted-* --with-all-dependencies
--EXPECT--
Updating whitelisted-component1 (1.0.0) to whitelisted-component1 (1.1.0)
Updating dependency (1.0.0) to dependency (1.1.0)
Updating whitelisted-component2 (1.0.0) to whitelisted-component2 (1.1.0)

@ -0,0 +1,49 @@
--TEST--
Update with a package whitelist only updates those packages and their dependencies matching the pattern but no dependencies defined as roo package
--COMPOSER--
{
"repositories": [
{
"type": "package",
"package": [
{ "name": "fixed", "version": "1.1.0" },
{ "name": "fixed", "version": "1.0.0" },
{ "name": "whitelisted-component1", "version": "1.1.0" },
{ "name": "whitelisted-component1", "version": "1.0.0" },
{ "name": "whitelisted-component2", "version": "1.1.0", "require": { "dependency": "1.*", "root-dependency": "1.*" } },
{ "name": "whitelisted-component2", "version": "1.0.0", "require": { "dependency": "1.*", "root-dependency": "1.*" } },
{ "name": "dependency", "version": "1.1.0" },
{ "name": "dependency", "version": "1.0.0" },
{ "name": "root-dependency", "version": "1.1.0" },
{ "name": "root-dependency", "version": "1.0.0" },
{ "name": "unrelated", "version": "1.1.0", "require": { "unrelated-dependency": "1.*" } },
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
{ "name": "unrelated-dependency", "version": "1.1.0" },
{ "name": "unrelated-dependency", "version": "1.0.0" }
]
}
],
"require": {
"fixed": "1.*",
"whitelisted-component1": "1.*",
"whitelisted-component2": "1.*",
"root-dependency": "1.*",
"unrelated": "1.*"
}
}
--INSTALLED--
[
{ "name": "fixed", "version": "1.0.0" },
{ "name": "whitelisted-component1", "version": "1.0.0" },
{ "name": "whitelisted-component2", "version": "1.0.0", "require": { "dependency": "1.0.0" } },
{ "name": "root-dependency", "version": "1.0.0" },
{ "name": "dependency", "version": "1.0.0" },
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
{ "name": "unrelated-dependency", "version": "1.0.0" }
]
--RUN--
update whitelisted-* --with-dependencies
--EXPECT--
Updating whitelisted-component1 (1.0.0) to whitelisted-component1 (1.1.0)
Updating dependency (1.0.0) to dependency (1.1.0)
Updating whitelisted-component2 (1.0.0) to whitelisted-component2 (1.1.0)

@ -0,0 +1,55 @@
--TEST--
Update with a package whitelist only updates those packages and their dependencies matching the pattern
--COMPOSER--
{
"repositories": [
{
"type": "package",
"package": [
{ "name": "fixed", "version": "1.1.0" },
{ "name": "fixed", "version": "1.0.0" },
{ "name": "whitelisted-component1", "version": "1.1.0", "require": { "whitelisted-component2": "1.1.0" } },
{ "name": "whitelisted-component1", "version": "1.0.0", "require": { "whitelisted-component2": "1.0.0" } },
{ "name": "whitelisted-component2", "version": "1.1.0", "require": { "dependency": "1.1.0", "whitelisted-component5": "1.0.0" } },
{ "name": "whitelisted-component2", "version": "1.0.0", "require": { "dependency": "1.0.0" } },
{ "name": "whitelisted-component3", "version": "1.1.0", "require": { "whitelisted-component4": "1.1.0" } },
{ "name": "whitelisted-component3", "version": "1.0.0", "require": { "whitelisted-component4": "1.0.0" } },
{ "name": "whitelisted-component4", "version": "1.1.0" },
{ "name": "whitelisted-component4", "version": "1.0.0" },
{ "name": "whitelisted-component5", "version": "1.1.0" },
{ "name": "whitelisted-component5", "version": "1.0.0" },
{ "name": "dependency", "version": "1.1.0" },
{ "name": "dependency", "version": "1.0.0" },
{ "name": "unrelated", "version": "1.1.0", "require": { "unrelated-dependency": "1.*" } },
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
{ "name": "unrelated-dependency", "version": "1.1.0" },
{ "name": "unrelated-dependency", "version": "1.0.0" }
]
}
],
"require": {
"fixed": "1.*",
"whitelisted-component1": "1.*",
"whitelisted-component2": "1.*",
"whitelisted-component3": "1.0.0",
"unrelated": "1.*"
}
}
--INSTALLED--
[
{ "name": "fixed", "version": "1.0.0" },
{ "name": "whitelisted-component1", "version": "1.0.0", "require": { "whitelisted-component2": "1.0.0" } },
{ "name": "whitelisted-component2", "version": "1.0.0", "require": { "dependency": "1.0.0" } },
{ "name": "whitelisted-component3", "version": "1.0.0", "require": { "whitelisted-component4": "1.0.0" } },
{ "name": "whitelisted-component4", "version": "1.0.0" },
{ "name": "whitelisted-component5", "version": "1.0.0" },
{ "name": "dependency", "version": "1.0.0" },
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
{ "name": "unrelated-dependency", "version": "1.0.0" }
]
--RUN--
update whitelisted-* --with-dependencies
--EXPECT--
Updating dependency (1.0.0) to dependency (1.1.0)
Updating whitelisted-component2 (1.0.0) to whitelisted-component2 (1.1.0)
Updating whitelisted-component1 (1.0.0) to whitelisted-component1 (1.1.0)

@ -0,0 +1,44 @@
--TEST--
Update with a package whitelist only updates those packages matching the pattern
--COMPOSER--
{
"repositories": [
{
"type": "package",
"package": [
{ "name": "fixed", "version": "1.1.0" },
{ "name": "fixed", "version": "1.0.0" },
{ "name": "whitelisted-component1", "version": "1.1.0" },
{ "name": "whitelisted-component1", "version": "1.0.0" },
{ "name": "whitelisted-component2", "version": "1.1.0", "require": { "dependency": "1.*" } },
{ "name": "whitelisted-component2", "version": "1.0.0", "require": { "dependency": "1.*" } },
{ "name": "dependency", "version": "1.1.0" },
{ "name": "dependency", "version": "1.0.0" },
{ "name": "unrelated", "version": "1.1.0", "require": { "unrelated-dependency": "1.*" } },
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
{ "name": "unrelated-dependency", "version": "1.1.0" },
{ "name": "unrelated-dependency", "version": "1.0.0" }
]
}
],
"require": {
"fixed": "1.*",
"whitelisted-component1": "1.*",
"whitelisted-component2": "1.*",
"unrelated": "1.*"
}
}
--INSTALLED--
[
{ "name": "fixed", "version": "1.0.0" },
{ "name": "whitelisted-component1", "version": "1.0.0" },
{ "name": "whitelisted-component2", "version": "1.0.0", "require": { "dependency": "1.0.0" } },
{ "name": "dependency", "version": "1.0.0" },
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
{ "name": "unrelated-dependency", "version": "1.0.0" }
]
--RUN--
update whitelisted-*
--EXPECT--
Updating whitelisted-component1 (1.0.0) to whitelisted-component1 (1.1.0)
Updating whitelisted-component2 (1.0.0) to whitelisted-component2 (1.1.0)
Loading…
Cancel
Save