[TASK] Add composer.json integrity check 88/55788/4
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 23:14:37 +0000 (00:14 +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/55788
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
composer.json
composer.lock
typo3/sysext/core/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 911d044..50c261c 100644 (file)
@@ -484,8 +484,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.getRequirementPhpVersion70Or71Or72()
             )
index 967a9fb..3d53d22 100644 (file)
@@ -31,7 +31,7 @@
                }
        },
        "require": {
-               "php": "^7.0",
+               "php": ">=7.0.0 <=7.2.99",
                "ext-json": "*",
                "ext-pcre": "*",
                "ext-session": "*",
index 07fcc13..48d7347 100644 (file)
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "content-hash": "078a52798f5e6d8f34b8b8c215c23dbc",
+    "content-hash": "46991b9dc7229f9f82903921e7aeb029",
     "packages": [
         {
             "name": "cogpowered/finediff",
     "prefer-stable": false,
     "prefer-lowest": false,
     "platform": {
-        "php": "^7.0",
+        "php": ">=7.0.0 <=7.2.99",
         "ext-json": "*",
         "ext-pcre": "*",
         "ext-session": "*",
index 7cb796e..af0f935 100644 (file)
@@ -11,7 +11,7 @@
                }],
 
        "require": {
-               "php": "^7.0",
+               "php": ">=7.0.0 <=7.2.99",
                "ext-json": "*",
                "ext-pcre": "*",
                "ext-session": "*",