diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4234a93..e59e02a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,6 +83,7 @@ jobs: - "json:lint" - "php:cs-fixer" - "php:mess" + - "php:rector" - "php:sniff" - "php:stan" - "typoscript:lint" @@ -326,6 +327,7 @@ jobs: documentation: name: Documentation runs-on: ubuntu-24.04 + timeout-minutes: 2 steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.gitlab/pipeline/.gitlab-ci.yml b/.gitlab/pipeline/.gitlab-ci.yml index 711eebe..ee51fac 100644 --- a/.gitlab/pipeline/.gitlab-ci.yml +++ b/.gitlab/pipeline/.gitlab-ci.yml @@ -8,8 +8,8 @@ stages: include: - '/.gitlab/pipeline/jobs/.composer-update.yml' - - '/.gitlab/pipeline/jobs/.default.yml' - '/.gitlab/pipeline/jobs/.default-frontend.yml' + - '/.gitlab/pipeline/jobs/.default.yml' - '/.gitlab/pipeline/jobs/.variables.yml' - '/.gitlab/pipeline/jobs/build-composer-dependencies.yml' - '/.gitlab/pipeline/jobs/composer-normalize.yml' @@ -20,21 +20,22 @@ include: - '/.gitlab/pipeline/jobs/func-php8.0-v11-lowest.yml' - '/.gitlab/pipeline/jobs/func-php8.1-v11-highest.yml' - '/.gitlab/pipeline/jobs/func-php8.1-v11-lowest.yml' - - '/.gitlab/pipeline/jobs/func-php8.2-v11-highest.yml' - - '/.gitlab/pipeline/jobs/func-php8.2-v11-lowest.yml' - '/.gitlab/pipeline/jobs/func-php8.1-v12-highest.yml' - '/.gitlab/pipeline/jobs/func-php8.1-v12-lowest.yml' + - '/.gitlab/pipeline/jobs/func-php8.2-v11-highest.yml' + - '/.gitlab/pipeline/jobs/func-php8.2-v11-lowest.yml' - '/.gitlab/pipeline/jobs/func-php8.2-v12-highest.yml' - '/.gitlab/pipeline/jobs/func-php8.2-v12-lowest.yml' - '/.gitlab/pipeline/jobs/javascript-lint.yml' - '/.gitlab/pipeline/jobs/json-lint.yml' + - '/.gitlab/pipeline/jobs/php-cs-fixer.yml' - '/.gitlab/pipeline/jobs/php-lint-php7.4.yml' - '/.gitlab/pipeline/jobs/php-lint-php8.0.yml' - '/.gitlab/pipeline/jobs/php-lint-php8.1.yml' - '/.gitlab/pipeline/jobs/php-lint-php8.2.yml' - '/.gitlab/pipeline/jobs/php-lint-php8.3.yml' - '/.gitlab/pipeline/jobs/phpcs.yml' - - '/.gitlab/pipeline/jobs/php-cs-fixer.yml' + - '/.gitlab/pipeline/jobs/rector.yml' - '/.gitlab/pipeline/jobs/typoscript-lint.yml' - '/.gitlab/pipeline/jobs/unit-php7.4-v11-highest.yml' - '/.gitlab/pipeline/jobs/unit-php7.4-v11-lowest.yml' @@ -42,14 +43,14 @@ include: - '/.gitlab/pipeline/jobs/unit-php8.0-v11-lowest.yml' - '/.gitlab/pipeline/jobs/unit-php8.1-v11-highest.yml' - '/.gitlab/pipeline/jobs/unit-php8.1-v11-lowest.yml' - - '/.gitlab/pipeline/jobs/unit-php8.2-v11-highest.yml' - - '/.gitlab/pipeline/jobs/unit-php8.2-v11-lowest.yml' - - '/.gitlab/pipeline/jobs/unit-php8.3-v11-highest.yml' - - '/.gitlab/pipeline/jobs/unit-php8.3-v11-lowest.yml' - '/.gitlab/pipeline/jobs/unit-php8.1-v12-highest.yml' - '/.gitlab/pipeline/jobs/unit-php8.1-v12-lowest.yml' + - '/.gitlab/pipeline/jobs/unit-php8.2-v11-highest.yml' + - '/.gitlab/pipeline/jobs/unit-php8.2-v11-lowest.yml' - '/.gitlab/pipeline/jobs/unit-php8.2-v12-highest.yml' - '/.gitlab/pipeline/jobs/unit-php8.2-v12-lowest.yml' + - '/.gitlab/pipeline/jobs/unit-php8.3-v11-highest.yml' + - '/.gitlab/pipeline/jobs/unit-php8.3-v11-lowest.yml' - '/.gitlab/pipeline/jobs/unit-php8.3-v12-highest.yml' - '/.gitlab/pipeline/jobs/unit-php8.3-v12-lowest.yml' - '/.gitlab/pipeline/jobs/xliff-lint.yml' diff --git a/.gitlab/pipeline/jobs/.default.yml b/.gitlab/pipeline/jobs/.default.yml index a84443f..2396446 100644 --- a/.gitlab/pipeline/jobs/.default.yml +++ b/.gitlab/pipeline/jobs/.default.yml @@ -4,5 +4,5 @@ - bash .gitlab/build/docker_install.sh > /dev/null variables: PHP_INI_SCAN_DIR: "/etc/php" - script: - - cp $CI_PROJECT_DIR/.gitlab/pipeline/ci/php.ini /usr/local/etc/php/php.ini; # copy php.ini into image + script: + - cp $CI_PROJECT_DIR/.gitlab/pipeline/ci/php.ini /usr/local/etc/php/php.ini; # copy php.ini into image diff --git a/.gitlab/pipeline/jobs/rector.yml b/.gitlab/pipeline/jobs/rector.yml new file mode 100644 index 0000000..013e940 --- /dev/null +++ b/.gitlab/pipeline/jobs/rector.yml @@ -0,0 +1,11 @@ +rector: + extends: .default + stage: codestyle + needs: + - build-composer-dependencies + - php-lint-php7.4 + - php-lint-php8.0 + - php-lint-php8.1 + - php-lint-php8.2 + script: + - composer ci:php:rector diff --git a/Documentation/Index.rst b/Documentation/Index.rst index a53417b..0bcfdb5 100644 --- a/Documentation/Index.rst +++ b/Documentation/Index.rst @@ -44,7 +44,7 @@ continuous integration. Introduction PHPVersionSupport - TestingFramework + ReleaseBranchingStrategy Environment DependencyManager Running diff --git a/Documentation/ReleaseBranchingStrategy.rst b/Documentation/ReleaseBranchingStrategy.rst new file mode 100644 index 0000000..6fa141d --- /dev/null +++ b/Documentation/ReleaseBranchingStrategy.rst @@ -0,0 +1,65 @@ +.. include:: /Includes.rst.txt + +.. _release-branching-strategy: + +============================== +Release and Branching Strategy +============================== + +When maintaining TYPO3 extensions, developers often need to support multiple +TYPO3 Long-Term Support (LTS) versions simultaneously. This typically requires +a clear release and branching strategy to manage development and maintenance +across different TYPO3 versions. + +There are two common strategies for managing branches when supporting multiple +TYPO3 LTS versions. + +.. contents:: Table of Contents: + :backlinks: top + :class: compact-list + :depth: 2 + :local: + +.. _release-branching-strategy-one-branch: + +Approach 1: One branch for multiple TYPO3 LTS versions +====================================================== + +In this approach, there is a single main branch that receives new features and +updates, while supporting multiple TYPO3 LTS versions at the same time. + +The downside of this approach is that it may require some version-dependent +code switches, which can increase complexity. However, the major advantage is +that there is only one branch to maintain, making it easier to implement new +features and code changes across all supported TYPO3 versions. + +This approach simplifies the maintenance of the extension and is preferred when +minimizing maintenance overhead is the primary concern. + +.. _release-branching-strategy-multiple-branches: + +Approach 2: Separate branch per TYPO3 LTS version +================================================= + +In this approach, there is one main branch for each TYPO3 LTS version. This +means that each branch exclusively supports a single TYPO3 LTS version. + +The advantage here is that version-specific code can be used without requiring +version-dependent switches, reducing complexity in the codebase. However, this +approach increases the maintenance burden, as any new features or updates must +be applied to each branch individually. + +This approach may be necessary when there are significant differences between +TYPO3 LTS versions or when you want to avoid version-dependent code. + +.. _release-strategy-conclusion: + +Conclusion +========== + +The appropriate release and branching strategy depends on the specific +requirements of the extension and the TYPO3 versions you are supporting. If +reducing maintenance complexity is a priority, using a single branch for +multiple versions is often the better choice. However, if you need to tailor +your extension for each version, a separate branch for each version may be more +suitable. diff --git a/Documentation/TestingFramework.rst b/Documentation/TestingFramework.rst deleted file mode 100644 index 1cdd068..0000000 --- a/Documentation/TestingFramework.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. include:: /Includes.rst.txt - -.. _testing-framework: - -================= -Testing framework -================= - -Extensions usually need to support two LTS versions of TYPO3 in parallel, -assuming that they should support all currently supported TYPO3 LTS versions. -To achieve this, there are two different approaches, which also affect the -choice of a testing framework for unit and functional tests. - -.. contents:: Table of Contents: - :backlinks: top - :class: compact-list - :depth: 2 - :local: - -.. _testing-framework-approach-many-versions: - -Approach 1: One branch for many TYPO3 LTS versions -================================================== - -With this approach, there is one main branch that gets new features. It needs to -support two TYPO3 LTS versions in parallel. - -The downside is that this slightly increases code complexity as -version-dependent code switches might be necessary. The upside is that there -is only one branch to maintain, which makes adding new features (and all other -code changes) a lot less of a hassle. - -The `Nimut testing framework `__ -can support multiple TYPO3 versions at a time, and -it provides version-independent abstractions for testing, making it the perfect -companion for this approach. - -This is the approach that we have chosen for this extension as we do not want -to maintain two branches in parallel. - -.. _testing-framework-approach-one-version: - -Approach 2: One branch per TYPO3 LTS version -============================================ - -With this approach, there are two main branches that get new features in -parallel. Each branch supports exactly one TYPO3 LTS version. - -The upside is that this slightly decreases code complexity as -version-dependent code switches are not necessary. The downside is that there -are two branches to maintain, which makes adding new features (and all other -code changes) more of a hassle. - -For this approach, the -`TYPO3 testing framework `__ -- which supports only one TYPO3 LTS version at a time - will work just fine. - diff --git a/Tests/Functional/Domain/Repository/TeaRepositoryTest.php b/Tests/Functional/Domain/Repository/TeaRepositoryTest.php index d781747..08f6558 100644 --- a/Tests/Functional/Domain/Repository/TeaRepositoryTest.php +++ b/Tests/Functional/Domain/Repository/TeaRepositoryTest.php @@ -8,6 +8,7 @@ use TTN\Tea\Domain\Model\Tea; use TTN\Tea\Domain\Repository\TeaRepository; use TYPO3\CMS\Extbase\Domain\Model\FileReference; use TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface; +use TYPO3\CMS\Extbase\Persistence\Repository; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; /** @@ -31,6 +32,14 @@ final class TeaRepositoryTest extends FunctionalTestCase $this->subject = $this->get(TeaRepository::class); } + /** + * @test + */ + public function isRepository(): void + { + self::assertInstanceOf(Repository::class, $this->subject); + } + /** * @test */ diff --git a/Tests/Unit/Domain/Repository/TeaRepositoryTest.php b/Tests/Unit/Domain/Repository/TeaRepositoryTest.php deleted file mode 100644 index c7e9e8b..0000000 --- a/Tests/Unit/Domain/Repository/TeaRepositoryTest.php +++ /dev/null @@ -1,39 +0,0 @@ -createStub(ObjectManagerInterface::class); - // @phpstan-ignore-next-line This line is 11LTS-specific, but we're running PHPStan on TYPO3 12. - $this->subject = new TeaRepository($objectManagerStub); - } else { - $this->subject = new TeaRepository(); - } - } - - /** - * @test - */ - public function isRepository(): void - { - self::assertInstanceOf(Repository::class, $this->subject); - } -} diff --git a/composer.json b/composer.json index 4502904..5631045 100644 --- a/composer.json +++ b/composer.json @@ -47,31 +47,31 @@ "typo3/cms-frontend": "^11.5.4 || ^12.4.2" }, "require-dev": { - "ergebnis/composer-normalize": "^2.43.0", - "friendsofphp/php-cs-fixer": "^3.64.0", - "helmich/typo3-typoscript-lint": "^3.1.1", - "icanhazstring/composer-unused": "^0.8.11", - "php-parallel-lint/php-parallel-lint": "^1.4", - "phpmd/phpmd": "^2.15.0", - "phpstan/extension-installer": "^1.4.3", - "phpstan/phpstan": "^1.12.3", - "phpstan/phpstan-phpunit": "^1.4.0", - "phpstan/phpstan-strict-rules": "^1.6.0", - "phpunit/phpunit": "^9.6.20", - "saschaegerer/phpstan-typo3": "^1.10.2", - "seld/jsonlint": "^1.11.0", - "spaze/phpstan-disallowed-calls": "^3.4", - "squizlabs/php_codesniffer": "^3.10.3", - "ssch/typo3-rector": "^2.6.5", - "ssch/typo3-rector-testing-framework": "^2.0.1", - "symfony/console": "^5.4 || ^6.4 || ^7.0", - "symfony/translation": "^5.4 || ^6.4 || ^7.0", - "symfony/yaml": "^5.4 || ^6.4 || ^7.0", - "tomasvotruba/cognitive-complexity": "^0.2.3", - "tomasvotruba/type-coverage": "^0.3.1", + "ergebnis/composer-normalize": "2.44.0", + "friendsofphp/php-cs-fixer": "3.64.0", + "helmich/typo3-typoscript-lint": "3.1.1", + "icanhazstring/composer-unused": "0.8.11", + "php-parallel-lint/php-parallel-lint": "1.4.0", + "phpmd/phpmd": "2.15.0", + "phpstan/extension-installer": "1.4.3", + "phpstan/phpstan": "1.12.6", + "phpstan/phpstan-phpunit": "1.4.0", + "phpstan/phpstan-strict-rules": "1.6.1", + "phpunit/phpunit": "9.6.20", + "saschaegerer/phpstan-typo3": "1.10.2", + "seld/jsonlint": "1.11.0", + "spaze/phpstan-disallowed-calls": "3.4.0", + "squizlabs/php_codesniffer": "3.10.3", + "ssch/typo3-rector": "2.9.2", + "ssch/typo3-rector-testing-framework": "2.0.1", + "symfony/console": "^5.4.44 || ^6.4.12 || ^7.1.5", + "symfony/translation": "^5.4.44 || ^6.4.12 || ^7.1.5", + "symfony/yaml": "^5.4.44 || ^6.4.12 || ^7.1.5", + "tomasvotruba/cognitive-complexity": "0.2.3", + "tomasvotruba/type-coverage": "1.0.0", "typo3/cms-fluid-styled-content": "^11.5.4 || ^12.4.2", - "typo3/coding-standards": "^0.6.1 || ^0.8.0", - "typo3/testing-framework": "^7.1.0", + "typo3/coding-standards": "0.6.1 || 0.8.0", + "typo3/testing-framework": "7.1.0", "webmozart/assert": "^1.11.0" }, "replace": { @@ -147,6 +147,7 @@ "ci:php:cs-fixer": "php-cs-fixer fix --config .php-cs-fixer.php -v --dry-run --diff", "ci:php:lint": "parallel-lint .*.php *.php Classes Configuration Tests", "ci:php:mess": "phpmd Classes text Build/phpmd/phpmd.xml", + "ci:php:rector": "rector --dry-run", "ci:php:sniff": "phpcs --standard=Build/phpcs/phpcs.xml Classes Configuration Tests", "ci:php:stan": "phpstan --no-progress -v", "ci:static": [ @@ -155,6 +156,7 @@ "@ci:json:lint", "@ci:php:cs-fixer", "@ci:php:lint", + "@ci:php:rector", "@ci:php:sniff", "@ci:php:stan", "@ci:typoscript:lint", @@ -174,10 +176,12 @@ "docs:generate": "docker run --rm --pull always -v $(pwd):/project -it ghcr.io/typo3-documentation/render-guides:latest --config=Documentation", "fix:composer:normalize": "@composer normalize --no-check-lock", "fix:php": [ + "@fix:php:rector", "@fix:php:cs", "@fix:php:sniff" ], "fix:php:cs": "php-cs-fixer fix --config .php-cs-fixer.php", + "fix:php:rector": "rector", "fix:php:sniff": "phpcbf --standard=Build/phpcs/phpcs.xml Classes Configuration Tests", "phpstan:baseline": "phpstan --generate-baseline --allow-empty-baseline", "prepare-release": [ @@ -218,6 +222,7 @@ "ci:php:cs-fixer": "Checks the code style with the PHP Coding Standards Fixer (PHP-CS-Fixer).", "ci:php:lint": "Lints the PHP files for syntax errors.", "ci:php:mess": "Runs PHP mess detection.", + "ci:php:rector": "Checks for code for changes by Rector.", "ci:php:sniff": "Checks the code style with PHP_CodeSniffer (PHPCS).", "ci:php:stan": "Checks the PHP types using PHPStan.", "ci:static": "Runs all static code checks (syntax, style, types).", @@ -232,6 +237,7 @@ "fix:composer:normalize": "Normalizes composer.json file content.", "fix:php": "Runs all fixers for the PHP code.", "fix:php:cs": "Fixes the code style with PHP-CS-Fixer.", + "fix:php:rector": "Updates the code with Rector.", "fix:php:sniff": "Fixes the code style with PHP_CodeSniffer.", "phpstan:baseline": "Updates the PHPStan baseline file to match the code.", "prepare-release": "Removes development-only files in preparation of a TER release."