Skip to content

Commit 4fd2741

Browse files
authored
Use JSON output for composer licenses command (#37)
* Use JSON output for composer licenses command Use a well-known format instead of manually parsing text to extract the required information.
1 parent 02bb3c4 commit 4fd2741

10 files changed

+215
-228
lines changed

composer-license-checker

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use Dominikb\ComposerLicenseChecker\LicenseLookup;
88
use Dominikb\ComposerLicenseChecker\ReportCommand;
99
use Symfony\Component\Console\Output\ConsoleOutput;
1010
use Dominikb\ComposerLicenseChecker\DependencyLoader;
11+
use Dominikb\ComposerLicenseChecker\JSONDependencyParser;
1112
use Dominikb\ComposerLicenseChecker\ConstraintViolationDetector;
1213

1314
function includeIfExists(string $file): bool
@@ -35,11 +36,11 @@ $licenceLookUp = new LicenseLookup($httpClient);
3536
$checkCommand = new CheckCommand;
3637
$checkCommand->setLicenseLookup($licenceLookUp);
3738
$checkCommand->setLicenseConstraintHandler(new ConstraintViolationDetector);
38-
$checkCommand->setDependencyLoader(new DependencyLoader);
39+
$checkCommand->setDependencyLoader(new DependencyLoader(new JSONDependencyParser()));
3940

4041
$reportCommand = new ReportCommand;
4142
$reportCommand->setLicenseLookup($licenceLookUp);
42-
$reportCommand->setDependencyLoader(new DependencyLoader);
43+
$reportCommand->setDependencyLoader(new DependencyLoader(new JSONDependencyParser()));
4344

4445
$application = new Application('composer-license-checker', '2.2.0');
4546

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
],
1919
"require": {
2020
"php": "^7.3|^8.0",
21+
"ext-json": "*",
2122
"composer/composer": "^1.10.27|~2.2.22|^2.6.4",
2223
"guzzlehttp/guzzle": "^6.3|^7.2",
2324
"psr/simple-cache": "^1.0|^2.0|^3.0",

src/Contracts/DependencyParser.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Dominikb\ComposerLicenseChecker\Contracts;
4+
5+
use Dominikb\ComposerLicenseChecker\Dependency;
6+
7+
interface DependencyParser
8+
{
9+
/**
10+
* @return Dependency[]
11+
*/
12+
public function parse(string $dependencyOutput): array;
13+
}

src/DependencyLoader.php

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,42 +5,32 @@
55
namespace Dominikb\ComposerLicenseChecker;
66

77
use Dominikb\ComposerLicenseChecker\Contracts\DependencyLoader as DependencyLoaderContract;
8+
use Dominikb\ComposerLicenseChecker\Contracts\DependencyParser;
89

910
class DependencyLoader implements DependencyLoaderContract
1011
{
11-
const LINES_BEFORE_DEPENDENCY_VERSIONS = 6;
12+
/**
13+
* @var DependencyParser
14+
*/
15+
private $dependencyParser;
1216

13-
public function loadDependencies(string $composer, string $project): array
17+
public function __construct(DependencyParser $dependencyParser)
1418
{
15-
$commandOutput = $this->runComposerLicenseCommand($composer, $project);
16-
17-
$cleanOutput = $this->stripHeadersFromOutput($commandOutput);
18-
19-
return $this->splitColumnsIntoDependencies($cleanOutput);
19+
$this->dependencyParser = $dependencyParser;
2020
}
2121

22-
private function runComposerLicenseCommand(string $composer, string $project): array
22+
public function loadDependencies(string $composer, string $project): array
2323
{
24-
$command = sprintf('%s licenses -d %s', $composer, $project);
25-
26-
return $this->exec($command);
27-
}
24+
$commandOutput = $this->runComposerLicenseCommand($composer, $project);
2825

29-
private function stripHeadersFromOutput(array $output): array
30-
{
31-
return array_slice($output, self::LINES_BEFORE_DEPENDENCY_VERSIONS);
26+
return $this->dependencyParser->parse(join(PHP_EOL, $commandOutput));
3227
}
3328

34-
private function splitColumnsIntoDependencies(array $output): array
29+
private function runComposerLicenseCommand(string $composer, string $project, string $format = 'json'): array
3530
{
36-
$parser = new DependencyParser;
37-
38-
$mappedToObjects = [];
39-
foreach ($output as $dependency) {
40-
$mappedToObjects[] = $parser->parse($dependency);
41-
}
31+
$command = sprintf('%s licenses -f %s -d %s', $composer, $format, $project);
4232

43-
return $mappedToObjects;
33+
return $this->exec($command);
4434
}
4535

4636
protected function exec(string $command)

src/DependencyParser.php

Lines changed: 0 additions & 74 deletions
This file was deleted.

src/JSONDependencyParser.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Dominikb\ComposerLicenseChecker;
6+
7+
use Dominikb\ComposerLicenseChecker\Contracts\DependencyParser as DependencyParserContract;
8+
9+
class JSONDependencyParser implements DependencyParserContract
10+
{
11+
public function parse(string $dependencyOutput): array
12+
{
13+
$dependencyOutput = json_decode($dependencyOutput, true);
14+
15+
$parsed = [];
16+
foreach ($dependencyOutput['dependencies'] as $name => $info) {
17+
$parsed[] = (new Dependency)
18+
->setName($name)
19+
->setVersion($info['version'])
20+
->setLicenses($info['license']);
21+
}
22+
23+
return $parsed;
24+
}
25+
}

src/ReportCommand.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,9 @@ protected function outputFormattedLicenses(OutputInterface $output, InputInterfa
191191

192192
for ($i = 0; $i < $columnWidth; $i++) {
193193
$licenseTable->addRow([
194-
'CAN' => $can[$i],
194+
'CAN' => $can[$i],
195195
'CANNOT' => $cannot[$i],
196-
'MUST' => $must[$i],
196+
'MUST' => $must[$i],
197197
]);
198198
}
199199
$licenseTable->render();

tests/DependencyLoaderTest.php

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Dominikb\ComposerLicenseChecker\Tests;
66

7+
use Dominikb\ComposerLicenseChecker\Contracts\DependencyParser;
78
use Dominikb\ComposerLicenseChecker\DependencyLoader;
89
use Mockery;
910

@@ -12,28 +13,31 @@ class DependencyLoaderTest extends TestCase
1213
/** @test */
1314
public function it_runs_the_command_with_the_given_inputs()
1415
{
15-
$loader = Mockery::mock(DependencyLoader::class)
16-
->shouldAllowMockingProtectedMethods()
16+
$loader = Mockery::mock(DependencyLoader::class, [$this->createNoOpParser()])
1717
->makePartial();
1818

1919
$command = '';
20-
$loader->shouldReceive('exec')
20+
$loader->shouldAllowMockingProtectedMethods()
21+
->shouldReceive('exec')
2122
->once()
2223
->withArgs(function ($c) use (&$command) {
2324
return (bool) ($command = $c);
2425
})
25-
->andReturn([
26-
'Name: dominikb/composer-license-checker',
27-
'Version: dev-master',
28-
'Licenses: MIT',
29-
'Dependencies:',
30-
'',
31-
'Name Version License ',
32-
'dominikb/composer-license-checker dev-master f12312 MIT',
33-
]);
26+
->andReturn([]);
3427

3528
$loader->loadDependencies('./composerpath/composer-binary', '/some/directory');
3629

37-
$this->assertEquals('./composerpath/composer-binary licenses -d /some/directory', $command);
30+
$this->assertEquals('./composerpath/composer-binary licenses -f json -d /some/directory', $command);
31+
}
32+
33+
public function createNoOpParser(): DependencyParser
34+
{
35+
return new class implements DependencyParser
36+
{
37+
public function parse(string $dependencyOutput): array
38+
{
39+
return [];
40+
}
41+
};
3842
}
3943
}

tests/DependencyParserTest.php

Lines changed: 0 additions & 114 deletions
This file was deleted.

0 commit comments

Comments
 (0)