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

Fix a bug with a disjunctive license #192

Merged
merged 11 commits into from
Sep 20, 2023
5 changes: 1 addition & 4 deletions src/Event/PackageWithViolatingLicense.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@

final class PackageWithViolatingLicense implements Event
{
/**
* @param non-empty-string $license
*/
public function __construct(public readonly Package $package, public readonly string $license)
public function __construct(public readonly Package $package)
{
}
}
14 changes: 6 additions & 8 deletions src/LicenseChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -167,21 +167,19 @@ protected function execute(InputInterface $input, OutputInterface $output): int
continue;
}

if ($package->licenses === []) {
if ($package->licenses->isEmpty()) {
$violation = true;
$this->dispatcher->dispatch(new UnlicensedPackageNotExplicitlyAllowed($package));

continue;
}

foreach ($package->licenses as $license) {
if ($config->allowsLicense($license)) {
continue;
}

$violation = true;
$this->dispatcher->dispatch(new PackageWithViolatingLicense($package, $license));
if ($config->allowsLicenseOfPackage($package)) {
continue;
}

$violation = true;
$this->dispatcher->dispatch(new PackageWithViolatingLicense($package));
}

if ($violation) {
Expand Down
15 changes: 13 additions & 2 deletions src/LicenseConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@ public function __construct(
) {
}

public function allowsLicense(string $license): bool
public function allowsLicenseOfPackage(Package $package): bool
{
return \in_array($license, $this->allowedLicenses, true);
foreach ($package->licenses as $license) {
if ($this->allowsLicense($license)) {
return true;
}
}

return false;
}

public function allowsPackage(string $package): bool
Expand All @@ -32,4 +38,9 @@ public function allowsPackage(string $package): bool

return false;
}

private function allowsLicense(string $license): bool
{
return \in_array($license, $this->allowedLicenses, true);
}
}
36 changes: 36 additions & 0 deletions src/Licenses.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Lendable\ComposerLicenseChecker;

use ArrayIterator;

/**
* @implements \IteratorAggregate<int, string>
*/
final class Licenses implements \IteratorAggregate
{
/**
* @param list<non-empty-string> $licenses
*/
public function __construct(
private readonly array $licenses,
) {
}

public function toString(): string
{
return \implode(', ', $this->licenses);
}

public function isEmpty(): bool
ivastly marked this conversation as resolved.
Show resolved Hide resolved
{
return $this->licenses === [];
}

public function getIterator(): \Traversable
{
return new ArrayIterator($this->licenses);
ivastly marked this conversation as resolved.
Show resolved Hide resolved
}
}
5 changes: 1 addition & 4 deletions src/Output/Display.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@ public function onOutcomeFailure(): void;

public function onOutcomeSuccess(): void;

/**
* @param non-empty-string $license
*/
public function onPackageWithViolatingLicense(Package $package, string $license): void;
public function onPackageWithViolatingLicense(Package $package): void;

public function onUnlicensedPackageNotExplicitlyAllowed(Package $package): void;

Expand Down
2 changes: 1 addition & 1 deletion src/Output/DisplayOutputSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ private function onOutcomeSuccess(OutcomeSuccess $event): void

private function onPackageWithViolatingLicense(PackageWithViolatingLicense $event): void
{
$this->display->onPackageWithViolatingLicense($event->package, $event->license);
$this->display->onPackageWithViolatingLicense($event->package);
}

private function onUnlicensedPackageNotExplicitlyAllowed(UnlicensedPackageNotExplicitlyAllowed $event): void
Expand Down
6 changes: 3 additions & 3 deletions src/Output/HumanReadableDisplay.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ public function onOutcomeSuccess(): void
$this->style->success('All dependencies have allowed licenses.');
}

public function onPackageWithViolatingLicense(Package $package, string $license): void
public function onPackageWithViolatingLicense(Package $package): void
{
$this->style->error(
\sprintf(
'Dependency "%s" has license "%s" which is not in the allowed list.',
'Dependency "%s" is licensed under "%s" which is not in the allowed list.',
ivastly marked this conversation as resolved.
Show resolved Hide resolved
$package->name->toString(),
$license,
$package->licenses->toString(),
),
);
}
Expand Down
6 changes: 4 additions & 2 deletions src/Output/JsonDisplay.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@ public function onFatalError(string $message): void
);
}

public function onPackageWithViolatingLicense(Package $package, string $license): void
public function onPackageWithViolatingLicense(Package $package): void
{
$this->violations[$license][] = $package->name->toString();
/** @var non-empty-string $licences */
$licences = $package->licenses->toString();
$this->violations[$licences][] = $package->name->toString();
}

public function onUnlicensedPackageNotExplicitlyAllowed(Package $package): void
Expand Down
5 changes: 1 addition & 4 deletions src/Package.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@

final class Package
{
/**
* @param list<non-empty-string> $licenses
*/
public function __construct(
public readonly PackageName $name,
public readonly array $licenses,
public readonly Licenses $licenses,
) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Lendable\ComposerLicenseChecker\PackagesProvider;

use Lendable\ComposerLicenseChecker\Exception\FailedProvidingPackages;
use Lendable\ComposerLicenseChecker\Licenses;
use Lendable\ComposerLicenseChecker\Package;
use Lendable\ComposerLicenseChecker\PackageName;
use Lendable\ComposerLicenseChecker\Packages;
Expand Down Expand Up @@ -84,11 +85,10 @@ static function (mixed $package) use ($skipPackages): ?Package {
throw FailedProvidingPackages::withReason('Key "license" is not a list');
}

/** @var list<non-empty-string> $licenses */
/** @var PackageData $package */
return new Package(
new PackageName($package['name']),
$licenses,
new Licenses($licenses),
);
},
$dependencies,
Expand Down
3 changes: 2 additions & 1 deletion src/PackagesProvider/ComposerLicensesPackagesProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Lendable\ComposerLicenseChecker\ComposerRunner;
use Lendable\ComposerLicenseChecker\Exception\FailedProvidingPackages;
use Lendable\ComposerLicenseChecker\Exception\FailedRunningComposer;
use Lendable\ComposerLicenseChecker\Licenses;
use Lendable\ComposerLicenseChecker\Package;
use Lendable\ComposerLicenseChecker\PackageName;
use Lendable\ComposerLicenseChecker\Packages;
Expand Down Expand Up @@ -45,7 +46,7 @@ public function provide(string $projectPath, bool $ignoreDev): Packages

return new Packages(
\array_map(
static fn (string $name, array $package): Package => new Package(new PackageName($name), $package['license']),
static fn (string $name, array $package): Package => new Package(new PackageName($name), new Licenses($package['license'])),
\array_keys($data['dependencies']),
$data['dependencies'],
),
Expand Down
1 change: 0 additions & 1 deletion tests/e2e/LicenseCheckerCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ public function test_report_not_allowed_licenses(): void
->foundLicensingIssues(
[
'lendable/apache' => 'Apache-2.0',
'lendable/bsd3_mit' => 'BSD-3-Clause',
'package/bsd3' => 'BSD-3-Clause',
],
);
Expand Down
10 changes: 5 additions & 5 deletions tests/e2e/Output/DisplayOutputSubscriberTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Lendable\ComposerLicenseChecker\Event\Started;
use Lendable\ComposerLicenseChecker\Event\TraceInformation;
use Lendable\ComposerLicenseChecker\Event\UnlicensedPackageNotExplicitlyAllowed;
use Lendable\ComposerLicenseChecker\Licenses;
use Lendable\ComposerLicenseChecker\Output\Display;
use Lendable\ComposerLicenseChecker\Output\DisplayOutputSubscriber;
use Lendable\ComposerLicenseChecker\Package;
Expand Down Expand Up @@ -75,20 +76,19 @@ public function test_delegates_on_outcome_success(): void

public function test_delegates_on_package_with_violating_license(): void
{
$package = new Package(new PackageName('foo/bar'), ['MIT']);
$license = 'MIT';
$package = new Package(new PackageName('foo/bar'), new Licenses(['MIT']));

$this->display
->expects(self::once())
->method('onPackageWithViolatingLicense')
->with($package, $license);
->with($package);

$this->dispatcher->dispatch(new PackageWithViolatingLicense($package, $license));
$this->dispatcher->dispatch(new PackageWithViolatingLicense($package));
}

public function test_delegates_on_unlicensed_package_not_explicitly_allowed(): void
{
$package = new Package(new PackageName('foo/bar'), ['MIT']);
$package = new Package(new PackageName('foo/bar'), new Licenses(['MIT']));

$this->display
->expects(self::once())
Expand Down
14 changes: 6 additions & 8 deletions tests/support/CommandTesterAsserter.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,12 @@ public function foundLicensingIssues(array $issues): self
}

if (\is_array($license)) {
foreach ($license as $element) {
$expectedOutput[] = \sprintf(
' [ERROR] Dependency "%s" has license "%s" which is not in the allowed list.',
$package,
$element,
);
$expectedOutput[] = '';
}
$expectedOutput[] = \sprintf(
' [ERROR] Dependency "%s" is licensed under "%s" which is not in the allowed list.',
$package,
\implode(', ', $license),
);
$expectedOutput[] = '';
} else {
$expectedOutput[] = \sprintf(
' [ERROR] Dependency "%s" does not have a license and is not explicitly allowed.',
Expand Down
20 changes: 7 additions & 13 deletions tests/support/PackageAsserter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Tests\Support\Lendable\ComposerLicenseChecker;

use Lendable\ComposerLicenseChecker\Licenses;
use Lendable\ComposerLicenseChecker\Package;
use Lendable\ComposerLicenseChecker\PackageName;
use PHPUnit\Framework\Assert;
Expand All @@ -30,32 +31,25 @@ public function hasName(string|PackageName $name): self
return $this;
}

public function hasLicense(string $license): self
public function equals(Package $package): self
{
Assert::assertContains($license, $this->package->licenses);
$this->hasName($package->name);
$this->hasExactLicenses($package->licenses);

return $this;
}

/**
* @param list<string> $licenses
*/
public function hasExactLicenses(array $licenses): self
private function hasExactLicenses(Licenses $licenses): void
{
Assert::assertSameSize($licenses, $this->package->licenses);

foreach ($licenses as $license) {
$this->hasLicense($license);
}

return $this;
}

public function equals(Package $package): self
private function hasLicense(string $license): void
{
$this->hasName($package->name);
$this->hasExactLicenses($package->licenses);

return $this;
Assert::assertContains($license, \explode(', ', $this->package->licenses->toString()));
}
}
49 changes: 10 additions & 39 deletions tests/support/PackagesAsserter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@

namespace Tests\Support\Lendable\ComposerLicenseChecker;

use Lendable\ComposerLicenseChecker\Package;
use Lendable\ComposerLicenseChecker\Packages;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\AssertionFailedError;

final class PackagesAsserter
{
Expand All @@ -20,43 +18,6 @@ public static function assertThat(Packages $packages): self
return new self($packages);
}

public function hasCount(int $count): self
{
Assert::assertCount($count, $this->packages);

return $this;
}

/**
* @param \Countable|array<mixed> $countable
*/
public function sameSize(\Countable|array $countable): self
{
Assert::assertSameSize($countable, $this->packages);

return $this;
}

public function containsPackage(Package $package): self
{
foreach ($this->packages as $existing) {
try {
PackageAsserter::assertThat($existing)->equals($package);

return $this;
} catch (AssertionFailedError) {
}
}

Assert::fail(
\sprintf(
'Failed to find a package with name "%s" and licenses [%s].',
$package->name->toString(),
\implode(', ', $package->licenses),
),
);
}

public function equals(Packages $packages): self
{
$this->sameSize($packages);
Expand All @@ -71,4 +32,14 @@ public function equals(Packages $packages): self

return $this;
}

/**
* @param \Countable|array<mixed> $countable
*/
private function sameSize(\Countable|array $countable): self
{
Assert::assertSameSize($countable, $this->packages);

return $this;
}
}
Loading