Add Yaml LintCommand
Add tests Fix tests & YamlLintCommand help formatting fabbot fixes Use Generator to iterate over the filesystem Move STDIN related code in a method Use RecursiveIteratorIterator::LEAVES_ONLY rather than SELF_FIRST Stop using the Finder component when available (Make findFiles() private) Re-add FrameworkBundle YamlLintCommandTest Use CommandTester::getStatusCode() rather than assign execute() Re-add feature for bundle directories, Test it
This commit is contained in:
parent
e949d348b1
commit
33402ea747
@ -28,7 +28,7 @@ class LintCommandTest extends \PHPUnit_Framework_TestCase
|
|||||||
$ret = $tester->execute(array('filename' => array($filename)), array('verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false));
|
$ret = $tester->execute(array('filename' => array($filename)), array('verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false));
|
||||||
|
|
||||||
$this->assertEquals(0, $ret, 'Returns 0 in case of success');
|
$this->assertEquals(0, $ret, 'Returns 0 in case of success');
|
||||||
$this->assertRegExp('/^\/\/ OK in /', trim($tester->getDisplay()));
|
$this->assertContains('OK in', trim($tester->getDisplay()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLintIncorrectFile()
|
public function testLintIncorrectFile()
|
||||||
|
@ -11,155 +11,45 @@
|
|||||||
|
|
||||||
namespace Symfony\Bundle\FrameworkBundle\Command;
|
namespace Symfony\Bundle\FrameworkBundle\Command;
|
||||||
|
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Yaml\Command\LintCommand as BaseLintCommand;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
|
||||||
use Symfony\Component\Finder\Finder;
|
|
||||||
use Symfony\Component\Yaml\Exception\ParseException;
|
|
||||||
use Symfony\Component\Yaml\Parser;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates YAML files syntax and outputs encountered errors.
|
* Validates YAML files syntax and outputs encountered errors.
|
||||||
*
|
*
|
||||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||||
|
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||||
*/
|
*/
|
||||||
class YamlLintCommand extends Command
|
class YamlLintCommand extends BaseLintCommand
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
parent::configure();
|
||||||
->setName('lint:yaml')
|
|
||||||
->setDescription('Lints a file and outputs encountered errors')
|
|
||||||
->addArgument('filename', null, 'A file or a directory or STDIN')
|
|
||||||
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt')
|
|
||||||
->setHelp(<<<EOF
|
|
||||||
The <info>%command.name%</info> command lints a YAML file and outputs to STDOUT
|
|
||||||
the first encountered syntax error.
|
|
||||||
|
|
||||||
You can validate the syntax of a file:
|
$this->setHelp(
|
||||||
|
$this->getHelp().<<<EOF
|
||||||
|
|
||||||
<info>php %command.full_name% filename</info>
|
Or find all files in a bundle:
|
||||||
|
|
||||||
Or of a whole directory:
|
|
||||||
|
|
||||||
<info>php %command.full_name% dirname</info>
|
|
||||||
<info>php %command.full_name% dirname --format=json</info>
|
|
||||||
|
|
||||||
Or all YAML files in a bundle:
|
|
||||||
|
|
||||||
<info>php %command.full_name% @AcmeDemoBundle</info>
|
<info>php %command.full_name% @AcmeDemoBundle</info>
|
||||||
|
|
||||||
You can also pass the YAML contents from STDIN:
|
|
||||||
|
|
||||||
<info>cat filename | php %command.full_name%</info>
|
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
)
|
);
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function getDirectoryIterator($directory)
|
||||||
{
|
{
|
||||||
$io = new SymfonyStyle($input, $output);
|
if (!is_dir($directory)) {
|
||||||
$filename = $input->getArgument('filename');
|
$directory = $this->getApplication()->getKernel()->locateResource($directory);
|
||||||
|
|
||||||
if (!$filename) {
|
|
||||||
if (0 !== ftell(STDIN)) {
|
|
||||||
throw new \RuntimeException('Please provide a filename or pipe file content to STDIN.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = '';
|
|
||||||
while (!feof(STDIN)) {
|
|
||||||
$content .= fread(STDIN, 1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->display($input, $output, $io, array($this->validate($content)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 !== strpos($filename, '@') && !is_readable($filename)) {
|
return parent::getDirectoryIterator($directory);
|
||||||
throw new \RuntimeException(sprintf('File or directory "%s" is not readable', $filename));
|
|
||||||
}
|
|
||||||
|
|
||||||
$files = array();
|
|
||||||
if (is_file($filename)) {
|
|
||||||
$files = array($filename);
|
|
||||||
} elseif (is_dir($filename)) {
|
|
||||||
$files = Finder::create()->files()->in($filename)->name('*.yml');
|
|
||||||
} else {
|
|
||||||
$dir = $this->getApplication()->getKernel()->locateResource($filename);
|
|
||||||
$files = Finder::create()->files()->in($dir)->name('*.yml');
|
|
||||||
}
|
|
||||||
|
|
||||||
$filesInfo = array();
|
|
||||||
foreach ($files as $file) {
|
|
||||||
$filesInfo[] = $this->validate(file_get_contents($file), $file);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->display($input, $output, $io, $filesInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function validate($content, $file = null)
|
protected function isReadable($fileOrDirectory)
|
||||||
{
|
{
|
||||||
$parser = new Parser();
|
return 0 === strpos($fileOrDirectory, '@') || parent::isReadable($fileOrDirectory);
|
||||||
try {
|
|
||||||
$parser->parse($content);
|
|
||||||
} catch (ParseException $e) {
|
|
||||||
return array('file' => $file, 'valid' => false, 'message' => $e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return array('file' => $file, 'valid' => true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function display(InputInterface $input, OutputInterface $output, SymfonyStyle $io, $files)
|
|
||||||
{
|
|
||||||
switch ($input->getOption('format')) {
|
|
||||||
case 'txt':
|
|
||||||
return $this->displayTxt($output, $io, $files);
|
|
||||||
case 'json':
|
|
||||||
return $this->displayJson($io, $files);
|
|
||||||
default:
|
|
||||||
throw new \InvalidArgumentException(sprintf('The format "%s" is not supported.', $input->getOption('format')));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function displayTxt(OutputInterface $output, SymfonyStyle $io, $filesInfo)
|
|
||||||
{
|
|
||||||
$errors = 0;
|
|
||||||
|
|
||||||
foreach ($filesInfo as $info) {
|
|
||||||
if ($info['valid'] && $output->isVerbose()) {
|
|
||||||
$io->comment('<info>OK</info>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
|
|
||||||
} elseif (!$info['valid']) {
|
|
||||||
++$errors;
|
|
||||||
$io->text(sprintf('<error> ERROR </error> in %s', $info['file']));
|
|
||||||
$io->text(sprintf('<error> >> %s</error>', $info['message']));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($errors === 0) {
|
|
||||||
$io->success(sprintf('All %d YAML files contain valid syntax.', count($filesInfo)));
|
|
||||||
} else {
|
|
||||||
$io->warning(sprintf('%d YAML files have valid syntax and %d contain errors.', count($filesInfo) - $errors, $errors));
|
|
||||||
}
|
|
||||||
|
|
||||||
return min($errors, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function displayJson(OutputInterface $output, $filesInfo)
|
|
||||||
{
|
|
||||||
$errors = 0;
|
|
||||||
|
|
||||||
array_walk($filesInfo, function (&$v) use (&$errors) {
|
|
||||||
$v['file'] = (string) $v['file'];
|
|
||||||
if (!$v['valid']) {
|
|
||||||
++$errors;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$output->writeln(json_encode($filesInfo, JSON_PRETTY_PRINT));
|
|
||||||
|
|
||||||
return min($errors, 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,198 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Command\YamlLintCommand;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||||
|
use Symfony\Component\Console\Application as BaseApplication;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Tester\CommandTester;
|
||||||
|
use Symfony\Component\Console\Helper\HelperSet;
|
||||||
|
use Symfony\Component\Console\Input\InputDefinition;
|
||||||
|
use Symfony\Component\HttpKernel\KernelInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the YamlLintCommand.
|
||||||
|
*
|
||||||
|
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||||
|
*/
|
||||||
|
class YamlLintCommandTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
private $files;
|
||||||
|
|
||||||
|
public function testLintCorrectFile()
|
||||||
|
{
|
||||||
|
$tester = $this->createCommandTester();
|
||||||
|
$filename = $this->createFile('foo: bar');
|
||||||
|
|
||||||
|
$tester->execute(
|
||||||
|
array('filename' => $filename),
|
||||||
|
array('verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(0, $tester->getStatusCode(), 'Returns 0 in case of success');
|
||||||
|
$this->assertContains('OK', trim($tester->getDisplay()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLintIncorrectFile()
|
||||||
|
{
|
||||||
|
$incorrectContent = '
|
||||||
|
foo:
|
||||||
|
bar';
|
||||||
|
$tester = $this->createCommandTester();
|
||||||
|
$filename = $this->createFile($incorrectContent);
|
||||||
|
|
||||||
|
$tester->execute(array('filename' => $filename), array('decorated' => false));
|
||||||
|
|
||||||
|
$this->assertEquals(1, $tester->getStatusCode(), 'Returns 1 in case of error');
|
||||||
|
$this->assertContains('Unable to parse at line 3 (near "bar").', trim($tester->getDisplay()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \RuntimeException
|
||||||
|
*/
|
||||||
|
public function testLintFileNotReadable()
|
||||||
|
{
|
||||||
|
$tester = $this->createCommandTester();
|
||||||
|
$filename = $this->createFile('');
|
||||||
|
unlink($filename);
|
||||||
|
|
||||||
|
$tester->execute(array('filename' => $filename), array('decorated' => false));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetHelp()
|
||||||
|
{
|
||||||
|
$command = new YamlLintCommand();
|
||||||
|
$expected = <<<EOF
|
||||||
|
The <info>%command.name%</info> command lints a YAML file and outputs to STDOUT
|
||||||
|
the first encountered syntax error.
|
||||||
|
|
||||||
|
You can validates YAML contents passed from STDIN:
|
||||||
|
|
||||||
|
<info>cat filename | php %command.full_name%</info>
|
||||||
|
|
||||||
|
You can also validate the syntax of a file:
|
||||||
|
|
||||||
|
<info>php %command.full_name% filename</info>
|
||||||
|
|
||||||
|
Or of a whole directory:
|
||||||
|
|
||||||
|
<info>php %command.full_name% dirname</info>
|
||||||
|
<info>php %command.full_name% dirname --format=json</info>
|
||||||
|
|
||||||
|
Or find all files in a bundle:
|
||||||
|
|
||||||
|
<info>php %command.full_name% @AcmeDemoBundle</info>
|
||||||
|
|
||||||
|
EOF;
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $command->getHelp());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLintFilesFromBundleDirectory()
|
||||||
|
{
|
||||||
|
$tester = $this->createCommandTester($this->getKernelAwareApplicationMock());
|
||||||
|
$tester->execute(
|
||||||
|
array('filename' => '@AppBundle/Resources'),
|
||||||
|
array('verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(0, $tester->getStatusCode(), 'Returns 0 in case of success');
|
||||||
|
$this->assertContains('[OK] All 0 YAML files contain valid syntax', trim($tester->getDisplay()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string Path to the new file
|
||||||
|
*/
|
||||||
|
private function createFile($content)
|
||||||
|
{
|
||||||
|
$filename = tempnam(sys_get_temp_dir(), 'sf-');
|
||||||
|
file_put_contents($filename, $content);
|
||||||
|
|
||||||
|
$this->files[] = $filename;
|
||||||
|
|
||||||
|
return $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return CommandTester
|
||||||
|
*/
|
||||||
|
private function createCommandTester($application = null)
|
||||||
|
{
|
||||||
|
if (!$application) {
|
||||||
|
$application = new BaseApplication();
|
||||||
|
$application->add(new YamlLintCommand());
|
||||||
|
}
|
||||||
|
|
||||||
|
$command = $application->find('lint:yaml');
|
||||||
|
|
||||||
|
if ($application) {
|
||||||
|
$command->setApplication($application);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CommandTester($command);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getKernelAwareApplicationMock()
|
||||||
|
{
|
||||||
|
$kernel = $this->getMockBuilder(KernelInterface::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$kernel
|
||||||
|
->expects($this->once())
|
||||||
|
->method('locateResource')
|
||||||
|
->with('@AppBundle/Resources')
|
||||||
|
->willReturn(sys_get_temp_dir());
|
||||||
|
|
||||||
|
$application = $this->getMockBuilder(Application::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$application
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getKernel')
|
||||||
|
->willReturn($kernel);
|
||||||
|
|
||||||
|
$application
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getHelperSet')
|
||||||
|
->willReturn(new HelperSet());
|
||||||
|
|
||||||
|
$application
|
||||||
|
->expects($this->any())
|
||||||
|
->method('getDefinition')
|
||||||
|
->willReturn(new InputDefinition());
|
||||||
|
|
||||||
|
$application
|
||||||
|
->expects($this->once())
|
||||||
|
->method('find')
|
||||||
|
->with('lint:yaml')
|
||||||
|
->willReturn(new YamlLintCommand());
|
||||||
|
|
||||||
|
return $application;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->files = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown()
|
||||||
|
{
|
||||||
|
foreach ($this->files as $file) {
|
||||||
|
if (file_exists($file)) {
|
||||||
|
unlink($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -49,7 +49,7 @@
|
|||||||
"symfony/process": "~2.8|~3.0",
|
"symfony/process": "~2.8|~3.0",
|
||||||
"symfony/serializer": "~2.8|^3.0",
|
"symfony/serializer": "~2.8|^3.0",
|
||||||
"symfony/validator": "~3.1",
|
"symfony/validator": "~3.1",
|
||||||
"symfony/yaml": "~2.8|~3.0",
|
"symfony/yaml": "~3.2",
|
||||||
"symfony/property-info": "~2.8|~3.0",
|
"symfony/property-info": "~2.8|~3.0",
|
||||||
"phpdocumentor/reflection-docblock": "^3.0",
|
"phpdocumentor/reflection-docblock": "^3.0",
|
||||||
"twig/twig": "~1.23|~2.0"
|
"twig/twig": "~1.23|~2.0"
|
||||||
|
204
src/Symfony/Component/Yaml/Command/LintCommand.php
Normal file
204
src/Symfony/Component/Yaml/Command/LintCommand.php
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\Yaml\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
use Symfony\Component\Yaml\Exception\ParseException;
|
||||||
|
use Symfony\Component\Yaml\Parser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates YAML files syntax and outputs encountered errors.
|
||||||
|
*
|
||||||
|
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||||
|
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||||
|
*/
|
||||||
|
class LintCommand extends Command
|
||||||
|
{
|
||||||
|
private $parser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->setName('lint:yaml')
|
||||||
|
->setDescription('Lints a file and outputs encountered errors')
|
||||||
|
->addArgument('filename', null, 'A file or a directory or STDIN')
|
||||||
|
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt')
|
||||||
|
->setHelp(<<<EOF
|
||||||
|
The <info>%command.name%</info> command lints a YAML file and outputs to STDOUT
|
||||||
|
the first encountered syntax error.
|
||||||
|
|
||||||
|
You can validates YAML contents passed from STDIN:
|
||||||
|
|
||||||
|
<info>cat filename | php %command.full_name%</info>
|
||||||
|
|
||||||
|
You can also validate the syntax of a file:
|
||||||
|
|
||||||
|
<info>php %command.full_name% filename</info>
|
||||||
|
|
||||||
|
Or of a whole directory:
|
||||||
|
|
||||||
|
<info>php %command.full_name% dirname</info>
|
||||||
|
<info>php %command.full_name% dirname --format=json</info>
|
||||||
|
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
$filename = $input->getArgument('filename');
|
||||||
|
|
||||||
|
if (!$filename) {
|
||||||
|
if (!$stdin = $this->getStdin()) {
|
||||||
|
throw new \RuntimeException('Please provide a filename or pipe file content to STDIN.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->display($input, $output, $io, array($this->validate($stdin)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->isReadable($filename)) {
|
||||||
|
throw new \RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
$filesInfo = array();
|
||||||
|
foreach ($this->getFiles($filename) as $file) {
|
||||||
|
$filesInfo[] = $this->validate(file_get_contents($file), $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->display($input, $output, $io, $filesInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validate($content, $file = null)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->getParser()->parse($content);
|
||||||
|
} catch (ParseException $e) {
|
||||||
|
return array('file' => $file, 'valid' => false, 'message' => $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return array('file' => $file, 'valid' => true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function display(InputInterface $input, OutputInterface $output, SymfonyStyle $io, $files)
|
||||||
|
{
|
||||||
|
switch ($input->getOption('format')) {
|
||||||
|
case 'txt':
|
||||||
|
return $this->displayTxt($output, $io, $files);
|
||||||
|
case 'json':
|
||||||
|
return $this->displayJson($io, $files);
|
||||||
|
default:
|
||||||
|
throw new \InvalidArgumentException(sprintf('The format "%s" is not supported.', $input->getOption('format')));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function displayTxt(OutputInterface $output, SymfonyStyle $io, $filesInfo)
|
||||||
|
{
|
||||||
|
$countFiles = count($filesInfo);
|
||||||
|
$erroredFiles = 0;
|
||||||
|
|
||||||
|
foreach ($filesInfo as $info) {
|
||||||
|
if ($info['valid'] && $output->isVerbose()) {
|
||||||
|
$io->comment('<info>OK</info>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
|
||||||
|
} elseif (!$info['valid']) {
|
||||||
|
++$erroredFiles;
|
||||||
|
$io->text(sprintf('<error> ERROR </error> in %s', $info['file']));
|
||||||
|
$io->text(sprintf('<error> >> %s</error>', $info['message']));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($erroredFiles === 0) {
|
||||||
|
$io->success(sprintf('All %d YAML files contain valid syntax.', $countFiles));
|
||||||
|
} else {
|
||||||
|
$io->warning(sprintf('%d YAML files have valid syntax and %d contain errors.', $countFiles - $erroredFiles, $erroredFiles));
|
||||||
|
}
|
||||||
|
|
||||||
|
return min($erroredFiles, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function displayJson(OutputInterface $output, $filesInfo)
|
||||||
|
{
|
||||||
|
$errors = 0;
|
||||||
|
|
||||||
|
array_walk($filesInfo, function (&$v) use (&$errors) {
|
||||||
|
$v['file'] = (string) $v['file'];
|
||||||
|
if (!$v['valid']) {
|
||||||
|
++$errors;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$output->writeln(json_encode($filesInfo, JSON_PRETTY_PRINT));
|
||||||
|
|
||||||
|
return min($errors, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getFiles($fileOrDirectory)
|
||||||
|
{
|
||||||
|
if (is_file($fileOrDirectory)) {
|
||||||
|
yield new \SplFileInfo($fileOrDirectory);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->getDirectoryIterator($fileOrDirectory) as $file) {
|
||||||
|
if (!in_array($file->getExtension(), array('yml', 'yaml'))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDirectoryIterator($directory)
|
||||||
|
{
|
||||||
|
return new \RecursiveIteratorIterator(
|
||||||
|
new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS),
|
||||||
|
\RecursiveIteratorIterator::LEAVES_ONLY
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getStdin()
|
||||||
|
{
|
||||||
|
if (0 !== ftell(STDIN)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$inputs = '';
|
||||||
|
while (!feof(STDIN)) {
|
||||||
|
$inputs .= fread(STDIN, 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getParser()
|
||||||
|
{
|
||||||
|
if (!$this->parser) {
|
||||||
|
$this->parser = new Parser();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function isReadable($fileOrDirectory)
|
||||||
|
{
|
||||||
|
return is_readable($fileOrDirectory);
|
||||||
|
}
|
||||||
|
}
|
103
src/Symfony/Component/Yaml/Tests/Command/LintCommandTest.php
Normal file
103
src/Symfony/Component/Yaml/Tests/Command/LintCommandTest.php
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\Yaml\Tests\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Yaml\Command\LintCommand;
|
||||||
|
use Symfony\Component\Console\Application;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Tester\CommandTester;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the YamlLintCommand.
|
||||||
|
*
|
||||||
|
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||||
|
*/
|
||||||
|
class LintCommandTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
private $files;
|
||||||
|
|
||||||
|
public function testLintCorrectFile()
|
||||||
|
{
|
||||||
|
$tester = $this->createCommandTester();
|
||||||
|
$filename = $this->createFile('foo: bar');
|
||||||
|
|
||||||
|
$ret = $tester->execute(array('filename' => $filename), array('verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false));
|
||||||
|
|
||||||
|
$this->assertEquals(0, $ret, 'Returns 0 in case of success');
|
||||||
|
$this->assertRegExp('/^\/\/ OK in /', trim($tester->getDisplay()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLintIncorrectFile()
|
||||||
|
{
|
||||||
|
$incorrectContent = '
|
||||||
|
foo:
|
||||||
|
bar';
|
||||||
|
$tester = $this->createCommandTester();
|
||||||
|
$filename = $this->createFile($incorrectContent);
|
||||||
|
|
||||||
|
$ret = $tester->execute(array('filename' => $filename), array('decorated' => false));
|
||||||
|
|
||||||
|
$this->assertEquals(1, $ret, 'Returns 1 in case of error');
|
||||||
|
$this->assertContains('Unable to parse at line 3 (near "bar").', trim($tester->getDisplay()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \RuntimeException
|
||||||
|
*/
|
||||||
|
public function testLintFileNotReadable()
|
||||||
|
{
|
||||||
|
$tester = $this->createCommandTester();
|
||||||
|
$filename = $this->createFile('');
|
||||||
|
unlink($filename);
|
||||||
|
|
||||||
|
$ret = $tester->execute(array('filename' => $filename), array('decorated' => false));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string Path to the new file
|
||||||
|
*/
|
||||||
|
private function createFile($content)
|
||||||
|
{
|
||||||
|
$filename = tempnam(sys_get_temp_dir(), 'sf-');
|
||||||
|
file_put_contents($filename, $content);
|
||||||
|
|
||||||
|
$this->files[] = $filename;
|
||||||
|
|
||||||
|
return $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return CommandTester
|
||||||
|
*/
|
||||||
|
protected function createCommandTester()
|
||||||
|
{
|
||||||
|
$application = new Application();
|
||||||
|
$application->add(new LintCommand());
|
||||||
|
$command = $application->find('lint:yaml');
|
||||||
|
|
||||||
|
return new CommandTester($command);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->files = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown()
|
||||||
|
{
|
||||||
|
foreach ($this->files as $file) {
|
||||||
|
if (file_exists($file)) {
|
||||||
|
unlink($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,12 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.5.9"
|
"php": ">=5.5.9"
|
||||||
},
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/console": "~2.8|~3.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"symfony/console": "For validating YAML files using the lint command"
|
||||||
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": { "Symfony\\Component\\Yaml\\": "" },
|
"psr-4": { "Symfony\\Component\\Yaml\\": "" },
|
||||||
"exclude-from-classmap": [
|
"exclude-from-classmap": [
|
||||||
|
Reference in New Issue
Block a user