diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 43037560..6e42c854 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,6 +12,7 @@ variables: DOCROOT: /var/www/ stages: + - prepare - validate - build - test @@ -20,56 +21,90 @@ stages: - deploy-production - stop -# -# Validation -# +.use_cache: &use_cache + cache: + key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG" + paths: + - .yarn-cache/ + - vendor/ -check-php-style: - image: composer:latest - stage: validate - before_script: - - composer --no-ansi global config --no-plugins allow-plugins.dealerdirect/phpcodesniffer-composer-installer true - - composer --no-ansi global require slevomat/coding-standard squizlabs/php_codesniffer - - export PATH=$PATH:$COMPOSER_HOME/vendor/bin - script: - - phpcs -p --no-colors --basepath="$PWD" - -# does everything that depends on packages installed by yarn -check-frontend: - image: node:alpine - stage: validate +# for jobs that depend on composer +.use_composer: &use_composer + <<: *use_cache needs: - - validate-yarn + - composer install before_script: - - yarn --frozen-lockfile - script: - - yarn check - - yarn lint + - composer install --no-ansi --no-progress -check-editorconfig: - image: mstruebing/editorconfig-checker - stage: validate - script: - - ec -v +# for jobs that depend on yarn +.use_yarn: &use_yarn + <<: *use_cache + needs: + - yarn install + before_script: + - yarn install --check-frontend --cache-folder .yarn-cache -validate-composer: +# +# Preparation +# + +composer validate: image: composer:latest - stage: validate + stage: prepare script: - composer --no-ansi validate --strict -validate-yarn: +composer install: + <<: *use_cache + image: composer:latest + stage: prepare + needs: + - composer audit + - composer validate + script: + - composer install --no-ansi --no-progress + +composer audit: + image: php:latest + stage: prepare + needs: + - composer validate + before_script: + - curl -Ls https://github.com/symfony/cli/releases/latest/download/symfony_linux_amd64.gz | gzip -d > /bin/symfony + - chmod +x /bin/symfony + script: + - symfony check:security --no-ansi + +yarn-validate: image: node:alpine - stage: validate + stage: prepare before_script: - yarn global add package-json-validator - export PATH=$PATH:~/.yarn/bin script: - pjv +yarn install: + <<: *use_cache + image: node:alpine + stage: prepare + needs: + - yarn-validate + - yarn audit + script: + - yarn install --check-frontend --cache-folder .yarn-cache + +yarn audit: + image: node:alpine + stage: prepare + needs: + - yarn-validate + script: + - yarn audit + generate-version: image: alpine - stage: validate + stage: prepare artifacts: name: "${CI_JOB_NAME}_${CI_JOB_ID}_version" expire_in: 1 day @@ -82,6 +117,44 @@ generate-version: - echo "${VERSION}" - echo -n "${VERSION}" > storage/app/VERSION +# +# Validation +# + +phpcs: + <<: *use_composer + image: composer:latest + stage: validate + script: + - ./vendor/bin/phpcs -p --no-colors --basepath="$PWD" + +phpstan: + <<: *use_composer + image: composer:latest + stage: validate + script: + - ./vendor/bin/phpstan --no-progress + +yarn check: + <<: *use_yarn + image: node:alpine + stage: validate + script: + - yarn check + +eslint: + <<: *use_yarn + image: node:alpine + stage: validate + script: + - yarn lint + +check-editorconfig: + image: mstruebing/editorconfig-checker + stage: validate + script: + - ec -v + # # Build # @@ -100,11 +173,12 @@ build-image: stage: build needs: - check-editorconfig - - check-php-style - - check-frontend + - phpcs + - phpstan + - composer validate + - yarn check + - eslint - generate-version - - validate-composer - - validate-yarn dependencies: - generate-version script: @@ -116,23 +190,6 @@ build-image: # Test # -audit-composer: - image: php:latest - stage: test - needs: [ ] - before_script: - - curl -Ls https://github.com/symfony/cli/releases/latest/download/symfony_linux_amd64.gz | gzip -d > /bin/symfony - - chmod +x /bin/symfony - script: - - symfony check:security --no-ansi - -audit-yarn: - image: node:alpine - stage: test - needs: [ ] - script: - - yarn audit - test: image: name: ${TEST_IMAGE} @@ -231,8 +288,8 @@ build-release-file: stage: release needs: - build-image - - audit-yarn - - audit-composer + - yarn audit + - composer audit - test - dump-database - generate-assets @@ -394,8 +451,8 @@ deploy-production: stage: deploy-production needs: - test - - audit-yarn - - audit-composer + - yarn audit + - composer audit - build-image - generate-assets dependencies: @@ -422,8 +479,8 @@ deploy-k8s-production: stage: deploy-production needs: - release-image - - audit-yarn - - audit-composer + - yarn audit + - composer audit environment: name: production on_stop: stop-k8s-production diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eb84be28..3a8e537d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,6 +4,7 @@ You may use `composer run phpcs` and [Editorconfig-Checker](https://editorconfig-checker.github.io) to verify that. * You should use an [editorconfig plugin for your editor](https://editorconfig.org/#pre-installed) for automatic basic code formatting. * Use `use` statements wherever possible instead of writing the fully qualified name. +* Code must pass PHPStan checks (`composer phpstan`) * Order the composer/npm dependencies alphabetically. * Do not use code from the [includes](includes) directory anywhere else. * Please cover your code by unit tests, our goal is to stay at 100% line coverage. diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index e0d252bc..d3d758ee 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -108,6 +108,14 @@ PRODUCTION_REMOTE # Same as STAGING_REMOTE but for the production environm PRODUCTION_REMOTE_PATH # Same as STAGING_REMOTE_PATH but for the production environment ``` +## Static code analysis + +You can run a static code analysis with this command: + +```bash +composer phpstan +``` + ## Docker If unspecific issues appear try using Docker version >= 20.10.14. diff --git a/composer.json b/composer.json index 5fa1e141..7ec6f1d0 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,8 @@ ], "scripts": { "phpcs": "phpcs -p", - "phpcbf": "phpcbf -p" + "phpcbf": "phpcbf -p", + "phpstan": "phpstan" }, "require": { "php": ">=7.4.0", @@ -51,6 +52,7 @@ "dms/phpunit-arraysubset-asserts": "^0.3.1", "fakerphp/faker": "^1.17", "filp/whoops": "^2.14", + "phpstan/phpstan": "^1.9", "phpunit/phpunit": "^9.5", "slevomat/coding-standard": "^7.1", "squizlabs/php_codesniffer": "^3.6", diff --git a/composer.lock b/composer.lock index 338a2496..0ed274e6 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": "b2eb1187f2e6d351073c1f8cdde0495d", + "content-hash": "753487aad9b4365e8f96952f4fb98d00", "packages": [ { "name": "composer/package-versions-deprecated", @@ -5854,6 +5854,65 @@ }, "time": "2022-04-14T12:24:06+00:00" }, + { + "name": "phpstan/phpstan", + "version": "1.9.2", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "d6fdf01c53978b6429f1393ba4afeca39cc68afa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d6fdf01c53978b6429f1393ba4afeca39cc68afa", + "reference": "d6fdf01c53978b6429f1393ba4afeca39cc68afa", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/phpstan/issues", + "source": "https://github.com/phpstan/phpstan/tree/1.9.2" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" + } + ], + "time": "2022-11-10T09:56:11+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "9.2.10", diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 00000000..109eba4d --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,10 @@ +parameters: + phpVersion: 70400 + level: 1 + paths: + - config + - db + - src + - tests + scanDirectories: + - includes diff --git a/src/Exceptions/Handlers/LegacyDevelopment.php b/src/Exceptions/Handlers/LegacyDevelopment.php index 335ce87c..6384d45d 100644 --- a/src/Exceptions/Handlers/LegacyDevelopment.php +++ b/src/Exceptions/Handlers/LegacyDevelopment.php @@ -82,7 +82,7 @@ class LegacyDevelopment extends Legacy $return[] = [ 'file' => $path . ':' . $line, - $functionName => $args ?? null, + $functionName => $args, ]; } diff --git a/src/Mail/MailerServiceProvider.php b/src/Mail/MailerServiceProvider.php index 32c8113e..a9662dd2 100644 --- a/src/Mail/MailerServiceProvider.php +++ b/src/Mail/MailerServiceProvider.php @@ -45,7 +45,7 @@ class MailerServiceProvider extends ServiceProvider } /** - * @param string $transport + * @param string|null $transport * @param array $config * @return TransportInterface */ diff --git a/tests/Unit/Controllers/ChecksArrivalsAndDeparturesTest.php b/tests/Unit/Controllers/ChecksArrivalsAndDeparturesTest.php index 89e246c0..3373a6ee 100644 --- a/tests/Unit/Controllers/ChecksArrivalsAndDeparturesTest.php +++ b/tests/Unit/Controllers/ChecksArrivalsAndDeparturesTest.php @@ -9,6 +9,8 @@ use Engelsystem\Test\Unit\TestCase; class ChecksArrivalsAndDeparturesTest extends TestCase { + private Config $config; + public function invalidArrivalCombinations(): array { return [ diff --git a/tests/Unit/Controllers/Metrics/ControllerTest.php b/tests/Unit/Controllers/Metrics/ControllerTest.php index b801f7a2..8f7b45c7 100644 --- a/tests/Unit/Controllers/Metrics/ControllerTest.php +++ b/tests/Unit/Controllers/Metrics/ControllerTest.php @@ -41,7 +41,7 @@ class ControllerTest extends TestCase $engine->expects($this->once()) ->method('get') - ->willReturnCallback(function ($path, $data) use ($response) { + ->willReturnCallback(function ($path, $data) { $this->assertEquals('/metrics', $path); $this->assertArrayHasKey('info', $data); $this->assertArrayHasKey('users', $data);