Add warnings to ValidatingArrayLoader that are simply stripped by default, add reporting of warnings when loading branches

main
Jordi Boggiano 12 years ago
parent 99b7ab4021
commit 967c771b26

@ -18,13 +18,15 @@ namespace Composer\Package\Loader;
class InvalidPackageException extends \Exception class InvalidPackageException extends \Exception
{ {
private $errors; private $errors;
private $warnings;
private $data; private $data;
public function __construct(array $errors, array $data) public function __construct(array $errors, array $warnings, array $data)
{ {
$this->errors = $errors; $this->errors = $errors;
$this->warnings = $warnings;
$this->data = $data; $this->data = $data;
parent::__construct("Invalid package information: \n".implode("\n", $errors)); parent::__construct("Invalid package information: \n".implode("\n", array_merge($errors, $warnings)));
} }
public function getData() public function getData()
@ -36,4 +38,9 @@ class InvalidPackageException extends \Exception
{ {
return $this->errors; return $this->errors;
} }
public function getWarnings()
{
return $this->warnings;
}
} }

@ -23,20 +23,20 @@ class ValidatingArrayLoader implements LoaderInterface
{ {
private $loader; private $loader;
private $versionParser; private $versionParser;
private $ignoreErrors;
private $errors; private $errors;
private $warnings;
private $config; private $config;
public function __construct(LoaderInterface $loader, $ignoreErrors = true, VersionParser $parser = null) public function __construct(LoaderInterface $loader, VersionParser $parser = null)
{ {
$this->loader = $loader; $this->loader = $loader;
$this->ignoreErrors = $ignoreErrors;
$this->versionParser = $parser ?: new VersionParser(); $this->versionParser = $parser ?: new VersionParser();
} }
public function load(array $config, $class = 'Composer\Package\CompletePackage') public function load(array $config, $class = 'Composer\Package\CompletePackage')
{ {
$this->errors = array(); $this->errors = array();
$this->warnings = array();
$this->config = $config; $this->config = $config;
$this->validateRegex('name', '[A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*', true); $this->validateRegex('name', '[A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*', true);
@ -77,30 +77,27 @@ class ValidatingArrayLoader implements LoaderInterface
} }
} }
$this->validateArray('authors'); if ($this->validateArray('authors') && !empty($this->config['authors'])) {
if (!empty($this->config['authors'])) {
foreach ($this->config['authors'] as $key => $author) { foreach ($this->config['authors'] as $key => $author) {
if (!is_array($author)) { if (!is_array($author)) {
$this->errors[] = 'authors.'.$key.' : should be an array, '.gettype($author).' given'; $this->errors[] = 'authors.'.$key.' : should be an array, '.gettype($author).' given';
unset($this->config['authors'][$key]); unset($this->config['authors'][$key]);
continue; continue;
} }
foreach (array('homepage', 'email', 'name', 'role') as $authorData) {
if (isset($author[$authorData]) && !is_string($author[$authorData])) {
$this->errors[] = 'authors.'.$key.'.'.$authorData.' : invalid value, must be a string';
unset($this->config['authors'][$key][$authorData]);
}
}
if (isset($author['homepage']) && !$this->filterUrl($author['homepage'])) { if (isset($author['homepage']) && !$this->filterUrl($author['homepage'])) {
$this->errors[] = 'authors.'.$key.'.homepage : invalid value, must be a valid http/https URL'; $this->warnings[] = 'authors.'.$key.'.homepage : invalid value, must be a valid http/https URL';
unset($this->config['authors'][$key]['homepage']); unset($this->config['authors'][$key]['homepage']);
} }
if (isset($author['email']) && !filter_var($author['email'], FILTER_VALIDATE_EMAIL)) { if (isset($author['email']) && !filter_var($author['email'], FILTER_VALIDATE_EMAIL)) {
$this->errors[] = 'authors.'.$key.'.email : invalid value, must be a valid email address'; $this->warnings[] = 'authors.'.$key.'.email : invalid value, must be a valid email address';
unset($this->config['authors'][$key]['email']); unset($this->config['authors'][$key]['email']);
} }
if (isset($author['name']) && !is_string($author['name'])) {
$this->errors[] = 'authors.'.$key.'.name : invalid value, must be a string';
unset($this->config['authors'][$key]['name']);
}
if (isset($author['role']) && !is_string($author['role'])) {
$this->errors[] = 'authors.'.$key.'.role : invalid value, must be a string';
unset($this->config['authors'][$key]['role']);
}
if (empty($this->config['authors'][$key])) { if (empty($this->config['authors'][$key])) {
unset($this->config['authors'][$key]); unset($this->config['authors'][$key]);
} }
@ -110,23 +107,29 @@ class ValidatingArrayLoader implements LoaderInterface
} }
} }
$this->validateArray('support'); if ($this->validateArray('support') && !empty($this->config['support'])) {
if (!empty($this->config['support'])) { foreach (array('issues', 'forum', 'wiki', 'source', 'email', 'irc') as $key) {
if (isset($this->config['support'][$key]) && !is_string($this->config['support'][$key])) {
$this->errors[] = 'support.'.$key.' : invalid value, must be a string';
unset($this->config['support'][$key]);
}
}
if (isset($this->config['support']['email']) && !filter_var($this->config['support']['email'], FILTER_VALIDATE_EMAIL)) { if (isset($this->config['support']['email']) && !filter_var($this->config['support']['email'], FILTER_VALIDATE_EMAIL)) {
$this->errors[] = 'support.email : invalid value, must be a valid email address'; $this->warnings[] = 'support.email : invalid value, must be a valid email address';
unset($this->config['support']['email']); unset($this->config['support']['email']);
} }
if (isset($this->config['support']['irc']) if (isset($this->config['support']['irc'])
&& (!filter_var($this->config['support']['irc'], FILTER_VALIDATE_URL) || !preg_match('{^irc://}iu', $this->config['support']['irc'])) && (!filter_var($this->config['support']['irc'], FILTER_VALIDATE_URL) || !preg_match('{^irc://}iu', $this->config['support']['irc']))
) { ) {
$this->errors[] = 'support.irc : invalid value, must be '; $this->warnings[] = 'support.irc : invalid value, must be ';
unset($this->config['support']['irc']); unset($this->config['support']['irc']);
} }
foreach (array('issues', 'forum', 'wiki', 'source') as $key) { foreach (array('issues', 'forum', 'wiki', 'source') as $key) {
if (isset($this->config['support'][$key]) && !$this->filterUrl($this->config['support'][$key])) { if (isset($this->config['support'][$key]) && !$this->filterUrl($this->config['support'][$key])) {
$this->errors[] = 'support.'.$key.' : invalid value, must be a valid http/https URL'; $this->warnings[] = 'support.'.$key.' : invalid value, must be a valid http/https URL';
unset($this->config['support'][$key]); unset($this->config['support'][$key]);
} }
} }
@ -136,7 +139,7 @@ class ValidatingArrayLoader implements LoaderInterface
} }
foreach (array_keys(BasePackage::$supportedLinkTypes) as $linkType) { foreach (array_keys(BasePackage::$supportedLinkTypes) as $linkType) {
if (isset($this->config[$linkType])) { if ($this->validateArray($linkType) && isset($this->config[$linkType])) {
foreach ($this->config[$linkType] as $package => $constraint) { foreach ($this->config[$linkType] as $package => $constraint) {
if (!is_string($constraint)) { if (!is_string($constraint)) {
$this->errors[] = $linkType.'.'.$package.' : invalid value, must be a string containing a version constraint'; $this->errors[] = $linkType.'.'.$package.' : invalid value, must be a string containing a version constraint';
@ -153,8 +156,7 @@ class ValidatingArrayLoader implements LoaderInterface
} }
} }
$this->validateArray('suggest'); if ($this->validateArray('suggest') && !empty($this->config['suggest'])) {
if (!empty($this->config['suggest'])) {
foreach ($this->config['suggest'] as $package => $description) { foreach ($this->config['suggest'] as $package => $description) {
if (!is_string($description)) { if (!is_string($description)) {
$this->errors[] = 'suggest.'.$package.' : invalid value, must be a string describing why the package is suggested'; $this->errors[] = 'suggest.'.$package.' : invalid value, must be a string describing why the package is suggested';
@ -205,17 +207,26 @@ class ValidatingArrayLoader implements LoaderInterface
} }
} }
if ($this->errors && !$this->ignoreErrors) { if ($this->errors) {
throw new InvalidPackageException($this->errors, $config); throw new InvalidPackageException($this->errors, $this->warnings, $config);
} }
$package = $this->loader->load($this->config, $class); $package = $this->loader->load($this->config, $class);
$this->errors = array();
$this->config = null; $this->config = null;
return $package; return $package;
} }
public function getWarnings()
{
return $this->warnings;
}
public function getErrors()
{
return $this->errors;
}
private function validateRegex($property, $regex, $mandatory = false) private function validateRegex($property, $regex, $mandatory = false)
{ {
if (!$this->validateString($property, $mandatory)) { if (!$this->validateString($property, $mandatory)) {
@ -307,11 +318,13 @@ class ValidatingArrayLoader implements LoaderInterface
} }
if (!$this->filterUrl($this->config[$property])) { if (!$this->filterUrl($this->config[$property])) {
$this->errors[] = $property.' : invalid value, must be a valid http/https URL'; $this->warnings[] = $property.' : invalid value, must be a valid http/https URL';
unset($this->config[$property]); unset($this->config[$property]);
return false; return false;
} }
return true;
} }
private function filterUrl($value) private function filterUrl($value)

@ -16,6 +16,8 @@ use Composer\Downloader\TransportException;
use Composer\Repository\Vcs\VcsDriverInterface; use Composer\Repository\Vcs\VcsDriverInterface;
use Composer\Package\Version\VersionParser; use Composer\Package\Version\VersionParser;
use Composer\Package\Loader\ArrayLoader; use Composer\Package\Loader\ArrayLoader;
use Composer\Package\Loader\ValidatingArrayLoader;
use Composer\Package\Loader\InvalidPackageException;
use Composer\Package\Loader\LoaderInterface; use Composer\Package\Loader\LoaderInterface;
use Composer\IO\IOInterface; use Composer\IO\IOInterface;
use Composer\Config; use Composer\Config;
@ -217,7 +219,12 @@ class VcsRepository extends ArrayRepository
$this->io->write('Importing branch '.$branch.' ('.$data['version'].')'); $this->io->write('Importing branch '.$branch.' ('.$data['version'].')');
} }
$this->addPackage($this->loader->load($this->preProcess($driver, $data, $identifier))); $packageData = $this->preProcess($driver, $data, $identifier);
$package = $this->loader->load($packageData);
if ($this->loader instanceof ValidatingArrayLoader && $this->loader->getWarnings()) {
throw new InvalidPackageException($this->loader->getErrors(), $this->loader->getWarnings(), $packageData);
}
$this->addPackage($package);
} catch (TransportException $e) { } catch (TransportException $e) {
if ($verbose) { if ($verbose) {
$this->io->write('Skipped branch '.$branch.', no composer file was found'); $this->io->write('Skipped branch '.$branch.', no composer file was found');

@ -97,7 +97,7 @@ class ConfigValidator
} }
try { try {
$loader = new ValidatingArrayLoader(new ArrayLoader(), false); $loader = new ValidatingArrayLoader(new ArrayLoader());
if (!isset($manifest['version'])) { if (!isset($manifest['version'])) {
$manifest['version'] = '1.0.0'; $manifest['version'] = '1.0.0';
} }
@ -107,6 +107,7 @@ class ConfigValidator
$loader->load($manifest); $loader->load($manifest);
} catch (InvalidPackageException $e) { } catch (InvalidPackageException $e) {
$errors = array_merge($errors, $e->getErrors()); $errors = array_merge($errors, $e->getErrors());
$warnings = array_merge($warnings, $e->getWarnings());
} }
return array($errors, $publishErrors, $warnings); return array($errors, $publishErrors, $warnings);

@ -29,7 +29,7 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
->method('load') ->method('load')
->with($config); ->with($config);
$loader = new ValidatingArrayLoader($internalLoader, false); $loader = new ValidatingArrayLoader($internalLoader);
$loader->load($config); $loader->load($config);
} }
@ -148,12 +148,12 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
} }
/** /**
* @dataProvider failureProvider * @dataProvider errorProvider
*/ */
public function testLoadFailureThrowsException($config, $expectedErrors) public function testLoadFailureThrowsException($config, $expectedErrors)
{ {
$internalLoader = $this->getMock('Composer\Package\Loader\LoaderInterface'); $internalLoader = $this->getMock('Composer\Package\Loader\LoaderInterface');
$loader = new ValidatingArrayLoader($internalLoader, false); $loader = new ValidatingArrayLoader($internalLoader);
try { try {
$loader->load($config); $loader->load($config);
$this->fail('Expected exception to be thrown'); $this->fail('Expected exception to be thrown');
@ -166,9 +166,24 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
} }
/** /**
* @dataProvider failureProvider * @dataProvider warningProvider
*/ */
public function testLoadSkipsInvalidDataWhenIgnoringErrors($config) public function testLoadWarnings($config, $expectedWarnings)
{
$internalLoader = $this->getMock('Composer\Package\Loader\LoaderInterface');
$loader = new ValidatingArrayLoader($internalLoader);
$loader->load($config);
$warnings = $loader->getWarnings();
sort($expectedWarnings);
sort($warnings);
$this->assertEquals($expectedWarnings, $warnings);
}
/**
* @dataProvider warningProvider
*/
public function testLoadSkipsWarningDataWhenIgnoringErrors($config)
{ {
$internalLoader = $this->getMock('Composer\Package\Loader\LoaderInterface'); $internalLoader = $this->getMock('Composer\Package\Loader\LoaderInterface');
$internalLoader $internalLoader
@ -176,12 +191,12 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
->method('load') ->method('load')
->with(array('name' => 'a/b')); ->with(array('name' => 'a/b'));
$loader = new ValidatingArrayLoader($internalLoader, true); $loader = new ValidatingArrayLoader($internalLoader);
$config['name'] = 'a/b'; $config['name'] = 'a/b';
$loader->load($config); $loader->load($config);
} }
public function failureProvider() public function errorProvider()
{ {
return array( return array(
array( array(
@ -192,6 +207,32 @@ class ValidatingArrayLoaderTest extends \PHPUnit_Framework_TestCase
'name : invalid value, must match [A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*' 'name : invalid value, must match [A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*'
) )
), ),
array(
array(
'name' => 'foo/bar',
'homepage' => 43,
),
array(
'homepage : should be a string, integer given',
)
),
array(
array(
'name' => 'foo/bar',
'support' => array(
'source' => array(),
),
),
array(
'support.source : invalid value, must be a string',
)
),
);
}
public function warningProvider()
{
return array(
array( array(
array( array(
'name' => 'foo/bar', 'name' => 'foo/bar',

Loading…
Cancel
Save