diff --git a/.dependabot/config.yml b/.dependabot/config.yml index a3bd09e6..2d68a999 100644 --- a/.dependabot/config.yml +++ b/.dependabot/config.yml @@ -3,7 +3,13 @@ version: 1 update_configs: - - default_assignees: + - automerged_updates: + - match: + dependency_type: "development" + commit_message: + include_scope: true + prefix: "Build" + default_assignees: - "localheinz" default_labels: - "dependency" diff --git a/.gitattributes b/.gitattributes index 7d7a5306..36d16720 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,10 +1,13 @@ -/.dependabot/ export-ignore -/.github/ export-ignore -/test/ export-ignore -/.editorconfig export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore -/.php_cs export-ignore -/infection.json export-ignore -/Makefile export-ignore -/phpstan.neon export-ignore +/.dependabot/ export-ignore +/.github/ export-ignore +/test/ export-ignore +/.editorconfig export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.php_cs export-ignore +/infection.json export-ignore +/Makefile export-ignore +/phpstan-baseline.neon export-ignore +/phpstan.neon export-ignore +/psalm-baseline.xml export-ignore +/psalm.xml export-ignore diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index ceddbcd7..285ab618 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -30,7 +30,7 @@ to run a dependency analysis. ## Static Code Analysis -We are using [`phpstan/phpstan`](https://github.com/phpstan/phpstan) to statically analyze the code. +We are using [`phpstan/phpstan`](https://github.com/phpstan/phpstan) and [`vimeo/psalm`](https://github.com/vimeo/psalm) to statically analyze the code. Run @@ -40,7 +40,7 @@ $ make static-code-analysis to run a static code analysis. -We are also using the [baseline feature](https://medium.com/@ondrejmirtes/phpstans-baseline-feature-lets-you-hold-new-code-to-a-higher-standard-e77d815a5dff) of [`phpstan/phpstan`](https://github.com/phpstan/phpstan). +We are also using the baseline features of [`phpstan/phpstan`(https://medium.com/@ondrejmirtes/phpstans-baseline-feature-lets-you-hold-new-code-to-a-higher-standard-e77d815a5dff) and [`vimeo/psalm`](https://psalm.dev/docs/running_psalm/dealing_with_code_issues/#using-a-baseline-file). Run @@ -48,9 +48,9 @@ Run $ make static-code-analysis-baseline ``` -to regenerate the baseline in [`../phpstan-baseline.neon`](../phpstan-baseline.neon). +to regenerate the baselines in [`../phpstan-baseline.neon`](../phpstan-baseline.neon) and [`../psalm-baseline.xml`](../psalm-baseline.xml). -:exclamation: Ideally, the baseline should shrink over time. +:exclamation: Ideally, the baselines should shrink over time. ## Tests diff --git a/.github/settings.yml b/.github/settings.yml index 0b690670..59733b4b 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -1,7 +1,11 @@ # https://github.com/probot/settings branches: - - name: master + - name: "master" + + # https://developer.github.com/v3/repos/branches/#remove-branch-protection + # https://developer.github.com/v3/repos/branches/#update-branch-protection + protection: enforce_admins: false required_pull_request_reviews: @@ -30,26 +34,41 @@ branches: - "codecov/patch" - "codecov/project" strict: false - restrictions: null + restrictions: + apps: + - "dependabot-preview" + teams: [] + users: [] + +# https://developer.github.com/v3/issues/labels/#create-a-label +# https://developer.github.com/v3/issues/labels/#update-a-label labels: - - name: bug - color: ee0701 + - name: "bug" + color: "#ee0701" + description: "" - - name: dependency - color: 0366d6 + - name: "dependency" + color: "#0366d6" + description: "" - - name: enhancement - color: 0e8a16 + - name: "enhancement" + color: "#0e8a16" + description: "" - - name: question - color: cc317c + - name: "question" + color: "#cc317c" + description: "" - - name: security - color: ee0701 + - name: "security" + color: "#ee0701" + description: "" - - name: stale - color: eeeeee + - name: "stale" + color: "#eeeeee" + description: "" + +# https://developer.github.com/v3/repos/#edit repository: allow_merge_commit: true @@ -62,5 +81,9 @@ repository: has_pages: false has_projects: false has_wiki: false - name: php-cs-fixer-config + name: "php-cs-fixer-config" private: false + + # https://developer.github.com/v3/repos/branches/#remove-branch-protection + + topics: "php-cs-fixer, configuration" diff --git a/.github/workflows/approve.yml b/.github/workflows/approve.yml new file mode 100644 index 00000000..cb33191e --- /dev/null +++ b/.github/workflows/approve.yml @@ -0,0 +1,19 @@ +# https://help.github.com/en/categories/automating-your-workflow-with-github-actions + +name: "Approve" + +on: + - "pull_request" + +jobs: + approve: + name: "Approve" + + runs-on: "ubuntu-latest" + + steps: + - name: "Approve" + uses: "hmarr/auto-approve-action@v2.0.0" + if: "(github.actor == 'dependabot[bot]' || github.actor == 'dependabot-preview[bot]') && startsWith(github.event.pull_request.title, 'Build(deps-dev)')" + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/continuous-deployment.yml b/.github/workflows/continuous-deployment.yml new file mode 100644 index 00000000..b91f7d58 --- /dev/null +++ b/.github/workflows/continuous-deployment.yml @@ -0,0 +1,29 @@ +# https://help.github.com/en/categories/automating-your-workflow-with-github-actions + +name: "Continuous Deployment" + +on: + push: + tags: + - "**" + +jobs: + release: + name: "Release" + + runs-on: "ubuntu-latest" + + steps: + - name: "Determine tag" + id: "determine-tag" + run: "echo \"::set-output name=tag::${GITHUB_REF#refs/tags/}\"" + + - name: "Create release" + uses: "actions/create-release@v1.0.0" + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + with: + draft: false + prerelease: false + release_name: "${{ steps.determine-tag.outputs.tag }}" + tag_name: "${{ steps.determine-tag.outputs.tag }}" diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index ad6a2d9c..ab3ca7ba 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -1,285 +1,335 @@ # https://help.github.com/en/categories/automating-your-workflow-with-github-actions +name: "Continuous Integration" + on: pull_request: push: branches: - - master - tags: - - "**" + - "master" -name: "Continuous Integration" +env: + MIN_COVERED_MSI: 100 + MIN_MSI: 100 + REQUIRED_PHP_EXTENSIONS: "mbstring" jobs: coding-standards: name: "Coding Standards" - runs-on: ubuntu-latest + runs-on: "ubuntu-latest" strategy: matrix: php-version: - - 7.1 + - "7.1" dependencies: - - locked + - "locked" steps: - name: "Checkout" - uses: actions/checkout@v2.0.0 + uses: "actions/checkout@v2.0.0" - name: "Install PHP with extensions" - uses: shivammathur/setup-php@1.6.1 + uses: "shivammathur/setup-php@1.7.0" with: - coverage: none - extensions: "mbstring" - php-version: ${{ matrix.php-version }} + coverage: "none" + extensions: "${{ env.REQUIRED_PHP_EXTENSIONS }}" + php-version: "${{ matrix.php-version }}" - name: "Validate composer.json and composer.lock" - run: composer validate --strict + run: "composer validate --strict" - name: "Cache dependencies installed with composer" - uses: actions/cache@v1.0.3 + uses: "actions/cache@v1.0.3" with: - path: ~/.composer/cache - key: php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('**/composer.lock') }} - restore-keys: | - php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}- + path: "~/.composer/cache" + key: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('**/composer.lock') }}" + restore-keys: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" + + - name: "Install lowest dependencies with composer" + if: "matrix.dependencies == 'lowest'" + run: "composer update --no-interaction --no-progress --no-suggest --prefer-lowest" - name: "Install locked dependencies with composer" - run: composer install --no-interaction --no-progress --no-suggest + if: "matrix.dependencies == 'locked'" + run: "composer install --no-interaction --no-progress --no-suggest" + + - name: "Install highest dependencies with composer" + if: "matrix.dependencies == 'highest'" + run: "composer update --no-interaction --no-progress --no-suggest" - name: "Run ergebnis/composer-normalize" - run: composer normalize --dry-run + run: "composer normalize --dry-run" - name: "Create cache directory for friendsofphp/php-cs-fixer" - run: mkdir -p .build/php-cs-fixer + run: "mkdir -p .build/php-cs-fixer" - name: "Cache cache directory for friendsofphp/php-cs-fixer" - uses: actions/cache@v1.0.3 + uses: "actions/cache@v1.0.3" with: - path: .build/php-cs-fixer - key: php-${{ matrix.php-version }}-php-cs-fixer-${{ hashFiles('**/composer.lock') }} - restore-keys: | - php-${{ matrix.php-version }}-php-cs-fixer- + path: ".build/php-cs-fixer" + key: "php-${{ matrix.php-version }}-php-cs-fixer-${{ hashFiles('**/composer.lock') }}" + restore-keys: "php-${{ matrix.php-version }}-php-cs-fixer-" - name: "Run friendsofphp/php-cs-fixer" - run: vendor/bin/php-cs-fixer fix --config=.php_cs --diff --diff-format=udiff --dry-run --verbose + run: "vendor/bin/php-cs-fixer fix --config=.php_cs --diff --diff-format=udiff --dry-run --verbose" dependency-analysis: name: "Dependency Analysis" - runs-on: ubuntu-latest + runs-on: "ubuntu-latest" strategy: matrix: php-version: - - 7.4 + - "7.4" dependencies: - - locked + - "locked" steps: - name: "Checkout" - uses: actions/checkout@v2.0.0 + uses: "actions/checkout@v2.0.0" - name: "Install PHP with extensions" - uses: shivammathur/setup-php@1.6.1 + uses: "shivammathur/setup-php@1.7.0" with: - coverage: none - extensions: "mbstring" - php-version: ${{ matrix.php-version }} + coverage: "none" + extensions: "${{ env.REQUIRED_PHP_EXTENSIONS }}" + php-version: "${{ matrix.php-version }}" - name: "Cache dependencies installed with composer" - uses: actions/cache@v1.0.3 + uses: "actions/cache@v1.0.3" with: - path: ~/.composer/cache - key: php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('**/composer.lock') }} - restore-keys: | - php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}- + path: "~/.composer/cache" + key: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('**/composer.lock') }}" + restore-keys: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" + + - name: "Install lowest dependencies with composer" + if: "matrix.dependencies == 'lowest'" + run: "composer update --no-interaction --no-progress --no-suggest --prefer-lowest" - name: "Install locked dependencies with composer" - run: composer install --no-interaction --no-progress --no-suggest + if: "matrix.dependencies == 'locked'" + run: "composer install --no-interaction --no-progress --no-suggest" + + - name: "Install highest dependencies with composer" + if: "matrix.dependencies == 'highest'" + run: "composer update --no-interaction --no-progress --no-suggest" - name: "Run maglnet/composer-require-checker" - uses: docker://webfactory/composer-require-checker:2.0.0 + uses: "docker://webfactory/composer-require-checker:2.0.0" static-code-analysis: name: "Static Code Analysis" - runs-on: ubuntu-latest + runs-on: "ubuntu-latest" strategy: matrix: php-version: - - 7.4 + - "7.4" dependencies: - - locked + - "locked" steps: - name: "Checkout" - uses: actions/checkout@v2.0.0 + uses: "actions/checkout@v2.0.0" - name: "Install PHP with extensions" - uses: shivammathur/setup-php@1.6.1 + uses: "shivammathur/setup-php@1.7.0" with: - coverage: none - extensions: "mbstring" - php-version: ${{ matrix.php-version }} + coverage: "none" + extensions: "${{ env.REQUIRED_PHP_EXTENSIONS }}" + php-version: "${{ matrix.php-version }}" - name: "Cache dependencies installed with composer" - uses: actions/cache@v1.0.3 + uses: "actions/cache@v1.0.3" with: - path: ~/.composer/cache - key: ${{ matrix.php-version }}-composer-locked-${{ hashFiles('**/composer.lock') }} - restore-keys: | - ${{ matrix.php-version }}-composer-locked- + path: "~/.composer/cache" + key: "${{ matrix.php-version }}-composer-locked-${{ hashFiles('**/composer.lock') }}" + restore-keys: "${{ matrix.php-version }}-composer-locked-" + + - name: "Install lowest dependencies with composer" + if: "matrix.dependencies == 'lowest'" + run: "composer update --no-interaction --no-progress --no-suggest --prefer-lowest" - name: "Install locked dependencies with composer" - run: composer install --no-interaction --no-progress --no-suggest + if: "matrix.dependencies == 'locked'" + run: "composer install --no-interaction --no-progress --no-suggest" + + - name: "Install highest dependencies with composer" + if: "matrix.dependencies == 'highest'" + run: "composer update --no-interaction --no-progress --no-suggest" + + - name: "Create cache directory for phpstan/phpstan" + run: "mkdir -p .build/phpstan" - name: "Run phpstan/phpstan" - run: vendor/bin/phpstan analyse --configuration=phpstan.neon + run: "vendor/bin/phpstan analyse --configuration=phpstan.neon" + + - name: "Create cache directory for vimeo/psalm" + run: "mkdir -p .build/psalm" + + - name: "Run vimeo/psalm" + run: "vendor/bin/psalm --config=psalm.xml" tests: name: "Tests" - runs-on: ubuntu-latest + runs-on: "ubuntu-latest" strategy: matrix: php-version: - - 7.1 - - 7.2 - - 7.3 - - 7.4 + - "7.1" + - "7.2" + - "7.3" + - "7.4" dependencies: - - lowest - - locked - - highest + - "lowest" + - "locked" + - "highest" steps: - name: "Checkout" - uses: actions/checkout@v2.0.0 + uses: "actions/checkout@v2.0.0" - name: "Install PHP with extensions" - uses: shivammathur/setup-php@1.6.1 + uses: "shivammathur/setup-php@1.7.0" with: - coverage: none - extensions: "mbstring" - php-version: ${{ matrix.php-version }} + coverage: "none" + extensions: "${{ env.REQUIRED_PHP_EXTENSIONS }}" + php-version: "${{ matrix.php-version }}" - name: "Cache dependencies installed with composer" - uses: actions/cache@v1.0.3 + uses: "actions/cache@v1.0.3" with: - path: ~/.composer/cache - key: php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('**/composer.lock') }} - restore-keys: | - php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}- + path: "~/.composer/cache" + key: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('**/composer.lock') }}" + restore-keys: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" - name: "Install lowest dependencies with composer" - if: matrix.dependencies == 'lowest' - run: composer update --no-interaction --no-progress --no-suggest --prefer-lowest + if: "matrix.dependencies == 'lowest'" + run: "composer update --no-interaction --no-progress --no-suggest --prefer-lowest" - name: "Install locked dependencies with composer" - if: matrix.dependencies == 'locked' - run: composer install --no-interaction --no-progress --no-suggest + if: "matrix.dependencies == 'locked'" + run: "composer install --no-interaction --no-progress --no-suggest" - name: "Install highest dependencies with composer" - if: matrix.dependencies == 'highest' - run: composer update --no-interaction --no-progress --no-suggest + if: "matrix.dependencies == 'highest'" + run: "composer update --no-interaction --no-progress --no-suggest" - name: "Run auto-review tests with phpunit/phpunit" - run: vendor/bin/phpunit --configuration=test/AutoReview/phpunit.xml + run: "vendor/bin/phpunit --configuration=test/AutoReview/phpunit.xml" - name: "Run unit tests with phpunit/phpunit" - run: vendor/bin/phpunit --configuration=test/Unit/phpunit.xml + run: "vendor/bin/phpunit --configuration=test/Unit/phpunit.xml" - name: "Run integration tests with phpunit/phpunit" - run: vendor/bin/phpunit --configuration=test/Integration/phpunit.xml + run: "vendor/bin/phpunit --configuration=test/Integration/phpunit.xml" code-coverage: name: "Code Coverage" - runs-on: ubuntu-latest + runs-on: "ubuntu-latest" strategy: matrix: php-version: - - 7.4 + - "7.4" dependencies: - - locked + - "locked" steps: - name: "Checkout" - uses: actions/checkout@v2.0.0 + uses: "actions/checkout@v2.0.0" - name: "Install PHP with extensions" - uses: shivammathur/setup-php@1.6.1 + uses: "shivammathur/setup-php@1.7.0" with: - coverage: xdebug - extensions: "mbstring" - php-version: ${{ matrix.php-version }} + coverage: "xdebug" + extensions: "${{ env.REQUIRED_PHP_EXTENSIONS }}" + php-version: "${{ matrix.php-version }}" - name: "Cache dependencies installed with composer" - uses: actions/cache@v1.0.3 + uses: "actions/cache@v1.0.3" with: - path: ~/.composer/cache - key: php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('**/composer.lock') }} - restore-keys: | - php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}- + path: "~/.composer/cache" + key: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('**/composer.lock') }}" + restore-keys: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" + + - name: "Install lowest dependencies with composer" + if: "matrix.dependencies == 'lowest'" + run: "composer update --no-interaction --no-progress --no-suggest --prefer-lowest" - name: "Install locked dependencies with composer" - run: composer install --no-interaction --no-progress --no-suggest + if: "matrix.dependencies == 'locked'" + run: "composer install --no-interaction --no-progress --no-suggest" + + - name: "Install highest dependencies with composer" + if: "matrix.dependencies == 'highest'" + run: "composer update --no-interaction --no-progress --no-suggest" - name: "Dump Xdebug filter with phpunit/phpunit" - run: vendor/bin/phpunit --configuration=test/Unit/phpunit.xml --dump-xdebug-filter=.build/phpunit/xdebug-filter.php + run: "vendor/bin/phpunit --configuration=test/Unit/phpunit.xml --dump-xdebug-filter=.build/phpunit/xdebug-filter.php" - name: "Collect code coverage with Xdebug and phpunit/phpunit" - run: vendor/bin/phpunit --configuration=test/Unit/phpunit.xml --coverage-clover=build/logs/clover.xml --prepend=.build/phpunit/xdebug-filter.php + run: "vendor/bin/phpunit --configuration=test/Unit/phpunit.xml --coverage-clover=build/logs/clover.xml --prepend=.build/phpunit/xdebug-filter.php" - name: "Send code coverage report to Codecov.io" env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - run: bash <(curl -s https://codecov.io/bash) + CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}" + run: "bash <(curl -s https://codecov.io/bash)" mutation-tests: name: "Mutation Tests" - runs-on: ubuntu-latest + runs-on: "ubuntu-latest" strategy: matrix: php-version: - - 7.4 + - "7.4" dependencies: - - locked + - "locked" steps: - name: "Checkout" - uses: actions/checkout@v2.0.0 + uses: "actions/checkout@v2.0.0" - name: "Install PHP with extensions" - uses: shivammathur/setup-php@1.6.1 + uses: "shivammathur/setup-php@1.7.0" with: - coverage: xdebug - extensions: "mbstring" - php-version: ${{ matrix.php-version }} + coverage: "xdebug" + extensions: "${{ env.REQUIRED_PHP_EXTENSIONS }}" + php-version: "${{ matrix.php-version }}" - name: "Cache dependencies installed with composer" - uses: actions/cache@v1.0.3 + uses: "actions/cache@v1.0.3" with: - path: ~/.composer/cache - key: php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('**/composer.lock') }} - restore-keys: | - php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}- + path: "~/.composer/cache" + key: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('**/composer.lock') }}" + restore-keys: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" + + - name: "Install lowest dependencies with composer" + if: "matrix.dependencies == 'lowest'" + run: "composer update --no-interaction --no-progress --no-suggest --prefer-lowest" - name: "Install locked dependencies with composer" - run: composer install --no-interaction --no-progress --no-suggest + if: "matrix.dependencies == 'locked'" + run: "composer install --no-interaction --no-progress --no-suggest" + + - name: "Install highest dependencies with composer" + if: "matrix.dependencies == 'highest'" + run: "composer update --no-interaction --no-progress --no-suggest" - name: "Run mutation tests with Xdebug and infection/infection" - run: vendor/bin/infection --ignore-msi-with-no-mutations --min-covered-msi=100 --min-msi=100 + run: "vendor/bin/infection --ignore-msi-with-no-mutations --min-covered-msi=${{ env.MIN_COVERED_MSI }} --min-msi=${{ env.MIN_MSI }}" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 8125fd9e..582d147a 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,6 +1,6 @@ # https://github.com/actions/stale -name: "Close stale issues and pull requests" +name: "Stale" on: schedule: @@ -8,20 +8,22 @@ on: jobs: stale: - runs-on: ubuntu-latest + runs-on: "ubuntu-latest" + steps: - - uses: actions/stale@v1 + - name: "Close stale issues and pull requests" + uses: "actions/stale@v1.1.0" with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - days-before-stale: 60 days-before-close: 5 + days-before-stale: 60 + repo-token: "${{ secrets.GITHUB_TOKEN }}" stale-issue-label: 'stale' stale-issue-message: > This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. + stale-pr-label: "stale" stale-pr-message: > This PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. - stale-pr-label: 'stale' diff --git a/Makefile b/Makefile index 950cf82a..3e8f8d78 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,13 @@ +MIN_COVERED_MSI:=100 +MIN_MSI:=100 + .PHONY: it it: coding-standards dependency-analysis static-code-analysis tests ## Runs the coding-standards, dependency-analysis, static-code-analysis, and tests targets .PHONY: code-coverage code-coverage: vendor ## Collects coverage from running unit tests with phpunit/phpunit - vendor/bin/phpunit --configuration=test/Unit/phpunit.xml --coverage-text + vendor/bin/phpunit --configuration=test/Unit/phpunit.xml --dump-xdebug-filter=.build/phpunit/xdebug-filter.php + vendor/bin/phpunit --configuration=test/Unit/phpunit.xml --coverage-text --prepend=.build/phpunit/xdebug-filter.php .PHONY: coding-standards coding-standards: vendor ## Fixes code style issues with friendsofphp/php-cs-fixer @@ -21,18 +25,22 @@ help: ## Displays this list of targets with descriptions .PHONY: mutation-tests mutation-tests: vendor ## Runs mutation tests with infection/infection mkdir -p .build/infection - vendor/bin/infection --ignore-msi-with-no-mutations --min-covered-msi=100 --min-msi=100 + vendor/bin/infection --ignore-msi-with-no-mutations --min-covered-msi=${MIN_COVERED_MSI} --min-msi=${MIN_MSI} .PHONY: static-code-analysis -static-code-analysis: vendor ## Runs a static code analysis with phpstan/phpstan +static-code-analysis: vendor ## Runs a static code analysis with phpstan/phpstan and vimeo/psalm mkdir -p .build/phpstan vendor/bin/phpstan analyse --configuration=phpstan.neon + mkdir -p .build/psalm + vendor/bin/psalm --config=psalm.xml .PHONY: static-code-analysis-baseline -static-code-analysis-baseline: vendor ## Generates a baseline for static code analysis with phpstan/phpstan +static-code-analysis-baseline: vendor ## Generates a baseline for static code analysis with phpstan/phpstan and vimeo/psalm mkdir -p .build/phpstan echo '' > phpstan-baseline.neon vendor/bin/phpstan analyze --configuration=phpstan.neon --error-format=baselineNeon > phpstan-baseline.neon || true + mkdir -p .build/psalm + vendor/bin/psalm --config=psalm.xml --set-baseline=psalm-baseline.xml .PHONY: tests tests: vendor ## Runs auto-review, unit, and integration tests with phpunit/phpunit diff --git a/composer.json b/composer.json index c85d1432..45f5b9b7 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,9 @@ "phpstan/phpstan-deprecation-rules": "~0.12.0", "phpstan/phpstan-phpunit": "~0.12.3", "phpstan/phpstan-strict-rules": "~0.12.0", - "phpunit/phpunit": "^7.5.18" + "phpunit/phpunit": "^7.5.18", + "psalm/plugin-phpunit": "~0.8.0", + "vimeo/psalm": "^3.8.1" }, "config": { "preferred-install": "dist", diff --git a/composer.lock b/composer.lock index b26d9598..10d4486f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2980fc89861a449c1d88ec44e0a32790", + "content-hash": "0e22476b9fe63a75a739d6cbd9b6bc46", "packages": [ { "name": "composer/semver", @@ -1326,6 +1326,142 @@ } ], "packages-dev": [ + { + "name": "amphp/amp", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/amp.git", + "reference": "13930a582947831bb66ff1aeac28672fd91c38ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/amp/zipball/13930a582947831bb66ff1aeac28672fd91c38ea", + "reference": "13930a582947831bb66ff1aeac28672fd91c38ea", + "shasum": "" + }, + "require": { + "php": ">=7" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1", + "ext-json": "*", + "phpstan/phpstan": "^0.8.5", + "phpunit/phpunit": "^6.0.9 | ^7", + "react/promise": "^2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\": "lib" + }, + "files": [ + "lib/functions.php", + "lib/Internal/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A non-blocking concurrency framework for PHP applications.", + "homepage": "http://amphp.org/amp", + "keywords": [ + "async", + "asynchronous", + "awaitable", + "concurrency", + "event", + "event-loop", + "future", + "non-blocking", + "promise" + ], + "time": "2019-11-11T19:32:05+00:00" + }, + { + "name": "amphp/byte-stream", + "version": "v1.7.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/byte-stream.git", + "reference": "9d8205686a004948475dc43f8a88d2fa5e75a113" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/9d8205686a004948475dc43f8a88d2fa5e75a113", + "reference": "9d8205686a004948475dc43f8a88d2fa5e75a113", + "shasum": "" + }, + "require": { + "amphp/amp": "^2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1", + "friendsofphp/php-cs-fixer": "^2.3", + "infection/infection": "^0.9.3", + "phpunit/phpunit": "^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\ByteStream\\": "lib" + }, + "files": [ + "lib/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A stream abstraction to make working with non-blocking I/O simple.", + "homepage": "http://amphp.org/byte-stream", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "non-blocking", + "stream" + ], + "time": "2019-10-27T14:33:41+00:00" + }, { "name": "composer/ca-bundle", "version": "1.2.5", @@ -1844,6 +1980,94 @@ ], "time": "2019-12-19T09:08:28+00:00" }, + { + "name": "felixfbecker/advanced-json-rpc", + "version": "v3.0.4", + "source": { + "type": "git", + "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git", + "reference": "23366dd0cab0a0f3fd3016bf3c0b36dec74348e7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/23366dd0cab0a0f3fd3016bf3c0b36dec74348e7", + "reference": "23366dd0cab0a0f3fd3016bf3c0b36dec74348e7", + "shasum": "" + }, + "require": { + "netresearch/jsonmapper": "^1.0", + "php": ">=7.0", + "phpdocumentor/reflection-docblock": "^4.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "AdvancedJsonRpc\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Felix Becker", + "email": "felix.b@outlook.com" + } + ], + "description": "A more advanced JSONRPC implementation", + "time": "2019-09-12T22:41:08+00:00" + }, + { + "name": "felixfbecker/language-server-protocol", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/felixfbecker/php-language-server-protocol.git", + "reference": "378801f6139bb74ac215d81cca1272af61df9a9f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/378801f6139bb74ac215d81cca1272af61df9a9f", + "reference": "378801f6139bb74ac215d81cca1272af61df9a9f", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpstan/phpstan": "*", + "phpunit/phpunit": "^6.3", + "squizlabs/php_codesniffer": "^3.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "LanguageServerProtocol\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Felix Becker", + "email": "felix.b@outlook.com" + } + ], + "description": "PHP classes for the Language Server Protocol", + "keywords": [ + "language", + "microsoft", + "php", + "server" + ], + "time": "2019-06-23T21:03:50+00:00" + }, { "name": "fzaninotto/faker", "version": "v1.9.1", @@ -2365,6 +2589,52 @@ ], "time": "2019-12-15T19:12:40+00:00" }, + { + "name": "netresearch/jsonmapper", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/cweiske/jsonmapper.git", + "reference": "0d4d1b48d682a93b6bfedf60b88c7750e9cb0b06" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/0d4d1b48d682a93b6bfedf60b88c7750e9cb0b06", + "reference": "0d4d1b48d682a93b6bfedf60b88c7750e9cb0b06", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "autoload": { + "psr-0": { + "JsonMapper": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "OSL-3.0" + ], + "authors": [ + { + "name": "Christian Weiske", + "email": "cweiske@cweiske.de", + "homepage": "http://github.com/cweiske/jsonmapper/", + "role": "Developer" + } + ], + "description": "Map nested JSON structures onto PHP classes", + "time": "2019-08-15T19:41:25+00:00" + }, { "name": "nikic/php-parser", "version": "v4.3.0", @@ -2467,6 +2737,55 @@ "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", "time": "2019-11-15T16:17:10+00:00" }, + { + "name": "openlss/lib-array2xml", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/nullivex/lib-array2xml.git", + "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nullivex/lib-array2xml/zipball/a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "autoload": { + "psr-0": { + "LSS": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Bryan Tong", + "email": "bryan@nullivex.com", + "homepage": "https://www.nullivex.com" + }, + { + "name": "Tony Butler", + "email": "spudz76@gmail.com", + "homepage": "https://www.nullivex.com" + } + ], + "description": "Array2XML conversion library credit to lalit.org", + "homepage": "https://www.nullivex.com", + "keywords": [ + "array", + "array conversion", + "xml", + "xml conversion" + ], + "time": "2019-03-29T20:06:56+00:00" + }, { "name": "padraic/humbug_get_contents", "version": "1.1.2", @@ -3534,6 +3853,63 @@ ], "time": "2018-01-21T07:42:36+00:00" }, + { + "name": "psalm/plugin-phpunit", + "version": "0.8.0", + "source": { + "type": "git", + "url": "https://github.com/psalm/phpunit-psalm-plugin.git", + "reference": "1dcd8ff7719b78b858d7560dd2d912a55272bfbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/psalm/phpunit-psalm-plugin/zipball/1dcd8ff7719b78b858d7560dd2d912a55272bfbc", + "reference": "1dcd8ff7719b78b858d7560dd2d912a55272bfbc", + "shasum": "" + }, + "require": { + "composer/semver": "^1.4", + "ocramius/package-versions": "^1.3", + "phpunit/phpunit": "^6.0 || ^7.0 || ^8.0", + "vimeo/psalm": "^3.6.2 || dev-master" + }, + "require-dev": { + "codeception/base": "^2.5", + "squizlabs/php_codesniffer": "^3.3.1", + "weirdan/codeception-psalm-module": "^0.2.2" + }, + "type": "psalm-plugin", + "extra": { + "psalm": { + "pluginClass": "Psalm\\PhpUnitPlugin\\Plugin" + } + }, + "autoload": { + "psr-4": { + "Psalm\\PhpUnitPlugin\\": [ + "." + ], + "Psalm\\PhpUnitPlugin\\Hooks\\": [ + "hooks" + ], + "Psalm\\PhpUnitPlugin\\Exception\\": [ + "Exception" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Brown", + "email": "github@muglug.com" + } + ], + "description": "Psalm plugin for PHPUnit", + "time": "2019-11-27T15:49:38+00:00" + }, { "name": "sebastian/code-unit-reverse-lookup", "version": "1.0.1", @@ -4199,6 +4575,97 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "time": "2019-06-13T22:48:21+00:00" }, + { + "name": "vimeo/psalm", + "version": "3.8.1", + "source": { + "type": "git", + "url": "https://github.com/vimeo/psalm.git", + "reference": "8e54e3aa060fc490d86d0e2abbf62750516d40fd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/8e54e3aa060fc490d86d0e2abbf62750516d40fd", + "reference": "8e54e3aa060fc490d86d0e2abbf62750516d40fd", + "shasum": "" + }, + "require": { + "amphp/amp": "^2.1", + "amphp/byte-stream": "^1.5", + "composer/xdebug-handler": "^1.1", + "ext-dom": "*", + "felixfbecker/advanced-json-rpc": "^3.0.3", + "felixfbecker/language-server-protocol": "^1.4", + "netresearch/jsonmapper": "^1.0", + "nikic/php-parser": "^4.3", + "ocramius/package-versions": "^1.2", + "openlss/lib-array2xml": "^1.0", + "php": "^7.1.3", + "sebastian/diff": "^3.0", + "symfony/console": "^3.3||^4.0||^5.0", + "webmozart/glob": "^4.1", + "webmozart/path-util": "^2.3" + }, + "provide": { + "psalm/psalm": "self.version" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.2", + "ext-curl": "*", + "friendsofphp/php-cs-fixer": "^2.15", + "phpmyadmin/sql-parser": "^5.0", + "phpspec/prophecy": ">=1.9.0", + "phpunit/phpunit": "^7.5 || ^8.0", + "psalm/plugin-phpunit": "^0.6", + "slevomat/coding-standard": "^5.0", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^4.3" + }, + "suggest": { + "ext-igbinary": "^2.0.5" + }, + "bin": [ + "psalm", + "psalter", + "psalm-language-server", + "psalm-plugin", + "psalm-refactor" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev", + "dev-2.x": "2.x-dev", + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psalm\\Plugin\\": "src/Psalm/Plugin", + "Psalm\\": "src/Psalm" + }, + "files": [ + "src/functions.php", + "src/spl_object_id.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthew Brown" + } + ], + "description": "A static analysis tool for finding errors in PHP applications", + "keywords": [ + "code", + "inspection", + "php" + ], + "time": "2019-12-29T16:11:07+00:00" + }, { "name": "webmozart/assert", "version": "1.6.0", @@ -4246,6 +4713,99 @@ "validate" ], "time": "2019-11-24T13:36:37+00:00" + }, + { + "name": "webmozart/glob", + "version": "4.1.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/glob.git", + "reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/glob/zipball/3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe", + "reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe", + "shasum": "" + }, + "require": { + "php": "^5.3.3|^7.0", + "webmozart/path-util": "^2.2" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1", + "symfony/filesystem": "^2.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Glob\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A PHP implementation of Ant's glob.", + "time": "2015-12-29T11:14:33+00:00" + }, + { + "name": "webmozart/path-util", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/path-util.git", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "webmozart/assert": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\PathUtil\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.", + "time": "2015-12-17T08:42:14+00:00" } ], "aliases": [], diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 14f99ef3..42b9e0a2 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -20,8 +20,3 @@ parameters: count: 1 path: test/Unit/RuleSet/AbstractRuleSetTestCase.php - - - message: "#^Parameter \\#1 \\$argument of class ReflectionClass constructor expects class\\-string\\\\|T of object, string given\\.$#" - count: 1 - path: test/Unit/RuleSet/AbstractRuleSetTestCase.php - diff --git a/psalm-baseline.xml b/psalm-baseline.xml new file mode 100644 index 00000000..b0a8d767 --- /dev/null +++ b/psalm-baseline.xml @@ -0,0 +1,15 @@ + + + + + FixerFactory::create() + RuleSet::create($rules) + + + FixerFactory::create() + registerBuiltInFixers + getFixers + RuleSet::create($rules) + + + diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 00000000..87dbffbd --- /dev/null +++ b/psalm.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/Factory.php b/src/Factory.php index 99d6474d..19e5bd02 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -31,7 +31,7 @@ public static function fromRuleSet(RuleSet $ruleSet, array $overrideRules = []): { if (\PHP_VERSION_ID < $ruleSet->targetPhpVersion()) { throw new \RuntimeException(\sprintf( - 'Current PHP version "%s is less than targeted PHP version "%s".', + 'Current PHP version "%s" is less than targeted PHP version "%s".', \PHP_VERSION_ID, $ruleSet->targetPhpVersion() )); diff --git a/src/RuleSet/AbstractRuleSet.php b/src/RuleSet/AbstractRuleSet.php index 154d4f37..e7ac3134 100644 --- a/src/RuleSet/AbstractRuleSet.php +++ b/src/RuleSet/AbstractRuleSet.php @@ -23,7 +23,7 @@ abstract class AbstractRuleSet implements RuleSet /** * @var string */ - protected $name; + protected $name = ''; /** * @var array @@ -33,7 +33,7 @@ abstract class AbstractRuleSet implements RuleSet /** * @var int */ - protected $targetPhpVersion; + protected $targetPhpVersion = 0; final public function __construct(?string $header = null) { diff --git a/test/Unit/FactoryTest.php b/test/Unit/FactoryTest.php index 017edb0f..e2f5a574 100644 --- a/test/Unit/FactoryTest.php +++ b/test/Unit/FactoryTest.php @@ -51,7 +51,7 @@ public function testFromRuleSetThrowsRuntimeExceptionIfCurrentPhpVersionIsLessTh $this->expectException(\RuntimeException::class); $this->expectExceptionMessage(\sprintf( - 'Current PHP version "%s is less than targeted PHP version "%s".', + 'Current PHP version "%s" is less than targeted PHP version "%s".', \PHP_VERSION_ID, $targetPhpVersion )); diff --git a/test/Unit/RuleSet/AbstractRuleSetTestCase.php b/test/Unit/RuleSet/AbstractRuleSetTestCase.php index 4f6c29e5..871b0bf9 100644 --- a/test/Unit/RuleSet/AbstractRuleSetTestCase.php +++ b/test/Unit/RuleSet/AbstractRuleSetTestCase.php @@ -127,10 +127,10 @@ final public function providerValidHeader(): \Generator /** * @dataProvider providerRuleNames * - * @param array $ruleNames - * @param string $source + * @param string $source + * @param string[] $ruleNames */ - final public function testRulesAreSortedByName($source, $ruleNames): void + final public function testRulesAreSortedByName(string $source, array $ruleNames): void { $sorted = $ruleNames; @@ -193,6 +193,7 @@ final protected static function className(): string */ final protected static function createRuleSet($header = null): Config\RuleSet { + /** @var class-string $className */ $className = self::className(); $reflection = new \ReflectionClass($className); @@ -236,7 +237,7 @@ private function configuredFixers(): array * * @see https://github.com/FriendsOfPHP/PHP-CS-Fixer/pull/2361 */ - $rules = \array_map(static function (): bool { + $rules = \array_map(static function ($ruleConfiguration): bool { return true; }, self::createRuleSet()->rules());