diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..c1108e7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +/.github/ export-ignore +/Build/ export-ignore +/Tests/ export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a4ebdfe --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +.cache/ +.idea/ +Build/ +bin/ +Documentation-GENERATED-temp/ +typo3temp/ +var/ +public/ +vendor/ +composer.lock +.php-cs-fixer.cache diff --git a/Build/Scripts/additionalTests.sh b/Build/Scripts/additionalTests.sh new file mode 100755 index 0000000..49fb49a --- /dev/null +++ b/Build/Scripts/additionalTests.sh @@ -0,0 +1,411 @@ +#!/usr/bin/env bash + +# +# TYPO3 core test runner based on docker or podman +# + +trap 'cleanUp;exit 2' SIGINT + +waitFor() { + local HOST=${1} + local PORT=${2} + local TESTCOMMAND=" + COUNT=0; + while ! nc -z ${HOST} ${PORT}; do + if [ \"\${COUNT}\" -gt 10 ]; then + echo \"Can not connect to ${HOST} port ${PORT}. Aborting.\"; + exit 1; + fi; + sleep 1; + COUNT=\$((COUNT + 1)); + done; + " + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name wait-for-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${IMAGE_ALPINE} /bin/sh -c "${TESTCOMMAND}" + if [[ $? -gt 0 ]]; then + kill -SIGINT -$$ + fi +} + +cleanUp() { + ATTACHED_CONTAINERS=$(${CONTAINER_BIN} ps --filter network=${NETWORK} --format='{{.Names}}') + for ATTACHED_CONTAINER in ${ATTACHED_CONTAINERS}; do + ${CONTAINER_BIN} kill ${ATTACHED_CONTAINER} >/dev/null + done + if [ ${CONTAINER_BIN} = "docker" ]; then + ${CONTAINER_BIN} network rm ${NETWORK} >/dev/null + else + ${CONTAINER_BIN} network rm -f ${NETWORK} >/dev/null + fi +} + +handleDbmsOptions() { + # -a, -d, -i depend on each other. Validate input combinations and set defaults. + case ${DBMS} in + mariadb) + [ -z "${DATABASE_DRIVER}" ] && DATABASE_DRIVER="mysqli" + if [ "${DATABASE_DRIVER}" != "mysqli" ] && [ "${DATABASE_DRIVER}" != "pdo_mysql" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="10.4" + if ! [[ ${DBMS_VERSION} =~ ^(10.4|10.5|10.6|10.7|10.8|10.9|10.10|10.11|11.0|11.1)$ ]]; then + echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + mysql) + [ -z "${DATABASE_DRIVER}" ] && DATABASE_DRIVER="mysqli" + if [ "${DATABASE_DRIVER}" != "mysqli" ] && [ "${DATABASE_DRIVER}" != "pdo_mysql" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="8.0" + if ! [[ ${DBMS_VERSION} =~ ^(8.0|8.1|8.2|8.3)$ ]]; then + echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + postgres) + if [ -n "${DATABASE_DRIVER}" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="10" + if ! [[ ${DBMS_VERSION} =~ ^(10|11|12|13|14|15|16)$ ]]; then + echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + sqlite) + if [ -n "${DATABASE_DRIVER}" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + if [ -n "${DBMS_VERSION}" ]; then + echo "Invalid combination -d ${DBMS} -i ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + *) + echo "Invalid option -d ${DBMS}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + ;; + esac +} + +cleanBuildFiles() { + echo -n "Clean builds ... " + rm -rf \ + Build/JavaScript \ + Build/node_modules \ + Documentation-GENERATED-temp + echo "done" +} + +cleanTestFiles() { + # test related + echo -n "Clean test related files ... " + rm -rf \ + bin/ \ + Build/phpunit \ + public/ \ + typo3temp/ \ + vendor/ \ + var/ \ + composer.lock + git checkout composer.json + echo "done" +} + +getPhpImageVersion() { + case ${1} in + 8.1) + echo -n "2.12" + ;; + 8.2) + echo -n "1.12" + ;; + 8.3) + echo -n "1.13" + ;; + esac +} + +loadHelp() { + # Load help text into $HELP + read -r -d '' HELP < + Specifies the test suite to run + - buildDocumentation: test build the documentation + - clean: clean up build, cache and testing related files and folders + - composerInstallPackage: install a package with composer + - lintXliff: test XLIFF language files + + -b + Container environment: + - podman (default) + - docker + + -p <8.1|8.2|8.3> + Specifies the PHP minor version to be used + - 8.1: use PHP 8.1 + - 8.2 (default): use PHP 8.2 + - 8.3: use PHP 8.3 + + -q + package to be installed by composer + + -r + parameters used with composer commands + + -h + Show this help. + + -v + Enable verbose script output. Shows variables and docker commands. + +Examples: + # Run install a package with composer + ./Build/Scripts/additionalTests.sh -p 8.2 -s composerInstallPackage "typo3/cms-core:13.0" + + # Test build the documentation + ./Build/Scripts/additionalTests.sh -s buildDocumentation + + # Test XLIFF language files + ./Build/Scripts/additionalTests.sh -s lintXliff +EOF +} + +# Test if docker exists, else exit out with error +if ! type "docker" >/dev/null; then + echo "This script relies on docker. Please install" >&2 + exit 1 +fi + +# Option defaults +TEST_SUITE="unit" +DBMS="sqlite" +DBMS_VERSION="" +PHP_VERSION="8.1" +PHP_XDEBUG_ON=0 +PHP_XDEBUG_PORT=9003 +ACCEPTANCE_HEADLESS=1 +EXTRA_TEST_OPTIONS="" +PHPUNIT_RANDOM="" +CGLCHECK_DRY_RUN="" +DATABASE_DRIVER="" +CHUNKS=0 +THISCHUNK=0 +CONTAINER_BIN="docker" + +SCRIPT_VERBOSE=0 +COMPOSER_PACKAGE="" +COMPOSER_PARAMETER="" + +# Option parsing updates above default vars +# 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:p:q:r:hv" OPT; do + case ${OPT} in + s) + TEST_SUITE=${OPTARG} + ;; + p) + PHP_VERSION=${OPTARG} + if ! [[ ${PHP_VERSION} =~ ^(8.1|8.2|8.3)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + fi + ;; + q) + COMPOSER_PACKAGE=${OPTARG} + ;; + r) + COMPOSER_PARAMETER=${OPTARG} + ;; + h) + loadHelp + echo "${HELP}" + exit 0 + ;; + 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 "Use \"./Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 +fi + +handleDbmsOptions + +COMPOSER_ROOT_VERSION="7.0.1" +HOST_UID=$(id -u) +HOST_PID=$(id -g) +USERSET="" +if [ $(uname) != "Darwin" ]; then + USERSET="--user $HOST_UID" +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, then go up two dirs. +THIS_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" +cd "$THIS_SCRIPT_DIR" || exit 1 +cd ../../ || exit 1 +CORE_ROOT="${PWD}" + +# Create .cache dir: composer and various npm jobs need this. +mkdir -p .cache +mkdir -p typo3temp/var/tests + +PHPSTAN_CONFIG_FILE="phpstan.local.neon" +IMAGE_PREFIX="docker.io/" +# Non-CI fetches TYPO3 images (php and nodejs) from ghcr.io +TYPO3_IMAGE_PREFIX="ghcr.io/" +CONTAINER_INTERACTIVE="-it --init" + +IS_CORE_CI=0 +# ENV var "CI" is set by gitlab-ci. We use it here to distinct 'local' and 'CI' environment. +if [ "${CI}" == "true" ]; then + IS_CORE_CI=1 + PHPSTAN_CONFIG_FILE="phpstan.ci.neon" + # In CI, we need to pull images from docker.io for the registry proxy to kick in. + TYPO3_IMAGE_PREFIX="docker.io/" + IMAGE_PREFIX="" + CONTAINER_INTERACTIVE="" +fi + + +IMAGE_APACHE="${TYPO3_IMAGE_PREFIX}typo3/core-testing-apache24:latest" +IMAGE_PHP="${TYPO3_IMAGE_PREFIX}typo3/core-testing-$(echo "php${PHP_VERSION}" | sed -e 's/\.//'):latest" +IMAGE_NODEJS="${TYPO3_IMAGE_PREFIX}typo3/core-testing-nodejs18:latest" +IMAGE_NODEJS_CHROME="${TYPO3_IMAGE_PREFIX}typo3/core-testing-nodejs18-chrome:latest" +IMAGE_ALPINE="${IMAGE_PREFIX}alpine:3.8" +IMAGE_SELENIUM="${IMAGE_PREFIX}selenium/standalone-chrome:4.11.0-20230801" +IMAGE_REDIS="${IMAGE_PREFIX}redis:4-alpine" +IMAGE_MEMCACHED="${IMAGE_PREFIX}memcached:1.5-alpine" +IMAGE_MARIADB="${IMAGE_PREFIX}mariadb:${DBMS_VERSION}" +IMAGE_MYSQL="${IMAGE_PREFIX}mysql:${DBMS_VERSION}" +IMAGE_POSTGRES="${IMAGE_PREFIX}postgres:${DBMS_VERSION}-alpine" +IMAGE_DOCUMENTATION="ghcr.io/t3docs/render-documentation:v3.0.dev30" +IMAGE_XLIFF="container.registry.gitlab.typo3.org/qa/example-extension:typo3-ci-xliff-lint" + +# Detect arm64 to use seleniarm image. +ARCH=$(uname -m) +if [ ${ARCH} = "arm64" ]; then + IMAGE_SELENIUM="${IMAGE_PREFIX}seleniarm/standalone-chromium:4.1.2-20220227" + echo "Architecture" ${ARCH} "requires" ${IMAGE_SELENIUM} "to run acceptance tests." +fi + +# Set $1 to first mass argument, this is the optional test file or test directory to execute +shift $((OPTIND - 1)) +TEST_FILE=${1} + +SUFFIX=$(echo $RANDOM) +NETWORK="typo3-core-${SUFFIX}" +${CONTAINER_BIN} network create ${NETWORK} >/dev/null + +CONTAINER_COMMON_PARAMS="${CONTAINER_INTERACTIVE} --rm --network $NETWORK --add-host "host.docker.internal:host-gateway" $USERSET -v ${CORE_ROOT}:${CORE_ROOT}" + +if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE="-e XDEBUG_MODE=off" + XDEBUG_CONFIG=" " + PHP_FPM_OPTIONS="-d xdebug.mode=off" +else + XDEBUG_MODE="-e XDEBUG_MODE=debug -e XDEBUG_TRIGGER=foo" + XDEBUG_CONFIG="client_port=${PHP_XDEBUG_PORT} client_host=host.docker.internal" + PHP_FPM_OPTIONS="-d xdebug.mode=debug -d xdebug.start_with_request=yes -d xdebug.client_host=host.docker.internal -d xdebug.client_port=${PHP_XDEBUG_PORT} -d memory_limit=256M" +fi +# if host uid is root, like for example on ci we need to set additional php-fpm command line options +if [ "${HOST_UID}" = 0 ]; then + PHP_FPM_OPTIONS+=" --allow-to-run-as-root" +fi + +# Suite execution +case ${TEST_SUITE} in + buildDocumentation) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} -v ${CORE_ROOT}:/project ghcr.io/typo3-documentation/render-guides:latest render Documentation + SUITE_EXIT_CODE=$? + ;; + clean) + cleanBuildFiles + cleanTestFiles + ;; + composerInstallPackage) + COMMAND="[ ${SCRIPT_VERBOSE} -eq 1 ] && set -x; composer require -W -n ${COMPOSER_PARAMETER} ${COMPOSER_PACKAGE};" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-require-package-${SUFFIX} -w ${CORE_ROOT} -e COMPOSER_CACHE_DIR=${CORE_ROOT}/Build/.cache/composer ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + lintXliff) + COMMAND="[ ${SCRIPT_VERBOSE} -eq 1 ] && set -x; xmllint --schema /xliff-core-1.2-strict.xsd --noout *.xlf;" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name lint-xliff-${SUFFIX} -w ${CORE_ROOT}/Resources/Private/Language ${IMAGE_XLIFF} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; +esac + +cleanUp + +# Print summary +echo "" >&2 +echo "###########################################################################" >&2 +echo "Result of ${TEST_SUITE}" >&2 +if [[ ${IS_CORE_CI} -eq 1 ]]; then + echo "Environment: CI" >&2 +else + echo "Environment: local" >&2 +fi +echo "PHP: ${PHP_VERSION}" >&2 +if [[ "${COMPOSER_PACKAGE}" != "" ]]; then + echo "Package: ${COMPOSER_PACKAGE}" >&2 +fi +if [[ ${SUITE_EXIT_CODE} -eq 0 ]]; then + echo "SUCCESS" >&2 +else + echo "FAILURE" >&2 +fi +echo "###########################################################################" >&2 +echo "" >&2 + +# Exit with code of test suite - This script return non-zero if the executed test failed. +exit $SUITE_EXIT_CODE diff --git a/Build/Scripts/runTests.sh b/Build/Scripts/runTests.sh new file mode 100755 index 0000000..b929768 --- /dev/null +++ b/Build/Scripts/runTests.sh @@ -0,0 +1,1147 @@ +#!/usr/bin/env bash + +# +# TYPO3 core test runner based on docker or podman +# + +trap 'cleanUp;exit 2' SIGINT + +waitFor() { + local HOST=${1} + local PORT=${2} + local TESTCOMMAND=" + COUNT=0; + while ! nc -z ${HOST} ${PORT}; do + if [ \"\${COUNT}\" -gt 10 ]; then + echo \"Can not connect to ${HOST} port ${PORT}. Aborting.\"; + exit 1; + fi; + sleep 1; + COUNT=\$((COUNT + 1)); + done; + " + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name wait-for-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${IMAGE_ALPINE} /bin/sh -c "${TESTCOMMAND}" + if [[ $? -gt 0 ]]; then + kill -SIGINT -$$ + fi +} + +cleanUp() { + ATTACHED_CONTAINERS=$(${CONTAINER_BIN} ps --filter network=${NETWORK} --format='{{.Names}}') + for ATTACHED_CONTAINER in ${ATTACHED_CONTAINERS}; do + ${CONTAINER_BIN} kill ${ATTACHED_CONTAINER} >/dev/null + done + if [ ${CONTAINER_BIN} = "docker" ]; then + ${CONTAINER_BIN} network rm ${NETWORK} >/dev/null + else + ${CONTAINER_BIN} network rm -f ${NETWORK} >/dev/null + fi +} + +handleDbmsOptions() { + # -a, -d, -i depend on each other. Validate input combinations and set defaults. + case ${DBMS} in + mariadb) + [ -z "${DATABASE_DRIVER}" ] && DATABASE_DRIVER="mysqli" + if [ "${DATABASE_DRIVER}" != "mysqli" ] && [ "${DATABASE_DRIVER}" != "pdo_mysql" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="10.4" + if ! [[ ${DBMS_VERSION} =~ ^(10.4|10.5|10.6|10.7|10.8|10.9|10.10|10.11|11.0|11.1)$ ]]; then + echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + mysql) + [ -z "${DATABASE_DRIVER}" ] && DATABASE_DRIVER="mysqli" + if [ "${DATABASE_DRIVER}" != "mysqli" ] && [ "${DATABASE_DRIVER}" != "pdo_mysql" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="8.0" + if ! [[ ${DBMS_VERSION} =~ ^(8.0|8.1|8.2|8.3)$ ]]; then + echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + postgres) + if [ -n "${DATABASE_DRIVER}" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="10" + if ! [[ ${DBMS_VERSION} =~ ^(10|11|12|13|14|15|16)$ ]]; then + echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + sqlite) + if [ -n "${DATABASE_DRIVER}" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + if [ -n "${DBMS_VERSION}" ]; then + echo "Invalid combination -d ${DBMS} -i ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + *) + echo "Invalid option -d ${DBMS}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + ;; + esac +} + +cleanBuildFiles() { + echo -n "Clean builds ... " + rm -rf \ + Build/JavaScript \ + Build/node_modules + echo "done" +} + +cleanCacheFiles() { + echo -n "Clean caches ... " + rm -rf \ + .cache \ + Build/.cache \ + Build/composer/.cache/ \ + .php-cs-fixer.cache + echo "done" +} + +cleanTestFiles() { + # composer distribution test + echo -n "Clean composer distribution test ... " + rm -rf \ + Build/composer/composer.json \ + Build/composer/composer.lock \ + Build/composer/public/index.php \ + Build/composer/public/typo3 \ + Build/composer/public/typo3conf/ext \ + Build/composer/var/ \ + Build/composer/vendor/ + echo "done" + + # test related + echo -n "Clean test related files ... " + rm -rf \ + Build/phpunit/FunctionalTests-Job-*.xml \ + typo3/sysext/core/Tests/AcceptanceTests-Job-* \ + typo3/sysext/core/Tests/Acceptance/Support/_generated \ + typo3temp/var/tests/ + echo "done" +} + +cleanRenderedDocumentationFiles() { + echo -n "Clean rendered documentation files ... " + rm -rf \ + ../../../typo3/sysext/*/Documentation-GENERATED-temp + echo "done" +} + +getPhpImageVersion() { + case ${1} in + 8.1) + echo -n "2.12" + ;; + 8.2) + echo -n "1.12" + ;; + 8.3) + echo -n "1.13" + ;; + esac +} + +loadHelp() { + # Load help text into $HELP + read -r -d '' HELP < + Specifies the test suite to run + - acceptance: main application acceptance tests + - acceptanceComposer: main application acceptance tests + - acceptanceInstall: installation acceptance tests, only with -d mariadb|postgres|sqlite + - buildCss: execute scss to css builder + - buildJavascript: execute typescript to javascript builder + - cgl: test and fix all core php files + - cglGit: test and fix latest committed patch for CGL compliance + - cglHeader: test and fix file header for all core php files + - cglHeaderGit: test and fix latest committed patch for CGL file header compliance + - checkAnnotations: check php code for allowed annotations + - checkBom: check UTF-8 files do not contain BOM + - checkComposer: check composer.json files for version integrity + - checkExceptionCodes: test core for duplicate exception codes + - checkExtensionScannerRst: test all .rst files referenced by extension scanner exist + - checkFilePathLength: test core file paths do not exceed maximum length + - checkGitSubmodule: test core git has no sub modules defined + - checkGruntClean: Verify "grunt build" is clean. Warning: Executes git commands! Usually used in CI only. + - checkIsoDatabase: Verify "updateIsoDatabase.php" does not change anything. + - checkNamespaceIntegrity: Verify namespace integrity in class and test code files are in good shape. + - checkPermissions: test some core files for correct executable bits + - checkRst: test .rst files for integrity + - checkTestClassFinal: check test case classes are final + - checkTestMethodsPrefix: check tests methods do not start with "test" + - clean: clean up build, cache and testing related files and folders + - cleanBuild: clean up build related files and folders + - cleanCache: clean up cache related files and folders + - cleanRenderedDocumentation: clean up rendered documentation files and folders (Documentation-GENERATED-temp) + - cleanTests: clean up test related files and folders + - composer: "composer" command dispatcher, to execute various composer commands + - 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. + - composerTestDistribution: "composer update" in Build/composer to verify core dependencies + - composerValidate: "composer validate" + - functional: PHP functional tests + - functionalDeprecated: deprecated PHP functional tests + - lintPhp: PHP linting + - lintScss: SCSS linting + - lintTypescript: TS linting + - lintHtml: HTML linting + - listExceptionCodes: list core exception codes in JSON format + - npm: "npm" command dispatcher, to execute various npm commands directly + - phpstan: phpstan tests + - phpstanGenerateBaseline: regenerate phpstan baseline, handy after phpstan updates + - unit (default): PHP unit tests + - unitDeprecated: deprecated PHP unit tests + - unitJavascript: JavaScript unit tests + - unitRandom: PHP unit tests in random order, add -o to use specific seed + + -b + Container environment: + - podman (default) + - docker + + -a + Only with -s functional|functionalDeprecated + Specifies to use another driver, following combinations are available: + - mysql + - mysqli (default) + - pdo_mysql + - mariadb + - mysqli (default) + - pdo_mysql + + -d + Only with -s functional|functionalDeprecated|acceptance|acceptanceComposer|acceptanceInstall + Specifies on which DBMS tests are performed + - sqlite: (default): use sqlite + - mariadb: use mariadb + - mysql: use MySQL + - postgres: use postgres + + -i version + Specify a specific database version + With "-d mariadb": + - 10.4 short-term, maintained until 2024-06-18 (default) + - 10.5 short-term, maintained until 2025-06-24 + - 10.6 long-term, maintained until 2026-06 + - 10.7 short-term, no longer maintained + - 10.8 short-term, maintained until 2023-05 + - 10.9 short-term, maintained until 2023-08 + - 10.10 short-term, maintained until 2023-11 + - 10.11 long-term, maintained until 2028-02 + - 11.0 development series + - 11.1 short-term development series + With "-d mysql": + - 8.0 maintained until 2026-04 (default) LTS + - 8.1 unmaintained since 2023-10 + - 8.2 unmaintained since 2024-01 + - 8.3 maintained until 2024-04 + With "-d postgres": + - 10 unmaintained since 2022-11-10 (default) + - 11 unmaintained since 2023-11-09 + - 12 maintained until 2024-11-14 + - 13 maintained until 2025-11-13 + - 14 maintained until 2026-11-12 + - 15 maintained until 2027-11-11 + - 16 maintained until 2028-11-09 + + -c + Only with -s functional|acceptance + Hack functional or acceptance tests into #numberOfChunks pieces and run tests of #chunk. + Example -c 3/13 + + -p <8.1|8.2|8.3> + Specifies the PHP minor version to be used + - 8.1: use PHP 8.1 + - 8.2 (default): use PHP 8.2 + - 8.3: use PHP 8.3 + + -t sets|systemplate + Only with -s acceptance|acceptanceComposer + Specifies which frontend rendering mechanism should be used + - sets: (default): use site sets + - systemplate: use sys_template records + + -e "" (DEPRECATED). + Only with -s functional|functionalDeprecated|unit|unitDeprecated|unitRandom|acceptance + Additional options to send to phpunit (unit & functional tests) or codeception (acceptance + tests). For phpunit, options starting with "--" must be added after options starting with "-". + Example -e "-d memory_limit=-1 --filter filterByValueRecursiveCorrectlyFiltersArray" to enable verbose output AND filter tests + named "canRetrieveValueWithGP" + + DEPRECATED - pass arguments after the `--` separator directly. For example, instead of + Build/Scripts/runTests.sh -s unit -e "--filter filterByValueRecursiveCorrectlyFiltersArray" + use + Build/Scripts/runTests.sh -s unit -- --filter filterByValueRecursiveCorrectlyFiltersArray + + -g + Only with -s acceptance|acceptanceComposer|acceptanceInstall + Activate selenium grid as local port to watch browser clicking around. Can be surfed using + http://localhost:7900/. A browser tab is opened automatically if xdg-open is installed. + + -x + Only with -s functional|functionalDeprecated|unit|unitDeprecated|unitRandom|acceptance|acceptanceComposer|acceptanceInstall + 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. + + -o + Only with -s unitRandom + Set specific random seed to replay a random run in this order again. The phpunit randomizer + outputs the used seed at the end (in gitlab core testing logs, too). Use that number to + replay the unit tests in that order. + + -n + Only with -s cgl|cglGit|cglHeader|cglHeaderGit + Activate dry-run in CGL check that does not actively change files and only prints broken ones. + + -u + Update existing typo3/core-testing-* container images and remove obsolete dangling image versions. + Use this if weird test errors occur. + + -h + Show this help. + +Examples: + # Run all core unit tests using PHP 8.2 + ./Build/Scripts/runTests.sh + ./Build/Scripts/runTests.sh -s unit + + # Run all core units tests and enable xdebug (have a PhpStorm listening on port 9003!) + ./Build/Scripts/runTests.sh -x + + # Run unit tests in phpunit with xdebug on PHP 8.3 and filter for test filterByValueRecursiveCorrectlyFiltersArray + ./Build/Scripts/runTests.sh -x -p 8.3 -- --filter filterByValueRecursiveCorrectlyFiltersArray + + # Run functional tests in phpunit with a filtered test method name in a specified file + # example will currently execute two tests, both of which start with the search term + ./Build/Scripts/runTests.sh -s functional -- \ + --filter datetimeInstanceCanBePersistedToDatabaseIfTypeIsExplicitlySpecified \ + typo3/sysext/core/Tests/Functional/Database/ConnectionTest.php + + # Run functional tests on postgres with xdebug, php 8.3 and execute a restricted set of tests + ./Build/Scripts/runTests.sh -x -p 8.3 -s functional -d postgres typo3/sysext/core/Tests/Functional/Authentication + + # Run functional tests on postgres 11 + ./Build/Scripts/runTests.sh -s functional -d postgres -i 11 + + # Run restricted set of application acceptance tests + ./Build/Scripts/runTests.sh -s acceptance typo3/sysext/core/Tests/Acceptance/Application/Login/BackendLoginCest.php:loginButtonMouseOver + + # Run installer tests of a new instance on sqlite + ./Build/Scripts/runTests.sh -s acceptanceInstall -d sqlite + + # Run composer require to require a dependency + ./Build/Scripts/runTests.sh -s composer -- require --dev typo3/testing-framework:dev-main + + # Some composer command examples + ./Build/Scripts/runTests.sh -s composer -- dumpautoload + ./Build/Scripts/runTests.sh -s composer -- info | grep "symfony" + + # Some npm command examples + ./Build/Scripts/runTests.sh -s npm -- audit + ./Build/Scripts/runTests.sh -s npm -- ci + ./Build/Scripts/runTests.sh -s npm -- run build + ./Build/Scripts/runTests.sh -s npm -- run watch:build + ./Build/Scripts/runTests.sh -s npm -- install --save bootstrap@^5.3.2 +EOF +} + +# Test if docker exists, else exit out with error +if ! type "docker" >/dev/null 2>&1 && ! type "podman" >/dev/null 2>&1; then + echo "This script relies on docker or podman. 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, then go up two dirs. +THIS_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" +cd "$THIS_SCRIPT_DIR" || exit 1 +cd ../../ || exit 1 +CORE_ROOT="${PWD}" + +# Default variables +TEST_SUITE="unit" +DBMS="sqlite" +DBMS_VERSION="" +PHP_VERSION="8.2" +PHP_XDEBUG_ON=0 +PHP_XDEBUG_PORT=9003 +ACCEPTANCE_HEADLESS=1 +ACCEPTANCE_TOPIC="sets" +EXTRA_TEST_OPTIONS="" +PHPUNIT_RANDOM="" +CGLCHECK_DRY_RUN="" +DATABASE_DRIVER="" +CHUNKS=0 +THISCHUNK=0 +CONTAINER_BIN="" +COMPOSER_ROOT_VERSION="13.2.x-dev" +PHPSTAN_CONFIG_FILE="phpstan.local.neon" +CONTAINER_INTERACTIVE="-it --init" +HOST_UID=$(id -u) +HOST_PID=$(id -g) +USERSET="" +SUFFIX=$(echo $RANDOM) +NETWORK="typo3-core-${SUFFIX}" +CI_PARAMS="${CI_PARAMS:-}" +CONTAINER_HOST="host.docker.internal" + +# Option parsing updates above default vars +# 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 ":a:b:s:c:d:i:t:p:e:xy:o:nhug" OPT; do + case ${OPT} in + s) + TEST_SUITE=${OPTARG} + ;; + b) + if ! [[ ${OPTARG} =~ ^(docker|podman)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + fi + CONTAINER_BIN=${OPTARG} + ;; + a) + DATABASE_DRIVER=${OPTARG} + ;; + c) + if ! [[ ${OPTARG} =~ ^([0-9]+\/[0-9]+)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + else + # Split "2/13" - run chunk 2 of 13 chunks + THISCHUNK=$(echo "${OPTARG}" | cut -d '/' -f1) + CHUNKS=$(echo "${OPTARG}" | cut -d '/' -f2) + fi + ;; + d) + DBMS=${OPTARG} + ;; + i) + DBMS_VERSION=${OPTARG} + ;; + p) + PHP_VERSION=${OPTARG} + if ! [[ ${PHP_VERSION} =~ ^(8.1|8.2|8.3)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + fi + ;; + e) + EXTRA_TEST_OPTIONS=${OPTARG} + ;; + g) + ACCEPTANCE_HEADLESS=0 + ;; + t) + ACCEPTANCE_TOPIC=${OPTARG} + ;; + x) + PHP_XDEBUG_ON=1 + ;; + y) + PHP_XDEBUG_PORT=${OPTARG} + ;; + o) + PHPUNIT_RANDOM="--random-order-seed=${OPTARG}" + ;; + n) + CGLCHECK_DRY_RUN="-n" + ;; + h) + loadHelp + echo "${HELP}" + exit 0 + ;; + u) + TEST_SUITE=update + ;; + \?) + 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 "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 +fi + +handleDbmsOptions + +# ENV var "CI" is set by gitlab-ci. Use it to force some CI details. +if [ "${CI}" == "true" ]; then + PHPSTAN_CONFIG_FILE="phpstan.ci.neon" + CONTAINER_INTERACTIVE="" +fi + +# determine default container binary to use: 1. podman 2. docker +if [[ -z "${CONTAINER_BIN}" ]]; then + if type "podman" >/dev/null 2>&1; then + CONTAINER_BIN="podman" + elif type "docker" >/dev/null 2>&1; then + CONTAINER_BIN="docker" + fi +fi + +if [ $(uname) != "Darwin" ] && [ ${CONTAINER_BIN} = "docker" ]; then + # Run docker jobs as current user to prevent permission issues. Not needed with podman. + USERSET="--user $HOST_UID" +fi + +if ! type ${CONTAINER_BIN} >/dev/null 2>&1; then + echo "Selected container environment \"${CONTAINER_BIN}\" not found. Please install or use -b option to select one." >&2 + exit 1 +fi + +IMAGE_APACHE="ghcr.io/typo3/core-testing-apache24:1.3" +IMAGE_PHP="ghcr.io/typo3/core-testing-$(echo "php${PHP_VERSION}" | sed -e 's/\.//'):$(getPhpImageVersion $PHP_VERSION)" + +IMAGE_NODEJS="ghcr.io/typo3/core-testing-nodejs22:1.0" +IMAGE_NODEJS_CHROME="ghcr.io/typo3/core-testing-nodejs22-chrome:1.0" +IMAGE_ALPINE="docker.io/alpine:3.8" +IMAGE_SELENIUM="docker.io/selenium/standalone-chrome:4.11.0-20230801" +IMAGE_REDIS="docker.io/redis:4-alpine" +IMAGE_MEMCACHED="docker.io/memcached:1.5-alpine" +IMAGE_MARIADB="docker.io/mariadb:${DBMS_VERSION}" +IMAGE_MYSQL="docker.io/mysql:${DBMS_VERSION}" +IMAGE_POSTGRES="docker.io/postgres:${DBMS_VERSION}-alpine" + +# Detect arm64 to use seleniarm image. +ARCH=$(uname -m) +if [ ${ARCH} = "arm64" ]; then + IMAGE_SELENIUM="docker.io/seleniarm/standalone-chromium:4.10.0-20230615" +fi + +# Remove handled options and leaving the rest in the line, so it can be passed raw to commands +shift $((OPTIND - 1)) + +# Create .cache dir: composer and various npm jobs need this. +mkdir -p .cache +mkdir -p typo3temp/var/tests + +${CONTAINER_BIN} network create ${NETWORK} >/dev/null + +if [ ${CONTAINER_BIN} = "docker" ]; then + # docker needs the add-host for xdebug remote debugging. podman has host.container.internal built in + CONTAINER_COMMON_PARAMS="${CONTAINER_INTERACTIVE} --rm --network ${NETWORK} --add-host "${CONTAINER_HOST}:host-gateway" ${USERSET} -v ${CORE_ROOT}:${CORE_ROOT} -w ${CORE_ROOT}" +else + # podman + CONTAINER_HOST="host.containers.internal" + CONTAINER_COMMON_PARAMS="${CONTAINER_INTERACTIVE} ${CI_PARAMS} --rm --network ${NETWORK} -v ${CORE_ROOT}:${CORE_ROOT} -w ${CORE_ROOT}" +fi + +if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE="-e XDEBUG_MODE=off" + XDEBUG_CONFIG=" " + PHP_FPM_OPTIONS="-d xdebug.mode=off" +else + XDEBUG_MODE="-e XDEBUG_MODE=debug -e XDEBUG_TRIGGER=foo" + XDEBUG_CONFIG="client_port=${PHP_XDEBUG_PORT} client_host=${CONTAINER_HOST}" + PHP_FPM_OPTIONS="-d xdebug.mode=debug -d xdebug.start_with_request=yes -d xdebug.client_host=${CONTAINER_HOST} -d xdebug.client_port=${PHP_XDEBUG_PORT} -d memory_limit=256M" +fi + +# Suite execution +case ${TEST_SUITE} in + acceptance) + CODECEPION_ENV="--env ci,classic,${ACCEPTANCE_TOPIC}" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,classic,headless,${ACCEPTANCE_TOPIC}" + fi + if [ "${CHUNKS}" -gt 0 ]; then + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-splitter-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/splitAcceptanceTests.php -v ${CHUNKS} + COMMAND=(bin/codecept run Application -d -g AcceptanceTests-Job-${THISCHUNK} -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} "$@" --html reports.html) + else + COMMAND=(bin/codecept run Application -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} "$@" --html reports.html) + fi + SELENIUM_GRID="" + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ]; then + SELENIUM_GRID="-p 7900:7900 -e SE_VNC_NO_PASSWORD=1 -e VNC_NO_PASSWORD=1" + fi + rm -rf "${CORE_ROOT}/typo3temp/var/tests/acceptance" "${CORE_ROOT}/typo3temp/var/tests/AcceptanceReports" + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/acceptance" + APACHE_OPTIONS="-e APACHE_RUN_USER=#${HOST_UID} -e APACHE_RUN_SERVERNAME=web -e APACHE_RUN_GROUP=#${HOST_PID} -e APACHE_RUN_DOCROOT=${CORE_ROOT}/typo3temp/var/tests/acceptance -e PHPFPM_HOST=phpfpm -e PHPFPM_PORT=9000" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d ${SELENIUM_GRID} --name ac-chrome-${SUFFIX} --network ${NETWORK} --network-alias chrome --tmpfs /dev/shm:rw,nosuid,nodev,noexec ${IMAGE_SELENIUM} >/dev/null + if [ ${CONTAINER_BIN} = "docker" ]; then + ${CONTAINER_BIN} run --rm -d --name ac-phpfpm-${SUFFIX} --network ${NETWORK} --network-alias phpfpm --add-host "${CONTAINER_HOST}:host-gateway" ${USERSET} -e PHPFPM_USER=${HOST_UID} -e PHPFPM_GROUP=${HOST_PID} -v ${CORE_ROOT}:${CORE_ROOT} ${IMAGE_PHP} php-fpm ${PHP_FPM_OPTIONS} >/dev/null + ${CONTAINER_BIN} run --rm -d --name ac-web-${SUFFIX} --network ${NETWORK} --network-alias web --add-host "${CONTAINER_HOST}:host-gateway" -v ${CORE_ROOT}:${CORE_ROOT} ${APACHE_OPTIONS} ${IMAGE_APACHE} >/dev/null + else + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d --name ac-phpfpm-${SUFFIX} --network ${NETWORK} --network-alias phpfpm ${USERSET} -e PHPFPM_USER=0 -e PHPFPM_GROUP=0 -v ${CORE_ROOT}:${CORE_ROOT} ${IMAGE_PHP} php-fpm -R ${PHP_FPM_OPTIONS} >/dev/null + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d --name ac-web-${SUFFIX} --network ${NETWORK} --network-alias web -v ${CORE_ROOT}:${CORE_ROOT} ${APACHE_OPTIONS} ${IMAGE_APACHE} >/dev/null + fi + waitFor chrome 4444 + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ]; then + waitFor chrome 7900 + fi + waitFor web 80 + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ] && type "xdg-open" >/dev/null; then + xdg-open http://localhost:7900/?autoconnect=1 >/dev/null + elif [ "${ACCEPTANCE_HEADLESS}" -eq 0 ] && type "open" >/dev/null; then + open http://localhost:7900/?autoconnect=1 >/dev/null + fi + case ${DBMS} in + mariadb) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mariadb-ac-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MARIADB} >/dev/null + waitFor mariadb-ac-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabasePassword=funcp -e typo3DatabaseHost=mariadb-ac-${SUFFIX}" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-mariadb ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + mysql) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mysql-ac-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MYSQL} >/dev/null + waitFor mysql-ac-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabasePassword=funcp -e typo3DatabaseHost=mysql-ac-${SUFFIX}" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-mysql ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + postgres) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name postgres-ac-${SUFFIX} --network ${NETWORK} -d -e POSTGRES_PASSWORD=funcp -e POSTGRES_USER=funcu --tmpfs /var/lib/postgresql/data:rw,noexec,nosuid ${IMAGE_POSTGRES} >/dev/null + waitFor postgres-ac-${SUFFIX} 5432 + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_pgsql -e typo3DatabaseName=func_test -e typo3DatabaseUsername=funcu -e typo3DatabasePassword=funcp -e typo3DatabaseHost=postgres-ac-${SUFFIX}" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-postgres ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + sqlite) + rm -rf "${CORE_ROOT}/typo3temp/var/tests/acceptance-sqlite-dbs/" + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/acceptance-sqlite-dbs/" + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-sqlite ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + esac + ;; + acceptanceComposer) + rm -rf "${CORE_ROOT}/typo3temp/var/tests/acceptance-composer" "${CORE_ROOT}/typo3temp/var/tests/AcceptanceReports" + + PREPAREPARAMS="" + TESTPARAMS="" + case ${DBMS} in + mariadb) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mariadb-ac-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=acp -e MYSQL_DATABASE=ac_test --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MARIADB} >/dev/null + waitFor mariadb-ac-${SUFFIX} 3306 + PREPAREPARAMS="-e TYPO3_DB_DRIVER=mysqli -e TYPO3_DB_DBNAME=ac_test -e TYPO3_DB_USERNAME=root -e TYPO3_DB_PASSWORD=acp -e TYPO3_DB_HOST=mariadb-ac-${SUFFIX} -e TYPO3_DB_PORT=3306" + TESTPARAMS="-e typo3DatabaseName=ac_test -e typo3DatabaseUsername=root -e typo3DatabasePassword=funcp -e typo3DatabaseHost=mariadb-ac-${SUFFIX}" + ;; + mysql) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mysql-ac-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=acp -e MYSQL_DATABASE=ac_test --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MYSQL} >/dev/null + waitFor mysql-ac-${SUFFIX} 3306 + PREPAREPARAMS="-e TYPO3_DB_DRIVER=mysqli -e TYPO3_DB_DBNAME=ac_test -e TYPO3_DB_USERNAME=root -e TYPO3_DB_PASSWORD=acp -e TYPO3_DB_HOST=mysql-ac-${SUFFIX} -e TYPO3_DB_PORT=3306" + TESTPARAMS="-e typo3DatabaseName=ac_test -e typo3DatabaseUsername=root -e typo3DatabasePassword=funcp -e typo3DatabaseHost=mysql-ac-${SUFFIX}" + ;; + postgres) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name postgres-ac-${SUFFIX} --network ${NETWORK} -d -e POSTGRES_DB=ac_test -e POSTGRES_PASSWORD=acp -e POSTGRES_USER=ac_test --tmpfs /var/lib/postgresql/data:rw,noexec,nosuid ${IMAGE_POSTGRES} >/dev/null + waitFor postgres-ac-${SUFFIX} 5432 + PREPAREPARAMS="-e TYPO3_DB_DRIVER=postgres -e TYPO3_DB_DBNAME=ac_test -e TYPO3_DB_USERNAME=ac_test -e TYPO3_DB_PASSWORD=acp -e TYPO3_DB_HOST=postgres-ac-${SUFFIX} -e TYPO3_DB_PORT=5432" + TESTPARAMS="-e typo3DatabaseDriver=pdo_pgsql -e typo3DatabaseName=ac_test -e typo3DatabaseUsername=ac_test -e typo3DatabasePassword=acp -e typo3DatabaseHost=postgres-ac-${SUFFIX}" + ;; + sqlite) + PREPAREPARAMS="-e TYPO3_DB_DRIVER=sqlite" + TESTPARAMS="-e typo3DatabaseDriver=pdo_sqlite" + ;; + esac + + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name acceptance-prepare ${XDEBUG_MODE} -e COMPOSER_CACHE_DIR=${CORE_ROOT}/.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${PREPAREPARAMS} ${IMAGE_PHP} "${CORE_ROOT}/Build/Scripts/setupAcceptanceComposer.sh" "typo3temp/var/tests/acceptance-composer" sqlite "" "${ACCEPTANCE_TOPIC}" + SUITE_EXIT_CODE=$? + if [[ ${SUITE_EXIT_CODE} -eq 0 ]]; then + CODECEPION_ENV="--env ci,composer,${ACCEPTANCE_TOPIC}" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,composer,headless,${ACCEPTANCE_TOPIC}" + fi + if [ "${CHUNKS}" -gt 0 ]; then + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-splitter-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/splitAcceptanceTests.php -v ${CHUNKS} + COMMAND=(bin/codecept run Application -d -g AcceptanceTests-Job-${THISCHUNK} -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} "$@" --html reports.html) + else + COMMAND=(bin/codecept run Application -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} "$@" --html reports.html) + fi + SELENIUM_GRID="" + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ]; then + SELENIUM_GRID="-p 7900:7900 -e SE_VNC_NO_PASSWORD=1 -e VNC_NO_PASSWORD=1" + fi + APACHE_OPTIONS="-e APACHE_RUN_USER=#${HOST_UID} -e APACHE_RUN_SERVERNAME=web -e APACHE_RUN_GROUP=#${HOST_PID} -e APACHE_RUN_DOCROOT=${CORE_ROOT}/typo3temp/var/tests/acceptance-composer/public -e PHPFPM_HOST=phpfpm -e PHPFPM_PORT=9000" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d ${SELENIUM_GRID} --name ac-chrome-${SUFFIX} --network ${NETWORK} --network-alias chrome --tmpfs /dev/shm:rw,nosuid,nodev,noexec ${IMAGE_SELENIUM} >/dev/null + if [ ${CONTAINER_BIN} = "docker" ]; then + ${CONTAINER_BIN} run --rm -d --name ac-phpfpm-${SUFFIX} --network ${NETWORK} --network-alias phpfpm --add-host "${CONTAINER_HOST}:host-gateway" ${USERSET} -e PHPFPM_USER=${HOST_UID} -e PHPFPM_GROUP=${HOST_PID} -v ${CORE_ROOT}:${CORE_ROOT} ${IMAGE_PHP} php-fpm ${PHP_FPM_OPTIONS} >/dev/null + ${CONTAINER_BIN} run --rm -d --name ac-web-${SUFFIX} --network ${NETWORK} --network-alias web --add-host "${CONTAINER_HOST}:host-gateway" -v ${CORE_ROOT}:${CORE_ROOT} ${APACHE_OPTIONS} ${IMAGE_APACHE} >/dev/null + else + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d --name ac-phpfpm-${SUFFIX} --network ${NETWORK} --network-alias phpfpm ${USERSET} -e PHPFPM_USER=0 -e PHPFPM_GROUP=0 -v ${CORE_ROOT}:${CORE_ROOT} ${IMAGE_PHP} php-fpm -R ${PHP_FPM_OPTIONS} >/dev/null + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d --name ac-web-${SUFFIX} --network ${NETWORK} --network-alias web -v ${CORE_ROOT}:${CORE_ROOT} ${APACHE_OPTIONS} ${IMAGE_APACHE} >/dev/null + fi + waitFor chrome 4444 + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ]; then + waitFor chrome 7900 + fi + waitFor web 80 + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ] && type "xdg-open" >/dev/null; then + xdg-open http://localhost:7900/?autoconnect=1 >/dev/null + elif [ "${ACCEPTANCE_HEADLESS}" -eq 0 ] && type "open" >/dev/null; then + open http://localhost:7900/?autoconnect=1 >/dev/null + fi + + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-${DBMS}-composer ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${TESTPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + fi + ;; + acceptanceInstall) + SELENIUM_GRID="" + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ]; then + SELENIUM_GRID="-p 7900:7900 -e SE_VNC_NO_PASSWORD=1 -e VNC_NO_PASSWORD=1" + fi + rm -rf "${CORE_ROOT}/typo3temp/var/tests/acceptance" "${CORE_ROOT}/typo3temp/var/tests/AcceptanceReports" + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/acceptance" + APACHE_OPTIONS="-e APACHE_RUN_USER=#${HOST_UID} -e APACHE_RUN_SERVERNAME=web -e APACHE_RUN_GROUP=#${HOST_PID} -e APACHE_RUN_DOCROOT=${CORE_ROOT}/typo3temp/var/tests/acceptance -e PHPFPM_HOST=phpfpm -e PHPFPM_PORT=9000" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d ${SELENIUM_GRID} --name ac-install-chrome-${SUFFIX} --network ${NETWORK} --network-alias chrome --tmpfs /dev/shm:rw,nosuid,nodev,noexec ${IMAGE_SELENIUM} >/dev/null + if [ ${CONTAINER_BIN} = "docker" ]; then + ${CONTAINER_BIN} run --rm -d --name ac-install-phpfpm-${SUFFIX} --network ${NETWORK} --network-alias phpfpm --add-host "${CONTAINER_HOST}:host-gateway" ${USERSET} -e PHPFPM_USER=${HOST_UID} -e PHPFPM_GROUP=${HOST_PID} -v ${CORE_ROOT}:${CORE_ROOT} ${IMAGE_PHP} php-fpm ${PHP_FPM_OPTIONS} >/dev/null + ${CONTAINER_BIN} run --rm -d --name ac-install-web-${SUFFIX} --network ${NETWORK} --network-alias web --add-host "${CONTAINER_HOST}:host-gateway" -v ${CORE_ROOT}:${CORE_ROOT} ${APACHE_OPTIONS} ${IMAGE_APACHE} >/dev/null + else + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d --name ac-install-phpfpm-${SUFFIX} --network ${NETWORK} --network-alias phpfpm ${USERSET} -e PHPFPM_USER=0 -e PHPFPM_GROUP=0 -v ${CORE_ROOT}:${CORE_ROOT} ${IMAGE_PHP} php-fpm -R ${PHP_FPM_OPTIONS} >/dev/null + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d --name ac-install-web-${SUFFIX} --network ${NETWORK} --network-alias web -v ${CORE_ROOT}:${CORE_ROOT} ${APACHE_OPTIONS} ${IMAGE_APACHE} >/dev/null + fi + waitFor chrome 4444 + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ]; then + waitFor chrome 7900 + fi + waitFor web 80 + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ] && type "xdg-open" >/dev/null; then + xdg-open http://localhost:7900/?autoconnect=1 >/dev/null + elif [ "${ACCEPTANCE_HEADLESS}" -eq 0 ] && type "open" >/dev/null; then + open http://localhost:7900/?autoconnect=1 >/dev/null + fi + case ${DBMS} in + mariadb) + CODECEPION_ENV="--env ci,mysql" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,mysql,headless" + fi + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mariadb-ac-install-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MARIADB} >/dev/null + waitFor mariadb-ac-install-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3InstallMysqlDatabaseName=func_test -e typo3InstallMysqlDatabaseUsername=root -e typo3InstallMysqlDatabasePassword=funcp -e typo3InstallMysqlDatabaseHost=mariadb-ac-install-${SUFFIX}" + COMMAND="bin/codecept run Install -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} --html reports.html" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-install-mariadb ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + mysql) + CODECEPION_ENV="--env ci,mysql" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,mysql,headless" + fi + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mysql-ac-install-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MYSQL} >/dev/null + waitFor mysql-ac-install-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3InstallMysqlDatabaseName=func_test -e typo3InstallMysqlDatabaseUsername=root -e typo3InstallMysqlDatabasePassword=funcp -e typo3InstallMysqlDatabaseHost=mysql-ac-install-${SUFFIX}" + COMMAND="bin/codecept run Install -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} --html reports.html" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-install-mysql ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + postgres) + CODECEPION_ENV="--env ci,postgresql" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,postgresql,headless" + fi + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name postgres-ac-install-${SUFFIX} --network ${NETWORK} -d -e POSTGRES_PASSWORD=funcp -e POSTGRES_USER=funcu --tmpfs /var/lib/postgresql/data:rw,noexec,nosuid ${IMAGE_POSTGRES} >/dev/null + waitFor postgres-ac-install-${SUFFIX} 5432 + CONTAINERPARAMS="-e typo3InstallPostgresqlDatabasePort=5432 -e typo3InstallPostgresqlDatabaseName=${USER} -e typo3InstallPostgresqlDatabaseHost=postgres-ac-install-${SUFFIX} -e typo3InstallPostgresqlDatabaseUsername=funcu -e typo3InstallPostgresqlDatabasePassword=funcp" + COMMAND="bin/codecept run Install -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} --html reports.html" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-install-postgres ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + sqlite) + rm -rf "${CORE_ROOT}/typo3temp/var/tests/acceptance-sqlite-dbs/" + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/acceptance-sqlite-dbs/" + CODECEPION_ENV="--env ci,sqlite" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,sqlite,headless" + fi + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite" + COMMAND="bin/codecept run Install -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} --html reports.html" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-install-sqlite ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + esac + ;; + buildCss) + COMMAND="cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt css" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name build-css-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + buildJavascript) + COMMAND="cd Build/; npm ci || exit 1; node_modules/grunt/bin/grunt scripts" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name build-js-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + cgl) + # Active dry-run for cgl needs not "-n" but specific options + if [ -n "${CGLCHECK_DRY_RUN}" ]; then + CGLCHECK_DRY_RUN="--dry-run --diff" + fi + COMMAND="php -dxdebug.mode=off bin/php-cs-fixer fix -v ${CGLCHECK_DRY_RUN} --path-mode intersection --config=Build/php-cs-fixer/config.php ." + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name cgl-${SUFFIX} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + cglGit) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name cgl-git-${SUFFIX} ${IMAGE_PHP} Build/Scripts/cglFixMyCommit.sh ${CGLCHECK_DRY_RUN} + SUITE_EXIT_CODE=$? + ;; + cglHeader) + # Active dry-run for cgl needs not "-n" but specific options + if [ -n "${CGLCHECK_DRY_RUN}" ]; then + CGLCHECK_DRY_RUN="--dry-run --diff" + fi + COMMAND="php -dxdebug.mode=off bin/php-cs-fixer fix -v ${CGLCHECK_DRY_RUN} --path-mode intersection --config=Build/php-cs-fixer/header-comment.php ." + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name cgl-header-${SUFFIX} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + cglHeaderGit) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name cgl-header-git-${SUFFIX} ${IMAGE_PHP} Build/Scripts/cglFixMyCommitFileHeader.sh ${CGLCHECK_DRY_RUN} + SUITE_EXIT_CODE=$? + ;; + checkAnnotations) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-annotations-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/annotationChecker.php + SUITE_EXIT_CODE=$? + ;; + checkTestClassFinal) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-test-classes-final-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/testClassFinalChecker.php + SUITE_EXIT_CODE=$? + ;; + checkTestMethodsPrefix) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-test-methods-prefix-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/testMethodPrefixChecker.php + SUITE_EXIT_CODE=$? + ;; + checkBom) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-utf8bom-${SUFFIX} ${IMAGE_PHP} Build/Scripts/checkUtf8Bom.sh + SUITE_EXIT_CODE=$? + ;; + checkComposer) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-composer-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/checkIntegrityComposer.php + SUITE_EXIT_CODE=$? + ;; + checkExceptionCodes) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-exception-codes-${SUFFIX} ${IMAGE_PHP} Build/Scripts/duplicateExceptionCodeCheck.sh + SUITE_EXIT_CODE=$? + ;; + checkExtensionScannerRst) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-extensionscanner-rst-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/extensionScannerRstFileReferences.php + SUITE_EXIT_CODE=$? + ;; + checkFilePathLength) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-file-path-length-${SUFFIX} ${IMAGE_PHP} Build/Scripts/maxFilePathLength.sh + SUITE_EXIT_CODE=$? + ;; + checkGitSubmodule) + COMMAND="if [ \$(git submodule status 2>&1 | wc -l) -ne 0 ]; then echo \"Found a submodule definition in repository\"; exit 1; fi" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-git-submodule-${SUFFIX} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + checkGruntClean) + COMMAND="find 'typo3/sysext' -name '*.js' -not -path '*/Fixtures/*' -exec rm '{}' + && cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt build; cd ..; git add *; git status; git status | grep -q \"nothing to commit, working tree clean\"" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-grunt-clean-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + checkIsoDatabase) + COMMAND="git checkout -- composer.json; git checkout -- composer.lock; php -dxdebug.mode=off Build/Scripts/updateIsoDatabase.php; git add *; git status; git status | grep -q \"nothing to commit, working tree clean\"" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-iso-database-${SUFFIX} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + checkNamespaceIntegrity) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-namespaces-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/checkNamespaceIntegrity.php + SUITE_EXIT_CODE=$? + ;; + checkPermissions) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-permissions-${SUFFIX} ${IMAGE_PHP} Build/Scripts/checkFilePermissions.sh + SUITE_EXIT_CODE=$? + ;; + checkRst) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-rst-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/validateRstFiles.php + SUITE_EXIT_CODE=$? + ;; + clean) + cleanBuildFiles + cleanCacheFiles + cleanRenderedDocumentationFiles + cleanTestFiles + ;; + cleanBuild) + cleanBuildFiles + ;; + cleanCache) + cleanCacheFiles + ;; + cleanRenderedDocumentation) + cleanRenderedDocumentationFiles + ;; + cleanTests) + cleanTestFiles + ;; + composer) + COMMAND=(composer "$@") + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-${SUFFIX} -e COMPOSER_CACHE_DIR=.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + composerInstall) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-install-${SUFFIX} -e COMPOSER_CACHE_DIR=.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} composer install --no-progress --no-interaction + SUITE_EXIT_CODE=$? + ;; + composerInstallMax) + COMMAND="composer config --unset platform.php; composer update --no-progress --no-interaction; composer dumpautoload" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-install-max-${SUFFIX} -e COMPOSER_CACHE_DIR=.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + composerInstallMin) + COMMAND="composer config platform.php ${PHP_VERSION}.0; composer update --prefer-lowest --no-progress --no-interaction; composer dumpautoload" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-install-min-${SUFFIX} -e COMPOSER_CACHE_DIR=.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + composerTestDistribution) + COMMAND="cd Build/composer; rm -rf composer.json composer.lock public/index.php public/typo3 public/typo3conf/ext var/ vendor/; cp composer.dist.json composer.json; composer update --no-progress --no-interaction" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-test-distribution-${SUFFIX} -e COMPOSER_CACHE_DIR=${CORE_ROOT}/.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + composerValidate) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-validate-${SUFFIX} ${IMAGE_PHP} composer validate + SUITE_EXIT_CODE=$? + ;; + functional) + if [ "${CHUNKS}" -gt 0 ]; then + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name func-splitter-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/splitFunctionalTests.php -v ${CHUNKS} + COMMAND=(bin/phpunit -c Build/phpunit/FunctionalTests-Job-${THISCHUNK}.xml --exclude-group not-${DBMS} ${EXTRA_TEST_OPTIONS} "$@") + else + COMMAND=(bin/phpunit -c Build/phpunit/FunctionalTests.xml --exclude-group not-${DBMS} ${EXTRA_TEST_OPTIONS} "$@") + fi + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name redis-func-${SUFFIX} --network ${NETWORK} -d ${IMAGE_REDIS} >/dev/null + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name memcached-func-${SUFFIX} --network ${NETWORK} -d ${IMAGE_MEMCACHED} >/dev/null + waitFor redis-func-${SUFFIX} 6379 + waitFor memcached-func-${SUFFIX} 11211 + CONTAINER_COMMON_PARAMS="${CONTAINER_COMMON_PARAMS} -e typo3TestingRedisHost=redis-func-${SUFFIX} -e typo3TestingMemcachedHost=memcached-func-${SUFFIX}" + case ${DBMS} in + mariadb) + echo "Using driver: ${DATABASE_DRIVER}" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mariadb-func-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MARIADB} >/dev/null + waitFor mariadb-func-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseDriver=${DATABASE_DRIVER} -e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabaseHost=mariadb-func-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + mysql) + echo "Using driver: ${DATABASE_DRIVER}" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mysql-func-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MYSQL} >/dev/null + waitFor mysql-func-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseDriver=${DATABASE_DRIVER} -e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabaseHost=mysql-func-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + postgres) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name postgres-func-${SUFFIX} --network ${NETWORK} -d -e POSTGRES_PASSWORD=funcp -e POSTGRES_USER=funcu --tmpfs /var/lib/postgresql/data:rw,noexec,nosuid ${IMAGE_POSTGRES} >/dev/null + waitFor postgres-func-${SUFFIX} 5432 + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_pgsql -e typo3DatabaseName=bamboo -e typo3DatabaseUsername=funcu -e typo3DatabaseHost=postgres-func-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + sqlite) + # create sqlite tmpfs mount typo3temp/var/tests/functional-sqlite-dbs/ to avoid permission issues + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/functional-sqlite-dbs/" + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite --tmpfs ${CORE_ROOT}/typo3temp/var/tests/functional-sqlite-dbs/:rw,noexec,nosuid" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + esac + ;; + functionalDeprecated) + COMMAND=(bin/phpunit -c Build/phpunit/FunctionalTestsDeprecated.xml --exclude-group not-${DBMS} ${EXTRA_TEST_OPTIONS} "$@") + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name redis-func-dep-${SUFFIX} --network ${NETWORK} -d ${IMAGE_REDIS} >/dev/null + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name memcached-func-dep-${SUFFIX} --network ${NETWORK} -d ${IMAGE_MEMCACHED} >/dev/null + waitFor redis-func-dep-${SUFFIX} 6379 + waitFor memcached-func-dep-${SUFFIX} 11211 + CONTAINER_COMMON_PARAMS="${CONTAINER_COMMON_PARAMS} -e typo3TestingRedisHost=redis-func-dep-${SUFFIX} -e typo3TestingMemcachedHost=memcached-func-dep-${SUFFIX}" + case ${DBMS} in + mariadb) + echo "Using driver: ${DATABASE_DRIVER}" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mariadb-func-dep-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MARIADB} >/dev/null + waitFor mariadb-func-dep-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseDriver=${DATABASE_DRIVER} -e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabaseHost=mariadb-func-dep-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-deprecated-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + mysql) + echo "Using driver: ${DATABASE_DRIVER}" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mysql-func-dep-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MYSQL} >/dev/null + waitFor mysql-func-dep-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseDriver=${DATABASE_DRIVER} -e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabaseHost=mysql-func-dep-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-deprecated-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + postgres) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name postgres-func-dep-${SUFFIX} --network ${NETWORK} -d -e POSTGRES_PASSWORD=funcp -e POSTGRES_USER=funcu --tmpfs /var/lib/postgresql/data:rw,noexec,nosuid ${IMAGE_POSTGRES} >/dev/null + waitFor postgres-func-dep-${SUFFIX} 5432 + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_pgsql -e typo3DatabaseName=bamboo -e typo3DatabaseUsername=funcu -e typo3DatabaseHost=postgres-func-dep-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-deprecated-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + sqlite) + # create sqlite tmpfs mount typo3temp/var/tests/functional-sqlite-dbs/ to avoid permission issues + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/functional-sqlite-dbs/" + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite --tmpfs ${CORE_ROOT}/typo3temp/var/tests/functional-sqlite-dbs/:rw,noexec,nosuid" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-deprecated-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + esac + ;; + lintPhp) + COMMAND="php -v | grep '^PHP'; find typo3/ -name \\*.php -print0 | xargs -0 -n1 -P4 php -dxdebug.mode=off -l >/dev/null" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name lint-php-${SUFFIX} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + lintScss) + COMMAND="cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt stylelint" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name lint-css-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + lintTypescript) + COMMAND="cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt eslint" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name lint-typescript-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + lintHtml) + COMMAND="cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt exec:lintspaces" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name lint-html-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + listExceptionCodes) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name list-exception-codes-${SUFFIX} ${IMAGE_PHP} Build/Scripts/duplicateExceptionCodeCheck.sh -p + SUITE_EXIT_CODE=$? + ;; + npm) + COMMAND=(npm "$@") + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} -w ${CORE_ROOT}/Build -e HOME=${CORE_ROOT}/.cache --name npm-${SUFFIX} ${IMAGE_NODEJS} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + phpstan) + COMMAND=(php -dxdebug.mode=off bin/phpstan analyse -c Build/phpstan/${PHPSTAN_CONFIG_FILE} --no-progress --no-interaction --memory-limit 4G "$@") + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name phpstan-${SUFFIX} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + phpstanGenerateBaseline) + COMMAND="php -dxdebug.mode=off bin/phpstan analyse -c Build/phpstan/${PHPSTAN_CONFIG_FILE} --no-progress --no-interaction --memory-limit 4G --generate-baseline=Build/phpstan/phpstan-baseline.neon" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name phpstan-baseline-${SUFFIX} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + unit) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name unit-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${IMAGE_PHP} bin/phpunit -c Build/phpunit/UnitTests.xml ${EXTRA_TEST_OPTIONS} "$@" + SUITE_EXIT_CODE=$? + ;; + unitDeprecated) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name unit-deprecated-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${IMAGE_PHP} bin/phpunit -c Build/phpunit/UnitTestsDeprecated.xml ${EXTRA_TEST_OPTIONS} "$@" + SUITE_EXIT_CODE=$? + ;; + unitJavascript) + COMMAND="cd Build; npm ci || exit 1; CHROME_SANDBOX=false BROWSERS=chrome npm run test" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name unit-javascript-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS_CHROME} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + unitRandom) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name unit-random-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${IMAGE_PHP} bin/phpunit -c Build/phpunit/UnitTests.xml --order-by=random ${EXTRA_TEST_OPTIONS} ${PHPUNIT_RANDOM} "$@" + SUITE_EXIT_CODE=$? + ;; + update) + # pull typo3/core-testing-* versions of those ones that exist locally + echo "> pull ghcr.io/typo3/core-testing-* versions of those ones that exist locally" + ${CONTAINER_BIN} images "ghcr.io/typo3/core-testing-*" --format "{{.Repository}}:{{.Tag}}" | xargs -I {} ${CONTAINER_BIN} pull {} + echo "" + # remove "dangling" typo3/core-testing-* images (those tagged as ) + echo "> remove \"dangling\" ghcr.io/typo3/core-testing-* images (those tagged as )" + ${CONTAINER_BIN} images --filter "reference=ghcr.io/typo3/core-testing-*" --filter "dangling=true" --format "{{.ID}}" | xargs -I {} ${CONTAINER_BIN} rmi -f {} + echo "" + ;; + *) + loadHelp + echo "Invalid -s option argument ${TEST_SUITE}" >&2 + echo >&2 + echo "${HELP}" >&2 + exit 1 + ;; +esac + +cleanUp + +# Print summary +echo "" >&2 +echo "###########################################################################" >&2 +echo "Result of ${TEST_SUITE}" >&2 +echo "Container runtime: ${CONTAINER_BIN}" >&2 +echo "PHP: ${PHP_VERSION}" >&2 +if [[ ${TEST_SUITE} =~ ^(functional|functionalDeprecated|acceptance|acceptanceComposer|acceptanceInstall)$ ]]; then + case "${DBMS}" in + mariadb|mysql|postgres) + echo "DBMS: ${DBMS} version ${DBMS_VERSION} driver ${DATABASE_DRIVER}" >&2 + ;; + sqlite) + echo "DBMS: ${DBMS}" >&2 + ;; + esac +fi +if [[ -n ${EXTRA_TEST_OPTIONS} ]]; then + echo " Note: Using -e is deprecated. Simply add the options at the end of the command." + echo " Instead of: Build/Scripts/runTests.sh -s ${TEST_SUITE} -e '${EXTRA_TEST_OPTIONS}' $@" + echo " use: Build/Scripts/runTests.sh -s ${TEST_SUITE} -- ${EXTRA_TEST_OPTIONS} $@" +fi +if [[ ${SUITE_EXIT_CODE} -eq 0 ]]; then + echo "SUCCESS" >&2 +else + echo "FAILURE" >&2 +fi +echo "###########################################################################" >&2 +echo "" >&2 + +# Exit with code of test suite - This script return non-zero if the executed test failed. +exit $SUITE_EXIT_CODE diff --git a/Build/Scripts/test.sh b/Build/Scripts/test.sh new file mode 100755 index 0000000..c1fa0cb --- /dev/null +++ b/Build/Scripts/test.sh @@ -0,0 +1,143 @@ +#!/bin/bash + +export NC='\e[0m' +export RED='\e[0;31m' +export GREEN='\e[0;32m' + +THIS_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" +cd "$THIS_SCRIPT_DIR" || exit 1 + +################################################# +# Run resource tests. +# Arguments: +# none +################################################# +checkResources () { + echo "#################################################################" >&2 + echo "Checking documentation, TypeScript and Scss files" >&2 + echo "#################################################################" >&2 + + ./additionalTests.sh -s lintXliff + EXIT_CODE_XLIFF=$? + + ./additionalTests.sh -s buildDocumentation + EXIT_CODE_DOCUMENTATION=$? + + echo "#################################################################" >&2 + echo "Checked documentation, TypeScript and Scss files" >&2 + if [[ ${EXIT_CODE_SCSS} -eq 0 ]] && \ + [[ ${EXIT_CODE_TYPESCRIPT} -eq 0 ]] && \ + [[ ${EXIT_CODE_XLIFF} -eq 0 ]] && \ + [[ ${EXIT_CODE_DOCUMENTATION} -eq 0 ]] + then + echo -e "${GREEN}Resources valid${NC}" >&2 + else + echo -e "${RED}Resources invalid${NC}" >&2 + fi + echo "#################################################################" >&2 + echo "" >&2 + + ./additionalTests.sh -s clean +} + +################################################# +# Run test matrix. +# Arguments: +# php version +# typo3 version +# testing framework version +# test path +# prefer lowest +################################################# +runFunctionalTests () { + local PHP_VERSION="${1}" + local TYPO3_VERSION=${2} + local TESTING_FRAMEWORK=${3} + local TEST_PATH=${4} + local PREFER_LOWEST=${5} + + echo "###########################################################################" >&2 + echo " Run unit and/or functional tests with" >&2 + echo " - TYPO3 ${TYPO3_VERSION}" >&2 + echo " - PHP ${PHP_VERSION}">&2 + echo " - Testing framework ${TESTING_FRAMEWORK}">&2 + echo " - Test path ${TEST_PATH}">&2 + echo " - Additional ${PREFER_LOWEST}">&2 + echo "###########################################################################" >&2 + + ./runTests.sh -s cleanTests + + ./additionalTests.sh \ + -p ${PHP_VERSION} \ + -s lintPhp || exit 1 ; \ + EXIT_CODE_LINT=$? + + ./additionalTests.sh \ + -p ${PHP_VERSION} \ + -s composerInstallPackage \ + -q "typo3/cms-core:${TYPO3_VERSION}" \ + -r " ${PREFER_LOWEST}" || exit 1 ; \ + EXIT_CODE_CORE=$? + + ./additionalTests.sh \ + -p ${PHP_VERSION} \ + -s composerInstallPackage \ + -q "typo3/testing-framework:${TESTING_FRAMEWORK}" \ + -r " --dev ${PREFER_LOWEST}" || exit 1 ; \ + EXIT_CODE_FRAMEWORK=$? + + ./runTests.sh \ + -p ${PHP_VERSION} \ + -s composerValidate || exit 1 ; \ + EXIT_CODE_VALIDATE=$? + + echo "###########################################################################" >&2 + echo " Finished unit and/or functional tests with" >&2 + echo " - TYPO3 ${TYPO3_VERSION}" >&2 + echo " - PHP ${PHP_VERSION}">&2 + echo " - Testing framework ${TESTING_FRAMEWORK}">&2 + echo " - Test path ${TEST_PATH}">&2 + echo " - Additional ${PREFER_LOWEST}">&2 + if [[ ${EXIT_CODE_LINT} -eq 0 ]] && \ + [[ ${EXIT_CODE_INSTALL} -eq 0 ]] && \ + [[ ${EXIT_CODE_CORE} -eq 0 ]] && \ + [[ ${EXIT_CODE_FRAMEWORK} -eq 0 ]] && \ + [[ ${EXIT_CODE_VALIDATE} -eq 0 ]] && \ + [[ ${EXIT_CODE_FUNCTIONAL} -eq 0 ]] + then + echo -e "${GREEN}SUCCESS${NC}" >&2 + else + echo -e "${RED}FAILURE${NC}" >&2 + exit 1 + fi + echo "#################################################################" >&2 + echo "" >&2 +} + +################################################# +# Removes all files created by tests. +# Arguments: +# none +################################################# +cleanup () { + ./runTests.sh -s clean + ./additionalTests.sh -s clean + git checkout ../../composer.json +} + +DEBUG_TESTS=false +if [[ $DEBUG_TESTS != true ]]; then + checkResources + + runFunctionalTests "8.2" "^13.0" "dev-main" "Tests/Functional" || exit 1 + runFunctionalTests "8.2" "^13.0" "dev-main" "Tests/Functional" "--prefer-lowest" || exit 1 + runFunctionalTests "8.3" "^13.0" "dev-main" "Tests/Functional" || exit 1 + runFunctionalTests "8.3" "^13.0" "dev-main" "Tests/Functional" "--prefer-lowest" || exit 1 + cleanup +else + cleanup + runFunctionalTests "8.2" "^13.0" "dev-main" "Tests/Functional" || exit 1 + cleanup + # ./runTests.sh -x -p 8.2 -d sqlite -s functional -e "--group selected" Tests/Functional + # ./runTests.sh -x -p 8.2 -d sqlite -s functional Tests/Functional +fi diff --git a/Build/php-cs-fixer/config.php b/Build/php-cs-fixer/config.php new file mode 100644 index 0000000..5e32557 --- /dev/null +++ b/Build/php-cs-fixer/config.php @@ -0,0 +1,116 @@ + Build/Scripts/additionalTests.sh -p 8.3 -s composerInstallPackage -q "typo3/cms-core:[dev-main,13...]" + * > Build/Scripts/runTests.sh -s cgl + * + * Fix your current patch: + * > Build/Scripts/runTests.sh -s cglGit + */ +if (PHP_SAPI !== 'cli') { + die('This script supports command line usage only. Please check your command.'); +} + +// Return a Code Sniffing configuration using +// all sniffers needed for PER +// 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. +return (new \PhpCsFixer\Config()) + ->setParallelConfig(\PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect()) + ->setFinder( + PhpCsFixer\Finder::create() + ->ignoreVCSIgnored(true) + ->in(realpath(__DIR__ . '/../../')) + ->exclude('bin') + ->exclude('public') + ->exclude('typo3temp') + ->exclude('vendor') + ) + ->setRiskyAllowed(true) + ->setRules([ + '@DoctrineAnnotation' => true, + // @todo: Switch to @PER-CS2.0 once php-cs-fixer's todo list is done: https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues/7247 + '@PER-CS1.0' => true, + 'array_indentation' => true, + 'array_syntax' => ['syntax' => 'short'], + 'cast_spaces' => ['space' => 'none'], + // @todo: Can be dropped once we enable @PER-CS2.0 + 'concat_space' => ['spacing' => 'one'], + 'declare_equal_normalize' => ['space' => 'none'], + 'declare_parentheses' => true, + 'dir_constant' => true, + // @todo: Can be dropped once we enable @PER-CS2.0 + 'function_declaration' => [ + 'closure_fn_spacing' => 'none', + ], + 'function_to_constant' => ['functions' => ['get_called_class', 'get_class', 'get_class_this', 'php_sapi_name', 'phpversion', 'pi']], + 'type_declaration_spaces' => true, + 'global_namespace_import' => ['import_classes' => false, 'import_constants' => false, 'import_functions' => false], + 'list_syntax' => ['syntax' => 'short'], + // @todo: Can be dropped once we enable @PER-CS2.0 + 'method_argument_space' => true, + 'modernize_strpos' => true, + 'modernize_types_casting' => true, + 'native_function_casing' => 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_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' => true, + 'no_unneeded_control_parentheses' => true, + 'no_unused_imports' => true, + 'no_useless_else' => true, + 'no_useless_nullsafe_operator' => true, + 'ordered_imports' => ['imports_order' => ['class', 'function', 'const'], 'sort_algorithm' => 'alpha'], + '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_space_around_construct' => true, + 'single_line_comment_style' => ['comment_types' => ['hash']], + // @todo: Can be dropped once we enable @PER-CS2.0 + 'single_line_empty_body' => true, + 'trailing_comma_in_multiline' => ['elements' => ['arrays']], + 'whitespace_after_comma_in_array' => ['ensure_single_space' => true], + 'yoda_style' => ['equal' => false, 'identical' => false, 'less_and_greater' => false], + ]); diff --git a/Build/php-cs-fixer/header-comment.php b/Build/php-cs-fixer/header-comment.php new file mode 100644 index 0000000..284ba9b --- /dev/null +++ b/Build/php-cs-fixer/header-comment.php @@ -0,0 +1,75 @@ + Build/Scripts/additionalTests.sh -p 8.3 -s composerInstallPackage -q "typo3/cms-core:[dev-main,13...]" + * > Build/Scripts/runTests.sh -s cglHeader + * + * Fix your current patch: + * > Build/Scripts/runTests.sh -s cglHeaderGit + */ +if (PHP_SAPI !== 'cli') { + die('This script supports command line usage only. Please check your command.'); +} + +$finder = PhpCsFixer\Finder::create() + ->name('*.php') + ->in(__DIR__ . '/../../') + ->exclude('Acceptance/Support/_generated') // EXT:core + ->exclude('Build') + // Configuration files do not need header comments + ->exclude('Configuration') + ->notName('*locallang*.php') + ->notName('ext_localconf.php') + ->notName('ext_tables.php') + ->notName('ext_emconf.php') + // ClassAliasMap files do not need header comments + ->notName('ClassAliasMap.php') + // CodeSnippets and Examples in Documentation do not need header comments + ->exclude('Documentation') + // Third-party inclusion files should not have a changed comment + ->notName('Rfc822AddressesParser.php') + ->notName('ClassMapGenerator.php') +; + +$headerComment = <<setParallelConfig(\PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect()) + ->setRiskyAllowed(false) + ->setRules([ + 'no_extra_blank_lines' => true, + 'header_comment' => [ + 'header' => $headerComment, + 'comment_type' => 'comment', + 'separate' => 'both', + 'location' => 'after_declare_strict', + ], + ]) + ->setFinder($finder); diff --git a/Classes/Command/ContentElementCommand.php b/Classes/Command/ContentElementCommand.php index d59a5c8..d27f63b 100755 --- a/Classes/Command/ContentElementCommand.php +++ b/Classes/Command/ContentElementCommand.php @@ -1,7 +1,5 @@ site) { try { $this->site = $this->siteFinder->getSiteByPageId($pageUid); - } catch (Exception) { + } catch (\Exception) { } } return $this->site; diff --git a/Classes/Services/QueryBuilderHelper.php b/Classes/Services/QueryBuilderHelper.php index efa5f70..aa385fa 100644 --- a/Classes/Services/QueryBuilderHelper.php +++ b/Classes/Services/QueryBuilderHelper.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace Evoweb\EwBase\Services; - /* * This file is developed by evoWeb. * @@ -15,6 +13,8 @@ namespace Evoweb\EwBase\Services; * LICENSE.txt file that was distributed with this source code. */ +namespace Evoweb\EwBase\Services; + use Doctrine\DBAL\ArrayParameterType; use Doctrine\DBAL\ParameterType; use TYPO3\CMS\Core\Database\Query\QueryBuilder; @@ -293,7 +293,8 @@ class QueryBuilderHelper ): mixed { if (array_key_exists($paramName, $paramsOrTypes)) { return $paramsOrTypes[$paramName]; - } elseif (array_key_exists(':' . $paramName, $paramsOrTypes)) { + } + if (array_key_exists(':' . $paramName, $paramsOrTypes)) { // Hash keys can be prefixed with a colon for compatibility return $paramsOrTypes[':' . $paramName]; } diff --git a/Classes/ToolbarItems/ReleaseToolbarItem.php b/Classes/ToolbarItems/ReleaseToolbarItem.php index 4f01aa4..097ba9a 100755 --- a/Classes/ToolbarItems/ReleaseToolbarItem.php +++ b/Classes/ToolbarItems/ReleaseToolbarItem.php @@ -1,7 +1,5 @@ resolveContainer = $config['migrationResolveContainer'] ?? []; $this->colPosOffset = $config['migrationColPosOffset'] ?? 0; $this->configuration = $config['migrationMapping'] ?? []; @@ -82,7 +92,6 @@ class GridelementsToContainerService $this->dataHandler->start([], [], $backendUser); } - protected function resolveContainers(string $layout): void { $containers = $this->getGridElementsByLayout($layout); @@ -110,7 +119,7 @@ class GridelementsToContainerService [ 'tx_gridelements_container' => 0, 'colPos' => $container['colPos'], - 'header' => $child['header'] ?: $container['header'] + 'header' => $child['header'] ?: $container['header'], ] ); $this->moveElementAfterElement($child['uid'], $moveAfterThis['uid']); @@ -134,10 +143,9 @@ class GridelementsToContainerService $this->dataHandler->moveRecord(self::TABLE_NAME, $elementToMove, $elementToMoveAfter * -1); } - protected function migrateConfiguredContainer(): void { - array_walk($this->configuration, function($config, $key) { + array_walk($this->configuration, function ($config, $key) { $containers = $this->getGridElementsByLayout((string)$key); foreach ($containers as $container) { $container['pi_flexform'] = $this->flexFormService->convertFlexFormContentToArray( @@ -157,7 +165,7 @@ class GridelementsToContainerService $data = [ 'CType' => $this->getCType($container, $config), - 'tx_gridelements_backend_layout' => '' + 'tx_gridelements_backend_layout' => '', ]; if (isset($config['map']) && is_array($config['map']) && !empty($container['pi_flexform'])) { @@ -205,13 +213,13 @@ class GridelementsToContainerService if (empty($container[$to]) && !empty($value)) { $data[$to] = $value; } - } catch (\throwable) {} + } catch (\throwable) { + } } return $data; } - protected function updateElement(int $uid, array $changes): void { $this->connectionPool diff --git a/Classes/User/AssetPath.php b/Classes/User/AssetPath.php index 4b047ba..58c18b2 100755 --- a/Classes/User/AssetPath.php +++ b/Classes/User/AssetPath.php @@ -2,6 +2,17 @@ declare(strict_types=1); +/* + * This file is developed by evoWeb. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + */ + namespace Evoweb\EwBase\User; use TYPO3\CMS\Core\Utility\PathUtility; diff --git a/Classes/ViewHelpers/Array/AddViewHelper.php b/Classes/ViewHelpers/Array/AddViewHelper.php index 7bdc507..fed0fcb 100755 --- a/Classes/ViewHelpers/Array/AddViewHelper.php +++ b/Classes/ViewHelpers/Array/AddViewHelper.php @@ -1,7 +1,5 @@ 1) { // glue contains a special type identifier, resolve the actual glue - list ($type, $value) = explode(':', $glue); + [$type, $value] = explode(':', $glue); $glue = match ($type) { 'constant' => constant($value), default => $value, diff --git a/Classes/ViewHelpers/Condition/InArrayViewHelper.php b/Classes/ViewHelpers/Condition/InArrayViewHelper.php index d59e8f6..52390db 100755 --- a/Classes/ViewHelpers/Condition/InArrayViewHelper.php +++ b/Classes/ViewHelpers/Condition/InArrayViewHelper.php @@ -1,14 +1,18 @@ getRawConfigurationForSiteWithRootPageId($siteFinder, $rootPageId); $result['databaseRow']['uid'] = $rowData['rootPageId']; $result['databaseRow']['identifier'] = $result['customData']['siteIdentifier']; - } elseif (in_array($tableName, ['site_errorhandling', 'site_language', 'site_route', 'site_base_variant'], true)) { + } elseif ( + in_array( + $tableName, + ['site_errorhandling', 'site_language', 'site_route', 'site_base_variant'], + true + ) + ) { $rootPageId = (int)($result['inlineTopMostParentUid'] ?? $result['inlineParentUid']); try { $rowData = $this->getRawConfigurationForSiteWithRootPageId($siteFinder, $rootPageId); diff --git a/Classes/Xclass/SiteTcaInline.php b/Classes/Xclass/SiteTcaInline.php index 1119f87..e420715 100755 --- a/Classes/Xclass/SiteTcaInline.php +++ b/Classes/Xclass/SiteTcaInline.php @@ -1,5 +1,16 @@ resolveSiteRelatedChildren($result, $fieldName); if (!empty($result['processedTca']['columns'][$fieldName]['config']['selectorOrUniqueConfiguration'])) { - throw new \RuntimeException('selectorOrUniqueConfiguration not implemented in sites module', 1624313533); + throw new \RuntimeException( + 'selectorOrUniqueConfiguration not implemented in sites module', + 1624313533 + ); } } diff --git a/Configuration/SiteConfiguration/site_usercentrics.php b/Configuration/SiteConfiguration/site_usercentrics.php index 67c84e0..d5fd966 100755 --- a/Configuration/SiteConfiguration/site_usercentrics.php +++ b/Configuration/SiteConfiguration/site_usercentrics.php @@ -34,7 +34,7 @@ return [ 0 => 'CMP 1', 1 => 'main', ], - ] + ], ], ], 'applicationContext' => [ @@ -56,7 +56,7 @@ return [ 0 => '', 1 => true, ], - ] + ], ], ], ], @@ -72,7 +72,7 @@ return [ 'showitem' => ' id, version, --linebreak--, applicationContext, useBlocker, - ' - ] - ] + ', + ], + ], ]; diff --git a/Configuration/TCA/Overrides/pages.php b/Configuration/TCA/Overrides/pages.php index 6a697aa..5a8dda2 100755 --- a/Configuration/TCA/Overrides/pages.php +++ b/Configuration/TCA/Overrides/pages.php @@ -15,14 +15,14 @@ $newColumns = [ 'suggestOptions' => [ 'default' => [ 'additionalSearchFields' => 'header, bodytext', - 'searchWholePhrase' => false - ] + 'searchWholePhrase' => false, + ], ], 'default' => 0, 'behaviour' => [ - 'allowLanguageSynchronization' => true - ] - ] + 'allowLanguageSynchronization' => true, + ], + ], ], ]; diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..95d36a7 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,345 @@ +Some icons used in the TYPO3 project are retrieved from the "Silk" icon set of +Mark James, which can be found at http://famfamfam.com/lab/icons/silk/. This +set is distributed under a Creative Commons Attribution 2.5 License. The +license can be found at http://creativecommons.org/licenses/by/2.5/. +--------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/composer.json b/composer.json index ecedfc6..045ecaa 100755 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ } }, "require": { - "typo3/cms-core": "^13.0 || 13.0.x-dev || dev-main", + "typo3/cms-core": "dev-main", "typo3/cms-backend": "*", "typo3/cms-extbase": "*", @@ -35,12 +35,26 @@ "typo3/cms-tstemplate": "*", "typo3/cms-scheduler": "*", - "helhum/typo3-console": "*", + "helhum/typo3-console": ">8.0", "clickstorm/cs-seo": "*" }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.57.1", + "phpunit/phpunit": "^11.0.3", + "typo3/testing-framework": "dev-main" + }, + "minimum-stability": "dev", + "prefer-stable": true, "extra": { "typo3/cms": { "extension-key": "ew_base" } + }, + "config": { + "bin-dir": "bin", + "allow-plugins": { + "typo3/class-alias-loader": true, + "typo3/cms-composer-installers": true + } } } diff --git a/ext_localconf.php b/ext_localconf.php index cca6d61..d6875da 100755 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -26,10 +26,10 @@ call_user_func(function () { ]; $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][BaseSiteDatabaseEditRow::class] = [ - 'className' => SiteDatabaseEditRow::class + 'className' => SiteDatabaseEditRow::class, ]; $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][BaseSiteTcaInline::class] = [ - 'className' => SiteTcaInline::class + 'className' => SiteTcaInline::class, ]; $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['formDataGroup']['siteConfiguration'][