Validate that a project does not require certain composer packages as dependencies. (Rough first draft).
<?php
/**
* This file contains a first rough draft of logic to validate that a project
* does not require certain composer packages as dependencies.
*
* It validates this by checking the project's `composer.lock` file.
*
* Usage:
* php composer-checker.php
*
* @TODO: Show which package causes violation
*/
namespace DealerDirect\QualityAssistance;
// @FIXME: Read $path from $argv
$path = '/path/to/project/composer.lock';
// @FIXME: Read default $blacklist from config file
// @FIXME: Read additional $blacklist from $argv
$blacklist = [
'barryvdh/laravel-debugbar',
'maximebf/debugbar',
'symfony/debug',
];
class ValidateComposerDependencies
{
////////////////////////////// CLASS PROPERTIES \\\\\\\\\\\\\\\\\\\\\\\\\\\\
/** @var array */
private $blacklist;
/** @var string */
private $contents;
//////////////////////////////// PUBLIC API \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
/**
* @param string $contents
* @param array $blacklist
*/
final public function __construct($contents, array $blacklist)
{
$this->contents = $contents;
$this->blacklist = $blacklist;
}
/**
* @return bool
*/
final public function validate()
{
$blacklist = $this->blacklist;
$contents = $this->contents;
$requirements = $this->retrievePackagesFromContents($contents);
return $this->validatePackagesAgainstBlacklisted($requirements, $blacklist);
}
////////////////////////////// UTILITY METHODS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\
/**
* @param string $contents
*
* @return array
*/
private function retrievePackagesFromContents($contents)
{
$packages = $this->retrieveRequirementsFromContents($contents);
return $this->retrievePackagesFromRequirements($packages);
}
/**
* @param string $contents
*
* @return array
*/
private function retrieveRequirementsFromContents($contents)
{
// @FIXME: Handle invalid JSON
$json = json_decode($contents, true);
// @FIXME: Handle missing 'packages' key
return $json['packages'];
}
/**
* @param array $requirements
*
* @return array
*/
private function retrievePackagesFromRequirements(array $requirements)
{
$packages = [];
array_walk($requirements, function (array $package) use (&$packages) {
if (array_key_exists('require', $package)) {
$name = $package['name'];
if (is_array($package['require'])) {
array_walk($package['require'], function ($version, $subPackage) use (&$packages, $name) {
if (array_key_exists($subPackage, $packages) === false) {
$packages[$subPackage] = [];
}
$packages[$subPackage][] = $name;
});
}
}
});
return $packages;
}
/**
* @param $requirements
* @param $blacklist
*
* @return bool
*/
private function validatePackagesAgainstBlacklisted(array $requirements, array $blacklist)
{
$diff = array_diff(
$blacklist,
array_keys($requirements)
);
return count($diff) === count($blacklist);
}
}
/**
* @param string $file
* @param array $blacklist
*
* @return int
*/
function run($file, array $blacklist)
{
if (is_readable($file) === false) {
throw new \UnexpectedValueException('Could not find a composer lock file.');
}
$contents = file_get_contents($file);
$validator = new ValidateComposerDependencies($contents, $blacklist);
$isValid = $validator->validate();
return (int)!$isValid;
}
$exitCode = run($path, $blacklist);
exit($exitCode);
/*EOF*/