Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
211 changes: 122 additions & 89 deletions validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@

final class Validate extends Command
{
/**
* @var Parser
*/
private $parser;

public function __construct()
Expand All @@ -31,11 +34,27 @@ public function __construct()
$this->parser = new Parser();
}

public function configure()
{
$this->addArgument(
'paths',
\Symfony\Component\Console\Input\InputArgument::IS_ARRAY,
'paths containing issue definitions'
);

}

protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);

$paths = $input->getArgument('paths');

//the current directory is used by default
$paths[] = __DIR__;

$advisoryFilter = function (SplFileInfo $file) {

if ($file->isFile() && __DIR__ === $file->getPath()) {
return false; // We want to skip root files
}
Expand All @@ -60,132 +79,146 @@ protected function execute(InputInterface $input, OutputInterface $output)

$messages = array();

/* @var $dir \SplFileInfo[] */
$dir = new \RecursiveIteratorIterator(new RecursiveCallbackFilterIterator(new \RecursiveDirectoryIterator(__DIR__), $advisoryFilter));
$fileCount = 0;
$dirs = array();

foreach ($paths as $path) {
/* @var $dir \SplFileInfo[] */
$directory = new \RecursiveIteratorIterator(new RecursiveCallbackFilterIterator(new \RecursiveDirectoryIterator($path), $advisoryFilter));
$fileCount += count(iterator_to_array($directory));
$dirs[] = $directory;
}

$progress = new ProgressBar($io, count(iterator_to_array($dir)));
$progress = new ProgressBar($io, $fileCount);
$progress->start();

foreach ($dir as $file) {
if (!$file->isFile()) {
$progress->advance();
foreach ($dirs as $dir) {

foreach ($dir as $file) {

if (!$file->isFile()) {
$progress->advance();

continue;
}
continue;
}

$path = str_replace(__DIR__.DIRECTORY_SEPARATOR, '', $file->getPathname());
$path = str_replace(__DIR__.DIRECTORY_SEPARATOR, '', $file->getPathname());

if ('yaml' !== $file->getExtension()) {
$messages[$path][] = 'The file extension should be ".yaml".';
continue;
}
if ('yaml' !== $file->getExtension()) {
$messages[$path][] = 'The file extension should be ".yaml".';
continue;
}

try {
$data = $this->parser->parse(file_get_contents($file));
try {
$data = $this->parser->parse(file_get_contents($file));

// validate first level keys
if ($keys = array_diff(array_keys($data), array('reference', 'branches', 'title', 'link', 'cve'))) {
foreach ($keys as $key) {
$messages[$path][] = sprintf('Key "%s" is not supported.', $key);
// validate first level keys
if ($keys = array_diff(array_keys($data), array('reference', 'branches', 'title', 'link', 'cve'))) {
foreach ($keys as $key) {
$messages[$path][] = sprintf('Key "%s" is not supported.', $key);
}
}
}

// required keys
foreach (array('reference', 'title', 'link', 'branches') as $key) {
if (!isset($data[$key])) {
$messages[$path][] = sprintf('Key "%s" is required.', $key);
// required keys
foreach (array('reference', 'title', 'link', 'branches') as $key) {
if (!isset($data[$key])) {
$messages[$path][] = sprintf('Key "%s" is required.', $key);
}
}
}

if (isset($data['reference'])) {
if (0 !== strpos($data['reference'], 'composer://')) {
$messages[$path][] = 'Reference must start with "composer://"';
} else {
$composerPackage = substr($data['reference'], 11);
if (isset($data['reference'])) {
if (0 !== strpos($data['reference'], 'composer://')) {
$messages[$path][] = 'Reference must start with "composer://"';
} else {
$composerPackage = substr($data['reference'], 11);

if (str_replace(DIRECTORY_SEPARATOR, '/', dirname($path)) !== $composerPackage) {
$messages[$path][] = 'Reference composer package must match the folder name';
}
//check if the folder containing the issue ends with the referenced package name
if ((substr($file->getPath(), -1) == $composerPackage)) {
$messages[$path][] = 'Reference composer package must match the folder name';
}


$packagistUrl = sprintf('https://packagist.org/packages/%s.json', $composerPackage);
$packagistUrl = sprintf('https://packagist.org/packages/%s.json', $composerPackage);

if(404 == explode(' ', get_headers($packagistUrl)[0], 3)[1]) {
$messages[$path][] = sprintf('Invalid composer package');
if(404 == explode(' ', get_headers($packagistUrl)[0], 3)[1]) {
$messages[$path][] = sprintf('Invalid composer package');
}
}
}
}

if (!isset($data['branches'])) {
$progress->advance();
if (!isset($data['branches'])) {
$progress->advance();

continue; // Don't validate branches when not set to avoid notices
}
continue; // Don't validate branches when not set to avoid notices
}

if (!is_array($data['branches'])) {
$messages[$path][] = '"branches" must be an array.';
$progress->advance();
if (!is_array($data['branches'])) {
$messages[$path][] = '"branches" must be an array.';
$progress->advance();

continue; // Don't validate branches when not set to avoid notices
}
continue; // Don't validate branches when not set to avoid notices
}

$upperBoundWithoutLowerBound = null;
$upperBoundWithoutLowerBound = null;

foreach ($data['branches'] as $name => $branch) {
if (!preg_match('/^([\d\.\-]+(\.x)?(\-dev)?|master)$/', $name)) {
$messages[$path][] = sprintf('Invalid branch name "%s".', $name);
}
foreach ($data['branches'] as $name => $branch) {
if (!preg_match('/^([\d\.\-]+(\.x)?(\-dev)?|master)$/', $name)) {
$messages[$path][] = sprintf('Invalid branch name "%s".', $name);
}

if ($keys = array_diff(array_keys($branch), array('time', 'versions'))) {
foreach ($keys as $key) {
$messages[$path][] = sprintf('Key "%s" is not supported for branch "%s".', $key, $name);
if ($keys = array_diff(array_keys($branch), array('time', 'versions'))) {
foreach ($keys as $key) {
$messages[$path][] = sprintf('Key "%s" is not supported for branch "%s".', $key, $name);
}
}
}

if (!isset($branch['time'])) {
$messages[$path][] = sprintf('Key "time" is required for branch "%s".', $name);
}
if (!isset($branch['time'])) {
$messages[$path][] = sprintf('Key "time" is required for branch "%s".', $name);
}

if (!isset($branch['versions'])) {
$messages[$path][] = sprintf('Key "versions" is required for branch "%s".', $name);
} elseif (!is_array($branch['versions'])) {
$messages[$path][] = sprintf('"versions" must be an array for branch "%s".', $name);
} else {
$upperBound = null;
$hasMin = false;
foreach ($branch['versions'] as $version) {
if (!$isAcceptableVersionConstraint($version)) {
$messages[$path][] = sprintf('Version constraint "%s" is not in an acceptable format.', $version);
if (!isset($branch['versions'])) {
$messages[$path][] = sprintf('Key "versions" is required for branch "%s".', $name);
} elseif (!is_array($branch['versions'])) {
$messages[$path][] = sprintf('"versions" must be an array for branch "%s".', $name);
} else {
$upperBound = null;
$hasMin = false;
foreach ($branch['versions'] as $version) {
if (!$isAcceptableVersionConstraint($version)) {
$messages[$path][] = sprintf('Version constraint "%s" is not in an acceptable format.', $version);
}

if ('<' === substr($version, 0, 1)) {
$upperBound = $version;
continue;
}
if ('>' === substr($version, 0, 1)) {
$hasMin = true;
}
}

if ('<' === substr($version, 0, 1)) {
$upperBound = $version;
continue;
}
if ('>' === substr($version, 0, 1)) {
$hasMin = true;
if (null === $upperBound) {
$messages[$path][] = sprintf('"versions" must have an upper bound for branch "%s".', $name);
}
}

if (null === $upperBound) {
$messages[$path][] = sprintf('"versions" must have an upper bound for branch "%s".', $name);
}

if (!$hasMin && null === $upperBoundWithoutLowerBound) {
$upperBoundWithoutLowerBound = $upperBound;
}
if (!$hasMin && null === $upperBoundWithoutLowerBound) {
$upperBoundWithoutLowerBound = $upperBound;
}

// Branches can omit the lower bound only if their upper bound is the same than for other branches without lower bound.
if (!$hasMin && $upperBoundWithoutLowerBound !== $upperBound) {
$messages[$path][] = sprintf('"versions" must have a lower bound for branch "%s" to avoid overlapping lower branches.', $name);
// Branches can omit the lower bound only if their upper bound is the same than for other branches without lower bound.
if (!$hasMin && $upperBoundWithoutLowerBound !== $upperBound) {
$messages[$path][] = sprintf('"versions" must have a lower bound for branch "%s" to avoid overlapping lower branches.', $name);
}
}
}
} catch (ParseException $e) {
$messages[$path][] = sprintf('YAML is not valid (%s).', $e->getMessage());
}
} catch (ParseException $e) {
$messages[$path][] = sprintf('YAML is not valid (%s).', $e->getMessage());
}

$progress->advance();
$progress->advance();
}
}


$progress->finish();

Expand Down