From 66685b40b2bee18d2b1b2db161ef49c5838edd5f Mon Sep 17 00:00:00 2001 From: Bernhard Sirlinger Date: Mon, 21 Mar 2022 15:03:19 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=B7=20WIP=20CI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/dependabot.yml | 16 +- .github/workflows/ci.yml | 122 ++++++ .github/workflows/ter-release.yml | 29 ++ .gitignore | 12 +- Build/.php-cs-fixer.php | 105 +++++ Build/Scripts/cglFixMyCommit.sh | 145 +++++++ ...heckComposerJsonForPushedMinimalPackage.sh | 6 + Build/Scripts/ci.sh | 117 ++++++ Build/Scripts/cleanup.sh | 16 + Build/Scripts/runTests.sh | 382 ++++++++++++++++++ Build/phpstan/phpstan-baseline.neon | 7 + Build/phpstan/phpstan.info.md | 38 ++ Build/phpstan/phpstan.neon | 19 + Build/phpunit/FunctionalTests.xml | 58 +++ Build/phpunit/FunctionalTestsBootstrap.php | 30 ++ Build/phpunit/UnitTests.xml | 62 +++ Build/phpunit/UnitTestsBootstrap.php | 31 ++ Build/testing-docker/docker-compose.yml | 372 +++++++++++++++++ Classes/Service/GarbageCollectorService.php | 27 +- Classes/Task/GarbageCollector.php | 4 - Tests/.gitkeep | 0 composer.json | 27 +- ext_localconf.php | 4 +- 23 files changed, 1592 insertions(+), 37 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/ter-release.yml create mode 100644 Build/.php-cs-fixer.php create mode 100755 Build/Scripts/cglFixMyCommit.sh create mode 100755 Build/Scripts/checkComposerJsonForPushedMinimalPackage.sh create mode 100755 Build/Scripts/ci.sh create mode 100755 Build/Scripts/cleanup.sh create mode 100755 Build/Scripts/runTests.sh create mode 100644 Build/phpstan/phpstan-baseline.neon create mode 100644 Build/phpstan/phpstan.info.md create mode 100644 Build/phpstan/phpstan.neon create mode 100644 Build/phpunit/FunctionalTests.xml create mode 100644 Build/phpunit/FunctionalTestsBootstrap.php create mode 100644 Build/phpunit/UnitTests.xml create mode 100644 Build/phpunit/UnitTestsBootstrap.php create mode 100644 Build/testing-docker/docker-compose.yml create mode 100644 Tests/.gitkeep diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5a98fda..7741d09 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,8 +1,12 @@ version: 2 updates: -- package-ecosystem: composer - directory: "/" - schedule: - interval: daily - time: "04:00" - open-pull-requests-limit: 10 + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + # Maintain dependencies for Composer + - package-ecosystem: "composer" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..53ac0ca --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,122 @@ + +# Configuration for running GitHub actions +# based on https://github.com/sypets/brofix/blob/main/.github/workflows/ci.yml + +name: CI + +on: + push: + pull_request: + +jobs: + all_core_9: + name: "all core-9" + runs-on: ubuntu-20.04 + strategy: + # This prevents cancellation of matrix job runs, if one/two already failed and let the + # rest matrix jobs be be executed anyway. + fail-fast: false + matrix: + php: [ '7.2', '7.3', '7.4' ] + minMax: [ 'composerInstallMin', 'composerInstallMax' ] + steps: + - name: "Checkout" + uses: actions/checkout@v3 + + # This must be checked before core version select is run, as this would write this + # and than the check would fail - obiously. + - name: "Check if typo3/minimal has been pushed in composer.json" + run: Build/Scripts/checkComposerJsonForPushedMinimalPackage.sh + + - name: "Set Typo3 core version" + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -t "^9.5" -s composerCoreVersion + + - name: "Composer" + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s ${{ matrix.minMax }} + + - name: "cgl" + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s cgl -v -n + + - name: "Composer validate" + if: always() + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s composerValidate + + - name: "Lint PHP" + if: always() + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s lint + + - name: "phpstan" + if: ${{ always() && matrix.minMax == 'composerInstallMax' }} + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s phpstan + + - name: "Unit tests" + if: always() + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s unit + + - name: "Functional tests with mariadb" + if: always() + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -d mariadb -s functional + + - name: "Functional tests with sqlite (nightly or pull_request)" + if: ${{ always() && (github.event_name == 'schedule' || github.event_name == 'pull_request' ) }} + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -d sqlite -s functional + + - name: "Functional tests with postgres (nightly or pull_request)" + if: ${{ always() && (github.event_name == 'schedule' || github.event_name == 'pull_request' ) }} + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -d postgres -s functional + + all_core_10: + name: "all core-10" + runs-on: ubuntu-20.04 + strategy: + # This prevents cancellation of matrix job runs, if one/two already failed and let the + # rest matrix jobs be be executed anyway. + fail-fast: false + matrix: + php: [ '7.2', '7.3', '7.4' ] + minMax: [ 'composerInstallMin', 'composerInstallMax' ] + steps: + - name: "Checkout" + uses: actions/checkout@v3 + + # This must be checked before core version select is run, as this would write this + # and than the check would fail - obiously. + - name: "Check if typo3/minimal has been pushed in composer.json" + run: Build/Scripts/checkComposerJsonForPushedMinimalPackage.sh + + - name: "Set Typo3 core version" + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -t "^10.4" -s composerCoreVersion + + - name: "Composer" + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s ${{ matrix.minMax }} + + - name: "cgl" + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s cgl -v -n + + - name: "Composer validate" + if: always() + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s composerValidate + + - name: "Lint PHP" + if: always() + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s lint + + - name: "phpstan" + if: ${{ always() && matrix.minMax == 'composerInstallMax' }} + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s phpstan + + - name: "Unit tests" + if: always() + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s unit + + - name: "Functional tests with mariadb" + if: always() + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -d mariadb -s functional + + - name: "Functional tests with sqlite (nightly or pull_request)" + if: ${{ always() && (github.event_name == 'schedule' || github.event_name == 'pull_request' ) }} + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -d sqlite -s functional + + - name: "Functional tests with postgres (nightly or pull_request)" + if: ${{ always() && (github.event_name == 'schedule' || github.event_name == 'pull_request' ) }} + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -d postgres -s functional diff --git a/.github/workflows/ter-release.yml b/.github/workflows/ter-release.yml new file mode 100644 index 0000000..a94cb10 --- /dev/null +++ b/.github/workflows/ter-release.yml @@ -0,0 +1,29 @@ +name: TYPO3 Extension TER Release +on: + push: + tags: + - '*' +jobs: + ter-release: + name: TYPO3 TER Release + runs-on: ubuntu-latest + env: + TYPO3_EXTENSION_KEY: ${{ secrets.TYPO3_EXTENSION_KEY }} + TYPO3_REPOSITORY_URL: ${{ secrets.TYPO3_REPOSITORY_URL }} + TYPO3_API_TOKEN: ${{ secrets.TYPO3_API_TOKEN }} + TYPO3_API_USERNAME: ${{ secrets.TYPO3_API_USERNAME }} + TYPO3_API_PASSWORD: ${{ secrets.TYPO3_API_PASSWORD }} + + steps: + - name: Grab new version + id: get_version + run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} + - name: Configure PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + extensions: intl, mbstring, xml, soap, zip, curl + - name: Install TYPO3 Tailor Extension + run: composer global require typo3/tailor --prefer-dist --no-progress --no-suggest + - name: Release EXT:${{ env.TYPO3_EXTENSION_KEY }} as ${{ steps.get_version.outputs.VERSION }} to TER + run: php ~/.composer/vendor/bin/tailor ter:publish ${{ steps.get_version.outputs.VERSION }} --artefact=${{ env.TYPO3_REPOSITORY_URL }}/archive/${{ steps.get_version.outputs.VERSION }}.zip --comment="Successfully release new version ${{ steps.get_version.outputs.VERSION }} - see changelog at ${{ env.TYPO3_REPOSITORY_URL }}" diff --git a/.gitignore b/.gitignore index 57f1cb2..26c445f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,11 @@ -/.idea/ \ No newline at end of file +/.Build/ +/.idea/ +/.php_cs.cache +/.php-cs-fixer.cache +/Build/testing-docker/.env +/Build/yarn/node_modules +/composer.lock +/Documentation-GENERATED-temp +/node_modules +/Tests/Unit/.phpunit.result.cache +/var/ diff --git a/Build/.php-cs-fixer.php b/Build/.php-cs-fixer.php new file mode 100644 index 0000000..a841e6c --- /dev/null +++ b/Build/.php-cs-fixer.php @@ -0,0 +1,105 @@ +exclude('vendor') + ->exclude('typo3conf') + ->exclude('typo3temp') + ->exclude('typo3/sysext/core/Tests/Acceptance/Support/_generated') + ->notName('install.php') + ->notName('index.php') + ->in(__DIR__ . '/../'); +// Return a Code Sniffing configuration using +// all sniffers needed for PSR-2 +// and additionally: +// - Remove leading slashes in use clauses. +// - PHP single-line arrays should not have trailing comma. +// - Single-line whitespace before closing semicolon are prohibited. +// - Remove unused use statements in the PHP source code +// - Ensure Concatenation to have at least one whitespace around +// - Remove trailing whitespace at the end of blank lines. +$config = new PhpCsFixer\Config(); +$config + ->setRiskyAllowed(true) + ->setRules([ + '@DoctrineAnnotation' => true, + '@PSR2' => true, + 'array_syntax' => ['syntax' => 'short'], + 'blank_line_after_opening_tag' => true, + 'braces' => ['allow_single_line_closure' => true], + 'cast_spaces' => ['space' => 'none'], + 'compact_nullable_typehint' => true, + 'concat_space' => ['spacing' => 'one'], + 'declare_equal_normalize' => ['space' => 'none'], + 'dir_constant' => true, + 'function_typehint_space' => true, + 'single_line_comment_style' => true, + 'lowercase_cast' => true, + 'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'], + 'modernize_types_casting' => true, + 'native_function_casing' => true, + 'new_with_braces' => true, + 'no_alias_functions' => true, + 'no_blank_lines_after_phpdoc' => true, + 'no_empty_phpdoc' => true, + 'no_empty_statement' => true, + 'no_extra_blank_lines' => true, + 'no_leading_import_slash' => true, + 'no_leading_namespace_whitespace' => true, + 'no_null_property_initialization' => true, + 'no_short_bool_cast' => true, + 'no_singleline_whitespace_before_semicolons' => true, + 'no_superfluous_elseif' => true, + 'no_trailing_comma_in_singleline_array' => true, + 'no_unneeded_control_parentheses' => true, + 'no_unused_imports' => true, + 'no_useless_else' => true, + 'no_whitespace_in_blank_line' => true, + 'ordered_imports' => true, + 'php_unit_construct' => ['assertions' => ['assertEquals', 'assertSame', 'assertNotEquals', 'assertNotSame']], + 'php_unit_mock_short_will_return' => true, + 'php_unit_test_case_static_method_calls' => ['call_type' => 'self'], + 'phpdoc_no_access' => true, + 'phpdoc_no_empty_return' => true, + 'phpdoc_no_package' => true, + 'phpdoc_scalar' => true, + 'phpdoc_trim' => true, + 'phpdoc_types' => true, + 'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], + 'return_type_declaration' => ['space_before' => 'none'], + 'single_quote' => true, + 'single_trait_insert_per_statement' => true, + 'whitespace_after_comma_in_array' => true, + ]) + ->setFinder($finder); +return $config; diff --git a/Build/Scripts/cglFixMyCommit.sh b/Build/Scripts/cglFixMyCommit.sh new file mode 100755 index 0000000..a6c184c --- /dev/null +++ b/Build/Scripts/cglFixMyCommit.sh @@ -0,0 +1,145 @@ +#!/usr/bin/env bash + +######################### +# +# CGL fix. +# +# It expects to be run from the core root. +# +# To auto-fix single files, use the php-cs-fixer command directly +# substitute $FILE with a filename +# +########################## + +# -------------------------- +# --- default parameters --- +# -------------------------- +# check files in last commit +filestype=commit +# non-dryrun is default +DRYRUN="" +DRYRUN_OPTIONS="--dry-run --diff" + +# ---------------------- +# --- automatic vars --- +# ---------------------- +progname=$(basename $0) + +# ------------------------ +# --- print usage info --- +# ------------------------ +usage() +{ + echo "Usage: $0 [options] " + echo " " + echo "no arguments/default: fix all php files in last commit " + echo " " + echo "Options: " + echo " -f " + echo " specifies which files to check: " + echo " - commit (default): all files in latest commit " + echo " - cache : all files in git cache (staging area) " + echo " - stdin : read list of files from stdin " + echo " " + echo " -n " + echo " dryrun only, do not fix anything! " + echo " " + echo " -h " + echo " help " + echo " " + echo "Note: In order to still support command line options of " + echo " older versions of this script, you can use the argument " + echo " dryrun. " + echo " " + echo " THIS IS NOT RECOMMENDED but will still work for now " + echo " Usage: $0 [options] [dryrun] " + exit 0 +} + +# ----------------------- +# --- parsing of args --- +# ----------------------- +OPTIND=1 + +while getopts "hnf:" opt;do + case "$opt" in + h) + usage + ;; + f) + filestype=$OPTARG + echo "$0 files type=$filestype" + ;; + n) + echo "$progname: dryrun mode" + DRYRUN="$DRYRUN_OPTIONS" + ;; + esac +done + +shift $((OPTIND-1)) + +if [ "$1" = "dryrun" ] +then + echo "$progname: dryrun mode" + DRYRUN="$DRYRUN_OPTIONS" +fi + +# -------------------------------------- +# --- check if php executable exists --- +# -------------------------------------- +exist_php_executable() { + which php >/dev/null 2>/dev/null + if [ $? -ne 0 ];then + echo "$progname: No php executable found\n" + exit 1 + fi +} + + +# ------------------------------ +# --- run php without xdebug --- +# ------------------------------ +php_no_xdebug () +{ + temporaryPath="$(mktemp -t php.XXXX).ini" + php -i | grep "\.ini" | grep -o -e '\(/[A-Za-z0-9._-]\+\)\+\.ini' | grep -v xdebug | xargs awk 'FNR==1{print ""}1' > "${temporaryPath}" + php -n -c "${temporaryPath}" "$@" + RETURN=$? + rm -f "${temporaryPath}" + exit $RETURN +} + +# ------------------------------------ +# --- get a list of files to check --- +# ------------------------------------ +if [[ $filestype == commit ]];then + echo "$progname: Searching for php files in latest git commit ..." + DETECTED_FILES=`git diff-tree --no-commit-id --name-only -r HEAD | grep '.php$' 2>/dev/null` +elif [[ $filestype == cache ]];then + echo "$progname: Searching for php files in git cache ..." + DETECTED_FILES=`git diff --cached --name-only | grep '.php$' 2>/dev/null` +elif [[ $filestype == stdin ]];then + echo "$progname: reading list of php files to check from stdin" + DETECTED_FILES=$(cat) +else + echo "$progname: ERROR: unknown filetype, possibly used -f with wrong argument" + usage +fi +if [ -z "${DETECTED_FILES}" ] +then + echo "$progname: No PHP files to check, all is well." + exit 0 +fi + +# --------------------------------- +# --- run php-cs-fixer on files --- +# --------------------------------- +exist_php_executable +php_no_xdebug .Build/bin/php-cs-fixer fix \ + -v ${DRYRUN} \ + --path-mode intersection \ + --config=Build/php-cs-fixer.php \ + `echo ${DETECTED_FILES} | xargs ls -d 2>/dev/null` + +exit $? diff --git a/Build/Scripts/checkComposerJsonForPushedMinimalPackage.sh b/Build/Scripts/checkComposerJsonForPushedMinimalPackage.sh new file mode 100755 index 0000000..1e55b2c --- /dev/null +++ b/Build/Scripts/checkComposerJsonForPushedMinimalPackage.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +TMP="$( cat composer.json | grep "typo3/minimal" )" +[[ "$?" -ne 1 ]] && echo "[FAIL] 'typo3/minimal' package requirement was pushed in composer.json, remove this." && exit 1 + +echo "[OK] composer.json clean, no 'typo3/minimal' found in composer.json" && exit 0 diff --git a/Build/Scripts/ci.sh b/Build/Scripts/ci.sh new file mode 100755 index 0000000..e75f0c6 --- /dev/null +++ b/Build/Scripts/ci.sh @@ -0,0 +1,117 @@ +#!/bin/bash + +# Convenience script to run CI tests locally +# default: PHP 7.4 and composer latest (uses TYPO3 v11) + +# abort on error +set -e +set -x + +php="7.4" +m="composerInstallMax" +vt3="10" +cleanup=0 + +# ------------------- +# automatic variables +# ------------------- +prevdir=$(pwd) +thisdir=$(dirname $0) +cd $thisdir +thisdir=$(pwd) +cd $prevdir +progname=$(basename $0) + +usage() +{ + echo "[-p ] [-m ] [-t <10|11> [-h] [-c]" + echo " -c : runs cleanup after" + echo " -t : TYPO3 version, can be 10 or 11, 11 is default" + exit 1 +} + +while getopts "hp:m:ct:" opt;do + case $opt in + p) + php=${OPTARG} + ;; + t) + vt3=${OPTARG} + ;; + h) + usage + ;; + c) + cleanup=1 + ;; + m) + level=${OPTARG} + if [[ $level == min ]];then + m="composerInstallMin" + fi + ;; + \?) + echo "invalid option" + usage + ;; + esac +done +shift $((OPTIND-1)) + +echo "Running with PHP=$php and $m" + +# Run this in case we need test traits (see EXT:redirects_helper) +# we need to get typo3/cms-core as source to get the Tests dir with Test traits +# echo "Tests: prepare" +# echo "Install typo3/cms-core as source. Modifies composer.json! (config:preferred-install)" +# composer config preferred-install.typo3/cms-core source + +if [[ $vt3 == 10 ]];then + Build/Scripts/runTests.sh -p ${php} -t "^10.4" -s composerCoreVersion +else + Build/Scripts/runTests.sh -p ${php} -t "^11.5" -s composerCoreVersion +fi + +echo "composer install" +Build/Scripts/runTests.sh -p ${php} -s ${m} + +echo "cgl" +Build/Scripts/runTests.sh -p ${php} -s cgl -n + +echo "composer validate" +Build/Scripts/runTests.sh -p ${php} -s composerValidate + +echo "lint" +Build/Scripts/runTests.sh -p ${php} -s lint + +echo "phpstan" +Build/Scripts/runTests.sh -p ${php} -s phpstan + +echo "Unit tests" +Build/Scripts/runTests.sh -p ${php} -s unit + +echo "functional tests" +Build/Scripts/runTests.sh -p ${php} -d mariadb -s functional + +# ------- +# cleanup +# ------- + +echo "cleanup" +echo "remove preferred-install from composer.json" +composer config --unset preferred-install +composer remove typo3/minimal + +if [ $cleanup -eq 1 ];then + $thisdir/cleanup.sh +else + echo "--------------------------------------------------------------------------------" + echo "!!!! Make sure to revert changes to composer.json e.g. by git checkout composer.json" + git diff composer.json + echo "--------------------------------------------------------------------------------" +fi + +# check if changes in composer.json +Build/Scripts/checkComposerJsonForPushedMinimalPackage.sh + +echo "done: ok" diff --git a/Build/Scripts/cleanup.sh b/Build/Scripts/cleanup.sh new file mode 100755 index 0000000..edd3a7f --- /dev/null +++ b/Build/Scripts/cleanup.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# convenience script for cleaning up after running test suite locally +# todo: possibly handle restoring of original composer.json file differently +# and make sure changes do not get committed accidentally if tests are run locally. + +composer config --unset platform.php +composer config --unset platform + +echo "--------------------------------------------------------------------------------" +echo "!!!! Make sure to revert changes to composer.json by test suite e.g. by git checkout composer.json" +git diff composer.json +echo "--------------------------------------------------------------------------------" + +rm -rf .Build +rm composer.lock diff --git a/Build/Scripts/runTests.sh b/Build/Scripts/runTests.sh new file mode 100755 index 0000000..a33bd99 --- /dev/null +++ b/Build/Scripts/runTests.sh @@ -0,0 +1,382 @@ +#!/usr/bin/env bash + +# copied from EXT:enetcache: +# https://github.com/lolli42/enetcache/blob/master/Build/Scripts/runTests.sh + +# +# TYPO3 core test runner based on docker and docker-compose. +# + +# Function to write a .env file in Build/testing-docker/local +# This is read by docker-compose and vars defined here are +# used in Build/testing-docker/local/docker-compose.yml +setUpDockerComposeDotEnv() { + # Delete possibly existing local .env file if exists + [ -e .env ] && rm .env + # Set up a new .env file for docker-compose + { + echo "COMPOSE_PROJECT_NAME=local" + + # To prevent access rights of files created by the testing, the docker image later + # runs with the same user that is currently executing the script. docker-compose can't + # use $UID directly itself since it is a shell variable and not an env variable, so + # we have to set it explicitly here. + echo "HOST_UID=`id -u`" + + # Your local home directory for composer and npm caching + echo "HOST_HOME=${HOME}" + + # Your local user + echo "CORE_VERSION=${CORE_VERSION}" + echo "ROOT_DIR=\"${ROOT_DIR}\"" + echo "HOST_USER=${USER}" + echo "TEST_FILE=\"${TEST_FILE}\"" + echo "CGLCHECK_DRY_RUN=${CGLCHECK_DRY_RUN}" + echo "PHP_XDEBUG_ON=${PHP_XDEBUG_ON}" + echo "PHP_XDEBUG_PORT=${PHP_XDEBUG_PORT}" + echo "PHP_VERSION=${PHP_VERSION}" + echo "DOCKER_PHP_IMAGE=${DOCKER_PHP_IMAGE}" + echo "EXTRA_TEST_OPTIONS=${EXTRA_TEST_OPTIONS}" + echo "SCRIPT_VERBOSE=${SCRIPT_VERBOSE}" + echo "PASSWD_PATH=${PASSWD_PATH}" + } > .env +} + +# Load help text into $HELP +read -r -d '' HELP <=20.10 for xdebug break pointing to work reliably, and +a recent docker-compose (tested >=1.21.2) is needed. + +Usage: $0 [options] [file] + +No arguments: Run all unit tests with PHP 7.2 + +Options: + -s <...> + Specifies which test suite to run + - composerInstall: "composer install" + - composerInstallMax: "composer update", with no platform.php config. + - composerInstallMin: "composer update --prefer-lowest", with platform.php set to PHP version x.x.0. + - composerValidate: "composer validate" + - composerCoreVersion: "composer require --no-install typo3/minimal:"coreVersion" + - cgl: test and fix all core php files + - cglGit: test and fix latest committed patch for CGL compliance + - lint: PHP linting + - phpstan: phpstan tests + - phpstanGenerateBaseline: regenerate phpstan baseline, handy after phpstan updates + - unit (default): PHP unit tests + - functional: functional tests + + -t + Only with -s composerCoreVersion + Specifies the Typo3 core version to be used + - '^10.4' (default) + - '^11.5' + - '^11.5.3' + - ... + + -d + Only with -s functional + Specifies on which DBMS tests are performed + - mariadb (default): use mariadb + - mssql: use mssql microsoft sql server + - postgres: use postgres + - sqlite: use sqlite + + -p <7.2|7.3|7.4|8.0|8.1> + Specifies the PHP minor version to be used + - 7.2 (default): use PHP 7.2 + - 7.3: use PHP 7.3 + - 7.4: use PHP 7.4 + - 8.0: use PHP 8.0 + - 8.1: use PHP 8.1 + + -e "" + Only with -s functional|unit|phpstan + Additional options to send to phpunit tests. + For phpunit, options starting with "--" must be added after options starting with "-". + Example -e "-v --filter canRetrieveValueWithGP" to enable verbose output AND filter tests + named "canRetrieveValueWithGP" + + -x + Only with -s unit | function + Send information to host instance for test or system under test break points. This is especially + useful if a local PhpStorm instance is listening on default xdebug port 9003. A different port + can be selected with -y + + -y + Send xdebug information to a different port than default 9003 if an IDE like PhpStorm + is not listening on default port. + + -n + Only with -s cgl|cglGit + Activate dry-run in CGL check that does not actively change files and only prints broken ones. + + -u + Update existing typo3gmbh/phpXY:latest docker images. Maintenance call to docker pull latest + versions of the main php images. The images are updated once in a while and only the youngest + ones are supported by core testing. Use this if weird test errors occur. Also removes obsolete + image versions of typo3gmbh/phpXY. + + -v + Enable verbose script output. Shows variables and docker commands. + + -h + Show this help. + +Examples: + # Run unit tests using PHP 7.2 + ./Build/Scripts/runTests.sh + + # Run unit tests using PHP 7.3 + ./Build/Scripts/runTests.sh -p 7.3 + + # Run functional tests using PHP 7.4 and sqlite + ./Build/Scripts/runTests.sh -s functional -p 7.4 -d sqlite + + # Run functional tests in phpunit with a filtered test method name in a specified file, php 7.4 and xdebug enabled. + ./Build/Scripts/runTests.sh -s functional -p 7.4 -x -e "--filter getLinkStatisticsFindOnlyPageBrokenLinks" Tests/Functional/LinkAnalyzerTest.php +EOF + +# Test if docker-compose exists, else exit out with error +if ! type "docker-compose" > /dev/null; then + echo "This script relies on docker and docker-compose. Please install" >&2 + exit 1 +fi + +# Go to the directory this script is located, so everything else is relative +# to this dir, no matter from where this script is called. +THIS_SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +cd "$THIS_SCRIPT_DIR" || exit 1 + +# Go to directory that contains the local docker-compose.yml file +cd ../testing-docker || exit 1 + +# Option defaults +if ! command -v realpath &> /dev/null; then + echo "This script works best with realpath installed" >&2 + ROOT_DIR="${PWD}/../../" +else + ROOT_DIR=`realpath ${PWD}/../../` +fi +CORE_VERSION="10.4" +TEST_SUITE="unit" +DBMS="mariadb" +PHP_VERSION="7.2" +PHP_XDEBUG_ON=0 +PHP_XDEBUG_PORT=9003 +EXTRA_TEST_OPTIONS="" +SCRIPT_VERBOSE=0 +CGLCHECK_DRY_RUN="" +PASSWD_PATH=/etc/passwd + +# Option parsing +# Reset in case getopts has been used previously in the shell +OPTIND=1 +# Array for invalid options +INVALID_OPTIONS=(); +# Simple option parsing based on getopts (! not getopt) +while getopts ":s:t:d:p:e:xy:huvn" OPT; do + case ${OPT} in + s) + TEST_SUITE=${OPTARG} + ;; + t) + CORE_VERSION=${OPTARG} + ;; + d) + DBMS=${OPTARG} + ;; + p) + PHP_VERSION=${OPTARG} + if ! [[ ${PHP_VERSION} =~ ^(7.2|7.3|7.4|8.0|8.1)$ ]]; then + INVALID_OPTIONS+=("${OPT} ${OPTARG} : unsupported php version") + fi + ;; + e) + EXTRA_TEST_OPTIONS=${OPTARG} + ;; + x) + PHP_XDEBUG_ON=1 + ;; + y) + PHP_XDEBUG_PORT=${OPTARG} + ;; + h) + echo "${HELP}" + exit 0 + ;; + n) + CGLCHECK_DRY_RUN="-n" + ;; + u) + TEST_SUITE=update + ;; + v) + SCRIPT_VERBOSE=1 + ;; + \?) + INVALID_OPTIONS+=("${OPTARG}") + ;; + :) + INVALID_OPTIONS+=("${OPTARG}") + ;; + esac +done + +# Exit on invalid options +if [ ${#INVALID_OPTIONS[@]} -ne 0 ]; then + echo "Invalid option(s):" >&2 + for I in "${INVALID_OPTIONS[@]}"; do + echo "-"${I} >&2 + done + echo >&2 + echo "${HELP}" >&2 + exit 1 +fi + +# Move "7.2" to "php72", the latter is the docker container name +DOCKER_PHP_IMAGE=`echo "php${PHP_VERSION}" | sed -e 's/\.//'` + +# Set $1 to first mass argument, this is the optional test file or test directory to execute +shift $((OPTIND - 1)) +if [ -n "${1}" ]; then + TEST_FILE="Web/typo3conf/ext/indexed_search_gc/${1}" +else + case ${TEST_SUITE} in + functional) + TEST_FILE="Web/typo3conf/ext/indexed_search_gc/Tests/Functional" + ;; + unit) + TEST_FILE="Web/typo3conf/ext/indexed_search_gc/Tests/Unit" + ;; + esac +fi + +if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x +fi + +# Suite execution +case ${TEST_SUITE} in + composerCoreVersion) + setUpDockerComposeDotEnv + docker-compose run composer_coreversion_require + SUITE_EXIT_CODE=$? + ;; + composerInstall) + setUpDockerComposeDotEnv + docker-compose run composer_install + SUITE_EXIT_CODE=$? + docker-compose down + ;; + composerInstallMax) + setUpDockerComposeDotEnv + docker-compose run composer_install_max + SUITE_EXIT_CODE=$? + docker-compose down + ;; + composerInstallMin) + setUpDockerComposeDotEnv + docker-compose run composer_install_min + SUITE_EXIT_CODE=$? + docker-compose down + ;; + composerValidate) + setUpDockerComposeDotEnv + docker-compose run composer_validate + SUITE_EXIT_CODE=$? + docker-compose down + ;; + cgl) + # Active dry-run for cglAll needs not "-n" but specific options + if [[ ! -z ${CGLCHECK_DRY_RUN} ]]; then + CGLCHECK_DRY_RUN="--dry-run --diff" + fi + setUpDockerComposeDotEnv + docker-compose run cgl_all + SUITE_EXIT_CODE=$? + docker-compose down + ;; + cglGit) + # Active dry-run for cglAll needs not "-n" but specific options + setUpDockerComposeDotEnv + docker-compose run cgl_git + SUITE_EXIT_CODE=$? + docker-compose down + ;; + functional) + setUpDockerComposeDotEnv + case ${DBMS} in + mariadb) + docker-compose run functional_mariadb10 + SUITE_EXIT_CODE=$? + ;; + mssql) + docker-compose run functional_mssql2019latest + SUITE_EXIT_CODE=$? + ;; + postgres) + docker-compose run functional_postgres10 + SUITE_EXIT_CODE=$? + ;; + sqlite) + # sqlite has a tmpfs as typo3temp/var/tests/functional-sqlite-dbs/ + # Since docker is executed as root (yay!), the path to this dir is owned by + # root if docker creates it. Thank you, docker. We create the path beforehand + # to avoid permission issues on host filesystem after execution. + mkdir -p "${ROOT_DIR}/.Build/Web/typo3temp/var/tests/functional-sqlite-dbs/" + docker-compose run functional_sqlite + SUITE_EXIT_CODE=$? + ;; + *) + echo "Invalid -d option argument ${DBMS}" >&2 + echo >&2 + echo "${HELP}" >&2 + exit 1 + esac + docker-compose down + ;; + lint) + setUpDockerComposeDotEnv + docker-compose run lint + SUITE_EXIT_CODE=$? + docker-compose down + ;; + phpstan) + setUpDockerComposeDotEnv + docker-compose run phpstan + SUITE_EXIT_CODE=$? + docker-compose down + ;; + phpstanGenerateBaseline) + setUpDockerComposeDotEnv + docker-compose run phpstan_generate_baseline + SUITE_EXIT_CODE=$? + docker-compose down + ;; + unit) + setUpDockerComposeDotEnv + docker-compose run unit + SUITE_EXIT_CODE=$? + docker-compose down + ;; + update) + # pull typo3gmbh/phpXY:latest versions of those ones that exist locally + docker images typo3gmbh/php*:latest --format "{{.Repository}}:latest" | xargs -I {} docker pull {} + # remove "dangling" typo3gmbh/phpXY images (those tagged as ) + docker images typo3gmbh/php* --filter "dangling=true" --format "{{.ID}}" | xargs -I {} docker rmi {} + ;; + *) + echo "Invalid -s option argument ${TEST_SUITE}" >&2 + echo >&2 + echo "${HELP}" >&2 + exit 1 +esac + +exit $SUITE_EXIT_CODE diff --git a/Build/phpstan/phpstan-baseline.neon b/Build/phpstan/phpstan-baseline.neon new file mode 100644 index 0000000..9169405 --- /dev/null +++ b/Build/phpstan/phpstan-baseline.neon @@ -0,0 +1,7 @@ +parameters: + ignoreErrors: + - + message: "#^Property KKSoftware\\\\IndexedSearchGC\\\\Service\\\\GarbageCollectorService\\:\\:\\$statements type has no value type specified in iterable type Doctrine\\\\DBAL\\\\Driver\\\\Statement\\.$#" + count: 1 + path: ../../Classes/Service/GarbageCollectorService.php + diff --git a/Build/phpstan/phpstan.info.md b/Build/phpstan/phpstan.info.md new file mode 100644 index 0000000..6cdb1c2 --- /dev/null +++ b/Build/phpstan/phpstan.info.md @@ -0,0 +1,38 @@ +# Adding a baseline + +The goal is to fix the code. However, sometimes fix cannot be done because of backwards +compatibility, thus errors can be added to a baseline file. The baseline file contains +ignorePatters to silence errors. + +Adding new ignore patterns should be done with care. Thus checking baseline file +is required, even if baseline regenerate is run because of fixed errors. + +To update baseline use: `Build/Scripts/runTests.sh -s phpstanGenerateBaseline` + +If code get fixed which was silenced through an ignorePattern, phpstan check +would complain with a corresponding error. + +- Ignore Patterns did not match: Fully solved and can be removed, regenerate baseline to do this. +- Ignore Pattern count do not match: Decreasing counts are issue solved, thus regenerate baseline. Increse should be checked if it can be directly fixed, otherwise update baseline. + + +Points which should be kept in mind: +* Never ever edit manually the baseline file (will be overriden) +* Do not add manually ignore patterns to the main config file OR a further file. Use baseline rebuild. + +# Some notes + +## Dealing with mixed arrays + +Be as specific as possible, e.g. use + +* `array` etc. +* or `array{'foo': int, "bar": string}` + +If the array is dynamic or cannot be specified, use `mixed[]` + +see + +* https://phpstan.org/writing-php-code/phpdoc-types#array-shapes +* https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type +* https://github.com/phpstan/phpstan/discussions/4375 diff --git a/Build/phpstan/phpstan.neon b/Build/phpstan/phpstan.neon new file mode 100644 index 0000000..d1a4646 --- /dev/null +++ b/Build/phpstan/phpstan.neon @@ -0,0 +1,19 @@ +includes: + # regenerate baseline with: Build/Scripts/runTests.sh -s phpstanGenerateBaseline + - phpstan-baseline.neon + +parameters: + # Use local cache dir instead of /tmp + tmpDir: ../../.Build/.cache/phpstan + + parallel: + # Don't be overly greedy on machines with more CPU's to be a good neighbor especially on CI + maximumNumberOfProcesses: 5 + + level: 6 + + paths: + - ../../Classes + - ../../Tests + scanDirectories: + - ../../.Build/Web/typo3/sysext diff --git a/Build/phpunit/FunctionalTests.xml b/Build/phpunit/FunctionalTests.xml new file mode 100644 index 0000000..f7e55f2 --- /dev/null +++ b/Build/phpunit/FunctionalTests.xml @@ -0,0 +1,58 @@ + + + + + + ../../Tests/Functional/ + + + + + + + + + + diff --git a/Build/phpunit/FunctionalTestsBootstrap.php b/Build/phpunit/FunctionalTestsBootstrap.php new file mode 100644 index 0000000..a95bc52 --- /dev/null +++ b/Build/phpunit/FunctionalTestsBootstrap.php @@ -0,0 +1,30 @@ +defineOriginalRootPath(); + $testbase->createDirectory(ORIGINAL_ROOT . 'typo3temp/var/tests'); + $testbase->createDirectory(ORIGINAL_ROOT . 'typo3temp/var/transient'); +})(); diff --git a/Build/phpunit/UnitTests.xml b/Build/phpunit/UnitTests.xml new file mode 100644 index 0000000..5a985b0 --- /dev/null +++ b/Build/phpunit/UnitTests.xml @@ -0,0 +1,62 @@ + + + + + + ../../Tests/Unit/ + + + + + + + + ../../Classes/ + + + + + + + + + diff --git a/Build/phpunit/UnitTestsBootstrap.php b/Build/phpunit/UnitTestsBootstrap.php new file mode 100644 index 0000000..a337228 --- /dev/null +++ b/Build/phpunit/UnitTestsBootstrap.php @@ -0,0 +1,31 @@ + + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + composer require --no-progress --no-interaction --no-install typo3/minimal:"${CORE_VERSION}"; + " + composer_install: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + environment: + COMPOSER_CACHE_DIR: ".Build/.cache/composer" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + composer install --no-progress --no-interaction; + " + composer_install_max: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + environment: + COMPOSER_CACHE_DIR: ".Build/.cache/composer" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + if [ ${PHP_VERSION} == "8.0" ]; then + composer req --dev typo3/cms-core:"dev-main" \ + typo3/cms-backend:"dev-main" \ + typo3/cms-frontend:"dev-main" \ + typo3/cms-extbase:"dev-main" \ + typo3/cms-fluid:"dev-main" \ + typo3/cms-recordlist:"dev-main" + fi + composer config --unset platform.php; + composer update --no-progress --no-interaction; + composer dumpautoload; + " + + composer_install_min: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + environment: + COMPOSER_CACHE_DIR: ".Build/.cache/composer" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + if [ ${PHP_VERSION} == "8.0" ]; then + composer req --dev typo3/cms-core:"dev-main" \ + typo3/cms-backend:"dev-main" \ + typo3/cms-frontend:"dev-main" \ + typo3/cms-extbase:"dev-main" \ + typo3/cms-fluid:"dev-main" \ + typo3/cms-recordlist:"dev-main" + fi + composer config platform.php ${PHP_VERSION}.0; + composer update --prefer-lowest --no-progress --no-interaction; + composer dumpautoload; + " + + composer_validate: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + environment: + COMPOSER_CACHE_DIR: ".Build/.cache/composer" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + composer validate; + " + + functional_mariadb10: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + links: + - mariadb10 + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + environment: + typo3DatabaseName: func_test + typo3DatabaseUsername: root + typo3DatabasePassword: funcp + typo3DatabaseHost: mariadb10 + working_dir: ${ROOT_DIR}/.Build + extra_hosts: + - "host.docker.internal:host-gateway" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + echo Waiting for database start...; + while ! nc -z mariadb10 3306; do + sleep 1; + done; + echo Database is up; + php -v | grep '^PHP'; + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + bin/phpunit -c Web/typo3conf/ext/indexed_search_gc/Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + else + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=host.docker.internal\" \ + bin/phpunit -c Web/typo3conf/ext/indexed_search_gc/Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + fi + " + + functional_mssql2019latest: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + links: + - mssql2019latest + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + environment: + typo3DatabaseDriver: sqlsrv + typo3DatabaseName: func + typo3DatabasePassword: "Test1234!" + typo3DatabaseUsername: SA + typo3DatabasePort: 1433 + typo3DatabaseCharset: utf-8 + typo3DatabaseHost: mssql2019latest + working_dir: ${ROOT_DIR}/.Build + extra_hosts: + - "host.docker.internal:host-gateway" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + echo Waiting for database start...; + while ! nc -z mssql2019latest 1433; do + sleep 1; + done; + sleep 5; + echo Database is up; + php -v | grep '^PHP'; + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + bin/phpunit -c Web/typo3conf/ext/indexed_search_gc/Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-mssql ${TEST_FILE}; + else + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=host.docker.internal\" \ + bin/phpunit -c Web/typo3conf/ext/indexed_search_gc/Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-mssql ${TEST_FILE}; + fi + " + + functional_postgres10: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + links: + - postgres10 + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + environment: + typo3DatabaseDriver: pdo_pgsql + typo3DatabaseName: bamboo + typo3DatabaseUsername: ${HOST_USER} + typo3DatabaseHost: postgres10 + typo3DatabasePassword: funcp + working_dir: ${ROOT_DIR}/.Build + extra_hosts: + - "host.docker.internal:host-gateway" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + echo Waiting for database start...; + while ! nc -z postgres10 5432; do + sleep 1; + done; + echo Database is up; + php -v | grep '^PHP'; + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + bin/phpunit -c Web/typo3conf/ext/indexed_search_gc/Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-postgres ${TEST_FILE}; + else + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=host.docker.internal\" \ + bin/phpunit -c Web/typo3conf/ext/indexed_search_gc/Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-postgres ${TEST_FILE}; + fi + " + + functional_sqlite: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + tmpfs: + - ${ROOT_DIR}/.Build/Web/typo3temp/var/tests/functional-sqlite-dbs/:rw,noexec,nosuid,uid=${HOST_UID} + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + environment: + typo3DatabaseDriver: pdo_sqlite + working_dir: ${ROOT_DIR}/.Build + extra_hosts: + - "host.docker.internal:host-gateway" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP'; + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + bin/phpunit -c Web/typo3conf/ext/indexed_search_gc/Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-sqlite ${TEST_FILE}; + else + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=host.docker.internal\" \ + bin/phpunit -c Web/typo3conf/ext/indexed_search_gc/Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-sqlite ${TEST_FILE}; + fi + " + + cgl_git: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + Build/Scripts/cglFixMyCommit.sh ${CGLCHECK_DRY_RUN}; + " + + cgl_all: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -dxdebug.mode=off .Build/bin/php-cs-fixer fix -v ${CGLCHECK_DRY_RUN} --path-mode intersection \ + --config=Build/.php-cs-fixer.php . + " + lint: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + - /etc/passwd:/etc/passwd:ro + - /etc/group:/etc/group:ro + working_dir: ${ROOT_DIR} + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP'; + find . -name \\*.php ! -path "./.Build/\\*" -print0 | xargs -0 -n1 -P4 php -dxdebug.mode=off -l >/dev/null + " + + phpstan: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + mkdir -p .Build/.cache + php -v | grep '^PHP'; + php -dxdebug.mode=off .Build/bin/phpstan analyse --no-progress --no-interaction --memory-limit 4G -c Build/phpstan/phpstan.neon ${EXTRA_TEST_OPTIONS} + " + + phpstan_generate_baseline: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + mkdir -p .Build/.cache + php -v | grep '^PHP'; + php -dxdebug.mode=off .Build/bin/phpstan analyse --no-progress --no-interaction --memory-limit 4G -c Build/phpstan/phpstan.neon --generate-baseline=Build/phpstan/phpstan-baseline.neon ${EXTRA_TEST_OPTIONS} + " + + unit: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR}/.Build + extra_hosts: + - "host.docker.internal:host-gateway" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP' + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + bin/phpunit -c Web/typo3conf/ext/indexed_search_gc/Build/phpunit/UnitTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + else + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=host.docker.internal\" \ + bin/phpunit -c Web/typo3conf/ext/indexed_search_gc/Build/phpunit/UnitTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + fi + " diff --git a/Classes/Service/GarbageCollectorService.php b/Classes/Service/GarbageCollectorService.php index a917e20..75f1030 100644 --- a/Classes/Service/GarbageCollectorService.php +++ b/Classes/Service/GarbageCollectorService.php @@ -2,7 +2,6 @@ namespace KKSoftware\IndexedSearchGC\Service; - use Doctrine\DBAL\Driver\Statement; use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\ConnectionPool; @@ -10,10 +9,6 @@ use TYPO3\CMS\Core\Log\LogManager; use TYPO3\CMS\Core\Utility\GeneralUtility; -/** - * Class GarbageCollectorService - * @package KKSoftware\IndexedSearchGC\Service - */ class GarbageCollectorService { /** @@ -34,18 +29,16 @@ class GarbageCollectorService protected $connection; /** - * @var Statement[] $statements + * @var array */ protected $statements = []; - /** - * - */ protected const TABLE_INDEX = 'index_phash'; /** * GarbageCollectorService constructor. - * @param $cleanupDelay + * + * @param int $cleanupDelay */ public function __construct(int $cleanupDelay = 48) { @@ -53,10 +46,7 @@ public function __construct(int $cleanupDelay = 48) $this->logger = GeneralUtility::makeInstance(LogManager::class)->getLogger(__CLASS__); } - /** - * - */ - public function collect() + public function collect(): void { $this->logger->debug('Garbage Collection Started'); @@ -85,10 +75,7 @@ public function collect() } } - /** - * - */ - protected function prepareStatements() + protected function prepareStatements(): void { $this->statements[] = $this->connection->prepare('DELETE FROM index_fulltext WHERE phash = ?'); $this->statements[] = $this->connection->prepare('DELETE FROM index_section WHERE phash = ?'); @@ -100,7 +87,7 @@ protected function prepareStatements() /** * @param int $phash */ - protected function deleteData(int $phash) + protected function deleteData(int $phash): void { $counter = 0; @@ -115,4 +102,4 @@ protected function deleteData(int $phash) $this->logger->info('Deleted Rows', [$counter]); } -} \ No newline at end of file +} diff --git a/Classes/Task/GarbageCollector.php b/Classes/Task/GarbageCollector.php index 5394d25..d482948 100644 --- a/Classes/Task/GarbageCollector.php +++ b/Classes/Task/GarbageCollector.php @@ -10,10 +10,6 @@ use TYPO3\CMS\Extbase\Object\ObjectManager; use TYPO3\CMS\Scheduler\Task\AbstractTask; -/** - * Class GarbageCollector - * @package KKSoftware\IndexedSearchGC\Task - */ class GarbageCollector extends AbstractTask { /** diff --git a/Tests/.gitkeep b/Tests/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/composer.json b/composer.json index 29b25b6..8d373d7 100644 --- a/composer.json +++ b/composer.json @@ -20,21 +20,42 @@ } ], "require": { + "php": "^7.2 || ^7.3 || ^7.4", "typo3/cms-core": "^9.5 || ^10.4", "typo3/cms-indexed-search": "^9.5 || ^10.4", - "typo3/cms-scheduler": "^9.5 || ^10.4" + "typo3/cms-scheduler": "^9.5 || ^10.4", + "typo3/minimal": "^10.4" }, "require-dev": { - "roave/security-advisories": "dev-master" + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^1.4.5", + "phpunit/phpunit": "^7.5.6 || ^8.5.25", + "typo3/testing-framework": "^4.15.5 || ^5.0.16" + }, + "config": { + "sort-packages": true, + "vendor-dir": ".Build/vendor", + "bin-dir": ".Build/bin", + "allow-plugins": { + "typo3/cms-composer-installers": true, + "typo3/class-alias-loader": true + } }, "autoload": { "psr-4": { "KKSoftware\\IndexedSearchGC\\": "Classes" } }, + "scripts": { + "post-autoload-dump": [ + "TYPO3\\TestingFramework\\Composer\\ExtensionTestEnvironment::prepare" + ] + }, "extra": { "typo3/cms": { - "extension-key": "indexed_search_gc" + "extension-key": "indexed_search_gc", + "cms-package-dir": "{$vendor-dir}/typo3/cms", + "web-dir": ".Build/Web" } } } diff --git a/ext_localconf.php b/ext_localconf.php index 9f355aa..4e9c664 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -4,9 +4,7 @@ die('Access denied.'); } -/* -* Configuration for Scheduler TASK -*/ +// Configuration for Scheduler TASK $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\KKSoftware\IndexedSearchGC\Task\GarbageCollector::class] = [ 'extension' => 'indexed_search_gc', 'title' => 'Indexed Search Garbage Collection',