diff --git a/.phplint.yml b/.phplint.yml
index b2bca65c..f22953e1 100644
--- a/.phplint.yml
+++ b/.phplint.yml
@@ -9,6 +9,3 @@ exclude:
warning: true
memory-limit: -1
no-cache: false
-log-json: false
-log-junit: false
-log-sarif: false
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index 039a5ac2..d084dd07 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -16,7 +16,7 @@ USER appuser
# Install Composer v2 then overtrue/phplint package
COPY --from=composer/composer:2-bin /composer /usr/bin/composer
ENV COMPOSER_ALLOW_SUPERUSER 1
-RUN composer global require --no-progress overtrue/phplint 9.3.x-dev
+RUN composer global require --no-progress overtrue/phplint 9.4.x-dev
# Following recommendation at https://docs.github.com/en/actions/creating-actions/dockerfile-support-for-github-actions#workdir
diff --git a/README.md b/README.md
index 516c4eb7..20a119a7 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@
| Version | Status | Requirements |
|:--------|:------------------------------------------|:---------------|
| **9.x** | **Active development** | **PHP >= 8.1** |
+| 9.4 | Active support | PHP >= 8.1 |
| 9.3 | Active support | PHP >= 8.1 |
| 9.2 | Active support | PHP >= 8.1 |
| 9.1 | Active support | PHP >= 8.1 |
diff --git a/docs/installation.md b/docs/installation.md
index 57e145df..7f98c2bc 100644
--- a/docs/installation.md
+++ b/docs/installation.md
@@ -48,7 +48,7 @@ You can also install `phplint` locally to your project with [Phive][phive] and c
```xml
-
+
```
diff --git a/src/Client.php b/src/Client.php
new file mode 100644
index 00000000..d3672ba6
--- /dev/null
+++ b/src/Client.php
@@ -0,0 +1,30 @@
+application;
+ }
+}
diff --git a/src/Command/ConfigureCommandTrait.php b/src/Command/ConfigureCommandTrait.php
index 7d1ab693..30db69a4 100644
--- a/src/Command/ConfigureCommandTrait.php
+++ b/src/Command/ConfigureCommandTrait.php
@@ -88,28 +88,16 @@ protected function configureCommand(Command $command): void
'Hide the progress output'
)
->addOption(
- 'log-json',
- null,
- InputOption::VALUE_OPTIONAL,
- 'Log scan results in JSON format to file (default: ' . OptionDefinition::DEFAULT_STANDARD_OUTPUT_LABEL . ')'
- )
- ->addOption(
- 'log-junit',
- null,
- InputOption::VALUE_OPTIONAL,
- 'Log scan results in JUnit XML format to file (default: ' . OptionDefinition::DEFAULT_STANDARD_OUTPUT_LABEL . ')'
- )
- ->addOption(
- 'log-sarif',
- null,
- InputOption::VALUE_OPTIONAL,
- 'Log scan results in SARIF format to file (default: ' . OptionDefinition::DEFAULT_STANDARD_OUTPUT_LABEL . ')'
+ 'output',
+ 'o',
+ InputOption::VALUE_REQUIRED,
+ 'Generate an output to the specified path (default: ' . OptionDefinition::DEFAULT_STANDARD_OUTPUT_LABEL . ')'
)
->addOption(
- 'sarif-converter',
+ 'format',
null,
- InputOption::VALUE_OPTIONAL,
- 'SARIF class converter (default: ' . OptionDefinition::DEFAULT_SARIF_CONVERTER_CLASS . ')'
+ InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
+ 'Format of requested reports'
)
->addOption(
'warning',
diff --git a/src/Command/LintCommand.php b/src/Command/LintCommand.php
index 43cdb7ac..f223bd09 100644
--- a/src/Command/LintCommand.php
+++ b/src/Command/LintCommand.php
@@ -13,6 +13,7 @@
namespace Overtrue\PHPLint\Command;
+use Overtrue\PHPLint\Client;
use Overtrue\PHPLint\Configuration\ConsoleOptionsResolver;
use Overtrue\PHPLint\Configuration\FileOptionsResolver;
use Overtrue\PHPLint\Configuration\OptionDefinition;
@@ -86,9 +87,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
$finder = (new Finder($configResolver))->getFiles();
- /** @var Application $app */
- $app = $this->getApplication();
- $linter = new Linter($configResolver, $this->dispatcher, $app->getLongVersion(), $this->getHelperSet(), $output);
+ $linter = new Linter(
+ $configResolver,
+ $this->dispatcher,
+ new Client($this->getApplication()),
+ $this->getHelperSet(),
+ $output
+ );
$this->results = $linter->lintFiles($finder, $startTime);
$data = $this->results->getFailures();
diff --git a/src/Configuration/ConsoleOptionsResolver.php b/src/Configuration/ConsoleOptionsResolver.php
index 4add9919..515ea7db 100644
--- a/src/Configuration/ConsoleOptionsResolver.php
+++ b/src/Configuration/ConsoleOptionsResolver.php
@@ -17,7 +17,7 @@
* @author Laurent Laville
* @since Release 9.0.0
*/
-class ConsoleOptionsResolver extends AbstractOptionsResolver
+final class ConsoleOptionsResolver extends AbstractOptionsResolver
{
public function factory(): Options
{
diff --git a/src/Configuration/FileOptionsResolver.php b/src/Configuration/FileOptionsResolver.php
index d3410f61..53169568 100644
--- a/src/Configuration/FileOptionsResolver.php
+++ b/src/Configuration/FileOptionsResolver.php
@@ -25,7 +25,7 @@
* @author Laurent Laville
* @since Release 9.0.0
*/
-class FileOptionsResolver extends AbstractOptionsResolver
+final class FileOptionsResolver extends AbstractOptionsResolver
{
public function __construct(InputInterface $input)
{
diff --git a/src/Console/Application.php b/src/Console/Application.php
index 44a32868..6508aaf3 100644
--- a/src/Console/Application.php
+++ b/src/Console/Application.php
@@ -16,19 +16,19 @@
use Overtrue\PHPLint\Helper\DebugFormatterHelper;
use Overtrue\PHPLint\Helper\ProcessHelper;
use Overtrue\PHPLint\Output\ConsoleOutput;
-use Phar;
use Symfony\Component\Console\Application as BaseApplication;
use Symfony\Component\Console\Command\HelpCommand;
use Symfony\Component\Console\Command\ListCommand;
use Symfony\Component\Console\Helper\FormatterHelper;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use function array_keys;
use function in_array;
+use const STDOUT;
+
/**
* @author Overtrue
* @author Laurent Laville (since v9.0)
@@ -36,7 +36,7 @@
final class Application extends BaseApplication
{
public const NAME = 'phplint';
- public const VERSION = '9.3.1';
+ public const VERSION = '9.4.0-dev';
public function __construct()
{
@@ -45,27 +45,11 @@ public function __construct()
public function run(InputInterface $input = null, OutputInterface $output = null): int
{
- $output ??= new ConsoleOutput();
+ $output ??= new ConsoleOutput(STDOUT);
return parent::run($input, $output);
}
- protected function configureIO(InputInterface $input, OutputInterface $output): void
- {
- if (Phar::running()) {
- $inputDefinition = $this->getDefinition();
- $inputDefinition->addOption(
- new InputOption(
- 'manifest',
- null,
- InputOption::VALUE_NONE,
- 'Show which versions of dependencies are bundled'
- )
- );
- }
- parent::configureIO($input, $output);
- }
-
protected function getDefaultCommands(): array
{
return [new HelpCommand(), new ListCommand()];
diff --git a/src/Linter.php b/src/Linter.php
index c5f82b51..dfc63560 100644
--- a/src/Linter.php
+++ b/src/Linter.php
@@ -21,7 +21,6 @@
use Overtrue\PHPLint\Event\BeforeCheckingEvent;
use Overtrue\PHPLint\Event\BeforeLintFileEvent;
use Overtrue\PHPLint\Helper\ProcessHelper;
-use Overtrue\PHPLint\Output\ConsoleOutputInterface;
use Overtrue\PHPLint\Output\LinterOutput;
use Overtrue\PHPLint\Process\LintProcess;
use Psr\Cache\InvalidArgumentException;
@@ -40,6 +39,7 @@
use function md5_file;
use function microtime;
use function phpversion;
+use function strip_tags;
use function version_compare;
/**
@@ -57,20 +57,16 @@ final class Linter
private int $processLimit;
private string $memoryLimit;
private bool $warning;
- private array $options;
- private string $appLongVersion;
public function __construct(
Resolver $configResolver,
EventDispatcherInterface $dispatcher,
- string $appVersion = '9.1.x-dev',
- HelperSet $helperSet = null,
- OutputInterface $output = null
+ private readonly ?Client $client = null,
+ ?HelperSet $helperSet = null,
+ ?OutputInterface $output = null,
) {
$this->configResolver = $configResolver;
$this->dispatcher = $dispatcher;
- $this->appLongVersion = $appVersion;
- $this->options = $configResolver->getOptions();
$this->processLimit = $configResolver->getOption(OptionDefinition::JOBS);
$this->memoryLimit = (string) $configResolver->getOption(OptionDefinition::OPTION_MEMORY_LIMIT);
$this->warning = $configResolver->getOption(OptionDefinition::WARNING);
@@ -108,21 +104,7 @@ public function lintFiles(Finder $finder, ?float $startTime = null): LinterOutpu
$fileCount = 0;
}
- if ($this->output instanceof ConsoleOutputInterface) {
- $configFile = $this->options['no-configuration']
- ? ''
- : $this->options['configuration']
- ;
- $this->output->headerBlock($this->appLongVersion, $configFile);
- $this->output->configBlock($this->options);
- }
-
- $this->dispatcher->dispatch(
- new BeforeCheckingEvent(
- $this,
- ['fileCount' => $fileCount, 'appVersion' => $this->appLongVersion, 'options' => $this->options]
- )
- );
+ $this->dispatcher->dispatch(new BeforeCheckingEvent($this, ['fileCount' => $fileCount]));
$processCount = 0;
if ($fileCount > 0) {
@@ -131,8 +113,16 @@ public function lintFiles(Finder $finder, ?float $startTime = null): LinterOutpu
$results = [];
}
+ if (null !== $this->client) {
+ $default = [
+ 'application_version' => [
+ 'long' => $this->client->getApplication()->getLongVersion(),
+ 'short' => $this->client->getApplication()->getVersion(),
+ ]
+ ];
+ }
$finalResults = new LinterOutput($results, $finder);
- $finalResults->setContext($this->configResolver, $startTime, $processCount);
+ $finalResults->setContext($this->configResolver, $startTime, $processCount, $default ?? []);
$this->dispatcher->dispatch(new AfterCheckingEvent($this, ['results' => $finalResults]));
diff --git a/src/Output/ChainOutput.php b/src/Output/ChainOutput.php
index e512992e..ee4347c0 100644
--- a/src/Output/ChainOutput.php
+++ b/src/Output/ChainOutput.php
@@ -16,6 +16,7 @@
use InvalidArgumentException;
use function count;
+use function fclose;
use function get_debug_type;
use function sprintf;
@@ -45,12 +46,24 @@ public function __construct(array $handlers)
}
}
+ public function getName(): string
+ {
+ return 'chain';
+ }
+
public function format(LinterOutput $results): void
{
$i = count($this->outputHandlers);
+ if ($i === 0) {
+ return;
+ }
+
while ($i--) {
$this->outputHandlers[$i]->format($results);
}
+
+ // close stream only once all formatters do their job
+ fclose($this->outputHandlers[0]->getStream());
}
}
diff --git a/src/Output/ConsoleOutput.php b/src/Output/ConsoleOutput.php
index db6fe885..0aa4e4b0 100644
--- a/src/Output/ConsoleOutput.php
+++ b/src/Output/ConsoleOutput.php
@@ -21,7 +21,8 @@
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Input\ArrayInput;
-use Symfony\Component\Console\Output\ConsoleOutput as BaseConsoleOutput;
+use Symfony\Component\Console\Output\ConsoleOutput as SymfonyConsoleOutput;
+use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Console\Terminal;
use Symfony\Component\Finder\SplFileInfo;
@@ -56,7 +57,7 @@
* @author Laurent Laville
* @since Release 9.0.0
*/
-class ConsoleOutput extends BaseConsoleOutput implements ConsoleOutputInterface
+final class ConsoleOutput extends StreamOutput implements OutputInterface, ConsoleOutputInterface
{
public const MAX_LINE_LENGTH = 120;
@@ -64,13 +65,22 @@ class ConsoleOutput extends BaseConsoleOutput implements ConsoleOutputInterface
private int $lineLength;
- public function __construct(int $verbosity = parent::VERBOSITY_NORMAL, bool $decorated = null, OutputFormatterInterface $formatter = null)
- {
- parent::__construct($verbosity, $decorated, $formatter);
+ public function __construct(
+ $stream,
+ int $verbosity = parent::VERBOSITY_NORMAL,
+ ?bool $decorated = null,
+ ?OutputFormatterInterface $formatter = null
+ ) {
+ parent::__construct($stream, $verbosity, $decorated, $formatter);
$width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH;
$this->lineLength = min($width - (int) (DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH);
}
+ public function getName(): string
+ {
+ return 'console';
+ }
+
public function format(LinterOutput $results): void
{
$data = $results->getFailures();
@@ -83,6 +93,11 @@ public function format(LinterOutput $results): void
return;
}
+ $options = $context['options_used'] ?? [];
+ $configFile = $options['no-configuration'] ? '' : $options['configuration'];
+ $this->headerBlock($context['application_version']['long'], $configFile);
+ $this->configBlock($options);
+
$this->consumeBlock($context['time_usage'], $context['memory_usage'], $context['cache_usage'], $context['process_count']);
if ($errCount > 0) {
@@ -262,8 +277,7 @@ public function configBlock(array $options): void
}
}
- $section = $this->section();
- $table = new Table($section);
+ $table = new Table($this);
$table
->setHeaders($headers)
->setRows($rows)
diff --git a/src/Output/ConsoleOutputInterface.php b/src/Output/ConsoleOutputInterface.php
index 41d38b98..07a35a8a 100644
--- a/src/Output/ConsoleOutputInterface.php
+++ b/src/Output/ConsoleOutputInterface.php
@@ -14,13 +14,14 @@
namespace Overtrue\PHPLint\Output;
use Symfony\Component\Console\Helper\ProgressBar;
+use Symfony\Component\Console\Output\OutputInterface as SymfonyOutputInterface;
use Symfony\Component\Finder\SplFileInfo;
/**
* @author Laurent Laville
* @since Release 9.1.0
*/
-interface ConsoleOutputInterface extends OutputInterface
+interface ConsoleOutputInterface extends SymfonyOutputInterface
{
public const NO_FILE_TO_LINT = 'Could not find any files to lint';
diff --git a/src/Output/LinterOutput.php b/src/Output/LinterOutput.php
index d6a92e15..e19baf7c 100644
--- a/src/Output/LinterOutput.php
+++ b/src/Output/LinterOutput.php
@@ -57,7 +57,7 @@ public function getContext(): array
return $this->context;
}
- public function setContext(Resolver $configResolver, float $startTime, int $processCount): void
+ public function setContext(Resolver $configResolver, float $startTime, int $processCount, array $default = []): void
{
$cacheHits = count($this->getHits());
$cacheMisses = count($this->getMisses());
@@ -78,14 +78,14 @@ public function setContext(Resolver $configResolver, float $startTime, int $proc
$fileCount = 0;
}
- $this->context = [
+ $this->context = array_merge($default, [
'time_usage' => $timeUsage,
'memory_usage' => $memUsage,
'cache_usage' => $cacheUsage,
'process_count' => $processCount,
'files_count' => $fileCount,
'options_used' => $configResolver->getOptions(),
- ];
+ ]);
}
public function hasFailures(): bool
diff --git a/src/Output/OutputInterface.php b/src/Output/OutputInterface.php
index ce36ace6..3d7aab27 100644
--- a/src/Output/OutputInterface.php
+++ b/src/Output/OutputInterface.php
@@ -19,5 +19,8 @@
*/
interface OutputInterface
{
+ public function getName(): string;
+
public function format(LinterOutput $results): void;
+
}
diff --git a/tests/Configuration/ConsoleConfigTest.php b/tests/Configuration/ConsoleConfigTest.php
index a94865b7..f0422375 100644
--- a/tests/Configuration/ConsoleConfigTest.php
+++ b/tests/Configuration/ConsoleConfigTest.php
@@ -68,18 +68,10 @@ public static function commandInputProvider(): array
'multiple path modified' => [['path' => [dirname(__DIR__) . '/Cache', __DIR__]], __CLASS__ . '::expectedPathModified'],
'without external configuration' => [['--no-configuration' => true], __CLASS__ . '::expectedExternalConfigNotFetched'],
'with external empty configuration' => [['--configuration' => 'tests/Configuration/empty.yaml'], __CLASS__ . '::expectedExternalEmptyConfig'],
- 'output to JSON format on Stdout 1/3' => [['--log-json' => null], __CLASS__ . '::expectedJsonOutputFormat'],
- 'output to JSON format on Stdout 2/3' => [['--log-json' => ''], __CLASS__ . '::expectedJsonOutputFormat'],
- 'output to JSON format on Stdout 3/3' => [['--log-json' => true], __CLASS__ . '::expectedJsonOutputFormat'],
- 'disable output to JSON format 1/2' => [['--log-json' => false], __CLASS__ . '::expectedJsonOutputFormat'],
- 'disable output to JSON format 2/2' => [['--log-json' => 'off'], __CLASS__ . '::expectedJsonOutputFormat'],
- 'output to JSON format on File' => [['--log-json' => '/tmp/phplint.json'], __CLASS__ . '::expectedJsonOutputFormat'],
- 'output to XML format on Stdout 1/3' => [['--log-junit' => null], __CLASS__ . '::expectedXmlOutputFormat'],
- 'output to XML format on Stdout 2/3' => [['--log-junit' => ''], __CLASS__ . '::expectedXmlOutputFormat'],
- 'output to XML format on Stdout 3/3' => [['--log-junit' => true], __CLASS__ . '::expectedXmlOutputFormat'],
- 'disable output to XML format 1/2' => [['--log-junit' => false], __CLASS__ . '::expectedXmlOutputFormat'],
- 'disable output to XML format 2/2' => [['--log-junit' => 'FALSE'], __CLASS__ . '::expectedXmlOutputFormat'],
- 'output to XML format on File' => [['--log-junit' => '/tmp/phplint.xml'], __CLASS__ . '::expectedXmlOutputFormat'],
+ 'output to JSON format on Stdout' => [['--format' => 'json'], __CLASS__ . '::expectedJsonOutputFormat'],
+ 'output to JSON format on File' => [['--format' => 'json', '--output' => '/tmp/phplint.json'], __CLASS__ . '::expectedJsonOutputFormat'],
+ 'output to XML format on Stdout' => [['--format' => 'junit'], __CLASS__ . '::expectedXmlOutputFormat'],
+ 'output to XML format on File' => [['--format' => 'junit', '--output' => '/tmp/phplint.xml'], __CLASS__ . '::expectedXmlOutputFormat'],
];
}
@@ -107,18 +99,12 @@ protected static function expectedExternalEmptyConfig(Resolver $resolver, array
protected static function expectedJsonOutputFormat(Resolver $resolver, array $arguments): array
{
- $expected = self::getExpectedValues($resolver);
- $logJson = $arguments['--log-json'];
- $expected['log-json'] = OptionsFactory::logNormalizer(new OptionsResolver(), $logJson);
- return $expected;
+ return self::getExpectedValues($resolver); // expected only default arguments/options from command line
}
protected static function expectedXmlOutputFormat(Resolver $resolver, array $arguments): array
{
- $expected = self::getExpectedValues($resolver);
- $logJunit = $arguments['--log-junit'];
- $expected['log-junit'] = OptionsFactory::logNormalizer(new OptionsResolver(), $logJunit);
- return $expected;
+ return self::getExpectedValues($resolver); // expected only default arguments/options from command line
}
protected static function getExpectedValues(Resolver $resolver): array
diff --git a/tests/Configuration/YamlConfigTest.php b/tests/Configuration/YamlConfigTest.php
index 977e6e72..d3d3fa9c 100644
--- a/tests/Configuration/YamlConfigTest.php
+++ b/tests/Configuration/YamlConfigTest.php
@@ -93,14 +93,16 @@ protected static function expectedJobsModified(Resolver $resolver): array
protected static function expectedJsonOutputFormat(Resolver $resolver, array $arguments): array
{
$expected = self::getExpectedValues($resolver);
- $expected['log-json'] = OptionDefinition::DEFAULT_STANDARD_OUTPUT; // see 'log-json.yaml' contents
+ $expected['output'] = OptionDefinition::DEFAULT_STANDARD_OUTPUT; // see 'log-json.yaml' contents
+ $expected['format'] = ['json'];
return $expected;
}
protected static function expectedXmlOutputFormat(Resolver $resolver, array $arguments): array
{
$expected = self::getExpectedValues($resolver);
- $expected['log-junit'] = '/tmp/phplint-results.xml'; // see 'log-junit.yaml' contents
+ $expected['output'] = '/tmp/phplint-results.xml'; // see 'log-junit.yaml' contents
+ $expected['format'] = ['junit'];
return $expected;
}
diff --git a/tests/Configuration/log-json.yaml b/tests/Configuration/log-json.yaml
index 132c6521..aec4d2c4 100644
--- a/tests/Configuration/log-json.yaml
+++ b/tests/Configuration/log-json.yaml
@@ -1 +1,3 @@
-log-json: php://stdout
+output: php://stdout
+format:
+ - json
diff --git a/tests/Configuration/log-junit.yaml b/tests/Configuration/log-junit.yaml
index 4b30aed8..0a5984da 100644
--- a/tests/Configuration/log-junit.yaml
+++ b/tests/Configuration/log-junit.yaml
@@ -1 +1,3 @@
-log-junit: /tmp/phplint-results.xml
+output: /tmp/phplint-results.xml
+format:
+ - junit