diff --git a/.changes/9.0.4.md b/.changes/9.0.4.md
new file mode 100644
index 00000000..da03e3e9
--- /dev/null
+++ b/.changes/9.0.4.md
@@ -0,0 +1,21 @@
+
+## 9.0.4 - 2023-02-23
+
+### Added
+
+- PHPUnit 10 support
+
+### Changed
+
+- ConsoleOutput is no more final to be able to customize it
+- LinterOutput implement Countable interface
+- Finder implement JsonSerializable interface
+
+### Fixed
+
+- [#182](https://github.com/overtrue/phplint/issues/182) : Docker usage may raise a permission denied
+- [#183](https://github.com/overtrue/phplint/issues/183) : Error is unintuitive when there are no files to lint
+- [#185](https://github.com/overtrue/phplint/issues/185) : Analyse multiple path at same time did not work with console command
+- [#187](https://github.com/overtrue/phplint/issues/187) : Improve log options implementation
+
+**Full Changelog**: [9.0.3...9.0.4](https://github.com/overtrue/phplint/compare/9.0.3...9.0.4)
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 4b631e8a..7cb778ac 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -8,19 +8,42 @@ on:
jobs:
build:
- runs-on: ubuntu-20.04
+ runs-on: "${{ matrix.operating-system }}"
+
+ strategy:
+ fail-fast: false
+
+ matrix:
+ operating-system:
+ - "ubuntu-20.04"
+ - "ubuntu-22.04"
+
+ php-version:
+ - "8.0"
+ - "8.1"
+ - "8.2"
+
steps:
- # Git Checkout
name: Checkout code
uses: actions/checkout@v3
- - # Setup PHP runtime
- name: Setup PHP runtime
+ - # Setup PHP runtime for PHPUnit 9 tool support
+ name: Setup PHP runtime for PHPUnit 9
uses: shivammathur/setup-php@v2
+ if: ${{ matrix.php-version == '8.0' }}
with:
- php-version: 8.0
+ php-version: "${{ matrix.php-version }}"
tools: phpunit:9.6
+ - # Setup PHP runtime for PHPUnit 10 tool support
+ name: Setup PHP runtime for PHPUnit 10
+ if: ${{ matrix.php-version != '8.0' }}
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: "${{ matrix.php-version }}"
+ tools: phpunit
+
- # Install Composer dependencies
name: Install Composer dependencies
uses: ramsey/composer-install@v2
@@ -28,5 +51,10 @@ jobs:
composer-options: "--prefer-dist --no-scripts"
- # Run unit tests
- name: Unit tests
- run: phpunit
+ name: Unit tests with PHPUnit 9
+ if: ${{ matrix.php-version == '8.0' }}
+ run: phpunit --configuration ./phpunit-9.xml --testdox --do-not-cache-result
+ -
+ name: Unit tests with PHPUnit 10
+ if: ${{ matrix.php-version != '8.0' }}
+ run: phpunit --testdox --do-not-cache-result
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index e777e46d..a3a27b30 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -3,35 +3,8 @@ name: Release
on:
push:
- branches:
tags:
- "[0-9]+.[0-9]+.[0-9]+"
- workflow_dispatch:
- # https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/
- inputs:
- box-output:
- description: "Path to the PHP Archive made by the BOX"
- required: true
- type: string
- release-tag:
- description: "Tag that identify version to be released"
- required: true
- type: string
- release-draft:
- description: "Indicator of whether or not this release is a draft"
- required: false
- default: false
- type: boolean
- changie-changesDir:
- description: "Directory for change files, header file and unreleased files. Relative to project root"
- required: false
- default: ".changes"
- type: string
- changie-version:
- description: "Version for Changie"
- required: false
- default: v1.11.1
- type: string
permissions:
contents: write
@@ -44,7 +17,7 @@ jobs:
fail-fast: false
matrix:
os:
- - ubuntu-20.04
+ - ubuntu-22.04
php:
- 8.1
@@ -65,27 +38,8 @@ jobs:
with:
composer-options: "--prefer-dist"
- - # Build the current change fragments
- name: Build Release Notes 1/2
- uses: miniscruff/changie-action@v1
- with:
- version: ${{ github.event.inputs.changie-version }}
- args: batch ${{ github.event.inputs.release-tag }}
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- - # Build the current release changelog
- name: Build Release Notes 2/2
- uses: miniscruff/changie-action@v1
- with:
- version: ${{ github.event.inputs.changie-version }}
- args: merge
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- # Build the current release with artifacts (php archive)
- name: Build Release Artifacts (without bootstrap file)
- if: endsWith(github.event.inputs.box-output, '.phar')
+ name: Build Release Artifacts
run: |
cd ${{ github.workspace }}
curl -Ls https://github.com/llaville/box-manifest/releases/latest/download/box-manifest.phar -o /usr/local/bin/box-manifest
@@ -94,13 +48,14 @@ jobs:
- # Create a new Release (from a tag)
name: Create Release from current tag
+ if: github.ref_type == 'tag'
uses: softprops/action-gh-release@v1
with: # https://github.com/softprops/action-gh-release#-customizing
prerelease: false
- draft: ${{ github.event.inputs.release-draft }}
- body_path: ${{ github.workspace }}/${{ github.event.inputs.changie-changesDir }}/${{ github.event.inputs.release-tag }}.md
+ draft: true
+ body_path: ${{ github.workspace }}/.changes/${{ github.ref_name }}.md
# https://github.com/softprops/action-gh-release#%EF%B8%8F-uploading-release-assets
files:
- ${{ github.workspace }}/${{ github.event.inputs.box-output }}
+ ${{ github.workspace }}/bin/phplint.phar
fail_on_unmatched_files: true
- tag_name: ${{ github.event.inputs.release-tag }}
+ tag_name: ${{ github.ref_name }}
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
index 9bacd6e0..784e7ed5 100755
--- a/.php-cs-fixer.dist.php
+++ b/.php-cs-fixer.dist.php
@@ -32,6 +32,6 @@
PhpCsFixer\Finder::create()
->exclude('vendor')
->notPath('fixtures/syntax_error.php')
- ->in([__DIR__.'/src/', __DIR__.'/tests/'])
+ ->in([__DIR__.'/src/', __DIR__.'/examples', __DIR__.'/tests/'])
)
;
diff --git a/.phplint.yml b/.phplint.yml
index 65bef3b3..ecb20486 100644
--- a/.phplint.yml
+++ b/.phplint.yml
@@ -1,4 +1,6 @@
-path: ./src
+path:
+ - src/
+ - tests/
jobs: 10
extensions:
- php
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2afb64da..4678a4d9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
and is generated by [Changie](https://github.com/miniscruff/changie).
+## 9.0.4 - 2023-02-23
+
+### Added
+
+- PHPUnit 10 support
+
+### Changed
+
+- ConsoleOutput is no more final to be able to customize it
+- LinterOutput implement Countable interface
+- Finder implement JsonSerializable interface
+
+### Fixed
+
+- [#182](https://github.com/overtrue/phplint/issues/182) : Docker usage may raise a permission denied
+- [#183](https://github.com/overtrue/phplint/issues/183) : Error is unintuitive when there are no files to lint
+- [#185](https://github.com/overtrue/phplint/issues/185) : Analyse multiple path at same time did not work with console command
+- [#187](https://github.com/overtrue/phplint/issues/187) : Improve log options implementation
+
+**Full Changelog**: [9.0.3...9.0.4](https://github.com/overtrue/phplint/compare/9.0.3...9.0.4)
+
## 9.0.3 - 2023-02-14
### Fixed
diff --git a/Dockerfile b/Dockerfile
index c421bff4..7d746abe 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,13 +1,23 @@
-ARG VERSION=8.0
+# syntax=docker/dockerfile:1.4
+ARG PHP_VERSION=8.2
-FROM composer:2.0 AS build
-RUN composer global require overtrue/phplint 9.0.x-dev
+FROM php:${PHP_VERSION}-cli-alpine
-FROM php:${VERSION}-cli-alpine
-COPY --from=build /tmp/vendor /root/.composer/vendor
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
RUN cp /usr/local/etc/php/php.ini-development /usr/local/etc/php/php.ini
-WORKDIR /workdir
+# Create a group and user
+RUN addgroup appgroup && adduser appuser -D -G appgroup
+
+# Tell docker that all future commands should run as the appuser user
+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.0
+
+# Following recommendation at https://docs.github.com/en/actions/creating-actions/dockerfile-support-for-github-actions#workdir
+
ENTRYPOINT ["/entrypoint.sh"]
diff --git a/README.md b/README.md
index 5423a10c..01d20af8 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
`phplint` is a tool that can speed up linting of php files by running several lint processes at once.
-[![Release Status](https://github.com/overtrue/phplint/actions/workflows/build-phar.yml/badge.svg)](https://github.com/overtrue/phplint/actions/workflows/build-phar.yml)
+[![Release Status](https://github.com/overtrue/phplint/actions/workflows/release.yml/badge.svg)](https://github.com/overtrue/phplint/actions/workflows/release.yml)
[![Latest Stable Version](https://img.shields.io/packagist/v/overtrue/phplint)](https://packagist.org/packages/overtrue/phplint)
[![Total Downloads](https://poser.pugx.org/overtrue/phplint/downloads.svg)](https://packagist.org/packages/overtrue/phplint)
[![License](https://poser.pugx.org/overtrue/phplint/license.svg)](https://packagist.org/packages/overtrue/phplint)
@@ -32,10 +32,11 @@ with lot of improvement, full documentation, and full unit code tested.
1. [Docker](docs/installation.md#docker)
1. [Phive](docs/installation.md#phive)
1. [Composer](docs/installation.md#composer)
-1. [Usage](docs/index.md#usage)
+1. [Usage](docs/README.md#usage)
1. [Configuration](docs/configuration.md#configuration)
1. [Upgrading](docs/upgrading.md#upgrading)
1. [Contributing](docs/contributing.md#contributing)
+1. [Architecture](docs/architecture/README.md#architecture)
## :heart: Sponsor me
diff --git a/composer.json b/composer.json
index 9973011e..a005c299 100644
--- a/composer.json
+++ b/composer.json
@@ -71,9 +71,9 @@
"cghooks": "vendor/bin/cghooks",
"check-style": "vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --using-cache=no --verbose --ansi --diff --dry-run",
"fix-style": "vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --using-cache=no --verbose --ansi",
- "tests:unit": "vendor/bin/phpunit --debug --testsuite=cache,configuration,finder",
- "tests:e2e": "vendor/bin/phpunit --debug --testsuite=e2e",
- "tests:all": "vendor/bin/phpunit --debug",
+ "tests:unit": "vendor/bin/phpunit --testsuite=cache,configuration,finder",
+ "tests:e2e": "vendor/bin/phpunit --testsuite=e2e",
+ "tests:all": "vendor/bin/phpunit",
"lint:syntax": "./bin/phplint --ansi"
},
"minimum-stability": "dev",
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 00000000..16491191
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,42 @@
+# Documentation
+
+Full documentation may be found in `docs` folder in repository, and may be read online without to do anything else.
+
+As alternative, you may generate a professional static site with [Material for MkDocs][mkdocs-material].
+
+Configuration file `mkdocs.yaml` is available and if you have Docker support, the documentation site can be simply build
+with following command:
+
+`docker run --rm -it -u "$(id -u):$(id -g)" -v ${PWD}:/docs squidfunk/mkdocs-material build --verbose`
+
+## Goal
+
+The PHPLint is a command line tool that can speed up linting of php files by running several lint processes at once.
+
+## Architecture
+
+> As a developer you want to learn more about PHPLint architecture!.
+
+See [Architecture's Guide](architecture/README.md)
+
+## Usage
+
+> Learn more about different usages with console, Docker, CI, and programmatically.
+
+See [Getting-Started's Guide](usage/README.md) to know how to use it.
+
+## Contributing
+
+> Contribution are always welcome and much appreciated!.
+
+See [Contributor's Guide](contributing.md#contributing) before you start.
+
+## Credits
+
+Project originally created by [@overtrue](https://github.com/overtrue), which is now (since version 9.0)
+actively supported by [Laurent Laville (@llaville)](https://github.com/llaville).
+
+See the list of [all contributors][contributors].
+
+[mkdocs-material]: https://github.com/squidfunk/mkdocs-material
+[contributors]: https://github.com/overtrue/phplint/graphs/contributors
diff --git a/docs/architecture/README.md b/docs/architecture/README.md
new file mode 100644
index 00000000..6e22937a
--- /dev/null
+++ b/docs/architecture/README.md
@@ -0,0 +1,31 @@
+# Architecture
+
+This guide is dedicated to all PHP developers that want to learn more about each PHPLint components.
+
+## [Cache](cache.md#cache)
+
+To learn how PHPLint is able to improve speed analysis on multiple runs.
+
+## [Configuration](configuration.md#configuration)
+
+To learn how PHPLint options can customize your checks.
+
+## [Event-Driven](event.md#event-driven-architecture-on-wikipediaeda)
+
+To learn more about how to extend PHPLint features.
+
+## [Extension](extension.md#extension)
+
+To learn more about how to extend PHPLint features.
+
+## [Finder](finder.md#finder)
+
+To learn how PHPLint find files to check.
+
+## [Output](output.md#output-formats)
+
+To learn how PHPLint can customize results output.
+
+## [Process](process.md#process)
+
+To learn how PHPLint is able to run multiple processes in parallel.
diff --git a/docs/architecture/extension.md b/docs/architecture/extension.md
index e349fc64..2c87a609 100644
--- a/docs/architecture/extension.md
+++ b/docs/architecture/extension.md
@@ -71,8 +71,8 @@ use Overtrue\PHPLint\Extension\OutputFormat;
$extensions = [
new OutputFormat([
- OptionDefinition::OPTION_JSON_FILE,
- OptionDefinition::OPTION_JUNIT_FILE,
+ OptionDefinition::LOG_JSON,
+ OptionDefinition::LOG_JUNIT,
])
];
diff --git a/docs/index.md b/docs/index.md
deleted file mode 100644
index 98ba774b..00000000
--- a/docs/index.md
+++ /dev/null
@@ -1,205 +0,0 @@
-# Documentation
-
-Full documentation may be found in `docs` folder in repository, and may be read online without to do anything else.
-
-As alternative, you may generate a professional static site with [Material for MkDocs][mkdocs-material].
-
-Configuration file `mkdocs.yaml` is available and if you have Docker support, the documentation site can be simply build
-with following command:
-
-`docker run --rm -it -u "$(id -u):$(id -g)" -v ${PWD}:/docs squidfunk/mkdocs-material build --verbose`
-
-## Goal
-
-The PHPLint is a command line tool that can speed up linting of php files by running several lint processes at once.
-
-## Usage
-
-1. [Console CLI](#console-cli)
-1. [Docker CLI](#docker-cli)
-1. [GitHub Actions](#github-actions)
-1. [GitLab CI](#gitlab-ci)
-1. [Other CI Pipelines](#other-ci-pipelines)
-2. [Programmatically](#programmatically)
-
-### Console CLI
-
-Linting PHP source files should be as simple as running `phplint` with one or more source paths (no config required!).
-It will however assume some defaults that you might want to change.
-
-PHPLint will by default be looking in order for the file `.phplint.yml` in the current working directory.
-You can use another filename by option: `--configuration=FILENAME` or `-c FILENAME`.
-
-A basic configuration could be for example:
-
-```yaml
-path: ./src
-jobs: 10
-extensions:
- - php
-exclude:
- - vendor
-warning: true
-memory-limit: -1
-no-cache: true
-```
-
-> If you want to ignore the configuration file directives, you should specify option `--no-configuration`.
-
-You can then find more advanced configuration settings in [the configuration documentation](configuration.md).
-For more information on which options are available, you can run: `phplint --help`
-
-```text
-Description:
- Files syntax check only
-
-Usage:
- lint [options] [--] [...]
-
-Arguments:
- path Path to file or directory to lint (default: working directory)
-
-Options:
- --exclude=EXCLUDE Path to file or directory to exclude from linting (multiple values allowed)
- --extensions=EXTENSIONS Check only files with selected extensions (multiple values allowed)
- -j, --jobs=JOBS Number of paralleled jobs to run
- -c, --configuration=CONFIGURATION Read configuration from config file [default: ".phplint.yml"]
- --no-configuration Ignore default configuration file (.phplint.yml)
- --cache=CACHE Path to the cache directory
- --no-cache Ignore cached data
- -p, --progress=PROGRESS Show the progress output
- --no-progress Hide the progress output
- --log-json[=LOG-JSON] Log scan results in JSON format to file (default: standard output)
- --log-junit[=LOG-JUNIT] Log scan results in JUnit XML format to file (default: standard output)
- -w, --warning Also show warnings
- --memory-limit=MEMORY-LIMIT Memory limit for analysis
- --ignore-exit-code Ignore exit codes so there are no "failure" exit code even when no files processed
- -h, --help Display help for the given command. When no command is given display help for the lint command
- -q, --quiet Do not output any message
- -V, --version Display this application version
- --ansi|--no-ansi Force (or disable --no-ansi) ANSI output
- -n, --no-interaction Do not ask any interactive question
- -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
-```
-
-### Docker CLI
-
-```shell
-docker run --rm -t -v "${PWD}":/workdir overtrue/phplint:latest ./ --exclude=vendor --no-configuration --no-cache
-```
-
-> Please mount your source code to `/workdir` in the container.
-
-> Be carefully when you use the cache subsystem. Don't forget to specify `-u "$(id -u):$(id -g)"` arguments on `docker run` command,
-otherwise cache files (into `.phplint.cache` directory by default) will be created with `root` account.
-
-### GitHub Actions
-
-```yaml
-uses: overtrue/phplint@main
-with:
- path: .
- options: --exclude=vendor
-```
-
-### GitLab CI
-
-```yaml
-code-quality:lint-php:
- image: overtrue/phplint:latest
- variables:
- INPUT_PATH: "./"
- INPUT_OPTIONS: "-c .phplint.yml"
- script: echo '' #prevents ci yml parse error
-```
-
-### Other CI Pipelines
-
-Run this command using `overtrue/phplint:latest` Docker image:
-
-```shell
-/root/.composer/vendor/bin/phplint ./ --exclude=vendor
-```
-
-### Programmatically
-
-```php
-use Overtrue\PHPLint\Command\LintCommand;
-use Overtrue\PHPLint\Configuration\ConsoleOptionsResolver;
-use Overtrue\PHPLint\Event\EventDispatcher;
-use Overtrue\PHPLint\Finder;
-use Overtrue\PHPLint\Linter;
-use Symfony\Component\Console\Input\ArrayInput;
-
-$dispatcher = new EventDispatcher([]);
-
-$arguments = [
- 'path' => [__DIR__ . '/src', __DIR__ . '/tests'],
- '--no-configuration' => true,
- '--no-cache' => true,
- '--exclude' => ['vendor'],
- '--extensions' => ['php'],
- '--warning' => true,
-];
-$command = new LintCommand($dispatcher);
-$definition = $command->getDefinition();
-$input = new ArrayInput($arguments, $definition);
-
-$configResolver = new ConsoleOptionsResolver($input);
-
-$finder = new Finder($configResolver);
-
-$linter = new Linter($configResolver, $dispatcher);
-
-$results = $linter->lintFiles($finder->getFiles());
-
-var_dump($results->getErrors());
-/*
- array(1) {
- ["/absolute/path/to/tests/fixtures/syntax_error.php"]=>
- array(4) {
- ["absolute_file"]=>
- string(62) "/absolute/path/to/tests/fixtures/syntax_error.php"
- ["relative_file"]=>
- string(25) "fixtures/syntax_error.php"
- ["error"]=>
- string(32) "unexpected end of file in line 4"
- ["line"]=>
- int(4)
- }
-}
- */
-
-var_dump($results->getWarnings());
-/*
-array(1) {
- ["/absolute/path/to/tests/fixtures/syntax_warning.php"]=>
- array(4) {
- ["absolute_file"]=>
- string(64) "/absolute/path/to/tests/fixtures/syntax_warning.php"
- ["relative_file"]=>
- string(27) "fixtures/syntax_warning.php"
- ["error"]=>
- string(97) " declare(encoding=...) ignored because Zend multibyte feature is turned off by settings in line 1"
- ["line"]=>
- int(1)
- }
-}
- */
-```
-
-## Contributing
-
-> Contribution are always welcome and much appreciated!.
-
-See [Contributor's Guide](contributing.md#contributing) before you start.
-
-## Credits
-
-Project originally created by [@overtrue](https://github.com/overtrue), which is now (since version 9.0)
-actively supported by [Laurent Laville (@llaville)](https://github.com/llaville).
-
-See the list of [all contributors][contributors].
-
-[mkdocs-material]: https://github.com/squidfunk/mkdocs-material
-[contributors]: https://github.com/overtrue/phplint/graphs/contributors
diff --git a/docs/usage/README.md b/docs/usage/README.md
new file mode 100644
index 00000000..6ac5624a
--- /dev/null
+++ b/docs/usage/README.md
@@ -0,0 +1,8 @@
+# Usage
+
+1. [Console CLI](console.md)
+1. [Docker CLI](docker.md)
+1. [GitHub Actions](github-actions.md)
+1. [GitLab CI](gitlab-ci.md)
+1. [Other CI Pipelines](other-ci.md)
+1. [Programmatically](programmatically.md)
diff --git a/docs/usage/console.md b/docs/usage/console.md
new file mode 100644
index 00000000..4700d215
--- /dev/null
+++ b/docs/usage/console.md
@@ -0,0 +1,59 @@
+# Console CLI
+
+Linting PHP source files should be as simple as running `phplint` with one or more source paths (no config required!).
+It will however assume some defaults that you might want to change.
+
+PHPLint will by default be looking in order for the file `.phplint.yml` in the current working directory.
+You can use another filename by option: `--configuration=FILENAME` or `-c FILENAME`.
+
+A basic configuration could be for example:
+
+```yaml
+path: ./src
+jobs: 10
+extensions:
+ - php
+exclude:
+ - vendor
+warning: true
+memory-limit: -1
+no-cache: true
+```
+
+> If you want to ignore the configuration file directives, you should specify option `--no-configuration`.
+
+You can then find more advanced configuration settings in [the configuration documentation](configuration.md).
+For more information on which options are available, you can run: `phplint --help`
+
+```text
+Description:
+ Files syntax check only
+
+Usage:
+ lint [options] [--] [...]
+
+Arguments:
+ path Path to file or directory to lint (default: working directory)
+
+Options:
+ --exclude=EXCLUDE Path to file or directory to exclude from linting (multiple values allowed)
+ --extensions=EXTENSIONS Check only files with selected extensions (multiple values allowed)
+ -j, --jobs=JOBS Number of paralleled jobs to run
+ -c, --configuration=CONFIGURATION Read configuration from config file [default: ".phplint.yml"]
+ --no-configuration Ignore default configuration file (.phplint.yml)
+ --cache=CACHE Path to the cache directory
+ --no-cache Ignore cached data
+ -p, --progress=PROGRESS Show the progress output
+ --no-progress Hide the progress output
+ --log-json[=LOG-JSON] Log scan results in JSON format to file (default: standard output)
+ --log-junit[=LOG-JUNIT] Log scan results in JUnit XML format to file (default: standard output)
+ -w, --warning Also show warnings
+ --memory-limit=MEMORY-LIMIT Memory limit for analysis
+ --ignore-exit-code Ignore exit codes so there are no "failure" exit code even when no files processed
+ -h, --help Display help for the given command. When no command is given display help for the lint command
+ -q, --quiet Do not output any message
+ -V, --version Display this application version
+ --ansi|--no-ansi Force (or disable --no-ansi) ANSI output
+ -n, --no-interaction Do not ask any interactive question
+ -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
+```
diff --git a/docs/usage/docker.md b/docs/usage/docker.md
new file mode 100644
index 00000000..21746c51
--- /dev/null
+++ b/docs/usage/docker.md
@@ -0,0 +1,9 @@
+# Docker CLI
+
+```shell
+docker run --rm -t -v "${PWD}":/workdir overtrue/phplint:latest ./ --exclude=vendor --no-configuration --no-cache
+```
+
+> Please mount your source code to `/workdir` in the container.
+
+**IMPORTANT** : Docker image with `latest` tag use the PHP 8.2 runtime !
diff --git a/docs/usage/github-actions.md b/docs/usage/github-actions.md
new file mode 100644
index 00000000..64eee25b
--- /dev/null
+++ b/docs/usage/github-actions.md
@@ -0,0 +1,71 @@
+# GitHub Actions
+
+## Use case 1
+
+Quick start, if your PHP runtime set up is not important for you.
+
+```yaml
+jobs:
+ php-lint:
+ name: Linting with overtrue/phplint
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Lint PHP files
+
+ uses: overtrue/phplint@main
+ with:
+ path: .
+ options: --exclude=vendor
+```
+
+## Use case 2
+
+Otherwise, if you want to detect specific PHP features used by scripts depending of your PHP runtime, then use this case.
+
+```yaml
+jobs:
+ php-lint:
+ name: "Linting with overtrue/phplint"
+
+ runs-on: "${{ matrix.operating-system }}"
+
+ strategy:
+ fail-fast: false
+
+ matrix:
+ operating-system:
+ - "ubuntu-20.04"
+ - "ubuntu-22.04"
+
+ php-version:
+ - "8.1"
+ - "8.2"
+
+ steps:
+ - name: Checkout Code
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ repository: overtrue/phplint
+
+ - name: Setup PHP runtime
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: "${{ matrix.php-version }}"
+ coverage: "none"
+
+ - name: Lint PHP files
+ run: |
+ curl -Ls https://github.com/overtrue/phplint/releases/latest/download/phplint.phar -o /usr/local/bin/phplint
+ chmod +x /usr/local/bin/phplint
+ /usr/local/bin/phplint -vvv --no-cache
+```
+
+Follows steps:
+
+- retrieve source code to check with [actions/checkout](https://github.com/actions/checkout)
+- set up the PHP runtime you want to use with [shivammathur/setup-php](https://github.com/shivammathur/setup-php)
+- download the latest (or specific) version of the PHAR distribution
+- and finally run PHPLint as usual, with a YAML config file or console command options
diff --git a/docs/usage/gitlab-ci.md b/docs/usage/gitlab-ci.md
new file mode 100644
index 00000000..c54ca19c
--- /dev/null
+++ b/docs/usage/gitlab-ci.md
@@ -0,0 +1,10 @@
+# GitLab CI
+
+```yaml
+code-quality:lint-php:
+ image: overtrue/phplint:latest
+ variables:
+ INPUT_PATH: "./"
+ INPUT_OPTIONS: "-c .phplint.yml"
+ script: echo '' #prevents ci yml parse error
+```
diff --git a/docs/usage/other-ci.md b/docs/usage/other-ci.md
new file mode 100644
index 00000000..9f9fcb08
--- /dev/null
+++ b/docs/usage/other-ci.md
@@ -0,0 +1,7 @@
+# Other CI Pipelines
+
+Run this command using `overtrue/phplint:latest` Docker image:
+
+```shell
+/root/.composer/vendor/bin/phplint ./ --exclude=vendor
+```
diff --git a/docs/usage/programmatically.md b/docs/usage/programmatically.md
new file mode 100644
index 00000000..317e7d5e
--- /dev/null
+++ b/docs/usage/programmatically.md
@@ -0,0 +1,66 @@
+# Programmatically
+
+```php
+use Overtrue\PHPLint\Command\LintCommand;
+use Overtrue\PHPLint\Configuration\ConsoleOptionsResolver;
+use Overtrue\PHPLint\Event\EventDispatcher;
+use Overtrue\PHPLint\Finder;
+use Overtrue\PHPLint\Linter;
+use Symfony\Component\Console\Input\ArrayInput;
+
+$dispatcher = new EventDispatcher([]);
+
+$arguments = [
+ 'path' => [__DIR__ . '/src', __DIR__ . '/tests'],
+ '--no-configuration' => true,
+ '--no-cache' => true,
+ '--exclude' => ['vendor'],
+ '--extensions' => ['php'],
+ '--warning' => true,
+];
+$command = new LintCommand($dispatcher);
+$definition = $command->getDefinition();
+$input = new ArrayInput($arguments, $definition);
+
+$configResolver = new ConsoleOptionsResolver($input);
+
+$finder = new Finder($configResolver);
+
+$linter = new Linter($configResolver, $dispatcher);
+
+$results = $linter->lintFiles($finder->getFiles());
+
+var_dump($results->getErrors());
+/*
+ array(1) {
+ ["/absolute/path/to/tests/fixtures/syntax_error.php"]=>
+ array(4) {
+ ["absolute_file"]=>
+ string(62) "/absolute/path/to/tests/fixtures/syntax_error.php"
+ ["relative_file"]=>
+ string(25) "fixtures/syntax_error.php"
+ ["error"]=>
+ string(32) "unexpected end of file in line 4"
+ ["line"]=>
+ int(4)
+ }
+}
+ */
+
+var_dump($results->getWarnings());
+/*
+array(1) {
+ ["/absolute/path/to/tests/fixtures/syntax_warning.php"]=>
+ array(4) {
+ ["absolute_file"]=>
+ string(64) "/absolute/path/to/tests/fixtures/syntax_warning.php"
+ ["relative_file"]=>
+ string(27) "fixtures/syntax_warning.php"
+ ["error"]=>
+ string(97) " declare(encoding=...) ignored because Zend multibyte feature is turned off by settings in line 1"
+ ["line"]=>
+ int(1)
+ }
+}
+ */
+```
diff --git a/entrypoint.sh b/entrypoint.sh
index 0aada501..b4e3c22d 100755
--- a/entrypoint.sh
+++ b/entrypoint.sh
@@ -1,9 +1,13 @@
-#!/bin/sh -l
+#!/bin/sh
-set -ex
+[ "$APP_DEBUG" == 'true' ] && set -x
+set -e
-if [ ! -z "$INPUT_PATH" ]; then
- /root/.composer/vendor/bin/phplint $INPUT_PATH $INPUT_OPTIONS
-else
- sh -c "/root/.composer/vendor/bin/phplint $*"
-fi
\ No newline at end of file
+if [ "$APP_DEBUG" == 'true' ]
+then
+ echo "> You will act as user: $(id -u -n)"
+ echo "$(composer config --global --list)"
+ /bin/sh -c "ls -l $(composer config --global home)"
+fi
+
+"$(composer config --global home)/vendor/bin/phplint" $@
diff --git a/examples/empty_dir/.gitkeep b/examples/empty_dir/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/no-source-to-lint.php b/examples/no-source-to-lint.php
new file mode 100644
index 00000000..de929439
--- /dev/null
+++ b/examples/no-source-to-lint.php
@@ -0,0 +1,43 @@
+ [__DIR__ . '/empty_dir', __DIR__ . '/missing_dir'],
+ '--no-configuration' => true,
+];
+$command = new LintCommand($dispatcher);
+$input = new ArrayInput($arguments, $command->getDefinition());
+$configResolver = new ConsoleOptionsResolver($input);
+
+$finder = (new Finder($configResolver)); //->getFiles();
+$linter = new Linter($configResolver, $dispatcher);
+$results = $linter->lintFiles($finder->getFiles());
+
+var_dump("Files checked :", count($results));
+
+if (count($results) === 0) {
+ throw new LogicException(
+ sprintf("Could not find any files to lint with this Finder %s", json_encode($finder))
+ );
+}
diff --git a/examples/no-yaml-configuration.php b/examples/no-yaml-configuration.php
index 8f1447fb..962a9f75 100644
--- a/examples/no-yaml-configuration.php
+++ b/examples/no-yaml-configuration.php
@@ -1,5 +1,14 @@
getFiles();
$linter = new Linter($configResolver, $dispatcher);
+$results = $linter->lintFiles($finder);
-$results = $linter->lintFiles($finder->getFiles());
+var_dump("Files checked :", count($results));
var_dump("Errors detected :", $results->getErrors());
diff --git a/mkdocs.yml b/mkdocs.yml
index 89e90506..499fe1b7 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -27,16 +27,10 @@ markdown_extensions:
- pymdownx.highlight # https://squidfunk.github.io/mkdocs-material/setup/extensions/python-markdown-extensions/#highlight
- pymdownx.superfences # https://squidfunk.github.io/mkdocs-material/setup/extensions/python-markdown-extensions/#superfences
nav:
- - "Home": index.md
+ - "Home": README.md
- "Installation": installation.md
+ - "Usage": usage/README.md
- "Upgrading": upgrading.md
- "Configuration": configuration.md
- - "Architecture":
- - "Event-Driven": architecture/event.md
- - "Extension": architecture/extension.md
- - "Output (formats)": architecture/output.md
- - "Process": architecture/process.md
- - "Cache": architecture/cache.md
- - "Finder": architecture/finder.md
- - "Configuration": architecture/configuration.md
+ - "Architecture": architecture/README.md
- "Contributing": contributing.md
diff --git a/phpunit-9.xml b/phpunit-9.xml
new file mode 100644
index 00000000..868c8059
--- /dev/null
+++ b/phpunit-9.xml
@@ -0,0 +1,37 @@
+
+
+
+
+ tests/Cache
+
+
+ tests/Configuration
+
+
+ tests/EndToEnd
+
+
+ tests/Finder
+
+
+
+
+
+ src
+
+
+
diff --git a/phpunit.xml b/phpunit.xml
index 868c8059..4ce62f4f 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,18 +1,16 @@
+ cacheDirectory=".phpunit.cache"
+ requireCoverageMetadata="true"
+ beStrictAboutCoverageMetadata="true"
+>
tests/Cache
@@ -27,9 +25,7 @@
tests/Finder
-
-
+
src
diff --git a/src/Command/LintCommand.php b/src/Command/LintCommand.php
index aeca7793..1bb62255 100644
--- a/src/Command/LintCommand.php
+++ b/src/Command/LintCommand.php
@@ -28,6 +28,7 @@
use Symfony\Component\Finder\Finder as SymfonyFinder;
use Throwable;
+use function array_unshift;
use function count;
use function microtime;
@@ -64,13 +65,10 @@ protected function initialize(InputInterface $input, OutputInterface $output): v
{
// initializes correctly command and path arguments when lint is set as default command
$cmd = $input->getArgument('command');
-
- if ($cmd === $this->getName()) {
- $paths = $input->getArgument('path');
- } else {
- $paths = [$cmd];
+ $paths = $input->getArgument('path');
+ if ($cmd !== $this->getName()) {
+ array_unshift($paths, $cmd);
}
-
$input->setArgument('path', $paths);
$input->setArgument('command', $this->getName());
}
@@ -89,7 +87,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}
$finder = (new Finder($configResolver))->getFiles();
- $fileCount = count($finder);
/** @var Application $app */
$app = $this->getApplication();
$linter = new Linter($configResolver, $this->dispatcher, $app->getLongVersion());
@@ -101,7 +98,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return self::SUCCESS;
}
- if ($fileCount === 0 || count($data)) {
+ if (count($this->results) === 0 || count($data)) {
return self::FAILURE;
}
diff --git a/src/Configuration/AbstractOptionsResolver.php b/src/Configuration/AbstractOptionsResolver.php
index 59f0021d..755caa35 100644
--- a/src/Configuration/AbstractOptionsResolver.php
+++ b/src/Configuration/AbstractOptionsResolver.php
@@ -45,8 +45,8 @@ public function __construct(InputInterface $input, array $configuration = [])
OptionDefinition::NO_CACHE => false,
OptionDefinition::PROGRESS => OptionDefinition::DEFAULT_PROGRESS_WIDGET,
OptionDefinition::NO_PROGRESS => false,
- OptionDefinition::LOG_JSON => null,
- OptionDefinition::LOG_JUNIT => null,
+ OptionDefinition::LOG_JSON => false,
+ OptionDefinition::LOG_JUNIT => false,
OptionDefinition::WARNING => false,
OptionDefinition::OPTION_MEMORY_LIMIT => ini_get('memory_limit'),
OptionDefinition::IGNORE_EXIT_CODE => false,
@@ -76,6 +76,21 @@ public function __construct(InputInterface $input, array $configuration = [])
unset($options['warning']);
}
+ // log options that accept :
+ // - NULL or empty string are values considered to enable output format for standard output
+ // - a string to identify stream
+ $names = [
+ OptionDefinition::LOG_JSON,
+ OptionDefinition::LOG_JUNIT,
+ ];
+ foreach ($names as $name) {
+ if ('' === $options[$name]) {
+ $options[$name] = true;
+ } elseif (null === $options[$name] && (true === $input->hasParameterOption(['--' . $name], true))) {
+ $options[$name] = true;
+ }
+ }
+
// options that cannot be overridden by YAML config file values
$names = [
OptionDefinition::CONFIGURATION,
diff --git a/src/Configuration/OptionsFactory.php b/src/Configuration/OptionsFactory.php
index 43b9dcdf..e406c90e 100644
--- a/src/Configuration/OptionsFactory.php
+++ b/src/Configuration/OptionsFactory.php
@@ -13,10 +13,16 @@
namespace Overtrue\PHPLint\Configuration;
+use Closure;
use Symfony\Component\OptionsResolver\Options as SymfonyOptions;
use Symfony\Component\OptionsResolver\OptionsResolver;
use function array_keys;
+use function filter_var;
+use function in_array;
+use function is_bool;
+
+use const FILTER_VALIDATE_BOOLEAN;
/**
* @author Laurent Laville
@@ -52,8 +58,8 @@ protected function configureOptions(OptionsResolver $resolver): void
OptionDefinition::NO_CACHE => 'bool',
OptionDefinition::PROGRESS => ['null', 'string'],
OptionDefinition::NO_PROGRESS => 'bool',
- OptionDefinition::LOG_JSON => ['bool', 'null', 'string'],
- OptionDefinition::LOG_JUNIT => ['bool', 'null', 'string'],
+ OptionDefinition::LOG_JSON => ['bool', 'string'],
+ OptionDefinition::LOG_JUNIT => ['bool', 'string'],
OptionDefinition::WARNING => 'bool',
OptionDefinition::OPTION_MEMORY_LIMIT => ['int', 'string'],
OptionDefinition::IGNORE_EXIT_CODE => 'bool',
@@ -81,13 +87,49 @@ protected function configureOptions(OptionsResolver $resolver): void
return (int) $value;
});
- $outputFormat = function (SymfonyOptions $options, $value) {
- if (true === $value) {
- $value = OptionDefinition::DEFAULT_STANDARD_OUTPUT;
- }
- return $value;
- };
- $resolver->setNormalizer(OptionDefinition::LOG_JSON, $outputFormat);
- $resolver->setNormalizer(OptionDefinition::LOG_JUNIT, $outputFormat);
+ $names = [
+ OptionDefinition::LOG_JSON,
+ OptionDefinition::LOG_JUNIT,
+ ];
+ foreach ($names as $name) {
+ $resolver->setNormalizer($name, Closure::fromCallable([$this, 'logNormalizer']));
+ }
+ }
+
+ /**
+ * Reused by unit tests suite ConsoleConfigTest
+ */
+ public static function logNormalizer(SymfonyOptions $options, $value)
+ {
+ $bool = static::toBool($value);
+ if (is_bool($bool)) {
+ $value = $bool ? OptionDefinition::DEFAULT_STANDARD_OUTPUT : false;
+ }
+ return $value;
+ }
+
+ /**
+ * Best strategy to convert string to boolean
+ *
+ *
+ * @link https://stackoverflow.com/questions/7336861/how-to-convert-string-to-boolean-php#answer-15075609
+ * @link https://www.php.net/manual/en/function.filter-var
+ */
+ public static function toBool(mixed $value): bool|int
+ {
+ $booleanValueDomain = [
+ false, 'false', 0, '0', 'off', 'no',
+ true, 'true', 1, '1', 'on', 'yes',
+ ];
+
+ if (in_array($value, ['', null], true)) {
+ // CAUTION: null or empty string must be considered as logging to standard output (like true boolean value)
+ $out = true;
+ } elseif (in_array($value, $booleanValueDomain, true)) {
+ $out = filter_var($value, FILTER_VALIDATE_BOOLEAN);
+ } else {
+ $out = -1;
+ }
+ return $out;
}
}
diff --git a/src/Console/Application.php b/src/Console/Application.php
index d96b4ff1..0ffb521d 100644
--- a/src/Console/Application.php
+++ b/src/Console/Application.php
@@ -33,7 +33,7 @@
final class Application extends BaseApplication
{
public const NAME = 'phplint';
- public const VERSION = '9.0.3';
+ public const VERSION = '9.0.4';
public function __construct()
{
diff --git a/src/Finder.php b/src/Finder.php
index 6878f189..b290c4a1 100644
--- a/src/Finder.php
+++ b/src/Finder.php
@@ -14,6 +14,7 @@
namespace Overtrue\PHPLint;
use ArrayIterator;
+use JsonSerializable;
use Overtrue\PHPLint\Configuration\OptionDefinition;
use Overtrue\PHPLint\Configuration\Resolver;
use Symfony\Component\Finder\Finder as SymfonyFinder;
@@ -31,7 +32,7 @@
* @author Laurent Laville
* @since Release 9.0.0
*/
-final class Finder
+final class Finder implements JsonSerializable
{
private array $paths;
private array $excludes;
@@ -44,6 +45,15 @@ public function __construct(Resolver $configResolver)
$this->extensions = $configResolver->getOption(OptionDefinition::EXTENSIONS);
}
+ public function jsonSerialize(): array
+ {
+ return [
+ 'paths' => $this->paths,
+ 'excludes' => $this->excludes,
+ 'extensions' => $this->extensions,
+ ];
+ }
+
public function getFiles(): SymfonyFinder
{
$finder = new SymfonyFinder();
diff --git a/src/Linter.php b/src/Linter.php
index e0a24dce..5dfe03a3 100644
--- a/src/Linter.php
+++ b/src/Linter.php
@@ -13,6 +13,7 @@
namespace Overtrue\PHPLint;
+use LogicException;
use Overtrue\PHPLint\Configuration\OptionDefinition;
use Overtrue\PHPLint\Configuration\Resolver;
use Overtrue\PHPLint\Event\AfterCheckingEvent;
@@ -80,61 +81,72 @@ public function lintFiles(Finder $finder, ?float $startTime = null): LinterOutpu
$startTime = microtime(true);
}
+ try {
+ $fileCount = count($finder);
+ } catch (LogicException) {
+ $fileCount = 0;
+ }
+
$this->dispatcher->dispatch(
new BeforeCheckingEvent(
$this,
- ['fileCount' => count($finder), 'appVersion' => $this->appLongVersion, 'options' => $this->options]
+ ['fileCount' => $fileCount, 'appVersion' => $this->appLongVersion, 'options' => $this->options]
)
);
- $pid = 0;
- $processRunning = [];
- $iterator = $finder->getIterator();
-
- while ($iterator->valid() || !empty($processRunning)) {
- for ($i = count($processRunning); $iterator->valid() && $i < $this->processLimit; ++$i) {
- $fileInfo = $iterator->current();
- $this->dispatcher->dispatch(new BeforeLintFileEvent($this, ['file' => $fileInfo]));
- $filename = $fileInfo->getRealPath();
-
- if ($this->cache->isHit($filename)) {
- $this->results['hits'][] = $filename;
- } else {
- $lintProcess = $this->createLintProcess($filename);
- $lintProcess->start();
-
- ++$pid;
- $processRunning[$pid] = [
- 'process' => $lintProcess,
- 'file' => $fileInfo,
- ];
- $this->results['misses'][] = $filename;
+ if ($fileCount > 0) {
+ $pid = 0;
+ $processRunning = [];
+ $iterator = $finder->getIterator();
+
+ while ($iterator->valid() || !empty($processRunning)) {
+ for ($i = count($processRunning); $iterator->valid() && $i < $this->processLimit; ++$i) {
+ $fileInfo = $iterator->current();
+ $this->dispatcher->dispatch(new BeforeLintFileEvent($this, ['file' => $fileInfo]));
+ $filename = $fileInfo->getRealPath();
+
+ if ($this->cache->isHit($filename)) {
+ $this->results['hits'][] = $filename;
+ } else {
+ $lintProcess = $this->createLintProcess($filename);
+ $lintProcess->start();
+
+ ++$pid;
+ $processRunning[$pid] = [
+ 'process' => $lintProcess,
+ 'file' => $fileInfo,
+ ];
+ $this->results['misses'][] = $filename;
+ }
+
+ $iterator->next();
}
- $iterator->next();
- }
-
- foreach ($processRunning as $pid => $item) {
- /** @var LintProcess $lintProcess */
- $lintProcess = $item['process'];
- if ($lintProcess->isRunning()) {
- continue;
+ foreach ($processRunning as $pid => $item) {
+ /** @var LintProcess $lintProcess */
+ $lintProcess = $item['process'];
+ if ($lintProcess->isRunning()) {
+ continue;
+ }
+ /** @var SplFileInfo $fileInfo */
+ $fileInfo = $item['file'];
+ $status = $this->processFile($fileInfo, $lintProcess);
+
+ unset($processRunning[$pid]);
+ $this->dispatcher->dispatch(new AfterLintFileEvent($this, ['file' => $fileInfo, 'status' => $status]));
}
- /** @var SplFileInfo $fileInfo */
- $fileInfo = $item['file'];
- $status = $this->processFile($fileInfo, $lintProcess);
-
- unset($processRunning[$pid]);
- $this->dispatcher->dispatch(new AfterLintFileEvent($this, ['file' => $fileInfo, 'status' => $status]));
}
- }
- $results = new LinterOutput($this->results, $finder);
- $results->setContext($this->configResolver, $startTime);
+ $results = $this->results;
+ } else {
+ $results = [];
+ }
+ $finalResults = new LinterOutput($results, $finder);
+ $finalResults->setContext($this->configResolver, $startTime);
- $this->dispatcher->dispatch(new AfterCheckingEvent($this, ['results' => $results]));
+ $this->dispatcher->dispatch(new AfterCheckingEvent($this, ['results' => $finalResults]));
- return $results;
+ return $finalResults;
}
private function processFile(SplFileInfo $fileInfo, LintProcess $lintProcess): string
diff --git a/src/Output/ConsoleOutput.php b/src/Output/ConsoleOutput.php
index bd326c53..91e7df9d 100644
--- a/src/Output/ConsoleOutput.php
+++ b/src/Output/ConsoleOutput.php
@@ -57,10 +57,12 @@
* @author Laurent Laville
* @since Release 9.0.0
*/
-final class ConsoleOutput extends BaseConsoleOutput implements OutputInterface
+class ConsoleOutput extends BaseConsoleOutput implements OutputInterface
{
public const MAX_LINE_LENGTH = 120;
+ public const NO_FILE_TO_LINT = 'Could not find any files to lint';
+
private ?ProgressBar $progressBar = null;
private int $lineLength;
@@ -335,7 +337,7 @@ public function successBlock(int $fileCount): void
$style->success($message);
}
- public function warningBlock(string $message = 'Could not find files to lint'): void
+ public function warningBlock(string $message = self::NO_FILE_TO_LINT): void
{
$style = new SymfonyStyle(new ArrayInput([]), $this);
$style->warning($message);
diff --git a/src/Output/LinterOutput.php b/src/Output/LinterOutput.php
index bb0984d7..c35c01b0 100644
--- a/src/Output/LinterOutput.php
+++ b/src/Output/LinterOutput.php
@@ -13,6 +13,8 @@
namespace Overtrue\PHPLint\Output;
+use Countable;
+use LogicException;
use Overtrue\PHPLint\Configuration\Resolver;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Finder\Finder;
@@ -27,7 +29,7 @@
* @author Laurent Laville
* @since Release 9.0.0
*/
-final class LinterOutput
+final class LinterOutput implements Countable
{
private Finder $finder;
private array $context;
@@ -45,6 +47,11 @@ public function __construct(array $results, Finder $finder)
$this->misses = $results['misses'] ?? [];
}
+ public function count(): int
+ {
+ return count($this->hits) + count($this->misses);
+ }
+
public function getContext(): array
{
return $this->context;
@@ -65,11 +72,17 @@ public function setContext(Resolver $configResolver, float $startTime): void
$cacheMisses > 1 ? 'es' : ''
);
+ try {
+ $fileCount = count($this->finder);
+ } catch (LogicException) {
+ $fileCount = 0;
+ }
+
$this->context = [
'time_usage' => $timeUsage,
'memory_usage' => $memUsage,
'cache_usage' => $cacheUsage,
- 'files_count' => count($this->finder),
+ 'files_count' => $fileCount,
'options_used' => $configResolver->getOptions(),
];
}
diff --git a/tests/Configuration/ConsoleConfigTest.php b/tests/Configuration/ConsoleConfigTest.php
index 7174fa8d..a94865b7 100644
--- a/tests/Configuration/ConsoleConfigTest.php
+++ b/tests/Configuration/ConsoleConfigTest.php
@@ -16,13 +16,15 @@
use Overtrue\PHPLint\Command\LintCommand;
use Overtrue\PHPLint\Configuration\ConsoleOptionsResolver;
use Overtrue\PHPLint\Configuration\OptionDefinition;
+use Overtrue\PHPLint\Configuration\OptionsFactory;
use Overtrue\PHPLint\Configuration\Resolver;
use Overtrue\PHPLint\Event\EventDispatcher;
use Overtrue\PHPLint\Tests\TestCase;
use Symfony\Component\Console\Input\ArrayInput;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+
use function dirname;
-use function is_string;
use function realpath;
final class ConsoleConfigTest extends TestCase
@@ -63,11 +65,20 @@ public static function commandInputProvider(): array
return [
'only default values' => [[], __CLASS__ . '::expectedOnlyDefaults'],
'only path modified' => [['path' => dirname(__DIR__)], __CLASS__ . '::expectedPathModified'],
+ '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' => [['--log-json' => null], __CLASS__ . '::expectedJsonOutputFormat'],
+ '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' => [['--log-junit' => true], __CLASS__ . '::expectedXmlOutputFormat'],
+ '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'],
];
}
@@ -80,7 +91,7 @@ protected static function expectedOnlyDefaults(Resolver $resolver): array
protected static function expectedPathModified(Resolver $resolver, array $arguments): array
{
$expected = self::getExpectedValues($resolver);
- $expected['path'] = [$arguments['path']];
+ $expected['path'] = (array) $arguments['path'];
return $expected;
}
@@ -98,7 +109,7 @@ protected static function expectedJsonOutputFormat(Resolver $resolver, array $ar
{
$expected = self::getExpectedValues($resolver);
$logJson = $arguments['--log-json'];
- $expected['log-json'] = (is_string($logJson)) ? $logJson : (empty($logJson) ? null : 'php://stdout');
+ $expected['log-json'] = OptionsFactory::logNormalizer(new OptionsResolver(), $logJson);
return $expected;
}
@@ -106,7 +117,7 @@ protected static function expectedXmlOutputFormat(Resolver $resolver, array $arg
{
$expected = self::getExpectedValues($resolver);
$logJunit = $arguments['--log-junit'];
- $expected['log-junit'] = (is_string($logJunit)) ? $logJunit : (empty($logJunit) ? null : 'php://stdout');
+ $expected['log-junit'] = OptionsFactory::logNormalizer(new OptionsResolver(), $logJunit);
return $expected;
}
diff --git a/tests/Configuration/YamlConfigTest.php b/tests/Configuration/YamlConfigTest.php
index a59ae0b7..977e6e72 100644
--- a/tests/Configuration/YamlConfigTest.php
+++ b/tests/Configuration/YamlConfigTest.php
@@ -15,6 +15,8 @@
use Overtrue\PHPLint\Command\LintCommand;
use Overtrue\PHPLint\Configuration\FileOptionsResolver;
+use Overtrue\PHPLint\Configuration\OptionDefinition;
+use Overtrue\PHPLint\Configuration\OptionsFactory;
use Overtrue\PHPLint\Configuration\Resolver;
use Overtrue\PHPLint\Event\EventDispatcher;
use Overtrue\PHPLint\Tests\TestCase;
@@ -88,17 +90,17 @@ protected static function expectedJobsModified(Resolver $resolver): array
return $expected;
}
- protected static function expectedJsonOutputFormat(Resolver $resolver): array
+ protected static function expectedJsonOutputFormat(Resolver $resolver, array $arguments): array
{
$expected = self::getExpectedValues($resolver);
- $expected['log-json'] = 'php://stdout'; // see 'log-json.yaml' contents
+ $expected['log-json'] = OptionDefinition::DEFAULT_STANDARD_OUTPUT; // see 'log-json.yaml' contents
return $expected;
}
- protected static function expectedXmlOutputFormat(Resolver $resolver): array
+ 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['log-junit'] = '/tmp/phplint-results.xml'; // see 'log-junit.yaml' contents
return $expected;
}
diff --git a/tests/Finder/FinderTest.php b/tests/Finder/FinderTest.php
index 83d80de5..6fa8b702 100644
--- a/tests/Finder/FinderTest.php
+++ b/tests/Finder/FinderTest.php
@@ -14,6 +14,7 @@
namespace Overtrue\PHPLint\Tests\Finder;
use Iterator;
+use LogicException;
use Overtrue\PHPLint\Command\LintCommand;
use Overtrue\PHPLint\Configuration\ConsoleOptionsResolver;
use Overtrue\PHPLint\Configuration\OptionDefinition;
@@ -61,6 +62,30 @@ public function testAllPhpFilesFoundShouldExists(): void
}
}
+ /**
+ * @covers \Overtrue\PHPLint\Finder::getFiles
+ */
+ public function testAllPathShouldExistsAndReadable(): void
+ {
+ $this->expectException(LogicException::class);
+
+ $dispatcher = new EventDispatcher([]);
+
+ $basePath = dirname(__DIR__) . '/fixtures/missing_dir';
+
+ $arguments = [
+ OptionDefinition::PATH => [$basePath],
+ '--no-configuration' => true,
+ ];
+ $definition = (new LintCommand($dispatcher))->getDefinition();
+ $input = new ArrayInput($arguments, $definition);
+
+ $configResolver = new ConsoleOptionsResolver($input);
+
+ $finder = new Finder($configResolver);
+ count($finder->getFiles());
+ }
+
/**
* @covers \Overtrue\PHPLint\Finder::getFiles
*/
diff --git a/tests/fixtures/php-8.1_syntax.php b/tests/fixtures/php-8.1_syntax.php
new file mode 100644
index 00000000..7ef9146f
--- /dev/null
+++ b/tests/fixtures/php-8.1_syntax.php
@@ -0,0 +1,18 @@
+