Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc improvements #20

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ Vagrantfile
*.log
*.phar
/*.lock
build
build
.phpunit.result.cache
/.idea
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ Additional guard checks can be enabled in the top-level composer.json file:
"white-list:vendor/package-two",

"accept-license:MIT",
"accept-license:proprietary"
"accept-license:proprietary",

"package-guards:vendor/package-three:abandoned,description"
]
}
}
Expand All @@ -40,6 +42,7 @@ Additional guard checks can be enabled in the top-level composer.json file:
- `check-abandoned` enables abandoned packages checking
- `check-license` enables license checking (packages must provide license information)
- `accept-license:...` specifies which licenses should be accepted (if the setting omitted, any license incl. proprietary)
- `package-guards:<package>:...` specifies the guards per package (comma separated list, guards: dev-package-name, dev-package-type, license*, abandoned*, description*). * = only available if enabled via the check-... option

# Usage

Expand Down
30 changes: 20 additions & 10 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@
"role": "maintainer"
}],
"require": {
"php": "^7.0|^8.0",
"ext-json": "*",
"composer-plugin-api": "^1.0|^2.0"
"php": ">=7.0",
"ext-json": "*",
"composer-plugin-api": "^1.0|^2.0"
},
"require-dev": {
"ext-xdebug": "*",
"composer/composer": "^1.0|^2.0",
"phpunit/phpunit": "^6.5",
"infection/infection": "^0.9",
"rregeer/phpunit-coverage-check": "^0.1"
"ext-xdebug": "*",
"composer/composer": "^1.0|^2.0",
"phpunit/phpunit": "^9.5",
"infection/infection": "^0.26",
"rregeer/phpunit-coverage-check": "^0.3",
"squizlabs/php_codesniffer": "^3.7",
"phpcompatibility/php-compatibility": "^9.3",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.2"
},
"autoload": {
"psr-4": {
Expand All @@ -36,9 +39,16 @@
},
"scripts": {
"test": [
"./vendor/bin/phpunit --coverage-html ./build --coverage-clover ./build/phpunit.clover.xml",
"XDEBUG_MODE=coverage ./vendor/bin/phpunit --coverage-html ./build --coverage-clover ./build/phpunit.clover.xml",
"./vendor/bin/coverage-check ./build/phpunit.clover.xml 100",
"./vendor/bin/infection --only-covered --min-msi=100 --quiet"
"./vendor/bin/infection --min-msi=100 --quiet",
"./vendor/bin/phpcs --standard=PHPCompatibility --extensions=php --ignore=./vendor,./tests --runtime-set testVersion 7.0- ."
]
},
"config": {
"allow-plugins": {
"infection/extension-installer": true,
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}
18 changes: 6 additions & 12 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,26 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/6.3/phpunit.xsd"
backupGlobals="false"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
bootstrap="vendor/autoload.php"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
forceCoversAnnotation="true"
failOnRisky="true"
failOnWarning="true"
>
<testsuites>
<testsuite name="Tests">
<directory suffix="Test.php">./tests</directory>
<directory>./tests</directory>
</testsuite>
</testsuites>

<filter>
<whitelist>
<coverage>
<include>
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
</include>
</coverage>
</phpunit>
50 changes: 28 additions & 22 deletions src/Guard.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Composer\Composer;
use Composer\EventDispatcher\EventSubscriberInterface as EventSubscriberContract;
use Composer\Factory;
use Composer\IO\IOInterface;
use Composer\Package\CompletePackageInterface;
use Composer\Plugin\PluginInterface as ComposerPluginContract;
Expand All @@ -14,18 +13,13 @@
use Kalessil\Composer\Plugins\ProductionDependenciesGuard\Inspectors\ByPackageLicenseInspector;
use Kalessil\Composer\Plugins\ProductionDependenciesGuard\Inspectors\ByPackageNameInspector;
use Kalessil\Composer\Plugins\ProductionDependenciesGuard\Inspectors\ByPackageTypeInspector;
use Kalessil\Composer\Plugins\ProductionDependenciesGuard\Inspectors\StubInspector;
use Kalessil\Composer\Plugins\ProductionDependenciesGuard\Inspectors\InspectorInterface as InspectorContract;
use Kalessil\Composer\Plugins\ProductionDependenciesGuard\Suppliers\FromComposerLockSupplier;
use Kalessil\Composer\Plugins\ProductionDependenciesGuard\Suppliers\FromComposerManifestSupplier;
use Kalessil\Composer\Plugins\ProductionDependenciesGuard\Suppliers\SupplierInterface as SupplierContract;

final class Guard implements ComposerPluginContract, EventSubscriberContract
{
const CHECK_LOCK_FILE = 'check-lock-file';
const CHECK_DESCRIPTION = 'check-description';
const CHECK_LICENSE = 'check-license';
const CHECK_ABANDONED = 'check-abandoned';

/** @var bool */
private $useLockFile;
/** @var Composer */
Expand All @@ -36,26 +30,35 @@ final class Guard implements ComposerPluginContract, EventSubscriberContract
private $whitelist;
/** @var SupplierContract */
private $supplier;
/** @var array<string, array<string>> */
private $packageInspectors;

public function activate(Composer $composer, IOInterface $io)
{
$manifest = json_decode(file_get_contents(Factory::getComposerFile()), true);
$settings = $manifest['extra']['production-dependencies-guard'] ?? [];
$settings = new Settings();

$checkLicense = \in_array(self::CHECK_LICENSE, $settings, true);
$checkAbandoned = \in_array(self::CHECK_ABANDONED, $settings, true);
$checkDescription = \in_array(self::CHECK_DESCRIPTION, $settings, true);
$this->inspectors = [
'dev-package-name' => new ByPackageNameInspector(),
'dev-package-type' => new ByPackageTypeInspector(),
'license' => $checkLicense ? new ByPackageLicenseInspector($settings) : new StubInspector(),
'abandoned' => $checkAbandoned ? new ByPackageAbandonedInspector() : new StubInspector(),
'description-keywords' => $checkDescription ? new ByPackageDescriptionInspector() : new StubInspector(),
'dev-package-name' => new ByPackageNameInspector(),
'dev-package-type' => new ByPackageTypeInspector(),
];

if ($settings->checkLicense()) {
$this->inspectors['license'] = new ByPackageLicenseInspector($settings->acceptLicense());
}

if ($settings->checkAbandoned()) {
$this->inspectors['abandoned'] = new ByPackageAbandonedInspector();
}

if ($settings->checkDescription()) {
$this->inspectors['description'] = new ByPackageDescriptionInspector();
}

$this->packageInspectors = $settings->packageGuards();

$this->composer = $composer;
$this->whitelist = new Whitelist($settings);
$this->useLockFile = \in_array(self::CHECK_LOCK_FILE, $settings, true);
$this->whitelist = new Whitelist($settings->whiteList());
$this->useLockFile = $settings->checkLockFile();
$this->supplier = $this->useLockFile ? new FromComposerLockSupplier() : new FromComposerManifestSupplier();
}

Expand All @@ -75,8 +78,10 @@ private function check(SupplierContract $supplier, CompletePackageInterface... $
$packageId = sprintf('%s (via %s)', $packageName, implode(', ', $supplier->why($packageName)));
$violations[$packageId] = [];
foreach ($this->inspectors as $rule => $inspector) {
if (! $inspector->canUse($package)) {
$violations[$packageId] []= $rule;
if (! isset($this->packageInspectors[$packageName]) || in_array($rule, $this->packageInspectors[$packageName], true)) {
if (! $inspector->canUse($package)) {
$violations[$packageId][] = $rule;
}
}
}
}
Expand All @@ -93,7 +98,8 @@ private function check(SupplierContract $supplier, CompletePackageInterface... $
}

/** @return array<int, CompletePackageInterface> */
private function find(string... $packages): array {
private function find(string ...$packages): array {
/* @infection-ignore-all */
return array_filter(
array_filter(
$this->composer->getRepositoryManager()->getLocalRepository()->getPackages(),
Expand Down
11 changes: 11 additions & 0 deletions src/Inspectors/ByPackageDescriptionInspector.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@

final class ByPackageDescriptionInspector implements InspectorContract
{
/* ignore reason: see https://github.com/symfony/symfony/issues/31379 */
const IGNORE_PACKAGES = [
'symfony/debug',
'symfony/var-dumper',
'symfony/error-handler',
];

private function hasDebugKeyword(CompletePackageInterface $package): bool
{
$callback = static function (string $term): bool { return strtolower($term) === 'debug'; };
Expand All @@ -21,6 +28,10 @@ private function hasAnalyzerDescription(CompletePackageInterface $package): bool

public function canUse(CompletePackageInterface $package): bool
{
if (true === in_array(strtolower($package->getName()), self::IGNORE_PACKAGES, true)) {
return true;
}

return ! $this->hasDebugKeyword($package) && ! $this->hasAnalyzerDescription($package);
}
}
26 changes: 14 additions & 12 deletions src/Inspectors/ByPackageLicenseInspector.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,28 @@

final class ByPackageLicenseInspector implements InspectorContract
{
/** @var array<int,string> */
/** @var array<string> */
private $allowed;

public function __construct(array $settings)
/**
* @param array<string> $allowed
*/
public function __construct(array $allowed)
{
$this->allowed = array_map(
static function (string $setting): string { return str_replace('accept-license:', '', $setting); },
array_filter(
array_map('strtolower', array_map('trim', $settings)),
static function (string $setting): bool { return strncmp($setting, 'accept-license:', 15) === 0; }
)
);
$this->allowed = $allowed;
}

public function canUse(CompletePackageInterface $package): bool
{
$hasLicense = ! empty($package->getLicense());
$licenses = $package->getLicense();
$hasLicense = ! empty($licenses);
if ($hasLicense && $this->allowed !== []) {
$unfit = array_diff(array_map('strtolower', array_map('trim', (array) $package->getLicense())), $this->allowed);
return $unfit === [];
return array_intersect(
array_map(static function (string $license): string {
return strtolower(trim($license));
}, $licenses),
$this->allowed
) !== [];
}

return $hasLicense;
Expand Down
2 changes: 1 addition & 1 deletion src/Inspectors/ByPackageNameInspector.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ final class ByPackageNameInspector implements InspectorContract
'humbug/humbug',
'infection/infection',
'mockery/mockery',
'mikey179/vfsStream',
'mikey179/vfsstream',
'phing/phing',

/* SCA and code quality tools */
Expand Down
14 changes: 0 additions & 14 deletions src/Inspectors/StubInspector.php

This file was deleted.

Loading