You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

319 lines
9.0 KiB
PHP

<?php
namespace Pds\Skeleton;
class ComplianceValidator
{
const STATE_OPTIONAL_NOT_PRESENT = 1;
const STATE_CORRECT_PRESENT = 2;
const STATE_RECOMMENDED_NOT_PRESENT = 3;
const STATE_INCORRECT_PRESENT = 4;
protected $files = null;
public function execute($root = null)
{
$lines = $this->getFiles($root);
$results = $this->validate($lines);
$this->outputResults($results);
return true;
}
public function validate($lines)
{
$complianceTests = [
"Command-line executables" => $this->checkBin($lines),
"Configuration files" => $this->checkConfig($lines),
"Documentation files" => $this->checkDocs($lines),
"Web server files" => $this->checkPublic($lines),
"Other resource files" => $this->checkResources($lines),
"PHP source code" => $this->checkSrc($lines),
"Test code" => $this->checkTests($lines),
"Log of changes between releases" => $this->checkChangelog($lines),
"Guidelines for contributors" => $this->checkContributing($lines),
"Licensing information" => $this->checkLicense($lines),
"Information about the package itself" => $this->checkReadme($lines),
];
$results = [];
foreach ($complianceTests as $label => $complianceResult) {
$state = $complianceResult[0];
$expected = $complianceResult[1];
$actual = $complianceResult[2];
$results[$expected] = [
'label' => $label,
'state' => $state,
'expected' => $expected,
'actual' => $actual,
];
}
return $results;
}
/**
* Get list of files and directories previously set, or generate from parent project.
*/
public function getFiles($root = null)
{
$root = $root ?: __DIR__ . '/../../../../';
$root = realpath($root);
if ($this->files == null) {
$files = scandir($root);
foreach ($files as $i => $file) {
if (is_dir("$root/$file")) {
$files[$i] .= "/";
}
}
$this->files = $files;
}
return $this->files;
}
public function outputResults($results)
{
foreach ($results as $result) {
$this->outputResultLine($result['label'], $result['state'], $result['expected'], $result['actual']);
}
}
protected function outputResultLine($label, $complianceState, $expected, $actual)
{
$messages = [
self::STATE_OPTIONAL_NOT_PRESENT => "Optional {$expected} not present",
self::STATE_CORRECT_PRESENT => "Correct {$actual} present",
self::STATE_INCORRECT_PRESENT => "Incorrect {$actual} present",
self::STATE_RECOMMENDED_NOT_PRESENT => "Recommended {$expected} not present",
];
echo $this->colorConsoleText("- " . $label . ": " . $messages[$complianceState], $complianceState) . PHP_EOL;
}
protected function colorConsoleText($text, $complianceState)
{
$colors = [
self::STATE_OPTIONAL_NOT_PRESENT => "\033[43;30m",
self::STATE_CORRECT_PRESENT => "\033[42;30m",
self::STATE_INCORRECT_PRESENT => "\033[41m",
self::STATE_RECOMMENDED_NOT_PRESENT => "\033[41m",
];
if (!array_key_exists($complianceState, $colors)) {
return $text;
}
return $colors[$complianceState] . " " . $text . " \033[0m";
}
protected function checkDir($lines, $pass, array $fail)
{
foreach ($lines as $line) {
$line = trim($line);
if ($line == $pass) {
return [self::STATE_CORRECT_PRESENT, $pass, $line];
}
if (in_array($line, $fail)) {
return [self::STATE_INCORRECT_PRESENT, $pass, $line];
}
}
return [self::STATE_OPTIONAL_NOT_PRESENT, $pass, null];
}
protected function checkFile($lines, $pass, array $fail, $state = self::STATE_OPTIONAL_NOT_PRESENT)
{
foreach ($lines as $line) {
$line = trim($line);
if (preg_match("/^{$pass}(\.[a-z]+)?$/", $line)) {
return [self::STATE_CORRECT_PRESENT, $pass, $line];
}
foreach ($fail as $regex) {
if (preg_match($regex, $line)) {
return [self::STATE_INCORRECT_PRESENT, $pass, $line];
}
}
}
return [$state, $pass, null];
}
protected function checkChangelog($lines)
{
return $this->checkFile($lines, 'CHANGELOG', [
'/^.*CHANGLOG.*$/i',
'/^.*CAHNGELOG.*$/i',
'/^WHATSNEW(\.[a-z]+)?$/i',
'/^RELEASE((_|-)?NOTES)?(\.[a-z]+)?$/i',
'/^RELEASES(\.[a-z]+)?$/i',
'/^CHANGES(\.[a-z]+)?$/i',
'/^CHANGE(\.[a-z]+)?$/i',
'/^HISTORY(\.[a-z]+)?$/i',
]);
}
protected function checkContributing($lines)
{
return $this->checkFile($lines, 'CONTRIBUTING', [
'/^DEVELOPMENT(\.[a-z]+)?$/i',
'/^README\.CONTRIBUTING(\.[a-z]+)?$/i',
'/^DEVELOPMENT_README(\.[a-z]+)?$/i',
'/^CONTRIBUTE(\.[a-z]+)?$/i',
'/^HACKING(\.[a-z]+)?$/i',
]);
}
protected function checkLicense($lines)
{
return $this->checkFile(
$lines,
'LICENSE',
[
'/^.*EULA.*$/i',
'/^.*(GPL|BSD).*$/i',
'/^([A-Z-]+)?LI(N)?(S|C)(E|A)N(S|C)(E|A)(_[A-Z_]+)?(\.[a-z]+)?$/i',
'/^COPY(I)?NG(\.[a-z]+)?$/i',
'/^COPYRIGHT(\.[a-z]+)?$/i',
],
self::STATE_RECOMMENDED_NOT_PRESENT
);
}
protected function checkReadme($lines)
{
return $this->checkFile($lines, 'README', [
'/^USAGE(\.[a-z]+)?$/i',
'/^SUMMARY(\.[a-z]+)?$/i',
'/^DESCRIPTION(\.[a-z]+)?$/i',
'/^IMPORTANT(\.[a-z]+)?$/i',
'/^NOTICE(\.[a-z]+)?$/i',
'/^GETTING(_|-)STARTED(\.[a-z]+)?$/i',
]);
}
protected function checkBin($lines)
{
return $this->checkDir($lines, 'bin/', [
'cli/',
'scripts/',
'console/',
'shell/',
'script/',
]);
}
protected function checkConfig($lines)
{
return $this->checkDir($lines, 'config/', [
'etc/',
'settings/',
'configuration/',
'configs/',
'_config/',
'conf/',
]);
}
protected function checkDocs($lines)
{
return $this->checkDir($lines, 'docs/', [
'manual/',
'documentation/',
'usage/',
'doc/',
'guide/',
'phpdoc/',
'apidocs/',
'apidoc/',
'api-reference/',
'user_guide/',
'manuals/',
'phpdocs/',
]);
}
protected function checkPublic($lines)
{
return $this->checkDir($lines, 'public/', [
'assets/',
'static/',
'html/',
'httpdocs/',
'media/',
'docroot/',
'css/',
'fonts/',
'styles/',
'style/',
'js/',
'javascript/',
'images/',
'site/',
'mysite/',
'img/',
'web/',
'pub/',
'webroot/',
'www/',
'htdocs/',
'asset/',
'public_html/',
'publish/',
'pages/',
'javascripts/',
'icons/',
'imgs/',
'wwwroot/',
'font/',
]);
}
protected function checkSrc($lines)
{
return $this->checkDir($lines, 'src/', [
'exception/',
'exceptions/',
'src-files/',
'traits/',
'interfaces/',
'common/',
'sources/',
'php/',
'inc/',
'libraries/',
'autoloads/',
'autoload/',
'source/',
'includes/',
'include/',
'lib/',
'libs/',
'library/',
'code/',
'classes/',
'func/',
'src-dev/',
]);
}
protected function checkTests($lines)
{
return $this->checkDir($lines, 'tests/', [
'test/',
'unit-tests/',
'phpunit/',
'testing/',
'unittest/',
'unit_tests/',
'unit_test/',
'phpunit-tests/',
]);
}
protected function checkResources($lines)
{
return $this->checkDir($lines, 'resources/', [
'Resources/',
'res/',
'resource/',
'Resource/',
'ressources/',
'Ressources/',
]);
}
}