From 0696b6e07b0ae2ac824e660f80be9469596ae6c5 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke <ben@bnf.dev> Date: Mon, 9 Sep 2024 20:55:15 +0200 Subject: [PATCH] [TASK] Add integrity check for set and setting labels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Labels for site sets and site settings – as added in #104831 - are now verified for completenes. The script checkIntegritySetLabels.php checks for required and optional labels to ensure labels.xlf and settings.definitions.yaml are in sync. Resolves: #104867 Related: #104831 Releases: main Change-Id: I7c91d9ce1fe79ac3137a06b53010fe36418cc896 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/85931 Reviewed-by: Benjamin Franzke <ben@bnf.dev> Tested-by: Benjamin Franzke <ben@bnf.dev> Tested-by: Benni Mack <benni@typo3.org> Reviewed-by: Benni Mack <benni@typo3.org> Reviewed-by: Oliver Bartsch <bo@cedev.de> Reviewed-by: Garvin Hicking <gh@faktor-e.de> Tested-by: Oliver Bartsch <bo@cedev.de> Tested-by: core-ci <typo3@b13.com> Tested-by: Garvin Hicking <gh@faktor-e.de> --- Build/Scripts/checkIntegritySetLabels.php | 135 ++++++++++++++++++++++ Build/Scripts/runTests.sh | 5 + Build/gitlab-ci/nightly/integrity.yml | 1 + Build/gitlab-ci/pre-merge/integrity.yml | 1 + 4 files changed, 142 insertions(+) create mode 100755 Build/Scripts/checkIntegritySetLabels.php diff --git a/Build/Scripts/checkIntegritySetLabels.php b/Build/Scripts/checkIntegritySetLabels.php new file mode 100755 index 000000000000..b001664560f7 --- /dev/null +++ b/Build/Scripts/checkIntegritySetLabels.php @@ -0,0 +1,135 @@ +#!/usr/bin/env php +<?php + +declare(strict_types=1); + +/* + * This file is part of the TYPO3 CMS project. + * + * 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. + * + * The TYPO3 project - inspiring people to share! + */ + +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Output\ConsoleOutput; +use Symfony\Component\Finder\Finder; +use Symfony\Component\Yaml\Yaml; + +require __DIR__ . '/../../vendor/autoload.php'; + +if (PHP_SAPI !== 'cli') { + die('Script must be called from command line.' . chr(10)); +} + +final readonly class CheckIntegritySetLabels +{ + public function execute(): int + { + $filesToProcess = $this->findSetLabels(); + $output = new ConsoleOutput(); + + $resultAcrossAllFiles = 0; + $testResults = []; + /** @var \SplFileInfo $labelFile */ + foreach ($filesToProcess as $labelFile) { + $fullFilePath = $labelFile->getRealPath(); + $result = $this->checkValidLabels($fullFilePath); + if ($result !== null) { + $testResults[] = $result; + } + } + if ($testResults === []) { + return 0; + } + + $table = new Table($output); + $table->setHeaders([ + 'EXT', + 'Set', + 'Invalid set labels', + 'Missing set labels', + ]); + foreach ($testResults as $result) { + $table->addRow([ + $result['ext'], + $result['set'], + implode("\n", $result['invalid']), + implode("\n", $result['missing']), + ]); + } + $table->render(); + return 1; + } + + private function findSetLabels(): Finder + { + $finder = new Finder(); + $labelFiles = $finder + ->files() + ->in(__DIR__ . '/../../typo3/sysext/*/Configuration/Sets/*') + ->name('labels.xlf'); + return $labelFiles; + } + + private function checkValidLabels(string $labelFile): ?array + { + $extensionKey = $this->extractExtensionKey($labelFile); + $doc = new DOMDocument(); + if (!$doc->load($labelFile)) { + throw new \RuntimeException('Failed to load xlf file: ' . $labelFile, 1725902515); + } + + $requiredLabels = [ + 'label', + ]; + $optionalLabels = [ + 'description', + ]; + + $settingsDefinitions = Yaml::parseFile(dirname($labelFile) . '/settings.definitions.yaml'); + foreach ($settingsDefinitions['settings'] as $key => $settingsDefinition) { + $requiredLabels[] = 'settings.' . $key; + $optionalLabels[] = 'settings.description.' . $key; + } + + $setName = Yaml::parseFile(dirname($labelFile) . '/config.yaml')['name']; + + $availableLabels = []; + foreach ($doc->getElementsByTagName('trans-unit') as $tu) { + $availableLabels[] = $tu->getAttribute('id'); + } + + $allowedLabels = [ + ...$requiredLabels, + ...$optionalLabels, + ]; + $missing = array_diff($requiredLabels, $availableLabels); + $invalid = array_diff($availableLabels, $allowedLabels); + + if ($missing === [] && $invalid === []) { + return null; + } + + return [ + 'ext' => $extensionKey, + 'set' => $setName, + 'invalid' => $invalid, + 'missing' => $missing, + ]; + } + + private function extractExtensionKey(string $filename): string + { + $pattern = '/typo3\/sysext\/(?<extName>[a-z].+?)\//'; + preg_match_all($pattern, $filename, $matches, PREG_SET_ORDER, 0); + return $matches[0]['extName']; + } +} + +exit((new CheckIntegritySetLabels())->execute()); diff --git a/Build/Scripts/runTests.sh b/Build/Scripts/runTests.sh index b6d78fb7c9d4..9034dc226445 100755 --- a/Build/Scripts/runTests.sh +++ b/Build/Scripts/runTests.sh @@ -198,6 +198,7 @@ Options: - cglHeaderGit: test and fix latest committed patch for CGL file header compliance - checkBom: check UTF-8 files do not contain BOM - checkComposer: check composer.json files for version integrity + - checkIntegritySetLabels: check labels.xlf file integrity of site sets - 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 @@ -893,6 +894,10 @@ case ${TEST_SUITE} in ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-utf8bom-${SUFFIX} ${IMAGE_PHP} Build/Scripts/checkUtf8Bom.sh SUITE_EXIT_CODE=$? ;; + checkIntegritySetLabels) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-integrity-set-labels-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/checkIntegritySetLabels.php + 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=$? diff --git a/Build/gitlab-ci/nightly/integrity.yml b/Build/gitlab-ci/nightly/integrity.yml index 32ae1708fd68..3ce3cc76bb7b 100644 --- a/Build/gitlab-ci/nightly/integrity.yml +++ b/Build/gitlab-ci/nightly/integrity.yml @@ -29,6 +29,7 @@ integration various php 8.4: - Build/Scripts/runTests.sh -s checkBom -p 8.4 - Build/Scripts/runTests.sh -s checkComposer -p 8.4 - Build/Scripts/runTests.sh -s checkIntegrityPhp -p 8.4 + - Build/Scripts/runTests.sh -s checkIntegritySetLabels -p 8.4 - Build/Scripts/runTests.sh -s lintServicesYaml -p 8.4 - Build/Scripts/runTests.sh -s lintYaml -p 8.4 diff --git a/Build/gitlab-ci/pre-merge/integrity.yml b/Build/gitlab-ci/pre-merge/integrity.yml index 163f518a3f31..a2e949ac0e23 100644 --- a/Build/gitlab-ci/pre-merge/integrity.yml +++ b/Build/gitlab-ci/pre-merge/integrity.yml @@ -31,6 +31,7 @@ integration various php 8.2 pre-merge: - Build/Scripts/runTests.sh -s checkBom -p 8.2 - Build/Scripts/runTests.sh -s checkComposer -p 8.2 - Build/Scripts/runTests.sh -s checkIntegrityPhp -p 8.2 + - Build/Scripts/runTests.sh -s checkIntegritySetLabels -p 8.2 - Build/Scripts/runTests.sh -s lintServicesYaml -p 8.2 - Build/Scripts/runTests.sh -s lintYaml -p 8.2 -- GitLab