[TASK] Add composer.json integrity check 85/55785/7
authorMathias Schreiber <mathias.schreiber@typo3.org>
Sat, 17 Feb 2018 20:40:05 +0000 (21:40 +0100)
committerChristian Kuhn <lolli@schwarzbu.ch>
Sat, 17 Feb 2018 22:44:32 +0000 (23:44 +0100)
Each composer.json file in a system extension now has its dependencies
checked against the root composer.json to avoid errors after the subtree split.

Resolves: #83957
Releases: master, 8.7
Change-Id: Ibf37bd56fd1534b14e714dfdfaaf6374a48978c4
Reviewed-on: https://review.typo3.org/55785
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Build/Scripts/checkIntegrityComposer.php [new file with mode: 0755]
Build/bamboo/src/main/java/core/AbstractCoreSpec.java
typo3/sysext/core/composer.json
typo3/sysext/fluid/composer.json
typo3/sysext/install/composer.json
typo3/sysext/redirects/composer.json

diff --git a/Build/Scripts/checkIntegrityComposer.php b/Build/Scripts/checkIntegrityComposer.php
new file mode 100755 (executable)
index 0000000..a3f12f1
--- /dev/null
@@ -0,0 +1,150 @@
+#!/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!
+ */
+
+require __DIR__ . '/../../vendor/autoload.php';
+
+if (PHP_SAPI !== 'cli') {
+    die('Script must be called from command line.' . chr(10));
+}
+
+/**
+ * Core integrity test script:
+ *
+ * Find all composer.json files in all system extensions and compare
+ * their dependencies against the defined dependencies of our root
+ * composer.json
+ */
+class checkIntegrityComposer
+{
+    /**
+     * @var array
+     */
+    private $rootComposerJson = [];
+
+    private $testResults = [];
+
+    /**
+     * Executes the composer integrity check.
+     * The return value is used directly in the ext() call outside this class.
+     *
+     * @return int
+     */
+    public function execute(): int
+    {
+        $rootComposerJson = __DIR__ . '/../../composer.json';
+        $this->rootComposerJson = json_decode(file_get_contents($rootComposerJson), true);
+        $filesToProcess = $this->findExtensionComposerJson();
+        $output = new \Symfony\Component\Console\Output\ConsoleOutput();
+
+        $resultAcrossAllFiles = 0;
+        /** @var \SplFileInfo $composerJsonFile */
+        foreach ($filesToProcess as $composerJsonFile) {
+            $fullFilePath = $composerJsonFile->getRealPath();
+            $this->validateComposerJson($fullFilePath);
+        }
+        if (!empty($this->testResults)) {
+            $table = new \Symfony\Component\Console\Helper\Table($output);
+            $table->setHeaders([
+                'EXT',
+                'type',
+                'Dependency',
+                'should be',
+                'actually is'
+            ]);
+            foreach ($this->testResults as $extKey => $results) {
+                foreach ($results as $result) {
+                    $table->addRow([
+                        $extKey,
+                        $result['type'],
+                        $result['dependency'],
+                        $result['shouldBe'],
+                        $result['actuallyIs']
+                    ]);
+                }
+            }
+            $table->render();
+            $resultAcrossAllFiles = 1;
+        }
+        return $resultAcrossAllFiles;
+    }
+
+    /**
+     * Finds all composer.json files in TYPO3s system extensions
+     *
+     * @return \Symfony\Component\Finder\Finder
+     */
+    private function findExtensionComposerJson(): \Symfony\Component\Finder\Finder
+    {
+        $finder = new Symfony\Component\Finder\Finder();
+        $composerFiles = $finder
+            ->files()
+            ->in(__DIR__ . '/../../typo3/sysext/*')
+            ->name('composer.json');
+        return $composerFiles;
+    }
+
+    /**
+     * Checks if the dependencies defined in $composerJsonFile are the same as
+     * in TYPO3s root composer.json file.
+     *
+     * @param string $composerJsonFile
+     */
+    private function validateComposerJson(string $composerJsonFile)
+    {
+        $extensionKey = $this->extractExtensionKey($composerJsonFile);
+        $extensionComposerJson = json_decode(file_get_contents($composerJsonFile), true);
+        // Check require section
+        foreach ($this->rootComposerJson['require'] as $requireKey => $requireItem) {
+            if (isset($extensionComposerJson['require'][$requireKey]) && $extensionComposerJson['require'][$requireKey] !== $requireItem) {
+                // log inconsistency
+                $this->testResults[$extensionKey][] = [
+                    'type' => 'require',
+                    'dependency' => $requireKey,
+                    'shouldBe' => $requireItem,
+                    'actuallyIs' => $extensionComposerJson['require'][$requireKey]
+                ];
+            }
+        }
+        // Check require-dev section
+        foreach ($this->rootComposerJson['require-dev'] as $requireDevKey => $requireDevItem) {
+            if (isset($extensionComposerJson['require-dev'][$requireDevKey]) && $extensionComposerJson['require-dev'][$requireDevKey] !== $requireDevItem) {
+                // log inconsistency
+                $this->testResults[$extensionKey][] = [
+                    'type' => 'require-dev',
+                    'dependency' => $requireDevKey,
+                    'shouldBe' => $requireDevItem,
+                    'actuallyIs' => $extensionComposerJson['require-dev'][$requireDevKey]
+                ];
+            }
+        }
+    }
+
+    /**
+     * Makes the output on CLI a bit more readable
+     *
+     * @param string $filename
+     * @return string
+     */
+    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'];
+    }
+}
+
+$composerIntegrityChecker = new checkIntegrityComposer();
+exit($composerIntegrityChecker->execute());
index 3c7e416..2b06cf8 100644 (file)
@@ -516,8 +516,15 @@ abstract public class AbstractCoreSpec {
                     .inlineBody(
                         this.getScriptTaskBashInlineBody() +
                         "./Build/Scripts/checkIntegrityCsvFixtures.php"
-                    )
-            )
+                    ),
+                new ScriptTask()
+                    .description("Run composer.json integrity check")
+                    .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
+                    .inlineBody(
+                        this.getScriptTaskBashInlineBody() +
+                        "./Build/Scripts/checkIntegrityComposer.php"
+                   )
+           )
             .requirements(
                 this.getRequirementPhpVersion72()
             )
index 450819e..ff3829c 100644 (file)
@@ -33,7 +33,7 @@
                "mso/idna-convert": "^1.1.0",
                "typo3fluid/fluid": "^2.4",
                "guzzlehttp/guzzle": "^6.3.0",
-               "doctrine/dbal": "~2.6",
+               "doctrine/dbal": "^2.6",
                "nikic/php-parser": "^3.1",
                "symfony/polyfill-intl-icu": "^1.6"
        },
index 3cbcb3c..e17530b 100644 (file)
@@ -13,7 +13,7 @@
        "require": {
                "typo3/cms-core": "9.2.*@dev",
                "typo3/cms-extbase": "9.2.*@dev",
-               "typo3fluid/fluid": "^2.3"
+               "typo3fluid/fluid": "^2.4"
        },
        "conflict": {
                "typo3/cms": "*"
index e6afbd3..9e1e024 100644 (file)
@@ -14,7 +14,7 @@
                "typo3/cms-core": "9.2.*@dev",
                "typo3/cms-extbase": "9.2.*@dev",
                "typo3/cms-fluid": "9.2.*@dev",
-               "nikic/php-parser": "~3.1",
+               "nikic/php-parser": "^3.1",
                "symfony/finder": "^2.7 || ^3.0 || ^4.0"
        },
        "conflict": {
index 592267c..8e360fe 100644 (file)
@@ -12,7 +12,7 @@
        "require": {
                "typo3/cms-core": "9.2.*@dev",
                "typo3/cms-backend": "9.2.*@dev",
-               "typo3fluid/fluid": "^2.3"
+               "typo3fluid/fluid": "^2.4"
        },
        "conflict": {
                "typo3/cms": "*"